1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 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
21 /*! \file o_line_basic.c
22 * \brief functions for the line object
30 #include "libgeda_priv.h"
32 /*! \brief Create and add line OBJECT to list.
33 * \par Function Description
34 * This function creates a new object representing a line.
36 * The line is described by its two ends - <B>x1</B>,<B>y1</B> and
37 * <B>x2</B>,<B>y2</B>.
38 * The <B>type</B> parameter must be equal to #OBJ_LINE.
39 * The <B>color</B> parameter corresponds to the color the box
42 * The #OBJECT structure is allocated with the #s_basic_new_object()
43 * function. The structure describing the line is allocated and
44 * initialized with the parameters given to the function.
46 * Both the line type and the filling type are set to default
47 * values : solid line type with a width of 0, and no filling.
48 * It can be changed after with the #o_set_line_options() and
49 * #o_set_fill_options().
51 * \param [in] toplevel The TOPLEVEL object.
52 * \param [in] color Circle line color.
53 * \param [in] x1 Upper x coordinate.
54 * \param [in] y1 Upper y coordinate.
55 * \param [in] x2 Lower x coordinate.
56 * \param [in] y2 Lower y coordinate.
57 * \return A pointer to the new end of the object list.
59 OBJECT
*o_line_new(TOPLEVEL
*toplevel
,
60 int color
, int x1
, int y1
, int x2
, int y2
)
64 /* create the object */
65 new_node
= s_basic_new_object(OBJ_LINE
, "line");
66 new_node
->color
= color
;
68 new_node
->line
= (LINE
*) g_malloc(sizeof(LINE
));
70 /* describe the line with its two ends */
71 new_node
->line
->x
[0] = x1
;
72 new_node
->line
->y
[0] = y1
;
73 new_node
->line
->x
[1] = x2
;
74 new_node
->line
->y
[1] = y2
;
76 /* line type and filling initialized to default */
77 o_set_line_options(toplevel
, new_node
,
78 DEFAULT_OBJECT_END
, TYPE_SOLID
, 0, -1, -1);
79 o_set_fill_options(toplevel
, new_node
,
80 FILLING_HOLLOW
, -1, -1, -1, -1, -1);
82 /* compute bounding box */
83 new_node
->w_bounds_valid_for
= NULL
;
88 /*! \brief Create a copy of a line.
89 * \par Function Description
90 * This function creates a verbatim copy of the
91 * object pointed by <B>o_current</B> describing a line.
93 * \param [in] toplevel The TOPLEVEL object.
94 * \param [in] o_current Line OBJECT to copy.
95 * \return The new OBJECT
97 OBJECT
*o_line_copy(TOPLEVEL
*toplevel
, OBJECT
*o_current
)
101 /* A new line object is created with #o_line_new().
102 * Values for its fields are default and need to be modified. */
103 new_obj
= o_line_new (toplevel
, o_current
->color
,
104 o_current
->line
->x
[0], o_current
->line
->y
[0],
105 o_current
->line
->x
[1], o_current
->line
->y
[1]);
108 * The coordinates of the ends of the new line are set with the ones
109 * of the original line. The two lines have the sale line type and
113 /* copy the line type and filling options */
114 o_set_line_options(toplevel
, new_obj
, o_current
->line_end
,
115 o_current
->line_type
, o_current
->line_width
,
116 o_current
->line_length
, o_current
->line_space
);
117 o_set_fill_options(toplevel
, new_obj
,
118 o_current
->fill_type
, o_current
->fill_width
,
119 o_current
->fill_pitch1
, o_current
->fill_angle1
,
120 o_current
->fill_pitch2
, o_current
->fill_angle2
);
122 /* calc the bounding box */
123 o_current
->w_bounds_valid_for
= NULL
;
125 /* new_obj->attribute = 0;*/
127 /* return the new tail of the object list */
131 /*! \brief Modify the description of a line OBJECT.
132 * \par Function Description
133 * This function modifies the coordinates of one of the two ends of
134 * the line described by <B>*object</B>. The new coordinates of this end,
135 * identified by <B>whichone</B>, are given by <B>x</B> and <B>y</B>
138 * The coordinates of the end of line is modified in the world
139 * coordinate system. Screen coordinates and boundings are then updated.
141 * \param [in] toplevel The TOPLEVEL object.
142 * \param [in,out] object Line OBJECT to modify.
143 * \param [in] x New x coordinate.
144 * \param [in] y New y coordinate.
145 * \param [in] whichone Which line parameter to modify.
147 * <B>whichone</B> can have the following values:
149 * <DT>*</DT><DD>LINE_END1
150 * <DT>*</DT><DD>LINE_END2
153 void o_line_modify(TOPLEVEL
*toplevel
, OBJECT
*object
,
154 int x
, int y
, int whichone
)
156 o_emit_pre_change_notify (toplevel
, object
);
158 /* change one of the end of the line */
161 object
->line
->x
[0] = x
;
162 object
->line
->y
[0] = y
;
166 object
->line
->x
[1] = x
;
167 object
->line
->y
[1] = y
;
174 /* recalculate the bounding box */
175 object
->w_bounds_valid_for
= NULL
;
176 o_emit_change_notify (toplevel
, object
);
179 /*! \brief Create line OBJECT from character string.
180 * \par Function Description
181 * This function creates a line OBJECT from the character string
182 * <B>*buf</B> the description of a box.
184 * The function returns a pointer on the new last element, that is
185 * the added line object.
187 * Depending on <B>*version</B>, the correct file format is considered.
188 * Currently two file format revisions are supported :
190 * <DT>*</DT><DD>the file format used until 20010704 release.
191 * <DT>*</DT><DD>the file format used for the releases after 20010704.
194 * \param [in] toplevel The TOPLEVEL object.
195 * \param [in] buf Character string with line description.
196 * \param [in] release_ver libgeda release version number.
197 * \param [in] fileformat_ver libgeda file format version number.
198 * \return A pointer to the new line object, or NULL on error.
200 OBJECT
*o_line_read (TOPLEVEL
*toplevel
, const char buf
[],
201 unsigned int release_ver
, unsigned int fileformat_ver
, GError
** err
)
207 int line_width
, line_space
, line_length
;
212 if (release_ver
<= VERSION_20000704
) {
214 * The old geda file format, i.e. releases 20000704 and older, does
215 * not handle the line type and the filling - here filling is irrelevant.
216 * They are set to default.
218 if (sscanf (buf
, "%c %d %d %d %d %d\n", &type
,
219 &x1
, &y1
, &x2
, &y2
, &color
) != 6) {
220 g_set_error(err
, EDA_ERROR
, EDA_ERROR_PARSE
, _("Failed to parse line object"));
226 line_type
= TYPE_SOLID
;
231 * The current line format to describe a line is a space separated
232 * list of characters and numbers in plain ASCII on a single line.
233 * The meaning of each item is described in the file format documentation.
235 if (sscanf (buf
, "%c %d %d %d %d %d %d %d %d %d %d\n", &type
,
236 &x1
, &y1
, &x2
, &y2
, &color
,
237 &line_width
, &line_end
, &line_type
, &line_length
, &line_space
) != 11) {
238 g_set_error(err
, EDA_ERROR
, EDA_ERROR_PARSE
, _("Failed to parse line object"));
244 * Null length line are not allowed. If such a line is detected a
247 * It also checks is the required color is valid.
249 if (x1
== x2
&& y1
== y2
) {
250 s_log_message (_("Found a zero length line [ %c %d %d %d %d %d ]\n"),
251 type
, x1
, y1
, x2
, y2
, color
);
254 if (color
< 0 || color
>= MAX_OBJECT_COLORS
) {
255 s_log_message (_("Found an invalid color [ %s ]\n"), buf
);
256 s_log_message (_("Setting color to default color\n"));
257 color
= DEFAULT_COLOR
;
261 * A line is internally described by its two ends. A new object is
262 * allocated, initialized and added to the list of objects. Its line
263 * type is set according to the values of the fields on the line.
265 /* create and add the line to the list */
266 new_obj
= o_line_new (toplevel
, color
, x1
, y1
, x2
, y2
);
267 /* set its line options */
268 o_set_line_options (toplevel
, new_obj
,
269 line_end
, line_type
, line_width
, line_length
,
271 /* filling is irrelevant for line, just set to default */
272 o_set_fill_options (toplevel
, new_obj
,
273 FILLING_HOLLOW
, -1, -1, -1, -1, -1);
278 /*! \brief Create a character string representation of a line OBJECT.
279 * \par Function Description
280 * The function formats a string in the buffer <B>*buff</B> to describe
281 * the box object <B>*object</B>.
282 * It follows the post-20000704 release file format that handle the
283 * line type and fill options - filling is irrelevant here.
285 * \param [in] object Line OBJECT to create string from.
286 * \return A pointer to the line OBJECT character string.
289 * Caller must g_free returned character string.
292 char *o_line_save(OBJECT
*object
)
294 g_return_val_if_fail (object
!= NULL
, NULL
);
295 g_return_val_if_fail (object
->line
!= NULL
, NULL
);
296 g_return_val_if_fail (object
->type
== OBJ_LINE
, NULL
);
298 return g_strdup_printf ("%c %d %d %d %d %d %d %d %d %d %d",
312 /*! \brief Translate a line position in WORLD coordinates by a delta.
313 * \par Function Description
314 * This function applies a translation of (<B>x1</B>,<B>y1</B>) to the line
315 * described by <B>*object</B>. <B>x1</B> and <B>y1</B> are in world unit.
317 * \param [in,out] object Line OBJECT to translate.
318 * \param [in] dx x distance to move.
319 * \param [in] dy y distance to move.
321 void o_line_translate_world(OBJECT
*object
, int dx
, int dy
)
323 g_return_if_fail (object
!= NULL
);
324 g_return_if_fail (object
->line
!= NULL
);
325 g_return_if_fail (object
->type
== OBJ_LINE
);
327 /* Update world coords */
328 object
->line
->x
[0] = object
->line
->x
[0] + dx
;
329 object
->line
->y
[0] = object
->line
->y
[0] + dy
;
330 object
->line
->x
[1] = object
->line
->x
[1] + dx
;
331 object
->line
->y
[1] = object
->line
->y
[1] + dy
;
333 /* Update bounding box */
334 object
->w_bounds_valid_for
= NULL
;
337 /*! \brief Rotate Line OBJECT using WORLD coordinates.
338 * \par Function Description
339 * This function rotates the line described by
340 * <B>*object</B> around the (<B>world_centerx</B>,<B>world_centery</B>)
341 * point by <B>angle</B> degrees.
342 * The center of rotation is in world units.
344 * \param [in] toplevel The TOPLEVEL object.
345 * \param [in] world_centerx Rotation center x coordinate in WORLD units.
346 * \param [in] world_centery Rotation center y coordinate in WORLD units.
347 * \param [in] angle Rotation angle in degrees (See note below).
348 * \param [in,out] object Line OBJECT to rotate.
350 void o_line_rotate_world(TOPLEVEL
*toplevel
,
351 int world_centerx
, int world_centery
, int angle
,
356 g_return_if_fail (object
!= NULL
);
357 g_return_if_fail (object
->line
!= NULL
);
358 g_return_if_fail (object
->type
== OBJ_LINE
);
363 /* angle must be positive */
364 if(angle
< 0) angle
= -angle
;
365 /* angle must be 90 multiple or no rotation performed */
366 if((angle
% 90) != 0) return;
369 * The center of rotation (<B>world_centerx</B>,<B>world_centery</B>)
370 * is translated to the origin. The rotation of the two ends of
371 * the line is performed. FInally, the rotated line is translated
372 * back to its previous location.
374 /* translate object to origin */
375 o_line_translate_world(object
, -world_centerx
, -world_centery
);
377 /* rotate line end 1 */
378 rotate_point_90(object
->line
->x
[0], object
->line
->y
[0], angle
,
381 object
->line
->x
[0] = newx
;
382 object
->line
->y
[0] = newy
;
384 /* rotate line end 2 */
385 rotate_point_90(object
->line
->x
[1], object
->line
->y
[1], angle
,
388 object
->line
->x
[1] = newx
;
389 object
->line
->y
[1] = newy
;
391 /* translate object back to normal position */
392 o_line_translate_world(object
, world_centerx
, world_centery
);
396 /*! \brief Mirror a line using WORLD coordinates.
397 * \par Function Description
398 * This function mirrors the line from the point
399 * (<B>world_centerx</B>,<B>world_centery</B>) in world unit.
401 * The line if first translated to the origin, then mirrored
402 * and finally translated back at its previous position.
404 * \param [in] toplevel The TOPLEVEL object.
405 * \param [in] world_centerx Origin x coordinate in WORLD units.
406 * \param [in] world_centery Origin y coordinate in WORLD units.
407 * \param [in,out] object Line OBJECT to mirror.
409 void o_line_mirror_world(TOPLEVEL
*toplevel
, int world_centerx
,
410 int world_centery
, OBJECT
*object
)
412 g_return_if_fail (object
!= NULL
);
413 g_return_if_fail (object
->line
!= NULL
);
414 g_return_if_fail (object
->type
== OBJ_LINE
);
416 /* translate object to origin */
417 o_line_translate_world(object
, -world_centerx
, -world_centery
);
419 /* mirror the line ends */
420 object
->line
->x
[0] = -object
->line
->x
[0];
421 object
->line
->x
[1] = -object
->line
->x
[1];
423 /* translate back in position */
424 o_line_translate_world(object
, world_centerx
, world_centery
);
428 /*! \brief Get line bounding rectangle in WORLD coordinates.
429 * \par Function Description
430 * This function sets the <B>left</B>, <B>top</B>, <B>right</B> and
431 * <B>bottom</B> parameters to the boundings of the line object described
432 * in <B>*line</B> in world units.
434 * \param [in] toplevel The TOPLEVEL object.
435 * \param [in] object Line OBJECT to read coordinates from.
436 * \param [out] left Left line coordinate in WORLD units.
437 * \param [out] top Top line coordinate in WORLD units.
438 * \param [out] right Right line coordinate in WORLD units.
439 * \param [out] bottom Bottom line coordinate in WORLD units.
441 void world_get_line_bounds(TOPLEVEL
*toplevel
, OBJECT
*object
,
442 int *left
, int *top
, int *right
, int *bottom
)
446 expand
= ceil (0.5 * G_SQRT2
* object
->line_width
);
448 *left
= min( object
->line
->x
[0], object
->line
->x
[1] );
449 *top
= min( object
->line
->y
[0], object
->line
->y
[1] );
450 *right
= max( object
->line
->x
[0], object
->line
->x
[1] );
451 *bottom
= max( object
->line
->y
[0], object
->line
->y
[1] );
453 /* This isn't strictly correct, but a 1st order approximation */
460 /*! \brief get the position of the first line point
461 * \par Function Description
462 * This function gets the position of the first point of a line object.
464 * \param [in] object The object to get the position.
465 * \param [out] x pointer to the x-position
466 * \param [out] y pointer to the y-position
467 * \return TRUE if successfully determined the position, FALSE otherwise
469 gboolean
o_line_get_position (OBJECT
*object
, gint
*x
, gint
*y
)
471 g_return_val_if_fail (object
!= NULL
, FALSE
);
472 g_return_val_if_fail (object
->type
== OBJ_LINE
, FALSE
);
473 g_return_val_if_fail (object
->line
!= NULL
, FALSE
);
476 *x
= object
->line
->x
[0];
480 *y
= object
->line
->y
[0];
486 /*! \brief calculate the length of a line object
487 * \par Function Description
488 * This function calculates the length of a line object
490 * \param [in] object a line OBJECT
491 * \return The length of the line
493 double o_line_length(OBJECT
*object
)
502 dx
= object
->line
->x
[0]-object
->line
->x
[1];
503 dy
= object
->line
->y
[0]-object
->line
->y
[1];
505 length
= hypot(dx
, dy
);
510 /*! \brief Calculates the distance between the given point and the closest
511 * point on the given line segment.
513 * If the closest point on the line resides beyond the line segment's
514 * end point, this function returns the distance from the given point to the
517 * If the line represents a single point (the endpoints are the same), this
518 * function calcualtes the distance to that point.
520 * \param [in] toplevel The TOPLEVEL object.
521 * \param [in] object The line OBJECT.
522 * \param [in] x The x coordinate of the given point.
523 * \param [in] y The y coordinate of the given point.
524 * \param [in] force_solid If true, force treating the object as solid.
525 * \return The shortest distance from the object to the point. With an
526 * invalid parameter, this function returns G_MAXDOUBLE.
528 double o_line_shortest_distance (TOPLEVEL
*toplevel
, OBJECT
*object
,
529 int x
, int y
, int force_solid
)
531 return m_line_shortest_distance (object
->line
, x
, y
);