gschem
|
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 }