Stop pretending to use an explicit printing origin.
[geda-gaf/berndj.git] / libgeda / src / o_path_basic.c
blob9c4084bf7ac7c6c65829d85bf85ff450b7143ad2
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
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
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,
37 enum grip_t whichone,
38 void *userdata),
39 void *userdata);
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,
49 int fill_width,
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
61 * will be drawn with.
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
66 * to the function.
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)
85 OBJECT *new_node;
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);
106 return 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>
115 * parameter.
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)
123 OBJECT *new_obj;
124 char *path_string;
125 int color;
127 if (o_current->saved_color == -1) {
128 color = o_current->color;
129 } else {
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 */
150 return new_obj;
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
160 * before the call.
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 :
165 * <DL>
166 * <DT>*</DT><DD>the file format used until 20010704 release.
167 * <DT>*</DT><DD>the file format used for the releases after 20010704.
168 * </DL>
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)
181 OBJECT *new_obj;
182 char type;
183 int color;
184 int line_width, line_space, line_length;
185 int line_end;
186 int line_type;
187 int fill_type, fill_width, angle1, pitch1, angle2, pitch2;
188 int num_lines = 0;
189 int i;
190 char *string;
191 GString *pathstr;
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"));
210 color = WHITE;
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++) {
221 gchar *line;
223 line = s_textbuffer_next_line (tb);
225 if (line != NULL) {
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);
236 g_free (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);
245 return new_obj;
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.
257 * \note
258 * Caller must g_free returned character string.
261 char *o_path_save (OBJECT *object)
263 int color;
264 int line_width, line_space, line_length;
265 char *buf;
266 int num_lines;
267 OBJECT_END line_end;
268 OBJECT_TYPE line_type;
269 OBJECT_FILLING fill_type;
270 int fill_width, angle1, pitch1, angle2, pitch2;
271 char *path_string;
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;
291 } else {
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);
304 return buf;
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;
319 int i;
321 for (i = 0; i < object->path->num_sections; i++) {
322 section = &object->path->sections[i];
324 switch (section->code) {
325 case PATH_CURVETO:
326 section->x1 += dx;
327 section->y1 += dy;
328 section->x2 += dx;
329 section->y2 += dy;
330 /* Fall through */
331 case PATH_MOVETO:
332 case PATH_MOVETO_OPEN:
333 case PATH_LINETO:
334 section->x3 += dx;
335 section->y3 += dy;
336 break;
337 case PATH_END:
338 break;
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,
360 OBJECT *object)
362 PATH_SECTION *section;
363 int i;
365 for (i = 0; i < object->path->num_sections; i++) {
366 section = &object->path->sections[i];
368 switch (section->code) {
369 case PATH_CURVETO:
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, &section->x1, &section->y1);
374 rotate_point_90 (section->x2, section->y2, angle, &section->x2, &section->y2);
375 section->x1 += world_centerx; section->y1 += world_centery;
376 section->x2 += world_centerx; section->y2 += world_centery;
377 /* Fall through */
378 case PATH_MOVETO:
379 case PATH_MOVETO_OPEN:
380 case PATH_LINETO:
381 /* Destination point grip */
382 section->x3 -= world_centerx; section->y3 -= world_centery;
383 rotate_point_90 (section->x3, section->y3, angle, &section->x3, &section->y3);
384 section->x3 += world_centerx; section->y3 += world_centery;
385 break;
386 case PATH_END:
387 break;
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;
406 int i;
408 for (i = 0; i < object->path->num_sections; i++) {
409 section = &object->path->sections[i];
411 switch (section->code) {
412 case PATH_CURVETO:
413 /* Two control point grips */
414 section->x1 = 2 * world_centerx - section->x1;
415 section->x2 = 2 * world_centerx - section->x2;
416 /* Fall through */
417 case PATH_MOVETO:
418 case PATH_MOVETO_OPEN:
419 case PATH_LINETO:
420 /* Destination point grip */
421 section->x3 = 2 * world_centerx - section->x3;
422 break;
423 case PATH_END:
424 break;
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) {
443 return;
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;
475 int halfwidth;
476 int i;
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) {
483 case PATH_CURVETO:
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;
490 found_bound = TRUE;
491 *left = MIN (*left, section->x2);
492 *top = MIN (*top, section->y2);
493 *right = MAX (*right, section->x2);
494 *bottom = MAX (*bottom, section->y2);
495 /* Fall through */
496 case PATH_MOVETO:
497 case PATH_MOVETO_OPEN:
498 case PATH_LINETO:
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;
503 found_bound = TRUE;
504 break;
505 case PATH_END:
506 break;
510 if (found_bound) {
511 /* This isn't strictly correct, but a 1st order approximation */
512 halfwidth = object->line_width / 2;
513 *left -= halfwidth;
514 *top -= halfwidth;
515 *right += halfwidth;
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,
524 void *userdata),
525 void *userdata)
527 int i;
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];
532 int whichone;
534 /* Encode the section in the grip number. */
535 whichone = GRIP_FIRST_OPAQUE + i*3;
537 switch (section->code) {
538 case PATH_CURVETO:
539 if ((*fn)(o, section->x1, section->y1, whichone + 0, userdata)) return;
540 if ((*fn)(o, section->x2, section->y2, whichone + 1, userdata)) return;
541 /* Fall through */
542 case PATH_MOVETO:
543 case PATH_MOVETO_OPEN:
544 case PATH_LINETO:
545 if ((*fn)(o, section->x3, section->y3, whichone + 2, userdata)) return;
546 break;
547 case PATH_END:
548 break;
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;
571 switch (whichone) {
572 PATH_SECTION *section;
573 int i, sub;
575 case GRIP_NONE:
576 s_path_moveto(o->path, x, y);
577 retval = GRIP_PATH_NEXT_SECTION;
578 break;
580 case GRIP_PATH_NEXT_SECTION:
581 s_path_lineto(o->path, x, y);
582 retval = GRIP_PATH_NEXT_SECTION;
583 break;
585 case GRIP_PATH_LAST_SECTION:
586 i = o->path->num_sections - 1;
587 g_return_val_if_fail(i >= 0, GRIP_NONE);
588 switch (i) {
589 case 0:
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);
592 default:
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];
602 switch (whichone) {
603 case GRIP_PATH_CONTROL_1:
604 section->x1 = x;
605 section->y1 = y;
606 retval = GRIP_PATH_CONTROL_2;
607 break;
608 case GRIP_PATH_CONTROL_2:
609 section->x2 = x;
610 section->y2 = y;
611 retval = GRIP_PATH_NEXT_SECTION;
612 break;
614 break;
616 default:
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];
621 switch (sub) {
622 case 0:
623 section->x1 = x;
624 section->y1 = y;
625 break;
626 case 1:
627 section->x2 = x;
628 section->y2 = y;
629 break;
630 case 2:
631 section->x3 = x;
632 section->y3 = y;
633 break;
635 switch (section->code) {
636 case PATH_CURVETO:
637 retval = whichone + 1;
638 break;
639 case PATH_MOVETO:
640 case PATH_MOVETO_OPEN:
641 case PATH_LINETO:
642 /* The next grip is just the first grip of the next section. */
643 retval = GRIP_FIRST_OPAQUE + (i+1)*3;
644 break;
645 case PATH_END:
646 retval = GRIP_NONE;
647 break;
649 if (retval >= GRIP_FIRST_OPAQUE + o->path->num_sections*3) {
650 /* We fell off the end of the path. */
651 retval = GRIP_NONE;
653 break;
656 o_path_recalc(o);
658 return retval;
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)
678 int i;
680 for (i = 0; i < path->num_sections; i++) {
681 PATH_SECTION *section = &path->sections[i];
683 if (i > 0)
684 fprintf (fp, " ");
686 switch (section->code) {
687 case PATH_MOVETO:
688 fprintf (fp, "closepath ");
689 /* Fall through */
690 case PATH_MOVETO_OPEN:
691 fprintf(fp, "%i %i moveto", section->x3, section->y3);
692 break;
693 case PATH_CURVETO:
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);
698 break;
699 case PATH_LINETO:
700 fprintf(fp, "%i %i lineto", section->x3, section->y3);
701 break;
702 case PATH_END:
703 fprintf (fp, "closepath ");
704 break;
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,
768 int space)
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,
789 int space)
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,
814 int fill_width,
815 int angle1, int pitch1, int angle2, int pitch2)
817 int i;
819 for (i = 0; i < path->num_sections; i++) {
820 PATH_SECTION *section = &path->sections[i];
822 if (i > 0)
823 fprintf (fp, " ");
825 switch (section->code) {
826 case PATH_MOVETO:
827 fprintf (fp, "closepath ");
828 /* Fall through */
829 case PATH_MOVETO_OPEN:
830 fprintf(fp, "%i %i moveto", section->x3, section->y3);
831 break;
832 case PATH_CURVETO:
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);
837 break;
838 case PATH_LINETO:
839 fprintf(fp, "%i %i lineto", section->x3, section->y3);
840 break;
841 case PATH_END:
842 fprintf (fp, "closepath ");
843 break;
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
856 * has to be hatched.
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,
873 int fill_width,
874 int angle1, int pitch1, int angle2, int pitch2)
876 GArray *lines;
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
896 * not allowed.
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,
909 int fill_width,
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;
934 /*! \note
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
942 * set to -1.
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
946 * case.
948 line_width = o_current->line_width;
950 if (line_width <= 2) {
951 if (toplevel->line_style == THICK) {
952 line_width = LINE_WIDTH;
953 } else {
954 line_width=2;
957 length = o_current->line_length;
958 space = o_current->line_space;
960 switch(o_current->line_type) {
961 case TYPE_SOLID:
962 length = -1; space = -1;
963 outl_func = o_path_print_solid;
964 break;
966 case TYPE_DOTTED:
967 length = -1;
968 outl_func = o_path_print_dotted;
969 break;
971 case TYPE_DASHED:
972 outl_func = o_path_print_dashed;
973 break;
975 case TYPE_CENTER:
976 outl_func = o_path_print_center;
977 break;
979 case TYPE_PHANTOM:
980 outl_func = o_path_print_phantom;
981 break;
983 case TYPE_ERASE:
984 /* Unused for now, print it solid */
985 length = -1; space = -1;
986 outl_func = o_path_print_solid;
987 break;
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);
1002 /*! \note
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) {
1021 case FILLING_FILL:
1022 angle1 = -1; pitch1 = 1;
1023 angle2 = -1; pitch2 = 1;
1024 fill_width = -1;
1025 fill_func = o_path_print_filled;
1026 break;
1028 case FILLING_MESH:
1029 fill_func = o_path_print_mesh;
1030 break;
1032 case FILLING_HATCH:
1033 angle2 = -1; pitch2 = 1;
1034 fill_func = o_path_print_hatch;
1035 break;
1037 case FILLING_VOID:
1038 /* Unused for now, print it filled */
1039 angle1 = -1; pitch1 = 1;
1040 angle2 = -1; pitch2 = 1;
1041 fill_width = -1;
1042 fill_func = o_path_print_filled;
1043 break;
1045 case FILLING_HOLLOW:
1046 /* nop */
1047 break;
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;
1079 int i;
1081 for (i = 0; i < object->path->num_sections; i++) {
1082 section = &object->path->sections[i];
1083 switch (section->code) {
1085 case PATH_CURVETO:
1086 /* TODO: Shortest distance to a besier section of the path.
1087 * For now, pretend it is a straight line. */
1088 /* Fall through */
1089 case PATH_LINETO:
1090 shortest = MIN(shortest,
1091 o_line_shortest_distance_raw(last_x, last_y,
1092 section->x3, section->y3,
1093 x, y));
1094 last_x = section->x3;
1095 last_y = section->y3;
1096 break;
1098 case PATH_MOVETO:
1099 case PATH_MOVETO_OPEN:
1100 last_x = section->x3;
1101 last_y = section->y3;
1102 break;
1104 case PATH_END:
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,
1110 x, y));
1111 last_x = object->path->sections[0].x3;
1112 last_y = object->path->sections[0].y3;
1113 break;
1117 return shortest;