1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
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
21 /*! \file o_arc_basic.c
22 * \brief functions for the arc object
30 #include "libgeda_priv.h"
32 #ifdef HAVE_LIBDMALLOC
46 static OBJECT
*o_arc_copy(TOPLEVEL
*toplevel
, OBJECT
*o_current
);
47 static void o_arc_recalc(OBJECT
*o_current
);
48 static void o_arc_grip_foreach(OBJECT
*o
,
49 gboolean (*fn
)(OBJECT
*o
,
50 int grip_x
, int grip_y
,
54 static int o_arc_grip_move(OBJECT
*o
, int whichone
, int x
, int y
);
56 /*! Default setting for arc draw function. */
57 void (*arc_draw_func
)() = NULL
;
59 /*! \brief Create a minimal consistent-state arc.
60 * \par Function Description
61 * Creates an arc at a given position but does not add it to the object list.
63 * \param [in] toplevel The TOPLEVEL environment.
64 * \param [in] type The object type (OBJ_ARC).
65 * \param [in] color The "main" color of the arc.
66 * \param [in] x The world X coordinate of the arc's origin.
67 * \param [in] y The world Y coordinate of the arc's origin.
68 * \return A pointer to the newly created OBJECT.
70 OBJECT
*o_arc_new_at_xy(TOPLEVEL
*toplevel
, char type
, int color
, int x
, int y
)
75 /* create the object */
76 new_node
= s_toplevel_new_object(toplevel
, type
, "arc");
77 new_node
->color
= color
;
79 arc
= g_malloc(sizeof (ARC
));
84 /* Placate valgrind. */
85 new_node
->arc
->width
= 0;
86 new_node
->arc
->height
= 0;
87 new_node
->arc
->start_angle
= 0;
88 new_node
->arc
->end_angle
= 0;
90 new_node
->copy_func
= &o_arc_copy
;
91 new_node
->bounds_recalc_func
= o_arc_recalc
;
92 new_node
->draw_func
= arc_draw_func
;
93 new_node
->psprint_func
= &o_arc_print
;
94 new_node
->grip_foreach_func
= &o_arc_grip_foreach
;
95 new_node
->grip_move_func
= &o_arc_grip_move
;
98 o_set_line_options(new_node
, END_NONE
, TYPE_SOLID
, 0, -1, -1);
99 o_set_fill_options(new_node
, FILLING_HOLLOW
, -1, -1, -1, -1, -1);
101 o_arc_recalc(new_node
);
107 * \par Function Description
108 * The function creates a new OBJECT of type arc.
110 * The arc is defined by its center in parameters x and y.
111 * The radius parameter specifies the radius of the arc. The start
112 * angle is given by start_angle and the end angle by end_angle.
113 * The line and fill type of the created arc are set to default.
115 * All dimensions are in world unit, except start_angle and
116 * end_angle in degrees.
118 * A new object of type OBJECT is allocated. Its type and color
119 * are initilized. The description of the arc characteristics
120 * are stored in a new ARC structure.
122 * Now fixed for world coordinates.
124 * \param [in] toplevel The TOPLEVEL object.
130 * \param [in] start_angle
131 * \param [in] end_angle
134 OBJECT
*o_arc_new(TOPLEVEL
*toplevel
,
135 char type
, int color
,
136 int x
, int y
, int radius
, int start_angle
, int end_angle
)
140 new_node
= o_arc_new_at_xy(toplevel
, type
, color
, x
, y
);
143 * The ARC structure is initialized with the parameters.
144 * A default initialization is performed for the line and
145 * fill type to avoid misunderstanding.
147 * The functions relative to the use of the object are sets.
150 /* World coordinates */
151 new_node
->arc
->width
= 2 * radius
;
152 new_node
->arc
->height
= 2 * radius
;
154 /* PB : must check the sign of start_angle, end_angle ... */
156 start_angle
= start_angle
+ end_angle
;
157 end_angle
= -end_angle
;
159 if(start_angle
< 0) start_angle
= 360 + start_angle
;
161 new_node
->arc
->start_angle
= start_angle
;
162 new_node
->arc
->end_angle
= end_angle
;
164 /* new_node->graphical = arc; eventually */
170 * \par Function Description
171 * This function creates a new object representing an arc.
173 * The values of the <B>o_current</B> pointed OBJECT are then copied to the new object.
175 * The arc, the line options are initialized whereas the fill options are
176 * initialized to passive values - as an arc can not be filled.
178 * \param [in] toplevel The TOPLEVEL object
179 * \param [in] o_current
180 * \return The new OBJECT
182 static OBJECT
*o_arc_copy(TOPLEVEL
*toplevel
, OBJECT
*o_current
)
187 if (o_current
->saved_color
== -1) {
188 color
= o_current
->color
;
190 color
= o_current
->saved_color
;
193 new_obj
= o_arc_new (toplevel
, OBJ_ARC
, color
,
194 o_current
->arc
->x
, o_current
->arc
->y
,
195 o_current
->arc
->width
/ 2,
196 o_current
->arc
->start_angle
,
197 o_current
->arc
->end_angle
);
198 o_set_line_options(new_obj
,
199 o_current
->line_end
, o_current
->line_type
,
200 o_current
->line_width
,
201 o_current
->line_length
, o_current
->line_space
);
202 o_set_fill_options(new_obj
, FILLING_HOLLOW
, -1, -1, -1, -1, -1);
208 * \par Function Description
209 * This function reads a formatted text buffer describing an arc
210 * in the gEDA file format and initializes the corresponding object.
211 * Depending on the version of the file format the data extraction is
212 * performed differently : currently pre-20000704 and 20000704 on one
213 * hand and post-20000704 file format version on the other hand are supported.
214 * The version is specified in string pointed by <B>fileformat_ver</B>.
216 * To get information on the various file formats have a
217 * look to the fileformats.html document.
219 * The object is initialized with the functions #o_set_line_options() and #o_set_fill_options().
220 * The second one is only used to put initialize unused values for an arc as an arc can not be filled.
222 * The arc is allocated initialized with the function #o_arc_new().
224 * A negative or null radius is not allowed.
226 * \param [in] toplevel The TOPLEVEL object.
228 * \param [in] release_ver
229 * \param [in] fileformat_ver
232 OBJECT
*o_arc_read(TOPLEVEL
*toplevel
, char buf
[],
233 unsigned int release_ver
, unsigned int fileformat_ver
)
239 int start_angle
, end_angle
;
241 int arc_width
, arc_length
, arc_space
;
246 * Depending on the version of the file format used to describe this arc,
247 * the buffer is parsed differently. The unknown parameters of the less
248 * restrictive - the oldest - file format are set to common values
250 if(release_ver
<= VERSION_20000704
) {
251 sscanf(buf
, "%c %d %d %d %d %d %d", &type
,
252 &x1
, &y1
, &radius
, &start_angle
, &end_angle
, &color
);
256 arc_type
= TYPE_SOLID
;
260 sscanf(buf
, "%c %d %d %d %d %d %d %d %d %d %d %d", &type
,
261 &x1
, &y1
, &radius
, &start_angle
, &end_angle
, &color
,
262 &arc_width
, &arc_end
, &arc_type
, &arc_length
, &arc_space
);
268 s_log_message (_("Found a zero radius arc [ %c %d, %d, %d, %d, %d, %d ]\n"),
269 type
, x1
, y1
, radius
, start_angle
, end_angle
, color
);
272 if (color
< 0 || color
> MAX_COLORS
) {
273 s_log_message(_("Found an invalid color [ %s ]\n"), buf
);
274 s_log_message(_("Setting color to WHITE\n"));
278 /* Allocation and initialization */
279 new_obj
= o_arc_new(toplevel
, OBJ_ARC
, color
,
280 x1
, y1
, radius
, start_angle
, end_angle
);
281 o_set_line_options(new_obj
,
282 arc_end
, arc_type
, arc_width
, arc_length
,
284 o_set_fill_options(new_obj
, FILLING_HOLLOW
, -1, -1, -1, -1, -1);
290 * \par Function Description
291 * This function formats a string in the buffer <B>*buff</B> to describe
292 * the arc object <B>*object</B>.
293 * It follows the post-20000704 release file format that handle the
294 * line type and filling options.
295 * A pointer to the new allocated and formated string is returned.
296 * The string must be freed at some point.
301 * \todo EEK! there is a nasty non-snap bug here!
302 * Basically the center isn't being snapped
303 * in complex objects only it seems...
305 char *o_arc_save(OBJECT
*object
)
308 int x
, y
, radius
, start_angle
, end_angle
;
309 int arc_width
, arc_length
, arc_space
;
312 OBJECT_TYPE arc_type
;
314 /* radius, center and angles of the arc */
315 radius
= object
->arc
->width
/ 2;
318 start_angle
= object
->arc
->start_angle
;
319 end_angle
= object
->arc
->end_angle
;
321 /* line type parameters */
322 arc_width
= object
->line_width
;
323 arc_end
= object
->line_end
;
324 arc_type
= object
->line_type
;
325 arc_length
= object
->line_length
;
326 arc_space
= object
->line_space
;
328 /* Save the right color */
329 if (object
->saved_color
== -1) {
330 color
= object
->color
;
332 color
= object
->saved_color
;
335 /* Describe a circle with post-20000704 file format */
336 buf
= g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d", object
->type
,
337 x
, y
, radius
, start_angle
, end_angle
, color
,
338 arc_width
, arc_end
, arc_type
, arc_length
, arc_space
);
344 * \par Function Description
345 * This function applies a translation of (<B>dx</B>,<B>dy</B>)
346 * to the arc described in <B>*object</B>. <B>dx</B> and <B>dy</B> are in world unit.
352 void o_arc_translate_world(int dx
, int dy
, OBJECT
*object
)
354 if (object
== NULL
) {
358 /* Do world coords */
359 object
->arc
->x
= object
->arc
->x
+ dx
;
360 object
->arc
->y
= object
->arc
->y
+ dy
;
363 /* Recalculate screen coords from new world coords */
364 o_arc_recalc(object
);
368 * \par Function Description
369 * This function rotates the world coordinates of an arc of an angle
370 * specified by <B>angle</B>. The center of the rotation is given by
371 * (<B>world_centerx</B>,<B>world_centery</B>).
373 * The arc is translated in order to put the center of the rotation
374 * on the origin. The center of the arc is then rotated of the angle
375 * specified by <B>angle</B>. The start angle of the arc is incremented by <B>angle</B>.
377 * The arc is finally back translated to its previous location on the page.
379 * <B>world_centerx</B> and <B>world_centery</B> are in world units, <B>angle</B> is in degrees.
381 * \param [in] world_centerx
382 * \param [in] world_centery
386 void o_arc_rotate_world(int world_centerx
, int world_centery
, int angle
,
389 int x
, y
, newx
, newy
;
391 /* translate object to origin */
392 object
->arc
->x
-= world_centerx
;
393 object
->arc
->y
-= world_centery
;
395 /* get center, and rotate center */
398 if(angle
% 90 == 0) {
399 rotate_point_90(x
, y
, angle
% 360, &newx
, &newy
);
401 rotate_point(x
, y
, angle
% 360, &newx
, &newy
);
403 object
->arc
->x
= newx
;
404 object
->arc
->y
= newy
;
406 /* apply rotation to angles */
407 object
->arc
->start_angle
= (object
->arc
->start_angle
+ angle
) % 360;
408 /* end_angle is unchanged as it is the sweep of the arc */
409 /* object->arc->end_angle = (object->arc->end_angle); */
411 /* translate object to its previous place */
412 object
->arc
->x
+= world_centerx
;
413 object
->arc
->y
+= world_centery
;
415 /* update the screen coords and the bounding box */
416 o_arc_recalc(object
);
420 /*! \brief Mirror the WORLD coordinates of an ARC.
421 * \par Function Description
422 * This function mirrors the world coordinates of an arc.
423 * The symmetry axis is given by the vertical line going through the point (<B>world_centerx</B>,<B>world_centery</B>).
425 * The arc is translated in order to put the point (<B>world_centerx</B>,<B>world_centery</B>)
426 * on the origin. The center of the arc is then mirrored. The start angle of the arc
427 * and the sweep of the arc are also mirrored.
429 * The arc is finally back translated to its previous location on the page.
431 * \param [in] world_centerx
432 * \param [in] world_centery
435 void o_arc_mirror_world(int world_centerx
, int world_centery
,
438 /* translate object to origin */
439 object
->arc
->x
-= world_centerx
;
440 object
->arc
->y
-= world_centery
;
442 /* get center, and mirror it (vertical mirror) */
443 object
->arc
->x
= -object
->arc
->x
;
444 object
->arc
->y
= object
->arc
->y
;
446 /* apply mirror to angles (vertical mirror) */
447 object
->arc
->start_angle
= (180 - object
->arc
->start_angle
) % 360;
448 /* pb20011125 - start_angle *MUST* be positive */
449 if(object
->arc
->start_angle
< 0) object
->arc
->start_angle
+= 360;
450 object
->arc
->end_angle
= -object
->arc
->end_angle
;
452 /* translate object back to its previous position */
453 object
->arc
->x
+= world_centerx
;
454 object
->arc
->y
+= world_centery
;
456 /* update the screen coords and bounding box */
457 o_arc_recalc(object
);
460 int o_arc_get_radius(OBJECT
const *o_current
)
462 return (o_current
->arc
->width
/ 2);
465 int o_arc_get_start_angle(OBJECT
const *o_current
)
467 return (o_current
->arc
->start_angle
);
470 int o_arc_get_end_angle(OBJECT
const *o_current
)
472 return (o_current
->arc
->end_angle
);
475 void o_arc_set_radius(OBJECT
*o_current
, int radius
)
477 o_current
->arc
->width
= radius
* 2;
479 /* update the screen coords and bounding box */
480 o_arc_recalc(o_current
);
483 void o_arc_set_start_angle(OBJECT
*o_current
, int angle
)
485 o_current
->arc
->start_angle
= angle
;
487 /* update the screen coords and bounding box */
488 o_arc_recalc(o_current
);
491 void o_arc_set_end_angle(OBJECT
*o_current
, int angle
)
493 o_current
->arc
->end_angle
= angle
;
495 /* update the screen coords and bounding box */
496 o_arc_recalc(o_current
);
500 * \par Function Description
501 * This function recalculates internal parameters in screen units
502 * of an object containing an arc. The object is given as parameters <B>o_current</B>.
503 * The calculation is done according to the zoom factor detailed in the <B>toplevel</B>
505 * It also recalculates the <B>OBJECT</B> specific fields and the bounding box of the arc.
507 * The bounding box - in world units - is recalculated with the <B>world_get_arc_bounds()</B> function.
509 * \param [in] o_current
511 static void o_arc_recalc(OBJECT
*o_current
)
513 int left
, right
, top
, bottom
;
515 if (o_current
->arc
== NULL
) {
519 /* recalculates the bounding box */
520 world_get_arc_bounds(o_current
, &left
, &top
, &right
, &bottom
);
521 o_current
->w_left
= left
;
522 o_current
->w_top
= top
;
523 o_current
->w_right
= right
;
524 o_current
->w_bottom
= bottom
;
525 o_current
->w_bounds_valid
= TRUE
;
528 static void o_arc_grip_foreach(OBJECT
*o
,
529 gboolean (*fn
)(OBJECT
*o
,
530 int grip_x
, int grip_y
,
531 enum grip_t whichone
,
535 int centerx
= o
->arc
->x
;
536 int centery
= o
->arc
->y
;
537 int radius
= o
->arc
->width
/ 2;
538 double start_angle
= o
->arc
->start_angle
* M_PI
/ 180;
539 double end_angle
= start_angle
+ o
->arc
->end_angle
* M_PI
/ 180;
541 const GRIP arc_grips
[] = {
545 .whichone
= GRIP_ARC_CENTER
,
550 .whichone
= GRIP_ARC_RADIUS
,
553 .x
= centerx
+ radius
* cos(start_angle
),
554 .y
= centery
+ radius
* sin(start_angle
),
555 .whichone
= GRIP_START_ANGLE
,
558 .x
= centerx
+ radius
* cos(end_angle
),
559 .y
= centery
+ radius
* sin(end_angle
),
560 .whichone
= GRIP_END_ANGLE
,
562 { .whichone
= GRIP_NONE
}
565 s_basic_grip_foreach_helper(o
, arc_grips
, fn
, userdata
);
568 static int o_arc_grip_move(OBJECT
*o
, int whichone
, int x
, int y
)
570 int retval
= whichone
;
573 double radius
, theta
, r_cos_theta
, r_sin_theta
;
579 o
->arc
->start_angle
= 0;
580 o
->arc
->end_angle
= 180;
581 retval
= GRIP_ARC_RADIUS
;
584 case GRIP_ARC_CENTER
:
587 retval
= GRIP_ARC_RADIUS
;
589 case GRIP_ARC_RADIUS
:
590 r_cos_theta
= x
- o
->arc
->x
;
591 r_sin_theta
= y
- o
->arc
->y
;
592 radius
= sqrt(r_cos_theta
*r_cos_theta
+ r_sin_theta
*r_sin_theta
);
593 o
->arc
->width
= o
->arc
->height
= rint(radius
* 2);
594 retval
= GRIP_START_ANGLE
;
596 case GRIP_START_ANGLE
:
598 r_cos_theta
= x
- o
->arc
->x
;
599 r_sin_theta
= y
- o
->arc
->y
;
600 radius
= sqrt(r_cos_theta
*r_cos_theta
+ r_sin_theta
*r_sin_theta
);
601 theta
= atan2(r_sin_theta
/ radius
, r_cos_theta
/ radius
);
607 case GRIP_START_ANGLE
:
608 o
->arc
->start_angle
= rint(theta
);
609 retval
= GRIP_END_ANGLE
;
612 theta
-= o
->arc
->start_angle
;
616 o
->arc
->end_angle
= rint(theta
);
629 * \par Function Description
630 * This function calculates the smallest rectangle the arc can be drawn into.
631 * The <B>OBJECT</B> pointed by object is assumed to be an arc.
632 * The <B>left</B>, <B>top</B>, <B>right</B> and <B>bottom</B> pointed integers define
633 * this rectangle at the end of the function. It is expressed in world units.
634 * The process is divided into two steps : the first step is to calculate the
635 * coordinates of the two ends of the arc and the coordinates of the center.
636 * They forms a first rectangle but (depending on the start angle and the
637 * sweep of the arc) not the right.
639 * \param [in] toplevel The TOPLEVEL object.
644 * \param [out] bottom
646 void world_get_arc_bounds(OBJECT
*object
, int *left
,
647 int *top
, int *right
, int *bottom
)
649 int x1
, y1
, x2
, y2
, x3
, y3
;
650 int radius
, start_angle
, end_angle
;
654 halfwidth
= object
->line_width
/ 2;
656 radius
= object
->arc
->width
/ 2;
657 start_angle
= object
->arc
->start_angle
% 360;
658 end_angle
= object
->arc
->end_angle
% 360;
662 x2
= x1
+ radius
* cos(start_angle
* M_PI
/ 180);
663 y2
= y1
+ radius
* sin(start_angle
* M_PI
/ 180);
664 x3
= x1
+ radius
* cos((start_angle
+ end_angle
) * M_PI
/ 180);
665 y3
= y1
+ radius
* sin((start_angle
+ end_angle
) * M_PI
/ 180);
667 *left
= (x1
< x2
) ? ((x1
< x3
) ? x1
: x3
) : ((x2
< x3
) ? x2
: x3
);
668 *right
= (x1
> x2
) ? ((x1
> x3
) ? x1
: x3
) : ((x2
> x3
) ? x2
: x3
);
669 *bottom
= (y1
> y2
) ? ((y1
> y3
) ? y1
: y3
) : ((y2
> y3
) ? y2
: y3
);
670 *top
= (y1
< y2
) ? ((y1
< y3
) ? y1
: y3
) : ((y2
< y3
) ? y2
: y3
);
673 * The previous rectangle is extended to the final one
674 * by checking whether the arc is over a main axis (vertical or horizontal).
675 * If so, the rectangle is extended in these directions.
677 * In the mirror mode, the sweep angle is negative. To get a
678 * CCW arc before this calculation we have to move the
679 * start angle to the end angle and reverse the sweep angle.
682 start_angle
= (start_angle
+ end_angle
+ 360) % 360;
683 end_angle
= -end_angle
;
685 angle
= ((int) (start_angle
/ 90)) * 90;
686 for(i
= 0; i
< 4; i
++) {
688 if(angle
< start_angle
+ end_angle
) {
689 if(angle
% 360 == 0) *right
= x1
+ radius
;
690 if(angle
% 360 == 90) *bottom
= y1
+ radius
;
691 if(angle
% 360 == 180) *left
= x1
- radius
;
692 if(angle
% 360 == 270) *top
= y1
- radius
;
698 /* This isn't strictly correct, but a 1st order approximation */
702 *bottom
+= halfwidth
;
708 * \par Function Description
709 * This function writes in a postscript file the arc described by
710 * the <B>o_current</B> pointed object.
711 * The postscript resulting file is described by the <B>fp</B> file pointer.
713 * Parameters of the arc are extracted from object pointed by <B>o_current</B>
714 * and formatted to suit future calls to specialized arc printing functions.
716 * \param [in] toplevel The TOPLEVEL object.
717 * \param [in] fp The postscript document to print to.
718 * \param [in] o_current
720 void o_arc_print(TOPLEVEL
*toplevel
, FILE *fp
, OBJECT
*o_current
,
721 double scale
, int unicode_count
, gunichar
*unicode_table
)
723 int x
, y
, radius
, start_angle
, end_angle
;
725 int arc_width
, space
, length
;
726 void (*outl_func
)(TOPLEVEL
*toplevel
, FILE *fp
,
727 int x
, int y
, int radius
,
728 int angle1
, int angle2
,
730 int arc_width
, int length
, int space
) = NULL
;
732 if (o_current
== NULL
) {
733 printf("got null in o_arc_print\n");
737 x
= o_current
->arc
->x
;
738 y
= o_current
->arc
->y
;
739 radius
= o_current
->arc
->width
/ 2;
740 start_angle
= o_current
->arc
->start_angle
;
741 end_angle
= o_current
->arc
->end_angle
;
742 color
= o_current
->color
;
745 * Depending on the type of the line for this particular arc, the
746 * appropriate function is chosen among #o_arc_print_solid(),
747 * #o_arc_print_dotted(), #o_arc_print_dashed(), #o_arc_print_center() and #o_arc_print_phantom().
749 * The needed parameters for each of these types are extracted from the <B>o_current</B> object.
750 * Depending on the type, unused parameters are set to -1.
752 * In the eventuality of a length and/or space null, the arc is printed solid to avoid and
753 * endless loop produced by other functions.
756 #if 0 /* was causing arcs which are solid to be much thinner compared to */
757 /* lines, boxes, also of zero width */
758 if (o_current
->line_width
> 0) {
759 arc_width
= o_current
->line_width
;
764 arc_width
= o_current
->line_width
; /* Added instead of above */
766 if(toplevel
->line_style
== THICK
) {
767 arc_width
=LINE_WIDTH
;
773 length
= o_current
->line_length
;
774 space
= o_current
->line_space
;
776 switch(o_current
->line_type
) {
778 length
= -1; space
= -1;
779 outl_func
= o_arc_print_solid
;
784 outl_func
= o_arc_print_dotted
;
788 outl_func
= o_arc_print_dashed
;
792 outl_func
= o_arc_print_center
;
796 outl_func
= o_arc_print_phantom
;
800 /* Unused for now, print it solid */
801 length
= -1; space
= -1;
802 outl_func
= o_arc_print_solid
;
806 if((space
== 0) || (length
== 0)) {
807 length
= -1; space
= -1;
808 outl_func
= o_arc_print_solid
;
811 (*outl_func
)(toplevel
, fp
,
813 start_angle
, end_angle
,
814 color
, arc_width
, length
, space
);
819 * \par Function Description
820 * This function prints an arc when a solid line type is required.
821 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
822 * in <B>radius</B> and the start and end angles of the arc on the circle.
823 * The postscript file is defined by the file pointer <B>fp</B>.
825 * The parameters <B>length</B> and <B>space</B> are ignored
826 * whereas <B>arc_width</B> specifies the width of the printed line.
828 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
830 * \param [in] toplevel The TOPLEVEL object.
831 * \param [in] fp FILE pointer to postscript document.
838 * \param [in] arc_width
842 void o_arc_print_solid(TOPLEVEL
*toplevel
, FILE *fp
,
843 int x
, int y
, int radius
,
844 int angle1
, int angle2
,
846 int arc_width
, int length
, int space
)
848 if (toplevel
->print_color
) {
849 f_print_set_color(fp
, color
);
852 /* PB/AVH inverting angle2 if < 0 and changing angle1 accordingly */
854 angle1
= angle1
+ angle2
;
858 fprintf(fp
, "%d %d %d %d %d %d darc\n",
859 x
,y
, radius
, angle1
, angle1
+ angle2
,
865 * \par Function Description
866 * This function prints an arc when a dotted line type is required.
867 * The arc is defined by its center in <B>x</B> and <B>y</B>, its
868 * radius in <B>radius</B> and the start and end angles of the arc on the circle.
869 * The postscript file is defined by the file pointer <B>fp</B>.
870 * The parameter <B>length</B> is ignored whereas <B>arc_width</B> specifies
871 * the diameter of the dots of the printed line and <B>space</B> the distance
874 * A negative value for <B>space</B> leads to an endless loop.
876 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
878 * The function sets the color the line will be printed with.
880 * \param [in] toplevel The TOPLEVEL object.
881 * \param [in] fp FILE pointer to postscript document.
888 * \param [in] arc_width
892 void o_arc_print_dotted(TOPLEVEL
*toplevel
, FILE *fp
,
893 int x
, int y
, int radius
,
894 int angle1
, int angle2
,
896 int arc_width
, int length
, int space
)
901 if (toplevel
->print_color
) {
902 f_print_set_color(fp
, color
);
906 * Depending on the radius of the arc, the <B>space</B> parameter is
907 * changed into a small angle <B>da</B>.
908 * Starting from <B>angle1</B> - the start angle - the dots are printed
909 * along the arc by increments of this new angle.
911 * As <B>da</B> is rounded as an integer, it can take a null value which
912 * will make the function enter an endless loop. In such a case, the arc
913 * is printed solid. The <B>da</B> variable should never be negative
914 * except if <B>space</B> is negative.
917 /* Inverting angle2 if < 0 and changing angle1 accordingly */
918 /* the loop test assume that da > 0 */
920 angle1
= angle1
+ angle2
;
923 da
= (int) ((space
* 180) / (M_PI
* ((double) radius
)));
925 /* If da or db too small for arc to be displayed as dotted,
928 o_arc_print_solid(toplevel
, fp
,
932 arc_width
, length
, space
);
938 while (d
< (angle2
+ angle1
)) {
939 /*xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
940 ya = ((double) y) + ((double) radius) * sin(d * M_PI / 180);
942 fprintf(fp
,"[%d] ",d
);
946 fprintf(fp
,"] %d %d %d %d dashedarc %% dotted\n",
947 x
,y
, radius
, arc_width
);
951 * \par Function Description
952 * This function prints an arc when a dashed line type is required.
953 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
954 * in <B>radius</B> and the start and end angles of the arc on the circle.
955 * The postscript file is defined by the file pointer <B>fp</B>.
956 * The parameter <B>arc_width</B> specifies the diameter of the dots of the printed line.
958 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
960 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
962 * The function sets the color the line will be printed with.
964 * \param [in] toplevel The TOPLEVEL object.
965 * \param [in] fp FILE pointer to postscript document.
972 * \param [in] arc_width
976 void o_arc_print_dashed(TOPLEVEL
*toplevel
, FILE *fp
,
977 int x
, int y
, int radius
,
978 int angle1
, int angle2
,
980 int arc_width
, int length
, int space
)
984 if (toplevel
->print_color
) {
985 f_print_set_color(fp
, color
);
989 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
990 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
991 * Starting from <B>angle1</B> - the start angle - the dashes are printed
992 * along the arc by increments of these new angles.
994 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a
995 * null value which will make the function enter an endless loop. In such a case,
996 * the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable should never
997 * be negative except if <B>space</B> (resp. <B>length</B>) is negative.
999 * It prints as many dashes of length <B>length</B> as possible.
1002 /* Inverting angle2 if < 0 and changing angle1 accordingly */
1003 /* the loop test assume that da > 0 */
1005 angle1
= angle1
+ angle2
;
1008 da
= (int) ((length
* 180) / (M_PI
* ((double) radius
)));
1009 db
= (int) ((space
* 180) / (M_PI
* ((double) radius
)));
1011 /* If da or db too small for arc to be displayed as dotted,
1013 if ((da
<= 0) || (db
<= 0)) {
1014 o_arc_print_solid(toplevel
, fp
,
1018 arc_width
, length
, space
);
1024 while ((d
+ da
+ db
) < (angle1
+ angle2
)) {
1028 fprintf(fp
,"[%d %d] ",
1034 * When the above condition is no more satisfied, then it is not
1035 * possible to print a dash of length <B>length</B> and the following <B>space</B>.
1036 * However it may be possible to print the complete dash or a shorter one.
1039 if ((d
+ da
) < (angle1
+ angle2
)) {
1045 fprintf(fp
,"[%d %d] ",
1049 fprintf(fp
,"] %d %d %d %d dashedarc %% dashed\n",
1050 x
,y
, radius
, arc_width
);
1054 * \par Function Description
1055 * This function prints an arc when a centered line type is required.
1056 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius in
1057 * <B>radius</B> and the start and end angles of the arc on the circle.
1058 * The postscript file is defined by the file pointer <B>fp</B>.
1059 * The parameter <B>arc_width</B> specifies the diameter of the dots and the width of the dashes of the printed line.
1061 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
1063 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
1065 * The function sets the color in which the line will be printed with.
1067 * \param [in] toplevel The TOPLEVEL object.
1068 * \param [in] fp FILE pointer to postscript document.
1071 * \param [in] radius
1072 * \param [in] angle1
1073 * \param [in] angle2
1075 * \param [in] arc_width
1076 * \param [in] length
1079 void o_arc_print_center(TOPLEVEL
*toplevel
, FILE *fp
,
1080 int x
, int y
, int radius
,
1081 int angle1
, int angle2
,
1083 int arc_width
, int length
, int space
)
1087 if (toplevel
->print_color
) {
1088 f_print_set_color(fp
, color
);
1092 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
1093 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
1094 * Starting from <B>angle1</B> - the start angle - the dashes are printed
1095 * along the arc by increments of these new angles.
1097 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a null
1098 * value which will make the function enter an endless loop. In such a case,
1099 * the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable should never
1100 * be negative except if <B>space</B> (resp. <B>length</B>) is negative.
1102 * It prints as many sets of dash-dot as possible.
1105 /* Inverting angle2 if < 0 and changing angle1 accordingly */
1106 /* the loop test assume that da > 0 */
1108 angle1
= angle1
+ angle2
;
1112 da
= (int) ((length
* 180) / (M_PI
* ((double) radius
)));
1113 db
= (int) ((space
* 180) / (M_PI
* ((double) radius
)));
1115 /* If da or db too small to be displayed, draw an arc */
1116 if ((da
<= 0) || (db
<= 0)) {
1117 o_arc_print_solid(toplevel
, fp
,
1121 arc_width
, length
, space
);
1127 while ((d
+ da
+ 2 * db
) < (angle1
+ angle2
)) {
1130 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1134 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1135 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1137 fprintf(fp
,"[%d] ",d
);
1141 * When the above condition is no more satisfied, then it is not
1142 * possible to print a dash of length <B>length</B>. However two cases are possible :
1144 * <DT>*</DT><DD>it is possible to print the dash and the dot
1145 * <DT>*</DT><DD>it is possible to print the dash or a part of the original dash
1153 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1155 if ((d
+ db
) < (angle1
+ angle2
)) {
1157 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1158 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1160 fprintf(fp
,"[%d] ",d
);
1163 fprintf(fp
,"] %d %d %d %d dashedarc %% center\n",
1164 x
,y
, radius
, arc_width
);
1168 * A dot is represented by a filled circle. Position of the circle is (<B>xa</B>, <B>ya</B>)
1169 * and its radius is the <B>arc_width</B> parameter.
1173 * \par Function Description
1174 * This function prints an arc when a phantom line type is required.
1175 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
1176 * in <B>radius</B> and the start and end angles of the arc on the circle.
1177 * The postscript file is defined by the file pointer <B>fp</B>.
1178 * The parameter <B>arc_width</B> specifies the diameter of the dots and the width of the dashes of the printed line.
1180 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
1182 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
1184 * The function sets the color in which the line will be printed with.
1186 * \param [in] toplevel The TOPLEVEL object.
1187 * \param [in] fp FILE pointer to postscript document.
1190 * \param [in] radius
1191 * \param [in] angle1
1192 * \param [in] angle2
1194 * \param [in] arc_width
1195 * \param [in] length
1198 void o_arc_print_phantom(TOPLEVEL
*toplevel
, FILE *fp
,
1199 int x
, int y
, int radius
,
1200 int angle1
, int angle2
,
1202 int arc_width
, int length
, int space
)
1206 if (toplevel
->print_color
) {
1207 f_print_set_color(fp
, color
);
1211 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
1212 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
1213 * Starting from <B>angle1</B> - the start angle - the dashes are printed
1214 * along the arc by increments of these new angles.
1216 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a
1217 * null value which will make the function enter an endless loop. In such
1218 * a case, the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable
1219 * should never be negative except if <B>space</B> (resp. <B>length</B>) is negative.
1221 * It prints as many sets of dash-dot-dot as possible.
1224 /* Inverting angle2 if < 0 and changing angle1 accordingly */
1225 /* the loop test assume that da > 0 */
1227 angle1
= angle1
+ angle2
;
1230 da
= (int) ((length
* 180) / (((double) radius
) * M_PI
));
1231 db
= (int) ((space
* 180) / (((double) radius
) * M_PI
));
1233 /* If da or db too small for arc to be displayed as dotted,
1235 if ((da
<= 0) || (db
<= 0)) {
1236 o_arc_print_solid(toplevel
, fp
,
1240 arc_width
, length
, space
);
1247 while ((d
+ da
+ 3 * db
) < (angle1
+ angle2
)) {
1251 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1255 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1256 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1258 fprintf(fp
,"[%d] ",d
);
1263 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1264 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1266 fprintf(fp
,"[%d] ",d
);
1272 * When the above condition is no more satisfied, then it is not
1273 * possible to print a dash of length <B>length</B>.
1274 * However three cases are possible :
1276 * <DT>*</DT><DD>it is possible to print a dash and a dot and a dot
1277 * <DT>*</DT><DD>it is possible to print a dash and a dot
1278 * <DT>*</DT><DD>it is possible to print the dash or a part of the original dash
1285 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1287 if ((d
+ db
) < (angle1
+ angle2
)) {
1291 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1292 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1294 fprintf(fp
,"[%d] ",d
);
1297 if ((d
+ db
) < (angle1
+ angle2
)) {
1301 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1302 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1305 fprintf(fp
,"[%d] ",d
);
1308 fprintf(fp
,"] %d %d %d %d dashedarc %% phantom\n",
1309 x
,y
, radius
, arc_width
);
1312 /*! \brief Calculates the distance between the given point and the closest
1313 * point on the perimeter of the arc.
1315 * \param [in] arc the arc of the OBJECT
1316 * \param [in] x The x coordinate of the given point.
1317 * \param [in] y The y coordinate of the given point.
1318 * \return The shortest distance from the object to the point. With an
1319 * invalid parameter, this function returns G_MAXDOUBLE.
1321 gdouble
o_arc_shortest_distance(ARC
const *arc
, gint x
, gint y
)
1324 gdouble shortest_distance
;
1327 g_critical("o_arc_shortest_distance(): arc == NULL\n");
1331 radius
= ((gdouble
) arc
->width
) / 2.0;
1333 if ( o_arc_within_sweep(arc
, x
, y
) ) {
1334 gdouble distance_to_center
;
1338 dx
= ((gdouble
) x
) - ((gdouble
) arc
->x
);
1339 dy
= ((gdouble
) y
) - ((gdouble
) arc
->y
);
1341 distance_to_center
= sqrt((dx
*dx
) + (dy
*dy
));
1343 shortest_distance
= fabs(distance_to_center
- radius
);
1347 gdouble distance_to_end0
;
1348 gdouble distance_to_end1
;
1352 angle
= G_PI
* ((gdouble
) arc
->start_angle
) / 180;
1354 dx
= ((gdouble
) x
) - radius
*cos(angle
) - ((gdouble
) arc
->x
);
1355 dy
= ((gdouble
) y
) - radius
*sin(angle
) - ((gdouble
) arc
->y
);
1357 distance_to_end0
= sqrt((dx
*dx
) + (dy
*dy
));
1359 angle
+= G_PI
* ((gdouble
) arc
->end_angle
) / 180;
1361 dx
= ((gdouble
) x
) - radius
*cos(angle
) - ((gdouble
) arc
->x
);
1362 dy
= ((gdouble
) y
) - radius
*sin(angle
) - ((gdouble
) arc
->y
);
1364 distance_to_end1
= sqrt((dx
*dx
) + (dy
*dy
));
1366 shortest_distance
= min(distance_to_end0
, distance_to_end1
);
1369 return shortest_distance
;
1372 /*! \brief Determines if a point lies within the sweep of the arc.
1374 * \param [in] arc The arc of object
1375 * \param [in] x The x coordinate of the given point.
1376 * \param [in] y The y coordinate of the given point.
1377 * \return TRUE if the point lies within the sweep of the arc.
1378 * FALSE if the point lies outside the sweep of the arc. With an
1379 * invalid parameter, this function returns FALSE.
1381 gboolean
o_arc_within_sweep(ARC
const *arc
, gint x
, gint y
)
1390 g_critical("o_arc_within_sweep(): arc == NULL\n");
1394 dx
= ((gdouble
) x
) - ((gdouble
) arc
->x
);
1395 dy
= ((gdouble
) y
) - ((gdouble
) arc
->y
);
1397 angle
= 180 * atan2(dy
, dx
) / G_PI
;
1399 a0
= (gdouble
) arc
->start_angle
;
1400 a1
= ((gdouble
) arc
->end_angle
) + a0
;
1402 while (angle
< a0
) {
1406 return (angle
< a1
);