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)
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 /*! \file o_circle_basic.c
22  *  \brief functions for the circle object
23  */
24 
25 #include <config.h>
26 #include <stdio.h>
27 #include <math.h>
28 
29 #include "libgeda_priv.h"
30 
31 #ifdef HAVE_LIBDMALLOC
32 #include <dmalloc.h>
33 #endif
34 
35 /*! \brief calculate the distance between two points
36  *  \par Function Description
37  *  This function calculates the distance between two points.
38  *  The two points are defined by the (\a x1, \a y1) and (\a x2, \a y2)
39  *  parameters.
40  *  \param [in]  x1  x-value of the first point
41  *  \param [in]  y1  y-value of the first point
42  *  \param [in]  x2  x-value of the second point
43  *  \param [in]  y2  y-value of the second point
44  *  \return the distance
45  *  \todo Move this function to a different place
46  */
dist(int x1,int y1,int x2,int y2)47 int dist(int x1, int y1, int x2, int y2)
48 {
49   return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
50 }
51 
52 /*! \brief Create and add circle OBJECT to list.
53  *  \par Function Description
54  *  This function creates a new object representing a circle.
55  *
56  *  The circle is described by its center (<B>x</B>,<B>y</B>) and its radius
57  *  <B>radius</B>.
58  *  The <B>type</B> parameter must be equal to <B>OBJ_CIRCLE</B>. The <B>color</B>
59  *  corresponds to the color the box will be drawn with.
60  *
61  *  The <B>OBJECT</B> structure is allocated with the #s_basic_new_object()
62  *  function. The structure describing the circle is allocated and initialized
63  *  with the parameters given to the function.
64  *
65  *  Both the line type and the filling type are set to default values : solid
66  *  line type with a width of 0, and no filling. It can be changed after
67  *  with #o_set_line_options() and #o_set_fill_options().
68  *
69  *  \param [in]     toplevel     The TOPLEVEL object.
70  *  \param [in]     type         Must be OBJ_CIRCLE.
71  *  \param [in]     color        Circle line color.
72  *  \param [in]     x            Center x coordinate.
73  *  \param [in]     y            Center y coordinate.
74  *  \param [in]     radius       Radius of new circle.
75  *  \return A pointer to the new end of the object list.
76  */
o_circle_new(TOPLEVEL * toplevel,char type,int color,int x,int y,int radius)77 OBJECT *o_circle_new(TOPLEVEL *toplevel,
78 		     char type, int color,
79 		     int x, int y, int radius)
80 {
81   OBJECT *new_node;
82 
83   /* create the object */
84   new_node = s_basic_new_object(type, "circle");
85   new_node->color  = color;
86 
87   new_node->circle = (CIRCLE *) g_malloc(sizeof(CIRCLE));
88 
89   /* describe the circle with its center and radius */
90   new_node->circle->center_x = x;
91   new_node->circle->center_y = y;
92   new_node->circle->radius   = radius;
93 
94   /* line type and filling initialized to default */
95   o_set_line_options(toplevel, new_node,
96 		     END_NONE, TYPE_SOLID, 0, -1, -1);
97   o_set_fill_options(toplevel, new_node,
98 		     FILLING_HOLLOW, -1, -1, -1, -1, -1);
99 
100   /* compute the bounding box coords */
101   o_circle_recalc(toplevel, new_node);
102 
103   return new_node;
104 }
105 
106 /*! \brief Create a copy of a circle.
107  *  \par Function Description
108  *  The function #o_circle_copy() creates a verbatim copy of the object
109  *  pointed by <B>o_current</B> describing a circle.
110  *
111  *  \param [in]  toplevel  The TOPLEVEL object.
112  *  \param [in]  o_current  Circle OBJECT to copy.
113  *  \return The new OBJECT
114  */
o_circle_copy(TOPLEVEL * toplevel,OBJECT * o_current)115 OBJECT *o_circle_copy(TOPLEVEL *toplevel, OBJECT *o_current)
116 {
117   OBJECT *new_obj;
118 
119   /* A new circle object is created with #o_circle_new().
120    * Values for its fields are default and need to be modified. */
121   new_obj = o_circle_new (toplevel, OBJ_CIRCLE, o_current->color, 0, 0, 0);
122 
123   /*
124    * The parameters of the new circle are set with the ones of the original
125    * circle. The two circle have the same line type and the same filling
126    * options.
127    *
128    * The bounding box coordinates are computed with
129    * #o_circle_recalc().
130    */
131   /* modify */
132   new_obj->circle->center_x = o_current->circle->center_x;
133   new_obj->circle->center_y = o_current->circle->center_y;
134   new_obj->circle->radius   = o_current->circle->radius;
135 
136   o_set_line_options(toplevel, new_obj, o_current->line_end,
137 		     o_current->line_type, o_current->line_width,
138 		     o_current->line_length, o_current->line_space);
139   o_set_fill_options(toplevel, new_obj,
140 		     o_current->fill_type, o_current->fill_width,
141 		     o_current->fill_pitch1, o_current->fill_angle1,
142 		     o_current->fill_pitch2, o_current->fill_angle2);
143 
144   o_circle_recalc(toplevel, new_obj);
145 
146   /*	new_obj->attribute = 0;*/
147 
148   return new_obj;
149 }
150 
151 /*! \brief Modify the description of a circle OBJECT.
152  *  \par Function Description
153  *  This function modifies the description of the circle object <B>*object</B>
154  *  depending on <B>whichone</B> that give the meaning of the <B>x</B> and <B>y</B>
155  *  parameters.
156  *
157  *  If <B>whichone</B> is equal to <B>CIRCLE_CENTER</B>, the new center of the
158  *  circle is given by (<B>x</B>,<B>y</B>) where <B>x</B> and <B>y</B> are in world units.
159  *
160  *  If <B>whichone</B> is equal to <B>CIRCLE_RADIUS</B>, the radius is given by
161  *  <B>x</B> - in world units. <B>y</B> is ignored.
162  *
163  *  The bounding box of the circle object is updated after the modification of its
164  *  parameters.
165  *
166  *  \param [in]     toplevel  The TOPLEVEL object.
167  *  \param [in,out] object     Circle OBJECT to modify.
168  *  \param [in]     x          New center x coordinate, or radius value.
169  *  \param [in]     y          New center y coordinate.
170  *                             Unused if radius is being modified.
171  *  \param [in]     whichone   Which circle parameter to modify.
172  *
173  *  <B>whichone</B> can have the following values:
174  *  <DL>
175  *    <DT>*</DT><DD>CIRCLE_CENTER
176  *    <DT>*</DT><DD>CIRCLE_RADIUS
177  *  </DL>
178  */
o_circle_modify(TOPLEVEL * toplevel,OBJECT * object,int x,int y,int whichone)179 void o_circle_modify(TOPLEVEL *toplevel, OBJECT *object,
180 		     int x, int y, int whichone)
181 {
182   o_emit_pre_change_notify (toplevel, object);
183 
184   switch(whichone) {
185     case CIRCLE_CENTER:
186       /* modify the center of the circle */
187       object->circle->center_x = x;
188       object->circle->center_y = y;
189       break;
190     case CIRCLE_RADIUS:
191       /* modify the radius of the circle */
192       if (x == 0) {
193 	s_log_message(_("Null radius circles are not allowed\n"));
194 	return;
195       }
196       object->circle->radius = x;
197       break;
198     default:
199       break;
200   }
201 
202   /* recalculate the boundings */
203   o_circle_recalc(toplevel, object);
204   o_emit_change_notify (toplevel, object);
205 }
206 
207 /*! \brief Create circle OBJECT from character string.
208  *  \par Function Description
209  *  The #o_circle_read() function gets from the character string <B>*buff</B> the
210  *  description of a circle.
211  *
212  *  Depending on <B>*version</B>, the right file format is considered.
213  *  Currently two file format revisions are supported :
214  *  <DL>
215  *    <DT>*</DT><DD>the file format used until 2000704 release.
216  *    <DT>*</DT><DD>the file format used for the releases after 20000704.
217  *  </DL>
218  *
219  *  \param [in]  toplevel       The TOPLEVEL object.
220  *  \param [in]  buf             Character string with circle description.
221  *  \param [in]  release_ver     libgeda release version number.
222  *  \param [in]  fileformat_ver  libgeda file format version number.
223  *  \return A pointer to the new circle object, or NULL on error.
224  */
o_circle_read(TOPLEVEL * toplevel,const char buf[],unsigned int release_ver,unsigned int fileformat_ver,GError ** err)225 OBJECT *o_circle_read (TOPLEVEL *toplevel, const char buf[],
226               unsigned int release_ver, unsigned int fileformat_ver, GError ** err)
227 {
228   OBJECT *new_obj;
229   char type;
230   int x1, y1;
231   int radius;
232   int color;
233   int circle_width, circle_space, circle_length;
234   int fill_width, angle1, pitch1, angle2, pitch2;
235   int circle_end;
236   int circle_type;
237   int circle_fill;
238 
239   if(release_ver <= VERSION_20000704) {
240     /*
241      * The old geda file format, i.e. releases 20000704 and older, does not
242      * handle the line type and the filling of the box object. They are set
243      * to default.
244      */
245     if (sscanf(buf, "%c %d %d %d %d\n", &type, &x1, &y1, &radius, &color) != 5) {
246       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object"));
247       return NULL;
248     }
249 
250     circle_width = 0;
251     circle_end   = END_NONE;
252     circle_type  = TYPE_SOLID;
253     circle_length= -1;
254     circle_space = -1;
255 
256     circle_fill  = FILLING_HOLLOW;
257     fill_width  = 0;
258     angle1      = -1;
259     pitch1      = -1;
260     angle2      = -1;
261     pitch2      = -1;
262 
263   } else {
264 
265     /*
266      * The current line format to describe a circle is a space separated
267      * list of characters and numbers in plain ASCII on a single line. The
268      * meaning of each item is described in the file format documentation.
269      */
270     if (sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
271 	       &type, &x1, &y1, &radius, &color,
272 	       &circle_width, &circle_end, &circle_type,
273 	       &circle_length, &circle_space, &circle_fill,
274 	       &fill_width, &angle1, &pitch1, &angle2, &pitch2) != 16) {
275       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object"));
276       return NULL;
277     }
278   }
279 
280 
281   if (radius <= 0) {
282     s_log_message(_("Found a zero or negative radius circle [ %c %d %d %d %d ]\n"),
283                   type, x1, y1, radius, color);
284     s_log_message (_("Setting radius to 0\n"));
285     radius = 0;
286   }
287 
288   if (color < 0 || color > MAX_COLORS) {
289     s_log_message(_("Found an invalid color [ %s ]\n"), buf);
290     s_log_message(_("Setting color to default color\n"));
291     color = DEFAULT_COLOR;
292   }
293 
294   /*
295    * A circle is internally described by its center and its radius.
296    *
297    * A new object is allocated, initialized and added to the object list.
298    * Its filling and line type are set according to the values of the field
299    * on the line.
300    */
301   new_obj = o_circle_new(toplevel, type, color, x1, y1, radius);
302   o_set_line_options(toplevel, new_obj,
303 		     circle_end, circle_type, circle_width,
304 		     circle_length, circle_space);
305   o_set_fill_options(toplevel, new_obj,
306 		     circle_fill, fill_width, pitch1, angle1, pitch2, angle2);
307 
308   return new_obj;
309 }
310 
311 /*! \brief Create a character string representation of a circle OBJECT.
312  *  \par Function Description
313  *  This function formats a string in the buffer <B>*buff</B> to describe the
314  *  circle object <B>*object</B>.
315  *  It follows the post-20000704 release file format that handle the line
316  *  type and fill options.
317  *
318  *  \param [in] toplevel  a TOPLEVEL structure.
319  *  \param [in] object  Circle OBJECT to create string from.
320  *  \return A pointer to the circle OBJECT character string.
321  *
322  *  \note
323  *  Caller must g_free returned character string.
324  *
325  */
o_circle_save(TOPLEVEL * toplevel,OBJECT * object)326 char *o_circle_save(TOPLEVEL *toplevel, OBJECT *object)
327 {
328   int x,y;
329   int radius;
330   int circle_width, circle_space, circle_length;
331   int fill_width, angle1, pitch1, angle2, pitch2;
332   char *buf;
333   OBJECT_END circle_end;
334   OBJECT_TYPE circle_type;
335   OBJECT_FILLING circle_fill;
336 
337   /* circle center and radius */
338   x = object->circle->center_x;
339   y = object->circle->center_y;
340   radius = object->circle->radius;
341 
342   /* line type parameters */
343   circle_width = object->line_width;
344   circle_end   = object->line_end;
345   circle_type  = object->line_type;
346   circle_length= object->line_length;
347   circle_space = object->line_space;
348 
349   /* filling parameters */
350   circle_fill  = object->fill_type;
351   fill_width   = object->fill_width;
352   angle1       = object->fill_angle1;
353   pitch1       = object->fill_pitch1;
354   angle2       = object->fill_angle2;
355   pitch2       = object->fill_pitch2;
356 
357   buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
358 			object->type, x, y, radius, object->color,
359 			circle_width, circle_end, circle_type, circle_length,
360 			circle_space, circle_fill,
361 			fill_width, angle1, pitch1, angle2, pitch2);
362   return(buf);
363 }
364 
365 /*! \brief Translate a circle position in WORLD coordinates by a delta.
366  *  \par Function Description
367  *  This function applies a translation of (<B>x1</B>,<B>y1</B>) to the circle
368  *  described by <B>*object</B>. <B>x1</B> and <B>y1</B> are in world unit.
369  *
370  *  \param [in]     toplevel  The TOPLEVEL object.
371  *  \param [in]     dx         x distance to move.
372  *  \param [in]     dy         y distance to move.
373  *  \param [in,out] object     Circle OBJECT to translate.
374  */
o_circle_translate_world(TOPLEVEL * toplevel,int dx,int dy,OBJECT * object)375 void o_circle_translate_world(TOPLEVEL *toplevel,
376 			      int dx, int dy, OBJECT *object)
377 {
378   /* Do world coords */
379   object->circle->center_x = object->circle->center_x + dx;
380   object->circle->center_y = object->circle->center_y + dy;
381 
382   /* recalc the screen coords and the bounding box */
383   o_circle_recalc(toplevel, object);
384 
385 }
386 
387 /*! \brief Rotate Circle OBJECT using WORLD coordinates.
388  *  \par Function Description
389  *  The function #o_circle_rotate_world() rotate the circle described by
390  *  <B>*object</B> around the (<B>world_centerx</B>,<B>world_centery</B>) point by
391  *  angle <B>angle</B> degrees.
392  *  The center of rotation is in world unit.
393  *
394  *  \param [in]      toplevel      The TOPLEVEL object.
395  *  \param [in]      world_centerx  Rotation center x coordinate in WORLD units.
396  *  \param [in]      world_centery  Rotation center y coordinate in WORLD units.
397  *  \param [in]      angle          Rotation angle in degrees (See note below).
398  *  \param [in,out]  object         Circle OBJECT to rotate.
399  */
o_circle_rotate_world(TOPLEVEL * toplevel,int world_centerx,int world_centery,int angle,OBJECT * object)400 void o_circle_rotate_world(TOPLEVEL *toplevel,
401 			   int world_centerx, int world_centery, int angle,
402 			   OBJECT *object)
403 {
404   int newx, newy;
405   int x, y;
406 
407   /* Only 90 degree multiple and positive angles are allowed. */
408   /* angle must be positive */
409   if(angle < 0) angle = -angle;
410   /* angle must be a 90 multiple or no rotation performed */
411   if((angle % 90) != 0) return;
412 
413   /*
414    * The center of rotation (<B>world_centerx</B>,<B>world_centery</B>) is
415    * translated to the origin. The rotation of the center around the origin
416    * is then performed. Finally, the rotated circle is translated back to
417    * its previous location.
418    */
419 
420   /* translate object to origin */
421   object->circle->center_x -= world_centerx;
422   object->circle->center_y -= world_centery;
423 
424   /* rotate the center of the circle around the origin */
425   x = object->circle->center_x;
426   y = object->circle->center_y;
427   rotate_point_90(x, y, angle, &newx, &newy);
428   object->circle->center_x = newx;
429   object->circle->center_y = newy;
430 
431   /* translate back in position */
432   object->circle->center_x += world_centerx;
433   object->circle->center_y += world_centery;
434 
435   o_circle_recalc(toplevel, object);
436 
437 }
438 
439 /*! \brief Mirror circle using WORLD coordinates.
440  *  \par Function Description
441  *  This function recalculates the screen coords of the <B>o_current</B> pointed
442  *  circle object from its world coords.
443  *
444  *  The circle coordinates and its bounding are recalculated as well as the
445  *  OBJECT specific (line width, filling ...).
446  *
447  *  \param [in]     toplevel      The TOPLEVEL object.
448  *  \param [in]     world_centerx  Origin x coordinate in WORLD units.
449  *  \param [in]     world_centery  Origin y coordinate in WORLD units.
450  *  \param [in,out] object         Circle OBJECT to mirror.
451  */
o_circle_mirror_world(TOPLEVEL * toplevel,int world_centerx,int world_centery,OBJECT * object)452 void o_circle_mirror_world(TOPLEVEL *toplevel,
453 			   int world_centerx, int world_centery,
454 			   OBJECT *object)
455 {
456   /* translate object to origin */
457   object->circle->center_x -= world_centerx;
458   object->circle->center_y -= world_centery;
459 
460   /* mirror the center of the circle */
461   object->circle->center_x = -object->circle->center_x;
462   object->circle->center_y =  object->circle->center_y;
463 
464   /* translate back in position */
465   object->circle->center_x += world_centerx;
466   object->circle->center_y += world_centery;
467 
468   /* recalc boundings and screen coords */
469   o_circle_recalc(toplevel, object);
470 
471 }
472 
473 /*! \brief Recalculate circle coordinates in SCREEN units.
474  *  \par Function Description
475  *  This function recalculates the screen coords of the <B>o_current</B> pointed
476  *  circle object from its world coords.
477  *
478  *  The circle coordinates and its bounding are recalculated as well as the
479  *  OBJECT specific (line width, filling ...).
480  *
481  *  \param [in] toplevel      The TOPLEVEL object.
482  *  \param [in,out] o_current  Circle OBJECT to be recalculated.
483  */
o_circle_recalc(TOPLEVEL * toplevel,OBJECT * o_current)484 void o_circle_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
485 {
486   int left, right, top, bottom;
487 
488   if (o_current->circle == NULL) {
489     return;
490   }
491 
492   /* update the bounding box - world unit */
493   world_get_circle_bounds(toplevel, o_current,
494 		    &left, &top, &right, &bottom);
495   o_current->w_left   = left;
496   o_current->w_top    = top;
497   o_current->w_right  = right;
498   o_current->w_bottom = bottom;
499   o_current->w_bounds_valid = TRUE;
500 }
501 
502 /*! \brief Get circle bounding rectangle in WORLD coordinates.
503  *  \par Function Description
504  *  This function sets the <B>left</B>, <B>top</B>, <B>right</B> and <B>bottom</B>
505  *  parameters to the boundings of the circle object described in <B>*circle</B>
506  *  in world units.
507  *
508  *  \param [in]  toplevel  The TOPLEVEL object.
509  *  \param [in]  object     Circle OBJECT to read coordinates from.
510  *  \param [out] left       Left circle coordinate in WORLD units.
511  *  \param [out] top        Top circle coordinate in WORLD units.
512  *  \param [out] right      Right circle coordinate in WORLD units.
513  *  \param [out] bottom     Bottom circle coordinate in WORLD units.
514  */
world_get_circle_bounds(TOPLEVEL * toplevel,OBJECT * object,int * left,int * top,int * right,int * bottom)515 void world_get_circle_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left,
516                              int *top, int *right, int *bottom)
517 {
518   int halfwidth;
519 
520   halfwidth = object->line_width / 2;
521 
522   *left   = object->circle->center_x - object->circle->radius;
523   *top    = object->circle->center_y - object->circle->radius;
524   *right  = object->circle->center_x + object->circle->radius;
525   *bottom = object->circle->center_y + object->circle->radius;
526 
527   /* This isn't strictly correct, but a 1st order approximation */
528   *left   -= halfwidth;
529   *top    -= halfwidth;
530   *right  += halfwidth;
531   *bottom += halfwidth;
532 
533 }
534 
535 /*! \brief get the position of the center point
536  *  \par Function Description
537  *  This function gets the position of the center point of a circle object.
538  *
539  *  \param [in] toplevel The toplevel environment.
540  *  \param [out] x       pointer to the x-position
541  *  \param [out] y       pointer to the y-position
542  *  \param [in] object   The object to get the position.
543  *  \return TRUE if successfully determined the position, FALSE otherwise
544  */
o_circle_get_position(TOPLEVEL * toplevel,gint * x,gint * y,OBJECT * object)545 gboolean o_circle_get_position (TOPLEVEL *toplevel, gint *x, gint *y,
546                               OBJECT *object)
547 {
548   *x = object->circle->center_x;
549   *y = object->circle->center_y;
550   return TRUE;
551 }
552 
553 /*! \brief Print circle to Postscript document.
554  *  \par Function Description
555  *  This function prints the circle described by the <B>o_current</B>
556  *  parameter to a Postscript document. It takes into account its line type
557  *  and fill type.
558  *  The Postscript document is descibed by the file pointer <B>fp</B>.
559  *
560  *  The validity of the <B>o_current</B> pointer is checked :
561  *  a null pointer causes an error message and a return.
562  *
563  *  The description of the circle is extracted from the <B>o_current</B>
564  *  parameter : the coordinates of the center of the circle, its radius,
565  *  its line type, its fill type.
566  *
567  *  The outline and the inside of the circle are successively handled by
568  *  two differend sets of functions.
569  *
570  *  \param [in] toplevel  The TOPLEVEL object.
571  *  \param [in] fp         FILE pointer to Postscript document.
572  *  \param [in] o_current  Circle OBJECT to write to document.
573  *  \param [in] origin_x   Page x coordinate to place circle OBJECT.
574  *  \param [in] origin_y   Page y coordinate to place circle OBJECT.
575  */
o_circle_print(TOPLEVEL * toplevel,FILE * fp,OBJECT * o_current,int origin_x,int origin_y)576 void o_circle_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
577 		    int origin_x, int origin_y)
578 {
579   int x, y, radius;
580   int color;
581   int circle_width, length, space;
582   int fill_width, angle1, pitch1, angle2, pitch2;
583   void (*outl_func)() = NULL;
584   void (*fill_func)() = NULL;
585 
586   if (o_current == NULL) {
587     printf("got null in o_circle_print\n");
588     return;
589   }
590 
591   x      = o_current->circle->center_x;
592   y      = o_current->circle->center_y;
593   radius = o_current->circle->radius;
594 
595   color  = o_current->color;
596 
597   /*
598    * Depending on the type of the line for this particular circle, the
599    * appropriate function is chosen among #o_circle_print_solid(),
600    * #o_circle_print_dotted(), #o_circle_print_dashed(),
601    * #o_circle_print_center() and #o_circle_print_phantom().
602    *
603    * The needed parameters for each of these type is extracted from the
604    * <B>o_current</B> object. Depending on the type, unused parameters are
605    * set to -1.
606    *
607    * In the eventuality of a length and/or space null, the line is
608    * printed solid to avoid and endless loop produced by other functions
609    * in such a case.
610    */
611   circle_width = o_current->line_width;
612   if(circle_width <=2) {
613     if(toplevel->line_style == THICK) {
614       circle_width=LINE_WIDTH;
615     } else {
616       circle_width=2;
617     }
618   }
619   length       = o_current->line_length;
620   space        = o_current->line_space;
621 
622   switch(o_current->line_type) {
623     case(TYPE_SOLID):
624       length = -1; space  = -1;
625       outl_func = o_circle_print_solid;
626       break;
627 
628     case(TYPE_DOTTED):
629       length = -1;
630       outl_func = o_circle_print_dotted;
631       break;
632 
633     case(TYPE_DASHED):
634       outl_func = o_circle_print_dashed;
635       break;
636 
637     case(TYPE_CENTER):
638       outl_func = o_circle_print_center;
639       break;
640 
641     case(TYPE_PHANTOM):
642       outl_func = o_circle_print_phantom;
643       break;
644 
645     case(TYPE_ERASE):
646       /* Unused for now print it solid */
647       length = -1; space  = -1;
648       outl_func = o_circle_print_solid;
649       break;
650   }
651 
652   if((length == 0) || (space == 0)) {
653     length = -1; space  = -1;
654     outl_func = o_circle_print_solid;
655   }
656 
657   (*outl_func)(toplevel, fp,
658                x - origin_x, y - origin_y,
659                radius,
660                color,
661                circle_width, length, space,
662                origin_x, origin_y);
663 
664   /*
665    * If the filling type of the circle is not <B>HOLLOW</B>, the appropriate
666    * function is chosen among #o_circle_print_filled(), #o_circle_print_mesh()
667    * and #o_circle_print_hatch(). The corresponding parameters are extracted
668    * from the <B>o_current</B> object and corrected afterward.
669    *
670    * The case where <B>pitch1</B> and <B>pitch2</B> are null or negative is
671    * avoided as it leads to an endless loop in most of the called functions.
672    * In such a case, the circle is printed filled. Unused parameters for
673    * each of these functions are set to -1 or any passive value.
674    */
675   if(o_current->fill_type != FILLING_HOLLOW) {
676     fill_width = o_current->fill_width;
677     angle1     = o_current->fill_angle1;
678     pitch1     = o_current->fill_pitch1;
679     angle2     = o_current->fill_angle2;
680     pitch2     = o_current->fill_pitch2;
681 
682     switch(o_current->fill_type) {
683       case(FILLING_FILL):
684         angle1 = -1; pitch1 = 1;
685         angle2 = -1; pitch2 = 1;
686         fill_width = -1;
687         fill_func = o_circle_print_filled;
688         break;
689 
690       case(FILLING_MESH):
691         fill_func = o_circle_print_mesh;
692         break;
693 
694       case(FILLING_HATCH):
695         angle2 = -1; pitch2 = 1;
696         fill_func = o_circle_print_hatch;
697         break;
698 
699       case(FILLING_VOID):
700 				/* Unused for now, print it filled */
701         angle1 = -1; pitch1 = 1;
702         angle2 = -1; pitch2 = 1;
703         fill_width = -1;
704         fill_func = o_circle_print_filled;
705         break;
706 
707       case(FILLING_HOLLOW):
708         /* nop */
709         break;
710     }
711 
712     if((pitch1 <= 0) || (pitch2 <= 0)) {
713       angle1 = -1; pitch1 = 1;
714       angle2 = -1; pitch2 = 1;
715       fill_func = o_circle_print_filled;
716     }
717 
718     (*fill_func)(toplevel, fp,
719                  x, y, radius,
720                  color,
721                  fill_width,
722                  angle1, pitch1, angle2, pitch2,
723                  origin_x, origin_y);
724   }
725 }
726 
727 /*! \brief Print a solid circle to Postscript document.
728  *  \par Function Description
729  *  This function prints the outline of a circle when a solid line type
730  *  is required. The circle is defined by its center in (<B>x</B>, <B>y</B>)
731  *  and its radius in <B>radius</B>. It is printed with the color given
732  *  in <B>color</B>.
733  *  The parameters <B>length</B> and <B>space</B> are ignored.
734  *
735  *  It uses the function #o_arc_print_solid() to print the outline.
736  *  Therefore it acts as an interface between the way a circle is defined
737  *  and the way an arc is defined.
738  *
739  *  All dimensions are in mils.
740  *
741  *  \param [in] toplevel     The TOPLEVEL object.
742  *  \param [in] fp            FILE pointer to Postscript document.
743  *  \param [in] x             Center x coordinate of circle.
744  *  \param [in] y             Center y coordinate of circle.
745  *  \param [in] radius        Circle radius.
746  *  \param [in] color         Circle color.
747  *  \param [in] circle_width  Width of circle.
748  *  \param [in] length        (unused).
749  *  \param [in] space         (unused).
750  *  \param [in] origin_x      Page x coordinate to place circle OBJECT.
751  *  \param [in] origin_y      Page y coordinate to place circle OBJECT.
752  */
o_circle_print_solid(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int color,int circle_width,int length,int space,int origin_x,int origin_y)753 void o_circle_print_solid(TOPLEVEL *toplevel, FILE *fp,
754 			  int x, int y, int radius,
755 			  int color,
756 			  int circle_width, int length, int space,
757 			  int origin_x, int origin_y)
758 {
759 
760   o_arc_print_solid(toplevel, fp,
761                     x, y, radius,
762                     0, FULL_CIRCLE / 64,
763                     color,
764                     circle_width, -1, -1,
765                     origin_x, origin_y);
766 
767 }
768 
769 
770 /*! \brief Print a dotted circle to Postscript document.
771  *  \par Function Description
772  *  This function prints the outline of a circle when a dotted line
773  *  type is required. The circle is defined by its center
774  *  in (<B>x</B>, <B>y</B>) and its radius in <B>radius</B>. It is printed
775  *  with the color given in <B>color</B>.
776  *  The parameter <B>length</B> is ignored.
777  *
778  *  It uses the function #o_arc_print_dotted() to print the outline.
779  *  Therefore it acts as an interface between the way a circle is
780  *  defined and the way an arc is defined.
781  *
782  *  All dimensions are in mils.
783  *
784  *  \param [in] toplevel     The TOPLEVEL object.
785  *  \param [in] fp            FILE pointer to Postscript document.
786  *  \param [in] x             Center x coordinate of circle.
787  *  \param [in] y             Center y coordinate of circle.
788  *  \param [in] radius        Circle radius.
789  *  \param [in] color         Circle color.
790  *  \param [in] circle_width  Width of circle.
791  *  \param [in] length        (unused).
792  *  \param [in] space         Space between dots.
793  *  \param [in] origin_x      Page x coordinate to place circle OBJECT.
794  *  \param [in] origin_y      Page y coordinate to place circle OBJECT.
795  */
o_circle_print_dotted(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int color,int circle_width,int length,int space,int origin_x,int origin_y)796 void o_circle_print_dotted(TOPLEVEL *toplevel, FILE *fp,
797 			   int x, int y, int radius,
798 			   int color,
799 			   int circle_width, int length, int space,
800 			   int origin_x, int origin_y)
801 {
802 
803   o_arc_print_dotted(toplevel, fp,
804                      x, y, radius,
805                      0, FULL_CIRCLE / 64,
806                      color,
807                      circle_width, -1, space,
808                      origin_x, origin_y);
809 
810 }
811 
812 /*! \brief Print a dashed circle to Postscript document.
813  *  \par Function Description
814  *  This function prints the outline of a circle when a dashed line type
815  *  is required. The circle is defined by its center in
816  *  (<B>x</B>, <B>y</B>) and its radius in <B>radius</B>. It is printed with the
817  *  color given in <B>color</B>.
818  *
819  *  It uses the function #o_arc_print_dashed() to print the outline.
820  *  Therefore it acts as an interface between the way a circle is
821  *  defined and the way an arc is defined.
822  *
823  *  All dimensions are in mils.
824  *
825  *  \param [in] toplevel     The TOPLEVEL object.
826  *  \param [in] fp            FILE pointer to Postscript document.
827  *  \param [in] x             Center x coordinate of circle.
828  *  \param [in] y             Center y coordinate of circle.
829  *  \param [in] radius        Circle radius.
830  *  \param [in] color         Circle color.
831  *  \param [in] circle_width  Width of circle.
832  *  \param [in] length        Length of dashed lines.
833  *  \param [in] space         Space between dashes.
834  *  \param [in] origin_x      Page x coordinate to place circle OBJECT.
835  *  \param [in] origin_y      Page y coordinate to place circle OBJECT.
836  */
o_circle_print_dashed(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int color,int circle_width,int length,int space,int origin_x,int origin_y)837 void o_circle_print_dashed(TOPLEVEL *toplevel, FILE *fp,
838 			   int x, int y,
839 			   int radius,
840 			   int color,
841 			   int circle_width, int length, int space,
842 			   int origin_x, int origin_y)
843 {
844 
845   o_arc_print_dashed(toplevel, fp,
846                      x, y, radius,
847                      0, FULL_CIRCLE / 64,
848                      color,
849                      circle_width, length, space,
850                      origin_x, origin_y);
851 
852 }
853 
854 /*! \brief Print a centered line type circle to Postscript document.
855  *  \par Function Description
856  *  This function prints the outline of a circle when a centered line
857  *  type is required. The circle is defined by its center in
858  *  (<B>x</B>, <B>y</B>) and its radius in <B>radius</B>. It is printed with the
859  *  color given in <B>color</B>.
860  *
861  *  It uses the function #o_arc_print_center() to print the outline.
862  *  Therefore it acts as an interface between the way a circle is
863  *  defined and the way an arc is defined.
864  *
865  *  All dimensions are in mils.
866  *
867  *  \param [in] toplevel     The TOPLEVEL object.
868  *  \param [in] fp            FILE pointer to Postscript document.
869  *  \param [in] x             Center x coordinate of circle.
870  *  \param [in] y             Center y coordinate of circle.
871  *  \param [in] radius        Circle radius.
872  *  \param [in] color         Circle color.
873  *  \param [in] circle_width  Width of circle.
874  *  \param [in] length        Length of dashed lines.
875  *  \param [in] space         Space between dashes.
876  *  \param [in] origin_x      Page x coordinate to place circle OBJECT.
877  *  \param [in] origin_y      Page y coordinate to place circle OBJECT.
878  */
o_circle_print_center(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int color,int circle_width,int length,int space,int origin_x,int origin_y)879 void o_circle_print_center(TOPLEVEL *toplevel, FILE *fp,
880 			   int x, int y,
881 			   int radius,
882 			   int color,
883 			   int circle_width, int length, int space,
884 			   int origin_x, int origin_y)
885 {
886 
887   o_arc_print_center(toplevel, fp,
888                      x, y, radius,
889                      0, FULL_CIRCLE / 64,
890                      color,
891                      circle_width, length, space,
892                      origin_x, origin_y);
893 
894 }
895 
896 /*! \brief Print a phantom line type circle to Postscript document.
897  *  \par Function Description
898  *  This function prints the outline of a circle when a phantom line type
899  *  is required. The circle is defined by its center in
900  *  (<B>x</B>, <B>y</B>) and its radius in <B>radius</B>. It is printed with the
901  *  color given in <B>color</B>.
902  *
903  *  It uses the function #o_arc_print_phantom() to print the outline.
904  *  Therefore it acts as an interface between the way a circle is defined
905  *  and the way an arc is defined.
906  *
907  *  All dimensions are in mils.
908  *
909  *  \param [in] toplevel     The TOPLEVEL object.
910  *  \param [in] fp            FILE pointer to Postscript document.
911  *  \param [in] x             Center x coordinate of circle.
912  *  \param [in] y             Center y coordinate of circle.
913  *  \param [in] radius        Circle radius.
914  *  \param [in] color         Circle color.
915  *  \param [in] circle_width  Width of circle.
916  *  \param [in] length        Length of dashed lines.
917  *  \param [in] space         Space between dashes.
918  *  \param [in] origin_x      Page x coordinate to place circle OBJECT.
919  *  \param [in] origin_y      Page y coordinate to place circle OBJECT.
920  */
o_circle_print_phantom(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int color,int circle_width,int length,int space,int origin_x,int origin_y)921 void o_circle_print_phantom(TOPLEVEL *toplevel, FILE *fp,
922 			    int x, int y,
923 			    int radius,
924 			    int color,
925 			    int circle_width, int length, int space,
926 			    int origin_x, int origin_y)
927 {
928 
929   o_arc_print_phantom(toplevel, fp,
930                       x, y, radius,
931                       0, FULL_CIRCLE / 64,
932                       color,
933                       circle_width, length, space,
934                       origin_x, origin_y);
935 
936 }
937 
938 /*! \brief Print a solid pattern circle to Postscript document.
939  *  \par Function Description
940  *  The function prints a filled circle with a solid pattern.
941  *  No outline is printed.
942  *  The circle is defined by the coordinates of its center in
943  *  (<B>x</B>,<B>y</B>) and its radius given by the <B>radius</B> parameter.
944  *  The postscript file is defined by the file pointer <B>fp</B>.
945  *  <B>fill_width</B>, <B>angle1</B> and <B>pitch1</B>, <B>angle2</B>
946  *  and <B>pitch2</B> parameters are ignored in this functions but
947  *  kept for compatibility with other fill functions.
948  *
949  *  All dimensions are in mils (except <B>angle1</B> and <B>angle2</B> in degree).
950  *
951  *  \param [in] toplevel   The TOPLEVEL object.
952  *  \param [in] fp          FILE pointer to Postscript document.
953  *  \param [in] x           Center x coordinate of circle.
954  *  \param [in] y           Center y coordinate of circle.
955  *  \param [in] radius      Radius of circle.
956  *  \param [in] color       Circle color.
957  *  \param [in] fill_width  Circle fill width. (unused).
958  *  \param [in] angle1      (unused).
959  *  \param [in] pitch1      (unused).
960  *  \param [in] angle2      (unused).
961  *  \param [in] pitch2      (unused).
962  *  \param [in] origin_x    Page x coordinate to place circle OBJECT.
963  *  \param [in] origin_y    Page y coordinate to place circle OBJECT.
964  */
o_circle_print_filled(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int color,int fill_width,int angle1,int pitch1,int angle2,int pitch2,int origin_x,int origin_y)965 void o_circle_print_filled(TOPLEVEL *toplevel, FILE *fp,
966 			   int x, int y, int radius,
967 			   int color,
968 			   int fill_width,
969 			   int angle1, int pitch1,
970 			   int angle2, int pitch2,
971 			   int origin_x, int origin_y)
972 {
973   f_print_set_color(toplevel, fp, color);
974 
975   fprintf(fp, "%d %d %d dot\n",
976 	  x-origin_x, y-origin_y,
977 	  radius);
978 
979 }
980 
981 /*! \brief Print a mesh pattern circle to Postscript document.
982  *  \par Function Description
983  *  This function prints a meshed circle. No outline is printed.
984  *  The circle is defined by the coordinates of its center in
985  *  (<B>x</B>,<B>y</B>) and its radius by the <B>radius</B> parameter.
986  *  The Postscript document is defined by the file pointer <B>fp</B>.
987  *
988  *  The inside mesh is achieved by two successive call to the
989  *  #o_circle_print_hatch() function, given <B>angle1</B> and <B>pitch1</B>
990  *  the first time and <B>angle2</B> and <B>pitch2</B> the second time.
991  *
992  *  Negative or null values for <B>pitch1</B> and/or <B>pitch2</B> are
993  *  not allowed as it leads to an endless loop in #o_circle_print_hatch().
994  *
995  *  All dimensions are in mils (except <B>angle1</B> and <B>angle2</B> in degree).
996  *
997  *  \param [in] toplevel   The TOPLEVEL object.
998  *  \param [in] fp          FILE pointer to Postscript document.
999  *  \param [in] x           Center x coordinate of circle.
1000  *  \param [in] y           Center y coordinate of circle.
1001  *  \param [in] radius      Radius of circle.
1002  *  \param [in] color       Circle color.
1003  *  \param [in] fill_width  Circle fill width.
1004  *  \param [in] angle1      1st angle for mesh pattern.
1005  *  \param [in] pitch1      1st pitch for mesh pattern.
1006  *  \param [in] angle2      2nd angle for mesh pattern.
1007  *  \param [in] pitch2      2nd pitch for mesh pattern.
1008  *  \param [in] origin_x    Page x coordinate to place circle OBJECT.
1009  *  \param [in] origin_y    Page y coordinate to place circle OBJECT.
1010  */
o_circle_print_mesh(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int color,int fill_width,int angle1,int pitch1,int angle2,int pitch2,int origin_x,int origin_y)1011 void o_circle_print_mesh(TOPLEVEL *toplevel, FILE *fp,
1012 			 int x, int y, int radius,
1013 			 int color,
1014 			 int fill_width,
1015 			 int angle1, int pitch1,
1016 			 int angle2, int pitch2,
1017 			 int origin_x, int origin_y)
1018 {
1019   o_circle_print_hatch(toplevel, fp,
1020                        x, y, radius,
1021                        color,
1022                        fill_width,
1023                        angle1, pitch1,
1024                        -1, -1,
1025                        origin_x, origin_y);
1026   o_circle_print_hatch(toplevel, fp,
1027                        x, y, radius,
1028                        color,
1029                        fill_width,
1030                        angle2, pitch2,
1031                        -1, -1,
1032                        origin_x, origin_y);
1033 
1034 }
1035 
1036 /*! \brief Print a hatch pattern circle to Postscript document.
1037  *  \par Function Description
1038  *  The function prints a hatched circle. No outline is printed.
1039  *  The circle is defined by the coordinates of its center in
1040  *  (<B>x</B>,<B>y</B>) and its radius by the <B>radius</B> parameter.
1041  *  The Postscript document is defined by the file pointer <B>fp</B>.
1042  *  <B>angle2</B> and <B>pitch2</B> parameters are ignored in this
1043  *  functions but kept for compatibility with other fill functions.
1044  *
1045  *  The only attribute of line here is its width from the parameter <B>width</B>.
1046  *
1047  *  Negative or null values for <B>pitch1</B> is not allowed as it
1048  *  leads to an endless loop.
1049  *
1050  *  All dimensions are in mils (except <B>angle1</B> is in degrees).
1051  *
1052  *  \param [in] toplevel   The TOPLEVEL object.
1053  *  \param [in] fp          FILE pointer to Postscript document.
1054  *  \param [in] x           Center x coordinate of circle.
1055  *  \param [in] y           Center y coordinate of circle.
1056  *  \param [in] radius      Radius of circle.
1057  *  \param [in] color       Circle color.
1058  *  \param [in] fill_width  Circle fill width.
1059  *  \param [in] angle1      Angle for hatch pattern.
1060  *  \param [in] pitch1      Pitch for hatch pattern.
1061  *  \param [in] angle2      (unused).
1062  *  \param [in] pitch2      (unused).
1063  *  \param [in] origin_x    Page x coordinate to place circle OBJECT.
1064  *  \param [in] origin_y    Page y coordinate to place circle OBJECT.
1065  */
o_circle_print_hatch(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int color,int fill_width,int angle1,int pitch1,int angle2,int pitch2,int origin_x,int origin_y)1066 void o_circle_print_hatch(TOPLEVEL *toplevel, FILE *fp,
1067 			  int x, int y, int radius,
1068 			  int color,
1069 			  int fill_width,
1070 			  int angle1, int pitch1,
1071 			  int angle2, int pitch2,
1072 			  int origin_x, int origin_y)
1073 {
1074   CIRCLE circle;
1075   gint index;
1076   GArray *lines;
1077 
1078   g_return_if_fail(toplevel != NULL);
1079   g_return_if_fail(fp != NULL);
1080 
1081   f_print_set_color(toplevel, fp, color);
1082 
1083   /* Avoid printing line widths too small */
1084   if (fill_width <= 1) fill_width = 2;
1085 
1086   lines = g_array_new(FALSE, FALSE, sizeof(LINE));
1087 
1088   circle.center_x = x;
1089   circle.center_y = y;
1090   circle.radius   = radius;
1091 
1092   m_hatch_circle(&circle, angle1, pitch1, lines);
1093 
1094   for(index=0; index<lines->len; index++) {
1095     LINE *line = &g_array_index(lines, LINE, index);
1096 
1097     fprintf(fp,"%d %d %d %d %d line\n",
1098             line->x[0], line->y[0],
1099             line->x[1], line->y[1],
1100             fill_width);
1101   }
1102 
1103   g_array_free(lines, TRUE);
1104 }
1105 
1106 /*! \brief Calculates the distance between the given point and the closest
1107  * point on the perimeter of the circle.
1108  *
1109  *  \param [in] object       The circle OBJECT.
1110  *  \param [in] x            The x coordinate of the given point.
1111  *  \param [in] y            The y coordinate of the given point.
1112  *  \param [in] force_solid  If true, force treating the object as solid.
1113  *  \return The shortest distance from the object to the point.  With an
1114  *  invalid parameter, this function returns G_MAXDOUBLE.
1115  */
o_circle_shortest_distance(OBJECT * object,int x,int y,int force_solid)1116 double o_circle_shortest_distance (OBJECT *object, int x, int y,
1117                                    int force_solid)
1118 {
1119   int solid;
1120 
1121   g_return_val_if_fail (object->circle != NULL, G_MAXDOUBLE);
1122 
1123   solid = force_solid || object->fill_type != FILLING_HOLLOW;
1124 
1125   return m_circle_shortest_distance (object->circle, x, y, solid);
1126 }
1127 
1128