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