1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
24 #include <libgeda/libgeda.h>
26 #include "../include/gschem_struct.h"
27 #include "../include/globals.h"
28 #include "../include/prototype.h"
30 #ifdef HAVE_LIBDMALLOC
34 /* Kazu on July 8, 1999 - added these macros to simplify the code */
36 #define GET_BOX_WIDTH(w) \
37 abs((w)->last_x - (w)->start_x)
39 #define GET_BOX_HEIGHT(w) \
40 abs((w)->last_y - (w)->start_y)
42 typedef void (*DRAW_FUNC
)( GdkDrawable
*w
, GdkGC
*gc
, GdkColor
*color
,
43 GdkCapStyle cap
, gint x
, gint y
, gint radius
,
44 gint angle1
, gint angle2
,
45 gint arc_width
, gint length
, gint space
);
48 * \note pb20011011 - added this macro to compute distance
50 #define GET_DISTANCE(w) \
51 sqrt(pow((w)->last_x-(w)->start_x,2)+pow((w)->last_y-(w)->start_y,2))
53 /*! \brief Draw an arc on the screen.
54 * \par Function Description
55 * This function is used to draw an arc on screen. The arc is described
56 * in the object which is referred by <B>o_current</B>. The arc is displayed
57 * according to the current state, described in the GSCHEM_TOPLEVEL object
58 * pointed by <B>w_current</B>.
60 * It first checkes if the object is valid or not. If not it returns
61 * and do not output anything. That should never happen though.
63 * \param [in] w_current The GSCHEM_TOPLEVEL object.
64 * \param [in] o_current The arc OBJECT to draw.
66 void o_arc_draw(GSCHEM_TOPLEVEL
*w_current
, OBJECT
*o_current
)
68 TOPLEVEL
*toplevel
= w_current
->toplevel
;
69 int wleft
, wright
, wtop
, wbottom
;
70 int x
, y
, radius
, start_angle
, end_angle
;
74 DRAW_FUNC draw_func
= NULL
;
77 if (o_current
->arc
== NULL
) {
81 world_get_arc_bounds(toplevel
, o_current
,
82 &wleft
, &wtop
, &wright
, &wbottom
);
84 if ( (toplevel
->DONT_REDRAW
== 1) ||
85 (!visible(toplevel
, wleft
, wtop
, wright
, wbottom
)) ) {
90 * As an arc is definetely not a closed shape there is no need to
91 * define and call any filling function. Another way to say that is
92 * that an arc can not be filled. It simply draws the arc according
95 * The values describing the line type are extracted from the
96 * <B>o_current</B> pointed structure. These are the width of the line,
97 * the field called length and the field called space and the desired
98 * end type for the arc.
100 * Depending on the type of line desired the appropriate function is
101 * called. Values of space and length are adapted to the type of line.
102 * The possible functions are the following : #o_arc_draw_solid(),
103 * #o_arc_draw_dotted(), #o_arc_draw_dashed() and #o_arc_draw_phantom().
105 * The combination <B>length</B> == 0 and <B>space</B> == 0 is avoided as it
106 * leads to an endless loop in function called after. If such a case is
107 * encountered the arc is drawn as a solid arc independently of its
110 WORLDtoSCREEN( toplevel
, o_current
->arc
->x
, o_current
->arc
->y
, &x
, &y
);
111 radius
= SCREENabs( toplevel
, o_current
->arc
->width
/ 2 );
112 start_angle
= o_current
->arc
->start_angle
;
113 end_angle
= o_current
->arc
->end_angle
;
116 printf("drawing arc x: %d y: %d sa: %d ea: %d width: %d height: %d\n",
119 o_current
->arc
->start_angle
,
120 o_current
->arc
->end_angle
,
125 if (toplevel
->override_color
!= -1 )
126 color
= x_get_color(toplevel
->override_color
);
128 color
= x_get_color(o_current
->color
);
130 arc_width
= SCREENabs( toplevel
, o_current
->line_width
);
135 switch(o_current
->line_end
) {
136 case END_NONE
: arc_end
= GDK_CAP_BUTT
; break;
137 case END_SQUARE
: arc_end
= GDK_CAP_PROJECTING
; break;
138 case END_ROUND
: arc_end
= GDK_CAP_ROUND
; break;
139 default: fprintf(stderr
, _("Unknown end for arc (%d)\n"), o_current
->line_end
);
140 arc_end
= GDK_CAP_BUTT
;
144 length
= SCREENabs( toplevel
, o_current
->line_length
);
145 space
= SCREENabs( toplevel
, o_current
->line_space
);
147 switch(o_current
->line_type
) {
151 draw_func
= o_arc_draw_solid
;
155 length
= -1; /* AVH changed o_arc_draw_dotted to use */
156 /* space parameter only */
157 draw_func
= o_arc_draw_dotted
;
161 draw_func
= o_arc_draw_dashed
;
165 draw_func
= o_arc_draw_center
;
169 draw_func
= o_arc_draw_phantom
;
178 arc_width
= 0; /* just to be careful */
179 draw_func
= o_arc_draw_solid
;
180 fprintf(stderr
, _("Unknown type for arc !\n"));
184 if((length
== 0) || (space
== 0))
185 draw_func
= o_arc_draw_solid
;
187 (*draw_func
)(w_current
->backingstore
, w_current
->gc
, color
,
189 x
, y
, radius
, start_angle
, end_angle
,
190 arc_width
, length
, space
);
193 if (o_current
->draw_grips
&& w_current
->draw_grips
== TRUE
) {
195 /* pb29911903 - modified to use the new o_arc_[draw|erase]_grips() */
196 if(!o_current
->selected
) {
197 /* object is no more selected, erase the grips */
198 o_current
->draw_grips
= FALSE
;
199 o_arc_erase_grips(w_current
, o_current
);
201 /* object is selected, draw the grips on the arc */
202 o_arc_draw_grips(w_current
, o_current
);
209 printf("drawing arc\n");
213 /*! \brief Draw an arc with a solid line type.
214 * \par Function Description
215 * This function draw an arc with a solid line type. The arc is defined
216 * by two angle (start and end of arc) and the definition of a box by
217 * which the arc is restricted by. The parameters <B>length</B> and
218 * <B>space</B> are unused here.
220 * The unit of <B>x</B>, <B>y</B> and <B>width</B>, <B>height</B> and <B>arc_width</B>,
221 * <B>space</B>, <B>length</B> is pixel.
223 * <B>angle1</B> and <B>angle2</B> are in degrees.
225 * The lines attributes are settled. Then it simply make a call to
226 * the gdk original function.
228 * \param [in] w GdkWindow to draw in.
229 * \param [in] gc GdkGC graphics context to draw on.
230 * \param [in] color Arc line color.
231 * \param [in] cap Arc line end cap type (unused).
232 * \param [in] x Arc center x.
233 * \param [in] y Arc center y.
234 * \param [in] radius Arc radius.
235 * \param [in] angle1 Start angle in degrees.
236 * \param [in] angle2 End angle in degrees.
237 * \param [in] arc_width Width of arc line.
238 * \param [in] length (unused)
239 * \param [in] space (unused)
241 void o_arc_draw_solid(GdkWindow
*w
, GdkGC
*gc
,
242 GdkColor
*color
, GdkCapStyle cap
,
243 gint x
, gint y
, gint radius
,
244 gint angle1
, gint angle2
,
245 gint arc_width
, gint length
, gint space
)
247 gdk_gc_set_foreground(gc
, color
);
248 /* Set the width, end type and join style of the line */
249 gdk_gc_set_line_attributes(gc
, arc_width
,
250 GDK_LINE_SOLID
, cap
, GDK_JOIN_MITER
);
253 gdk_draw_arc(w
, gc
, FALSE
,
254 x
- radius
, y
- radius
, 2 * radius
, 2 * radius
,
255 angle1
* 64, angle2
* 64);
259 /*! \brief Draw an arch with a dotted line type.
260 * \par Function Description
261 * This functions draws an arc with a dotted line type. The parameter
262 * <B>space</B> represents the distance between two of the dots. The
263 * parameter <B>length</B> is unused. The diameter of the dots is given
264 * by the width of the line given by <B>arc_width</B>.
266 * The unit of <B>x</B>, <B>y</B> and <B>width</B>, <B>height</B> and
267 * <B>arc_width</B>, <B>space</B>, <B>length</B> is pixel.
269 * <B>angle1</B> and <B>angle2</B> are in degrees.
270 * A negative or null value for length leads to an endless loop.
271 * length parameter is not used here.
273 * \param [in] w GdkWindow to draw in.
274 * \param [in] gc GdkGC graphics context to draw on.
275 * \param [in] color Arc line color.
276 * \param [in] cap Arc line end cap type (unused).
277 * \param [in] x Arc center x.
278 * \param [in] y Arc center y.
279 * \param [in] radius Arc radius.
280 * \param [in] angle1 Start angle in degrees.
281 * \param [in] angle2 End angle in degrees.
282 * \param [in] arc_width Width of arc line.
283 * \param [in] length (unused).
284 * \param [in] space Spacing between dots in pixels.
286 void o_arc_draw_dotted(GdkWindow
*w
, GdkGC
*gc
,
287 GdkColor
*color
, GdkCapStyle cap
,
288 gint x
, gint y
, gint radius
,
289 gint angle1
, gint angle2
,
290 gint arc_width
, gint length
, gint space
)
295 gdk_gc_set_foreground(gc
, color
);
298 * It calculates the angle that match the length <B>space</B> as <B>da</B>.
299 * If <B>da</B> is negative or null, the way the function uses it after
300 * leads to an andless loop. In fact such a case occur when it is not
301 * possible to distinguish a solid line from a dotted line because of
302 * zoom factor. The arc is therefore drawn solid.
304 /* PB inverting angle2 if < 0 and changing angle1 accordingly */
305 /* the loop test assume that da > 0 */
307 angle1
= angle1
+ angle2
;
311 da
= space
* 180 / (M_PI
* radius
);
313 /* If da is too small for arc to be displayed as dotted,
316 gdk_draw_arc(w
, gc
, FALSE
,
317 x
- radius
, y
- radius
, 2 * radius
, 2 * radius
,
318 angle1
* 64, angle2
* 64);
322 * It starts from <B>angle1</B> and increments <B>angle1</B> by <B>da</B> as
323 * a loop until all the arc has been browsed. For each angle value a
324 * dot is drawing after calculating back its coordinates from the angle.
327 while(d
< (angle2
+ angle1
)) {
328 xa
= ((double) x
) + ((double) radius
) * cos(d
* M_PI
/ 180);
329 ya
= ((double) y
) - ((double) radius
) * sin(d
* M_PI
/ 180);
332 * Depending on the width of the line, dots has to be drawn in a
333 * different manner : if the real worl width is equal to 0, then the
334 * width is translated to 1 in screen coordinates to be visible.
335 * Drawing a circle with a 1-diameter and the GDK function
336 * #gdk_draw_arc() is not possible. So we needs to test
337 * whether the width is 1 or not.
340 gdk_draw_point(w
, gc
, (int) xa
, (int) ya
);
342 gdk_draw_arc(w
, gc
, TRUE
,
343 ((int) xa
) - arc_width
/2,
344 ((int) ya
) - arc_width
/2,
345 arc_width
, arc_width
, 0, FULL_CIRCLE
);
353 /*! \brief Draw an arc with a dashed line type.
354 * This functions draws an arc with a dashed line type. The parameter
355 * <B>space</B> represents the distance between two of the dash. The
356 * parameter <B>length</B> represents the length of the dash.
358 * The unit of <B>x</B>, <B>y</B> and <B>width</B>, <B>height</B> and
359 * <B>arc_width</B>, <B>space</B>, <B>length</B> is pixel.
361 * <B>angle1</B> and <B>angle2</B> are in degrees.
363 * A negative or null value for <B>length</B> and <B>space</B> leads to an
366 * \param [in] w GdkWindow to draw in.
367 * \param [in] gc GdkGC graphics context to draw on.
368 * \param [in] color Arc line color.
369 * \param [in] cap Arc line end cap type (unused).
370 * \param [in] x Arc center x.
371 * \param [in] y Arc center y.
372 * \param [in] radius Arc radius.
373 * \param [in] angle1 Start angle in degrees.
374 * \param [in] angle2 End angle in degrees.
375 * \param [in] arc_width Width of arc line.
376 * \param [in] length Length of dash in pixels..
377 * \param [in] space Spacing between dashes in pixels.
379 void o_arc_draw_dashed(GdkWindow
*w
, GdkGC
*gc
,
380 GdkColor
*color
, GdkCapStyle cap
,
383 gint angle1
, gint angle2
,
384 gint arc_width
, gint length
, gint space
)
386 int da
, db
, a1
, a2
, d
;
388 gdk_gc_set_foreground(gc
, color
);
389 gdk_gc_set_line_attributes(gc
, arc_width
, GDK_LINE_SOLID
, cap
,
393 * The function first determines the radius and the center of the arc.
395 * The function determines the angular increments that match the
396 * <B>length</B> and <B>space</B> parameter. These are <B>db</B> and <B>da</B>.
397 * Whenever one or both of these variables are null or negative, the
398 * line is drawn solid. It means that it is not possible to distinguish
399 * a dashed line from a solid line because of current value of zoom.
402 /* PB inverting angle2 if < 0 and changing angle1 accordingly */
403 /* the loop test assume that da > 0 */
405 angle1
= angle1
+ angle2
;
408 da
= length
* 180 / (M_PI
* radius
);
409 db
= space
* 180 / (M_PI
* radius
);
411 /* If da or db too small for arc to be displayed as dotted,
413 if((da
<= 0) || (db
<= 0)) {
414 gdk_draw_arc(w
, gc
, FALSE
,
415 x
- radius
, y
- radius
, 2 * radius
, 2 * radius
,
416 angle1
* 64, angle2
* 64);
421 * It starts from <B>angle1</B> and increments <B>angle1</B> by <B>da</B> as a
422 * loop until the whole arc has been browsed. At each position a dash
423 * of length <B>length</B> - represented by the <B>da</B> increment - is drawn.
425 * It draws as many dashes of length <B>length</B> as possible.
429 while((d
+ da
+ db
) < (angle1
+ angle2
)) {
432 gdk_draw_arc(w
, gc
, FALSE
,
433 x
- radius
, y
- radius
, 2 * radius
, 2 * radius
,
441 * When the above condition is no more satisfied, the it is possible
442 * to draw a dash of length <B>length</B>. However it may be possible to
443 * draw a shorter dash.
446 if((d
+ da
) < (angle1
+ angle2
)) {
451 a2
= (angle1
+ angle2
) - d
;
453 gdk_draw_arc(w
, gc
, FALSE
,
454 x
- radius
, y
- radius
, 2 * radius
, 2 * radius
,
460 /*! \brief Draw arc with a centered line type.
461 * \par Function Description
462 * This functions draws an arc with a centered line type. The parameter
463 * <B>space</B> represents the distance between a dot and the dash. The
464 * parameter <B>length</B> represents the length of a dash.
466 * The unit of <B>x</B>, <B>y</B> and <B>width</B>, <B>height</B> and
467 * <B>arc_width</B>, <B>space</B>, <B>length</B> is pixel.
469 * <B>angle1</B> and <B>angle2</B> are in units of degrees.
471 * A negative or null value for <B>length</B> and <B>space</B> leads to an
474 * \param [in] w GdkWindow to draw in.
475 * \param [in] gc GdkGC graphics context to draw on.
476 * \param [in] color Arc line color.
477 * \param [in] cap Arc line end cap type (unused).
478 * \param [in] x Arc center x.
479 * \param [in] y Arc center y.
480 * \param [in] radius Arc radius.
481 * \param [in] angle1 Start angle in degrees.
482 * \param [in] angle2 End angle in degrees.
483 * \param [in] arc_width Width of arc line.
484 * \param [in] length Length of dash in pixels..
485 * \param [in] space Spacing between dashes in pixels.
487 void o_arc_draw_center(GdkWindow
*w
, GdkGC
*gc
,
488 GdkColor
*color
, GdkCapStyle cap
,
491 gint angle1
, gint angle2
,
492 gint arc_width
, gint length
, gint space
)
494 double xa
, ya
; /* coordinate of center */
495 int da
, db
, a1
, a2
, d
;
497 gdk_gc_set_foreground(gc
, color
);
498 gdk_gc_set_line_attributes(gc
, arc_width
,
499 GDK_LINE_SOLID
, cap
, GDK_JOIN_MITER
);
502 * The function determines the angular increments that match the
503 * <B>length</B> and <B>space</B> parameter. These are <B>db</B> and <B>da</B>.
504 * Whenever one or both of these variables are null or negative, the
505 * line is drawn solid. It means that it is not possible to distinguish
506 * a dashed line from a solid line because of current value of zoom.
509 /* PB inverting angle2 if < 0 and changing angle1 accordingly */
510 /* the loop test assume that da > 0 */
512 angle1
= angle1
+ angle2
;
515 da
= length
* 180 / (M_PI
* radius
);
516 db
= space
* 180 / (M_PI
* radius
);
518 /* If da or db too small to be displayed, draw an arc */
519 if((da
<= 0) || (db
<= 0)) {
520 gdk_draw_arc(w
, gc
, FALSE
,
521 x
- radius
, y
- radius
, 2* radius
, 2 * radius
,
522 angle1
* 64, angle2
* 64);
527 * Starting from <B>angle1</B> and incrementing the position gives the
528 * coordinates of every dots and dashes on the arc providing that the
529 * second extremity is not exceeded.
531 * It draws as many sets of 'dash of length <B>length</B> and dot' as possible.
535 while((d
+ da
+ 2 * db
) < (angle1
+ angle2
)) {
538 gdk_draw_arc(w
, gc
, FALSE
,
539 x
- radius
, y
- radius
, 2 * radius
, 2 * radius
,
543 xa
= ((double) x
) + ((double) radius
) * cos(d
* M_PI
/ 180);
544 ya
= ((double) y
) - ((double) radius
) * sin(d
* M_PI
/ 180);
548 gdk_draw_point(w
, gc
, (int) xa
, (int) ya
);
550 gdk_draw_arc(w
, gc
, TRUE
,
551 ((int) xa
) - arc_width
/2,
552 ((int) ya
) - arc_width
/2,
553 arc_width
, arc_width
, 0, FULL_CIRCLE
);
557 * If the above condition is no more satisfied, it may still be possible
558 * to continue drawing a part of the initial pattern. Here two cases are
561 * <DT>*</DT><DD>it is possible to draw a dash and a dot.
562 * <DT>*</DT><DD>it is possible to draw a dash or at least
563 * a part of the original dash.
571 if((d
+ da
) < (angle1
+ angle2
)) {
578 a2
= (angle1
+ angle2
) - d
;
582 gdk_draw_arc(w
, gc
, FALSE
,
583 x
- radius
, y
- radius
, 2 * radius
, 2 * radius
,
586 if((d
+ db
) < (angle1
+ angle2
)) {
587 xa
= ((double) x
) + ((double) radius
) * cos(d
* M_PI
/ 180);
588 ya
= ((double) y
) - ((double) radius
) * sin(d
* M_PI
/ 180);
591 * Depending on the width of the line, dots has to be drawn in a
592 * different manner : if the real worl width is equal to 0, then the
593 * width is translated to 1 in screen coordinates to be visible.
594 * Drawing a circle with a 1-diameter and the GDK function
595 * #gdk_draw_arc() is not possible. So we needs to test whether the
600 gdk_draw_point(w
, gc
, (int) xa
, (int) ya
);
602 gdk_draw_arc(w
, gc
, TRUE
,
603 ((int) xa
) - arc_width
/2,
604 ((int) ya
) - arc_width
/2,
605 arc_width
, arc_width
, 0, FULL_CIRCLE
);
614 /*! \brief Draw an arc with a phantom line type.
615 * \par Function Description
616 * This function draws an arc with a phantom line type. The parameter
617 * <B>space</B> represents the distance between a dot and a dash. The
618 * parameter <B>length</B> represents the length of a dash.
620 * The unit of <B>x</B>, <B>y</B> and <B>width</B>, <B>height</B> and
621 * <B>arc_width</B>, <B>space</B>, <B>length</B> is pixel.
623 * <B>angle1</B> and <B>angle2</B> are in units of degrees.
625 * A negative or null value for <B>length</B> and <B>space</B> leads to an
628 * \param [in] w GdkWindow to draw in.
629 * \param [in] gc GdkGC graphics context to draw on.
630 * \param [in] color Arc line color.
631 * \param [in] cap Arc line end cap type (unused).
632 * \param [in] x Arc center x.
633 * \param [in] y Arc center y.
634 * \param [in] radius Arc radius.
635 * \param [in] angle1 Start angle in degrees.
636 * \param [in] angle2 End angle in degrees.
637 * \param [in] arc_width Width of arc line.
638 * \param [in] length Length of dash in pixels.
639 * \param [in] space Spacing between dashes in pixels.
641 void o_arc_draw_phantom(GdkWindow
*w
, GdkGC
*gc
,
642 GdkColor
*color
, GdkCapStyle cap
,
645 gint angle1
, gint angle2
,
646 gint arc_width
, gint length
, gint space
)
649 int da
, db
, a1
, a2
, d
;
651 gdk_gc_set_foreground(gc
, color
);
652 gdk_gc_set_line_attributes(gc
, arc_width
,
653 GDK_LINE_SOLID
, cap
, GDK_JOIN_MITER
);
655 /* The function determines the angular increments that match the
656 * <B>length</B> and <B>space</B> parameters. These are <B>db</B> and <B>da</B>.
657 * Whenever one or both of these variables are null or negative, the
658 * line is drawn solid. It means that it is not possible to distinguish
659 * a dashed line from a solid line because of current value of zoom.
662 /* PB inverting angle2 if < 0 and changing angle1 accordingly */
663 /* the loop test assume that da > 0 */
665 angle1
= angle1
+ angle2
;
668 da
= length
* 180 / (M_PI
* radius
);
669 db
= space
* 180 / (M_PI
* radius
);
671 /* If da or db too small for arc to be displayed as dotted,
673 if((da
<= 0) || (db
<= 0)) {
674 gdk_draw_arc(w
, gc
, FALSE
,
675 x
- radius
, y
- radius
, 2 * radius
, 2 * radius
,
676 angle1
* 64, angle2
* 64);
681 * Starting from <B>angle1</B> and incrementing the position gives the
682 * coordinates of every dots and dashes on the arc providing that the
683 * second extremity is not exceeded.
685 * It draws as many sets of 'dash of length <B>length</B> and two dots'
690 while((d
+ da
+ 3 * db
) < (angle1
+ angle2
)) {
693 gdk_draw_arc(w
, gc
, FALSE
,
694 x
- radius
, y
- radius
, 2 * radius
, 2 * radius
,
698 xa
= ((double) x
) + ((double) radius
) * cos(d
* M_PI
/ 180);
699 ya
= ((double) y
) - ((double) radius
) * sin(d
* M_PI
/ 180);
702 * Depending on the width of the line, dots has to be drawn in a
703 * different manner : if the real worl width is equal to 0, then the
704 * width is translated to 1 in screen coordinates to be visible.
705 * Drawing a circle with a 1-diameter and the GDK function
706 * #gdk_draw_arc() is not possible. So we needs to test whether the
711 gdk_draw_point(w
, gc
, (int) xa
, (int) ya
);
713 gdk_draw_arc(w
, gc
, TRUE
,
714 ((int) xa
) - arc_width
/2,
715 ((int) ya
) - arc_width
/2,
716 arc_width
, arc_width
, 0, FULL_CIRCLE
);
721 xa
= ((double) x
) + ((double) radius
) * cos(d
* M_PI
/ 180);
722 ya
= ((double) y
) - ((double) radius
) * sin(d
* M_PI
/ 180);
726 * Depending on the width of the line, dots has to be drawn in a
727 * different manner : if the real world width is equal to 0, then the
728 * width is translated to 1 in screen coordinates to be visible. Drawing
729 * a circle with a 1-diameter and the GDK function #gdk_draw_arc() is
730 * not possible. So we needs to test whether the width is 1 or not.
734 gdk_draw_point(w
, gc
, (int) xa
, (int) ya
);
736 gdk_draw_arc(w
, gc
, TRUE
,
737 ((int) xa
) - arc_width
/2,
738 ((int) ya
) - arc_width
/2,
739 arc_width
, arc_width
, 0, FULL_CIRCLE
);
748 * If the above condition is no more satisfied, it may still be possible
749 * to continue drawing a part of the original pattern. Here three cases
752 * <DT>*</DT><DD>it is possible to draw a dash and the two dots.
753 * <DT>*</DT><DD>it is possible to draw a dash and one of the two dots.
754 * <DT>*</DT><DD>it is possible to draw at least a part of the initial
758 if((d
+ da
) < (angle1
+ angle2
)) {
764 a2
= (angle1
+ angle2
) - d
;
767 gdk_draw_arc(w
, gc
, FALSE
,
768 x
- radius
, y
- radius
, 2 * radius
, 2 * radius
,
771 if((d
+ db
) < (angle1
+ angle2
)) {
774 xa
= ((double) x
) + ((double) radius
) * cos(d
* M_PI
/ 180);
775 ya
= ((double) y
) - ((double) radius
) * sin(d
* M_PI
/ 180);
778 gdk_draw_point(w
, gc
, (int) xa
, (int) ya
);
780 gdk_draw_arc(w
, gc
, TRUE
,
781 ((int) xa
) - arc_width
/2,
782 ((int) ya
) - arc_width
/2,
783 arc_width
, arc_width
, 0, FULL_CIRCLE
);
787 if((d
+ db
) < (angle1
+ angle2
)) {
790 xa
= ((double) x
) + ((double) radius
) * cos(d
* M_PI
/ 180);
791 ya
= ((double) y
) - ((double) radius
) * sin(d
* M_PI
/ 180);
794 gdk_draw_point(w
, gc
, (int) xa
, (int) ya
);
796 gdk_draw_arc(w
, gc
, TRUE
,
797 ((int) xa
) - arc_width
/2,
798 ((int) ya
) - arc_width
/2,
799 arc_width
, arc_width
, 0, FULL_CIRCLE
);
806 /*! \brief Erase arc described by OBJECT.
807 * \par Function Description
808 * This function erases the arc described in the <B>OBJECT</B> structure
809 * pointed by <B>o_current</B>.
811 * It makes a call to the #o_box_draw() function after setting the
812 * special color. Therefo re an arc is drawn with the background color
813 * over the previous one.
815 void o_arc_erase(GSCHEM_TOPLEVEL
*w_current
, OBJECT
*o_current
)
817 TOPLEVEL
*toplevel
= w_current
->toplevel
;
818 toplevel
->override_color
= toplevel
->background_color
;
819 o_arc_draw(w_current
, o_current
);
820 toplevel
->override_color
= -1;
823 /*! \todo Finish function documentation!!!
825 * \par Function Description
828 void o_arc_eraserubber(GSCHEM_TOPLEVEL
*w_current
)
830 o_arc_rubberarc_xor(w_current
);
833 /*! \brief Draw an arc described by OBJECT with translation
834 * \par Function Description
835 * This function draws the arc object described by <B>*o_current</B>
836 * translated by the vector (<B>dx</B>,<B>dy</B>) with an xor-function over
838 * The translation vector is in screen unit.
840 * The arc is displayed with the color of the object.
842 * \param [in] w_current The GSCHEM_TOPLEVEL object.
843 * \param [in] dx Delta x coordinate for arc.
844 * \param [in] dy Delta y coordinate for arc.
845 * \param [in] o_current Arc OBJECT to draw.
847 void o_arc_draw_xor(GSCHEM_TOPLEVEL
*w_current
, int dx
, int dy
, OBJECT
*o_current
)
849 TOPLEVEL
*toplevel
= w_current
->toplevel
;
850 int x
, y
, width
, height
, start_angle
, end_angle
;
853 if (o_current
->arc
== NULL
) {
858 width
= SCREENabs( toplevel
, o_current
->arc
->width
);
859 /* height MUST be equal to width, just another name for diameter */
860 height
= SCREENabs( toplevel
, o_current
->arc
->height
);
862 WORLDtoSCREEN( toplevel
, o_current
->arc
->x
, o_current
->arc
->y
, &x
, &y
);
865 /* start and end angles */
866 start_angle
= o_current
->arc
->start_angle
;
867 end_angle
= o_current
->arc
->end_angle
;
869 /* check the size of the displayed arc */
870 /* do not allow null diameter = arc always displayed */
878 if (o_current
->saved_color
!= -1) {
879 color
= o_current
->saved_color
;
881 color
= o_current
->color
;
884 gdk_gc_set_foreground(w_current
->outline_xor_gc
,
885 x_get_darkcolor(color
));
886 /* better to set the line attributes here ? */
887 gdk_draw_arc(w_current
->backingstore
, w_current
->outline_xor_gc
, FALSE
,
888 x
+ dx
, y
+ dy
, width
, height
,
889 start_angle
* 64, end_angle
* 64);
891 /* backing store? not appropriate here */
895 /*! \brief Start process to input a new arc.
896 * \par Function Description
897 * This function starts the process to input a new arc. Parameters for
898 * this arc are put into/extracted from the <B>w_current</B> toplevel structure.
899 * <B>x</B> and <B>y</B> are current coordinates of the pointer in screen unit.
901 * First step of the arc input is to set the radius of the arc. The center
902 * of the arc is kept in (<B>w_current->start_x</B>,<B>w_current->start_y</B>).
903 * The other point of the radius, i.e. on the arc, in
904 * (<B>w_current->last_x</B>,<B>w_current->last_y</B>). The radius of the arc is
905 * in <B>w_current->distance</B>.
907 * \param [in] w_current The GSCHEM_TOPLEVEL object.
908 * \param [in] x Current x coordinate of pointer in screen units.
909 * \param [in] y Current y coordinate of pointer in screen units.
911 void o_arc_start(GSCHEM_TOPLEVEL
*w_current
, int x
, int y
)
913 TOPLEVEL
*toplevel
= w_current
->toplevel
;
914 /* set the center of the arc */
915 w_current
->last_x
= w_current
->start_x
= fix_x(toplevel
, x
);
916 w_current
->last_y
= w_current
->start_y
= fix_y(toplevel
, y
);
919 w_current
->distance
= 0;
921 /* set the start and end angles */
922 w_current
->loc_x
= w_current
->loc_y
= 0;
924 /* start the rubberbanding process of the radius */
925 o_arc_rubberarc_xor(w_current
);
929 /*! \brief End the input of an arc.
930 * \par Function Description
931 * This function ends the input of the radius of the arc.
932 * The (<B>x</B>,<B>y</B>) point is taken as the other end of the radius segment.
933 * The distance between this point and the center is the radius of the arc.
934 * <B>x</B> and <B>y</B> are in screen coords.
936 * At the end of this function, the center of the arc is at
937 * (<B>w_current->start_x</B>,<B>w_current->start_y</B>) and its radius is
938 * <B>w_current->distance</B>.
940 * The two angles needs to be input to fully define the arc.
942 * \param [in] w_current The GSCHEM_TOPLEVEL object.
943 * \param [in] x Current x coordinate of pointer in screen units.
944 * \param [in] y Current y coordinate of pointer in screen units.
946 void o_arc_end1(GSCHEM_TOPLEVEL
*w_current
, int x
, int y
)
948 TOPLEVEL
*toplevel
= w_current
->toplevel
;
951 g_assert( w_current
->inside_action
!= 0 );
953 /* erases the previous temporary radius segment */
954 o_arc_rubberarc_xor(w_current
);
956 w_current
->last_x
= fix_x(toplevel
, x
);
957 w_current
->last_y
= fix_y(toplevel
, y
);
958 /* compute the radius */
959 diff_x
= GET_BOX_WIDTH (w_current
);
960 diff_y
= GET_BOX_HEIGHT(w_current
);
961 if (diff_x
>= diff_y
) {
962 w_current
->distance
= diff_x
;
964 w_current
->distance
= diff_y
;
967 /* ack! zero length radius */
968 if (w_current
->distance
== 0) {
973 printf("DIST: %d\n", w_current
->distance
);
976 /* open a dialog to input the start and end angle */
977 arc_angle_dialog(w_current
);
981 /*! \brief Set the start angle of a temporary arc.
982 * \par Function Description
983 * This function sets the start angle of the temporary representation of
984 * an arc. This angle is determined from the current mouse position
985 * described by <B>x</B> and <B>y</B> in screen coords, and the arc center
986 * previously set as (<B>w_current->start_x</B>,<B>w_current->start_y</B>).
988 * The previous temporary arc is erased, the start angle is then updated
989 * and finally, the temporary arc is drawn again.
991 * This function is used when the input of an arc is fully interactive,
992 * not through a dialog box.
994 * \param [in] w_current The GSCHEM_TOPLEVEL object.
995 * \param [in] x Current x coordinate of pointer in screen units.
996 * \param [in] y Current y coordinate of pointer in screen units.
998 void o_arc_end2(GSCHEM_TOPLEVEL
*w_current
, int x
, int y
)
1000 double dx
, dy
, d
, cos_a_
, sin_a_
, a
;
1002 /* erase the previous temporary arc */
1003 o_arc_rubberarc_xor(w_current
);
1005 /* compute the start angle */
1006 dx
= ((double) x
) - ((double) w_current
->start_x
);
1007 dy
= - ((double) y
) + ((double) w_current
->start_y
);
1008 d
= sqrt((dx
* dx
) + (dy
* dy
));
1010 sin_a_
= dy
/ ((double) d
);
1011 cos_a_
= dx
/ ((double) d
);
1012 a
= asin(sin_a_
) * 180 / M_PI
;
1015 /* find the right quadrant */
1017 if(cos_a_
>= 0) a
= a
;
1020 if(cos_a_
>= 0) a
= 360 - a
;
1024 /* start angle in degree is in a */
1025 w_current
->loc_x
= (int) a
;
1027 /* draw the new temporary arc */
1028 o_arc_rubberarc_xor(w_current
);
1032 /*! \brief Set the end angle during the input of a new arc object.
1033 * \par Function Description
1034 * This function sets the end angle during the input of a new arc object.
1035 * The angle is computed from the current mouse position in <B>x</B> and
1036 * <B>y</B> and the center of the arc. The arc is internally represented
1037 * with its center in (<B>w_current->start_x</B>,<B>w_current->start_y</B>),
1038 * its radius in <B>w_current->distance</B> and its start angle in
1039 * <B>w_current->loc_x</B>.
1041 * The temporary arc is erased, a new object is initialized and drawn.
1043 * This function is used when the input of an arc is fully interactive,
1044 * i.e. not through a dialog box.
1046 * \param [in] w_current The GSCHEM_TOPLEVEL object.
1047 * \param [in] x Current x coordinate of pointer in screen units.
1048 * \param [in] y Current x coordinate of pointer in screen units.
1050 void o_arc_end3(GSCHEM_TOPLEVEL
*w_current
, int x
, int y
)
1052 TOPLEVEL
*toplevel
= w_current
->toplevel
;
1053 double d
, dx
, dy
, cos_a_
, sin_a_
, a
;
1055 /* erase the previous temporary arc */
1056 o_arc_rubberarc_xor(w_current
);
1058 /* compute the end angle */
1059 dx
= ((double) x
) - ((double) w_current
->start_x
);
1060 dy
= - ((double) y
) + ((double) w_current
->start_y
);
1061 d
= sqrt((dx
* dx
) + (dy
* dy
));
1063 sin_a_
= dy
/ ((double) d
);
1064 cos_a_
= dx
/ ((double) d
);
1065 a
= asin(sin_a_
) * 180 / M_PI
;
1068 /* find the right quadrant */
1070 if(cos_a_
>= 0) a
= a
;
1073 if(cos_a_
>= 0) a
= 360 - a
;
1077 /* end angle in degree is in a */
1078 w_current
->loc_y
= (int) a
;
1080 /* create, initialize and link the new arc object */
1081 toplevel
->page_current
->object_tail
=
1082 o_arc_add(toplevel
, toplevel
->page_current
->object_tail
,
1083 OBJ_ARC
, w_current
->graphic_color
,
1084 w_current
->start_x
, w_current
->start_y
,
1085 w_current
->distance
,
1086 w_current
->loc_x
, w_current
->loc_y
);
1088 /* draw the new object */
1089 o_redraw_single(w_current
, toplevel
->page_current
->object_tail
);
1091 w_current
->start_x
= (-1);
1092 w_current
->start_y
= (-1);
1093 w_current
->last_x
= (-1);
1094 w_current
->last_y
= (-1);
1095 w_current
->loc_x
= -1;
1096 w_current
->loc_y
= -1;
1097 w_current
->distance
= -1;
1099 toplevel
->page_current
->CHANGED
= 1;
1101 o_undo_savestate(w_current
, UNDO_ALL
);
1105 /*! \brief Ends the process of arc input.
1106 * \par Function Description
1107 * The #o_arc_end4() function ends the process of the input of an arc.
1108 * <B>start_angle</B> and <B>end_angle</B> are the start and end angle of the
1109 * arc in degrees. The partial internal representation of the arc, i.e.
1110 * the center and the radius of the arc, are converted in world units.
1111 * A new object is created and linked to the object list.
1113 * \param [in] w_current The GSCHEM_TOPLEVEL object.
1114 * \param [in] start_angle Start of angle in degrees.
1115 * \param [in] end_angle End of angle in degrees.
1117 void o_arc_end4(GSCHEM_TOPLEVEL
*w_current
, int start_angle
, int end_angle
)
1119 TOPLEVEL
*toplevel
= w_current
->toplevel
;
1123 /* get the center in world coords */
1124 SCREENtoWORLD(toplevel
,
1125 w_current
->start_x
, w_current
->start_y
,
1128 /* get the radius in world coords */
1129 radius
= snap_grid(toplevel
, WORLDabs(toplevel
, w_current
->distance
));
1131 /* create, initialize and link the new arc object */
1132 toplevel
->page_current
->object_tail
=
1133 o_arc_add(toplevel
, toplevel
->page_current
->object_tail
,
1134 OBJ_ARC
, w_current
->graphic_color
,
1135 x1
, y1
, radius
, start_angle
, end_angle
);
1137 /* draw the new object */
1138 o_redraw_single(w_current
, toplevel
->page_current
->object_tail
);
1140 w_current
->start_x
= (-1);
1141 w_current
->start_y
= (-1);
1142 w_current
->last_x
= (-1);
1143 w_current
->last_y
= (-1);
1144 w_current
->loc_x
= -1;
1145 w_current
->loc_y
= -1;
1146 w_current
->distance
= -1;
1148 toplevel
->page_current
->CHANGED
= 1;
1150 o_undo_savestate(w_current
, UNDO_ALL
);
1154 /*! \brief Draw an arc using one angle modification.
1155 * \par Function Description
1156 * This function draws an arc according to its internal representation
1157 * and allows the modification of one of its angle. The start or end
1158 * angle of the arc is updated according to <B>whichone</B> with the angle
1159 * that the current pointer and the arc center are making with the horizontal.
1161 * The previous temporary arc is erased, the angle is then computed
1162 * and updated and finally a new temporary arc with the new angle is drawn.
1164 * The arc is internally described by :
1166 * <DT>*</DT><DD>(<B>w_current->start_x</B>,<B>w_current->start_y</B>) as
1168 * <DT>*</DT><DD><B>w_current->distance</B> as its radius.
1169 * <DT>*</DT><DD><B>w_current->loc_x</B> and <B>w_current->loc_y</B> as its
1170 * start and end angle respectively.
1173 * \param [in] w_current The GSCHEM_TOPLEVEL object.
1174 * \param [in] x Current x coordinate of pointer in screen units.
1175 * \param [in] y Current y coordinate of pointer in screen units.
1176 * \param [in] whichone Which angle to change.
1178 * <B>whichone</B> can have one of the following values:
1180 * <DT>*</DT><DD>ARC_START_ANGLE
1181 * <DT>*</DT><DD>ARC_END_ANGLE
1184 void o_arc_rubberarc(GSCHEM_TOPLEVEL
*w_current
, int x
, int y
, int whichone
)
1186 TOPLEVEL
*toplevel
= w_current
->toplevel
;
1190 /* erase the previous temporary arc */
1191 o_arc_rubberarc_xor(w_current
);
1193 if(whichone
== ARC_RADIUS
) {
1196 * The radius is taken as the biggest distance on the x and y
1197 * axis between the center of the arc and the mouse position.
1199 /* update the radius */
1200 w_current
->last_x
= fix_x(toplevel
, x
);
1201 w_current
->last_y
= fix_y(toplevel
, y
);
1203 diff_x
= GET_BOX_WIDTH (w_current
);
1204 diff_y
= GET_BOX_HEIGHT(w_current
);
1205 if (diff_x
>= diff_y
) {
1206 w_current
->distance
= diff_x
;
1208 w_current
->distance
= diff_y
;
1212 else if((whichone
== ARC_START_ANGLE
) || (whichone
== ARC_END_ANGLE
)) {
1214 /* compute the angle */
1215 dx
= ((double) x
) - ((double) w_current
->start_x
);
1216 dy
= - ((double) y
) + ((double) w_current
->start_y
);
1217 a
= atan2(dy
,dx
) * 180 / M_PI
;
1219 /* set the start or end angle with this angle */
1221 case ARC_START_ANGLE
:
1222 w_current
->loc_x
= ((int) a
+ 360) % 360;
1226 w_current
->loc_y
= ((int) a
- w_current
->loc_x
+ 720) % 360;
1235 /* draw the new temporary arc */
1236 o_arc_rubberarc_xor(w_current
);
1240 /*! \brief Draw arc from GSCHEM_TOPLEVEL object.
1241 * \par Function Description
1242 * This function draws the arc from the variables in the GSCHEM_TOPLEVEL
1243 * structure <B>*w_current</B>.
1244 * The center of the arc is at (<B>w_current->start_x</B>,
1245 * <B>w_current->start_y</B>), its radius equal to <B>w_current->radius</B>,
1246 * and the start and end angle are given by <B>w_current->loc_x</B> and
1247 * <B>w_current->loc_y</B>.
1249 * The arc is drawn with a xor function over the current sheet with the
1252 * \param [in] w_current The GSCHEM_TOPLEVEL object.
1254 void o_arc_rubberarc_xor(GSCHEM_TOPLEVEL
*w_current
)
1259 gdk_gc_set_foreground(w_current
->xor_gc
,
1260 x_get_darkcolor(w_current
->select_color
));
1261 gdk_gc_set_line_attributes(w_current
->xor_gc
, 0,
1262 GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
,
1264 /* draw the arc from the w_current variables */
1265 gdk_draw_arc(w_current
->backingstore
, w_current
->xor_gc
, FALSE
,
1266 w_current
->start_x
- w_current
->distance
,
1267 w_current
->start_y
- w_current
->distance
,
1268 w_current
->distance
* 2,
1269 w_current
->distance
* 2,
1270 w_current
->loc_x
* 64,
1271 w_current
->loc_y
* 64);
1272 /* draw the radius segment from the w_current variables */
1273 tmp
= ((double) w_current
->loc_x
) * M_PI
/ 180;
1274 x1
= w_current
->start_x
+ w_current
->distance
*cos(tmp
);
1275 y1
= w_current
->start_y
- w_current
->distance
*sin(tmp
);
1276 gdk_draw_line(w_current
->backingstore
, w_current
->xor_gc
,
1277 w_current
->start_x
, w_current
->start_y
,
1279 /* FIXME: This isn't a tight bounding box for now, but the code
1280 * to compute a better bounds it complex, and might wait
1281 * until we're considered having real OBJECT data during
1282 * rubberbanding and using world_get_arc_bounds().
1284 o_invalidate_rect(w_current
, w_current
->start_x
- w_current
->distance
,
1285 w_current
->start_y
- w_current
->distance
,
1286 w_current
->start_x
+ w_current
->distance
,
1287 w_current
->start_y
+ w_current
->distance
);
1290 /*! \brief Draw grip marks on arc.
1291 * \par Function Description
1292 * This function draws three grips on the center and on the ends of
1293 * the arc object described by <B>*o_current</B>.
1295 * \param [in] w_current The GSCHE_TOPLEVEL object.
1296 * \param [in] o_current Arc OBJECT to draw grip points on.
1298 void o_arc_draw_grips(GSCHEM_TOPLEVEL
*w_current
, OBJECT
*o_current
)
1300 TOPLEVEL
*toplevel
= w_current
->toplevel
;
1301 int radius
, x
, y
, start_angle
, end_angle
;
1304 if (w_current
->draw_grips
== FALSE
)
1308 * An arc has three grips:
1310 * <DT>*</DT><DD>one at the center that allows changes on the
1311 * radius - at (<B>x</B>,<B>y</B>).
1312 * <DT>*</DT><DD>one at the start of the arc - at (<B>x1</B>,<B>y1</B>).
1313 * <DT>*</DT><DD>one at the end of the arc - at (<B>x2</B>,<B>y2</B>).
1316 WORLDtoSCREEN( toplevel
, o_current
->arc
->x
, o_current
->arc
->y
, &x
, &y
);
1317 radius
= SCREENabs( toplevel
, o_current
->arc
->width
/ 2 );
1318 start_angle
= o_current
->arc
->start_angle
;
1319 end_angle
= o_current
->arc
->end_angle
;
1321 x1
= x
+ radius
* cos(((double) start_angle
) * M_PI
/ 180);
1322 y1
= y
- radius
* sin(((double) start_angle
) * M_PI
/ 180);
1323 x2
= x
+ radius
* cos(((double) (start_angle
+ end_angle
)) * M_PI
/ 180);
1324 y2
= y
- radius
* sin(((double) (start_angle
+ end_angle
)) * M_PI
/ 180);
1326 /* draw the grip at the center */
1327 o_grips_draw(w_current
, x
, y
);
1329 /* draw the grip at the start_angle end of the arc */
1330 o_grips_draw(w_current
, x1
, y1
);
1332 /* draw the grip at the end_angle end of the arc */
1333 o_grips_draw(w_current
, x2
, y2
);
1337 /*! \brief Erase grip marks from arc.
1338 * \par Function Description
1339 * This function erases the three grips displayed on the <B>o_current</B>
1340 * arc object. These grips are on the center of the arc and on each end
1343 * \param [in] w_current The GSCHEM_TOPLEVEL object.
1344 * \param [in] o_current Arc OBJECT to remove grip marks from.
1346 void o_arc_erase_grips(GSCHEM_TOPLEVEL
*w_current
, OBJECT
*o_current
)
1348 TOPLEVEL
*toplevel
= w_current
->toplevel
;
1349 int radius
, x
, y
, start_angle
, end_angle
;
1352 if (w_current
->draw_grips
== FALSE
)
1356 * The coordinates of the three grips are determined by the parameters
1357 * of the arc. The grips are centered at (<B>x</B>,<B>y</B>), (<B>x1</B>,<B>y1</B>)
1358 * and (<B>x2</B>,<B>y2</B>).
1361 WORLDtoSCREEN( toplevel
, o_current
->arc
->x
, o_current
->arc
->y
, &x
, &y
);
1362 radius
= SCREENabs( toplevel
, o_current
->arc
->width
/ 2 );
1363 start_angle
= o_current
->arc
->start_angle
;
1364 end_angle
= o_current
->arc
->end_angle
;
1366 x1
= x
+ radius
* cos(((double) start_angle
) * M_PI
/ 180);
1367 y1
= y
- radius
* sin(((double) start_angle
) * M_PI
/ 180);
1368 x2
= x
+ radius
* cos(((double) start_angle
+ end_angle
) * M_PI
/ 180);
1369 y2
= y
- radius
* sin(((double) start_angle
+ end_angle
) * M_PI
/ 180);
1371 /* erase the grip at the center */
1372 o_grips_erase(w_current
, x
, y
);
1374 /* erase the grip at the start_angle end of the arc */
1375 o_grips_erase(w_current
, x1
, y1
);
1377 /* erase the grip at the end_angle end of the arc */
1378 o_grips_erase(w_current
, x2
, y2
);