libgeda

o_net_basic.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * libgeda - gEDA's library
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 #include <config.h>
00021 
00022 #include <stdio.h>
00023 #include <math.h>
00024 
00025 #include "libgeda_priv.h"
00026 
00027 #ifdef HAVE_LIBDMALLOC
00028 #include <dmalloc.h>
00029 #endif
00030 
00045 gboolean o_net_get_position (TOPLEVEL *toplevel, gint *x, gint *y,
00046                               OBJECT *object)
00047 {
00048   return o_line_get_position(toplevel, x, y, object);
00049 }
00050 
00062 void world_get_net_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left,
00063                           int *top, int *right, int *bottom)
00064 {
00065   world_get_line_bounds( toplevel, object, left, top, right, bottom );
00066 }
00067 
00081 OBJECT *o_net_new(TOPLEVEL *toplevel, char type,
00082           int color, int x1, int y1, int x2, int y2)
00083 {
00084   OBJECT *new_node;
00085 
00086   new_node = s_basic_new_object(type, "net");
00087   new_node->color = color;
00088 
00089   new_node->line = (LINE *) g_malloc(sizeof(LINE));
00090   /* check for null */
00091 
00092   new_node->line->x[0] = x1;
00093   new_node->line->y[0] = y1;
00094   new_node->line->x[1] = x2;
00095   new_node->line->y[1] = y2;
00096   new_node->line_width = NET_WIDTH;
00097 
00098   o_net_recalc (toplevel, new_node);
00099 
00100   return new_node;
00101 }
00102 
00111 void o_net_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
00112 {
00113   int left, right, top, bottom;
00114 
00115   if (o_current == NULL) {
00116     return;
00117   }
00118 
00119   if (o_current->line == NULL) {
00120     return;
00121   }
00122 
00123   world_get_net_bounds(toplevel, o_current, &left, &top, &right,
00124                  &bottom);
00125 
00126   o_current->w_left = left;
00127   o_current->w_top = top;
00128   o_current->w_right = right;
00129   o_current->w_bottom = bottom;
00130   o_current->w_bounds_valid = TRUE;
00131 }
00132 
00146 OBJECT *o_net_read (TOPLEVEL *toplevel, const char buf[],
00147                     unsigned int release_ver, unsigned int fileformat_ver, GError **err)
00148 {
00149   OBJECT *new_obj;
00150   char type;
00151   int x1, y1;
00152   int x2, y2;
00153   int color;
00154 
00155   if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
00156         g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse net object"));
00157     return NULL;
00158   }
00159 
00160   if (x1 == x2 && y1 == y2) {
00161     s_log_message (_("Found a zero length net [ %c %d %d %d %d %d ]\n"),
00162                    type, x1, y1, x2, y2, color);
00163   }
00164 
00165 
00166   if (toplevel->override_net_color != -1) {
00167     color = toplevel->override_net_color;
00168   }
00169 
00170   if (color < 0 || color > MAX_COLORS) {
00171     s_log_message (_("Found an invalid color [ %s ]\n"), buf);
00172     s_log_message (_("Setting color to default color\n"));
00173     color = DEFAULT_COLOR;
00174   }
00175 
00176   new_obj = o_net_new (toplevel, type, color, x1, y1, x2, y2);
00177 
00178   return new_obj;
00179 }
00180 
00190 char *o_net_save(TOPLEVEL *toplevel, OBJECT *object)
00191 {
00192   int x1, x2, y1, y2;
00193   char *buf;
00194 
00195   x1 = object->line->x[0];
00196   y1 = object->line->y[0];
00197   x2 = object->line->x[1];
00198   y2 = object->line->y[1];
00199 
00200   buf = g_strdup_printf("%c %d %d %d %d %d", object->type, x1, y1, x2, y2, object->color);
00201   return (buf);
00202 }
00203 
00214 void o_net_translate_world(TOPLEVEL *toplevel, int dx, int dy,
00215                OBJECT *object)
00216 {
00217   /* Update world coords */
00218   object->line->x[0] = object->line->x[0] + dx;
00219   object->line->y[0] = object->line->y[0] + dy;
00220   object->line->x[1] = object->line->x[1] + dx;
00221   object->line->y[1] = object->line->y[1] + dy;
00222 
00223   /* Update bounding box */
00224   o_net_recalc (toplevel, object);
00225 
00226   s_tile_update_object(toplevel, object);
00227 }
00228 
00237 OBJECT *o_net_copy(TOPLEVEL *toplevel,  OBJECT *o_current)
00238 {
00239   OBJECT *new_obj;
00240 
00241   /* make sure you fix this in pin and bus as well */
00242   /* still doesn't work... you need to pass in the new values */
00243   /* or don't update and update later */
00244   /* I think for now I'll disable the update and manually update */
00245   new_obj = o_net_new (toplevel, OBJ_NET, o_current->color,
00246                        o_current->line->x[0], o_current->line->y[0],
00247                        o_current->line->x[1], o_current->line->y[1]);
00248 
00249   return new_obj;
00250 }
00251 
00263 void o_net_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
00264          int origin_x, int origin_y)
00265 {
00266   int net_width;
00267   int x1, y1;
00268   int x2, y2;
00269 
00270   if (o_current == NULL) {
00271     printf("got null in o_net_print\n");
00272     return;
00273   }
00274 
00275   f_print_set_color(toplevel, fp, o_current->color);
00276 
00277   net_width = 2;
00278   if (toplevel->net_style == THICK) {
00279     net_width = NET_WIDTH;
00280   }
00281 
00282   x1 = o_current->line->x[0] - origin_x,
00283   y1 = o_current->line->y[0] - origin_y;
00284   x2 = o_current->line->x[1] - origin_x,
00285   y2 = o_current->line->y[1] - origin_y;
00286 
00287   fprintf(fp, "%d %d %d %d %d line\n", x1,y1,x2,y2,net_width);
00288 }
00289 
00290 
00303 void o_net_rotate_world(TOPLEVEL *toplevel,
00304             int world_centerx, int world_centery, int angle,
00305             OBJECT *object)
00306 {
00307   int newx, newy;
00308 
00309   if (angle == 0)
00310     return;
00311 
00312   /* translate object to origin */
00313   o_net_translate_world(toplevel, -world_centerx, -world_centery,
00314                         object);
00315 
00316   rotate_point_90(object->line->x[0], object->line->y[0], angle,
00317                   &newx, &newy);
00318 
00319   object->line->x[0] = newx;
00320   object->line->y[0] = newy;
00321 
00322   rotate_point_90(object->line->x[1], object->line->y[1], angle,
00323                   &newx, &newy);
00324 
00325   object->line->x[1] = newx;
00326   object->line->y[1] = newy;
00327 
00328   o_net_translate_world(toplevel, world_centerx, world_centery, object);
00329 }
00330 
00341 void o_net_mirror_world(TOPLEVEL *toplevel, int world_centerx,
00342             int world_centery, OBJECT *object)
00343 {
00344   /* translate object to origin */
00345   o_net_translate_world(toplevel, -world_centerx, -world_centery,
00346                         object);
00347 
00348   object->line->x[0] = -object->line->x[0];
00349 
00350   object->line->x[1] = -object->line->x[1];
00351 
00352   o_net_translate_world(toplevel, world_centerx, world_centery, object);
00353 }
00354 
00362 int o_net_orientation(OBJECT *object)
00363 {
00364     if (object->line->y[0] == object->line->y[1]) {
00365     return (HORIZONTAL);
00366     }
00367 
00368     if (object->line->x[0] == object->line->x[1]) {
00369     return (VERTICAL);
00370     }
00371 
00372     return (NEITHER);
00373 }
00374 
00375 
00390 static void o_net_consolidate_lowlevel (OBJECT *object,
00391                                         OBJECT *del_object, int orient)
00392 {
00393   int temp1, temp2;
00394   int final1, final2;
00395   int changed = 0;
00396   GList *a_iter;
00397   OBJECT *a_current;
00398 
00399 #if DEBUG
00400   printf("o %d %d %d %d\n", object->line->x[0], object->line->y[0],
00401          object->line->x[1], object->line->y[1]);
00402   printf("d %d %d %d %d\n", del_object->line->x[0],
00403          del_object->line->y[0], del_object->line->x[1],
00404          del_object->line->y[1]);
00405 #endif
00406 
00407 
00408   if (orient == HORIZONTAL) {
00409 
00410     temp1 = min(object->line->x[0], del_object->line->x[0]);
00411     temp2 = min(object->line->x[1], del_object->line->x[1]);
00412 
00413     final1 = min(temp1, temp2);
00414 
00415     temp1 = max(object->line->x[0], del_object->line->x[0]);
00416     temp2 = max(object->line->x[1], del_object->line->x[1]);
00417 
00418     final2 = max(temp1, temp2);
00419 
00420     object->line->x[0] = final1;
00421     object->line->x[1] = final2;
00422     changed = 1;
00423   }
00424 
00425   if (orient == VERTICAL) {
00426     temp1 = min(object->line->y[0], del_object->line->y[0]);
00427     temp2 = min(object->line->y[1], del_object->line->y[1]);
00428 
00429     final1 = min(temp1, temp2);
00430 
00431     temp1 = max(object->line->y[0], del_object->line->y[0]);
00432     temp2 = max(object->line->y[1], del_object->line->y[1]);
00433 
00434     final2 = max(temp1, temp2);
00435 
00436     object->line->y[0] = final1;
00437     object->line->y[1] = final2;
00438     changed = 1;
00439   }
00440 #if DEBUG
00441   printf("fo %d %d %d %d\n", object->line->x[0], object->line->y[0],
00442          object->line->x[1], object->line->y[1]);
00443 #endif
00444 
00445   /* Move any attributes from the deleted object*/
00446   if (changed && del_object->attribs != NULL) {
00447 
00448     /* Reassign the attached_to pointer on attributes from the del object */
00449     a_iter = del_object->attribs;
00450     while (a_iter != NULL) {
00451       a_current = a_iter->data;
00452       a_current->attached_to = object;
00453       a_iter = g_list_next (a_iter);
00454     }
00455 
00456     object->attribs = g_list_concat (object->attribs, del_object->attribs);
00457 
00458     /* Don't free del_object->attribs as it's relinked into object's list */
00459     del_object->attribs = NULL;
00460   }
00461 }
00462 
00474 static int o_net_consolidate_nomidpoint (OBJECT *object, int x, int y)
00475 {
00476   GList *c_current;
00477   CONN *conn;
00478 
00479   c_current = object->conn_list;
00480   while(c_current != NULL) {
00481     conn = (CONN *) c_current->data;
00482     if (conn->other_object) {
00483       if (conn->other_object->sid != object->sid &&
00484           conn->x == x && conn->y == y &&
00485           conn->type == CONN_MIDPOINT) {
00486 #if DEBUG        
00487         printf("Found one! %s\n", conn->other_object->name); 
00488 #endif         
00489         return(FALSE);
00490       }
00491     }
00492     
00493     c_current = g_list_next(c_current);
00494   }
00495 
00496   return(TRUE);
00497 }
00498 
00509 static int o_net_consolidate_segments (TOPLEVEL *toplevel, OBJECT *object)
00510 {
00511   int object_orient;
00512   int other_orient;
00513   GList *c_current;
00514   CONN *conn;
00515   OBJECT *other_object;
00516   PAGE *page;
00517   int changed = 0;
00518 
00519   g_return_val_if_fail ((toplevel != NULL), 0);
00520   g_return_val_if_fail ((object != NULL), 0);
00521   g_return_val_if_fail ((object->type == OBJ_NET), 0);
00522 
00523   /* It's meaningless to do anything here if the object isn't in a page. */
00524   page = o_get_page (toplevel, object);
00525   g_return_val_if_fail ((page != NULL), 0);
00526 
00527   object_orient = o_net_orientation(object);
00528 
00529   c_current = object->conn_list;
00530   while(c_current != NULL) {
00531     conn = (CONN *) c_current->data;
00532     other_object = conn->other_object;
00533 
00534     /* only look at end points which have a valid end on the other side */
00535     if (other_object != NULL && conn->type == CONN_ENDPOINT &&
00536         conn->other_whichone != -1 && conn->whichone != -1 &&
00537         o_net_consolidate_nomidpoint(object, conn->x, conn->y) ) {
00538 
00539       if (other_object->type == OBJ_NET) {
00540         other_orient = o_net_orientation(other_object);
00541 
00542         /* - both objects have the same orientation (either vert or horiz) */
00543         /* - it's not the same object */
00544         if (object_orient == other_orient &&
00545             object->sid != other_object->sid &&
00546             other_orient != NEITHER) {
00547 
00548 #if DEBUG
00549           printf("consolidating %s to %s\n", object->name, other_object->name);
00550 #endif
00551 
00552           o_net_consolidate_lowlevel(object, other_object, other_orient);
00553 
00554           changed++;
00555           if (other_object->selected == TRUE ) {
00556             o_selection_remove (toplevel, page->selection_list, other_object);
00557 
00558             /* If we're consolidating with a selected object,
00559              * ensure we select the resulting object.
00560              */
00561             if (object->selected == FALSE) {
00562               o_selection_add (toplevel, page->selection_list, object);
00563             }
00564           }
00565 
00566           s_delete_object (toplevel, other_object);
00567           o_net_recalc(toplevel, object);
00568           s_tile_update_object(toplevel, object);
00569           s_conn_update_object (toplevel, object);
00570           return(-1);
00571         }
00572       }
00573       
00574     }
00575 
00576     c_current = g_list_next (c_current);
00577   }
00578 
00579   return(0);
00580 }
00581 
00590 void o_net_consolidate(TOPLEVEL *toplevel, PAGE *page)
00591 {
00592   OBJECT *o_current;
00593   const GList *iter;
00594   int status = 0;
00595 
00596   g_return_if_fail (toplevel != NULL);
00597   g_return_if_fail (page != NULL);
00598 
00599   iter = s_page_objects (page);
00600 
00601   while (iter != NULL) {
00602     o_current = (OBJECT *)iter->data;
00603 
00604     if (o_current->type == OBJ_NET) {
00605       status = o_net_consolidate_segments(toplevel, o_current);
00606     }
00607 
00608     if (status == -1) {
00609       iter = s_page_objects (page);
00610       status = 0;
00611     } else {
00612       iter = g_list_next (iter);
00613     }
00614   }
00615 }
00616 
00630 void o_net_modify(TOPLEVEL *toplevel, OBJECT *object,
00631           int x, int y, int whichone)
00632 {
00633   object->line->x[whichone] = x;
00634   object->line->y[whichone] = y;
00635 
00636   o_net_recalc (toplevel, object);
00637 
00638   s_tile_update_object(toplevel, object);
00639 }
00640 
00661 void o_net_refresh_conn_cache(TOPLEVEL *toplevel, OBJECT *o_current)
00662 {
00663   gint            num_conns = 0;
00664   GHashTable     *visited;
00665   GHashTableIter  iter;
00666   GList          *stack = NULL;
00667   OBJECT         *obj;
00668   gpointer       key;
00669 
00670   g_return_if_fail (toplevel);
00671   g_return_if_fail (o_current);
00672   g_return_if_fail (o_current->type == OBJ_NET);
00673 
00674   /* Keep track of visited nets, pins and buses in the hash table.
00675    * This way we short-circuit the search and avoid loops.
00676    */
00677   visited = g_hash_table_new (NULL, NULL);
00678 
00679   /*
00680    * Add the starting net to the hash so:
00681    *   1. it is not traversed twice
00682    *   2. it is updated at the end if no connections are found
00683    */
00684   g_hash_table_insert (visited, o_current, o_current);
00685 
00686   /* Check if a netname= is attached to the starting net segment */
00687   if (NULL != o_attrib_search_object_attribs_by_name (o_current,
00688                                                       "netname",
00689                                                       0)) {
00690     num_conns += 1;
00691   }
00692 
00693   /* Keep track of connections to search at each net segment in a stack.
00694    * Each stack entry points to an entry in obj->conn_list.
00695    * Pop the stack when we have no more connections to check.
00696    * Push next entry on the stack if we encounter a net segment.
00697    */
00698 
00699   /* Initialise the stack for the starting net segment. */
00700   stack = g_list_prepend (stack, o_current->conn_list);
00701 
00702   while (stack != NULL) {
00703     /* At start of the loop, take a new connection from the stack. */
00704     GList *conn_list = (GList*) stack->data;
00705     CONN *conn;
00706 
00707     if (conn_list == NULL) {
00708       /* No more connections to check at this level. Pop the stack. */
00709       stack = g_list_delete_link (stack, stack);
00710       continue;
00711     }
00712 
00713     /* Extract the next connected object and advance the connection list. */
00714     conn = (CONN*) conn_list->data;
00715     stack->data = (gpointer) g_list_next (conn_list);
00716 
00717     if (conn == NULL)
00718         /* should not happen */
00719         continue;
00720     obj = conn->other_object;
00721     if (obj == NULL)
00722         /* should not happen */
00723         continue;
00724 
00725     /* Act upon the object that is connected to the segment. */
00726     switch (obj->type) {
00727       case OBJ_PIN:
00728       case OBJ_BUS:
00729         if (NULL == g_hash_table_lookup (visited, obj)) {
00730           g_hash_table_insert (visited, obj, obj);
00731           num_conns += 1;
00732         }
00733         break;
00734       case OBJ_NET:
00735         if (NULL == g_hash_table_lookup (visited, obj)) {
00736           g_hash_table_insert (visited, obj, obj);
00737           /* Check if a netname= is attached to this net segment */
00738           if (NULL != o_attrib_search_object_attribs_by_name (obj,
00739                                                               "netname",
00740                                                               0)) {
00741             num_conns += 1;
00742           }
00743           /* Push new list of connections to check onto the stack */
00744           stack = g_list_prepend (stack, obj->conn_list);
00745         }
00746         break;
00747       default:
00748         break;
00749     }
00750   }
00751 
00752   /* Cache value of num_conns in all visited objects */
00753   g_hash_table_iter_init (&iter, visited);
00754 
00755   while (g_hash_table_iter_next (&iter, &key, NULL)) {
00756     obj = (OBJECT*) key;
00757     if (obj->type == OBJ_NET) {
00758       obj->net_num_connected = num_conns;
00759       obj->valid_num_connected = TRUE;
00760     }
00761   }
00762 
00763   g_hash_table_destroy (visited);
00764   g_list_free (stack);
00765 }
00766 
00779 gboolean o_net_is_fully_connected (TOPLEVEL *toplevel,
00780                                    OBJECT   *o_current)
00781 {
00782   g_return_val_if_fail (toplevel, FALSE);
00783   g_return_val_if_fail (o_current, FALSE);
00784   g_return_val_if_fail (o_current->type == OBJ_NET, FALSE);
00785 
00786   if (!o_current->valid_num_connected)
00787     o_net_refresh_conn_cache (toplevel, o_current);
00788 
00789   g_return_val_if_fail (o_current->valid_num_connected, FALSE);
00790 
00791   return o_current->net_num_connected > 1 ? TRUE : FALSE;
00792 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines