Hunt down some unused variables.
[geda-gaf/berndj.git] / libgeda / src / o_arc_basic.c
blob6e99adb21c763bffd8b84425387dd8c817594ab4
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
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 struct st_arc {
37 int x, y; /* world */
39 int width;
40 int height;
42 int start_angle;
43 int end_angle;
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,
51 enum grip_t whichone,
52 void *userdata),
53 void *userdata);
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)
72 OBJECT *new_node;
73 ARC *arc;
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));
80 new_node->arc = arc;
82 new_node->arc->x = x;
83 new_node->arc->y = y;
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;
97 /* Default init */
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);
103 return new_node;
106 /*! \brief
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.
125 * \param [in] type
126 * \param [in] color
127 * \param [in] x
128 * \param [in] y
129 * \param [in] radius
130 * \param [in] start_angle
131 * \param [in] end_angle
132 * \return
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)
138 OBJECT *new_node;
140 new_node = o_arc_new_at_xy(toplevel, type, color, x, y);
142 /*! \note
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 ... */
155 if(end_angle < 0) {
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 */
166 return new_node;
169 /*! \brief
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)
184 OBJECT *new_obj;
185 int color;
187 if (o_current->saved_color == -1) {
188 color = o_current->color;
189 } else {
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);
204 return new_obj;
207 /*! \brief
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.
227 * \param [in] buf
228 * \param [in] release_ver
229 * \param [in] fileformat_ver
230 * \return
232 OBJECT *o_arc_read(TOPLEVEL *toplevel, char buf[],
233 unsigned int release_ver, unsigned int fileformat_ver)
235 OBJECT *new_obj;
236 char type;
237 int x1, y1;
238 int radius;
239 int start_angle, end_angle;
240 int color;
241 int arc_width, arc_length, arc_space;
242 int arc_type;
243 int arc_end;
245 /*! \note
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);
254 arc_width = 0;
255 arc_end = END_NONE;
256 arc_type = TYPE_SOLID;
257 arc_space = -1;
258 arc_length= -1;
259 } else {
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);
266 /* Error check */
267 if (radius <= 0) {
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"));
275 color = WHITE;
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,
283 arc_space);
284 o_set_fill_options(new_obj, FILLING_HOLLOW, -1, -1, -1, -1, -1);
286 return new_obj;
289 /*! \brief
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.
298 * \param [in] object
299 * \return
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)
307 int color;
308 int x, y, radius, start_angle, end_angle;
309 int arc_width, arc_length, arc_space;
310 char *buf;
311 OBJECT_END arc_end;
312 OBJECT_TYPE arc_type;
314 /* radius, center and angles of the arc */
315 radius = object->arc->width / 2;
316 x = object->arc->x;
317 y = object->arc->y;
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;
331 } else {
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);
340 return(buf);
343 /*! \brief
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.
348 * \param [in] dx
349 * \param [in] dy
350 * \param [in] object
352 void o_arc_translate_world(int dx, int dy, OBJECT *object)
354 if (object == NULL) {
355 return;
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);
367 /*! \brief
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
383 * \param [in] angle
384 * \param [in] object
386 void o_arc_rotate_world(int world_centerx, int world_centery, int angle,
387 OBJECT *object)
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 */
396 x = object->arc->x;
397 y = object->arc->y;
398 if(angle % 90 == 0) {
399 rotate_point_90(x, y, angle % 360, &newx, &newy);
400 } else {
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
433 * \param [in] object
435 void o_arc_mirror_world(int world_centerx, int world_centery,
436 OBJECT *object)
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);
499 /*! \brief
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>
504 * pointed structure.
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) {
516 return;
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,
532 void *userdata),
533 void *userdata)
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[] = {
543 .x = centerx,
544 .y = centery,
545 .whichone = GRIP_ARC_CENTER,
548 .x = centerx,
549 .y = centery,
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;
572 switch (whichone) {
573 double radius, theta, r_cos_theta, r_sin_theta;
574 case GRIP_NONE:
575 o->arc->x = x;
576 o->arc->y = y;
577 o->arc->width = 0;
578 o->arc->height = 0;
579 o->arc->start_angle = 0;
580 o->arc->end_angle = 180;
581 retval = GRIP_ARC_RADIUS;
582 break;
584 case GRIP_ARC_CENTER:
585 o->arc->x = x;
586 o->arc->y = y;
587 retval = GRIP_ARC_RADIUS;
588 break;
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;
595 break;
596 case GRIP_START_ANGLE:
597 case GRIP_END_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);
602 if (theta < 0) {
603 theta += 2*M_PI;
605 theta *= 180 / M_PI;
606 switch (whichone) {
607 case GRIP_START_ANGLE:
608 o->arc->start_angle = rint(theta);
609 retval = GRIP_END_ANGLE;
610 break;
611 case GRIP_END_ANGLE:
612 theta -= o->arc->start_angle;
613 if (theta < 0) {
614 theta += 360;
616 o->arc->end_angle = rint(theta);
617 retval = GRIP_NONE;
618 break;
620 break;
623 o_arc_recalc(o);
625 return retval;
628 /*! \brief
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.
640 * \param [in] object
641 * \param [out] left
642 * \param [out] top
643 * \param [out] right
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;
651 int i, angle;
652 int halfwidth;
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;
660 x1 = object->arc->x;
661 y1 = object->arc->y;
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);
672 /*! \note
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.
681 if (end_angle < 0) {
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++) {
687 angle = angle + 90;
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;
693 } else {
694 break;
698 /* This isn't strictly correct, but a 1st order approximation */
699 *left -= halfwidth;
700 *top -= halfwidth;
701 *right += halfwidth;
702 *bottom += halfwidth;
707 /*! \brief
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;
726 int color;
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");
732 return;
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;
742 /*! \note
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;
758 } else {
759 arc_width = 1;
761 #endif
762 arc_width = o_current->line_width; /* Added instead of above */
763 if(arc_width <=2) {
764 if(toplevel->line_style == THICK) {
765 arc_width=LINE_WIDTH;
766 } else {
767 arc_width=2;
771 length = o_current->line_length;
772 space = o_current->line_space;
774 switch(o_current->line_type) {
775 case(TYPE_SOLID):
776 length = -1; space = -1;
777 outl_func = o_arc_print_solid;
778 break;
780 case(TYPE_DOTTED):
781 length = -1;
782 outl_func = o_arc_print_dotted;
783 break;
785 case(TYPE_DASHED):
786 outl_func = o_arc_print_dashed;
787 break;
789 case(TYPE_CENTER):
790 outl_func = o_arc_print_center;
791 break;
793 case(TYPE_PHANTOM):
794 outl_func = o_arc_print_phantom;
795 break;
797 case(TYPE_ERASE):
798 /* Unused for now, print it solid */
799 length = -1; space = -1;
800 outl_func = o_arc_print_solid;
801 break;
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);
816 /*! \brief
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.
830 * \param [in] x
831 * \param [in] y
832 * \param [in] radius
833 * \param [in] angle1
834 * \param [in] angle2
835 * \param [in] color
836 * \param [in] arc_width
837 * \param [in] length
838 * \param [in] space
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,
845 int color,
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 */
854 if (angle2 < 0) {
855 angle1 = angle1 + angle2;
856 angle2 = -angle2;
859 fprintf(fp, "%d %d %d %d %d %d darc\n",
860 x,y, radius, angle1, angle1 + angle2,
861 arc_width);
865 /*! \brief
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
873 * between two dots.
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.
883 * \param [in] x
884 * \param [in] y
885 * \param [in] radius
886 * \param [in] angle1
887 * \param [in] angle2
888 * \param [in] color
889 * \param [in] arc_width
890 * \param [in] length
891 * \param [in] space
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,
898 int color,
899 int arc_width, int length, int space,
900 int origin_x, int origin_y)
902 int da, d;
905 if (toplevel->print_color) {
906 f_print_set_color(fp, color);
909 /*! \note
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 */
923 if (angle2 < 0) {
924 angle1 = angle1 + angle2;
925 angle2 = -angle2;
927 da = (int) ((space * 180) / (M_PI * ((double) radius)));
929 /* If da or db too small for arc to be displayed as dotted,
930 draw a solid arc */
931 if (da <= 0) {
932 o_arc_print_solid(toplevel, fp,
933 x, y, radius,
934 angle1, angle2,
935 color,
936 arc_width, length, space, origin_x, origin_y);
937 return;
940 fprintf(fp,"[");
941 d = angle1;
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);
948 d = d + da;
950 fprintf(fp,"] %d %d %d %d dashedarc %% dotted\n",
951 x,y, radius, arc_width);
954 /*! \brief
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.
970 * \param [in] x
971 * \param [in] y
972 * \param [in] radius
973 * \param [in] angle1
974 * \param [in] angle2
975 * \param [in] color
976 * \param [in] arc_width
977 * \param [in] length
978 * \param [in] space
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,
985 int color,
986 int arc_width, int length, int space,
987 int origin_x, int origin_y)
989 int da, db, a1, d;
991 if (toplevel->print_color) {
992 f_print_set_color(fp, color);
995 /*! \note
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 */
1011 if (angle2 < 0) {
1012 angle1 = angle1 + angle2;
1013 angle2 = -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,
1019 draw a solid arc */
1020 if ((da <= 0) || (db <= 0)) {
1021 o_arc_print_solid(toplevel, fp,
1022 x, y, radius,
1023 angle1, angle2,
1024 color,
1025 arc_width, length, space, origin_x, origin_y);
1026 return;
1029 fprintf(fp,"[");
1030 d = angle1;
1031 while ((d + da + db) < (angle1 + angle2)) {
1032 a1 = d;
1033 d = d + da;
1035 fprintf(fp,"[%d %d] ",
1036 a1, a1+da);
1038 d = d + db;
1040 /*! \note
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)) {
1047 a1 = d;
1048 } else {
1049 a1 = d;
1052 fprintf(fp,"[%d %d] ",
1053 a1, a1+da);
1056 fprintf(fp,"] %d %d %d %d dashedarc %% dashed\n",
1057 x,y, radius, arc_width);
1060 /*! \brief
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.
1076 * \param [in] x
1077 * \param [in] y
1078 * \param [in] radius
1079 * \param [in] angle1
1080 * \param [in] angle2
1081 * \param [in] color
1082 * \param [in] arc_width
1083 * \param [in] length
1084 * \param [in] space
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,
1091 int color,
1092 int arc_width, int length, int space,
1093 int origin_x, int origin_y)
1095 int da, db, a1, d;
1097 if (toplevel->print_color) {
1098 f_print_set_color(fp, color);
1101 /*! \note
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 */
1117 if (angle2 < 0) {
1118 angle1 = angle1 + angle2;
1119 angle2 = -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,
1128 x, y, radius,
1129 angle1, angle2,
1130 color,
1131 arc_width, length, space, origin_x, origin_y);
1132 return;
1135 fprintf(fp, "[");
1136 d = angle1;
1137 while ((d + da + 2 * db) < (angle1 + angle2)) {
1138 a1 = d;
1139 d = d + da;
1140 fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
1142 d = d + db;
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);
1148 d = d + db;
1150 /*! \note
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 :
1153 * <DL>
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
1156 * </DL>
1159 a1 = d;
1161 d = d + da;
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);
1177 /*! \note
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.
1182 /*! \brief
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.
1198 * \param [in] x
1199 * \param [in] y
1200 * \param [in] radius
1201 * \param [in] angle1
1202 * \param [in] angle2
1203 * \param [in] color
1204 * \param [in] arc_width
1205 * \param [in] length
1206 * \param [in] space
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,
1213 int color,
1214 int arc_width, int length, int space,
1215 int origin_x, int origin_y)
1217 int da, db, a1, d;
1219 if (toplevel->print_color) {
1220 f_print_set_color(fp, color);
1223 /*! \note
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 */
1239 if (angle2 < 0) {
1240 angle1 = angle1 + angle2;
1241 angle2 = -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,
1247 draw a solid arc */
1248 if ((da <= 0) || (db <= 0)) {
1249 o_arc_print_solid(toplevel, fp,
1250 x, y, radius,
1251 angle1, angle2,
1252 color,
1253 arc_width, length, space, origin_x, origin_y);
1254 return;
1257 fprintf(fp,"[");
1259 d = angle1;
1260 while ((d + da + 3 * db) < (angle1 + angle2)) {
1261 a1 = d;
1262 d = d + da;
1264 fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
1266 d = d + db;
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);
1273 d = d + db;
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);
1281 d = d + db;
1284 /*! \note
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 :
1288 * <DL>
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
1292 * </DL>
1295 a1 = d;
1296 d = d + da;
1298 fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
1300 if ((d + db) < (angle1 + angle2)) {
1301 d = d + db;
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)) {
1311 d = d + db;
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)
1336 gdouble radius;
1337 gdouble shortest_distance;
1339 if (arc == NULL) {
1340 g_critical("o_arc_shortest_distance(): arc == NULL\n");
1341 return G_MAXDOUBLE;
1344 radius = ((gdouble) arc->width) / 2.0;
1346 if ( o_arc_within_sweep(arc, x, y) ) {
1347 gdouble distance_to_center;
1348 gdouble dx;
1349 gdouble dy;
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);
1358 else {
1359 gdouble angle;
1360 gdouble distance_to_end0;
1361 gdouble distance_to_end1;
1362 gdouble dx;
1363 gdouble dy;
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)
1396 gdouble a0;
1397 gdouble a1;
1398 gdouble angle;
1399 gdouble dx;
1400 gdouble dy;
1402 if (arc == NULL) {
1403 g_critical("o_arc_within_sweep(): arc == NULL\n");
1404 return FALSE;
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) {
1416 angle+=360;
1419 return (angle < a1);