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
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
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
49 /* instrumentation code */
55 #include "libgeda_priv.h"
57 #ifdef HAVE_LIBDMALLOC
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
) {
98 o_line_recalc(toplevel
, o_current
);
102 o_net_recalc(toplevel
, o_current
);
106 o_bus_recalc(toplevel
, o_current
);
110 o_box_recalc(toplevel
, o_current
);
114 o_path_recalc(toplevel
, o_current
);
118 o_picture_recalc(toplevel
, o_current
);
122 o_circle_recalc(toplevel
, o_current
);
126 case(OBJ_PLACEHOLDER
):
127 o_complex_recalc(toplevel
, o_current
);
131 o_pin_recalc(toplevel
, o_current
);
135 o_arc_recalc(toplevel
, o_current
);
139 o_text_recalc(toplevel
, o_current
);
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.
156 o_recalc_object_glist(TOPLEVEL
*toplevel
, GList
*object_glist
)
158 GList
*list
= object_glist
;
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
) {
194 /* do some error checking / correcting */
199 s_log_message (_("Invalid space specified, setting to 100\n"));
207 s_log_message (_("Invalid length specified, setting to 100\n"));
211 s_log_message (_("Invalid space specified, setting to 100\n"));
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
)
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
;
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
) {
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
)
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
;
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;
363 g_critical ("o_get_position: object %p has bad type '%c'\n",
364 object
, object
->type
);
368 return (*func
) (toplevel
, x
, y
, object
);
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;
402 g_critical ("o_translate_world: object %p has bad type '%c'\n",
403 object
, object
->type
);
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;
441 g_critical ("o_rotate_world: object %p has bad type '%c'\n",
442 object
, object
->type
);
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;
479 g_critical ("o_mirror_world: object %p has bad type '%c'\n",
480 object
, object
->type
);
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
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
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
) {
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;
538 g_critical ("o_shortest_distance: object %p has bad type '%c'\n",
539 object
, object
->type
);
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
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
);