Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / libgeda / src / o_net_basic.c
blobc2c5af1d9205b20ba1c621d1754f9c09f7d21da4
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] object_list list of OBJECTS to append a new net
152 * \param [in] buf a text buffer (usually a line of a schematic file)
153 * \param [in] release_ver The release number gEDA
154 * \param [in] fileformat_ver a integer value of the file format
155 * \return The object list
158 OBJECT *o_net_read (TOPLEVEL *toplevel, char buf[],
159 unsigned int release_ver, unsigned int fileformat_ver)
161 OBJECT *new_obj;
162 char type;
163 int x1, y1;
164 int x2, y2;
165 int color;
167 sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color);
169 if (x1 == x2 && y1 == y2) {
170 s_log_message (_("Found a zero length net [ %c %d %d %d %d %d ]\n"),
171 type, x1, y1, x2, y2, color);
175 if (toplevel->override_net_color != -1) {
176 color = toplevel->override_net_color;
179 if (color < 0 || color > MAX_COLORS) {
180 s_log_message (_("Found an invalid color [ %s ]\n"), buf);
181 s_log_message (_("Setting color to default color\n"));
182 color = DEFAULT_COLOR;
185 new_obj = o_net_new (toplevel, type, color, x1, y1, x2, y2);
187 return new_obj;
190 /*! \brief Create a string representation of the net object
191 * \par Function Description
192 * This function takes a net \a object and return a string
193 * according to the file format definition.
195 * \param [in] object a net OBJECT
196 * \return the string representation of the net OBJECT
198 char *o_net_save(OBJECT *object)
200 int x1, x2, y1, y2;
201 char *buf;
203 x1 = object->line->x[0];
204 y1 = object->line->y[0];
205 x2 = object->line->x[1];
206 y2 = object->line->y[1];
208 buf = g_strdup_printf("%c %d %d %d %d %d", object->type, x1, y1, x2, y2, object->color);
209 return (buf);
212 /*! \brief move a net object
213 * \par Function Description
214 * This function changes the position of a net \a object.
216 * \param [in] toplevel The TOPLEVEL object
217 * \param [in] dx The x-distance to move the object
218 * \param [in] dy The y-distance to move the object
219 * \param [in] object The net OBJECT to be moved
222 void o_net_translate_world(TOPLEVEL *toplevel, int dx, int dy,
223 OBJECT *object)
225 if (object == NULL)
226 printf("ntw NO!\n");
228 /* Update world coords */
229 object->line->x[0] = object->line->x[0] + dx;
230 object->line->y[0] = object->line->y[0] + dy;
231 object->line->x[1] = object->line->x[1] + dx;
232 object->line->y[1] = object->line->y[1] + dy;
234 /* Update bounding box */
235 o_net_recalc (toplevel, object);
237 s_tile_update_object(toplevel, object);
240 /*! \brief create a copy of a net object
241 * \par Function Description
242 * This function creates a copy of the net object \a o_current.
244 * \param [in] toplevel The TOPLEVEL object
245 * \param [in] o_current The object that is copied
246 * \return a new net object
248 OBJECT *o_net_copy(TOPLEVEL *toplevel, OBJECT *o_current)
250 OBJECT *new_obj;
252 /* make sure you fix this in pin and bus as well */
253 /* still doesn't work... you need to pass in the new values */
254 /* or don't update and update later */
255 /* I think for now I'll disable the update and manually update */
256 new_obj = o_net_new (toplevel, OBJ_NET, o_current->color,
257 o_current->line->x[0], o_current->line->y[0],
258 o_current->line->x[1], o_current->line->y[1]);
260 return new_obj;
263 /*! \brief postscript print command for a net object
264 * \par Function Description
265 * This function writes the postscript command of the net object \a o_current
266 * into the FILE \a fp points to.
268 * \param [in] toplevel The TOPLEVEL object
269 * \param [in] fp pointer to a FILE structure
270 * \param [in] o_current The OBJECT to print
271 * \param [in] origin_x x-coord of the postscript origin
272 * \param [in] origin_y y-coord of the postscript origin
274 void o_net_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
275 int origin_x, int origin_y)
277 int offset, offset2;
278 int cross, net_width;
279 int x1, y1;
280 int x2, y2;
282 if (o_current == NULL) {
283 printf("got null in o_net_print\n");
284 return;
287 offset = 7 * 6;
288 offset2 = 7;
290 cross = offset;
292 f_print_set_color(toplevel, fp, o_current->color);
294 net_width = 2;
295 if (toplevel->net_style == THICK) {
296 net_width = NET_WIDTH;
299 x1 = o_current->line->x[0] - origin_x,
300 y1 = o_current->line->y[0] - origin_y;
301 x2 = o_current->line->x[1] - origin_x,
302 y2 = o_current->line->y[1] - origin_y;
304 fprintf(fp, "%d %d %d %d %d line\n", x1,y1,x2,y2,net_width);
308 /*! \brief rotate a net object around a centerpoint
309 * \par Function Description
310 * This function rotates a net \a object around the point
311 * (\a world_centerx, \a world_centery).
313 * \param [in] toplevel The TOPLEVEL object
314 * \param [in] world_centerx x-coord of the rotation center
315 * \param [in] world_centery y-coord of the rotation center
316 * \param [in] angle The angle to rotat the net object
317 * \param [in] object The net object
318 * \note only steps of 90 degrees are allowed for the \a angle
320 void o_net_rotate_world(TOPLEVEL *toplevel,
321 int world_centerx, int world_centery, int angle,
322 OBJECT *object)
324 int newx, newy;
326 if (angle == 0)
327 return;
329 /* translate object to origin */
330 o_net_translate_world(toplevel, -world_centerx, -world_centery,
331 object);
333 rotate_point_90(object->line->x[0], object->line->y[0], angle,
334 &newx, &newy);
336 object->line->x[0] = newx;
337 object->line->y[0] = newy;
339 rotate_point_90(object->line->x[1], object->line->y[1], angle,
340 &newx, &newy);
342 object->line->x[1] = newx;
343 object->line->y[1] = newy;
345 o_net_translate_world(toplevel, world_centerx, world_centery, object);
348 /*! \brief mirror a net object horizontaly at a centerpoint
349 * \par Function Description
350 * This function mirrors a net \a object horizontaly at the point
351 * (\a world_centerx, \a world_centery).
353 * \param [in] toplevel The TOPLEVEL object
354 * \param [in] world_centerx x-coord of the mirror position
355 * \param [in] world_centery y-coord of the mirror position
356 * \param [in] object The net object
358 void o_net_mirror_world(TOPLEVEL *toplevel, int world_centerx,
359 int world_centery, OBJECT *object)
361 /* translate object to origin */
362 o_net_translate_world(toplevel, -world_centerx, -world_centery,
363 object);
365 object->line->x[0] = -object->line->x[0];
367 object->line->x[1] = -object->line->x[1];
369 o_net_translate_world(toplevel, world_centerx, world_centery, object);
372 /*! \brief calculate the orientation of a net object
373 * \par Function Description
374 * This function calculates the orientation of a net object.
376 * \param [in] object The net object
377 * \return The orientation: HORIZONTAL, VERTICAL or NEITHER
379 int o_net_orientation(OBJECT *object)
381 if (object->line->y[0] == object->line->y[1]) {
382 return (HORIZONTAL);
385 if (object->line->x[0] == object->line->x[1]) {
386 return (VERTICAL);
389 return (NEITHER);
393 /*! \brief merge two net object
394 * \par Function Description
395 * This function does the actual work of making one net segment out of two
396 * connected segments. The first net segment is extended to the lenght of
397 * both objects.
398 * The second object (\a del_object) is the object that should be deleted.
400 * \param [in] object A net object to extend
401 * \param [in] del_object A net object to be merged into \a object
402 * \param [in] orient The orientation of both net objects
404 * \note The first net \a object gets the attributes of the second net
405 * \a del_object if the two nets are merged together.
407 static void o_net_consolidate_lowlevel (OBJECT *object,
408 OBJECT *del_object, int orient)
410 int temp1, temp2;
411 int final1, final2;
412 int changed = 0;
413 GList *a_iter;
414 OBJECT *a_current;
416 #if DEBUG
417 printf("o %d %d %d %d\n", object->line->x[0], object->line->y[0],
418 object->line->x[1], object->line->y[1]);
419 printf("d %d %d %d %d\n", del_object->line->x[0],
420 del_object->line->y[0], del_object->line->x[1],
421 del_object->line->y[1]);
422 #endif
425 if (orient == HORIZONTAL) {
427 temp1 = min(object->line->x[0], del_object->line->x[0]);
428 temp2 = min(object->line->x[1], del_object->line->x[1]);
430 final1 = min(temp1, temp2);
432 temp1 = max(object->line->x[0], del_object->line->x[0]);
433 temp2 = max(object->line->x[1], del_object->line->x[1]);
435 final2 = max(temp1, temp2);
437 object->line->x[0] = final1;
438 object->line->x[1] = final2;
439 changed = 1;
442 if (orient == VERTICAL) {
443 temp1 = min(object->line->y[0], del_object->line->y[0]);
444 temp2 = min(object->line->y[1], del_object->line->y[1]);
446 final1 = min(temp1, temp2);
448 temp1 = max(object->line->y[0], del_object->line->y[0]);
449 temp2 = max(object->line->y[1], del_object->line->y[1]);
451 final2 = max(temp1, temp2);
453 object->line->y[0] = final1;
454 object->line->y[1] = final2;
455 changed = 1;
457 #if DEBUG
458 printf("fo %d %d %d %d\n", object->line->x[0], object->line->y[0],
459 object->line->x[1], object->line->y[1]);
460 #endif
462 /* Move any attributes from the deleted object*/
463 if (changed && del_object->attribs != NULL) {
465 /* Reassign the attached_to pointer on attributes from the del object */
466 a_iter = del_object->attribs;
467 while (a_iter != NULL) {
468 a_current = a_iter->data;
469 a_current->attached_to = object;
470 a_iter = g_list_next (a_iter);
473 object->attribs = g_list_concat (object->attribs, del_object->attribs);
475 /* Don't free del_object->attribs as it's relinked into object's list */
476 del_object->attribs = NULL;
480 /*! \brief Check if there's a midpoint connection at (x,y)
481 * \par Function Description
482 * This function checks if the \a object is connected to another net
483 * between it's endpoints. Net segment's only can be merged if there
484 * is no midpoint connection.
486 * \param object a net OBJECT to check
487 * \param x x-coord of the connection location
488 * \param y y-coord of the connection location
489 * \return TRUE if there's no midpoint connection, else return FALSE
491 static int o_net_consolidate_nomidpoint (OBJECT *object, int x, int y)
493 GList *c_current;
494 CONN *conn;
496 c_current = object->conn_list;
497 while(c_current != NULL) {
498 conn = (CONN *) c_current->data;
499 if (conn->other_object) {
500 if (conn->other_object->sid != object->sid &&
501 conn->x == x && conn->y == y &&
502 conn->type == CONN_MIDPOINT) {
503 #if DEBUG
504 printf("Found one! %s\n", conn->other_object->name);
505 #endif
506 return(FALSE);
510 c_current = g_list_next(c_current);
513 return(TRUE);
516 /*! \brief try to consolidate a net object
517 * \par Function Description
518 * This function tries to consolidate a net with any other object
519 * that is connected to the current \a object.
521 * \param toplevel The TOPLEVEL object
522 * \param object The object to consolidate
523 * \return 0 if no consolidation was possible, -1 otherwise
526 static int o_net_consolidate_segments (TOPLEVEL *toplevel, OBJECT *object)
528 int object_orient;
529 int other_orient;
530 GList *c_current;
531 CONN *conn;
532 OBJECT *other_object;
533 int changed = 0;
535 if (object == NULL) {
536 return(0);
539 if (object->type != OBJ_NET) {
540 return(0);
543 object_orient = o_net_orientation(object);
545 c_current = object->conn_list;
546 while(c_current != NULL) {
547 conn = (CONN *) c_current->data;
548 other_object = conn->other_object;
550 /* only look at end points which have a valid end on the other side */
551 if (other_object != NULL && conn->type == CONN_ENDPOINT &&
552 conn->other_whichone != -1 && conn->whichone != -1 &&
553 o_net_consolidate_nomidpoint(object, conn->x, conn->y) ) {
555 if (other_object->type == OBJ_NET) {
556 other_orient = o_net_orientation(other_object);
558 /* - both objects have the same orientation (either vert or horiz) */
559 /* - it's not the same object */
560 if (object_orient == other_orient &&
561 object->sid != other_object->sid &&
562 other_orient != NEITHER) {
564 #if DEBUG
565 printf("consolidating %s to %s\n", object->name, other_object->name);
566 #endif
568 o_net_consolidate_lowlevel(object, other_object, other_orient);
570 changed++;
571 if (other_object->selected == TRUE ) {
572 o_selection_remove (toplevel, toplevel->page_current->selection_list, other_object);
574 /* If we're consolidating with a selected object,
575 * ensure we select the resulting object.
577 if (object->selected == FALSE) {
578 o_selection_add (toplevel, toplevel->page_current->selection_list, object);
582 s_conn_remove_object (toplevel, other_object);
583 s_page_remove (toplevel, toplevel->page_current, other_object);
584 s_delete_object (toplevel, other_object);
585 o_net_recalc(toplevel, object);
586 s_tile_update_object(toplevel, object);
587 s_conn_update_object (toplevel, object);
588 return(-1);
594 c_current = g_list_next (c_current);
597 return(0);
600 /*! \brief consolidate all net objects
601 * \par Function Description
602 * This function consolidates all net objects until no more consolidations
603 * are posible.
605 * \param toplevel The TOPLEVEL object
608 void o_net_consolidate(TOPLEVEL *toplevel)
610 OBJECT *o_current;
611 const GList *iter;
612 int status = 0;
614 iter = s_page_objects (toplevel->page_current);
616 while (iter != NULL) {
617 o_current = (OBJECT *)iter->data;
619 if (o_current->type == OBJ_NET) {
620 status = o_net_consolidate_segments(toplevel, o_current);
623 if (status == -1) {
624 iter = s_page_objects (toplevel->page_current);
625 status = 0;
626 } else {
627 iter = g_list_next (iter);
632 /*! \brief modify one point of a net object
633 * \par Function Description
634 * This function modifies one point of a net \a object. The point
635 * is specified by the \a whichone variable and the new coordinate
636 * is (\a x, \a y).
638 * \param toplevel The TOPLEVEL object
639 * \param object The net OBJECT to modify
640 * \param x new x-coord of the net point
641 * \param y new y-coord of the net point
642 * \param whichone net point to modify
645 void o_net_modify(TOPLEVEL *toplevel, OBJECT *object,
646 int x, int y, int whichone)
648 object->line->x[whichone] = x;
649 object->line->y[whichone] = y;
651 o_net_recalc (toplevel, object);
653 s_tile_update_object(toplevel, object);