gschem

o_net.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * gschem - gEDA Schematic Capture
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2011 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 "gschem.h"
00026 
00027 #ifdef HAVE_LIBDMALLOC
00028 #include <dmalloc.h>
00029 #endif
00030 
00031 
00032 /* magnetic options */
00033 /* half size of the magnetic marker on the screen. */
00034 #define MAGNETIC_HALFSIZE 6
00035 
00036 /* define how far the cursor could be to activate magnetic */
00037 #define MAGNETIC_PIN_REACH 50 
00038 #define MAGNETIC_NET_REACH 20
00039 #define MAGNETIC_BUS_REACH 30
00040 
00041 /* weighting factors to tell that a pin is more important than a net */
00042 #define MAGNETIC_PIN_WEIGHT 5.0
00043 #define MAGNETIC_NET_WEIGHT 2.0
00044 #define MAGNETIC_BUS_WEIGHT 3.0
00045 
00046 /* Bit definitions for the four quardrants of the direction guessing */
00047 #define QUADRANT1  0x01
00048 #define QUADRANT2  0x02
00049 #define QUADRANT3  0x04
00050 #define QUADRANT4  0x08
00051 
00052 
00059 void o_net_reset(GSCHEM_TOPLEVEL *w_current) 
00060 {
00061   w_current->first_wx = w_current->first_wy = -1;
00062   w_current->second_wx = w_current->second_wy = -1;
00063   w_current->third_wx = w_current->third_wy = -1;
00064   w_current->magnetic_wx = w_current->magnetic_wy = -1;
00065   w_current->rubber_visible = 0;
00066 }
00067 
00073 void o_net_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
00074 {
00075   TOPLEVEL *toplevel = w_current->toplevel;
00076   int x1, y1, x2, y2;
00077   int size = 0;
00078 
00079 #if NET_DEBUG /* debug */
00080   char *tempstring;
00081   GdkFont *font;
00082 #endif
00083 
00084   if (o_current == NULL) {
00085     return;
00086   }
00087 
00088   if (o_current->line == NULL) {
00089     return;
00090   }
00091 
00092   /* reuse line's routine */
00093   if (!o_line_visible (w_current, o_current->line, &x1, &y1, &x2, &y2)) {
00094     return;
00095   }
00096 
00097   if (toplevel->net_style == THICK)
00098     size = NET_WIDTH;
00099 
00100   gschem_cairo_line (w_current, END_SQUARE, size, x1, y1, x2, y2);
00101   gschem_cairo_set_source_color (w_current,
00102                                  o_drawing_color (w_current, o_current));
00103   gschem_cairo_stroke (w_current, TYPE_SOLID, END_SQUARE, size, -1, -1);
00104 
00105   if (o_current->selected && w_current->draw_grips) {
00106     o_line_draw_grips (w_current, o_current);
00107   }
00108 }
00109 
00110 
00116 void o_net_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
00117 {
00118   int size = 0;
00119 
00120   if (o_current->line == NULL) {
00121     return;
00122   }
00123 
00124   if (w_current->toplevel->net_style == THICK)
00125     size = NET_WIDTH;
00126 
00127   gschem_cairo_line (w_current, END_NONE, size,
00128                      o_current->line->x[0] + dx, o_current->line->y[0] + dy,
00129                      o_current->line->x[1] + dx, o_current->line->y[1] + dy);
00130   gschem_cairo_set_source_color (w_current,
00131                                  x_color_lookup_dark (o_current->color));
00132   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, size, -1, -1);
00133 }
00134 
00140 void o_net_draw_stretch (GSCHEM_TOPLEVEL *w_current,
00141                          int dx, int dy, int whichone, OBJECT *o_current)
00142 {
00143   int dx1 = -1, dx2 = -1, dy1 = -1,dy2 = -1;
00144 
00145   if (o_current->line == NULL) {
00146     return;
00147   }
00148 
00149   if (whichone == 0) {
00150     dx1 = dx;
00151     dy1 = dy;
00152     dx2 = dy2 = 0;
00153   } else if (whichone == 1) {
00154     dx1 = dy1 = 0;
00155     dx2 = dx;
00156     dy2 = dy;
00157   } else {
00158     fprintf(stderr, _("Got an invalid which one in o_net_draw_stretch\n"));
00159   }
00160 
00161   gschem_cairo_line (w_current, END_NONE, 0,
00162                      o_current->line->x[0] + dx1, o_current->line->y[0] + dy1,
00163                      o_current->line->x[1] + dx2, o_current->line->y[1] + dy2);
00164 
00165   gschem_cairo_set_source_color (w_current,
00166                                  x_color_lookup_dark (o_current->color));
00167   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
00168 }
00169 
00170 
00180 void o_net_guess_direction(GSCHEM_TOPLEVEL *w_current,
00181                int wx, int wy)
00182 {
00183   TOPLEVEL *toplevel = w_current->toplevel;
00184   int up=0, down=0, left=0, right=0;
00185   int x1, y1, x2, y2;
00186   int xmin, ymin, xmax, ymax;
00187   int orientation;
00188   GList *objectlists, *iter1, *iter2;
00189   OBJECT *o_current;
00190 
00191   int *current_rules;
00192   /* badness values       {OVERWRITE, ORTHO, CONTINUE} */
00193   const int pin_rules[] = {100, 50, 0};
00194   const int bus_rules[] = {90, 0, 40};
00195   const int net_rules[] = {80, 30, 0};
00196   
00197   objectlists = s_tile_get_objectlists(toplevel, toplevel->page_current,
00198                                        wx, wy, wx, wy);
00199 
00200   for (iter1 = objectlists; iter1 != NULL; iter1 = g_list_next(iter1)) {
00201     for (iter2 = (GList*) iter1->data; iter2 != NULL; iter2 = g_list_next(iter2)) {
00202       o_current = (OBJECT*) iter2->data;
00203 
00204       if ((orientation = o_net_orientation(o_current)) == NEITHER)
00205     continue;
00206 
00207       switch (o_current->type) {
00208       case OBJ_NET:
00209     current_rules = (int*) net_rules;
00210     break;
00211       case OBJ_PIN:
00212     current_rules = (int*) pin_rules;
00213     break;
00214       case OBJ_BUS:
00215     current_rules = (int*) bus_rules;
00216     break;
00217       default:
00218     g_assert_not_reached ();
00219       }
00220       
00221       x1 = o_current->line->x[0];
00222       x2 = o_current->line->x[1];
00223       y1 = o_current->line->y[0];
00224       y2 = o_current->line->y[1];
00225       
00226       xmin = min(x1, x2);
00227       ymin = min(y1, y2);
00228       xmax = max(x1, x2);
00229       ymax = max(y1, y2);
00230       
00231       if (orientation == HORIZONTAL && wy == y1) {
00232     if (wx == xmin) {
00233       up = max(up, current_rules[1]);
00234       down = max(down, current_rules[1]);
00235       right = max(right, current_rules[0]);
00236       left = max(left, current_rules[2]);
00237     }
00238     else if (wx == xmax) {
00239       up = max(up, current_rules[1]);
00240       down = max(down, current_rules[1]);
00241       right = max(right, current_rules[2]);
00242       left = max(left, current_rules[0]);
00243     }
00244     else if (xmin < wx && wx < xmax) {
00245       up = max(up, current_rules[1]);
00246       down = max(down, current_rules[1]);
00247       right = max(right, current_rules[0]);
00248       left = max(left, current_rules[0]);
00249     }
00250     else {
00251       continue;
00252     }
00253       }
00254       if (orientation == VERTICAL && wx == x1) {
00255     if (wy == ymin) {
00256       up = max(up, current_rules[0]);
00257       down = max(down, current_rules[2]);
00258       right = max(right, current_rules[1]);
00259       left = max(left, current_rules[1]);
00260     }
00261     else if (wy == ymax) {
00262       up = max(up, current_rules[2]);
00263       down = max(down, current_rules[0]);
00264       right = max(right, current_rules[1]);
00265       left = max(left, current_rules[1]);
00266     }
00267     else if (ymin < wy && wy < ymax) {
00268       up = max(up, current_rules[0]);
00269       down = max(down, current_rules[0]);
00270       right = max(right, current_rules[1]);
00271       left = max(left, current_rules[1]);
00272     }
00273     else {
00274       continue;
00275     }
00276       }
00277     }
00278   }
00279   
00280   w_current->net_direction = 0;
00281   w_current->net_direction |= up >= right ? 0 : QUADRANT1;
00282   w_current->net_direction |= up >= left ? 0 : QUADRANT2;
00283   w_current->net_direction |= down >= left ? 0 : QUADRANT3;
00284   w_current->net_direction |= down >= right ? 0 : QUADRANT4;
00285 
00286 #if 0
00287   printf("o_net_guess_direction: up=%d down=%d left=%d right=%d direction=%d\n",
00288      up, down, left, right, w_current->net_direction);
00289 #endif
00290   g_list_free(objectlists);
00291 }
00292 
00303 void o_net_find_magnetic(GSCHEM_TOPLEVEL *w_current,
00304              int w_x, int w_y)
00305 {
00306   TOPLEVEL *toplevel = w_current->toplevel;
00307   int x1, x2, y1, y2, min_x, min_y, w_magnetic_reach;
00308   double mindist, minbest, dist1, dist2;
00309   double weight, min_weight;
00310   int magnetic_reach = 0;
00311   OBJECT *o_current;
00312   OBJECT *o_magnetic = NULL;
00313   GList *objectlists, *iter1, *iter2;
00314 
00315   minbest = min_x = min_y = 0;
00316   min_weight = 0;
00317 
00318   /* max distance of all the different reaches */
00319   magnetic_reach = max(MAGNETIC_PIN_REACH, MAGNETIC_NET_REACH);
00320   magnetic_reach = max(magnetic_reach, MAGNETIC_BUS_REACH);
00321   w_magnetic_reach = WORLDabs (w_current, magnetic_reach);
00322 
00323   /* get the objects of the tiles around the reach region */
00324   x1 = w_x - w_magnetic_reach;
00325   y1 = w_y - w_magnetic_reach;
00326   x2 = w_x + w_magnetic_reach;
00327   y2 = w_y + w_magnetic_reach;
00328   objectlists = s_tile_get_objectlists(toplevel, toplevel->page_current,
00329                                        x1, y1, x2, y2);
00330 
00331   for (iter1 = objectlists; iter1 != NULL; iter1 = g_list_next(iter1)) {
00332     for (iter2 = (GList*) iter1->data; iter2 != NULL; iter2 = g_list_next(iter2)) {
00333       o_current = (OBJECT*) iter2->data;
00334 
00335       if (!visible (w_current,  o_current->w_left, o_current->w_top,
00336            o_current->w_right, o_current->w_bottom))
00337     continue; /* skip invisible objects */
00338 
00339       if (o_current->type == OBJ_PIN) {
00340     min_x = o_current->line->x[o_current->whichend];
00341     min_y = o_current->line->y[o_current->whichend];
00342 
00343     mindist = sqrt((double) (w_x - min_x)*(w_x - min_x)
00344                + (double) (w_y - min_y)*(w_y - min_y));
00345     weight = mindist / MAGNETIC_PIN_WEIGHT;
00346       }
00347 
00348       else if (o_current->type == OBJ_NET
00349            || o_current->type == OBJ_BUS) {
00350     /* we have 3 possible points to connect: 
00351        2 endpoints and 1 midpoint point */
00352     x1 = o_current->line->x[0];
00353     y1 = o_current->line->y[0];
00354     x2 = o_current->line->x[1];
00355     y2 = o_current->line->y[1];
00356     /* endpoint tests */
00357     dist1 = sqrt((double) (w_x - x1)*(w_x - x1)
00358              + (double) (w_y - y1)*(w_y - y1));
00359     dist2 = sqrt((double) (w_x - x2)*(w_x - x2)
00360              + (double) (w_y - y2)*(w_y - y2));
00361     if (dist1 < dist2) {
00362       min_x = x1;
00363       min_y = y1;
00364       mindist = dist1;
00365     }
00366     else {
00367       min_x = x2;
00368       min_y = y2;
00369       mindist = dist2;
00370     }
00371       
00372     /* midpoint tests */
00373     if ((x1 == x2)  /* vertical net */
00374         && ((y1 >= w_y && w_y >= y2)
00375         || (y2 >= w_y && w_y >= y1))) {
00376       if (abs(w_x - x1) < mindist) {
00377         mindist = abs(w_x - x1);
00378         min_x = x1;
00379         min_y = w_y;
00380       }
00381     } 
00382     if ((y1 == y2)  /* horitontal net */
00383         && ((x1 >= w_x && w_x >= x2)
00384         || (x2 >= w_x && w_x >= x1))) {  
00385       if (abs(w_y - y1) < mindist) {
00386         mindist = abs(w_y - y1);
00387         min_x = w_x;
00388         min_y = y1;
00389       }
00390     }
00391 
00392     if (o_current->type == OBJ_BUS)
00393       weight = mindist / MAGNETIC_BUS_WEIGHT;
00394     else /* OBJ_NET */
00395       weight = mindist / MAGNETIC_NET_WEIGHT;
00396       }
00397       else { /* neither pin nor net or bus */
00398     continue;
00399       }
00400 
00401       if (o_magnetic == NULL
00402       || weight < min_weight) {
00403     minbest = mindist;
00404     min_weight = weight;
00405     o_magnetic = o_current;
00406     w_current->magnetic_wx = min_x;
00407     w_current->magnetic_wy = min_y;
00408       }
00409     }
00410   }
00411 
00412   /* check whether we found an object and if it's close enough */
00413   if (o_magnetic != NULL) {
00414     switch (o_magnetic->type) {
00415     case (OBJ_PIN): magnetic_reach = MAGNETIC_PIN_REACH; break;
00416     case (OBJ_NET): magnetic_reach = MAGNETIC_NET_REACH; break;
00417     case (OBJ_BUS): magnetic_reach = MAGNETIC_BUS_REACH; break;
00418     }
00419     if (minbest > WORLDabs (w_current, magnetic_reach)) {
00420       w_current->magnetic_wx = -1;
00421       w_current->magnetic_wy = -1;
00422     }
00423   }
00424   else {
00425     w_current->magnetic_wx = -1;
00426     w_current->magnetic_wy = -1;
00427   }
00428 
00429   g_list_free(objectlists);
00430 }
00431 
00438 void o_net_finishmagnetic(GSCHEM_TOPLEVEL *w_current)
00439 {
00440   int primary_zero_length, secondary_zero_length;
00441 
00442   primary_zero_length = ((w_current->first_wx == w_current->second_wx) 
00443              && (w_current->first_wy == w_current->second_wy));
00444  
00445   secondary_zero_length = ((w_current->second_wx == w_current->third_wx) 
00446                && (w_current->second_wy == w_current->third_wy));
00447 
00448   if (!primary_zero_length && secondary_zero_length) {
00449     if (w_current->first_wx == w_current->second_wx) {
00450       /* expand vertical line to magnetic_wy */
00451       w_current->second_wy = w_current->magnetic_wy;
00452     }
00453     else if (w_current->first_wy == w_current->second_wy) {
00454       /* expand horitontal line to vertical to magnetic_wx */
00455       w_current->second_wx = w_current->magnetic_wx;
00456     }
00457     /* connect to magnetic */
00458     w_current->third_wx = w_current->magnetic_wx;
00459     w_current->third_wy = w_current->magnetic_wy;
00460   }
00461 
00462   if (primary_zero_length && !secondary_zero_length) {
00463     /* move second line to the first (empty line) */
00464     w_current->first_wx = w_current->second_wx;
00465     w_current->first_wy = w_current->second_wy;
00466     if (w_current->second_wx == w_current->third_wx) {
00467       /* expand vertical line to magnetic_wy */
00468       w_current->second_wy = w_current->magnetic_wy;
00469     }
00470     else if (w_current->second_wy == w_current->third_wy) {
00471       /* expand horitontal line to magnetic_wx */
00472       w_current->second_wx = w_current->magnetic_wx;
00473     }
00474     /* connect to magnetic */
00475     w_current->third_wx = w_current->magnetic_wx;
00476     w_current->third_wy = w_current->magnetic_wy;
00477   }
00478 
00479   if (!primary_zero_length && !secondary_zero_length) {
00480     /* expand line in both directions */
00481     if (w_current->first_wx == w_current->second_wx) {
00482       w_current->second_wy = w_current->magnetic_wy;
00483     }
00484     else {
00485       w_current->second_wx = w_current->magnetic_wx;
00486     }
00487     w_current->third_wx = w_current->magnetic_wx;
00488     w_current->third_wy = w_current->magnetic_wy;
00489   }
00490 }
00491 
00498 void o_net_start_magnetic(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00499 {
00500   o_net_invalidate_rubber (w_current);
00501 
00502   if (w_current->CONTROLKEY) {
00503     w_current->magnetic_wx = w_x;
00504     w_current->magnetic_wy = w_y;
00505   }
00506   else {
00507     o_net_find_magnetic(w_current, w_x, w_y);
00508   }
00509 
00510   o_net_invalidate_rubber (w_current);
00511   w_current->rubber_visible = 1;
00512   w_current->inside_action = 1;
00513 }
00514 
00521 void o_net_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00522 {
00523   if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
00524     w_current->first_wx = w_current->magnetic_wx;
00525     w_current->first_wy = w_current->magnetic_wy;
00526   }
00527   else {
00528     w_current->first_wx = w_x;
00529     w_current->first_wy = w_y;
00530   }
00531 
00532   w_current->second_wx = w_current->third_wx = w_current->first_wx;
00533   w_current->second_wy = w_current->third_wy = w_current->first_wy;
00534 
00535   if (w_current->first_wx != snap_grid (w_current, w_current->first_wx)
00536       || w_current->first_wy != snap_grid (w_current, w_current->first_wy))
00537       s_log_message(_("Warning: Starting net at off grid coordinate\n"));
00538 
00539   if (w_current->net_direction_mode)
00540     o_net_guess_direction(w_current, w_current->first_wx, w_current->first_wy);
00541 }
00542 
00554 int o_net_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00555 {
00556   TOPLEVEL *toplevel = w_current->toplevel;
00557   int color;
00558   int primary_zero_length, secondary_zero_length;
00559   int found_primary_connection = FALSE;
00560   int save_wx, save_wy;
00561 
00562   GList *prev_conn_objects;
00563   OBJECT *new_net = NULL;
00564 
00565   /* Save a list of added objects to run the %add-objects-hook later */
00566   GList *added_objects = NULL;
00567 
00568   g_assert( w_current->inside_action != 0 );
00569 
00570   o_net_invalidate_rubber (w_current);
00571 
00572   if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1)
00573     o_net_finishmagnetic(w_current);
00574 
00575   w_current->rubber_visible = 0;
00576 
00577   /* See if either of the nets are zero length.  We'll only add */
00578   /* the non-zero ones */
00579   primary_zero_length = (w_current->first_wx == w_current->second_wx) &&
00580     (w_current->first_wy == w_current->second_wy);
00581  
00582   secondary_zero_length = (w_current->second_wx == w_current->third_wx) &&
00583       (w_current->second_wy == w_current->third_wy);
00584 
00585   /* If both nets are zero length... */
00586   /* this ends the net drawing behavior */
00587   if ( primary_zero_length && secondary_zero_length ) {
00588     return FALSE;
00589   }
00590 
00591   save_wx = w_current->third_wx;
00592   save_wy = w_current->third_wy;
00593 
00594   if (toplevel->override_net_color == -1) {
00595     color = NET_COLOR;
00596   } else {
00597     color = toplevel->override_net_color;
00598   }
00599 
00600   if (w_current->third_wx != snap_grid (w_current, w_current->third_wx)
00601       || w_current->third_wy != snap_grid (w_current, w_current->third_wy))
00602       s_log_message(_("Warning: Ending net at off grid coordinate\n"));
00603 
00604   if (!primary_zero_length ) {
00605   /* create primary net */
00606       new_net = o_net_new(toplevel, OBJ_NET, color,
00607                           w_current->first_wx, w_current->first_wy,
00608                           w_current->second_wx, w_current->second_wy);
00609       s_page_append (toplevel, toplevel->page_current, new_net);
00610 
00611       added_objects = g_list_prepend (added_objects, new_net);
00612 
00613       /* conn stuff */
00614       /* LEAK CHECK 1 */
00615       prev_conn_objects = s_conn_return_others (NULL, new_net);
00616       o_net_add_busrippers (w_current, new_net, prev_conn_objects);
00617       g_list_free (prev_conn_objects);
00618 
00619 #if DEBUG 
00620       printf("primary:\n"); 
00621       s_conn_print(new_net->conn_list);
00622 #endif
00623 
00624       /* Go off and search for valid connection on this newly created net */
00625       found_primary_connection = s_conn_net_search(new_net, 1, 
00626                                                    new_net->conn_list);
00627       if (found_primary_connection)
00628       {
00629         /* if a net connection is found, reset start point of next net */
00630     save_wx = w_current->second_wx;
00631     save_wy = w_current->second_wy;
00632       }
00633   }
00634 
00635 
00636   /* If the second net is not zero length, add it as well */
00637   /* Also, a valid net connection from the primary net was not found */
00638   if (!secondary_zero_length && !found_primary_connection) {
00639       
00640       /* Add secondary net */
00641       new_net = o_net_new(toplevel, OBJ_NET, color,
00642                           w_current->second_wx, w_current->second_wy,
00643                           w_current->third_wx, w_current->third_wy);
00644       s_page_append (toplevel, toplevel->page_current, new_net);
00645 
00646       added_objects = g_list_prepend (added_objects, new_net);
00647 
00648       /* conn stuff */
00649       /* LEAK CHECK 2 */
00650       prev_conn_objects = s_conn_return_others (NULL, new_net);
00651       o_net_add_busrippers (w_current, new_net, prev_conn_objects);
00652       g_list_free (prev_conn_objects);
00653 #if DEBUG
00654       s_conn_print(new_net->conn_list);
00655 #endif
00656   }
00657 
00658   /* Call add-objects-hook */
00659   if (added_objects != NULL) {
00660     g_run_hook_object_list (w_current, "%add-objects-hook", added_objects);
00661     g_list_free (added_objects);
00662   }
00663 
00664   toplevel->page_current->CHANGED = 1;
00665   w_current->first_wx = save_wx;
00666   w_current->first_wy = save_wy;
00667   o_undo_savestate(w_current, UNDO_ALL);
00668 
00669   return (TRUE);
00670 }
00671 
00676 void o_net_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00677 {
00678   int ortho, horizontal, quadrant;
00679 
00680   g_assert( w_current->inside_action != 0 );
00681 
00682   /* Orthognal mode enabled when Control Key is NOT pressed or
00683      if we are using magnetic mode */
00684   ortho = !w_current->CONTROLKEY || w_current->magneticnet_mode;
00685 
00686   if (w_current->rubber_visible)
00687     o_net_invalidate_rubber (w_current);
00688 
00689   if (w_current->magneticnet_mode) {
00690     if (w_current->CONTROLKEY) {
00691       /* set the magnetic marker position to current xy if the
00692      controlkey is pressed. Thus the net will not connect to 
00693      the closest net if we finish the net drawing */
00694       w_current->magnetic_wx = w_x;
00695       w_current->magnetic_wy = w_y;
00696     }
00697     else {
00698       o_net_find_magnetic(w_current, w_x, w_y);
00699     }
00700   }
00701 
00702   w_current->second_wx = w_x;
00703   w_current->second_wy = w_y;
00704 
00705   /* In orthogonal mode secondary line is the same as the first */
00706   if (!ortho) {
00707       w_current->third_wx = w_current->second_wx;
00708       w_current->third_wy = w_current->second_wy;
00709   }
00710   /* If you press the control key then you can draw non-ortho nets */
00711   else {
00712     if (w_current->second_wy > w_current->first_wy) 
00713       quadrant = w_current->second_wx > w_current->first_wx ? QUADRANT1: QUADRANT2;
00714     else
00715       quadrant = w_current->second_wx > w_current->first_wx ? QUADRANT4: QUADRANT3;
00716 
00717     horizontal = w_current->net_direction & quadrant;
00718 
00719     if (!w_current->SHIFTKEY)
00720       horizontal = !horizontal;
00721 
00722     /* calculate the co-ordinates necessary to draw the lines*/
00723     /* Pressing the shift key will cause the vertical and horizontal lines to switch places */
00724     if ( horizontal ) {
00725       w_current->second_wy = w_current->first_wy;
00726       w_current->third_wx = w_current->second_wx;
00727       w_current->third_wy = w_y;
00728     } else {
00729       w_current->second_wx = w_current->first_wx;
00730       w_current->third_wx = w_x;
00731       w_current->third_wy = w_current->second_wy;
00732     }
00733   }
00734 
00735   o_net_invalidate_rubber (w_current);
00736   w_current->rubber_visible = 1;
00737 }
00738 
00743 void o_net_draw_rubber(GSCHEM_TOPLEVEL *w_current)
00744 {
00745   int size = 0, w_magnetic_halfsize;
00746 
00747   if (w_current->toplevel->net_style == THICK)
00748     size = NET_WIDTH;
00749 
00750   gschem_cairo_set_source_color (w_current,
00751                                  x_color_lookup_dark (SELECT_COLOR));
00752 
00753   if (w_current->magneticnet_mode) {
00754     if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
00755       w_magnetic_halfsize = max (4 * size,
00756                                  WORLDabs (w_current, MAGNETIC_HALFSIZE));
00757       gschem_cairo_arc (w_current, size, w_current->magnetic_wx,
00758                                          w_current->magnetic_wy,
00759                                          w_magnetic_halfsize, 0, 360);
00760     }
00761   }
00762 
00763   /* Primary line */
00764   gschem_cairo_line (w_current, END_NONE, size,
00765                      w_current->first_wx,  w_current->first_wy,
00766                      w_current->second_wx, w_current->second_wy);
00767 
00768   /* Secondary line */
00769   gschem_cairo_line (w_current, END_NONE, size,
00770                      w_current->second_wx, w_current->second_wy,
00771                      w_current->third_wx,  w_current->third_wy);
00772 
00773   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, size, -1, -1);
00774 }
00775 
00776 
00782 void o_net_invalidate_rubber (GSCHEM_TOPLEVEL *w_current)
00783 {
00784   TOPLEVEL *toplevel = w_current->toplevel;
00785   int size = 0, magnetic_halfsize;
00786   int bloat;
00787   int magnetic_x, magnetic_y;
00788   int first_x, first_y, third_x, third_y, second_x, second_y;
00789   int x1, y1, x2, y2;
00790 
00791   WORLDtoSCREEN (w_current, w_current->magnetic_wx, w_current->magnetic_wy,
00792                  &magnetic_x, &magnetic_y);
00793   WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy,
00794                  &first_x, &first_y);
00795   WORLDtoSCREEN (w_current, w_current->third_wx, w_current->third_wy,
00796                  &third_x, &third_y);
00797   WORLDtoSCREEN (w_current, w_current->second_wx, w_current->second_wy,
00798                  &second_x, &second_y);
00799 
00800   if (toplevel->net_style == THICK) {
00801     size = SCREENabs (w_current, NET_WIDTH);
00802   }
00803   size = max (size, 0);
00804   bloat = size / 2;
00805 
00806   if (w_current->magneticnet_mode) {
00807     if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
00808       magnetic_halfsize = max (4 * size, MAGNETIC_HALFSIZE);
00809 
00810       o_invalidate_rect (w_current, magnetic_x - magnetic_halfsize,
00811                                     magnetic_y - magnetic_halfsize,
00812                                     magnetic_x + magnetic_halfsize,
00813                                     magnetic_y + magnetic_halfsize);
00814     }
00815   }
00816 
00817   x1 = min (first_x, second_x) - bloat;
00818   x2 = max (first_x, second_x) + bloat;
00819   y1 = min (first_y, second_y) - bloat;
00820   y2 = max (first_y, second_y) + bloat;
00821   o_invalidate_rect (w_current, x1, y1, x2, y2);
00822 
00823   x1 = min (second_x, third_x) - bloat;
00824   x2 = max (second_x, third_x) + bloat;
00825   y1 = min (second_y, third_y) - bloat;
00826   y2 = max (second_y, third_y) + bloat;
00827   o_invalidate_rect (w_current, x1, y1, x2, y2);
00828 }
00829 
00830 
00836 int o_net_add_busrippers(GSCHEM_TOPLEVEL *w_current, OBJECT *net_obj,
00837                          GList *prev_conn_objects)
00838 
00839 {
00840   TOPLEVEL *toplevel = w_current->toplevel;
00841   OBJECT *new_obj;
00842   int color;
00843   GList *cl_current = NULL;
00844   OBJECT *bus_object = NULL;
00845   CONN *found_conn = NULL;
00846   int done;
00847   int otherone;
00848   BUS_RIPPER rippers[2];
00849   int ripper_count = 0;
00850   int i;
00851   double length;
00852   int sign;
00853   double distance1, distance2;
00854   int first, second;
00855   int made_changes = FALSE;
00856   const int ripper_size = w_current->bus_ripper_size;
00857   int complex_angle = 0;
00858   const CLibSymbol *rippersym = NULL;
00859   
00860   length = o_line_length(net_obj);
00861 
00862   if (!prev_conn_objects) {
00863     return(FALSE);
00864   }
00865   
00866   if (length <= ripper_size) {
00867     return(FALSE);
00868   }
00869 
00870   if (toplevel->override_net_color == -1) {
00871     color = NET_COLOR;
00872   } else {
00873     color = toplevel->override_net_color;
00874   }
00875 
00876   
00877   /* check for a bus connection and draw rippers if so */
00878   cl_current = prev_conn_objects;
00879   while (cl_current != NULL) {
00880     
00881     bus_object = (OBJECT *) cl_current->data;
00882     if (bus_object && bus_object->type == OBJ_BUS) {
00883       /* yes, using the net routine is okay */
00884       int bus_orientation = o_net_orientation(bus_object);
00885       int net_orientation = o_net_orientation(net_obj);
00886 
00887       /* find the CONN structure which is associated with this object */
00888       GList *cl_current2 = net_obj->conn_list;
00889       done = FALSE;
00890       while (cl_current2 != NULL && !done) {
00891     CONN *tmp_conn = (CONN *) cl_current2->data;
00892 
00893     if (tmp_conn && tmp_conn->other_object &&
00894         tmp_conn->other_object == bus_object) {
00895 
00896       found_conn = tmp_conn;
00897       done = TRUE;
00898     }
00899 
00900     cl_current2 = g_list_next(cl_current2);
00901       }
00902 
00903       if (!found_conn) {
00904         return(FALSE);
00905       }
00906       
00907       otherone = !found_conn->whichone;
00908       
00909       /* now deal with the found connection */
00910       if (bus_orientation == HORIZONTAL && net_orientation == VERTICAL) {
00911     /* printf("found horiz bus %s %d!\n", bus_object->name, 
00912            found_conn->whichone);*/
00913 
00914         sign = bus_object->bus_ripper_direction;
00915         if (!sign) {
00916           if (bus_object->line->x[0] < bus_object->line->x[1]) {
00917             first = 0;
00918             second = 1;
00919           } else {
00920             first = 1;
00921             second = 0;
00922           }
00923               
00924           distance1 = abs(bus_object->line->x[first] -
00925                           net_obj->line->x[found_conn->whichone]);
00926           distance2 = abs(bus_object->line->x[second] -
00927                           net_obj->line->x[found_conn->whichone]);
00928           
00929           if (distance1 <= distance2) {
00930             sign = 1;
00931           } else {
00932             sign = -1;
00933           }
00934           bus_object->bus_ripper_direction = sign;
00935         }
00936         /* printf("hor sign: %d\n", sign); */
00937 
00938         if (net_obj->line->y[otherone] < bus_object->line->y[0]) {
00939           /* new net is below bus */
00940           /*printf("below\n");*/
00941 
00942           if (ripper_count >= 2) {
00943             /* try to exit gracefully */
00944             fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
00945             made_changes = FALSE;
00946             break;
00947           }
00948 
00949           if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
00950             /* non-symmetric */
00951             if (sign == 1) {
00952               complex_angle = 0;
00953             } else {
00954               complex_angle = 90;
00955             }
00956           } else {
00957             /* symmetric */
00958             complex_angle = 0;
00959           }
00960 
00961           net_obj->line->y[found_conn->whichone] -= ripper_size;
00962           o_recalc_single_object(toplevel, net_obj);
00963           rippers[ripper_count].x[0] = 
00964             net_obj->line->x[found_conn->whichone];
00965           rippers[ripper_count].y[0] =
00966             net_obj->line->y[found_conn->whichone];
00967           rippers[ripper_count].x[1] =
00968             net_obj->line->x[found_conn->whichone] + sign*ripper_size;       
00969           rippers[ripper_count].y[1] =
00970             net_obj->line->y[found_conn->whichone] + ripper_size;
00971           ripper_count++;
00972           /* printf("done\n"); */
00973           made_changes++;
00974           
00975         } else {
00976           /* new net is above bus */
00977           /* printf("above\n"); */
00978 
00979           if (ripper_count >= 2) {
00980             /* try to exit gracefully */
00981             fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
00982             made_changes = FALSE;
00983             break;
00984           }
00985 
00986           if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
00987             /* non-symmetric */
00988             if (sign == 1) {
00989               complex_angle = 270;
00990             } else {
00991               complex_angle = 180;
00992             }
00993           } else {
00994             /* symmetric */
00995             complex_angle = 180;
00996           }
00997           
00998           net_obj->line->y[found_conn->whichone] += ripper_size;
00999           o_recalc_single_object(toplevel, net_obj);
01000           rippers[ripper_count].x[0] = 
01001             net_obj->line->x[found_conn->whichone];
01002           rippers[ripper_count].y[0] =
01003             net_obj->line->y[found_conn->whichone];
01004           rippers[ripper_count].x[1] =
01005             net_obj->line->x[found_conn->whichone] + sign*ripper_size;      
01006           rippers[ripper_count].y[1] =
01007             net_obj->line->y[found_conn->whichone] - ripper_size;
01008             ripper_count++;
01009             
01010             /* printf("done\n"); */
01011           made_changes++;
01012         }
01013         
01014         
01015       } else if (bus_orientation == VERTICAL &&
01016          net_orientation == HORIZONTAL) {
01017 
01018     /* printf("found vert bus %s %d!\n", bus_object->name,
01019            found_conn->whichone); */
01020 
01021         sign = bus_object->bus_ripper_direction;
01022         if (!sign) {
01023           if (bus_object->line->y[0] < bus_object->line->y[1]) {
01024             first = 0;
01025             second = 1;
01026           } else {
01027             first = 1;
01028             second = 0;
01029           }
01030 
01031           distance1 = abs(bus_object->line->y[first] -
01032                           net_obj->line->y[found_conn->whichone]);
01033           distance2 = abs(bus_object->line->y[second] -
01034                           net_obj->line->y[found_conn->whichone]);
01035           
01036           if (distance1 <= distance2) {
01037             sign = 1;
01038           } else {
01039             sign = -1;
01040           }
01041           bus_object->bus_ripper_direction = sign;
01042         } 
01043         /* printf("ver sign: %d\n", sign); */
01044 
01045         
01046         if (net_obj->line->x[otherone] < bus_object->line->x[0]) {
01047           /* new net is to the left of the bus */
01048           /* printf("left\n"); */
01049           
01050           if (ripper_count >= 2) {
01051             /* try to exit gracefully */
01052             fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
01053             made_changes = FALSE;
01054             break;
01055           }
01056 
01057           if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
01058             /* non-symmetric */
01059             if (sign == 1) {
01060               complex_angle = 0;
01061             } else {
01062               complex_angle = 270;
01063             }
01064           } else {
01065             /* symmetric */
01066             complex_angle = 270;
01067           }
01068 
01069           net_obj->line->x[found_conn->whichone] -= ripper_size;
01070           o_recalc_single_object(toplevel, net_obj);
01071           rippers[ripper_count].x[0] = 
01072             net_obj->line->x[found_conn->whichone];
01073           rippers[ripper_count].y[0] =
01074             net_obj->line->y[found_conn->whichone];
01075           rippers[ripper_count].x[1] =
01076             net_obj->line->x[found_conn->whichone] + ripper_size;
01077           rippers[ripper_count].y[1] =
01078             net_obj->line->y[found_conn->whichone] + sign*ripper_size;
01079           ripper_count++;
01080                     
01081           made_changes++;
01082         } else {
01083           /* new net is to the right of the bus */
01084           /* printf("right\n"); */
01085 
01086           if (ripper_count >= 2) {
01087             /* try to exit gracefully */
01088             fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
01089             made_changes = FALSE;
01090             break;
01091           }
01092 
01093           if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
01094             /* non-symmetric */
01095             if (sign == 1) {
01096               complex_angle = 90;
01097             } else {
01098               complex_angle = 180;
01099             }
01100           } else {
01101             /* symmetric */
01102             complex_angle = 90;
01103           }
01104 
01105           net_obj->line->x[found_conn->whichone] += ripper_size;
01106           o_recalc_single_object(toplevel, net_obj);
01107           rippers[ripper_count].x[0] = 
01108             net_obj->line->x[found_conn->whichone];
01109           rippers[ripper_count].y[0] =
01110             net_obj->line->y[found_conn->whichone];
01111           rippers[ripper_count].x[1] =
01112             net_obj->line->x[found_conn->whichone] - ripper_size;
01113           rippers[ripper_count].y[1] =
01114             net_obj->line->y[found_conn->whichone] + sign*ripper_size;
01115           ripper_count++;
01116 
01117           made_changes++;
01118         }
01119       }
01120     }
01121 
01122 
01123     cl_current = g_list_next(cl_current);
01124   }
01125  
01126   if (made_changes) {
01127     s_conn_remove_object (toplevel, net_obj);
01128 
01129     if (w_current->bus_ripper_type == COMP_BUS_RIPPER) {
01130       GList *symlist = 
01131     s_clib_search (toplevel->bus_ripper_symname, CLIB_EXACT);
01132       if (symlist != NULL) {
01133         rippersym = (CLibSymbol *) symlist->data;
01134       }
01135       g_list_free (symlist);
01136     }
01137     
01138     for (i = 0; i < ripper_count; i++) {
01139       if (w_current->bus_ripper_type == NET_BUS_RIPPER) {
01140         new_obj = o_net_new(toplevel, OBJ_NET, color,
01141                   rippers[i].x[0], rippers[i].y[0],
01142                   rippers[i].x[1], rippers[i].y[1]);
01143         s_page_append (toplevel, toplevel->page_current, new_obj);
01144       } else {
01145 
01146         if (rippersym != NULL) {
01147           new_obj = o_complex_new (toplevel, OBJ_COMPLEX, DEFAULT_COLOR,
01148                                    rippers[i].x[0], rippers[i].y[0],
01149                                    complex_angle, 0,
01150                                    rippersym,
01151                                    toplevel->bus_ripper_symname, 1);
01152           s_page_append_list (toplevel, toplevel->page_current,
01153                               o_complex_promote_attribs (toplevel, new_obj));
01154           s_page_append (toplevel, toplevel->page_current, new_obj);
01155         } else {
01156           s_log_message(_("Bus ripper symbol [%s] was not found in any component library\n"),
01157                         toplevel->bus_ripper_symname);
01158         }
01159       }
01160     }
01161     
01162     s_conn_update_object (toplevel, net_obj);
01163     return(TRUE);
01164   }
01165 
01166   return(FALSE);
01167 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines