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
->sel_func
= select_func
;
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
719 * \param [in] origin_x
720 * \param [in] origin_y
722 void o_arc_print(TOPLEVEL
*toplevel
, FILE *fp
, OBJECT
*o_current
,
723 int origin_x
, int origin_y
)
725 int x
, y
, radius
, start_angle
, end_angle
;
727 int arc_width
, space
, length
;
728 void (*outl_func
)() = NULL
;
730 if (o_current
== NULL
) {
731 printf("got null in o_arc_print\n");
735 x
= o_current
->arc
->x
;
736 y
= o_current
->arc
->y
;
737 radius
= o_current
->arc
->width
/ 2;
738 start_angle
= o_current
->arc
->start_angle
;
739 end_angle
= o_current
->arc
->end_angle
;
740 color
= o_current
->color
;
743 * Depending on the type of the line for this particular arc, the
744 * appropriate function is chosen among #o_arc_print_solid(),
745 * #o_arc_print_dotted(), #o_arc_print_dashed(), #o_arc_print_center() and #o_arc_print_phantom().
747 * The needed parameters for each of these types are extracted from the <B>o_current</B> object.
748 * Depending on the type, unused parameters are set to -1.
750 * In the eventuality of a length and/or space null, the arc is printed solid to avoid and
751 * endless loop produced by other functions.
754 #if 0 /* was causing arcs which are solid to be much thinner compared to */
755 /* lines, boxes, also of zero width */
756 if (o_current
->line_width
> 0) {
757 arc_width
= o_current
->line_width
;
762 arc_width
= o_current
->line_width
; /* Added instead of above */
764 if(toplevel
->line_style
== THICK
) {
765 arc_width
=LINE_WIDTH
;
771 length
= o_current
->line_length
;
772 space
= o_current
->line_space
;
774 switch(o_current
->line_type
) {
776 length
= -1; space
= -1;
777 outl_func
= o_arc_print_solid
;
782 outl_func
= o_arc_print_dotted
;
786 outl_func
= o_arc_print_dashed
;
790 outl_func
= o_arc_print_center
;
794 outl_func
= o_arc_print_phantom
;
798 /* Unused for now, print it solid */
799 length
= -1; space
= -1;
800 outl_func
= o_arc_print_solid
;
804 if((space
== 0) || (length
== 0)) {
805 length
= -1; space
= -1;
806 outl_func
= o_arc_print_solid
;
809 (*outl_func
)(toplevel
, fp
,
810 x
- origin_x
, y
- origin_x
, radius
,
811 start_angle
, end_angle
,
812 color
, arc_width
, length
, space
, origin_x
, origin_y
);
817 * \par Function Description
818 * This function prints an arc when a solid line type is required.
819 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
820 * in <B>radius</B> and the start and end angles of the arc on the circle.
821 * The postscript file is defined by the file pointer <B>fp</B>.
823 * The parameters <B>length</B> and <B>space</B> are ignored
824 * whereas <B>arc_width</B> specifies the width of the printed line.
826 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
828 * \param [in] toplevel The TOPLEVEL object.
829 * \param [in] fp FILE pointer to postscript document.
836 * \param [in] arc_width
839 * \param [in] origin_x
840 * \param [in] origin_y
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
,
847 int origin_x
, int origin_y
)
849 if (toplevel
->print_color
) {
850 f_print_set_color(fp
, color
);
853 /* PB/AVH inverting angle2 if < 0 and changing angle1 accordingly */
855 angle1
= angle1
+ angle2
;
859 fprintf(fp
, "%d %d %d %d %d %d darc\n",
860 x
,y
, radius
, angle1
, angle1
+ angle2
,
866 * \par Function Description
867 * This function prints an arc when a dotted line type is required.
868 * The arc is defined by its center in <B>x</B> and <B>y</B>, its
869 * radius in <B>radius</B> and the start and end angles of the arc on the circle.
870 * The postscript file is defined by the file pointer <B>fp</B>.
871 * The parameter <B>length</B> is ignored whereas <B>arc_width</B> specifies
872 * the diameter of the dots of the printed line and <B>space</B> the distance
875 * A negative value for <B>space</B> leads to an endless loop.
877 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
879 * The function sets the color the line will be printed with.
881 * \param [in] toplevel The TOPLEVEL object.
882 * \param [in] fp FILE pointer to postscript document.
889 * \param [in] arc_width
892 * \param [in] origin_x
893 * \param [in] origin_y
895 void o_arc_print_dotted(TOPLEVEL
*toplevel
, FILE *fp
,
896 int x
, int y
, int radius
,
897 int angle1
, int angle2
,
899 int arc_width
, int length
, int space
,
900 int origin_x
, int origin_y
)
905 if (toplevel
->print_color
) {
906 f_print_set_color(fp
, color
);
910 * Depending on the radius of the arc, the <B>space</B> parameter is
911 * changed into a small angle <B>da</B>.
912 * Starting from <B>angle1</B> - the start angle - the dots are printed
913 * along the arc by increments of this new angle.
915 * As <B>da</B> is rounded as an integer, it can take a null value which
916 * will make the function enter an endless loop. In such a case, the arc
917 * is printed solid. The <B>da</B> variable should never be negative
918 * except if <B>space</B> is negative.
921 /* Inverting angle2 if < 0 and changing angle1 accordingly */
922 /* the loop test assume that da > 0 */
924 angle1
= angle1
+ angle2
;
927 da
= (int) ((space
* 180) / (M_PI
* ((double) radius
)));
929 /* If da or db too small for arc to be displayed as dotted,
932 o_arc_print_solid(toplevel
, fp
,
936 arc_width
, length
, space
, origin_x
, origin_y
);
942 while (d
< (angle2
+ angle1
)) {
943 /*xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
944 ya = ((double) y) + ((double) radius) * sin(d * M_PI / 180);
946 fprintf(fp
,"[%d] ",d
);
950 fprintf(fp
,"] %d %d %d %d dashedarc %% dotted\n",
951 x
,y
, radius
, arc_width
);
955 * \par Function Description
956 * This function prints an arc when a dashed line type is required.
957 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
958 * in <B>radius</B> and the start and end angles of the arc on the circle.
959 * The postscript file is defined by the file pointer <B>fp</B>.
960 * The parameter <B>arc_width</B> specifies the diameter of the dots of the printed line.
962 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
964 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
966 * The function sets the color the line will be printed with.
968 * \param [in] toplevel The TOPLEVEL object.
969 * \param [in] fp FILE pointer to postscript document.
976 * \param [in] arc_width
979 * \param [in] origin_x
980 * \param [in] origin_y
982 void o_arc_print_dashed(TOPLEVEL
*toplevel
, FILE *fp
,
983 int x
, int y
, int radius
,
984 int angle1
, int angle2
,
986 int arc_width
, int length
, int space
,
987 int origin_x
, int origin_y
)
991 if (toplevel
->print_color
) {
992 f_print_set_color(fp
, color
);
996 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
997 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
998 * Starting from <B>angle1</B> - the start angle - the dashes are printed
999 * along the arc by increments of these new angles.
1001 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a
1002 * null value which will make the function enter an endless loop. In such a case,
1003 * the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable should never
1004 * be negative except if <B>space</B> (resp. <B>length</B>) is negative.
1006 * It prints as many dashes of length <B>length</B> as possible.
1009 /* Inverting angle2 if < 0 and changing angle1 accordingly */
1010 /* the loop test assume that da > 0 */
1012 angle1
= angle1
+ angle2
;
1015 da
= (int) ((length
* 180) / (M_PI
* ((double) radius
)));
1016 db
= (int) ((space
* 180) / (M_PI
* ((double) radius
)));
1018 /* If da or db too small for arc to be displayed as dotted,
1020 if ((da
<= 0) || (db
<= 0)) {
1021 o_arc_print_solid(toplevel
, fp
,
1025 arc_width
, length
, space
, origin_x
, origin_y
);
1031 while ((d
+ da
+ db
) < (angle1
+ angle2
)) {
1035 fprintf(fp
,"[%d %d] ",
1041 * When the above condition is no more satisfied, then it is not
1042 * possible to print a dash of length <B>length</B> and the following <B>space</B>.
1043 * However it may be possible to print the complete dash or a shorter one.
1046 if ((d
+ da
) < (angle1
+ angle2
)) {
1052 fprintf(fp
,"[%d %d] ",
1056 fprintf(fp
,"] %d %d %d %d dashedarc %% dashed\n",
1057 x
,y
, radius
, arc_width
);
1061 * \par Function Description
1062 * This function prints an arc when a centered line type is required.
1063 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius in
1064 * <B>radius</B> and the start and end angles of the arc on the circle.
1065 * The postscript file is defined by the file pointer <B>fp</B>.
1066 * The parameter <B>arc_width</B> specifies the diameter of the dots and the width of the dashes of the printed line.
1068 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
1070 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
1072 * The function sets the color in which the line will be printed with.
1074 * \param [in] toplevel The TOPLEVEL object.
1075 * \param [in] fp FILE pointer to postscript document.
1078 * \param [in] radius
1079 * \param [in] angle1
1080 * \param [in] angle2
1082 * \param [in] arc_width
1083 * \param [in] length
1085 * \param [in] origin_x
1086 * \param [in] origin_y
1088 void o_arc_print_center(TOPLEVEL
*toplevel
, FILE *fp
,
1089 int x
, int y
, int radius
,
1090 int angle1
, int angle2
,
1092 int arc_width
, int length
, int space
,
1093 int origin_x
, int origin_y
)
1097 if (toplevel
->print_color
) {
1098 f_print_set_color(fp
, color
);
1102 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
1103 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
1104 * Starting from <B>angle1</B> - the start angle - the dashes are printed
1105 * along the arc by increments of these new angles.
1107 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a null
1108 * value which will make the function enter an endless loop. In such a case,
1109 * the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable should never
1110 * be negative except if <B>space</B> (resp. <B>length</B>) is negative.
1112 * It prints as many sets of dash-dot as possible.
1115 /* Inverting angle2 if < 0 and changing angle1 accordingly */
1116 /* the loop test assume that da > 0 */
1118 angle1
= angle1
+ angle2
;
1122 da
= (int) ((length
* 180) / (M_PI
* ((double) radius
)));
1123 db
= (int) ((space
* 180) / (M_PI
* ((double) radius
)));
1125 /* If da or db too small to be displayed, draw an arc */
1126 if ((da
<= 0) || (db
<= 0)) {
1127 o_arc_print_solid(toplevel
, fp
,
1131 arc_width
, length
, space
, origin_x
, origin_y
);
1137 while ((d
+ da
+ 2 * db
) < (angle1
+ angle2
)) {
1140 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1144 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1145 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1147 fprintf(fp
,"[%d] ",d
);
1151 * When the above condition is no more satisfied, then it is not
1152 * possible to print a dash of length <B>length</B>. However two cases are possible :
1154 * <DT>*</DT><DD>it is possible to print the dash and the dot
1155 * <DT>*</DT><DD>it is possible to print the dash or a part of the original dash
1163 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1165 if ((d
+ db
) < (angle1
+ angle2
)) {
1167 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1168 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1170 fprintf(fp
,"[%d] ",d
);
1173 fprintf(fp
,"] %d %d %d %d dashedarc %% center\n",
1174 x
,y
, radius
, arc_width
);
1178 * A dot is represented by a filled circle. Position of the circle is (<B>xa</B>, <B>ya</B>)
1179 * and its radius is the <B>arc_width</B> parameter.
1183 * \par Function Description
1184 * This function prints an arc when a phantom line type is required.
1185 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
1186 * in <B>radius</B> and the start and end angles of the arc on the circle.
1187 * The postscript file is defined by the file pointer <B>fp</B>.
1188 * The parameter <B>arc_width</B> specifies the diameter of the dots and the width of the dashes of the printed line.
1190 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
1192 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
1194 * The function sets the color in which the line will be printed with.
1196 * \param [in] toplevel The TOPLEVEL object.
1197 * \param [in] fp FILE pointer to postscript document.
1200 * \param [in] radius
1201 * \param [in] angle1
1202 * \param [in] angle2
1204 * \param [in] arc_width
1205 * \param [in] length
1207 * \param [in] origin_x
1208 * \param [in] origin_y
1210 void o_arc_print_phantom(TOPLEVEL
*toplevel
, FILE *fp
,
1211 int x
, int y
, int radius
,
1212 int angle1
, int angle2
,
1214 int arc_width
, int length
, int space
,
1215 int origin_x
, int origin_y
)
1219 if (toplevel
->print_color
) {
1220 f_print_set_color(fp
, color
);
1224 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
1225 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
1226 * Starting from <B>angle1</B> - the start angle - the dashes are printed
1227 * along the arc by increments of these new angles.
1229 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a
1230 * null value which will make the function enter an endless loop. In such
1231 * a case, the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable
1232 * should never be negative except if <B>space</B> (resp. <B>length</B>) is negative.
1234 * It prints as many sets of dash-dot-dot as possible.
1237 /* Inverting angle2 if < 0 and changing angle1 accordingly */
1238 /* the loop test assume that da > 0 */
1240 angle1
= angle1
+ angle2
;
1243 da
= (int) ((length
* 180) / (((double) radius
) * M_PI
));
1244 db
= (int) ((space
* 180) / (((double) radius
) * M_PI
));
1246 /* If da or db too small for arc to be displayed as dotted,
1248 if ((da
<= 0) || (db
<= 0)) {
1249 o_arc_print_solid(toplevel
, fp
,
1253 arc_width
, length
, space
, origin_x
, origin_y
);
1260 while ((d
+ da
+ 3 * db
) < (angle1
+ angle2
)) {
1264 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1268 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1269 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1271 fprintf(fp
,"[%d] ",d
);
1276 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1277 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1279 fprintf(fp
,"[%d] ",d
);
1285 * When the above condition is no more satisfied, then it is not
1286 * possible to print a dash of length <B>length</B>.
1287 * However three cases are possible :
1289 * <DT>*</DT><DD>it is possible to print a dash and a dot and a dot
1290 * <DT>*</DT><DD>it is possible to print a dash and a dot
1291 * <DT>*</DT><DD>it is possible to print the dash or a part of the original dash
1298 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1300 if ((d
+ db
) < (angle1
+ angle2
)) {
1304 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1305 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1307 fprintf(fp
,"[%d] ",d
);
1310 if ((d
+ db
) < (angle1
+ angle2
)) {
1314 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1315 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1318 fprintf(fp
,"[%d] ",d
);
1321 fprintf(fp
,"] %d %d %d %d dashedarc %% phantom\n",
1322 x
,y
, radius
, arc_width
);
1325 /*! \brief Calculates the distance between the given point and the closest
1326 * point on the perimeter of the arc.
1328 * \param [in] arc the arc of the OBJECT
1329 * \param [in] x The x coordinate of the given point.
1330 * \param [in] y The y coordinate of the given point.
1331 * \return The shortest distance from the object to the point. With an
1332 * invalid parameter, this function returns G_MAXDOUBLE.
1334 gdouble
o_arc_shortest_distance(ARC
const *arc
, gint x
, gint y
)
1337 gdouble shortest_distance
;
1340 g_critical("o_arc_shortest_distance(): arc == NULL\n");
1344 radius
= ((gdouble
) arc
->width
) / 2.0;
1346 if ( o_arc_within_sweep(arc
, x
, y
) ) {
1347 gdouble distance_to_center
;
1351 dx
= ((gdouble
) x
) - ((gdouble
) arc
->x
);
1352 dy
= ((gdouble
) y
) - ((gdouble
) arc
->y
);
1354 distance_to_center
= sqrt((dx
*dx
) + (dy
*dy
));
1356 shortest_distance
= fabs(distance_to_center
- radius
);
1360 gdouble distance_to_end0
;
1361 gdouble distance_to_end1
;
1365 angle
= G_PI
* ((gdouble
) arc
->start_angle
) / 180;
1367 dx
= ((gdouble
) x
) - radius
*cos(angle
) - ((gdouble
) arc
->x
);
1368 dy
= ((gdouble
) y
) - radius
*sin(angle
) - ((gdouble
) arc
->y
);
1370 distance_to_end0
= sqrt((dx
*dx
) + (dy
*dy
));
1372 angle
+= G_PI
* ((gdouble
) arc
->end_angle
) / 180;
1374 dx
= ((gdouble
) x
) - radius
*cos(angle
) - ((gdouble
) arc
->x
);
1375 dy
= ((gdouble
) y
) - radius
*sin(angle
) - ((gdouble
) arc
->y
);
1377 distance_to_end1
= sqrt((dx
*dx
) + (dy
*dy
));
1379 shortest_distance
= min(distance_to_end0
, distance_to_end1
);
1382 return shortest_distance
;
1385 /*! \brief Determines if a point lies within the sweep of the arc.
1387 * \param [in] arc The arc of object
1388 * \param [in] x The x coordinate of the given point.
1389 * \param [in] y The y coordinate of the given point.
1390 * \return TRUE if the point lies within the sweep of the arc.
1391 * FALSE if the point lies outside the sweep of the arc. With an
1392 * invalid parameter, this function returns FALSE.
1394 gboolean
o_arc_within_sweep(ARC
const *arc
, gint x
, gint y
)
1403 g_critical("o_arc_within_sweep(): arc == NULL\n");
1407 dx
= ((gdouble
) x
) - ((gdouble
) arc
->x
);
1408 dy
= ((gdouble
) y
) - ((gdouble
) arc
->y
);
1410 angle
= 180 * atan2(dy
, dx
) / G_PI
;
1412 a0
= (gdouble
) arc
->start_angle
;
1413 a1
= ((gdouble
) arc
->end_angle
) + a0
;
1415 while (angle
< a0
) {
1419 return (angle
< a1
);