1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /*! \file o_arc_basic.c
22 * \brief functions for the arc object
30 #include "libgeda_priv.h"
32 #ifdef HAVE_LIBDMALLOC
37 * \par Function Description
38 * The function creates a new OBJECT of type arc.
40 * The arc is defined by its center in parameters x and y.
41 * The radius parameter specifies the radius of the arc. The start
42 * angle is given by start_angle and the end angle by end_angle.
43 * The line and fill type of the created arc are set to default.
45 * All dimensions are in world unit, except start_angle and
46 * end_angle in degrees.
48 * A new object of type OBJECT is allocated. Its type and color
49 * are initilized. The description of the arc characteristics
50 * are stored in a new ARC structure.
52 * Now fixed for world coordinates.
54 * \param [in] toplevel The TOPLEVEL object.
60 * \param [in] start_angle
61 * \param [in] end_angle
64 OBJECT
*o_arc_new(TOPLEVEL
*toplevel
,
66 int x
, int y
, int radius
, int start_angle
, int end_angle
)
71 new_node
= s_basic_new_object(type
, "arc");
73 new_node
->color
= color
;
75 new_node
->arc
= (ARC
*) g_malloc(sizeof(ARC
));
78 * The ARC structure is initialized with the parameters.
79 * A default initialization is performed for the line and
80 * fill type to avoid misunderstanding.
82 * The functions relative to the use of the object are sets.
85 /* World coordinates */
88 new_node
->arc
->width
= 2 * radius
;
89 new_node
->arc
->height
= 2 * radius
;
91 /* must check the sign of start_angle, end_angle ... */
93 start_angle
= start_angle
+ end_angle
;
94 end_angle
= -end_angle
;
96 if(start_angle
< 0) start_angle
= 360 + start_angle
;
98 new_node
->arc
->start_angle
= start_angle
;
99 new_node
->arc
->end_angle
= end_angle
;
102 o_set_line_options(toplevel
, new_node
,
103 END_NONE
, TYPE_SOLID
, 0, -1, -1);
104 o_set_fill_options(toplevel
, new_node
,
105 FILLING_HOLLOW
, -1, -1, -1, -1, -1);
107 o_arc_recalc(toplevel
, new_node
);
109 /* new_node->graphical = arc; eventually */
115 * \par Function Description
116 * This function creates a new object representing an arc.
118 * The values of the <B>o_current</B> pointed OBJECT are then copied to the new object.
120 * The arc, the line options are initialized whereas the fill options are
121 * initialized to passive values - as an arc can not be filled.
123 * \param [in] toplevel The TOPLEVEL object
124 * \param [in] o_current
125 * \return The new OBJECT
127 OBJECT
*o_arc_copy(TOPLEVEL
*toplevel
, OBJECT
*o_current
)
131 new_obj
= o_arc_new (toplevel
, OBJ_ARC
, o_current
->color
,
132 o_current
->arc
->x
, o_current
->arc
->y
,
133 o_current
->arc
->width
/ 2,
134 o_current
->arc
->start_angle
,
135 o_current
->arc
->end_angle
);
136 o_set_line_options(toplevel
, new_obj
,
137 o_current
->line_end
, o_current
->line_type
,
138 o_current
->line_width
,
139 o_current
->line_length
, o_current
->line_space
);
140 o_set_fill_options(toplevel
, new_obj
,
141 FILLING_HOLLOW
, -1, -1, -1, -1, -1);
147 * \par Function Description
148 * This function modifies the internal values of the arc object
149 * *object according to the whichone parameter.
151 * The new values are given by <B>x</B> and/or <B>y</B>. Their meaning depends on the value of whichone.
153 * If <B>whichone</B> is equal to #ARC_CENTER, the (<B>x</B>,<B>y</B>) point is taken as the new center
154 * of the arc in world unit.
156 * If <B>whichone</B> is equal to #ARC_RADIUS, the <B>x</B> parameter is taken to be the radius
157 * of the arc in world unit. The <B>y</B> parameter is ignored.
159 * If <B>whichone</B> is equal to #ARC_START_ANGLE, the <B>x</B> parameter is the starting angle of the arc.
160 * <B>x</B> is in degrees. <B>y</B> is ignored.
162 * If <B>whichone</B> is equal to #ARC_END_ANGLE, the <B>x</B> parameter is the ending angle of the arc.
163 * <B>x</B> is in degrees. <B>y</B> is ignored.
165 * \param [in] toplevel The TOPLEVEL object.
166 * \param [in,out] object
169 * \param [in] whichone
171 void o_arc_modify(TOPLEVEL
*toplevel
, OBJECT
*object
,
172 int x
, int y
, int whichone
)
175 o_emit_pre_change_notify (toplevel
, object
);
179 /* modify the center of arc object */
185 /* modify the radius of arc object */
186 object
->arc
->width
= 2 * x
;
187 object
->arc
->height
= 2 * x
;
190 case ARC_START_ANGLE
:
191 /* modify the start angle of the arc object */
192 object
->arc
->start_angle
= x
;
196 /* modify the end angle of the arc object */
197 object
->arc
->end_angle
= x
;
204 /* update the screen coords and the bounding box */
205 o_arc_recalc(toplevel
, object
);
206 o_emit_change_notify (toplevel
, object
);
210 * \par Function Description
211 * This function reads a formatted text buffer describing an arc
212 * in the gEDA file format and initializes the corresponding object.
214 * Depending on the version of the file format the data extraction is
215 * performed differently : currently pre-20000704 and 20000704 on one
216 * hand and post-20000704 file format version on the other hand are supported.
217 * The version is specified in string pointed by <B>fileformat_ver</B>.
219 * To get information on the various file formats have a
220 * look to the fileformats.html document.
222 * The object is initialized with the functions #o_set_line_options() and #o_set_fill_options().
223 * The second one is only used to put initialize unused values for an arc as an arc can not be filled.
225 * The arc is allocated initialized with the function #o_arc_new().
227 * A negative or null radius is not allowed.
229 * \param [in] toplevel The TOPLEVEL object.
231 * \param [in] release_ver
232 * \param [in] fileformat_ver
235 OBJECT
*o_arc_read (TOPLEVEL
*toplevel
, char buf
[],
236 unsigned int release_ver
, unsigned int fileformat_ver
)
242 int start_angle
, end_angle
;
244 int arc_width
, arc_length
, arc_space
;
249 * Depending on the version of the file format used to describe this arc,
250 * the buffer is parsed differently. The unknown parameters of the less
251 * restrictive - the oldest - file format are set to common values
253 if(release_ver
<= VERSION_20000704
) {
254 sscanf(buf
, "%c %d %d %d %d %d %d", &type
,
255 &x1
, &y1
, &radius
, &start_angle
, &end_angle
, &color
);
259 arc_type
= TYPE_SOLID
;
263 sscanf(buf
, "%c %d %d %d %d %d %d %d %d %d %d %d", &type
,
264 &x1
, &y1
, &radius
, &start_angle
, &end_angle
, &color
,
265 &arc_width
, &arc_end
, &arc_type
, &arc_length
, &arc_space
);
271 s_log_message (_("Found a zero radius arc [ %c %d, %d, %d, %d, %d, %d ]\n"),
272 type
, x1
, y1
, radius
, start_angle
, end_angle
, color
);
275 if (color
< 0 || color
> MAX_COLORS
) {
276 s_log_message(_("Found an invalid color [ %s ]\n"), buf
);
277 s_log_message(_("Setting color to default color\n"));
278 color
= DEFAULT_COLOR
;
281 /* Allocation and initialization */
282 new_obj
= o_arc_new(toplevel
, OBJ_ARC
, color
,
283 x1
, y1
, radius
, start_angle
, end_angle
);
284 o_set_line_options(toplevel
, new_obj
,
285 arc_end
, arc_type
, arc_width
, arc_length
,
287 o_set_fill_options(toplevel
, new_obj
,
288 FILLING_HOLLOW
, -1, -1, -1,
294 /*! \brief create the string representation of an arc object
295 * \par Function Description
296 * This function formats a string in the buffer <B>*buf</B> to describe
297 * the arc object <B>*object</B>.
298 * A pointer to the new allocated and formated string is returned.
299 * The string must be freed at some point.
301 * \param [in] toplevel
303 * \return the string representation of the arc object
305 char *o_arc_save(TOPLEVEL
*toplevel
, OBJECT
*object
)
307 int x
, y
, radius
, start_angle
, end_angle
;
308 int arc_width
, arc_length
, arc_space
;
311 OBJECT_TYPE arc_type
;
313 /* radius, center and angles of the arc */
314 radius
= object
->arc
->width
/ 2;
317 start_angle
= object
->arc
->start_angle
;
318 end_angle
= object
->arc
->end_angle
;
320 /* line type parameters */
321 arc_width
= object
->line_width
;
322 arc_end
= object
->line_end
;
323 arc_type
= object
->line_type
;
324 arc_length
= object
->line_length
;
325 arc_space
= object
->line_space
;
327 /* Describe a circle with post-20000704 file format */
328 buf
= g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d", object
->type
,
329 x
, y
, radius
, start_angle
, end_angle
, object
->color
,
330 arc_width
, arc_end
, arc_type
, arc_length
, arc_space
);
336 * \par Function Description
337 * This function applies a translation of (<B>dx</B>,<B>dy</B>)
338 * to the arc described in <B>*object</B>. <B>dx</B> and <B>dy</B> are in world unit.
340 * \param [in] toplevel The TOPLEVEL object.
345 void o_arc_translate_world(TOPLEVEL
*toplevel
, int dx
, int dy
,
348 if (object
== NULL
) {
352 /* Do world coords */
353 object
->arc
->x
= object
->arc
->x
+ dx
;
354 object
->arc
->y
= object
->arc
->y
+ dy
;
357 /* Recalculate screen coords from new world coords */
358 o_arc_recalc(toplevel
, object
);
362 * \par Function Description
363 * This function rotates the world coordinates of an arc of an angle
364 * specified by <B>angle</B>. The center of the rotation is given by
365 * (<B>world_centerx</B>,<B>world_centery</B>).
367 * The arc is translated in order to put the center of the rotation
368 * on the origin. The center of the arc is then rotated of the angle
369 * specified by <B>angle</B>. The start angle of the arc is incremented by <B>angle</B>.
371 * The arc is finally back translated to its previous location on the page.
373 * <B>world_centerx</B> and <B>world_centery</B> are in world units, <B>angle</B> is in degrees.
375 * \param [in] toplevel The TOPLEVEL object.
376 * \param [in] world_centerx
377 * \param [in] world_centery
381 void o_arc_rotate_world(TOPLEVEL
*toplevel
,
382 int world_centerx
, int world_centery
, int angle
,
385 int x
, y
, newx
, newy
;
387 /* translate object to origin */
388 object
->arc
->x
-= world_centerx
;
389 object
->arc
->y
-= world_centery
;
391 /* get center, and rotate center */
394 if(angle
% 90 == 0) {
395 rotate_point_90(x
, y
, angle
% 360, &newx
, &newy
);
397 rotate_point(x
, y
, angle
% 360, &newx
, &newy
);
399 object
->arc
->x
= newx
;
400 object
->arc
->y
= newy
;
402 /* apply rotation to angles */
403 object
->arc
->start_angle
= (object
->arc
->start_angle
+ angle
) % 360;
404 /* end_angle is unchanged as it is the sweep of the arc */
405 /* object->arc->end_angle = (object->arc->end_angle); */
407 /* translate object to its previous place */
408 object
->arc
->x
+= world_centerx
;
409 object
->arc
->y
+= world_centery
;
411 /* update the screen coords and the bounding box */
412 o_arc_recalc(toplevel
, object
);
416 /*! \brief Mirror the WORLD coordinates of an ARC.
417 * \par Function Description
418 * This function mirrors the world coordinates of an arc.
419 * The symetry axis is given by the vertical line going through the point (<B>world_centerx</B>,<B>world_centery</B>).
421 * The arc is translated in order to put the point (<B>world_centerx</B>,<B>world_centery</B>)
422 * on the origin. The center of the arc is then mirrored. The start angle of the arc
423 * and the sweep of the arc are also mirrored.
425 * The arc is finally back translated to its previous location on the page.
427 * \param [in] toplevel The TOPLEVEL object.
428 * \param [in] world_centerx
429 * \param [in] world_centery
432 void o_arc_mirror_world(TOPLEVEL
*toplevel
,
433 int world_centerx
, int world_centery
,
436 /* translate object to origin */
437 object
->arc
->x
-= world_centerx
;
438 object
->arc
->y
-= world_centery
;
440 /* get center, and mirror it (vertical mirror) */
441 object
->arc
->x
= -object
->arc
->x
;
442 object
->arc
->y
= object
->arc
->y
;
444 /* apply mirror to angles (vertical mirror) */
445 object
->arc
->start_angle
= (180 - object
->arc
->start_angle
) % 360;
446 /* start_angle *MUST* be positive */
447 if(object
->arc
->start_angle
< 0) object
->arc
->start_angle
+= 360;
448 object
->arc
->end_angle
= -object
->arc
->end_angle
;
450 /* translate object back to its previous position */
451 object
->arc
->x
+= world_centerx
;
452 object
->arc
->y
+= world_centery
;
454 /* update the screen coords and bounding box */
455 o_arc_recalc(toplevel
, object
);
460 * \par Function Description
461 * This function recalculates internal parameters in screen units
462 * of an object containing an arc. The object is given as parameters <B>o_current</B>.
463 * The calculation is done according to the zoom factor detailed in the <B>toplevel</B>
465 * It also recalculates the <B>OBJECT</B> specific fields and the bounding box of the arc.
467 * The bounding box - in world units - is recalculated with the <B>world_get_arc_bounds()</B> function.
469 * \param [in] toplevel The TOPLEVEL object.
470 * \param [in] o_current
472 void o_arc_recalc(TOPLEVEL
*toplevel
, OBJECT
*o_current
)
474 int left
, right
, top
, bottom
;
476 if (o_current
->arc
== NULL
) {
480 /* recalculates the bounding box */
481 world_get_arc_bounds(toplevel
, o_current
, &left
, &top
, &right
, &bottom
);
482 o_current
->w_left
= left
;
483 o_current
->w_top
= top
;
484 o_current
->w_right
= right
;
485 o_current
->w_bottom
= bottom
;
486 o_current
->w_bounds_valid
= TRUE
;
491 * \par Function Description
492 * This function calculates the smallest rectangle the arc can be drawn into.
493 * The <B>OBJECT</B> pointed by object is assumed to be an arc.
494 * The <B>left</B>, <B>top</B>, <B>right</B> and <B>bottom</B> pointed integers define
495 * this rectangle at the end of the function. It is expressed in world units.
496 * The process is divided into two steps : the first step is to calculate the
497 * coordinates of the two ends of the arc and the coordinates of the center.
498 * They forms a first rectangle but (depending on the start angle and the
499 * sweep of the arc) not the right.
501 * \param [in] toplevel The TOPLEVEL object.
506 * \param [out] bottom
508 void world_get_arc_bounds(TOPLEVEL
*toplevel
, OBJECT
*object
, int *left
,
509 int *top
, int *right
, int *bottom
)
511 int x1
, y1
, x2
, y2
, x3
, y3
;
512 int radius
, start_angle
, end_angle
;
516 halfwidth
= object
->line_width
/ 2;
518 radius
= object
->arc
->width
/ 2;
519 start_angle
= object
->arc
->start_angle
;
520 end_angle
= object
->arc
->end_angle
;
524 x2
= x1
+ radius
* cos(start_angle
* M_PI
/ 180);
525 y2
= y1
+ radius
* sin(start_angle
* M_PI
/ 180);
526 x3
= x1
+ radius
* cos((start_angle
+ end_angle
) * M_PI
/ 180);
527 y3
= y1
+ radius
* sin((start_angle
+ end_angle
) * M_PI
/ 180);
529 *left
= (x1
< x2
) ? ((x1
< x3
) ? x1
: x3
) : ((x2
< x3
) ? x2
: x3
);
530 *right
= (x1
> x2
) ? ((x1
> x3
) ? x1
: x3
) : ((x2
> x3
) ? x2
: x3
);
531 *bottom
= (y1
> y2
) ? ((y1
> y3
) ? y1
: y3
) : ((y2
> y3
) ? y2
: y3
);
532 *top
= (y1
< y2
) ? ((y1
< y3
) ? y1
: y3
) : ((y2
< y3
) ? y2
: y3
);
535 * The previous rectangle is extended to the final one
536 * by checking whether the arc is over a main axis (vertical or horizontal).
537 * If so, the rectangle is extended in these directions.
539 * In the mirror mode, the sweep angle is negativ. To get a
540 * CCW arc before this calculation we have to move the
541 * start angle to the end angle and reverse the sweep angle.
544 start_angle
= (start_angle
+ end_angle
+ 360) % 360;
545 end_angle
= -end_angle
;
547 angle
= ((int) (start_angle
/ 90)) * 90;
548 for(i
= 0; i
< 4; i
++) {
550 if(angle
< start_angle
+ end_angle
) {
551 if(angle
% 360 == 0) *right
= x1
+ radius
;
552 if(angle
% 360 == 90) *bottom
= y1
+ radius
;
553 if(angle
% 360 == 180) *left
= x1
- radius
;
554 if(angle
% 360 == 270) *top
= y1
- radius
;
560 /* This isn't strictly correct, but a 1st order approximation */
564 *bottom
+= halfwidth
;
568 /*! \brief get the position of the center point
569 * \par Function Description
570 * This function gets the position of the center point of an arc object.
572 * \param [in] toplevel The toplevel environment.
573 * \param [out] x pointer to the x-position
574 * \param [out] y pointer to the y-position
575 * \param [in] object The object to get the position.
576 * \return TRUE if successfully determined the position, FALSE otherwise
578 gboolean
o_arc_get_position (TOPLEVEL
*toplevel
, gint
*x
, gint
*y
,
587 * \par Function Description
588 * This function writes in a postscript file the arc described by
589 * the <B>o_current</B> pointed object.
590 * The postscript resulting file is described by the <B>fp</B> file pointer.
592 * Parameters of the arc are extracted from object pointed by <B>o_current</B>
593 * and formatted to suit future calls to specialized arc printing functions.
595 * \param [in] toplevel The TOPLEVEL object.
596 * \param [in] fp The postscript document to print to.
597 * \param [in] o_current
598 * \param [in] origin_x
599 * \param [in] origin_y
601 void o_arc_print(TOPLEVEL
*toplevel
, FILE *fp
, OBJECT
*o_current
,
602 int origin_x
, int origin_y
)
604 int x
, y
, radius
, start_angle
, end_angle
;
606 int arc_width
, space
, length
;
607 void (*outl_func
)() = NULL
;
609 if (o_current
== NULL
) {
610 printf("got null in o_arc_print\n");
614 x
= o_current
->arc
->x
;
615 y
= o_current
->arc
->y
;
616 radius
= o_current
->arc
->width
/ 2;
617 start_angle
= o_current
->arc
->start_angle
;
618 end_angle
= o_current
->arc
->end_angle
;
619 color
= o_current
->color
;
622 * Depending on the type of the line for this particular arc, the
623 * appropriate function is chosen among #o_arc_print_solid(),
624 * #o_arc_print_dotted(), #o_arc_print_dashed(), #o_arc_print_center() and #o_arc_print_phantom().
626 * The needed parameters for each of these types are extracted from the <B>o_current</B> object.
627 * Depending on the type, unused parameters are set to -1.
629 * In the eventuality of a length and/or space null, the arc is printed solid to avoid and
630 * endless loop produced by other functions.
633 #if 0 /* was causing arcs which are solid to be much thinner compared to */
634 /* lines, boxes, also of zero width */
635 if (o_current
->line_width
> 0) {
636 arc_width
= o_current
->line_width
;
641 arc_width
= o_current
->line_width
; /* Added instead of above */
643 if(toplevel
->line_style
== THICK
) {
644 arc_width
=LINE_WIDTH
;
650 length
= o_current
->line_length
;
651 space
= o_current
->line_space
;
653 switch(o_current
->line_type
) {
655 length
= -1; space
= -1;
656 outl_func
= o_arc_print_solid
;
661 outl_func
= o_arc_print_dotted
;
665 outl_func
= o_arc_print_dashed
;
669 outl_func
= o_arc_print_center
;
673 outl_func
= o_arc_print_phantom
;
677 /* Unused for now, print it solid */
678 length
= -1; space
= -1;
679 outl_func
= o_arc_print_solid
;
683 if((space
== 0) || (length
== 0)) {
684 length
= -1; space
= -1;
685 outl_func
= o_arc_print_solid
;
688 (*outl_func
)(toplevel
, fp
,
689 x
- origin_x
, y
- origin_x
, radius
,
690 start_angle
, end_angle
,
691 color
, arc_width
, length
, space
, origin_x
, origin_y
);
696 * \par Function Description
697 * This function prints an arc when a solid line type is required.
698 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
699 * in <B>radius</B> and the start and end angles of the arc on the circle.
700 * The postscript file is defined by the file pointer <B>fp</B>.
702 * The parameters <B>length</B> and <B>space</B> are ignored
703 * whereas <B>arc_width</B> specifies the width of the printed line.
705 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
707 * \param [in] toplevel The TOPLEVEL object.
708 * \param [in] fp FILE pointer to postscript document.
715 * \param [in] arc_width
718 * \param [in] origin_x
719 * \param [in] origin_y
721 void o_arc_print_solid(TOPLEVEL
*toplevel
, FILE *fp
,
722 int x
, int y
, int radius
,
723 int angle1
, int angle2
,
725 int arc_width
, int length
, int space
,
726 int origin_x
, int origin_y
)
728 f_print_set_color(toplevel
, fp
, color
);
730 /* inverting angle2 if < 0 and changing angle1 accordingly */
732 angle1
= angle1
+ angle2
;
736 fprintf(fp
, "%d %d %d %d %d %d darc\n",
737 x
,y
, radius
, angle1
, angle1
+ angle2
,
743 * \par Function Description
744 * This function prints an arc when a dotted line type is required.
745 * The arc is defined by its center in <B>x</B> and <B>y</B>, its
746 * radius in <B>radius</B> and the start and end angles of the arc on the circle.
747 * The postscript file is defined by the file pointer <B>fp</B>.
748 * The parameter <B>length</B> is ignored whereas <B>arc_width</B> specifies
749 * the diameter of the dots of the printed line and <B>space</B> the distance
752 * A negative value for <B>space</B> leads to an endless loop.
754 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
756 * The function sets the color the line will be printed with.
758 * \param [in] toplevel The TOPLEVEL object.
759 * \param [in] fp FILE pointer to postscript document.
766 * \param [in] arc_width
769 * \param [in] origin_x
770 * \param [in] origin_y
772 void o_arc_print_dotted(TOPLEVEL
*toplevel
, FILE *fp
,
773 int x
, int y
, int radius
,
774 int angle1
, int angle2
,
776 int arc_width
, int length
, int space
,
777 int origin_x
, int origin_y
)
781 f_print_set_color(toplevel
, fp
, color
);
784 * Depending on the radius of the arc, the <B>space</B> parameter is
785 * changed into a small angle <B>da</B>.
786 * Starting from <B>angle1</B> - the start angle - the dots are printed
787 * along the arc by increments of this new angle.
789 * As <B>da</B> is rounded as an integer, it can take a null value which
790 * will make the function enter an endless loop. In such a case, the arc
791 * is printed solid. The <B>da</B> variable should never be negative
792 * except if <B>space</B> is negative.
795 /* Inverting angle2 if < 0 and changing angle1 accordingly */
796 /* the loop test assume that da > 0 */
798 angle1
= angle1
+ angle2
;
801 da
= (int) ((space
* 180) / (M_PI
* ((double) radius
)));
803 /* If da or db too small for arc to be displayed as dotted,
806 o_arc_print_solid(toplevel
, fp
,
810 arc_width
, length
, space
, origin_x
, origin_y
);
816 while (d
< (angle2
+ angle1
)) {
817 /*xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
818 ya = ((double) y) + ((double) radius) * sin(d * M_PI / 180);
820 fprintf(fp
,"[%d] ",d
);
824 fprintf(fp
,"] %d %d %d %d dashedarc %% dotted\n",
825 x
,y
, radius
, arc_width
);
829 * \par Function Description
830 * This function prints an arc when a dashed line type is required.
831 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
832 * in <B>radius</B> and the start and end angles of the arc on the circle.
833 * The postscript file is defined by the file pointer <B>fp</B>.
834 * The parameter <B>arc_width</B> specifies the diameter of the dots of the printed line.
836 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
838 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
840 * The function sets the color the line will be printed with.
842 * \param [in] toplevel The TOPLEVEL object.
843 * \param [in] fp FILE pointer to postscript document.
850 * \param [in] arc_width
853 * \param [in] origin_x
854 * \param [in] origin_y
856 void o_arc_print_dashed(TOPLEVEL
*toplevel
, FILE *fp
,
857 int x
, int y
, int radius
,
858 int angle1
, int angle2
,
860 int arc_width
, int length
, int space
,
861 int origin_x
, int origin_y
)
865 f_print_set_color(toplevel
, fp
, color
);
868 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
869 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
870 * Starting from <B>angle1</B> - the start angle - the dashes are printed
871 * along the arc by increments of these new angles.
873 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a
874 * null value which will make the function enter an endless loop. In such a case,
875 * the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable should never
876 * be negative except if <B>space</B> (resp. <B>length</B>) is negative.
878 * It prints as many dashes of length <B>length</B> as possible.
881 /* Inverting angle2 if < 0 and changing angle1 accordingly */
882 /* the loop test assume that da > 0 */
884 angle1
= angle1
+ angle2
;
887 da
= (int) ((length
* 180) / (M_PI
* ((double) radius
)));
888 db
= (int) ((space
* 180) / (M_PI
* ((double) radius
)));
890 /* If da or db too small for arc to be displayed as dotted,
892 if ((da
<= 0) || (db
<= 0)) {
893 o_arc_print_solid(toplevel
, fp
,
897 arc_width
, length
, space
, origin_x
, origin_y
);
903 while ((d
+ da
+ db
) < (angle1
+ angle2
)) {
907 fprintf(fp
,"[%d %d] ",
913 * When the above condition is no more satisfied, then it is not
914 * possible to print a dash of length <B>length</B> and the following <B>space</B>.
915 * However it may be possible to print the complete dash or a shorter one.
918 if ((d
+ da
) < (angle1
+ angle2
)) {
924 fprintf(fp
,"[%d %d] ",
928 fprintf(fp
,"] %d %d %d %d dashedarc %% dashed\n",
929 x
,y
, radius
, arc_width
);
934 * \par Function Description
935 * This function prints an arc when a centered line type is required.
936 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius in
937 * <B>radius</B> and the start and end angles of the arc on the circle.
938 * The postscript file is defined by the file pointer <B>fp</B>.
939 * The parameter <B>arc_width</B> specifies the diameter of the dots and the width of the dashes of the printed line.
941 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
943 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
945 * The function sets the color in which the line will be printed with.
947 * \param [in] toplevel The TOPLEVEL object.
948 * \param [in] fp FILE pointer to postscript document.
955 * \param [in] arc_width
958 * \param [in] origin_x
959 * \param [in] origin_y
961 void o_arc_print_center(TOPLEVEL
*toplevel
, FILE *fp
,
962 int x
, int y
, int radius
,
963 int angle1
, int angle2
,
965 int arc_width
, int length
, int space
,
966 int origin_x
, int origin_y
)
970 f_print_set_color(toplevel
, fp
, color
);
973 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
974 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
975 * Starting from <B>angle1</B> - the start angle - the dashes are printed
976 * along the arc by increments of these new angles.
978 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a null
979 * value which will make the function enter an endless loop. In such a case,
980 * the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable should never
981 * be negative except if <B>space</B> (resp. <B>length</B>) is negative.
983 * It prints as many sets of dash-dot as possible.
986 /* Inverting angle2 if < 0 and changing angle1 accordingly */
987 /* the loop test assume that da > 0 */
989 angle1
= angle1
+ angle2
;
993 da
= (int) ((length
* 180) / (M_PI
* ((double) radius
)));
994 db
= (int) ((space
* 180) / (M_PI
* ((double) radius
)));
996 /* If da or db too small to be displayed, draw an arc */
997 if ((da
<= 0) || (db
<= 0)) {
998 o_arc_print_solid(toplevel
, fp
,
1002 arc_width
, length
, space
, origin_x
, origin_y
);
1008 while ((d
+ da
+ 2 * db
) < (angle1
+ angle2
)) {
1011 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1015 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1016 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1018 fprintf(fp
,"[%d] ",d
);
1022 * When the above condition is no more satisfied, then it is not
1023 * possible to print a dash of length <B>length</B>. However two cases are possible :
1025 * <DT>*</DT><DD>it is possible to print the dash and the dot
1026 * <DT>*</DT><DD>it is possible to print the dash or a part of the original dash
1030 if ((d
+ da
) < (angle1
+ angle2
)) {
1040 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1043 if ((d
+ db
) < (angle1
+ angle2
)) {
1045 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1046 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1048 fprintf(fp
,"[%d] ",d
);
1052 fprintf(fp
,"] %d %d %d %d dashedarc %% center\n",
1053 x
,y
, radius
, arc_width
);
1057 * A dot is represented by a filled circle. Position of the circle is (<B>xa</B>, <B>ya</B>)
1058 * and its radius is the <B>arc_width</B> parameter.
1062 * \par Function Description
1063 * This function prints an arc when a phantom line type is required.
1064 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
1065 * in <B>radius</B> and the start and end angles of the arc on the circle.
1066 * The postscript file is defined by the file pointer <B>fp</B>.
1067 * The parameter <B>arc_width</B> specifies the diameter of the dots and the width of the dashes of the printed line.
1069 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
1071 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
1073 * The function sets the color in which the line will be printed with.
1075 * \param [in] toplevel The TOPLEVEL object.
1076 * \param [in] fp FILE pointer to postscript document.
1079 * \param [in] radius
1080 * \param [in] angle1
1081 * \param [in] angle2
1083 * \param [in] arc_width
1084 * \param [in] length
1086 * \param [in] origin_x
1087 * \param [in] origin_y
1089 void o_arc_print_phantom(TOPLEVEL
*toplevel
, FILE *fp
,
1090 int x
, int y
, int radius
,
1091 int angle1
, int angle2
,
1093 int arc_width
, int length
, int space
,
1094 int origin_x
, int origin_y
)
1098 f_print_set_color(toplevel
, fp
, color
);
1101 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
1102 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
1103 * Starting from <B>angle1</B> - the start angle - the dashes are printed
1104 * along the arc by increments of these new angles.
1106 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a
1107 * null value which will make the function enter an endless loop. In such
1108 * a case, the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable
1109 * should never be negative except if <B>space</B> (resp. <B>length</B>) is negative.
1111 * It prints as many sets of dash-dot-dot as possible.
1114 /* Inverting angle2 if < 0 and changing angle1 accordingly */
1115 /* the loop test assume that da > 0 */
1117 angle1
= angle1
+ angle2
;
1120 da
= (int) ((length
* 180) / (((double) radius
) * M_PI
));
1121 db
= (int) ((space
* 180) / (((double) radius
) * M_PI
));
1123 /* If da or db too small for arc to be displayed as dotted,
1125 if ((da
<= 0) || (db
<= 0)) {
1126 o_arc_print_solid(toplevel
, fp
,
1130 arc_width
, length
, space
, origin_x
, origin_y
);
1137 while ((d
+ da
+ 3 * db
) < (angle1
+ angle2
)) {
1141 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1145 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1146 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1148 fprintf(fp
,"[%d] ",d
);
1153 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1154 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1156 fprintf(fp
,"[%d] ",d
);
1162 * When the above condition is no more satisfied, then it is not
1163 * possible to print a dash of length <B>length</B>.
1164 * However three cases are possible :
1166 * <DT>*</DT><DD>it is possible to print a dash and a dot and a dot
1167 * <DT>*</DT><DD>it is possible to print a dash and a dot
1168 * <DT>*</DT><DD>it is possible to print the dash or a part of the original dash
1172 if ((d
+ da
) < (angle1
+ angle2
)) {
1180 fprintf(fp
,"[%d %d] ",(int) a1
, (int) a1
+ da
);
1182 if ((d
+ db
) < (angle1
+ angle2
)) {
1186 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1187 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1189 fprintf(fp
,"[%d] ",d
);
1193 if ((d
+ db
) < (angle1
+ angle2
)) {
1197 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1198 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1201 fprintf(fp
,"[%d] ",d
);
1206 fprintf(fp
,"] %d %d %d %d dashedarc %% phantom\n",
1207 x
,y
, radius
, arc_width
);
1210 /*! \brief Calculates the distance between the given point and the closest
1211 * point on the perimeter of the arc.
1213 * \param [in] object The arc OBJECT.
1214 * \param [in] x The x coordinate of the given point.
1215 * \param [in] y The y coordinate of the given point.
1216 * \param [in] force_solid If true, force treating the object as solid.
1217 * \return The shortest distance from the object to the point. With an
1218 * invalid parameter, this function returns G_MAXDOUBLE.
1220 double o_arc_shortest_distance (OBJECT
*object
, int x
, int y
, int force_solid
)
1222 double shortest_distance
;
1225 g_return_val_if_fail (object
->arc
!= NULL
, G_MAXDOUBLE
);
1227 radius
= ((double)object
->arc
->width
) / 2.0;
1229 if (o_arc_within_sweep (object
->arc
, x
, y
)) {
1230 double distance_to_center
;
1234 dx
= ((double)x
) - ((double)object
->arc
->x
);
1235 dy
= ((double)y
) - ((double)object
->arc
->y
);
1237 distance_to_center
= sqrt ((dx
* dx
) + (dy
* dy
));
1239 shortest_distance
= fabs (distance_to_center
- radius
);
1243 double distance_to_end0
;
1244 double distance_to_end1
;
1247 angle
= G_PI
* ((double)object
->arc
->start_angle
) / 180;
1249 dx
= ((double)x
) - radius
* cos (angle
) - ((double)object
->arc
->x
);
1250 dy
= ((double)y
) - radius
* sin (angle
) - ((double)object
->arc
->y
);
1252 distance_to_end0
= sqrt ((dx
* dx
) + (dy
* dy
));
1254 angle
+= G_PI
* ((double)object
->arc
->end_angle
) / 180;
1256 dx
= ((double)x
) - radius
* cos (angle
) - ((double)object
->arc
->x
);
1257 dy
= ((double)y
) - radius
* sin (angle
) - ((double)object
->arc
->y
);
1259 distance_to_end1
= sqrt ((dx
* dx
) + (dy
* dy
));
1261 shortest_distance
= min (distance_to_end0
, distance_to_end1
);
1264 return shortest_distance
;
1267 /*! \brief Determines if a point lies within the sweep of the arc.
1269 * \param [in] arc The arc of object
1270 * \param [in] x The x coordinate of the given point.
1271 * \param [in] y The y coordinate of the given point.
1272 * \return TRUE if the point lies within the sweep of the arc.
1273 * FALSE if the point lies outside the sweep of the arc. With an
1274 * invalid parameter, this function returns FALSE.
1276 gboolean
o_arc_within_sweep(ARC
*arc
, gint x
, gint y
)
1285 g_critical("o_arc_within_sweep(): arc == NULL\n");
1289 dx
= ((gdouble
) x
) - ((gdouble
) arc
->x
);
1290 dy
= ((gdouble
) y
) - ((gdouble
) arc
->y
);
1292 angle
= 180 * atan2(dy
, dx
) / G_PI
;
1294 if (arc
->end_angle
> 0) {
1295 a0
= arc
->start_angle
;
1296 a1
= arc
->start_angle
+ arc
->end_angle
;
1298 a0
= arc
->start_angle
+ arc
->end_angle
+ 360;
1299 a1
= arc
->start_angle
+ 360;
1302 while (angle
< a0
) {
1306 return (angle
< a1
);