Bump gEDA version
[geda-gaf.git] / libgeda / src / o_pin_basic.c
blobb350153db037ec14beb784f66308ab9919a473f9
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
20 #include <config.h>
22 #include <stdio.h>
23 #include <math.h>
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);
65 if (x != NULL) {
66 *x = object->line->x[object->whichend];
69 if (y != NULL) {
70 *y = object->line->y[object->whichend];
73 return TRUE;
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,
91 int color,
92 int x1, int y1, int x2, int y2, int pin_type, int whichend)
94 OBJECT *new_node;
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;
112 return new_node;
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)
130 OBJECT *new_obj;
131 char type;
132 int x1, y1;
133 int x2, y2;
134 int color;
135 int pin_type;
136 int whichend;
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"));
141 return NULL;
143 pin_type = PIN_TYPE_NET;
144 whichend = -1;
145 } else {
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"));
149 return NULL;
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"),
158 whichend);
159 whichend = 0;
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,
169 pin_type, whichend);
171 return new_obj;
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
182 * g_free().
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",
194 OBJ_PIN,
195 object->line->x[0],
196 object->line->y[0],
197 object->line->x[1],
198 object->line->y[1],
199 object->color,
200 object->pin_type,
201 object->whichend);
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)
238 OBJECT *new_obj;
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);
249 return new_obj;
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,
266 OBJECT *object)
268 int newx, newy;
270 g_return_if_fail (object != NULL);
271 g_return_if_fail (object->line != NULL);
272 g_return_if_fail (object->type == OBJ_PIN);
274 if (angle == 0)
275 return;
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,
281 &newx, &newy);
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,
287 &newx, &newy);
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
326 * is (\a x, \a y).
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)
367 OBJECT *o_current;
368 GList *iter;
369 int top = 0, left = 0;
370 int right = 0, bottom = 0;
371 int d1, d2, d3, d4;
372 int min0, min1;
373 int min0_whichend, min1_whichend;
374 int rleft, rtop, rright, rbottom;
375 int found;
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);
381 } else {
382 found = 0;
384 /* only look at the pins to calculate bounds of the symbol */
385 iter = object_list;
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);
392 if ( found ) {
393 left = min( left, rleft );
394 top = min( top, rtop );
395 right = max( right, rright );
396 bottom = max( bottom, rbottom );
397 } else {
398 left = rleft;
399 top = rtop;
400 right = rright;
401 bottom = rbottom;
402 found = 1;
405 iter = g_list_next (iter);
409 } else {
410 return;
413 iter = object_list;
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]) {
419 /* horizontal */
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);
426 if (d1 <= d2) {
427 min0 = d1;
428 min0_whichend = 0;
429 } else {
430 min0 = d2;
431 min0_whichend = 1;
434 if (d3 <= d4) {
435 min1 = d3;
436 min1_whichend = 0;
437 } else {
438 min1 = d4;
439 min1_whichend = 1;
442 if (min0 <= min1) {
443 o_current->whichend = min0_whichend;
444 } else {
445 o_current->whichend = min1_whichend;
448 } else if (o_current->line->x[0] == o_current->line->x[1]) {
449 /* vertical */
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);
456 if (d1 <= d2) {
457 min0 = d1;
458 min0_whichend = 0;
459 } else {
460 min0 = d2;
461 min0_whichend = 1;
464 if (d3 <= d4) {
465 min1 = d3;
466 min1_whichend = 0;
467 } else {
468 min1 = d4;
469 min1_whichend = 1;
472 if (min0 <= min1) {
473 o_current->whichend = min0_whichend;
474 } else {
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);
499 switch (pin_type) {
500 default:
501 g_critical ("o_pin_set_type: Got invalid pin type %i\n", pin_type);
502 /* Fall through */
503 case PIN_TYPE_NET:
504 o_current->line_width = PIN_WIDTH_NET;
505 o_current->pin_type = PIN_TYPE_NET;
506 break;
507 case PIN_TYPE_BUS:
508 o_current->line_width = PIN_WIDTH_BUS;
509 o_current->pin_type = PIN_TYPE_BUS;
510 break;
512 o_emit_change_notify (toplevel, o_current);