Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / libgeda / src / o_basic.c
blobc8a4e6cf8896f754e16b379d84564f45352a283c
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
21 /*! \file o_basic.c
22 * \brief functions for the basic object type
24 * This file contains the code used to handle OBJECTs (st_object).
25 * The object is the basic type of all elements stored in schematic
26 * and symbol files.
28 * The object be extended to become concrete objects like a line,
29 * a pin, text, a circle or a picture. These extentions are substructures
30 * in the object struct.
31 * The subobjects are picture (st_picture), path (st_path), arcs (st_arc),
32 * a line (st_line), box (st_box), circle (st_circle), text (st_text) and
33 * a complex type (st_complex).
35 * Pins, nets and busses are just a kind of a line.
37 * The complex object can carry many primary objects. If the complex
38 * object is a symbol, then the complex symbol contains all the pins,
39 * the text and the graphics.
41 * \image html o_object_relations.png
42 * \image latex o_object_relations.pdf "object relations" width=14cm
45 #include <config.h>
47 #include <stdio.h>
49 /* instrumentation code */
50 #if 0
51 #include <sys/time.h>
52 #include <unistd.h>
53 #endif
55 #include "libgeda_priv.h"
57 #ifdef HAVE_LIBDMALLOC
58 #include <dmalloc.h>
59 #endif
61 /*! Default setting for object selection function. */
62 void (*select_func)() = NULL;
65 /*! \brief Check if point is inside a region
66 * \par Function Description
67 * This function takes a rectangular region and a point. It will check
68 * if the point is located in the region or not.
70 * \param [in] xmin Smaller x coordinate of the region.
71 * \param [in] ymin Smaller y coordinate of the region.
72 * \param [in] xmax Larger x coordinate of the region.
73 * \param [in] ymax Larger y coordinate of the region.
74 * \param [in] x x coordinate of the point to check.
75 * \param [in] y y coordinate of the point to check.
76 * \return 1 if the point is inside the region, 0 otherwise.
78 int inside_region(int xmin, int ymin, int xmax, int ymax, int x, int y)
80 return ((x >= xmin && x <= xmax && y >= ymin && y <= ymax) ? 1 : 0);
83 /*! \brief Recalculate position of the given object.
84 * \par Function Description
85 * This function will take an object and recalculate its
86 * position on the screen.
88 * \param [in] toplevel The TOPLEVEL object.
89 * \param [in,out] o_current OBJECT to recalculate.
92 void o_recalc_single_object(TOPLEVEL *toplevel, OBJECT *o_current)
94 if (o_current != NULL) {
95 switch(o_current->type) {
97 case(OBJ_LINE):
98 o_line_recalc(toplevel, o_current);
99 break;
101 case(OBJ_NET):
102 o_net_recalc(toplevel, o_current);
103 break;
105 case(OBJ_BUS):
106 o_bus_recalc(toplevel, o_current);
107 break;
109 case(OBJ_BOX):
110 o_box_recalc(toplevel, o_current);
111 break;
113 case(OBJ_PATH):
114 o_path_recalc(toplevel, o_current);
115 break;
117 case(OBJ_PICTURE):
118 o_picture_recalc(toplevel, o_current);
119 break;
121 case(OBJ_CIRCLE):
122 o_circle_recalc(toplevel, o_current);
123 break;
125 case(OBJ_COMPLEX):
126 case(OBJ_PLACEHOLDER):
127 o_complex_recalc(toplevel, o_current);
128 break;
130 case(OBJ_PIN):
131 o_pin_recalc(toplevel, o_current);
132 break;
134 case(OBJ_ARC):
135 o_arc_recalc(toplevel, o_current);
136 break;
138 case(OBJ_TEXT):
139 o_text_recalc(toplevel, o_current);
140 break;
146 /*! \brief Recalculate position of a list (GList) of objects.
147 * \par Function Description
148 * This function will take a list (GList) of objects and recalculate their
149 * positions on the screen.
151 * \param [in] toplevel The TOPLEVEL object.
152 * \param [in,out] object_glist OBJECT list to recalculate.
155 void
156 o_recalc_object_glist(TOPLEVEL *toplevel, GList *object_glist)
158 GList *list = object_glist;
159 OBJECT *o_current;
161 while (list != NULL) {
162 o_current = (OBJECT *) list->data;
163 o_recalc_single_object(toplevel, o_current);
164 list = g_list_next(list);
169 /*! \brief Set an #OBJECT's line options.
170 * \par Function Description
171 * This function allows a line's end, type, width, length and space to be set.
172 * See #OBJECT_END and #OBJECT_TYPE for information on valid
173 * object end and type values.
175 * \param [in] toplevel The TOPLEVEL object.
176 * \param [in,out] o_current OBJECT to set line options on.
177 * \param [in] end An OBJECT_END.
178 * \param [in] type An OBJECT_TYPE.
179 * \param [in] width Line width.
180 * \param [in] length Line length.
181 * \param [in] space Spacing between dashes/dots. Cannot be negative.
183 * \todo Make space an unsigned int and check for a max value instead.
184 * If a max value is not required, then it would simplify the code.
186 void o_set_line_options(TOPLEVEL *toplevel, OBJECT *o_current,
187 OBJECT_END end, OBJECT_TYPE type,
188 int width, int length, int space)
190 if(o_current == NULL) {
191 return;
194 /* do some error checking / correcting */
195 switch(type) {
196 case(TYPE_DOTTED):
197 if (space < 1) {
198 space = 100;
199 s_log_message (_("Invalid space specified, setting to 100\n"));
201 break;
202 case(TYPE_DASHED):
203 case(TYPE_CENTER):
204 case(TYPE_PHANTOM):
205 if (length < 1) {
206 length = 100;
207 s_log_message (_("Invalid length specified, setting to 100\n"));
209 if (space < 1) {
210 space = 100;
211 s_log_message (_("Invalid space specified, setting to 100\n"));
213 break;
214 default:
216 break;
219 o_current->line_width = width;
220 o_current->line_end = end;
221 o_current->line_type = type;
223 o_current->line_length = length;
224 o_current->line_space = space;
226 /* Recalculate the object's bounding box */
227 o_recalc_single_object( toplevel, o_current );
230 /*! \brief get #OBJECT's line properties.
231 * \par Function Description
232 * This function get's the #OBJECT's line options.
233 * See #OBJECT_END and #OBJECT_TYPE for information on valid
234 * object end and type values.
236 * \param [in] object OBJECT to read the properties
237 * \param [out] end An OBJECT_END.
238 * \param [out] type An OBJECT_TYPE.
239 * \param [out] width Line width.
240 * \param [out] length Line length.
241 * \param [out] space Spacing between dashes/dots.
242 * \return TRUE on succes, FALSE otherwise
245 gboolean o_get_line_options(OBJECT *object,
246 OBJECT_END *end, OBJECT_TYPE *type,
247 int *width, int *length, int *space)
249 if (object->type != OBJ_LINE
250 && object->type != OBJ_ARC
251 && object->type != OBJ_BOX
252 && object->type != OBJ_CIRCLE
253 && object->type != OBJ_PATH)
254 return FALSE;
256 *end = object->line_end;
257 *type = object->line_type;
258 *width = object->line_width;
259 *length = object->line_length;
260 *space = object->line_space;
262 return TRUE;
265 /*! \brief Set #OBJECT's fill options.
266 * \par Function Description
267 * This function allows an #OBJECT's fill options to be configured.
268 * See #OBJECT_FILLING for information on valid fill types.
270 * \param [in] toplevel The TOPLEVEL object.
271 * \param [in,out] o_current OBJECT to be updated.
272 * \param [in] type OBJECT_FILLING type.
273 * \param [in] width fill width.
274 * \param [in] pitch1 cross hatch line distance
275 * \param [in] angle1 cross hatch angle
276 * \param [in] pitch2 cross hatch line distance
277 * \param [in] angle2 cross hatch angle
280 void o_set_fill_options(TOPLEVEL *toplevel, OBJECT *o_current,
281 OBJECT_FILLING type, int width,
282 int pitch1, int angle1,
283 int pitch2, int angle2)
285 if(o_current == NULL) {
286 return;
289 o_current->fill_type = type;
290 o_current->fill_width = width;
292 o_current->fill_pitch1 = pitch1;
293 o_current->fill_angle1 = angle1;
295 o_current->fill_pitch2 = pitch2;
296 o_current->fill_angle2 = angle2;
300 /*! \brief get #OBJECT's fill properties.
301 * \par Function Description
302 * This function get's the #OBJECT's fill options.
303 * See #OBJECT_FILLING for information on valid fill types.
305 * \param [in] object OBJECT to read the properties
306 * \param [out] type OBJECT_FILLING type
307 * \param [out] width fill width.
308 * \param [out] pitch1 cross hatch line distance
309 * \param [out] angle1 cross hatch angle
310 * \param [out] pitch2 cross hatch line distance
311 * \param [out] angle2 cross hatch angle
312 * \return TRUE on succes, FALSE otherwise
315 gboolean o_get_fill_options(OBJECT *object,
316 OBJECT_FILLING *type, int *width,
317 int *pitch1, int *angle1,
318 int *pitch2, int *angle2)
320 if (object->type != OBJ_BOX
321 && object->type != OBJ_CIRCLE
322 && object->type != OBJ_PATH)
323 return FALSE;
325 *type = object->fill_type;
326 *width = object->fill_width;
327 *pitch1 = object->fill_pitch1;
328 *angle1 = object->fill_angle1;
329 *pitch2 = object->fill_pitch2;
330 *angle2 = object->fill_angle2;
332 return TRUE;
335 /*! \brief get the base position of an object
336 * \par Function Description
337 * This function gets the position of an object in world coordinates.
339 * \param [in] toplevel The toplevel environment.
340 * \param [out] x pointer to the x-position
341 * \param [out] y pointer to the y-position
342 * \param [in] object The object to get the position.
343 * \return TRUE if successfully determined the position, FALSE otherwise
345 gboolean o_get_position (TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *object)
347 gboolean (*func) (TOPLEVEL*, int*, int*, OBJECT*) = NULL;
349 switch (object->type) {
350 case OBJ_LINE: func = o_line_get_position; break;
351 case OBJ_NET: func = o_net_get_position; break;
352 case OBJ_BUS: func = o_bus_get_position; break;
353 case OBJ_BOX: func = o_box_get_position; break;
354 case OBJ_PICTURE: func = o_picture_get_position; break;
355 case OBJ_CIRCLE: func = o_circle_get_position; break;
356 case OBJ_PLACEHOLDER:
357 case OBJ_COMPLEX: func = o_complex_get_position; break;
358 case OBJ_TEXT: func = o_text_get_position; break;
359 case OBJ_PATH: func = o_path_get_position; break;
360 case OBJ_PIN: func = o_pin_get_position; break;
361 case OBJ_ARC: func = o_arc_get_position; break;
362 default:
363 g_critical ("o_get_position: object %p has bad type '%c'\n",
364 object, object->type);
367 if (func != NULL) {
368 return (*func) (toplevel, x, y, object);
370 return FALSE;
374 /*! \brief Translates an object in world coordinates
375 * \par Function Description
376 * This function translates the object <B>object</B> by
377 * <B>dx</B> and <B>dy</B>.
379 * \param [in] toplevel The toplevel environment.
380 * \param [in] dx Amount to horizontally translate object
381 * \param [in] dy Amount to vertically translate object
382 * \param [in] object The object to translate.
384 void o_translate_world (TOPLEVEL *toplevel, gint dx, gint dy, OBJECT *object)
386 void (*func) (TOPLEVEL*, int, int, OBJECT*) = NULL;
388 switch (object->type) {
389 case OBJ_LINE: func = o_line_translate_world; break;
390 case OBJ_NET: func = o_net_translate_world; break;
391 case OBJ_BUS: func = o_bus_translate_world; break;
392 case OBJ_BOX: func = o_box_translate_world; break;
393 case OBJ_PICTURE: func = o_picture_translate_world; break;
394 case OBJ_CIRCLE: func = o_circle_translate_world; break;
395 case OBJ_PLACEHOLDER:
396 case OBJ_COMPLEX: func = o_complex_translate_world; break;
397 case OBJ_TEXT: func = o_text_translate_world; break;
398 case OBJ_PATH: func = o_path_translate_world; break;
399 case OBJ_PIN: func = o_pin_translate_world; break;
400 case OBJ_ARC: func = o_arc_translate_world; break;
401 default:
402 g_critical ("o_translate_world: object %p has bad type '%c'\n",
403 object, object->type);
406 if (func != NULL) {
407 (*func) (toplevel, dx, dy, object);
412 /*! \brief Rotates an object in world coordinates
413 * \par Function Description
414 * This function rotates the object <B>object</B> about the coordinates
415 * <B>world_centerx</B> and <B>world_centery</B>, by <B>angle</B>degrees.
417 * \param [in] toplevel The toplevel environment.
418 * \param [in] world_centerx X coordinate of rotation center (world coords)
419 * \param [in] world_centery Y coordinate of rotation center (world coords)
420 * \param [in] angle Angle of rotation (degrees)
421 * \param [in] object The object to rotate.
423 void o_rotate_world (TOPLEVEL *toplevel, int world_centerx, int world_centery, int angle, OBJECT *object)
425 void (*func) (TOPLEVEL*, int, int, int, OBJECT*) = NULL;
427 switch (object->type) {
428 case OBJ_LINE: func = o_line_rotate_world; break;
429 case OBJ_NET: func = o_net_rotate_world; break;
430 case OBJ_BUS: func = o_bus_rotate_world; break;
431 case OBJ_BOX: func = o_box_rotate_world; break;
432 case OBJ_PICTURE: func = o_picture_rotate_world; break;
433 case OBJ_CIRCLE: func = o_circle_rotate_world; break;
434 case OBJ_PLACEHOLDER:
435 case OBJ_COMPLEX: func = o_complex_rotate_world; break;
436 case OBJ_TEXT: func = o_text_rotate_world; break;
437 case OBJ_PATH: func = o_path_rotate_world; break;
438 case OBJ_PIN: func = o_pin_rotate_world; break;
439 case OBJ_ARC: func = o_arc_rotate_world; break;
440 default:
441 g_critical ("o_rotate_world: object %p has bad type '%c'\n",
442 object, object->type);
445 if (func != NULL) {
446 (*func) (toplevel, world_centerx, world_centery, angle, object);
451 /*! \brief Mirrors an object in world coordinates
452 * \par Function Description
453 * This function mirrors an object about the point
454 * (<B>world_centerx</B>,<B>world_centery</B>) in world units.
456 * \param [in] toplevel The TOPLEVEL object.
457 * \param [in] world_centerx Origin x coordinate in WORLD units.
458 * \param [in] world_centery Origin y coordinate in WORLD units.
459 * \param [in,out] object The OBJECT to mirror.
461 void o_mirror_world (TOPLEVEL *toplevel, int world_centerx, int world_centery, OBJECT *object)
463 void (*func) (TOPLEVEL*, int, int, OBJECT*) = NULL;
465 switch (object->type) {
466 case OBJ_LINE: func = o_line_mirror_world; break;
467 case OBJ_NET: func = o_net_mirror_world; break;
468 case OBJ_BUS: func = o_bus_mirror_world; break;
469 case OBJ_BOX: func = o_box_mirror_world; break;
470 case OBJ_PICTURE: func = o_picture_mirror_world; break;
471 case OBJ_CIRCLE: func = o_circle_mirror_world; break;
472 case OBJ_PLACEHOLDER:
473 case OBJ_COMPLEX: func = o_complex_mirror_world; break;
474 case OBJ_TEXT: func = o_text_mirror_world; break;
475 case OBJ_PATH: func = o_path_mirror_world; break;
476 case OBJ_PIN: func = o_pin_mirror_world; break;
477 case OBJ_ARC: func = o_arc_mirror_world; break;
478 default:
479 g_critical ("o_mirror_world: object %p has bad type '%c'\n",
480 object, object->type);
483 if (func != NULL) {
484 (*func) (toplevel, world_centerx, world_centery, object);
489 /*! \brief Calculates the distance between the given point and the closest
490 * point on the given object.
492 * \param [in] object The given object.
493 * \param [in] x The x coordinate of the given point.
494 * \param [in] y The y coordinate of the given point.
495 * \return The shortest distance from the object to the point. If the
496 * distance cannot be calculated, this function returns a really large
497 * number (G_MAXDOUBLE). If an error occurs, this function returns
498 * G_MAXDOUBLE.
500 double o_shortest_distance (OBJECT *object, int x, int y)
502 return o_shortest_distance_full (object, x, y, FALSE);
505 /*! \brief Calculates the distance between the given point and the closest
506 * point on the given object. Allows forcing objects to solid.
508 * \param [in] object The given object.
509 * \param [in] x The x coordinate of the given point.
510 * \param [in] y The y coordinate of the given point.
511 * \param [in] force_solid If true, force treating the object as solid.
512 * \return The shortest distance from the object to the point. If the
513 * distance cannot be calculated, this function returns a really large
514 * number (G_MAXDOUBLE). If an error occurs, this function returns
515 * G_MAXDOUBLE.
517 double o_shortest_distance_full (OBJECT *object, int x, int y, int force_solid)
519 double shortest_distance = G_MAXDOUBLE;
520 double (*func) (OBJECT *, int, int, int) = NULL;
522 g_return_val_if_fail (object != NULL, G_MAXDOUBLE);
524 switch(object->type) {
525 case OBJ_BUS:
526 case OBJ_NET:
527 case OBJ_PIN:
528 case OBJ_LINE: func = o_line_shortest_distance; break;
529 case OBJ_BOX: func = o_box_shortest_distance; break;
530 case OBJ_PICTURE: func = o_picture_shortest_distance; break;
531 case OBJ_CIRCLE: func = o_circle_shortest_distance; break;
532 case OBJ_PLACEHOLDER:
533 case OBJ_COMPLEX: func = o_complex_shortest_distance; break;
534 case OBJ_TEXT: func = o_text_shortest_distance; break;
535 case OBJ_PATH: func = o_path_shortest_distance; break;
536 case OBJ_ARC: func = o_arc_shortest_distance; break;
537 default:
538 g_critical ("o_shortest_distance: object %p has bad type '%c'\n",
539 object, object->type);
542 if (func != NULL) {
543 shortest_distance = (*func) (object, x, y, force_solid);
546 return shortest_distance;
549 /*! \brief Mark an OBJECT's cached bounds as invalid
550 * \par Function Description
551 * Marks the cached bounds of the given OBJECT as having been
552 * invalidated and in need of an update. They will be recalculated
553 * next time the OBJECT's bounds are requested (e.g. via
554 * world_get_single_object_bounds() ).
556 * \param [in] toplevel
557 * \param [in] obj
559 * \todo Turn this into a macro?
561 void o_bounds_invalidate(TOPLEVEL *toplevel, OBJECT *obj)
563 obj->w_bounds_valid = FALSE;
567 /*! \brief Change the color of an object
569 * \par Function Description
570 * This function changes the color of an object.
572 * \param [in] toplevel The TOPLEVEL structure.
573 * \param [in] object The OBJECT to change color.
574 * \param [in] color The new color.
576 void o_set_color (TOPLEVEL *toplevel, OBJECT *object, int color)
578 g_return_if_fail (object != NULL);
580 object->color = color;
582 if (object->type == OBJ_COMPLEX ||
583 object->type == OBJ_PLACEHOLDER)
584 o_glist_set_color (toplevel, object->complex->prim_objs, color);