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
25 #include "libgeda_priv.h"
27 /*! \file o_pin_basic.c
28 * \brief functions for the pin object
31 /*! \brief calculate and return the boundaries of a pin object
32 * \par Function Description
33 * This function calculates the object boudaries of a pin \a object.
35 * \param [in] toplevel The TOPLEVEL object.
36 * \param [in] object a pin object
37 * \param [out] left the left world coord
38 * \param [out] top the top world coord
39 * \param [out] right the right world coord
40 * \param [out] bottom the bottom world coord
42 void world_get_pin_bounds(TOPLEVEL
*toplevel
, OBJECT
*object
, int *left
, int *top
,
43 int *right
, int *bottom
)
45 world_get_line_bounds( toplevel
, object
, left
, top
, right
, bottom
);
48 /*! \brief get the position of a whichend of the pin object
49 * \par Function Description
50 * This function gets the position of the whichend side of a pin object.
52 * \param [in] object The object to get the position.
53 * \param [out] x pointer to the x-position
54 * \param [out] y pointer to the y-position
55 * \return TRUE if successfully determined the position, FALSE otherwise
57 gboolean
o_pin_get_position (OBJECT
*object
, gint
*x
, gint
*y
)
59 g_return_val_if_fail (object
!= NULL
, FALSE
);
60 g_return_val_if_fail (object
->type
== OBJ_PIN
, FALSE
);
61 g_return_val_if_fail (object
->line
!= NULL
, FALSE
);
62 g_return_val_if_fail (object
->whichend
>= 0, FALSE
);
63 g_return_val_if_fail (object
->whichend
< 2, FALSE
);
66 *x
= object
->line
->x
[object
->whichend
];
70 *y
= object
->line
->y
[object
->whichend
];
76 /*! \brief create a new pin object
77 * \par Function Description
78 * This function creates and returns a new pin object.
80 * \param [in] toplevel The TOPLEVEL object.
81 * \param [in] color The color of the pin
82 * \param [in] x1 x-coord of the first point
83 * \param [in] y1 y-coord of the first point
84 * \param [in] x2 x-coord of the second point
85 * \param [in] y2 y-coord of the second point
86 * \param [in] pin_type type of pin (PIN_TYPE_NET or PIN_TYPE_BUS)
87 * \param [in] whichend The connectable end of the pin
88 * \return A new pin OBJECT
90 OBJECT
*o_pin_new(TOPLEVEL
*toplevel
,
92 int x1
, int y1
, int x2
, int y2
, int pin_type
, int whichend
)
96 new_node
= s_basic_new_object(OBJ_PIN
, "pin");
97 new_node
->color
= color
;
99 new_node
->line
= (LINE
*) g_malloc(sizeof(LINE
));
101 new_node
->line
->x
[0] = x1
;
102 new_node
->line
->y
[0] = y1
;
103 new_node
->line
->x
[1] = x2
;
104 new_node
->line
->y
[1] = y2
;
106 o_pin_set_type (toplevel
, new_node
, pin_type
);
108 new_node
->w_bounds_valid_for
= NULL
;
110 new_node
->whichend
= whichend
;
115 /*! \brief read a pin object from a char buffer
116 * \par Function Description
117 * This function reads a pin object from the buffer \a buf.
118 * If the pin object was read successfully, a new pin object is
119 * allocated and appended to the \a object_list.
121 * \param [in] toplevel The TOPLEVEL object
122 * \param [in] buf a text buffer (usually a line of a schematic file)
123 * \param [in] release_ver The release number gEDA
124 * \param [in] fileformat_ver a integer value of the file format
125 * \return The object list, or NULL on error.
127 OBJECT
*o_pin_read (TOPLEVEL
*toplevel
, const char buf
[],
128 unsigned int release_ver
, unsigned int fileformat_ver
, GError
**err
)
138 if (release_ver
<= VERSION_20020825
) {
139 if (sscanf (buf
, "%c %d %d %d %d %d\n", &type
, &x1
, &y1
, &x2
, &y2
, &color
) != 6) {
140 g_set_error(err
, EDA_ERROR
, EDA_ERROR_PARSE
, _("Failed to parse pin object"));
143 pin_type
= PIN_TYPE_NET
;
146 if (sscanf (buf
, "%c %d %d %d %d %d %d %d\n", &type
, &x1
, &y1
, &x2
, &y2
,
147 &color
, &pin_type
, &whichend
) != 8) {
148 g_set_error(err
, EDA_ERROR
, EDA_ERROR_PARSE
, _("Failed to parse pin object"));
153 if (whichend
== -1) {
154 s_log_message (_("Found a pin which did not have the whichend field set.\n"
155 "Verify and correct manually.\n"));
156 } else if (whichend
< -1 || whichend
> 1) {
157 s_log_message (_("Found an invalid whichend on a pin (reseting to zero): %d\n"),
162 if (color
< 0 || color
>= MAX_OBJECT_COLORS
) {
163 s_log_message (_("Found an invalid color [ %s ]\n"), buf
);
164 s_log_message (_("Setting color to default color\n"));
165 color
= DEFAULT_COLOR
;
168 new_obj
= o_pin_new (toplevel
, color
, x1
, y1
, x2
, y2
,
174 /*! \brief Create a string representation of the pin object
176 * This function takes a pin \a object and returns a string
177 * according to the file format definition.
179 * On failure, this function returns NULL.
181 * The caller must free the returned string when no longer needed using
184 * \param [in] object a pin object
185 * \return a string representation of the pin object
187 char *o_pin_save(OBJECT
*object
)
189 g_return_val_if_fail (object
!= NULL
, NULL
);
190 g_return_val_if_fail (object
->line
!= NULL
, NULL
);
191 g_return_val_if_fail (object
->type
== OBJ_PIN
, NULL
);
193 return g_strdup_printf ("%c %d %d %d %d %d %d %d",
204 /*! \brief move a pin object
205 * \par Function Description
206 * This function changes the position of a pin \a object.
208 * \param [ref] object The pin OBJECT to be moved
209 * \param [in] dx The x-distance to move the object
210 * \param [in] dy The y-distance to move the object
212 void o_pin_translate_world(OBJECT
*object
, int dx
, int dy
)
214 g_return_if_fail (object
!= NULL
);
215 g_return_if_fail (object
->line
!= NULL
);
216 g_return_if_fail (object
->type
== OBJ_PIN
);
218 /* Update world coords */
219 object
->line
->x
[0] = object
->line
->x
[0] + dx
;
220 object
->line
->y
[0] = object
->line
->y
[0] + dy
;
221 object
->line
->x
[1] = object
->line
->x
[1] + dx
;
222 object
->line
->y
[1] = object
->line
->y
[1] + dy
;
224 /* Update bounding box */
225 object
->w_bounds_valid_for
= NULL
;
228 /*! \brief create a copy of a pin object
229 * \par Function Description
230 * This function creates a copy of the pin object \a o_current.
232 * \param [in] toplevel The TOPLEVEL object
233 * \param [in] o_current The object that is copied
234 * \return a new pin object
236 OBJECT
*o_pin_copy(TOPLEVEL
*toplevel
, OBJECT
*o_current
)
240 g_return_val_if_fail (o_current
!= NULL
, NULL
);
241 g_return_val_if_fail (o_current
->line
!= NULL
, NULL
);
242 g_return_val_if_fail (o_current
->type
== OBJ_PIN
, NULL
);
244 new_obj
= o_pin_new (toplevel
, o_current
->color
,
245 o_current
->line
->x
[0], o_current
->line
->y
[0],
246 o_current
->line
->x
[1], o_current
->line
->y
[1],
247 o_current
->pin_type
, o_current
->whichend
);
252 /*! \brief rotate a pin object around a centerpoint
253 * \par Function Description
254 * This function rotates a pin \a object around the point
255 * (\a world_centerx, \a world_centery).
257 * \param [in] toplevel The TOPLEVEL object
258 * \param [in] world_centerx x-coord of the rotation center
259 * \param [in] world_centery y-coord of the rotation center
260 * \param [in] angle The angle to rotat the pin object
261 * \param [in] object The pin object
262 * \note only steps of 90 degrees are allowed for the \a angle
264 void o_pin_rotate_world(TOPLEVEL
*toplevel
, int world_centerx
,
265 int world_centery
, int angle
,
270 g_return_if_fail (object
!= NULL
);
271 g_return_if_fail (object
->line
!= NULL
);
272 g_return_if_fail (object
->type
== OBJ_PIN
);
277 /* translate object to origin */
278 o_pin_translate_world(object
, -world_centerx
, -world_centery
);
280 rotate_point_90(object
->line
->x
[0], object
->line
->y
[0], angle
,
283 object
->line
->x
[0] = newx
;
284 object
->line
->y
[0] = newy
;
286 rotate_point_90(object
->line
->x
[1], object
->line
->y
[1], angle
,
289 object
->line
->x
[1] = newx
;
290 object
->line
->y
[1] = newy
;
292 o_pin_translate_world(object
, world_centerx
, world_centery
);
295 /*! \brief mirror a pin object horizontaly at a centerpoint
296 * \par Function Description
297 * This function mirrors a pin \a object horizontaly at the point
298 * (\a world_centerx, \a world_centery).
300 * \param [in] toplevel The TOPLEVEL object
301 * \param [in] world_centerx x-coord of the mirror position
302 * \param [in] world_centery y-coord of the mirror position
303 * \param [in] object The pin object
305 void o_pin_mirror_world(TOPLEVEL
*toplevel
,
306 int world_centerx
, int world_centery
, OBJECT
*object
)
308 g_return_if_fail (object
!= NULL
);
309 g_return_if_fail (object
->line
!= NULL
);
310 g_return_if_fail (object
->type
== OBJ_PIN
);
312 /* translate object to origin */
313 o_pin_translate_world(object
, -world_centerx
, -world_centery
);
315 object
->line
->x
[0] = -object
->line
->x
[0];
317 object
->line
->x
[1] = -object
->line
->x
[1];
319 o_pin_translate_world(object
, world_centerx
, world_centery
);
322 /*! \brief modify one point of a pin object
323 * \par Function Description
324 * This function modifies one point of a pin \a object. The point
325 * is specified by the \a whichone variable and the new coordinate
328 * \param toplevel The TOPLEVEL object
329 * \param object The pin OBJECT to modify
330 * \param x new x-coord of the pin point
331 * \param y new y-coord of the pin point
332 * \param whichone pin point to modify
335 void o_pin_modify(TOPLEVEL
*toplevel
, OBJECT
*object
,
336 int x
, int y
, int whichone
)
338 g_return_if_fail (object
!= NULL
);
339 g_return_if_fail (object
->line
!= NULL
);
340 g_return_if_fail (object
->type
== OBJ_PIN
);
341 g_return_if_fail (object
->whichend
>= 0);
342 g_return_if_fail (object
->whichend
< 2);
344 object
->line
->x
[whichone
] = x
;
345 object
->line
->y
[whichone
] = y
;
347 object
->w_bounds_valid_for
= NULL
;
350 /*! \brief guess the whichend of pins of object list
351 * \par Function Description
352 * This function determines the whichend of the pins in the \a object_list.
353 * In older libgeda file format versions there was no information about the
354 * active end of pins.
355 * This function calculates the bounding box of all pins in the object list.
356 * The side of the pins that are closer to the boundary of the box are
357 * set as active ends of the pins.
359 * \param toplevel The TOPLEVEL object
360 * \param object_list list of OBJECTs
361 * \param num_pins pin count in the object list
364 void o_pin_update_whichend(TOPLEVEL
*toplevel
,
365 GList
*object_list
, int num_pins
)
369 int top
= 0, left
= 0;
370 int right
= 0, bottom
= 0;
373 int min0_whichend
, min1_whichend
;
374 int rleft
, rtop
, rright
, rbottom
;
377 if (object_list
&& num_pins
) {
378 if (num_pins
== 1 || toplevel
->force_boundingbox
) {
379 world_get_object_glist_bounds (toplevel
, object_list
,
380 &left
, &top
, &right
, &bottom
);
384 /* only look at the pins to calculate bounds of the symbol */
386 while (iter
!= NULL
) {
387 o_current
= (OBJECT
*)iter
->data
;
388 if (o_current
->type
== OBJ_PIN
) {
389 (void) world_get_single_object_bounds(
390 toplevel
, o_current
, &rleft
, &rtop
, &rright
, &rbottom
);
393 left
= min( left
, rleft
);
394 top
= min( top
, rtop
);
395 right
= max( right
, rright
);
396 bottom
= max( bottom
, rbottom
);
405 iter
= g_list_next (iter
);
414 while (iter
!= NULL
) {
415 o_current
= (OBJECT
*)iter
->data
;
416 /* Determine which end of the pin is on or nearest the boundary */
417 if (o_current
->type
== OBJ_PIN
&& o_current
->whichend
== -1) {
418 if (o_current
->line
->y
[0] == o_current
->line
->y
[1]) {
421 d1
= abs(o_current
->line
->x
[0] - left
);
422 d2
= abs(o_current
->line
->x
[1] - left
);
423 d3
= abs(o_current
->line
->x
[0] - right
);
424 d4
= abs(o_current
->line
->x
[1] - right
);
443 o_current
->whichend
= min0_whichend
;
445 o_current
->whichend
= min1_whichend
;
448 } else if (o_current
->line
->x
[0] == o_current
->line
->x
[1]) {
451 d1
= abs(o_current
->line
->y
[0] - top
);
452 d2
= abs(o_current
->line
->y
[1] - top
);
453 d3
= abs(o_current
->line
->y
[0] - bottom
);
454 d4
= abs(o_current
->line
->y
[1] - bottom
);
473 o_current
->whichend
= min0_whichend
;
475 o_current
->whichend
= min1_whichend
;
479 iter
= g_list_next (iter
);
484 /*! \brief Sets the type, and corresponding width of a pin
486 * \par Function Description
487 * Sets the pin's type and width to a particular style.
489 * \param [in] toplevel The TOPLEVEL object
490 * \param [in] o_current The pin OBJECT being modified
491 * \param [in] pin_type The new type of this pin
493 void o_pin_set_type (TOPLEVEL
*toplevel
, OBJECT
*o_current
, int pin_type
)
495 g_return_if_fail (o_current
!= NULL
);
496 g_return_if_fail (o_current
->type
== OBJ_PIN
);
498 o_emit_pre_change_notify (toplevel
, o_current
);
501 g_critical ("o_pin_set_type: Got invalid pin type %i\n", pin_type
);
504 o_current
->line_width
= PIN_WIDTH_NET
;
505 o_current
->pin_type
= PIN_TYPE_NET
;
508 o_current
->line_width
= PIN_WIDTH_BUS
;
509 o_current
->pin_type
= PIN_TYPE_BUS
;
512 o_emit_change_notify (toplevel
, o_current
);