Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / gschem / src / o_net.c
blob14bd87d54342d31c32f5db39279ba4e3911d30c6
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <math.h>
25 #include "gschem.h"
27 #ifdef HAVE_LIBDMALLOC
28 #include <dmalloc.h>
29 #endif
32 /* magnetic options */
33 /* half size of the magnetic marker on the screen. */
34 #define MAGNETIC_HALFSIZE 6
36 /* define how far the cursor could be to activate magnetic */
37 #define MAGNETIC_PIN_REACH 50
38 #define MAGNETIC_NET_REACH 20
39 #define MAGNETIC_BUS_REACH 30
41 /* weighting factors to tell that a pin is more important than a net */
42 #define MAGNETIC_PIN_WEIGHT 5.0
43 #define MAGNETIC_NET_WEIGHT 2.0
44 #define MAGNETIC_BUS_WEIGHT 3.0
46 /* Bit definitions for the four quardrants of the direction guessing */
47 #define QUADRANT1 0x01
48 #define QUADRANT2 0x02
49 #define QUADRANT3 0x04
50 #define QUADRANT4 0x08
53 /*! \brief Reset all variables used for net drawing
54 * \par Function Description
55 * This function resets all variables from GSCHEM_TOPLEVEL that are used
56 * for net drawing. This function should be called when escaping from
57 * a net drawing action or before entering it.
59 void o_net_reset(GSCHEM_TOPLEVEL *w_current)
61 w_current->first_wx = w_current->first_wy = -1;
62 w_current->second_wx = w_current->second_wy = -1;
63 w_current->third_wx = w_current->third_wy = -1;
64 w_current->magnetic_wx = w_current->magnetic_wy = -1;
65 w_current->rubber_visible = 0;
68 /*! \todo Finish function documentation!!!
69 * \brief
70 * \par Function Description
73 void o_net_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
75 TOPLEVEL *toplevel = w_current->toplevel;
76 int x1, y1, x2, y2;
77 int size = 0;
79 #if NET_DEBUG /* debug */
80 char *tempstring;
81 GdkFont *font;
82 #endif
84 if (o_current == NULL) {
85 return;
88 if (o_current->line == NULL) {
89 return;
92 /* reuse line's routine */
93 if ( (toplevel->DONT_REDRAW == 1) ||
94 (!o_line_visible (w_current, o_current->line, &x1, &y1, &x2, &y2)) ) {
95 return;
98 if (toplevel->net_style == THICK)
99 size = NET_WIDTH;
101 gschem_cairo_line (w_current, END_SQUARE, size, x1, y1, x2, y2);
102 gschem_cairo_set_source_color (w_current,
103 o_drawing_color (w_current, o_current));
104 gschem_cairo_stroke (w_current, TYPE_SOLID, END_SQUARE, size, -1, -1);
106 if (o_current->selected && w_current->draw_grips) {
107 o_line_draw_grips (w_current, o_current);
112 /*! \todo Finish function documentation!!!
113 * \brief
114 * \par Function Description
117 void o_net_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
119 int size = 0;
121 if (o_current->line == NULL) {
122 return;
125 if (w_current->toplevel->net_style == THICK)
126 size = NET_WIDTH;
128 gschem_cairo_line (w_current, END_NONE, size,
129 o_current->line->x[0] + dx, o_current->line->y[0] + dy,
130 o_current->line->x[1] + dx, o_current->line->y[1] + dy);
131 gschem_cairo_set_source_color (w_current,
132 x_color_lookup_dark (o_current->color));
133 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, size, -1, -1);
136 /*! \todo Finish function documentation!!!
137 * \brief
138 * \par Function Description
141 void o_net_draw_stretch (GSCHEM_TOPLEVEL *w_current,
142 int dx, int dy, int whichone, OBJECT *o_current)
144 int dx1 = -1, dx2 = -1, dy1 = -1,dy2 = -1;
146 if (o_current->line == NULL) {
147 return;
150 if (whichone == 0) {
151 dx1 = dx;
152 dy1 = dy;
153 dx2 = dy2 = 0;
154 } else if (whichone == 1) {
155 dx1 = dy1 = 0;
156 dx2 = dx;
157 dy2 = dy;
158 } else {
159 fprintf(stderr, _("Got an invalid which one in o_net_draw_stretch\n"));
162 gschem_cairo_line (w_current, END_NONE, 0,
163 o_current->line->x[0] + dx1, o_current->line->y[0] + dy1,
164 o_current->line->x[1] + dx2, o_current->line->y[1] + dy2);
166 gschem_cairo_set_source_color (w_current,
167 x_color_lookup_dark (o_current->color));
168 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
172 /*! \brief guess the best direction for the next net drawing action
173 * \par Function Description
174 * This function checks all connectable objects at a starting point.
175 * It determines the best drawing direction for each quadrant of the
176 * possible net endpoint.
178 * The directions are stored in the GSCHEM_TOPLEVEL->net_direction variable
179 * as a bitfield.
181 void o_net_guess_direction(GSCHEM_TOPLEVEL *w_current,
182 int wx, int wy)
184 TOPLEVEL *toplevel = w_current->toplevel;
185 int up=0, down=0, left=0, right=0;
186 int x1, y1, x2, y2;
187 int xmin, ymin, xmax, ymax;
188 int orientation;
189 GList *objectlists, *iter1, *iter2;
190 OBJECT *o_current;
192 int *current_rules;
193 /* badness values {OVERWRITE, ORTHO, CONTINUE} */
194 const int pin_rules[] = {100, 50, 0};
195 const int bus_rules[] = {90, 0, 40};
196 const int net_rules[] = {80, 30, 0};
198 objectlists = s_tile_get_objectlists(toplevel, wx, wy, wx, wy);
200 for (iter1 = objectlists; iter1 != NULL; iter1 = g_list_next(iter1)) {
201 for (iter2 = (GList*) iter1->data; iter2 != NULL; iter2 = g_list_next(iter2)) {
202 o_current = (OBJECT*) iter2->data;
204 if ((orientation = o_net_orientation(o_current)) == NEITHER)
205 continue;
207 switch (o_current->type) {
208 case OBJ_NET:
209 current_rules = (int*) net_rules;
210 break;
211 case OBJ_PIN:
212 current_rules = (int*) pin_rules;
213 break;
214 case OBJ_BUS:
215 current_rules = (int*) bus_rules;
216 break;
217 default:
218 g_assert_not_reached ();
221 x1 = o_current->line->x[0];
222 x2 = o_current->line->x[1];
223 y1 = o_current->line->y[0];
224 y2 = o_current->line->y[1];
226 xmin = min(x1, x2);
227 ymin = min(y1, y2);
228 xmax = max(x1, x2);
229 ymax = max(y1, y2);
231 if (orientation == HORIZONTAL && wy == y1) {
232 if (wx == xmin) {
233 up = max(up, current_rules[1]);
234 down = max(down, current_rules[1]);
235 right = max(right, current_rules[0]);
236 left = max(left, current_rules[2]);
238 else if (wx == xmax) {
239 up = max(up, current_rules[1]);
240 down = max(down, current_rules[1]);
241 right = max(right, current_rules[2]);
242 left = max(left, current_rules[0]);
244 else if (xmin < wx && wx < xmax) {
245 up = max(up, current_rules[1]);
246 down = max(down, current_rules[1]);
247 right = max(right, current_rules[0]);
248 left = max(left, current_rules[0]);
250 else {
251 continue;
254 if (orientation == VERTICAL && wx == x1) {
255 if (wy == ymin) {
256 up = max(up, current_rules[0]);
257 down = max(down, current_rules[2]);
258 right = max(right, current_rules[1]);
259 left = max(left, current_rules[1]);
261 else if (wy == ymax) {
262 up = max(up, current_rules[2]);
263 down = max(down, current_rules[0]);
264 right = max(right, current_rules[1]);
265 left = max(left, current_rules[1]);
267 else if (ymin < wy && wy < ymax) {
268 up = max(up, current_rules[0]);
269 down = max(down, current_rules[0]);
270 right = max(right, current_rules[1]);
271 left = max(left, current_rules[1]);
273 else {
274 continue;
280 w_current->net_direction = 0;
281 w_current->net_direction |= up >= right ? 0 : QUADRANT1;
282 w_current->net_direction |= up >= left ? 0 : QUADRANT2;
283 w_current->net_direction |= down >= left ? 0 : QUADRANT3;
284 w_current->net_direction |= down >= right ? 0 : QUADRANT4;
286 #if 0
287 printf("o_net_guess_direction: up=%d down=%d left=%d right=%d direction=%d\n",
288 up, down, left, right, w_current->net_direction);
289 #endif
290 g_list_free(objectlists);
293 /*! \brief find the closest possible location to connect to
294 * \par Function Description
295 * This function calculates the distance to all connectable objects
296 * and searches the closest connection point.
297 * It searches for pins, nets and busses.
299 * The connection point is stored in GSCHEM_TOPLEVEL->magnetic_wx and
300 * GSCHEM_TOPLEVEL->magnetic_wy. If no connection is found. Both variables
301 * are set to -1.
303 void o_net_find_magnetic(GSCHEM_TOPLEVEL *w_current,
304 int w_x, int w_y)
306 TOPLEVEL *toplevel = w_current->toplevel;
307 int x1, x2, y1, y2, min_x, min_y, w_magnetic_reach;
308 double mindist, minbest, dist1, dist2;
309 double weight, min_weight;
310 int magnetic_reach = 0;
311 OBJECT *o_current;
312 OBJECT *o_magnetic = NULL;
313 GList *objectlists, *iter1, *iter2;
315 minbest = min_x = min_y = 0;
316 min_weight = 0;
318 /* max distance of all the different reaches */
319 magnetic_reach = max(MAGNETIC_PIN_REACH, MAGNETIC_NET_REACH);
320 magnetic_reach = max(magnetic_reach, MAGNETIC_BUS_REACH);
321 w_magnetic_reach = WORLDabs (w_current, magnetic_reach);
323 /* get the objects of the tiles around the reach region */
324 x1 = w_x - w_magnetic_reach;
325 y1 = w_y - w_magnetic_reach;
326 x2 = w_x + w_magnetic_reach;
327 y2 = w_y + w_magnetic_reach;
328 objectlists = s_tile_get_objectlists(toplevel, x1, y1, x2, y2);
330 for (iter1 = objectlists; iter1 != NULL; iter1 = g_list_next(iter1)) {
331 for (iter2 = (GList*) iter1->data; iter2 != NULL; iter2 = g_list_next(iter2)) {
332 o_current = (OBJECT*) iter2->data;
334 if (!visible (w_current, o_current->w_left, o_current->w_top,
335 o_current->w_right, o_current->w_bottom))
336 continue; /* skip invisible objects */
338 if (o_current->type == OBJ_PIN) {
339 min_x = o_current->line->x[o_current->whichend];
340 min_y = o_current->line->y[o_current->whichend];
342 mindist = sqrt((double) (w_x - min_x)*(w_x - min_x)
343 + (double) (w_y - min_y)*(w_y - min_y));
344 weight = mindist / MAGNETIC_PIN_WEIGHT;
347 else if (o_current->type == OBJ_NET
348 || o_current->type == OBJ_BUS) {
349 /* we have 3 possible points to connect:
350 2 endpoints and 1 midpoint point */
351 x1 = o_current->line->x[0];
352 y1 = o_current->line->y[0];
353 x2 = o_current->line->x[1];
354 y2 = o_current->line->y[1];
355 /* endpoint tests */
356 dist1 = sqrt((double) (w_x - x1)*(w_x - x1)
357 + (double) (w_y - y1)*(w_y - y1));
358 dist2 = sqrt((double) (w_x - x2)*(w_x - x2)
359 + (double) (w_y - y2)*(w_y - y2));
360 if (dist1 < dist2) {
361 min_x = x1;
362 min_y = y1;
363 mindist = dist1;
365 else {
366 min_x = x2;
367 min_y = y2;
368 mindist = dist2;
371 /* midpoint tests */
372 if ((x1 == x2) /* vertical net */
373 && ((y1 >= w_y && w_y >= y2)
374 || (y2 >= w_y && w_y >= y1))) {
375 if (abs(w_x - x1) < mindist) {
376 mindist = abs(w_x - x1);
377 min_x = x1;
378 min_y = w_y;
381 if ((y1 == y2) /* horitontal net */
382 && ((x1 >= w_x && w_x >= x2)
383 || (x2 >= w_x && w_x >= x1))) {
384 if (abs(w_y - y1) < mindist) {
385 mindist = abs(w_y - y1);
386 min_x = w_x;
387 min_y = y1;
391 if (o_current->type == OBJ_BUS)
392 weight = mindist / MAGNETIC_BUS_WEIGHT;
393 else /* OBJ_NET */
394 weight = mindist / MAGNETIC_NET_WEIGHT;
396 else { /* neither pin nor net or bus */
397 continue;
400 if (o_magnetic == NULL
401 || weight < min_weight) {
402 minbest = mindist;
403 min_weight = weight;
404 o_magnetic = o_current;
405 w_current->magnetic_wx = min_x;
406 w_current->magnetic_wy = min_y;
411 /* check whether we found an object and if it's close enough */
412 if (o_magnetic != NULL) {
413 switch (o_magnetic->type) {
414 case (OBJ_PIN): magnetic_reach = MAGNETIC_PIN_REACH; break;
415 case (OBJ_NET): magnetic_reach = MAGNETIC_NET_REACH; break;
416 case (OBJ_BUS): magnetic_reach = MAGNETIC_BUS_REACH; break;
418 if (minbest > WORLDabs (w_current, magnetic_reach)) {
419 w_current->magnetic_wx = -1;
420 w_current->magnetic_wy = -1;
423 else {
424 w_current->magnetic_wx = -1;
425 w_current->magnetic_wy = -1;
428 g_list_free(objectlists);
431 /*! \brief calcutates the net route to the magnetic marker
432 * \par Function Description
433 * Depending on the two rubbernet lines from start to last and from
434 * last to second, the 3 coordinates are manipulated to find
435 * a way to the magnetic marker.
437 void o_net_finishmagnetic(GSCHEM_TOPLEVEL *w_current)
439 int primary_zero_length, secondary_zero_length;
441 primary_zero_length = ((w_current->first_wx == w_current->second_wx)
442 && (w_current->first_wy == w_current->second_wy));
444 secondary_zero_length = ((w_current->second_wx == w_current->third_wx)
445 && (w_current->second_wy == w_current->third_wy));
447 if (!primary_zero_length && secondary_zero_length) {
448 if (w_current->first_wx == w_current->second_wx) {
449 /* expand vertical line to magnetic_wy */
450 w_current->second_wy = w_current->magnetic_wy;
452 else if (w_current->first_wy == w_current->second_wy) {
453 /* expand horitontal line to vertical to magnetic_wx */
454 w_current->second_wx = w_current->magnetic_wx;
456 /* connect to magnetic */
457 w_current->third_wx = w_current->magnetic_wx;
458 w_current->third_wy = w_current->magnetic_wy;
461 if (primary_zero_length && !secondary_zero_length) {
462 /* move second line to the first (empty line) */
463 w_current->first_wx = w_current->second_wx;
464 w_current->first_wy = w_current->second_wy;
465 if (w_current->second_wx == w_current->third_wx) {
466 /* expand vertical line to magnetic_wy */
467 w_current->second_wy = w_current->magnetic_wy;
469 else if (w_current->second_wy == w_current->third_wy) {
470 /* expand horitontal line to magnetic_wx */
471 w_current->second_wx = w_current->magnetic_wx;
473 /* connect to magnetic */
474 w_current->third_wx = w_current->magnetic_wx;
475 w_current->third_wy = w_current->magnetic_wy;
478 if (!primary_zero_length && !secondary_zero_length) {
479 /* expand line in both directions */
480 if (w_current->first_wx == w_current->second_wx) {
481 w_current->second_wy = w_current->magnetic_wy;
483 else {
484 w_current->second_wx = w_current->magnetic_wx;
486 w_current->third_wx = w_current->magnetic_wx;
487 w_current->third_wy = w_current->magnetic_wy;
491 /*! \brief callback function to draw a net marker in magnetic mode
492 * \par Function Description
493 * If the mouse is moved, this function is called to update the
494 * position of the magnetic marker.
495 * If the controllkey is pressed the magnetic marker follows the mouse.
497 void o_net_start_magnetic(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
499 o_net_invalidate_rubber (w_current);
501 if (w_current->CONTROLKEY) {
502 w_current->magnetic_wx = w_x;
503 w_current->magnetic_wy = w_y;
505 else {
506 o_net_find_magnetic(w_current, w_x, w_y);
509 o_net_invalidate_rubber (w_current);
510 w_current->rubber_visible = 1;
511 w_current->inside_action = 1;
514 /*! \brief set the start point of a new net
515 * \par Function Description
516 * This function sets the start point of a new net at the position of the
517 * cursor. If we have a visible magnetic marker, we use that instead of
518 * the cursor position
520 void o_net_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
522 if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
523 w_current->first_wx = w_current->magnetic_wx;
524 w_current->first_wy = w_current->magnetic_wy;
526 else {
527 w_current->first_wx = w_x;
528 w_current->first_wy = w_y;
531 w_current->second_wx = w_current->third_wx = w_current->first_wx;
532 w_current->second_wy = w_current->third_wy = w_current->first_wy;
534 if (w_current->first_wx != snap_grid (w_current, w_current->first_wx)
535 || w_current->first_wy != snap_grid (w_current, w_current->first_wy))
536 s_log_message(_("Warning: Starting net at off grid coordinate\n"));
538 if (w_current->net_direction_mode)
539 o_net_guess_direction(w_current, w_current->first_wx, w_current->first_wy);
542 /*! \brief finish a net drawing action
543 * \par Function Description
544 * This function finishes the drawing of a net. If we have a visible
545 * magnetic marker, we use that instead of the current cursor
546 * position.
548 * The rubber nets are removed, the nets and cues are drawn and the
549 * net is added to the TOPLEVEL structure.
551 * The function returns TRUE if it has drawn a net, FALSE otherwise.
553 int o_net_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
555 TOPLEVEL *toplevel = w_current->toplevel;
556 int color;
557 int primary_zero_length, secondary_zero_length;
558 int found_primary_connection = FALSE;
559 int save_wx, save_wy;
561 GList *prev_conn_objects = NULL;
562 OBJECT *new_net = NULL;
564 g_assert( w_current->inside_action != 0 );
566 o_net_invalidate_rubber (w_current);
568 if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1)
569 o_net_finishmagnetic(w_current);
571 w_current->rubber_visible = 0;
573 /* See if either of the nets are zero length. We'll only add */
574 /* the non-zero ones */
575 primary_zero_length = (w_current->first_wx == w_current->second_wx) &&
576 (w_current->first_wy == w_current->second_wy);
578 secondary_zero_length = (w_current->second_wx == w_current->third_wx) &&
579 (w_current->second_wy == w_current->third_wy);
581 /* If both nets are zero length... */
582 /* this ends the net drawing behavior */
583 if ( primary_zero_length && secondary_zero_length ) {
584 return FALSE;
587 save_wx = w_current->third_wx;
588 save_wy = w_current->third_wy;
590 if (toplevel->override_net_color == -1) {
591 color = NET_COLOR;
592 } else {
593 color = toplevel->override_net_color;
596 if (w_current->third_wx != snap_grid (w_current, w_current->third_wx)
597 || w_current->third_wy != snap_grid (w_current, w_current->third_wy))
598 s_log_message(_("Warning: Ending net at off grid coordinate\n"));
600 if (!primary_zero_length ) {
601 /* create primary net */
602 new_net = o_net_new(toplevel, OBJ_NET, color,
603 w_current->first_wx, w_current->first_wy,
604 w_current->second_wx, w_current->second_wy);
605 s_page_append (toplevel, toplevel->page_current, new_net);
607 /* conn stuff */
608 /* LEAK CHECK 1 */
609 prev_conn_objects = s_conn_return_others (prev_conn_objects, new_net);
611 if (o_net_add_busrippers (w_current, new_net, prev_conn_objects)) {
612 g_list_free (prev_conn_objects);
613 prev_conn_objects = NULL;
614 prev_conn_objects = s_conn_return_others (prev_conn_objects, new_net);
617 #if DEBUG
618 printf("primary:\n");
619 s_conn_print(new_net->conn_list);
620 #endif
622 o_invalidate (w_current, new_net);
624 o_invalidate_glist (w_current, prev_conn_objects);
626 g_list_free (prev_conn_objects);
627 prev_conn_objects = NULL;
629 /* Go off and search for valid connection on this newly created net */
630 found_primary_connection = s_conn_net_search(new_net, 1,
631 new_net->conn_list);
632 if (found_primary_connection)
634 /* if a net connection is found, reset start point of next net */
635 save_wx = w_current->second_wx;
636 save_wy = w_current->second_wy;
641 /* If the second net is not zero length, add it as well */
642 /* Also, a valid net connection from the primary net was not found */
643 if (!secondary_zero_length && !found_primary_connection) {
645 /* Add secondary net */
646 new_net = o_net_new(toplevel, OBJ_NET, color,
647 w_current->second_wx, w_current->second_wy,
648 w_current->third_wx, w_current->third_wy);
649 s_page_append (toplevel, toplevel->page_current, new_net);
651 /* conn stuff */
652 /* LEAK CHECK 2 */
653 prev_conn_objects = s_conn_return_others (prev_conn_objects, new_net);
655 if (o_net_add_busrippers (w_current, new_net, prev_conn_objects)) {
656 g_list_free (prev_conn_objects);
657 prev_conn_objects = NULL;
658 prev_conn_objects = s_conn_return_others (prev_conn_objects, new_net);
660 #if DEBUG
661 s_conn_print(new_net->conn_list);
662 #endif
664 o_invalidate (w_current, new_net);
666 o_invalidate_glist (w_current, prev_conn_objects);
668 g_list_free (prev_conn_objects);
669 prev_conn_objects = NULL;
672 toplevel->page_current->CHANGED = 1;
673 w_current->first_wx = save_wx;
674 w_current->first_wy = save_wy;
675 o_undo_savestate(w_current, UNDO_ALL);
677 return (TRUE);
680 /*! \brief erase and redraw the rubber lines when drawing a net
681 * \par Function Description
682 * This function draws the rubbernet lines when drawing a net.
684 void o_net_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
686 int ortho, horizontal, quadrant;
688 g_assert( w_current->inside_action != 0 );
690 /* Orthognal mode enabled when Control Key is NOT pressed or
691 if we are using magnetic mode */
692 ortho = !w_current->CONTROLKEY || w_current->magneticnet_mode;
694 if (w_current->rubber_visible)
695 o_net_invalidate_rubber (w_current);
697 if (w_current->magneticnet_mode) {
698 if (w_current->CONTROLKEY) {
699 /* set the magnetic marker position to current xy if the
700 controlkey is pressed. Thus the net will not connect to
701 the closest net if we finish the net drawing */
702 w_current->magnetic_wx = w_x;
703 w_current->magnetic_wy = w_y;
705 else {
706 o_net_find_magnetic(w_current, w_x, w_y);
710 w_current->second_wx = w_x;
711 w_current->second_wy = w_y;
713 /* In orthogonal mode secondary line is the same as the first */
714 if (!ortho) {
715 w_current->third_wx = w_current->second_wx;
716 w_current->third_wy = w_current->second_wy;
718 /* If you press the control key then you can draw non-ortho nets */
719 else {
720 if (w_current->second_wy > w_current->first_wy)
721 quadrant = w_current->second_wx > w_current->first_wx ? QUADRANT1: QUADRANT2;
722 else
723 quadrant = w_current->second_wx > w_current->first_wx ? QUADRANT4: QUADRANT3;
725 horizontal = w_current->net_direction & quadrant;
727 if (!w_current->SHIFTKEY)
728 horizontal = !horizontal;
730 /* calculate the co-ordinates necessary to draw the lines*/
731 /* Pressing the shift key will cause the vertical and horizontal lines to switch places */
732 if ( horizontal ) {
733 w_current->second_wy = w_current->first_wy;
734 w_current->third_wx = w_current->second_wx;
735 w_current->third_wy = w_y;
736 } else {
737 w_current->second_wx = w_current->first_wx;
738 w_current->third_wx = w_x;
739 w_current->third_wy = w_current->second_wy;
743 o_net_invalidate_rubber (w_current);
744 w_current->rubber_visible = 1;
747 /*! \brief draw rubbernet lines to the gc
748 * \par Function Description
749 * This function draws the rubbernets to the graphic context
751 void o_net_draw_rubber(GSCHEM_TOPLEVEL *w_current)
753 int size = 0, w_magnetic_halfsize;
755 if (w_current->toplevel->net_style == THICK)
756 size = NET_WIDTH;
758 gschem_cairo_set_source_color (w_current,
759 x_color_lookup_dark (SELECT_COLOR));
761 if (w_current->magneticnet_mode) {
762 if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
763 w_magnetic_halfsize = max (4 * size,
764 WORLDabs (w_current, MAGNETIC_HALFSIZE));
765 gschem_cairo_arc (w_current, size, w_current->magnetic_wx,
766 w_current->magnetic_wy,
767 w_magnetic_halfsize, 0, 360);
771 /* Primary line */
772 gschem_cairo_line (w_current, END_NONE, size,
773 w_current->first_wx, w_current->first_wy,
774 w_current->second_wx, w_current->second_wy);
776 /* Secondary line */
777 gschem_cairo_line (w_current, END_NONE, size,
778 w_current->second_wx, w_current->second_wy,
779 w_current->third_wx, w_current->third_wy);
781 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, size, -1, -1);
785 /*! \todo Finish function documentation!!!
786 * \brief
787 * \par Function Description
790 void o_net_invalidate_rubber (GSCHEM_TOPLEVEL *w_current)
792 TOPLEVEL *toplevel = w_current->toplevel;
793 int size = 0, magnetic_halfsize;
794 int bloat;
795 int magnetic_x, magnetic_y;
796 int first_x, first_y, third_x, third_y, second_x, second_y;
797 int x1, y1, x2, y2;
799 WORLDtoSCREEN (w_current, w_current->magnetic_wx, w_current->magnetic_wy,
800 &magnetic_x, &magnetic_y);
801 WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy,
802 &first_x, &first_y);
803 WORLDtoSCREEN (w_current, w_current->third_wx, w_current->third_wy,
804 &third_x, &third_y);
805 WORLDtoSCREEN (w_current, w_current->second_wx, w_current->second_wy,
806 &second_x, &second_y);
808 if (toplevel->net_style == THICK) {
809 size = SCREENabs (w_current, NET_WIDTH);
811 size = max (size, 0);
812 bloat = size / 2;
814 if (w_current->magneticnet_mode) {
815 if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
816 magnetic_halfsize = max (4 * size, MAGNETIC_HALFSIZE);
818 o_invalidate_rect (w_current, magnetic_x - magnetic_halfsize,
819 magnetic_y - magnetic_halfsize,
820 magnetic_x + magnetic_halfsize,
821 magnetic_y + magnetic_halfsize);
825 x1 = min (first_x, second_x) - bloat;
826 x2 = max (first_x, second_x) + bloat;
827 y1 = min (first_y, second_y) - bloat;
828 y2 = max (first_y, second_y) + bloat;
829 o_invalidate_rect (w_current, x1, y1, x2, y2);
831 x1 = min (second_x, third_x) - bloat;
832 x2 = max (second_x, third_x) + bloat;
833 y1 = min (second_y, third_y) - bloat;
834 y2 = max (second_y, third_y) + bloat;
835 o_invalidate_rect (w_current, x1, y1, x2, y2);
839 /*! \todo Finish function documentation!!!
840 * \brief
841 * \par Function Description
844 int o_net_add_busrippers(GSCHEM_TOPLEVEL *w_current, OBJECT *net_obj,
845 GList *prev_conn_objects)
848 TOPLEVEL *toplevel = w_current->toplevel;
849 OBJECT *new_obj;
850 int color;
851 GList *cl_current = NULL;
852 OBJECT *bus_object = NULL;
853 CONN *found_conn = NULL;
854 int done;
855 int otherone;
856 BUS_RIPPER rippers[2];
857 int ripper_count = 0;
858 int i;
859 double length;
860 int sign;
861 double distance1, distance2;
862 int first, second;
863 int made_changes = FALSE;
864 const int ripper_size = w_current->bus_ripper_size;
865 int complex_angle = 0;
866 const CLibSymbol *rippersym = NULL;
868 length = o_line_length(net_obj);
870 if (!prev_conn_objects) {
871 return(FALSE);
874 if (length <= ripper_size) {
875 return(FALSE);
878 if (toplevel->override_net_color == -1) {
879 color = NET_COLOR;
880 } else {
881 color = toplevel->override_net_color;
885 /* check for a bus connection and draw rippers if so */
886 cl_current = prev_conn_objects;
887 while (cl_current != NULL) {
889 bus_object = (OBJECT *) cl_current->data;
890 if (bus_object && bus_object->type == OBJ_BUS) {
891 /* yes, using the net routine is okay */
892 int bus_orientation = o_net_orientation(bus_object);
893 int net_orientation = o_net_orientation(net_obj);
895 /* find the CONN structure which is associated with this object */
896 GList *cl_current2 = net_obj->conn_list;
897 done = FALSE;
898 while (cl_current2 != NULL && !done) {
899 CONN *tmp_conn = (CONN *) cl_current2->data;
901 if (tmp_conn && tmp_conn->other_object &&
902 tmp_conn->other_object == bus_object) {
904 found_conn = tmp_conn;
905 done = TRUE;
908 cl_current2 = g_list_next(cl_current2);
911 if (!found_conn) {
912 return(FALSE);
915 otherone = !found_conn->whichone;
917 /* now deal with the found connection */
918 if (bus_orientation == HORIZONTAL && net_orientation == VERTICAL) {
919 /* printf("found horiz bus %s %d!\n", bus_object->name,
920 found_conn->whichone);*/
922 sign = bus_object->bus_ripper_direction;
923 if (!sign) {
924 if (bus_object->line->x[0] < bus_object->line->x[1]) {
925 first = 0;
926 second = 1;
927 } else {
928 first = 1;
929 second = 0;
932 distance1 = abs(bus_object->line->x[first] -
933 net_obj->line->x[found_conn->whichone]);
934 distance2 = abs(bus_object->line->x[second] -
935 net_obj->line->x[found_conn->whichone]);
937 if (distance1 <= distance2) {
938 sign = 1;
939 } else {
940 sign = -1;
942 bus_object->bus_ripper_direction = sign;
944 /* printf("hor sign: %d\n", sign); */
946 if (net_obj->line->y[otherone] < bus_object->line->y[0]) {
947 /* new net is below bus */
948 /*printf("below\n");*/
950 if (ripper_count >= 2) {
951 /* try to exit gracefully */
952 fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
953 made_changes = FALSE;
954 break;
957 if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
958 /* non-symmetric */
959 if (sign == 1) {
960 complex_angle = 0;
961 } else {
962 complex_angle = 90;
964 } else {
965 /* symmetric */
966 complex_angle = 0;
969 net_obj->line->y[found_conn->whichone] -= ripper_size;
970 o_recalc_single_object(toplevel, net_obj);
971 rippers[ripper_count].x[0] =
972 net_obj->line->x[found_conn->whichone];
973 rippers[ripper_count].y[0] =
974 net_obj->line->y[found_conn->whichone];
975 rippers[ripper_count].x[1] =
976 net_obj->line->x[found_conn->whichone] + sign*ripper_size;
977 rippers[ripper_count].y[1] =
978 net_obj->line->y[found_conn->whichone] + ripper_size;
979 ripper_count++;
980 /* printf("done\n"); */
981 made_changes++;
983 } else {
984 /* new net is above bus */
985 /* printf("above\n"); */
987 if (ripper_count >= 2) {
988 /* try to exit gracefully */
989 fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
990 made_changes = FALSE;
991 break;
994 if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
995 /* non-symmetric */
996 if (sign == 1) {
997 complex_angle = 270;
998 } else {
999 complex_angle = 180;
1001 } else {
1002 /* symmetric */
1003 complex_angle = 180;
1006 net_obj->line->y[found_conn->whichone] += ripper_size;
1007 o_recalc_single_object(toplevel, net_obj);
1008 rippers[ripper_count].x[0] =
1009 net_obj->line->x[found_conn->whichone];
1010 rippers[ripper_count].y[0] =
1011 net_obj->line->y[found_conn->whichone];
1012 rippers[ripper_count].x[1] =
1013 net_obj->line->x[found_conn->whichone] + sign*ripper_size;
1014 rippers[ripper_count].y[1] =
1015 net_obj->line->y[found_conn->whichone] - ripper_size;
1016 ripper_count++;
1018 /* printf("done\n"); */
1019 made_changes++;
1023 } else if (bus_orientation == VERTICAL &&
1024 net_orientation == HORIZONTAL) {
1026 /* printf("found vert bus %s %d!\n", bus_object->name,
1027 found_conn->whichone); */
1029 sign = bus_object->bus_ripper_direction;
1030 if (!sign) {
1031 if (bus_object->line->y[0] < bus_object->line->y[1]) {
1032 first = 0;
1033 second = 1;
1034 } else {
1035 first = 1;
1036 second = 0;
1039 distance1 = abs(bus_object->line->y[first] -
1040 net_obj->line->y[found_conn->whichone]);
1041 distance2 = abs(bus_object->line->y[second] -
1042 net_obj->line->y[found_conn->whichone]);
1044 if (distance1 <= distance2) {
1045 sign = 1;
1046 } else {
1047 sign = -1;
1049 bus_object->bus_ripper_direction = sign;
1051 /* printf("ver sign: %d\n", sign); */
1054 if (net_obj->line->x[otherone] < bus_object->line->x[0]) {
1055 /* new net is to the left of the bus */
1056 /* printf("left\n"); */
1058 if (ripper_count >= 2) {
1059 /* try to exit gracefully */
1060 fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
1061 made_changes = FALSE;
1062 break;
1065 if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
1066 /* non-symmetric */
1067 if (sign == 1) {
1068 complex_angle = 0;
1069 } else {
1070 complex_angle = 270;
1072 } else {
1073 /* symmetric */
1074 complex_angle = 270;
1077 net_obj->line->x[found_conn->whichone] -= ripper_size;
1078 o_recalc_single_object(toplevel, net_obj);
1079 rippers[ripper_count].x[0] =
1080 net_obj->line->x[found_conn->whichone];
1081 rippers[ripper_count].y[0] =
1082 net_obj->line->y[found_conn->whichone];
1083 rippers[ripper_count].x[1] =
1084 net_obj->line->x[found_conn->whichone] + ripper_size;
1085 rippers[ripper_count].y[1] =
1086 net_obj->line->y[found_conn->whichone] + sign*ripper_size;
1087 ripper_count++;
1089 made_changes++;
1090 } else {
1091 /* new net is to the right of the bus */
1092 /* printf("right\n"); */
1094 if (ripper_count >= 2) {
1095 /* try to exit gracefully */
1096 fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
1097 made_changes = FALSE;
1098 break;
1101 if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
1102 /* non-symmetric */
1103 if (sign == 1) {
1104 complex_angle = 90;
1105 } else {
1106 complex_angle = 180;
1108 } else {
1109 /* symmetric */
1110 complex_angle = 90;
1113 net_obj->line->x[found_conn->whichone] += ripper_size;
1114 o_recalc_single_object(toplevel, net_obj);
1115 rippers[ripper_count].x[0] =
1116 net_obj->line->x[found_conn->whichone];
1117 rippers[ripper_count].y[0] =
1118 net_obj->line->y[found_conn->whichone];
1119 rippers[ripper_count].x[1] =
1120 net_obj->line->x[found_conn->whichone] - ripper_size;
1121 rippers[ripper_count].y[1] =
1122 net_obj->line->y[found_conn->whichone] + sign*ripper_size;
1123 ripper_count++;
1125 made_changes++;
1131 cl_current = g_list_next(cl_current);
1134 if (made_changes) {
1135 s_conn_remove_object (toplevel, net_obj);
1137 if (w_current->bus_ripper_type == COMP_BUS_RIPPER) {
1138 GList *symlist =
1139 s_clib_search (toplevel->bus_ripper_symname, CLIB_EXACT);
1140 if (symlist != NULL) {
1141 rippersym = (CLibSymbol *) symlist->data;
1143 g_list_free (symlist);
1146 for (i = 0; i < ripper_count; i++) {
1147 if (w_current->bus_ripper_type == NET_BUS_RIPPER) {
1148 new_obj = o_net_new(toplevel, OBJ_NET, color,
1149 rippers[i].x[0], rippers[i].y[0],
1150 rippers[i].x[1], rippers[i].y[1]);
1151 s_page_append (toplevel, toplevel->page_current, new_obj);
1152 } else {
1154 if (rippersym != NULL) {
1155 new_obj = o_complex_new (toplevel, OBJ_COMPLEX, DEFAULT_COLOR,
1156 rippers[i].x[0], rippers[i].y[0],
1157 complex_angle, 0,
1158 rippersym,
1159 toplevel->bus_ripper_symname, 1);
1160 s_page_append_list (toplevel, toplevel->page_current,
1161 o_complex_promote_attribs (toplevel, new_obj));
1162 s_page_append (toplevel, toplevel->page_current, new_obj);
1164 o_invalidate (w_current, new_obj);
1165 } else {
1166 s_log_message(_("Bus ripper symbol [%s] was not found in any component library\n"),
1167 toplevel->bus_ripper_symname);
1172 s_conn_update_object (toplevel, net_obj);
1173 return(TRUE);
1176 return(FALSE);