libgeda: Remove some exit() calls and assertions.
[geda-gaf/peter-b.git] / libgeda / src / o_path_basic.c
blobb71e30aa72384493c15a5a9c41f2ada9f96d8428
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)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <math.h>
24 #include <string.h>
26 #include "libgeda_priv.h"
28 #ifdef HAVE_LIBDMALLOC
29 #include <dmalloc.h>
30 #endif
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);
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);
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.
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.
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().
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().
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.
74 OBJECT *o_path_new (TOPLEVEL *toplevel,
75 char type, int color, const char *path_string)
77 OBJECT *new_node;
79 /* create the object */
80 new_node = s_basic_new_object (type, "path");
81 new_node->color = color;
83 new_node->path = s_path_parse (path_string);
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);
91 /* compute bounding box */
92 o_path_recalc (toplevel, new_node);
94 return new_node;
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.
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.
109 OBJECT *o_path_copy (TOPLEVEL *toplevel, OBJECT *o_current)
111 OBJECT *new_obj;
112 char *path_string;
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);
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);
127 /* calc the bounding box */
128 o_path_recalc (toplevel, o_current);
130 /* return the new tail of the object list */
131 return new_obj;
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>.
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>
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.
155 OBJECT *o_path_read (TOPLEVEL *toplevel,
156 const char *first_line, TextBuffer *tb,
157 unsigned int release_ver, unsigned int fileformat_ver)
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;
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.
176 /* Allocate enough space */
177 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);
183 * Checks if the required color is valid.
185 if (color < 0 || color > MAX_COLORS) {
186 s_log_message (_("Found an invalid color [ %s ]\n"), first_line);
187 s_log_message (_("Setting color to default color\n"));
188 color = DEFAULT_COLOR;
192 * A path is internally described by its two ends. A new object is
193 * allocated, initialized and added to the list of objects. Its path
194 * type is set according to the values of the fields on the path.
197 pathstr = g_string_new ("");
198 for (i = 0; i < num_lines; i++) {
199 gchar *line;
201 line = s_textbuffer_next_line (tb);
203 if (line != NULL) {
204 pathstr = g_string_append (pathstr, line);
208 /* retrieve the character string from the GString */
209 string = g_string_free (pathstr, FALSE);
210 string = remove_last_nl (string);
212 /* create a new path */
213 new_obj = o_path_new (toplevel, type, color, string);
214 g_free (string);
216 /* set its line options */
217 o_set_line_options (toplevel, new_obj,
218 line_end, line_type, line_width, line_length, line_space);
219 /* set its fill options */
220 o_set_fill_options (toplevel, new_obj,
221 fill_type, fill_width, pitch1, angle1, pitch2, angle2);
223 return new_obj;
227 /*! \brief Create a character string representation of a path OBJECT.
228 * \par Function Description
229 * The function formats a string in the buffer <B>*buff</B> to describe
230 * the path object <B>*object</B>.
232 * \param [in] toplevel a TOPLEVEL structure
233 * \param [in] object path OBJECT to create string from.
234 * \return A pointer to the path OBJECT character string.
236 * \note
237 * Caller must g_free returned character string.
240 char *o_path_save (TOPLEVEL *toplevel, OBJECT *object)
242 int line_width, line_space, line_length;
243 char *buf;
244 int num_lines;
245 OBJECT_END line_end;
246 OBJECT_TYPE line_type;
247 OBJECT_FILLING fill_type;
248 int fill_width, angle1, pitch1, angle2, pitch2;
249 char *path_string;
251 /* description of the line type */
252 line_width = object->line_width;
253 line_end = object->line_end;
254 line_type = object->line_type;
255 line_length = object->line_length;
256 line_space = object->line_space;
258 /* filling parameters */
259 fill_type = object->fill_type;
260 fill_width = object->fill_width;
261 angle1 = object->fill_angle1;
262 pitch1 = object->fill_pitch1;
263 angle2 = object->fill_angle2;
264 pitch2 = object->fill_pitch2;
266 path_string = s_path_string_from_path (object->path);
267 num_lines = o_text_num_lines (path_string);
268 buf = g_strdup_printf ("%c %d %d %d %d %d %d %d %d %d %d %d %d %d\n%s",
269 object->type, object->color, line_width, line_end,
270 line_type, line_length, line_space, fill_type,
271 fill_width, angle1, pitch1, angle2, pitch2,
272 num_lines, path_string);
273 g_free (path_string);
275 return buf;
279 /*! \brief Modify controol point location
281 * \par Function Description
282 * This function modifies a control point location of the path object
283 * *object. The control point being modified is selected according to
284 * the whichone parameter.
286 * The new position is given by <B>x</B> and <B>y</B>.
288 * \param [in] toplevel The TOPLEVEL object.
289 * \param [in,out] object The path OBJECT
290 * \param [in] x New x coordinate for the control point
291 * \param [in] y New y coordinate for the control point
292 * \param [in] whichone Which control point is being modified
294 void o_path_modify (TOPLEVEL *toplevel, OBJECT *object,
295 int x, int y, int whichone)
297 int i;
298 int grip_no = 0;
299 PATH_SECTION *section;
301 o_emit_pre_change_notify (toplevel, object);
303 for (i = 0; i < object->path->num_sections; i++) {
304 section = &object->path->sections[i];
306 switch (section->code) {
307 case PATH_CURVETO:
308 /* Two control point grips */
309 if (whichone == grip_no++) {
310 section->x1 = x;
311 section->y1 = y;
313 if (whichone == grip_no++) {
314 section->x2 = x;
315 section->y2 = y;
317 /* Fall through */
318 case PATH_MOVETO:
319 case PATH_MOVETO_OPEN:
320 case PATH_LINETO:
321 /* Destination point grip */
322 if (whichone == grip_no++) {
323 section->x3 = x;
324 section->y3 = y;
326 break;
327 case PATH_END:
328 break;
332 /* Update bounding box */
333 o_path_recalc (toplevel, object);
334 o_emit_change_notify (toplevel, object);
338 /*! \brief Translate a path position in WORLD coordinates by a delta.
339 * \par Function Description
340 * This function applies a translation of (<B>x1</B>,<B>y1</B>) to the path
341 * described by <B>*object</B>. <B>x1</B> and <B>y1</B> are in world unit.
343 * \param [in] toplevel The TOPLEVEL object.
344 * \param [in] dx x distance to move.
345 * \param [in] dy y distance to move.
346 * \param [in,out] object Line OBJECT to translate.
348 void o_path_translate_world (TOPLEVEL *toplevel,
349 int dx, int dy, OBJECT *object)
351 PATH_SECTION *section;
352 int i;
354 for (i = 0; i < object->path->num_sections; i++) {
355 section = &object->path->sections[i];
357 switch (section->code) {
358 case PATH_CURVETO:
359 section->x1 += dx;
360 section->y1 += dy;
361 section->x2 += dx;
362 section->y2 += dy;
363 /* Fall through */
364 case PATH_MOVETO:
365 case PATH_MOVETO_OPEN:
366 case PATH_LINETO:
367 section->x3 += dx;
368 section->y3 += dy;
369 break;
370 case PATH_END:
371 break;
375 /* Update bounding box */
376 o_path_recalc (toplevel, object);
380 /*! \brief Rotate Line OBJECT using WORLD coordinates.
381 * \par Function Description
382 * This function rotates the path described by
383 * <B>*object</B> around the (<B>world_centerx</B>,<B>world_centery</B>)
384 * point by <B>angle</B> degrees.
385 * The center of rotation is in world units.
387 * \param [in] toplevel The TOPLEVEL object.
388 * \param [in] world_centerx Rotation center x coordinate in WORLD units.
389 * \param [in] world_centery Rotation center y coordinate in WORLD units.
390 * \param [in] angle Rotation angle in degrees (See note below).
391 * \param [in,out] object Line OBJECT to rotate.
393 void o_path_rotate_world (TOPLEVEL *toplevel,
394 int world_centerx, int world_centery, int angle,
395 OBJECT *object)
397 PATH_SECTION *section;
398 int i;
400 for (i = 0; i < object->path->num_sections; i++) {
401 section = &object->path->sections[i];
403 switch (section->code) {
404 case PATH_CURVETO:
405 /* Two control point grips */
406 section->x1 -= world_centerx; section->y1 -= world_centery;
407 section->x2 -= world_centerx; section->y2 -= world_centery;
408 rotate_point_90 (section->x1, section->y1, angle, &section->x1, &section->y1);
409 rotate_point_90 (section->x2, section->y2, angle, &section->x2, &section->y2);
410 section->x1 += world_centerx; section->y1 += world_centery;
411 section->x2 += world_centerx; section->y2 += world_centery;
412 /* Fall through */
413 case PATH_MOVETO:
414 case PATH_MOVETO_OPEN:
415 case PATH_LINETO:
416 /* Destination point grip */
417 section->x3 -= world_centerx; section->y3 -= world_centery;
418 rotate_point_90 (section->x3, section->y3, angle, &section->x3, &section->y3);
419 section->x3 += world_centerx; section->y3 += world_centery;
420 break;
421 case PATH_END:
422 break;
425 o_path_recalc (toplevel, object);
429 /*! \brief Mirror a path using WORLD coordinates.
430 * \par Function Description
431 * This function mirrors the path from the point
432 * (<B>world_centerx</B>,<B>world_centery</B>) in world unit.
434 * \param [in] toplevel The TOPLEVEL object.
435 * \param [in] world_centerx Origin x coordinate in WORLD units.
436 * \param [in] world_centery Origin y coordinate in WORLD units.
437 * \param [in,out] object Line OBJECT to mirror.
439 void o_path_mirror_world (TOPLEVEL *toplevel, int world_centerx,
440 int world_centery, OBJECT *object)
442 PATH_SECTION *section;
443 int i;
445 for (i = 0; i < object->path->num_sections; i++) {
446 section = &object->path->sections[i];
448 switch (section->code) {
449 case PATH_CURVETO:
450 /* Two control point grips */
451 section->x1 = 2 * world_centerx - section->x1;
452 section->x2 = 2 * world_centerx - section->x2;
453 /* Fall through */
454 case PATH_MOVETO:
455 case PATH_MOVETO_OPEN:
456 case PATH_LINETO:
457 /* Destination point grip */
458 section->x3 = 2 * world_centerx - section->x3;
459 break;
460 case PATH_END:
461 break;
465 o_path_recalc (toplevel, object);
469 /*! \brief Recalculate path coordinates in SCREEN units.
470 * \par Function Description
471 * This function recalculate the bounding box of the <B>o_current</B>
473 * \param [in] toplevel The TOPLEVEL object.
474 * \param [in,out] o_current Line OBJECT to be recalculated.
476 void o_path_recalc (TOPLEVEL *toplevel, OBJECT *o_current)
478 int left, right, top, bottom;
480 g_return_if_fail (o_current->path != NULL);
482 /* Update the bounding box */
483 if (o_current->path->num_sections > 0) {
484 world_get_path_bounds (toplevel, o_current, &left, &top, &right, &bottom);
485 o_current->w_left = left;
486 o_current->w_top = top;
487 o_current->w_right = right;
488 o_current->w_bottom = bottom;
489 o_current->w_bounds_valid = TRUE;
490 } else {
491 o_current->w_bounds_valid = FALSE;
496 /*! \brief Get path bounding rectangle in WORLD coordinates.
497 * \par Function Description
498 * This function sets the <B>left</B>, <B>top</B>, <B>right</B> and
499 * <B>bottom</B> parameters to the boundings of the path object described
500 * in <B>*path</B> in world units.
502 * \note Bounding box for bezier curves is loose because we just consider
503 * the convex hull of the curve control and end-points.
505 * \param [in] toplevel The TOPLEVEL object.
506 * \param [in] object Line OBJECT to read coordinates from.
507 * \param [out] left Left path coordinate in WORLD units.
508 * \param [out] top Top path coordinate in WORLD units.
509 * \param [out] right Right path coordinate in WORLD units.
510 * \param [out] bottom Bottom path coordinate in WORLD units.
512 void world_get_path_bounds (TOPLEVEL *toplevel, OBJECT *object,
513 int *left, int *top, int *right, int *bottom)
515 PATH_SECTION *section;
516 int halfwidth;
517 int i;
518 int found_bound = FALSE;
520 /* Find the bounds of the path region */
521 for (i = 0; i < object->path->num_sections; i++) {
522 section = &object->path->sections[i];
523 switch (section->code) {
524 case PATH_CURVETO:
525 /* Bezier curves with this construction of control points will lie
526 * within the convex hull of the control and curve end points */
527 *left = (found_bound) ? MIN (*left, section->x1) : section->x1;
528 *top = (found_bound) ? MIN (*top, section->y1) : section->y1;
529 *right = (found_bound) ? MAX (*right, section->x1) : section->x1;
530 *bottom = (found_bound) ? MAX (*bottom, section->y1) : section->y1;
531 found_bound = TRUE;
532 *left = MIN (*left, section->x2);
533 *top = MIN (*top, section->y2);
534 *right = MAX (*right, section->x2);
535 *bottom = MAX (*bottom, section->y2);
536 /* Fall through */
537 case PATH_MOVETO:
538 case PATH_MOVETO_OPEN:
539 case PATH_LINETO:
540 *left = (found_bound) ? MIN (*left, section->x3) : section->x3;
541 *top = (found_bound) ? MIN (*top, section->y3) : section->y3;
542 *right = (found_bound) ? MAX (*right, section->x3) : section->x3;
543 *bottom = (found_bound) ? MAX (*bottom, section->y3) : section->y3;
544 found_bound = TRUE;
545 break;
546 case PATH_END:
547 break;
551 if (found_bound) {
552 /* This isn't strictly correct, but a 1st order approximation */
553 halfwidth = object->line_width / 2;
554 *left -= halfwidth;
555 *top -= halfwidth;
556 *right += halfwidth;
557 *bottom += halfwidth;
561 /*! \brief get the position of the first path point
562 * \par Function Description
563 * This function gets the position of the first point of an path object.
565 * \param [in] toplevel The toplevel environment.
566 * \param [out] x pointer to the x-position
567 * \param [out] y pointer to the y-position
568 * \param [in] object The object to get the position.
569 * \return TRUE if successfully determined the position, FALSE otherwise
571 gboolean o_path_get_position (TOPLEVEL *toplevel, gint *x, gint *y,
572 OBJECT *object)
574 if (object->path->num_sections == 0)
575 return FALSE;
577 *x = object->path->sections[0].x3;
578 *y = object->path->sections[0].y3;
579 return TRUE;
582 /*! \brief Print a solid PATH to Postscript document.
583 * \par Function Description
584 * This function prints the outline of a path when a solid line type is
585 * required. The postscript file is defined by the file pointer <B>fp</B>.
586 * The parameters <B>length</B> and <B>space</B> are ignored.
588 * All dimensions are in mils.
590 * \param [in] toplevel The TOPLEVEL object.
591 * \param [in] fp FILE pointer to Postscript document.
592 * \param [in] path The PATH object ot print
593 * \param [in] line_width PATH Line width.
594 * \param [in] length Dashed line length.
595 * \param [in] space Amount of space between dashes.
596 * \param [in] origin_x Page x coordinate to place PATH OBJECT.
597 * \param [in] origin_y Page y coordinate to place PATH OBJECT.
599 static void o_path_print_solid (TOPLEVEL *toplevel, FILE *fp, PATH *path,
600 int line_width, int length, int space,
601 int origin_x, int origin_y)
603 int i;
605 for (i = 0; i < path->num_sections; i++) {
606 PATH_SECTION *section = &path->sections[i];
608 if (i > 0)
609 fprintf (fp, " ");
611 switch (section->code) {
612 case PATH_MOVETO:
613 fprintf (fp, "closepath");
614 /* Fall through */
615 case PATH_MOVETO_OPEN:
616 fprintf (fp, "%i %i moveto",
617 section->x3 - origin_x, section->y3 - origin_y);
618 break;
619 case PATH_CURVETO:
620 fprintf (fp, "%i %i %i %i %i %i curveto",
621 section->x1 - origin_x, section->y1 - origin_y,
622 section->x2 - origin_x, section->y2 - origin_y,
623 section->x3 - origin_x, section->y3 - origin_y);
624 break;
625 case PATH_LINETO:
626 fprintf (fp, "%i %i lineto",
627 section->x3 - origin_x, section->y3 - origin_y);
628 break;
629 case PATH_END:
630 fprintf (fp, "closepath");
631 break;
635 fprintf (fp, " stroke\n");
639 /*! \brief Print a dotted PATH to Postscript document.
640 * \par Function Description
641 * This function prints the outline of a path when a dotted line type is
642 * required. The postscript file is defined by the file pointer <B>fp</B>.
643 * The parameter <B>length</B> is ignored.
645 * All dimensions are in mils.
647 * \param [in] toplevel The TOPLEVEL object
648 * \param [in] fp FILE pointer to Postscript document
649 * \param [in] path The PATH object to print
650 * \param [in] line_width PATH Line width
651 * \param [in] length Dashed line length
652 * \param [in] space Amount of space between dashes
653 * \param [in] origin_x Page x coordinate to place PATH OBJECT
654 * \param [in] origin_y Page y coordinate to place PATH OBJECT
656 static void o_path_print_dotted (TOPLEVEL *toplevel, FILE *fp, PATH *path,
657 int line_width, int length, int space,
658 int origin_x, int origin_y)
660 o_path_print_solid (toplevel, fp, path, line_width,
661 length, space, origin_x, origin_y);
665 /*! \brief Print a dashed PATH to Postscript document.
666 * \par Function Description
667 * This function prints the outline of a path when a dashed line type is
668 * required. The postscript file is defined by the file pointer <B>fp</B>.
670 * All dimensions are in mils.
672 * \param [in] toplevel The TOPLEVEL object.
673 * \param [in] fp FILE pointer to Postscript document.
674 * \param [in] path The PATH object to print.
675 * \param [in] line_width PATH Line width.
676 * \param [in] length Dashed line length.
677 * \param [in] space Amount of space between dashes.
678 * \param [in] origin_x Page x coordinate to place PATH OBJECT.
679 * \param [in] origin_y Page y coordinate to place PATH OBJECT.
681 static void o_path_print_dashed (TOPLEVEL *toplevel, FILE *fp, PATH *path,
682 int line_width, int length, int space,
683 int origin_x, int origin_y)
685 o_path_print_solid (toplevel, fp, path, line_width,
686 length, space, origin_x, origin_y);
690 /*! \brief Print centered line type PATH to Postscript document.
691 * \par Function Description
692 * This function prints the outline of a path when a centered line type is
693 * required. The postscript file is defined by the file pointer <B>fp</B>.
695 * All dimensions are in mils.
697 * \param [in] toplevel The TOPLEVEL object
698 * \param [in] fp FILE pointer to Postscript document
699 * \param [in] path The PATH object to print
700 * \param [in] line_width PATH Line width
701 * \param [in] length Dashed line length
702 * \param [in] space Amount of space between dashes
703 * \param [in] origin_x Page x coordinate to place PATH OBJECT
704 * \param [in] origin_y Page y coordinate to place PATH OBJECT
706 static void o_path_print_center (TOPLEVEL *toplevel, FILE *fp, PATH *path,
707 int line_width, int length,
708 int space, int origin_x, int origin_y)
710 o_path_print_solid (toplevel, fp, path, line_width,
711 length, space, origin_x, origin_y);
715 /*! \brief Print phantom line type PATH to Postscript document.
716 * \par Function Description
717 * This function prints the outline of a path when a phantom line type is
718 * required. The postscript file is defined by the file pointer <B>fp</B>.
720 * All dimensions are in mils.
722 * \param [in] toplevel The TOPLEVEL object
723 * \param [in] fp FILE pointer to Postscript document
724 * \param [in] path The PATH object to print
725 * \param [in] line_width PATH Line width
726 * \param [in] length Dashed line length
727 * \param [in] space Amount of space between dashes
728 * \param [in] origin_x Page x coordinate to place PATH OBJECT
729 * \param [in] origin_y Page y coordinate to place PATH OBJECT
731 static void o_path_print_phantom (TOPLEVEL *toplevel, FILE *fp, PATH *path,
732 int line_width, int length,
733 int space, int origin_x, int origin_y)
735 o_path_print_solid (toplevel, fp, path, line_width,
736 length, space, origin_x, origin_y);
740 /*! \brief Print a solid pattern PATH to Postscript document.
741 * \par Function Description
742 * The function prints a filled path with a solid pattern. No outline is
743 * printed. The postscript file is defined by the file pointer <B>fp</B>.
744 * <B>fill_width</B>, <B>angle1</B> and <B>pitch1</B>, <B>angle2</B> and <B>pitch2</B>
745 * parameters are ignored in this functions but kept for compatibility
746 * with other fill functions.
748 * All dimensions are in mils.
750 * \param [in] toplevel The TOPLEVEL object
751 * \param [in] fp FILE pointer to Postscript document
752 * \param [in] path The PATH object to print
753 * \param [in] fill_width PATH fill width (unused)
754 * \param [in] angle1 (unused)
755 * \param [in] pitch1 (unused)
756 * \param [in] angle2 (unused)
757 * \param [in] pitch2 (unused)
758 * \param [in] origin_x Page x coordinate to place PATH OBJECT
759 * \param [in] origin_y Page y coordinate to place PATH OBJECT
761 static void o_path_print_filled (TOPLEVEL *toplevel, FILE *fp, PATH *path,
762 int fill_width,
763 int angle1, int pitch1, int angle2, int pitch2,
764 int origin_x, int origin_y)
766 int i;
768 for (i = 0; i < path->num_sections; i++) {
769 PATH_SECTION *section = &path->sections[i];
771 if (i > 0)
772 fprintf (fp, " ");
774 switch (section->code) {
775 case PATH_MOVETO:
776 fprintf (fp, "closepath");
777 /* Fall through */
778 case PATH_MOVETO_OPEN:
779 fprintf (fp, "%i %i moveto",
780 section->x3 - origin_x, section->y3 - origin_y);
781 break;
782 case PATH_CURVETO:
783 fprintf (fp, "%i %i %i %i %i %i curveto",
784 section->x1 - origin_x, section->y1 - origin_y,
785 section->x2 - origin_x, section->y2 - origin_y,
786 section->x3 - origin_x, section->y3 - origin_y);
787 break;
788 case PATH_LINETO:
789 fprintf (fp, "%i %i lineto",
790 section->x3 - origin_x, section->y3 - origin_y);
791 break;
792 case PATH_END:
793 fprintf (fp, "closepath");
794 break;
798 fprintf (fp, " fill\n");
802 /*! \brief Print a hatch pattern PATH to Postscript document.
803 * \par Function Description
804 * The function prints a hatched path. No outline is printed.
805 * The postscript file is defined by the file pointer <B>fp</B>.
806 * <B>fill_width</B>, <B>angle1</B>, <B>pitch1</B> parameters define the way the path
807 * has to be hatched.
808 * <B>angle2</B> and <B>pitch2</B> parameters are unused but kept for compatibility
809 * with other fill functions.
811 * Negative or zero values for <B>pitch1</B> are not allowed.
813 * All dimensions are in mils.
815 * \param [in] toplevel The TOPLEVEL object
816 * \param [in] fp FILE pointer to Postscript document
817 * \param [in] path The PATH object to print
818 * \param [in] fill_width PATH fill width
819 * \param [in] angle1 Angle of hatch pattern
820 * \param [in] pitch1 Pitch of hatch pattern
821 * \param [in] angle2 (unused)
822 * \param [in] pitch2 (unused)
823 * \param [in] origin_x Page x coordinate to place PATH OBJECT
824 * \param [in] origin_y Page y coordinate to place PATH OBJECT
826 static void o_path_print_hatch (TOPLEVEL *toplevel, FILE *fp, PATH *path,
827 int fill_width,
828 int angle1, int pitch1, int angle2, int pitch2,
829 int origin_x, int origin_y)
831 int i;
832 GArray *lines;
834 g_return_if_fail (toplevel != NULL);
835 g_return_if_fail (fp != NULL);
837 /* Avoid printing line widths too small */
838 if (fill_width <= 1) fill_width = 2;
840 lines = g_array_new (FALSE, FALSE, sizeof(LINE));
842 m_hatch_path (path, angle1, pitch1, lines);
844 for (i=0; i < lines->len; i++) {
845 LINE *line = &g_array_index (lines, LINE, i);
847 fprintf (fp,"%d %d %d %d %d line\n", line->x[0], line->y[0],
848 line->x[1], line->y[1], fill_width);
851 g_array_free (lines, TRUE);
855 /*! \brief Print a mesh pattern PATH to Postscript document.
856 * \par Function Description
857 * This function prints a meshed path. No outline is printed.
858 * The postscript file is defined by the file pointer <B>fp</B>.
860 * Negative or zero values for <B>pitch1</B> and/or <B>pitch2</B> are
861 * not allowed.
863 * All dimensions are in mils.
865 * \param [in] toplevel The TOPLEVEL object
866 * \param [in] fp FILE pointer to Postscript document
867 * \param [in] path The PATH object to print
868 * \param [in] fill_width PATH fill width
869 * \param [in] angle1 1st angle for mesh pattern
870 * \param [in] pitch1 1st pitch for mesh pattern
871 * \param [in] angle2 2nd angle for mesh pattern
872 * \param [in] pitch2 2nd pitch for mesh pattern
873 * \param [in] origin_x Page x coordinate to place PATH OBJECT
874 * \param [in] origin_y Page y coordinate to place PATH OBJECT
876 static void o_path_print_mesh (TOPLEVEL *toplevel, FILE *fp, PATH *path,
877 int fill_width,
878 int angle1, int pitch1, int angle2, int pitch2,
879 int origin_x, int origin_y)
881 o_path_print_hatch (toplevel, fp, path, fill_width,
882 angle1, pitch1, -1, -1, origin_x, origin_y);
884 o_path_print_hatch (toplevel, fp, path, fill_width,
885 angle2, pitch2, -1, -1, origin_x, origin_y);
889 /*! \brief Print PATH to Postscript document.
890 * \par Function Description
891 * This function prints the path described by the <B>o_current</B>
892 * parameter to a Postscript document.
893 * The Postscript document is descibed by the file pointer <B>fp</B>.
895 * \param [in] toplevel The TOPLEVEL object.
896 * \param [in] fp FILE pointer to Postscript document.
897 * \param [in] o_current PATH OBJECT to write to document.
898 * \param [in] origin_x Page x coordinate to place PATH OBJECT.
899 * \param [in] origin_y Page y coordinate to place PATH OBJECT.
901 void o_path_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
902 int origin_x, int origin_y)
904 int line_width, length, space;
905 int fill_width, angle1, pitch1, angle2, pitch2;
906 DRAW_FUNC outl_func = NULL;
907 FILL_FUNC fill_func = NULL;
909 /*! \note
910 * Depending on the type of the line for this particular path, the
911 * appropriate function is chosen among #o_path_print_solid(),
912 * #o_path_print_dotted(), #o_path_print_dashed(),
913 * #o_path_print_center() and #o_path_print_phantom().
915 * The needed parameters for each of these type is extracted from the
916 * <B>o_current</B> object. Depending on the type, unused parameters are
917 * set to -1.
919 * In the eventuality of a length and/or space null, the line is printed
920 * solid to avoid and endless loop produced by other functions in such a
921 * case.
923 line_width = o_current->line_width;
925 if (line_width <= 2) {
926 if (toplevel->line_style == THICK) {
927 line_width = LINE_WIDTH;
928 } else {
929 line_width=2;
932 length = o_current->line_length;
933 space = o_current->line_space;
935 switch(o_current->line_type) {
936 case TYPE_SOLID:
937 length = -1; space = -1;
938 outl_func = o_path_print_solid;
939 break;
941 case TYPE_DOTTED:
942 length = -1;
943 outl_func = o_path_print_dotted;
944 break;
946 case TYPE_DASHED:
947 outl_func = o_path_print_dashed;
948 break;
950 case TYPE_CENTER:
951 outl_func = o_path_print_center;
952 break;
954 case TYPE_PHANTOM:
955 outl_func = o_path_print_phantom;
956 break;
958 case TYPE_ERASE:
959 /* Unused for now, print it solid */
960 length = -1; space = -1;
961 outl_func = o_path_print_solid;
962 break;
965 if((length == 0) || (space == 0)) {
966 length = -1; space = -1;
967 outl_func = o_path_print_solid;
970 f_print_set_color (toplevel, fp, o_current->color);
972 f_print_set_line_width (fp, line_width);
974 (*outl_func) (toplevel, fp, o_current->path, line_width,
975 length, space, origin_x, origin_y);
977 /*! \note
978 * If the filling type of the path is not <B>HOLLOW</B>, the appropriate
979 * function is chosen among #o_path_print_filled(), #o_path_print_mesh()
980 * and #o_path_print_hatch(). The corresponding parameters are extracted
981 * from the <B>o_current</B> object and corrected afterward.
983 * The case where <B>pitch1</B> and <B>pitch2</B> are null or negative is
984 * avoided as it leads to an endless loop in most of the called functions.
985 * In such a case, the path is printed filled. Unused parameters for each of
986 * these functions are set to -1 or any passive value.
988 if(o_current->fill_type != FILLING_HOLLOW) {
989 fill_width = o_current->fill_width;
990 angle1 = o_current->fill_angle1;
991 pitch1 = o_current->fill_pitch1;
992 angle2 = o_current->fill_angle2;
993 pitch2 = o_current->fill_pitch2;
995 switch(o_current->fill_type) {
996 case FILLING_FILL:
997 angle1 = -1; pitch1 = 1;
998 angle2 = -1; pitch2 = 1;
999 fill_width = -1;
1000 fill_func = o_path_print_filled;
1001 break;
1003 case FILLING_MESH:
1004 fill_func = o_path_print_mesh;
1005 break;
1007 case FILLING_HATCH:
1008 angle2 = -1; pitch2 = 1;
1009 fill_func = o_path_print_hatch;
1010 break;
1012 case FILLING_VOID:
1013 /* Unused for now, print it filled */
1014 angle1 = -1; pitch1 = 1;
1015 angle2 = -1; pitch2 = 1;
1016 fill_width = -1;
1017 fill_func = o_path_print_filled;
1018 break;
1020 case FILLING_HOLLOW:
1021 /* nop */
1022 break;
1026 if((pitch1 <= 0) || (pitch2 <= 0)) {
1027 angle1 = -1; pitch1 = 1;
1028 angle2 = -1; pitch2 = 1;
1029 fill_func = o_path_print_filled;
1032 (*fill_func) (toplevel, fp,
1033 o_current->path, fill_width,
1034 angle1, pitch1, angle2, pitch2, origin_x, origin_y);
1039 /*! \brief Calculates the distance between the given point and the closest
1040 * point on the given path segment.
1042 * \param [in] object The path OBJECT.
1043 * \param [in] x The x coordinate of the given point.
1044 * \param [in] y The y coordinate of the given point.
1045 * \param [in] force_solid If true, force treating the object as solid.
1046 * \return The shortest distance from the object to the point. With an
1047 * invalid parameter, this function returns G_MAXDOUBLE.
1049 double o_path_shortest_distance (OBJECT *object, int x, int y, int force_solid)
1051 int solid;
1053 solid = force_solid || object->fill_type != FILLING_HOLLOW;
1055 return s_path_shortest_distance (object->path, x, y, solid);