missing NULL terminator in set_config_x
[geda-gaf.git] / libgeda / src / o_line_basic.c
blobe414f309de3b746e272b67fa500b47f5b4c1d6bc
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
25 #include <config.h>
27 #include <stdio.h>
28 #include <math.h>
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
40 * will be drawn with.
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)
62 OBJECT *new_node;
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;
85 return new_node;
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)
99 OBJECT *new_obj;
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
110 * filling options.
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 */
128 return new_obj;
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>
136 * in world unit.
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:
148 * <DL>
149 * <DT>*</DT><DD>LINE_END1
150 * <DT>*</DT><DD>LINE_END2
151 * </DL>
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 */
159 switch (whichone) {
160 case LINE_END1:
161 object->line->x[0] = x;
162 object->line->y[0] = y;
163 break;
165 case LINE_END2:
166 object->line->x[1] = x;
167 object->line->y[1] = y;
168 break;
170 default:
171 return;
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 :
189 * <DL>
190 * <DT>*</DT><DD>the file format used until 20010704 release.
191 * <DT>*</DT><DD>the file format used for the releases after 20010704.
192 * </DL>
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)
203 OBJECT *new_obj;
204 char type;
205 int x1, y1;
206 int x2, y2;
207 int line_width, line_space, line_length;
208 int line_end;
209 int line_type;
210 int color;
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"));
221 return NULL;
224 line_width = 0;
225 line_end = END_NONE;
226 line_type = TYPE_SOLID;
227 line_length= -1;
228 line_space = -1;
229 } else {
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"));
239 return NULL;
244 * Null length line are not allowed. If such a line is detected a
245 * message is issued.
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,
270 line_space);
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);
275 return new_obj;
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.
288 * \note
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",
299 OBJ_LINE,
300 object->line->x[0],
301 object->line->y[0],
302 object->line->x[1],
303 object->line->y[1],
304 object->color,
305 object->line_width,
306 object->line_end,
307 object->line_type,
308 object->line_length,
309 object->line_space);
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,
352 OBJECT *object)
354 int newx, newy;
356 g_return_if_fail (object != NULL);
357 g_return_if_fail (object->line != NULL);
358 g_return_if_fail (object->type == OBJ_LINE);
360 if (angle == 0)
361 return;
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,
379 &newx, &newy);
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,
386 &newx, &newy);
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)
444 int expand;
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 */
454 *left -= expand;
455 *top -= expand;
456 *right += expand;
457 *bottom += expand;
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);
475 if (x != NULL) {
476 *x = object->line->x[0];
479 if (y != NULL) {
480 *y = object->line->y[0];
483 return TRUE;
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)
495 double length;
496 double dx, dy;
498 if (!object->line) {
499 return 0.0;
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);
507 return(length);
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
515 * closest end point.
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);