1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2008 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA
26 #include "libgeda_priv.h"
28 #ifdef HAVE_LIBDMALLOC
32 static OBJECT
*o_path_copy(TOPLEVEL
*toplevel
, OBJECT
*o_current
);
33 static void o_path_recalc(OBJECT
*o_current
);
34 void o_path_grip_foreach(OBJECT
*o
,
35 gboolean (*fn
)(OBJECT
*o
,
36 int grip_x
, int grip_y
,
40 static int o_path_grip_move(OBJECT
*o
, int whichone
, int x
, int y
);
42 /*! Default setting for path draw function. */
43 void (*path_draw_func
)() = NULL
;
45 typedef void (*DRAW_FUNC
) (FILE *fp
, PATH
*path
,
46 int line_width
, int length
, int space
);
48 typedef void (*FILL_FUNC
) (FILE *fp
, PATH
*path
,
50 int angle1
, int pitch1
, int angle2
, int pitch2
);
52 /*! \brief Create and add path OBJECT to list.
53 * \par Function Description
54 * This function creates a new object representing a path.
55 * This object is added to the end of the list <B>object_list</B>
56 * pointed object belongs to.
57 * The path is described by its two ends - <B>x1</B>,<B>y1</B> and
58 * <B>x2</B>,<B>y2</B>.
59 * The <B>type</B> parameter must be equal to #OBJ_PATH.
60 * The <B>color</B> parameter corresponds to the color the path
63 * The #OBJECT structure is allocated with the
64 * #s_basic_init_object() function. The structure describing
65 * the path is allocated and initialized with the parameters given
68 * Both the path type and the filling type are set to default
69 * values : solid path type with a width of 0, and no filling.
70 * It can be changed after with the #o_set_line_options() and
71 * #o_set_fill_options().
73 * The object is added to the end of the list described by the
74 * <B>object_list</B> parameter by the #s_basic_link_object().
76 * \param [in] toplevel The TOPLEVEL object.
77 * \param [in] type Must be OBJ_PATH.
78 * \param [in] color The path color.
79 * \param [in] path_string The string representation of the path
80 * \return A pointer to the new end of the object list.
82 OBJECT
*o_path_new (TOPLEVEL
*toplevel
,
83 char type
, int color
, const char *path_string
)
87 /* create the object */
88 new_node
= s_toplevel_new_object(toplevel
, type
, "path");
89 new_node
->color
= color
;
91 new_node
->path
= s_path_parse (path_string
);
93 new_node
->copy_func
= &o_path_copy
;
94 new_node
->bounds_recalc_func
= o_path_recalc
;
95 new_node
->draw_func
= path_draw_func
;
96 new_node
->grip_foreach_func
= &o_path_grip_foreach
;
97 new_node
->grip_move_func
= &o_path_grip_move
;
99 /* path type and filling initialized to default */
100 o_set_line_options (new_node
, END_NONE
, TYPE_SOLID
, 0, -1, -1);
101 o_set_fill_options (new_node
, FILLING_HOLLOW
, -1, -1, -1, -1, -1);
103 /* compute bounding box */
104 o_path_recalc(new_node
);
110 /*! \brief Create a copy of a path.
111 * \par Function Description
112 * This function creates a verbatim copy of the
113 * object pointed by <B>o_current</B> describing a path. The new object
114 * is added at the end of the list following the <B>list_tail</B>
117 * \param [in] toplevel The TOPLEVEL object.
118 * \param [in] o_current Line OBJECT to copy.
119 * \return A new pointer to the end of the object list.
121 static OBJECT
*o_path_copy(TOPLEVEL
*toplevel
, OBJECT
*o_current
)
127 if (o_current
->saved_color
== -1) {
128 color
= o_current
->color
;
130 color
= o_current
->saved_color
;
133 path_string
= s_path_string_from_path (o_current
->path
);
134 new_obj
= o_path_new (toplevel
, OBJ_PATH
, color
, path_string
);
135 g_free (path_string
);
137 /* copy the path type and filling options */
138 o_set_line_options (new_obj
, o_current
->line_end
,
139 o_current
->line_type
, o_current
->line_width
,
140 o_current
->line_length
, o_current
->line_space
);
141 o_set_fill_options (new_obj
,
142 o_current
->fill_type
, o_current
->fill_width
,
143 o_current
->fill_pitch1
, o_current
->fill_angle1
,
144 o_current
->fill_pitch2
, o_current
->fill_angle2
);
146 /* calc the bounding box */
147 o_path_recalc(o_current
);
149 /* return the new tail of the object list */
154 /*! \brief Create path OBJECT from character string.
155 * \par Function Description
156 * This function creates a path OBJECT from the character string
157 * <B>*buf</B> and a number of lines following that describing the
158 * path, read from <B>*tb</B>. The new path is added to the
159 * list of objects of which <B>*object_list</B> is the last element
161 * The function returns the new path object.
163 * Depending on <B>*version</B>, the correct file format is considered.
164 * Currently two file format revisions are supported :
166 * <DT>*</DT><DD>the file format used until 20010704 release.
167 * <DT>*</DT><DD>the file format used for the releases after 20010704.
170 * \param [in] toplevel The TOPLEVEL object.
171 * \param [in] first_line Character string with path description.
172 * \param [in] tb Text buffer containing the path string.
173 * \param [in] release_ver libgeda release version number.
174 * \param [in] fileformat_ver libgeda file format version number.
175 * \return A pointer to the new path object.
177 OBJECT
*o_path_read (TOPLEVEL
*toplevel
,
178 const char *first_line
, TextBuffer
*tb
,
179 unsigned int release_ver
, unsigned int fileformat_ver
)
184 int line_width
, line_space
, line_length
;
187 int fill_type
, fill_width
, angle1
, pitch1
, angle2
, pitch2
;
194 * The current path format to describe a line is a space separated
195 * list of characters and numbers in plain ASCII on a single path.
196 * The meaning of each item is described in the file format documentation.
198 /* Allocate enough space */
199 sscanf (first_line
, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
200 &type
, &color
, &line_width
, &line_end
, &line_type
,
201 &line_length
, &line_space
, &fill_type
, &fill_width
, &angle1
,
202 &pitch1
, &angle2
, &pitch2
, &num_lines
);
205 * Checks if the required color is valid.
207 if (color
< 0 || color
> MAX_COLORS
) {
208 s_log_message (_("Found an invalid color [ %s ]\n"), first_line
);
209 s_log_message (_("Setting color to WHITE\n"));
214 * A path is internally described by its two ends. A new object is
215 * allocated, initialized and added to the list of objects. Its path
216 * type is set according to the values of the fields on the path.
219 pathstr
= g_string_new ("");
220 for (i
= 0; i
< num_lines
; i
++) {
223 line
= s_textbuffer_next_line (tb
);
226 pathstr
= g_string_append (pathstr
, line
);
230 /* retrieve the character string from the GString */
231 string
= g_string_free (pathstr
, FALSE
);
232 string
= remove_last_nl (string
);
234 /* create a new path */
235 new_obj
= o_path_new (toplevel
, type
, color
, string
);
238 /* set its line options */
239 o_set_line_options (new_obj
,
240 line_end
, line_type
, line_width
, line_length
, line_space
);
241 /* set its fill options */
242 o_set_fill_options (new_obj
,
243 fill_type
, fill_width
, pitch1
, angle1
, pitch2
, angle2
);
249 /*! \brief Create a character string representation of a path OBJECT.
250 * \par Function Description
251 * The function formats a string in the buffer <B>*buff</B> to describe
252 * the path object <B>*object</B>.
254 * \param [in] object path OBJECT to create string from.
255 * \return A pointer to the path OBJECT character string.
258 * Caller must g_free returned character string.
261 char *o_path_save (OBJECT
*object
)
264 int line_width
, line_space
, line_length
;
268 OBJECT_TYPE line_type
;
269 OBJECT_FILLING fill_type
;
270 int fill_width
, angle1
, pitch1
, angle2
, pitch2
;
273 /* description of the line type */
274 line_width
= object
->line_width
;
275 line_end
= object
->line_end
;
276 line_type
= object
->line_type
;
277 line_length
= object
->line_length
;
278 line_space
= object
->line_space
;
280 /* filling parameters */
281 fill_type
= object
->fill_type
;
282 fill_width
= object
->fill_width
;
283 angle1
= object
->fill_angle1
;
284 pitch1
= object
->fill_pitch1
;
285 angle2
= object
->fill_angle2
;
286 pitch2
= object
->fill_pitch2
;
288 /* Use the right color */
289 if (object
->saved_color
== -1) {
290 color
= object
->color
;
292 color
= object
->saved_color
;
295 path_string
= s_path_string_from_path (object
->path
);
296 num_lines
= o_text_num_lines (path_string
);
297 buf
= g_strdup_printf ("%c %d %d %d %d %d %d %d %d %d %d %d %d %d\n%s",
298 object
->type
, color
, line_width
, line_end
,
299 line_type
, line_length
, line_space
, fill_type
,
300 fill_width
, angle1
, pitch1
, angle2
, pitch2
,
301 num_lines
, path_string
);
302 g_free (path_string
);
307 /*! \brief Translate a path position in WORLD coordinates by a delta.
308 * \par Function Description
309 * This function applies a translation of (<B>x1</B>,<B>y1</B>) to the path
310 * described by <B>*object</B>. <B>x1</B> and <B>y1</B> are in world unit.
312 * \param [in] dx x distance to move.
313 * \param [in] dy y distance to move.
314 * \param [in,out] object Line OBJECT to translate.
316 void o_path_translate_world (int dx
, int dy
, OBJECT
*object
)
318 PATH_SECTION
*section
;
321 for (i
= 0; i
< object
->path
->num_sections
; i
++) {
322 section
= &object
->path
->sections
[i
];
324 switch (section
->code
) {
332 case PATH_MOVETO_OPEN
:
342 /* Update bounding box */
343 o_path_recalc(object
);
347 /*! \brief Rotate Line OBJECT using WORLD coordinates.
348 * \par Function Description
349 * This function rotates the path described by
350 * <B>*object</B> around the (<B>world_centerx</B>,<B>world_centery</B>)
351 * point by <B>angle</B> degrees.
352 * The center of rotation is in world units.
354 * \param [in] world_centerx Rotation center x coordinate in WORLD units.
355 * \param [in] world_centery Rotation center y coordinate in WORLD units.
356 * \param [in] angle Rotation angle in degrees (See note below).
357 * \param [in,out] object Line OBJECT to rotate.
359 void o_path_rotate_world (int world_centerx
, int world_centery
, int angle
,
362 PATH_SECTION
*section
;
365 for (i
= 0; i
< object
->path
->num_sections
; i
++) {
366 section
= &object
->path
->sections
[i
];
368 switch (section
->code
) {
370 /* Two control point grips */
371 section
->x1
-= world_centerx
; section
->y1
-= world_centery
;
372 section
->x2
-= world_centerx
; section
->y2
-= world_centery
;
373 rotate_point_90 (section
->x1
, section
->y1
, angle
, §ion
->x1
, §ion
->y1
);
374 rotate_point_90 (section
->x2
, section
->y2
, angle
, §ion
->x2
, §ion
->y2
);
375 section
->x1
+= world_centerx
; section
->y1
+= world_centery
;
376 section
->x2
+= world_centerx
; section
->y2
+= world_centery
;
379 case PATH_MOVETO_OPEN
:
381 /* Destination point grip */
382 section
->x3
-= world_centerx
; section
->y3
-= world_centery
;
383 rotate_point_90 (section
->x3
, section
->y3
, angle
, §ion
->x3
, §ion
->y3
);
384 section
->x3
+= world_centerx
; section
->y3
+= world_centery
;
390 o_path_recalc(object
);
394 /*! \brief Mirror a path using WORLD coordinates.
395 * \par Function Description
396 * This function mirrors the path from the point
397 * (<B>world_centerx</B>,<B>world_centery</B>) in world unit.
399 * \param [in] world_centerx Origin x coordinate in WORLD units.
400 * \param [in] world_centery Origin y coordinate in WORLD units.
401 * \param [in,out] object Line OBJECT to mirror.
403 void o_path_mirror_world (int world_centerx
, int world_centery
, OBJECT
*object
)
405 PATH_SECTION
*section
;
408 for (i
= 0; i
< object
->path
->num_sections
; i
++) {
409 section
= &object
->path
->sections
[i
];
411 switch (section
->code
) {
413 /* Two control point grips */
414 section
->x1
= 2 * world_centerx
- section
->x1
;
415 section
->x2
= 2 * world_centerx
- section
->x2
;
418 case PATH_MOVETO_OPEN
:
420 /* Destination point grip */
421 section
->x3
= 2 * world_centerx
- section
->x3
;
428 o_path_recalc(object
);
432 /*! \brief Recalculate path coordinates in SCREEN units.
433 * \par Function Description
434 * This function recalculate the bounding box of the <B>o_current</B>
436 * \param [in,out] o_current Line OBJECT to be recalculated.
438 static void o_path_recalc(OBJECT
*o_current
)
440 int left
, right
, top
, bottom
;
442 if (o_current
->path
== NULL
) {
446 /* Update the bounding box */
447 world_get_path_bounds(o_current
, &left
, &top
, &right
, &bottom
);
448 o_current
->w_left
= left
;
449 o_current
->w_top
= top
;
450 o_current
->w_right
= right
;
451 o_current
->w_bottom
= bottom
;
452 o_current
->w_bounds_valid
= TRUE
;
456 /*! \brief Get path bounding rectangle in WORLD coordinates.
457 * \par Function Description
458 * This function sets the <B>left</B>, <B>top</B>, <B>right</B> and
459 * <B>bottom</B> parameters to the boundings of the path object described
460 * in <B>*path</B> in world units.
462 * \note Bounding box for bezier curves is loose because we just consider
463 * the convex hull of the curve control and end-points.
465 * \param [in] object Line OBJECT to read coordinates from.
466 * \param [out] left Left path coordinate in WORLD units.
467 * \param [out] top Top path coordinate in WORLD units.
468 * \param [out] right Right path coordinate in WORLD units.
469 * \param [out] bottom Bottom path coordinate in WORLD units.
471 void world_get_path_bounds (OBJECT
*object
,
472 int *left
, int *top
, int *right
, int *bottom
)
474 PATH_SECTION
*section
;
477 int found_bound
= FALSE
;
479 /* Find the bounds of the path region */
480 for (i
= 0; i
< object
->path
->num_sections
; i
++) {
481 section
= &object
->path
->sections
[i
];
482 switch (section
->code
) {
484 /* Bezier curves with this construction of control points will lie
485 * within the convex hull of the control and curve end points */
486 *left
= (found_bound
) ? MIN (*left
, section
->x1
) : section
->x1
;
487 *top
= (found_bound
) ? MIN (*top
, section
->y1
) : section
->y1
;
488 *right
= (found_bound
) ? MAX (*right
, section
->x1
) : section
->x1
;
489 *bottom
= (found_bound
) ? MAX (*bottom
, section
->y1
) : section
->y1
;
491 *left
= MIN (*left
, section
->x2
);
492 *top
= MIN (*top
, section
->y2
);
493 *right
= MAX (*right
, section
->x2
);
494 *bottom
= MAX (*bottom
, section
->y2
);
497 case PATH_MOVETO_OPEN
:
499 *left
= (found_bound
) ? MIN (*left
, section
->x3
) : section
->x3
;
500 *top
= (found_bound
) ? MIN (*top
, section
->y3
) : section
->y3
;
501 *right
= (found_bound
) ? MAX (*right
, section
->x3
) : section
->x3
;
502 *bottom
= (found_bound
) ? MAX (*bottom
, section
->y3
) : section
->y3
;
511 /* This isn't strictly correct, but a 1st order approximation */
512 halfwidth
= object
->line_width
/ 2;
516 *bottom
+= halfwidth
;
520 void o_path_grip_foreach(OBJECT
*o
,
521 gboolean (*fn
)(OBJECT
*o
,
522 int grip_x
, int grip_y
,
523 enum grip_t whichone
,
529 /* Find the bounds of the path region */
530 for (i
= 0; i
< o
->path
->num_sections
; i
++) {
531 PATH_SECTION
*section
= &o
->path
->sections
[i
];
534 /* Encode the section in the grip number. */
535 whichone
= GRIP_FIRST_OPAQUE
+ i
*3;
537 switch (section
->code
) {
539 if ((*fn
)(o
, section
->x1
, section
->y1
, whichone
+ 0, userdata
)) return;
540 if ((*fn
)(o
, section
->x2
, section
->y2
, whichone
+ 1, userdata
)) return;
543 case PATH_MOVETO_OPEN
:
545 if ((*fn
)(o
, section
->x3
, section
->y3
, whichone
+ 2, userdata
)) return;
553 /*! \brief Modify control point location
555 * \par Function Description
556 * This function modifies a control point location of the path object
557 * *object. The control point being modified is selected according to
558 * the whichone parameter.
560 * The new position is given by <B>x</B> and <B>y</B>.
562 * \param [in,out] o The path OBJECT
563 * \param [in] whichone Which control point is being modified
564 * \param [in] x New x coordinate for the control point
565 * \param [in] y New y coordinate for the control point
567 static int o_path_grip_move(OBJECT
*o
, int whichone
, int x
, int y
)
569 int retval
= GRIP_NONE
;
572 PATH_SECTION
*section
;
576 s_path_moveto(o
->path
, x
, y
);
577 retval
= GRIP_PATH_NEXT_SECTION
;
580 case GRIP_PATH_NEXT_SECTION
:
581 s_path_lineto(o
->path
, x
, y
);
582 retval
= GRIP_PATH_NEXT_SECTION
;
585 case GRIP_PATH_LAST_SECTION
:
586 i
= o
->path
->num_sections
- 1;
587 g_return_val_if_fail(i
>= 0, GRIP_NONE
);
590 /* Degenerate path: add a new section instead of moving the path origin. */
591 return o_path_grip_move(o
, GRIP_PATH_NEXT_SECTION
, x
, y
);
593 return o_path_grip_move(o
, GRIP_FIRST_OPAQUE
+ i
*3 + 2, x
, y
);
596 case GRIP_PATH_CONTROL_1
:
597 case GRIP_PATH_CONTROL_2
:
598 g_return_val_if_fail(o
->path
->num_sections
>= 2, GRIP_NONE
);
599 s_path_mutate(o
->path
, PATH_CURVETO
);
600 i
= o
->path
->num_sections
- 1;
601 section
= &o
->path
->sections
[i
];
603 case GRIP_PATH_CONTROL_1
:
606 retval
= GRIP_PATH_CONTROL_2
;
608 case GRIP_PATH_CONTROL_2
:
611 retval
= GRIP_PATH_NEXT_SECTION
;
617 i
= (whichone
- GRIP_FIRST_OPAQUE
) / 3;
618 sub
= (whichone
- GRIP_FIRST_OPAQUE
) % 3;
619 g_return_val_if_fail(i
< o
->path
->num_sections
, GRIP_NONE
);
620 section
= &o
->path
->sections
[i
];
635 switch (section
->code
) {
637 retval
= whichone
+ 1;
640 case PATH_MOVETO_OPEN
:
642 /* The next grip is just the first grip of the next section. */
643 retval
= GRIP_FIRST_OPAQUE
+ (i
+1)*3;
649 if (retval
>= GRIP_FIRST_OPAQUE
+ o
->path
->num_sections
*3) {
650 /* We fell off the end of the path. */
661 /*! \brief Print a solid PATH to Postscript document.
662 * \par Function Description
663 * This function prints the outline of a path when a solid line type is
664 * required. The postscript file is defined by the file pointer <B>fp</B>.
665 * The parameters <B>length</B> and <B>space</B> are ignored.
667 * All dimensions are in mils.
669 * \param [in] fp FILE pointer to Postscript document.
670 * \param [in] path The PATH object ot print
671 * \param [in] line_width PATH Line width.
672 * \param [in] length Dashed line length.
673 * \param [in] space Amount of space between dashes.
675 static void o_path_print_solid (FILE *fp
, PATH
*path
,
676 int line_width
, int length
, int space
)
680 for (i
= 0; i
< path
->num_sections
; i
++) {
681 PATH_SECTION
*section
= &path
->sections
[i
];
686 switch (section
->code
) {
688 fprintf (fp
, "closepath ");
690 case PATH_MOVETO_OPEN
:
691 fprintf(fp
, "%i %i moveto", section
->x3
, section
->y3
);
694 fprintf (fp
, "%i %i %i %i %i %i curveto",
695 section
->x1
, section
->y1
,
696 section
->x2
, section
->y2
,
697 section
->x3
, section
->y3
);
700 fprintf(fp
, "%i %i lineto", section
->x3
, section
->y3
);
703 fprintf (fp
, "closepath ");
708 fprintf (fp
, "stroke\n");
712 /*! \brief Print a dotted PATH to Postscript document.
713 * \par Function Description
714 * This function prints the outline of a path when a dotted line type is
715 * required. The postscript file is defined by the file pointer <B>fp</B>.
716 * The parameter <B>length</B> is ignored.
718 * All dimensions are in mils.
720 * \param [in] fp FILE pointer to Postscript document
721 * \param [in] path The PATH object to print
722 * \param [in] line_width PATH Line width
723 * \param [in] length Dashed line length
724 * \param [in] space Amount of space between dashes
726 static void o_path_print_dotted (FILE *fp
, PATH
*path
,
727 int line_width
, int length
, int space
)
729 o_path_print_solid(fp
, path
, line_width
, length
, space
);
733 /*! \brief Print a dashed PATH to Postscript document.
734 * \par Function Description
735 * This function prints the outline of a path when a dashed line type is
736 * required. The postscript file is defined by the file pointer <B>fp</B>.
738 * All dimensions are in mils.
740 * \param [in] fp FILE pointer to Postscript document.
741 * \param [in] path The PATH object to print.
742 * \param [in] line_width PATH Line width.
743 * \param [in] length Dashed line length.
744 * \param [in] space Amount of space between dashes.
746 static void o_path_print_dashed (FILE *fp
, PATH
*path
,
747 int line_width
, int length
, int space
)
749 o_path_print_solid(fp
, path
, line_width
, length
, space
);
753 /*! \brief Print centered line type PATH to Postscript document.
754 * \par Function Description
755 * This function prints the outline of a path when a centered line type is
756 * required. The postscript file is defined by the file pointer <B>fp</B>.
758 * All dimensions are in mils.
760 * \param [in] fp FILE pointer to Postscript document
761 * \param [in] path The PATH object to print
762 * \param [in] line_width PATH Line width
763 * \param [in] length Dashed line length
764 * \param [in] space Amount of space between dashes
766 static void o_path_print_center (FILE *fp
, PATH
*path
,
767 int line_width
, int length
,
770 o_path_print_solid(fp
, path
, line_width
, length
, space
);
774 /*! \brief Print phantom line type PATH to Postscript document.
775 * \par Function Description
776 * This function prints the outline of a path when a phantom line type is
777 * required. The postscript file is defined by the file pointer <B>fp</B>.
779 * All dimensions are in mils.
781 * \param [in] fp FILE pointer to Postscript document
782 * \param [in] path The PATH object to print
783 * \param [in] line_width PATH Line width
784 * \param [in] length Dashed line length
785 * \param [in] space Amount of space between dashes
787 static void o_path_print_phantom (FILE *fp
, PATH
*path
,
788 int line_width
, int length
,
791 o_path_print_solid(fp
, path
, line_width
, length
, space
);
795 /*! \brief Print a solid pattern PATH to Postscript document.
796 * \par Function Description
797 * The function prints a filled path with a solid pattern. No outline is
798 * printed. The postscript file is defined by the file pointer <B>fp</B>.
799 * <B>fill_width</B>, <B>angle1</B> and <B>pitch1</B>, <B>angle2</B> and <B>pitch2</B>
800 * parameters are ignored in this functions but kept for compatibility
801 * with other fill functions.
803 * All dimensions are in mils.
805 * \param [in] fp FILE pointer to Postscript document
806 * \param [in] path The PATH object to print
807 * \param [in] fill_width PATH fill width (unused)
808 * \param [in] angle1 (unused)
809 * \param [in] pitch1 (unused)
810 * \param [in] angle2 (unused)
811 * \param [in] pitch2 (unused)
813 static void o_path_print_filled (FILE *fp
, PATH
*path
,
815 int angle1
, int pitch1
, int angle2
, int pitch2
)
819 for (i
= 0; i
< path
->num_sections
; i
++) {
820 PATH_SECTION
*section
= &path
->sections
[i
];
825 switch (section
->code
) {
827 fprintf (fp
, "closepath ");
829 case PATH_MOVETO_OPEN
:
830 fprintf(fp
, "%i %i moveto", section
->x3
, section
->y3
);
833 fprintf (fp
, "%i %i %i %i %i %i curveto",
834 section
->x1
, section
->y1
,
835 section
->x2
, section
->y2
,
836 section
->x3
, section
->y3
);
839 fprintf(fp
, "%i %i lineto", section
->x3
, section
->y3
);
842 fprintf (fp
, "closepath ");
847 fprintf (fp
, "fill\n");
851 /*! \brief Print a hatch pattern PATH to Postscript document.
852 * \par Function Description
853 * The function prints a hatched path. No outline is printed.
854 * The postscript file is defined by the file pointer <B>fp</B>.
855 * <B>fill_width</B>, <B>angle1</B>, <B>pitch1</B> parameters define the way the path
857 * <B>angle2</B> and <B>pitch2</B> parameters are unused but kept for compatibility
858 * with other fill functions.
860 * Negative or zero values for <B>pitch1</B> are not allowed.
862 * All dimensions are in mils.
864 * \param [in] fp FILE pointer to Postscript document
865 * \param [in] path The PATH object to print
866 * \param [in] fill_width PATH fill width
867 * \param [in] angle1 Angle of hatch pattern
868 * \param [in] pitch1 Pitch of hatch pattern
869 * \param [in] angle2 (unused)
870 * \param [in] pitch2 (unused)
872 static void o_path_print_hatch (FILE *fp
, PATH
*path
,
874 int angle1
, int pitch1
, int angle2
, int pitch2
)
878 g_return_if_fail (fp
!= NULL
);
880 /* Avoid printing line widths too small */
881 if (fill_width
<= 1) fill_width
= 2;
883 lines
= m_hatch_new();
884 m_hatch_path (path
, angle1
, pitch1
, lines
);
885 m_hatch_print(lines
, fp
, fill_width
);
886 g_array_free (lines
, TRUE
);
890 /*! \brief Print a mesh pattern PATH to Postscript document.
891 * \par Function Description
892 * This function prints a meshed path. No outline is printed.
893 * The postscript file is defined by the file pointer <B>fp</B>.
895 * Negative or zero values for <B>pitch1</B> and/or <B>pitch2</B> are
898 * All dimensions are in mils.
900 * \param [in] fp FILE pointer to Postscript document
901 * \param [in] path The PATH object to print
902 * \param [in] fill_width PATH fill width
903 * \param [in] angle1 1st angle for mesh pattern
904 * \param [in] pitch1 1st pitch for mesh pattern
905 * \param [in] angle2 2nd angle for mesh pattern
906 * \param [in] pitch2 2nd pitch for mesh pattern
908 static void o_path_print_mesh (FILE *fp
, PATH
*path
,
910 int angle1
, int pitch1
, int angle2
, int pitch2
)
912 o_path_print_hatch(fp
, path
, fill_width
, angle1
, pitch1
, -1, -1);
913 o_path_print_hatch(fp
, path
, fill_width
, angle2
, pitch2
, -1, -1);
917 /*! \brief Print PATH to Postscript document.
918 * \par Function Description
919 * This function prints the path described by the <B>o_current</B>
920 * parameter to a Postscript document.
921 * The Postscript document is described by the file pointer <B>fp</B>.
923 * \param [in] toplevel The TOPLEVEL object.
924 * \param [in] fp FILE pointer to Postscript document.
925 * \param [in] o_current PATH OBJECT to write to document.
927 void o_path_print(TOPLEVEL
*toplevel
, FILE *fp
, OBJECT
*o_current
)
929 int line_width
, length
, space
;
930 int fill_width
, angle1
, pitch1
, angle2
, pitch2
;
931 DRAW_FUNC outl_func
= NULL
;
932 FILL_FUNC fill_func
= NULL
;
935 * Depending on the type of the line for this particular path, the
936 * appropriate function is chosen among #o_path_print_solid(),
937 * #o_path_print_dotted(), #o_path_print_dashed(),
938 * #o_path_print_center() and #o_path_print_phantom().
940 * The needed parameters for each of these type is extracted from the
941 * <B>o_current</B> object. Depending on the type, unused parameters are
944 * In the eventuality of a length and/or space null, the line is printed
945 * solid to avoid and endless loop produced by other functions in such a
948 line_width
= o_current
->line_width
;
950 if (line_width
<= 2) {
951 if (toplevel
->line_style
== THICK
) {
952 line_width
= LINE_WIDTH
;
957 length
= o_current
->line_length
;
958 space
= o_current
->line_space
;
960 switch(o_current
->line_type
) {
962 length
= -1; space
= -1;
963 outl_func
= o_path_print_solid
;
968 outl_func
= o_path_print_dotted
;
972 outl_func
= o_path_print_dashed
;
976 outl_func
= o_path_print_center
;
980 outl_func
= o_path_print_phantom
;
984 /* Unused for now, print it solid */
985 length
= -1; space
= -1;
986 outl_func
= o_path_print_solid
;
990 if((length
== 0) || (space
== 0)) {
991 length
= -1; space
= -1;
992 outl_func
= o_path_print_solid
;
995 if (toplevel
->print_color
)
996 f_print_set_color (fp
, o_current
->color
);
998 f_print_set_line_width (fp
, line_width
);
1000 (*outl_func
)(fp
, o_current
->path
, line_width
, length
, space
);
1003 * If the filling type of the path is not <B>HOLLOW</B>, the appropriate
1004 * function is chosen among #o_path_print_filled(), #o_path_print_mesh()
1005 * and #o_path_print_hatch(). The corresponding parameters are extracted
1006 * from the <B>o_current</B> object and corrected afterward.
1008 * The case where <B>pitch1</B> and <B>pitch2</B> are null or negative is
1009 * avoided as it leads to an endless loop in most of the called functions.
1010 * In such a case, the path is printed filled. Unused parameters for each of
1011 * these functions are set to -1 or any passive value.
1013 if(o_current
->fill_type
!= FILLING_HOLLOW
) {
1014 fill_width
= o_current
->fill_width
;
1015 angle1
= o_current
->fill_angle1
;
1016 pitch1
= o_current
->fill_pitch1
;
1017 angle2
= o_current
->fill_angle2
;
1018 pitch2
= o_current
->fill_pitch2
;
1020 switch(o_current
->fill_type
) {
1022 angle1
= -1; pitch1
= 1;
1023 angle2
= -1; pitch2
= 1;
1025 fill_func
= o_path_print_filled
;
1029 fill_func
= o_path_print_mesh
;
1033 angle2
= -1; pitch2
= 1;
1034 fill_func
= o_path_print_hatch
;
1038 /* Unused for now, print it filled */
1039 angle1
= -1; pitch1
= 1;
1040 angle2
= -1; pitch2
= 1;
1042 fill_func
= o_path_print_filled
;
1045 case FILLING_HOLLOW
:
1051 if((pitch1
<= 0) || (pitch2
<= 0)) {
1052 angle1
= -1; pitch1
= 1;
1053 angle2
= -1; pitch2
= 1;
1054 fill_func
= o_path_print_filled
;
1057 (*fill_func
) (fp
, o_current
->path
, fill_width
,
1058 angle1
, pitch1
, angle2
, pitch2
);
1063 /*! \brief Calculates the distance between the given point and the closest
1064 * point on the given path segment.
1066 * \todo Support for bezier path segments.
1068 * \param [in] object The path OBJECT
1069 * \param [in] x The x coordinate of the given point.
1070 * \param [in] y The y coordinate of the given point.
1071 * \return The shortest distance from the object to the point. With an
1072 * invalid parameter, this function returns G_MAXDOUBLE.
1074 gdouble
o_path_shortest_distance (OBJECT
const *object
, gint x
, gint y
)
1076 PATH_SECTION
const *section
;
1077 gdouble shortest
= G_MAXDOUBLE
;
1078 int last_x
= 0, last_y
= 0;
1081 for (i
= 0; i
< object
->path
->num_sections
; i
++) {
1082 section
= &object
->path
->sections
[i
];
1083 switch (section
->code
) {
1086 /* TODO: Shortest distance to a besier section of the path.
1087 * For now, pretend it is a straight line. */
1090 shortest
= MIN(shortest
,
1091 o_line_shortest_distance_raw(last_x
, last_y
,
1092 section
->x3
, section
->y3
,
1094 last_x
= section
->x3
;
1095 last_y
= section
->y3
;
1099 case PATH_MOVETO_OPEN
:
1100 last_x
= section
->x3
;
1101 last_y
= section
->y3
;
1105 /* Need to consider the line back to the first point in the path */
1106 shortest
= MIN(shortest
,
1107 o_line_shortest_distance_raw(last_x
, last_y
,
1108 object
->path
->sections
[0].x3
,
1109 object
->path
->sections
[0].y3
,
1111 last_x
= object
->path
->sections
[0].x3
;
1112 last_y
= object
->path
->sections
[0].y3
;