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