Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / libgeda / src / o_net_basic.c
blob20bbd1cb884cb252ea69b5ff0591e25354e9527d
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
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 /*! Default setting for net draw function. */
36 void (*net_draw_func)() = NULL;
38 /*! \brief get the position of the first net point
39 * \par Function Description
40 * This function gets the position of the first point of a net object.
42 * \param [in] toplevel The toplevel environment.
43 * \param [out] x pointer to the x-position
44 * \param [out] y pointer to the y-position
45 * \param [in] object The object to get the position.
46 * \return TRUE if successfully determined the position, FALSE otherwise
48 gboolean o_net_get_position (TOPLEVEL *toplevel, gint *x, gint *y,
49 OBJECT *object)
51 return o_line_get_position(toplevel, x, y, object);
54 /*! \brief calculate and return the boundaries of a net object
55 * \par Function Description
56 * This function calculates the object boudaries of a net \a object.
58 * \param [in] toplevel The TOPLEVEL object.
59 * \param [in] object a net object
60 * \param [out] left the left world coord
61 * \param [out] top the top world coord
62 * \param [out] right the right world coord
63 * \param [out] bottom the bottom world coord
65 void world_get_net_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left,
66 int *top, int *right, int *bottom)
68 world_get_line_bounds( toplevel, object, left, top, right, bottom );
71 /*! \brief create a new net object
72 * \par Function Description
73 * This function creates and returns a new net object.
75 * \param [in] toplevel The TOPLEVEL object.
76 * \param [in] type The OBJECT type (usually OBJ_NET)
77 * \param [in] color The color of the net
78 * \param [in] x1 x-coord of the first point
79 * \param [in] y1 y-coord of the first point
80 * \param [in] x2 x-coord of the second point
81 * \param [in] y2 y-coord of the second point
82 * \return A new net OBJECT
84 OBJECT *o_net_new(TOPLEVEL *toplevel, char type,
85 int color, int x1, int y1, int x2, int y2)
87 OBJECT *new_node;
89 new_node = s_basic_new_object(type, "net");
90 new_node->color = color;
92 new_node->line = (LINE *) g_malloc(sizeof(LINE));
93 /* check for null */
95 new_node->line->x[0] = x1;
96 new_node->line->y[0] = y1;
97 new_node->line->x[1] = x2;
98 new_node->line->y[1] = y2;
99 new_node->line_width = NET_WIDTH;
101 o_net_recalc (toplevel, new_node);
103 new_node->draw_func = net_draw_func;
104 new_node->sel_func = select_func;
106 if (!toplevel->ADDING_SEL) {
107 s_tile_add_object (toplevel, new_node);
108 s_conn_update_object (toplevel, new_node);
111 return new_node;
114 /*! \brief recalc the visual properties of a net object
115 * \par Function Description
116 * This function updates the visual coords of the \a o_current object.
118 * \param [in] toplevel The TOPLEVEL object.
119 * \param [in] o_current a net object.
122 void o_net_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
124 int left, right, top, bottom;
126 if (o_current == NULL) {
127 return;
130 if (o_current->line == NULL) {
131 return;
134 world_get_net_bounds(toplevel, o_current, &left, &top, &right,
135 &bottom);
137 o_current->w_left = left;
138 o_current->w_top = top;
139 o_current->w_right = right;
140 o_current->w_bottom = bottom;
141 o_current->w_bounds_valid = TRUE;
144 /*! \brief read a net object from a char buffer
145 * \par Function Description
146 * This function reads a net object from the buffer \a buf.
147 * If the netobject was read successfully, a new net object is
148 * allocated and appended to the \a object_list.
150 * \param [in] toplevel The TOPLEVEL object
151 * \param [in] buf a text buffer (usually a line of a schematic file)
152 * \param [in] release_ver The release number gEDA
153 * \param [in] fileformat_ver a integer value of the file format
154 * \return The object list
157 OBJECT *o_net_read (TOPLEVEL *toplevel, char buf[],
158 unsigned int release_ver, unsigned int fileformat_ver)
160 OBJECT *new_obj;
161 char type;
162 int x1, y1;
163 int x2, y2;
164 int color;
166 sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color);
168 if (x1 == x2 && y1 == y2) {
169 s_log_message (_("Found a zero length net [ %c %d %d %d %d %d ]\n"),
170 type, x1, y1, x2, y2, color);
174 if (toplevel->override_net_color != -1) {
175 color = toplevel->override_net_color;
178 if (color < 0 || color > MAX_COLORS) {
179 s_log_message (_("Found an invalid color [ %s ]\n"), buf);
180 s_log_message (_("Setting color to default color\n"));
181 color = DEFAULT_COLOR;
184 new_obj = o_net_new (toplevel, type, color, x1, y1, x2, y2);
186 return new_obj;
189 /*! \brief Create a string representation of the net object
190 * \par Function Description
191 * This function takes a net \a object and return a string
192 * according to the file format definition.
194 * \param [in] object a net OBJECT
195 * \return the string representation of the net OBJECT
197 char *o_net_save(OBJECT *object)
199 int x1, x2, y1, y2;
200 char *buf;
202 x1 = object->line->x[0];
203 y1 = object->line->y[0];
204 x2 = object->line->x[1];
205 y2 = object->line->y[1];
207 buf = g_strdup_printf("%c %d %d %d %d %d", object->type, x1, y1, x2, y2, object->color);
208 return (buf);
211 /*! \brief move a net object
212 * \par Function Description
213 * This function changes the position of a net \a object.
215 * \param [in] toplevel The TOPLEVEL object
216 * \param [in] dx The x-distance to move the object
217 * \param [in] dy The y-distance to move the object
218 * \param [in] object The net OBJECT to be moved
221 void o_net_translate_world(TOPLEVEL *toplevel, int dx, int dy,
222 OBJECT *object)
224 if (object == NULL)
225 printf("ntw NO!\n");
227 /* Update world coords */
228 object->line->x[0] = object->line->x[0] + dx;
229 object->line->y[0] = object->line->y[0] + dy;
230 object->line->x[1] = object->line->x[1] + dx;
231 object->line->y[1] = object->line->y[1] + dy;
233 /* Update bounding box */
234 o_net_recalc (toplevel, object);
236 s_tile_update_object(toplevel, object);
239 /*! \brief create a copy of a net object
240 * \par Function Description
241 * This function creates a copy of the net object \a o_current.
243 * \param [in] toplevel The TOPLEVEL object
244 * \param [in] o_current The object that is copied
245 * \return a new net object
247 OBJECT *o_net_copy(TOPLEVEL *toplevel, OBJECT *o_current)
249 OBJECT *new_obj;
251 /* make sure you fix this in pin and bus as well */
252 /* still doesn't work... you need to pass in the new values */
253 /* or don't update and update later */
254 /* I think for now I'll disable the update and manually update */
255 new_obj = o_net_new (toplevel, OBJ_NET, o_current->color,
256 o_current->line->x[0], o_current->line->y[0],
257 o_current->line->x[1], o_current->line->y[1]);
259 return new_obj;
262 /*! \brief postscript print command for a net object
263 * \par Function Description
264 * This function writes the postscript command of the net object \a o_current
265 * into the FILE \a fp points to.
267 * \param [in] toplevel The TOPLEVEL object
268 * \param [in] fp pointer to a FILE structure
269 * \param [in] o_current The OBJECT to print
270 * \param [in] origin_x x-coord of the postscript origin
271 * \param [in] origin_y y-coord of the postscript origin
273 void o_net_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
274 int origin_x, int origin_y)
276 int offset, offset2;
277 int cross, net_width;
278 int x1, y1;
279 int x2, y2;
281 if (o_current == NULL) {
282 printf("got null in o_net_print\n");
283 return;
286 offset = 7 * 6;
287 offset2 = 7;
289 cross = offset;
291 f_print_set_color(toplevel, fp, o_current->color);
293 net_width = 2;
294 if (toplevel->net_style == THICK) {
295 net_width = NET_WIDTH;
298 x1 = o_current->line->x[0] - origin_x,
299 y1 = o_current->line->y[0] - origin_y;
300 x2 = o_current->line->x[1] - origin_x,
301 y2 = o_current->line->y[1] - origin_y;
303 fprintf(fp, "%d %d %d %d %d line\n", x1,y1,x2,y2,net_width);
307 /*! \brief rotate a net object around a centerpoint
308 * \par Function Description
309 * This function rotates a net \a object around the point
310 * (\a world_centerx, \a world_centery).
312 * \param [in] toplevel The TOPLEVEL object
313 * \param [in] world_centerx x-coord of the rotation center
314 * \param [in] world_centery y-coord of the rotation center
315 * \param [in] angle The angle to rotat the net object
316 * \param [in] object The net object
317 * \note only steps of 90 degrees are allowed for the \a angle
319 void o_net_rotate_world(TOPLEVEL *toplevel,
320 int world_centerx, int world_centery, int angle,
321 OBJECT *object)
323 int newx, newy;
325 if (angle == 0)
326 return;
328 /* translate object to origin */
329 o_net_translate_world(toplevel, -world_centerx, -world_centery,
330 object);
332 rotate_point_90(object->line->x[0], object->line->y[0], angle,
333 &newx, &newy);
335 object->line->x[0] = newx;
336 object->line->y[0] = newy;
338 rotate_point_90(object->line->x[1], object->line->y[1], angle,
339 &newx, &newy);
341 object->line->x[1] = newx;
342 object->line->y[1] = newy;
344 o_net_translate_world(toplevel, world_centerx, world_centery, object);
347 /*! \brief mirror a net object horizontaly at a centerpoint
348 * \par Function Description
349 * This function mirrors a net \a object horizontaly at the point
350 * (\a world_centerx, \a world_centery).
352 * \param [in] toplevel The TOPLEVEL object
353 * \param [in] world_centerx x-coord of the mirror position
354 * \param [in] world_centery y-coord of the mirror position
355 * \param [in] object The net object
357 void o_net_mirror_world(TOPLEVEL *toplevel, int world_centerx,
358 int world_centery, OBJECT *object)
360 /* translate object to origin */
361 o_net_translate_world(toplevel, -world_centerx, -world_centery,
362 object);
364 object->line->x[0] = -object->line->x[0];
366 object->line->x[1] = -object->line->x[1];
368 o_net_translate_world(toplevel, world_centerx, world_centery, object);
371 /*! \brief calculate the orientation of a net object
372 * \par Function Description
373 * This function calculates the orientation of a net object.
375 * \param [in] object The net object
376 * \return The orientation: HORIZONTAL, VERTICAL or NEITHER
378 int o_net_orientation(OBJECT *object)
380 if (object->line->y[0] == object->line->y[1]) {
381 return (HORIZONTAL);
384 if (object->line->x[0] == object->line->x[1]) {
385 return (VERTICAL);
388 return (NEITHER);
392 /*! \brief merge two net object
393 * \par Function Description
394 * This function does the actual work of making one net segment out of two
395 * connected segments. The first net segment is extended to the lenght of
396 * both objects.
397 * The second object (\a del_object) is the object that should be deleted.
399 * \param [in] object A net object to extend
400 * \param [in] del_object A net object to be merged into \a object
401 * \param [in] orient The orientation of both net objects
403 * \note The first net \a object gets the attributes of the second net
404 * \a del_object if the two nets are merged together.
406 static void o_net_consolidate_lowlevel (OBJECT *object,
407 OBJECT *del_object, int orient)
409 int temp1, temp2;
410 int final1, final2;
411 int changed = 0;
412 GList *a_iter;
413 OBJECT *a_current;
415 #if DEBUG
416 printf("o %d %d %d %d\n", object->line->x[0], object->line->y[0],
417 object->line->x[1], object->line->y[1]);
418 printf("d %d %d %d %d\n", del_object->line->x[0],
419 del_object->line->y[0], del_object->line->x[1],
420 del_object->line->y[1]);
421 #endif
424 if (orient == HORIZONTAL) {
426 temp1 = min(object->line->x[0], del_object->line->x[0]);
427 temp2 = min(object->line->x[1], del_object->line->x[1]);
429 final1 = min(temp1, temp2);
431 temp1 = max(object->line->x[0], del_object->line->x[0]);
432 temp2 = max(object->line->x[1], del_object->line->x[1]);
434 final2 = max(temp1, temp2);
436 object->line->x[0] = final1;
437 object->line->x[1] = final2;
438 changed = 1;
441 if (orient == VERTICAL) {
442 temp1 = min(object->line->y[0], del_object->line->y[0]);
443 temp2 = min(object->line->y[1], del_object->line->y[1]);
445 final1 = min(temp1, temp2);
447 temp1 = max(object->line->y[0], del_object->line->y[0]);
448 temp2 = max(object->line->y[1], del_object->line->y[1]);
450 final2 = max(temp1, temp2);
452 object->line->y[0] = final1;
453 object->line->y[1] = final2;
454 changed = 1;
456 #if DEBUG
457 printf("fo %d %d %d %d\n", object->line->x[0], object->line->y[0],
458 object->line->x[1], object->line->y[1]);
459 #endif
461 /* Move any attributes from the deleted object*/
462 if (changed && del_object->attribs != NULL) {
464 /* Reassign the attached_to pointer on attributes from the del object */
465 a_iter = del_object->attribs;
466 while (a_iter != NULL) {
467 a_current = a_iter->data;
468 a_current->attached_to = object;
469 a_iter = g_list_next (a_iter);
472 object->attribs = g_list_concat (object->attribs, del_object->attribs);
474 /* Don't free del_object->attribs as it's relinked into object's list */
475 del_object->attribs = NULL;
479 /*! \brief Check if there's a midpoint connection at (x,y)
480 * \par Function Description
481 * This function checks if the \a object is connected to another net
482 * between it's endpoints. Net segment's only can be merged if there
483 * is no midpoint connection.
485 * \param object a net OBJECT to check
486 * \param x x-coord of the connection location
487 * \param y y-coord of the connection location
488 * \return TRUE if there's no midpoint connection, else return FALSE
490 static int o_net_consolidate_nomidpoint (OBJECT *object, int x, int y)
492 GList *c_current;
493 CONN *conn;
495 c_current = object->conn_list;
496 while(c_current != NULL) {
497 conn = (CONN *) c_current->data;
498 if (conn->other_object) {
499 if (conn->other_object->sid != object->sid &&
500 conn->x == x && conn->y == y &&
501 conn->type == CONN_MIDPOINT) {
502 #if DEBUG
503 printf("Found one! %s\n", conn->other_object->name);
504 #endif
505 return(FALSE);
509 c_current = g_list_next(c_current);
512 return(TRUE);
515 /*! \brief try to consolidate a net object
516 * \par Function Description
517 * This function tries to consolidate a net with any other object
518 * that is connected to the current \a object.
520 * \param toplevel The TOPLEVEL object
521 * \param object The object to consolidate
522 * \return 0 if no consolidation was possible, -1 otherwise
525 static int o_net_consolidate_segments (TOPLEVEL *toplevel, OBJECT *object)
527 int object_orient;
528 int other_orient;
529 GList *c_current;
530 CONN *conn;
531 OBJECT *other_object;
532 int changed = 0;
534 if (object == NULL) {
535 return(0);
538 if (object->type != OBJ_NET) {
539 return(0);
542 object_orient = o_net_orientation(object);
544 c_current = object->conn_list;
545 while(c_current != NULL) {
546 conn = (CONN *) c_current->data;
547 other_object = conn->other_object;
549 /* only look at end points which have a valid end on the other side */
550 if (other_object != NULL && conn->type == CONN_ENDPOINT &&
551 conn->other_whichone != -1 && conn->whichone != -1 &&
552 o_net_consolidate_nomidpoint(object, conn->x, conn->y) ) {
554 if (other_object->type == OBJ_NET) {
555 other_orient = o_net_orientation(other_object);
557 /* - both objects have the same orientation (either vert or horiz) */
558 /* - it's not the same object */
559 if (object_orient == other_orient &&
560 object->sid != other_object->sid &&
561 other_orient != NEITHER) {
563 #if DEBUG
564 printf("consolidating %s to %s\n", object->name, other_object->name);
565 #endif
567 o_net_consolidate_lowlevel(object, other_object, other_orient);
569 changed++;
570 if (other_object->selected == TRUE ) {
571 o_selection_remove (toplevel, toplevel->page_current->selection_list, other_object);
573 /* If we're consolidating with a selected object,
574 * ensure we select the resulting object.
576 if (object->selected == FALSE) {
577 o_selection_add (toplevel, toplevel->page_current->selection_list, object);
581 s_conn_remove_object (toplevel, other_object);
582 s_page_remove (toplevel, toplevel->page_current, other_object);
583 s_delete_object (toplevel, other_object);
584 o_net_recalc(toplevel, object);
585 s_tile_update_object(toplevel, object);
586 s_conn_update_object (toplevel, object);
587 return(-1);
593 c_current = g_list_next (c_current);
596 return(0);
599 /*! \brief consolidate all net objects
600 * \par Function Description
601 * This function consolidates all net objects until no more consolidations
602 * are posible.
604 * \param toplevel The TOPLEVEL object
607 void o_net_consolidate(TOPLEVEL *toplevel)
609 OBJECT *o_current;
610 const GList *iter;
611 int status = 0;
613 iter = s_page_objects (toplevel->page_current);
615 while (iter != NULL) {
616 o_current = (OBJECT *)iter->data;
618 if (o_current->type == OBJ_NET) {
619 status = o_net_consolidate_segments(toplevel, o_current);
622 if (status == -1) {
623 iter = s_page_objects (toplevel->page_current);
624 status = 0;
625 } else {
626 iter = g_list_next (iter);
631 /*! \brief modify one point of a net object
632 * \par Function Description
633 * This function modifies one point of a net \a object. The point
634 * is specified by the \a whichone variable and the new coordinate
635 * is (\a x, \a y).
637 * \param toplevel The TOPLEVEL object
638 * \param object The net OBJECT to modify
639 * \param x new x-coord of the net point
640 * \param y new y-coord of the net point
641 * \param whichone net point to modify
644 void o_net_modify(TOPLEVEL *toplevel, OBJECT *object,
645 int x, int y, int whichone)
647 object->line->x[whichone] = x;
648 object->line->y[whichone] = y;
650 o_net_recalc (toplevel, object);
652 s_tile_update_object(toplevel, object);