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
26 #include "libgeda_priv.h"
28 #ifdef HAVE_LIBDMALLOC
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
,
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
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
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
)
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
);
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>
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
)
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 */
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 :
144 * <DT>*</DT><DD>the file format used until 20010704 release.
145 * <DT>*</DT><DD>the file format used for the releases after 20010704.
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
)
162 int line_width
, line_space
, line_length
;
165 int fill_type
, fill_width
, angle1
, pitch1
, angle2
, pitch2
;
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
++) {
201 line
= s_textbuffer_next_line (tb
);
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
);
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
);
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.
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
;
246 OBJECT_TYPE line_type
;
247 OBJECT_FILLING fill_type
;
248 int fill_width
, angle1
, pitch1
, angle2
, pitch2
;
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
);
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
)
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
) {
308 /* Two control point grips */
309 if (whichone
== grip_no
++) {
313 if (whichone
== grip_no
++) {
319 case PATH_MOVETO_OPEN
:
321 /* Destination point grip */
322 if (whichone
== grip_no
++) {
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
;
354 for (i
= 0; i
< object
->path
->num_sections
; i
++) {
355 section
= &object
->path
->sections
[i
];
357 switch (section
->code
) {
365 case PATH_MOVETO_OPEN
:
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
,
397 PATH_SECTION
*section
;
400 for (i
= 0; i
< object
->path
->num_sections
; i
++) {
401 section
= &object
->path
->sections
[i
];
403 switch (section
->code
) {
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
, §ion
->x1
, §ion
->y1
);
409 rotate_point_90 (section
->x2
, section
->y2
, angle
, §ion
->x2
, §ion
->y2
);
410 section
->x1
+= world_centerx
; section
->y1
+= world_centery
;
411 section
->x2
+= world_centerx
; section
->y2
+= world_centery
;
414 case PATH_MOVETO_OPEN
:
416 /* Destination point grip */
417 section
->x3
-= world_centerx
; section
->y3
-= world_centery
;
418 rotate_point_90 (section
->x3
, section
->y3
, angle
, §ion
->x3
, §ion
->y3
);
419 section
->x3
+= world_centerx
; section
->y3
+= world_centery
;
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
;
445 for (i
= 0; i
< object
->path
->num_sections
; i
++) {
446 section
= &object
->path
->sections
[i
];
448 switch (section
->code
) {
450 /* Two control point grips */
451 section
->x1
= 2 * world_centerx
- section
->x1
;
452 section
->x2
= 2 * world_centerx
- section
->x2
;
455 case PATH_MOVETO_OPEN
:
457 /* Destination point grip */
458 section
->x3
= 2 * world_centerx
- section
->x3
;
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
;
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
;
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
) {
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
;
532 *left
= MIN (*left
, section
->x2
);
533 *top
= MIN (*top
, section
->y2
);
534 *right
= MAX (*right
, section
->x2
);
535 *bottom
= MAX (*bottom
, section
->y2
);
538 case PATH_MOVETO_OPEN
:
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
;
552 /* This isn't strictly correct, but a 1st order approximation */
553 halfwidth
= object
->line_width
/ 2;
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
,
574 if (object
->path
->num_sections
== 0)
577 *x
= object
->path
->sections
[0].x3
;
578 *y
= object
->path
->sections
[0].y3
;
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
)
605 for (i
= 0; i
< path
->num_sections
; i
++) {
606 PATH_SECTION
*section
= &path
->sections
[i
];
611 switch (section
->code
) {
613 fprintf (fp
, "closepath");
615 case PATH_MOVETO_OPEN
:
616 fprintf (fp
, "%i %i moveto",
617 section
->x3
- origin_x
, section
->y3
- origin_y
);
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
);
626 fprintf (fp
, "%i %i lineto",
627 section
->x3
- origin_x
, section
->y3
- origin_y
);
630 fprintf (fp
, "closepath");
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
,
763 int angle1
, int pitch1
, int angle2
, int pitch2
,
764 int origin_x
, int origin_y
)
768 for (i
= 0; i
< path
->num_sections
; i
++) {
769 PATH_SECTION
*section
= &path
->sections
[i
];
774 switch (section
->code
) {
776 fprintf (fp
, "closepath");
778 case PATH_MOVETO_OPEN
:
779 fprintf (fp
, "%i %i moveto",
780 section
->x3
- origin_x
, section
->y3
- origin_y
);
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
);
789 fprintf (fp
, "%i %i lineto",
790 section
->x3
- origin_x
, section
->y3
- origin_y
);
793 fprintf (fp
, "closepath");
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
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
,
828 int angle1
, int pitch1
, int angle2
, int pitch2
,
829 int origin_x
, int origin_y
)
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
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
,
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
;
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
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
923 line_width
= o_current
->line_width
;
925 if (line_width
<= 2) {
926 if (toplevel
->line_style
== THICK
) {
927 line_width
= LINE_WIDTH
;
932 length
= o_current
->line_length
;
933 space
= o_current
->line_space
;
935 switch(o_current
->line_type
) {
937 length
= -1; space
= -1;
938 outl_func
= o_path_print_solid
;
943 outl_func
= o_path_print_dotted
;
947 outl_func
= o_path_print_dashed
;
951 outl_func
= o_path_print_center
;
955 outl_func
= o_path_print_phantom
;
959 /* Unused for now, print it solid */
960 length
= -1; space
= -1;
961 outl_func
= o_path_print_solid
;
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
);
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
) {
997 angle1
= -1; pitch1
= 1;
998 angle2
= -1; pitch2
= 1;
1000 fill_func
= o_path_print_filled
;
1004 fill_func
= o_path_print_mesh
;
1008 angle2
= -1; pitch2
= 1;
1009 fill_func
= o_path_print_hatch
;
1013 /* Unused for now, print it filled */
1014 angle1
= -1; pitch1
= 1;
1015 angle2
= -1; pitch2
= 1;
1017 fill_func
= o_path_print_filled
;
1020 case FILLING_HOLLOW
:
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
)
1053 solid
= force_solid
|| object
->fill_type
!= FILLING_HOLLOW
;
1055 return s_path_shortest_distance (object
->path
, x
, y
, solid
);