gnetlist: Add basic concatenated net support for verilog.
[geda-gaf/whiteaudio.git] / libgeda / src / o_arc_basic.c
blob52dadaf27ca11785291c9bf9840e30bc87abb973
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
25 #include <config.h>
27 #include <stdio.h>
28 #include <math.h>
30 #include "libgeda_priv.h"
32 #ifdef HAVE_LIBDMALLOC
33 #include <dmalloc.h>
34 #endif
36 /*! \brief
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.
55 * \param [in] type
56 * \param [in] color
57 * \param [in] x
58 * \param [in] y
59 * \param [in] radius
60 * \param [in] start_angle
61 * \param [in] end_angle
62 * \return
64 OBJECT *o_arc_new(TOPLEVEL *toplevel,
65 char type, int color,
66 int x, int y, int radius, int start_angle, int end_angle)
69 OBJECT *new_node;
71 new_node = s_basic_new_object(type, "arc");
73 new_node->color = color;
75 new_node->arc = (ARC *) g_malloc(sizeof(ARC));
77 /*! \note
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 */
86 new_node->arc->x = x;
87 new_node->arc->y = y;
88 new_node->arc->width = 2 * radius;
89 new_node->arc->height = 2 * radius;
91 /* must check the sign of start_angle, end_angle ... */
92 if(end_angle < 0) {
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;
101 /* Default init */
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 */
111 return new_node;
114 /*! \brief
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)
129 OBJECT *new_obj;
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);
143 return new_obj;
146 /*! \brief
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
167 * \param [in] x
168 * \param [in] y
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);
177 switch(whichone) {
178 case ARC_CENTER:
179 /* modify the center of arc object */
180 object->arc->x = x;
181 object->arc->y = y;
182 break;
184 case ARC_RADIUS:
185 /* modify the radius of arc object */
186 object->arc->width = 2 * x;
187 object->arc->height = 2 * x;
188 break;
190 case ARC_START_ANGLE:
191 /* modify the start angle of the arc object */
192 object->arc->start_angle = x;
193 break;
195 case ARC_END_ANGLE:
196 /* modify the end angle of the arc object */
197 object->arc->end_angle = x;
198 break;
200 default:
201 break;
204 /* update the screen coords and the bounding box */
205 o_arc_recalc(toplevel, object);
206 o_emit_change_notify (toplevel, object);
209 /*! \brief
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.
230 * \param [in] buf
231 * \param [in] release_ver
232 * \param [in] fileformat_ver
233 * \return
235 OBJECT *o_arc_read (TOPLEVEL *toplevel, char buf[],
236 unsigned int release_ver, unsigned int fileformat_ver)
238 OBJECT *new_obj;
239 char type;
240 int x1, y1;
241 int radius;
242 int start_angle, end_angle;
243 int color;
244 int arc_width, arc_length, arc_space;
245 int arc_type;
246 int arc_end;
248 /*! \note
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);
257 arc_width = 0;
258 arc_end = END_NONE;
259 arc_type = TYPE_SOLID;
260 arc_space = -1;
261 arc_length= -1;
262 } else {
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);
269 /* Error check */
270 if (radius <= 0) {
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,
286 arc_space);
287 o_set_fill_options(toplevel, new_obj,
288 FILLING_HOLLOW, -1, -1, -1,
289 -1, -1);
291 return new_obj;
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
302 * \param [in] object
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;
309 char *buf;
310 OBJECT_END arc_end;
311 OBJECT_TYPE arc_type;
313 /* radius, center and angles of the arc */
314 radius = object->arc->width / 2;
315 x = object->arc->x;
316 y = object->arc->y;
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);
332 return(buf);
335 /*! \brief
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.
341 * \param [in] dx
342 * \param [in] dy
343 * \param [in] object
345 void o_arc_translate_world(TOPLEVEL *toplevel, int dx, int dy,
346 OBJECT *object)
348 if (object == NULL) {
349 return;
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);
361 /*! \brief
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
378 * \param [in] angle
379 * \param [in] object
381 void o_arc_rotate_world(TOPLEVEL *toplevel,
382 int world_centerx, int world_centery, int angle,
383 OBJECT *object)
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 */
392 x = object->arc->x;
393 y = object->arc->y;
394 if(angle % 90 == 0) {
395 rotate_point_90(x, y, angle % 360, &newx, &newy);
396 } else {
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
430 * \param [in] object
432 void o_arc_mirror_world(TOPLEVEL *toplevel,
433 int world_centerx, int world_centery,
434 OBJECT *object)
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);
459 /*! \brief
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>
464 * pointed structure.
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) {
477 return;
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;
490 /*! \brief
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.
502 * \param [in] object
503 * \param [out] left
504 * \param [out] top
505 * \param [out] right
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;
513 int i, angle;
514 int halfwidth;
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;
522 x1 = object->arc->x;
523 y1 = object->arc->y;
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);
534 /*! \note
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.
543 if (end_angle < 0) {
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++) {
549 angle = angle + 90;
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;
555 } else {
556 break;
560 /* This isn't strictly correct, but a 1st order approximation */
561 *left -= halfwidth;
562 *top -= halfwidth;
563 *right += halfwidth;
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,
579 OBJECT *object)
581 *x = object->arc->x;
582 *y = object->arc->y;
583 return TRUE;
586 /*! \brief
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;
605 int color;
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");
611 return;
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;
621 /*! \note
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;
637 } else {
638 arc_width = 1;
640 #endif
641 arc_width = o_current->line_width; /* Added instead of above */
642 if(arc_width <=2) {
643 if(toplevel->line_style == THICK) {
644 arc_width=LINE_WIDTH;
645 } else {
646 arc_width=2;
650 length = o_current->line_length;
651 space = o_current->line_space;
653 switch(o_current->line_type) {
654 case(TYPE_SOLID):
655 length = -1; space = -1;
656 outl_func = o_arc_print_solid;
657 break;
659 case(TYPE_DOTTED):
660 length = -1;
661 outl_func = o_arc_print_dotted;
662 break;
664 case(TYPE_DASHED):
665 outl_func = o_arc_print_dashed;
666 break;
668 case(TYPE_CENTER):
669 outl_func = o_arc_print_center;
670 break;
672 case(TYPE_PHANTOM):
673 outl_func = o_arc_print_phantom;
674 break;
676 case(TYPE_ERASE):
677 /* Unused for now, print it solid */
678 length = -1; space = -1;
679 outl_func = o_arc_print_solid;
680 break;
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);
695 /*! \brief
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.
709 * \param [in] x
710 * \param [in] y
711 * \param [in] radius
712 * \param [in] angle1
713 * \param [in] angle2
714 * \param [in] color
715 * \param [in] arc_width
716 * \param [in] length
717 * \param [in] space
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,
724 int color,
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 */
731 if (angle2 < 0) {
732 angle1 = angle1 + angle2;
733 angle2 = -angle2;
736 fprintf(fp, "%d %d %d %d %d %d darc\n",
737 x,y, radius, angle1, angle1 + angle2,
738 arc_width);
742 /*! \brief
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
750 * between two dots.
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.
760 * \param [in] x
761 * \param [in] y
762 * \param [in] radius
763 * \param [in] angle1
764 * \param [in] angle2
765 * \param [in] color
766 * \param [in] arc_width
767 * \param [in] length
768 * \param [in] space
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,
775 int color,
776 int arc_width, int length, int space,
777 int origin_x, int origin_y)
779 int da, d;
781 f_print_set_color(toplevel, fp, color);
783 /*! \note
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 */
797 if (angle2 < 0) {
798 angle1 = angle1 + angle2;
799 angle2 = -angle2;
801 da = (int) ((space * 180) / (M_PI * ((double) radius)));
803 /* If da or db too small for arc to be displayed as dotted,
804 draw a solid arc */
805 if (da <= 0) {
806 o_arc_print_solid(toplevel, fp,
807 x, y, radius,
808 angle1, angle2,
809 color,
810 arc_width, length, space, origin_x, origin_y);
811 return;
814 fprintf(fp,"[");
815 d = angle1;
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);
822 d = d + da;
824 fprintf(fp,"] %d %d %d %d dashedarc %% dotted\n",
825 x,y, radius, arc_width);
828 /*! \brief
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.
844 * \param [in] x
845 * \param [in] y
846 * \param [in] radius
847 * \param [in] angle1
848 * \param [in] angle2
849 * \param [in] color
850 * \param [in] arc_width
851 * \param [in] length
852 * \param [in] space
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,
859 int color,
860 int arc_width, int length, int space,
861 int origin_x, int origin_y)
863 int da, db, a1, d;
865 f_print_set_color(toplevel, fp, color);
867 /*! \note
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 */
883 if (angle2 < 0) {
884 angle1 = angle1 + angle2;
885 angle2 = -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,
891 draw a solid arc */
892 if ((da <= 0) || (db <= 0)) {
893 o_arc_print_solid(toplevel, fp,
894 x, y, radius,
895 angle1, angle2,
896 color,
897 arc_width, length, space, origin_x, origin_y);
898 return;
901 fprintf(fp,"[");
902 d = angle1;
903 while ((d + da + db) < (angle1 + angle2)) {
904 a1 = d;
905 d = d + da;
907 fprintf(fp,"[%d %d] ",
908 a1, a1+da);
910 d = d + db;
912 /*! \note
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)) {
919 a1 = d;
920 } else {
921 a1 = d;
924 fprintf(fp,"[%d %d] ",
925 a1, a1+da);
928 fprintf(fp,"] %d %d %d %d dashedarc %% dashed\n",
929 x,y, radius, arc_width);
933 /*! \brief
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.
949 * \param [in] x
950 * \param [in] y
951 * \param [in] radius
952 * \param [in] angle1
953 * \param [in] angle2
954 * \param [in] color
955 * \param [in] arc_width
956 * \param [in] length
957 * \param [in] space
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,
964 int color,
965 int arc_width, int length, int space,
966 int origin_x, int origin_y)
968 int da, db, a1, d;
970 f_print_set_color(toplevel, fp, color);
972 /*! \note
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 */
988 if (angle2 < 0) {
989 angle1 = angle1 + angle2;
990 angle2 = -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,
999 x, y, radius,
1000 angle1, angle2,
1001 color,
1002 arc_width, length, space, origin_x, origin_y);
1003 return;
1006 fprintf(fp, "[");
1007 d = angle1;
1008 while ((d + da + 2 * db) < (angle1 + angle2)) {
1009 a1 = d;
1010 d = d + da;
1011 fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
1013 d = d + db;
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);
1019 d = d + db;
1021 /*! \note
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 :
1024 * <DL>
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
1027 * </DL>
1030 if ((d + da) < (angle1 + angle2)) {
1031 a1 = d;
1033 d = d + da;
1034 } else {
1035 a1 = d;
1037 d = d + da;
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);
1056 /*! \note
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.
1061 /*! \brief
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.
1077 * \param [in] x
1078 * \param [in] y
1079 * \param [in] radius
1080 * \param [in] angle1
1081 * \param [in] angle2
1082 * \param [in] color
1083 * \param [in] arc_width
1084 * \param [in] length
1085 * \param [in] space
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,
1092 int color,
1093 int arc_width, int length, int space,
1094 int origin_x, int origin_y)
1096 int da, db, a1, d;
1098 f_print_set_color(toplevel, fp, color);
1100 /*! \note
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 */
1116 if (angle2 < 0) {
1117 angle1 = angle1 + angle2;
1118 angle2 = -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,
1124 draw a solid arc */
1125 if ((da <= 0) || (db <= 0)) {
1126 o_arc_print_solid(toplevel, fp,
1127 x, y, radius,
1128 angle1, angle2,
1129 color,
1130 arc_width, length, space, origin_x, origin_y);
1131 return;
1134 fprintf(fp,"[");
1136 d = angle1;
1137 while ((d + da + 3 * db) < (angle1 + angle2)) {
1138 a1 = d;
1139 d = d + da;
1141 fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
1143 d = d + db;
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);
1150 d = d + db;
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);
1158 d = d + db;
1161 /*! \note
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 :
1165 * <DL>
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
1169 * </DL>
1172 if ((d + da) < (angle1 + angle2)) {
1173 a1 = d;
1174 d = d + da;
1175 } else {
1176 a1 = d;
1177 d = d + da;
1180 fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
1182 if ((d + db) < (angle1 + angle2)) {
1183 d = d + db;
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)) {
1194 d = d + db;
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;
1223 double radius;
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;
1231 double dx;
1232 double dy;
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);
1241 } else {
1242 double angle;
1243 double distance_to_end0;
1244 double distance_to_end1;
1245 double dx, dy;
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)
1278 gdouble a0;
1279 gdouble a1;
1280 gdouble angle;
1281 gdouble dx;
1282 gdouble dy;
1284 if (arc == NULL) {
1285 g_critical("o_arc_within_sweep(): arc == NULL\n");
1286 return FALSE;
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;
1297 } else {
1298 a0 = arc->start_angle + arc->end_angle + 360;
1299 a1 = arc->start_angle + 360;
1302 while (angle < a0) {
1303 angle+=360;
1306 return (angle < a1);