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