gsch2pcb: Make --m4-file and -m4-pcbdir arguments work again.
[geda-gaf/peter-b.git] / libgeda / src / o_net_basic.c
blob3fa642f7126fff09f0f8dc9188cb8629d5bbf72f
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., 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 #ifdef HAVE_LIBDMALLOC
28 #include <dmalloc.h>
29 #endif
31 /*! \file o_net_basic.c
32 * \brief functions for the net object
35 /*! \brief get the position of the first net point
36 * \par Function Description
37 * This function gets the position of the first point of a net object.
39 * \param [in] toplevel The toplevel environment.
40 * \param [out] x pointer to the x-position
41 * \param [out] y pointer to the y-position
42 * \param [in] object The object to get the position.
43 * \return TRUE if successfully determined the position, FALSE otherwise
45 gboolean o_net_get_position (TOPLEVEL *toplevel, gint *x, gint *y,
46 OBJECT *object)
48 return o_line_get_position(toplevel, x, y, object);
51 /*! \brief calculate and return the boundaries of a net object
52 * \par Function Description
53 * This function calculates the object boudaries of a net \a object.
55 * \param [in] toplevel The TOPLEVEL object.
56 * \param [in] object a net object
57 * \param [out] left the left world coord
58 * \param [out] top the top world coord
59 * \param [out] right the right world coord
60 * \param [out] bottom the bottom world coord
62 void world_get_net_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left,
63 int *top, int *right, int *bottom)
65 world_get_line_bounds( toplevel, object, left, top, right, bottom );
68 /*! \brief create a new net object
69 * \par Function Description
70 * This function creates and returns a new net object.
72 * \param [in] toplevel The TOPLEVEL object.
73 * \param [in] type The OBJECT type (usually OBJ_NET)
74 * \param [in] color The color of the net
75 * \param [in] x1 x-coord of the first point
76 * \param [in] y1 y-coord of the first point
77 * \param [in] x2 x-coord of the second point
78 * \param [in] y2 y-coord of the second point
79 * \return A new net OBJECT
81 OBJECT *o_net_new(TOPLEVEL *toplevel, char type,
82 int color, int x1, int y1, int x2, int y2)
84 OBJECT *new_node;
86 new_node = s_basic_new_object(type, "net");
87 new_node->color = color;
89 new_node->line = (LINE *) g_malloc(sizeof(LINE));
90 /* check for null */
92 new_node->line->x[0] = x1;
93 new_node->line->y[0] = y1;
94 new_node->line->x[1] = x2;
95 new_node->line->y[1] = y2;
96 new_node->line_width = NET_WIDTH;
98 o_net_recalc (toplevel, new_node);
100 return new_node;
103 /*! \brief recalc the visual properties of a net object
104 * \par Function Description
105 * This function updates the visual coords of the \a o_current object.
107 * \param [in] toplevel The TOPLEVEL object.
108 * \param [in] o_current a net object.
111 void o_net_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
113 int left, right, top, bottom;
115 if (o_current == NULL) {
116 return;
119 if (o_current->line == NULL) {
120 return;
123 world_get_net_bounds(toplevel, o_current, &left, &top, &right,
124 &bottom);
126 o_current->w_left = left;
127 o_current->w_top = top;
128 o_current->w_right = right;
129 o_current->w_bottom = bottom;
130 o_current->w_bounds_valid = TRUE;
133 /*! \brief read a net object from a char buffer
134 * \par Function Description
135 * This function reads a net object from the buffer \a buf.
136 * If the netobject was read successfully, a new net object is
137 * allocated and appended to the \a object_list.
139 * \param [in] toplevel The TOPLEVEL object
140 * \param [in] buf a text buffer (usually a line of a schematic file)
141 * \param [in] release_ver The release number gEDA
142 * \param [in] fileformat_ver a integer value of the file format
143 * \return The object list
146 OBJECT *o_net_read (TOPLEVEL *toplevel, char buf[],
147 unsigned int release_ver, unsigned int fileformat_ver)
149 OBJECT *new_obj;
150 char type;
151 int x1, y1;
152 int x2, y2;
153 int color;
155 sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color);
157 if (x1 == x2 && y1 == y2) {
158 s_log_message (_("Found a zero length net [ %c %d %d %d %d %d ]\n"),
159 type, x1, y1, x2, y2, color);
163 if (toplevel->override_net_color != -1) {
164 color = toplevel->override_net_color;
167 if (color < 0 || color > MAX_COLORS) {
168 s_log_message (_("Found an invalid color [ %s ]\n"), buf);
169 s_log_message (_("Setting color to default color\n"));
170 color = DEFAULT_COLOR;
173 new_obj = o_net_new (toplevel, type, color, x1, y1, x2, y2);
175 return new_obj;
178 /*! \brief Create a string representation of the net object
179 * \par Function Description
180 * This function takes a net \a object and return a string
181 * according to the file format definition.
183 * \param [in] toplevel a TOPLEVEL structure
184 * \param [in] object a net OBJECT
185 * \return the string representation of the net OBJECT
187 char *o_net_save(TOPLEVEL *toplevel, OBJECT *object)
189 int x1, x2, y1, y2;
190 char *buf;
192 x1 = object->line->x[0];
193 y1 = object->line->y[0];
194 x2 = object->line->x[1];
195 y2 = object->line->y[1];
197 buf = g_strdup_printf("%c %d %d %d %d %d", object->type, x1, y1, x2, y2, object->color);
198 return (buf);
201 /*! \brief move a net object
202 * \par Function Description
203 * This function changes the position of a net \a object.
205 * \param [in] toplevel The TOPLEVEL object
206 * \param [in] dx The x-distance to move the object
207 * \param [in] dy The y-distance to move the object
208 * \param [in] object The net OBJECT to be moved
211 void o_net_translate_world(TOPLEVEL *toplevel, int dx, int dy,
212 OBJECT *object)
214 if (object == NULL)
215 printf("ntw NO!\n");
217 /* Update world coords */
218 object->line->x[0] = object->line->x[0] + dx;
219 object->line->y[0] = object->line->y[0] + dy;
220 object->line->x[1] = object->line->x[1] + dx;
221 object->line->y[1] = object->line->y[1] + dy;
223 /* Update bounding box */
224 o_net_recalc (toplevel, object);
226 s_tile_update_object(toplevel, object);
229 /*! \brief create a copy of a net object
230 * \par Function Description
231 * This function creates a copy of the net object \a o_current.
233 * \param [in] toplevel The TOPLEVEL object
234 * \param [in] o_current The object that is copied
235 * \return a new net object
237 OBJECT *o_net_copy(TOPLEVEL *toplevel, OBJECT *o_current)
239 OBJECT *new_obj;
241 /* make sure you fix this in pin and bus as well */
242 /* still doesn't work... you need to pass in the new values */
243 /* or don't update and update later */
244 /* I think for now I'll disable the update and manually update */
245 new_obj = o_net_new (toplevel, OBJ_NET, o_current->color,
246 o_current->line->x[0], o_current->line->y[0],
247 o_current->line->x[1], o_current->line->y[1]);
249 return new_obj;
252 /*! \brief postscript print command for a net object
253 * \par Function Description
254 * This function writes the postscript command of the net object \a o_current
255 * into the FILE \a fp points to.
257 * \param [in] toplevel The TOPLEVEL object
258 * \param [in] fp pointer to a FILE structure
259 * \param [in] o_current The OBJECT to print
260 * \param [in] origin_x x-coord of the postscript origin
261 * \param [in] origin_y y-coord of the postscript origin
263 void o_net_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
264 int origin_x, int origin_y)
266 int net_width;
267 int x1, y1;
268 int x2, y2;
270 if (o_current == NULL) {
271 printf("got null in o_net_print\n");
272 return;
275 f_print_set_color(toplevel, fp, o_current->color);
277 net_width = 2;
278 if (toplevel->net_style == THICK) {
279 net_width = NET_WIDTH;
282 x1 = o_current->line->x[0] - origin_x,
283 y1 = o_current->line->y[0] - origin_y;
284 x2 = o_current->line->x[1] - origin_x,
285 y2 = o_current->line->y[1] - origin_y;
287 fprintf(fp, "%d %d %d %d %d line\n", x1,y1,x2,y2,net_width);
291 /*! \brief rotate a net object around a centerpoint
292 * \par Function Description
293 * This function rotates a net \a object around the point
294 * (\a world_centerx, \a world_centery).
296 * \param [in] toplevel The TOPLEVEL object
297 * \param [in] world_centerx x-coord of the rotation center
298 * \param [in] world_centery y-coord of the rotation center
299 * \param [in] angle The angle to rotat the net object
300 * \param [in] object The net object
301 * \note only steps of 90 degrees are allowed for the \a angle
303 void o_net_rotate_world(TOPLEVEL *toplevel,
304 int world_centerx, int world_centery, int angle,
305 OBJECT *object)
307 int newx, newy;
309 if (angle == 0)
310 return;
312 /* translate object to origin */
313 o_net_translate_world(toplevel, -world_centerx, -world_centery,
314 object);
316 rotate_point_90(object->line->x[0], object->line->y[0], angle,
317 &newx, &newy);
319 object->line->x[0] = newx;
320 object->line->y[0] = newy;
322 rotate_point_90(object->line->x[1], object->line->y[1], angle,
323 &newx, &newy);
325 object->line->x[1] = newx;
326 object->line->y[1] = newy;
328 o_net_translate_world(toplevel, world_centerx, world_centery, object);
331 /*! \brief mirror a net object horizontaly at a centerpoint
332 * \par Function Description
333 * This function mirrors a net \a object horizontaly at the point
334 * (\a world_centerx, \a world_centery).
336 * \param [in] toplevel The TOPLEVEL object
337 * \param [in] world_centerx x-coord of the mirror position
338 * \param [in] world_centery y-coord of the mirror position
339 * \param [in] object The net object
341 void o_net_mirror_world(TOPLEVEL *toplevel, int world_centerx,
342 int world_centery, OBJECT *object)
344 /* translate object to origin */
345 o_net_translate_world(toplevel, -world_centerx, -world_centery,
346 object);
348 object->line->x[0] = -object->line->x[0];
350 object->line->x[1] = -object->line->x[1];
352 o_net_translate_world(toplevel, world_centerx, world_centery, object);
355 /*! \brief calculate the orientation of a net object
356 * \par Function Description
357 * This function calculates the orientation of a net object.
359 * \param [in] object The net object
360 * \return The orientation: HORIZONTAL, VERTICAL or NEITHER
362 int o_net_orientation(OBJECT *object)
364 if (object->line->y[0] == object->line->y[1]) {
365 return (HORIZONTAL);
368 if (object->line->x[0] == object->line->x[1]) {
369 return (VERTICAL);
372 return (NEITHER);
376 /*! \brief merge two net object
377 * \par Function Description
378 * This function does the actual work of making one net segment out of two
379 * connected segments. The first net segment is extended to the lenght of
380 * both objects.
381 * The second object (\a del_object) is the object that should be deleted.
383 * \param [in] object A net object to extend
384 * \param [in] del_object A net object to be merged into \a object
385 * \param [in] orient The orientation of both net objects
387 * \note The first net \a object gets the attributes of the second net
388 * \a del_object if the two nets are merged together.
390 static void o_net_consolidate_lowlevel (OBJECT *object,
391 OBJECT *del_object, int orient)
393 int temp1, temp2;
394 int final1, final2;
395 int changed = 0;
396 GList *a_iter;
397 OBJECT *a_current;
399 #if DEBUG
400 printf("o %d %d %d %d\n", object->line->x[0], object->line->y[0],
401 object->line->x[1], object->line->y[1]);
402 printf("d %d %d %d %d\n", del_object->line->x[0],
403 del_object->line->y[0], del_object->line->x[1],
404 del_object->line->y[1]);
405 #endif
408 if (orient == HORIZONTAL) {
410 temp1 = min(object->line->x[0], del_object->line->x[0]);
411 temp2 = min(object->line->x[1], del_object->line->x[1]);
413 final1 = min(temp1, temp2);
415 temp1 = max(object->line->x[0], del_object->line->x[0]);
416 temp2 = max(object->line->x[1], del_object->line->x[1]);
418 final2 = max(temp1, temp2);
420 object->line->x[0] = final1;
421 object->line->x[1] = final2;
422 changed = 1;
425 if (orient == VERTICAL) {
426 temp1 = min(object->line->y[0], del_object->line->y[0]);
427 temp2 = min(object->line->y[1], del_object->line->y[1]);
429 final1 = min(temp1, temp2);
431 temp1 = max(object->line->y[0], del_object->line->y[0]);
432 temp2 = max(object->line->y[1], del_object->line->y[1]);
434 final2 = max(temp1, temp2);
436 object->line->y[0] = final1;
437 object->line->y[1] = final2;
438 changed = 1;
440 #if DEBUG
441 printf("fo %d %d %d %d\n", object->line->x[0], object->line->y[0],
442 object->line->x[1], object->line->y[1]);
443 #endif
445 /* Move any attributes from the deleted object*/
446 if (changed && del_object->attribs != NULL) {
448 /* Reassign the attached_to pointer on attributes from the del object */
449 a_iter = del_object->attribs;
450 while (a_iter != NULL) {
451 a_current = a_iter->data;
452 a_current->attached_to = object;
453 a_iter = g_list_next (a_iter);
456 object->attribs = g_list_concat (object->attribs, del_object->attribs);
458 /* Don't free del_object->attribs as it's relinked into object's list */
459 del_object->attribs = NULL;
463 /*! \brief Check if there's a midpoint connection at (x,y)
464 * \par Function Description
465 * This function checks if the \a object is connected to another net
466 * between it's endpoints. Net segment's only can be merged if there
467 * is no midpoint connection.
469 * \param object a net OBJECT to check
470 * \param x x-coord of the connection location
471 * \param y y-coord of the connection location
472 * \return TRUE if there's no midpoint connection, else return FALSE
474 static int o_net_consolidate_nomidpoint (OBJECT *object, int x, int y)
476 GList *c_current;
477 CONN *conn;
479 c_current = object->conn_list;
480 while(c_current != NULL) {
481 conn = (CONN *) c_current->data;
482 if (conn->other_object) {
483 if (conn->other_object->sid != object->sid &&
484 conn->x == x && conn->y == y &&
485 conn->type == CONN_MIDPOINT) {
486 #if DEBUG
487 printf("Found one! %s\n", conn->other_object->name);
488 #endif
489 return(FALSE);
493 c_current = g_list_next(c_current);
496 return(TRUE);
499 /*! \brief try to consolidate a net object
500 * \par Function Description
501 * This function tries to consolidate a net with any other object
502 * that is connected to the current \a object.
504 * \param toplevel The TOPLEVEL object
505 * \param object The object to consolidate
506 * \return 0 if no consolidation was possible, -1 otherwise
509 static int o_net_consolidate_segments (TOPLEVEL *toplevel, OBJECT *object)
511 int object_orient;
512 int other_orient;
513 GList *c_current;
514 CONN *conn;
515 OBJECT *other_object;
516 PAGE *page;
517 int changed = 0;
519 g_return_val_if_fail ((toplevel != NULL), 0);
520 g_return_val_if_fail ((object != NULL), 0);
521 g_return_val_if_fail ((object->type == OBJ_NET), 0);
523 /* It's meaningless to do anything here if the object isn't in a page. */
524 page = o_get_page (toplevel, object);
525 g_return_val_if_fail ((page != NULL), 0);
527 object_orient = o_net_orientation(object);
529 c_current = object->conn_list;
530 while(c_current != NULL) {
531 conn = (CONN *) c_current->data;
532 other_object = conn->other_object;
534 /* only look at end points which have a valid end on the other side */
535 if (other_object != NULL && conn->type == CONN_ENDPOINT &&
536 conn->other_whichone != -1 && conn->whichone != -1 &&
537 o_net_consolidate_nomidpoint(object, conn->x, conn->y) ) {
539 if (other_object->type == OBJ_NET) {
540 other_orient = o_net_orientation(other_object);
542 /* - both objects have the same orientation (either vert or horiz) */
543 /* - it's not the same object */
544 if (object_orient == other_orient &&
545 object->sid != other_object->sid &&
546 other_orient != NEITHER) {
548 #if DEBUG
549 printf("consolidating %s to %s\n", object->name, other_object->name);
550 #endif
552 o_net_consolidate_lowlevel(object, other_object, other_orient);
554 changed++;
555 if (other_object->selected == TRUE ) {
556 o_selection_remove (toplevel, page->selection_list, other_object);
558 /* If we're consolidating with a selected object,
559 * ensure we select the resulting object.
561 if (object->selected == FALSE) {
562 o_selection_add (toplevel, page->selection_list, object);
566 s_delete_object (toplevel, other_object);
567 o_net_recalc(toplevel, object);
568 s_tile_update_object(toplevel, object);
569 s_conn_update_object (toplevel, object);
570 return(-1);
576 c_current = g_list_next (c_current);
579 return(0);
582 /*! \brief consolidate all net objects
583 * \par Function Description
584 * This function consolidates all net objects in a page until no more
585 * consolidations are possible.
587 * \param toplevel The TOPLEVEL object.
588 * \param page The PAGE to consolidate nets in.
590 void o_net_consolidate(TOPLEVEL *toplevel, PAGE *page)
592 OBJECT *o_current;
593 const GList *iter;
594 int status = 0;
596 g_return_if_fail (toplevel != NULL);
597 g_return_if_fail (page != NULL);
599 iter = s_page_objects (page);
601 while (iter != NULL) {
602 o_current = (OBJECT *)iter->data;
604 if (o_current->type == OBJ_NET) {
605 status = o_net_consolidate_segments(toplevel, o_current);
608 if (status == -1) {
609 iter = s_page_objects (page);
610 status = 0;
611 } else {
612 iter = g_list_next (iter);
617 /*! \brief modify one point of a net object
618 * \par Function Description
619 * This function modifies one point of a net \a object. The point
620 * is specified by the \a whichone variable and the new coordinate
621 * is (\a x, \a y).
623 * \param toplevel The TOPLEVEL object
624 * \param object The net OBJECT to modify
625 * \param x new x-coord of the net point
626 * \param y new y-coord of the net point
627 * \param whichone net point to modify
630 void o_net_modify(TOPLEVEL *toplevel, OBJECT *object,
631 int x, int y, int whichone)
633 object->line->x[whichone] = x;
634 object->line->y[whichone] = y;
636 o_net_recalc (toplevel, object);
638 s_tile_update_object(toplevel, object);