Remove extra debug message
[geda-gaf.git] / gschem / src / o_net.c
blobae8aae49c27da89dd0f4eb008484f4391d6cb360
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <math.h>
25 #include "gschem.h"
28 /* magnetic options */
29 /* half size of the magnetic marker on the screen. */
30 #define MAGNETIC_HALFSIZE 6
32 /* define how far the cursor could be to activate magnetic */
33 #define MAGNETIC_PIN_REACH 50
34 #define MAGNETIC_NET_REACH 20
35 #define MAGNETIC_BUS_REACH 30
37 /* weighting factors to tell that a pin is more important than a net */
38 #define MAGNETIC_PIN_WEIGHT 5.0
39 #define MAGNETIC_NET_WEIGHT 2.0
40 #define MAGNETIC_BUS_WEIGHT 3.0
42 /* Bit definitions for the four quardrants of the direction guessing */
43 #define QUADRANT1 0x01
44 #define QUADRANT2 0x02
45 #define QUADRANT3 0x04
46 #define QUADRANT4 0x08
49 /*! \brief Reset all variables used for net drawing
50 * \par Function Description
51 * This function resets all variables from GschemToplevel that are used
52 * for net drawing. This function should be called when escaping from
53 * a net drawing action or before entering it.
55 void o_net_reset(GschemToplevel *w_current)
57 o_net_invalidate_rubber (w_current);
58 w_current->first_wx = w_current->first_wy = -1;
59 w_current->second_wx = w_current->second_wy = -1;
60 w_current->third_wx = w_current->third_wy = -1;
61 w_current->magnetic_wx = w_current->magnetic_wy = -1;
62 w_current->rubber_visible = 0;
63 i_action_stop (w_current);
66 /*! \brief guess the best direction for the next net drawing action
67 * \par Function Description
68 * This function checks all connectable objects at a starting point.
69 * It determines the best drawing direction for each quadrant of the
70 * possible net endpoint.
72 * The directions are stored in the GschemToplevel->net_direction variable
73 * as a bitfield.
75 void o_net_guess_direction(GschemToplevel *w_current,
76 int wx, int wy)
78 int up=0, down=0, left=0, right=0;
79 int x1, y1, x2, y2;
80 int xmin, ymin, xmax, ymax;
81 int orientation;
82 GList *object_list, *iter1, *iter2;
83 OBJECT *o_current;
85 int *current_rules;
86 /* badness values {OVERWRITE, ORTHO, CONTINUE} */
87 const int pin_rules[] = {100, 50, 0};
88 const int bus_rules[] = {90, 0, 40};
89 const int net_rules[] = {80, 30, 0};
91 GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
92 g_return_if_fail (page_view != NULL);
94 PAGE *page = gschem_page_view_get_page (page_view);
95 g_return_if_fail (page != NULL);
97 object_list = g_list_append (NULL, page->connectible_list);
99 for (iter1 = object_list; iter1 != NULL; iter1 = g_list_next(iter1)) {
100 for (iter2 = (GList*) iter1->data; iter2 != NULL; iter2 = g_list_next(iter2)) {
101 o_current = (OBJECT*) iter2->data;
103 if ((orientation = o_net_orientation(o_current)) == NEITHER)
104 continue;
106 switch (o_current->type) {
107 case OBJ_NET:
108 current_rules = (int*) net_rules;
109 break;
110 case OBJ_PIN:
111 current_rules = (int*) pin_rules;
112 break;
113 case OBJ_BUS:
114 current_rules = (int*) bus_rules;
115 break;
116 default:
117 g_assert_not_reached ();
120 x1 = o_current->line->x[0];
121 x2 = o_current->line->x[1];
122 y1 = o_current->line->y[0];
123 y2 = o_current->line->y[1];
125 xmin = min(x1, x2);
126 ymin = min(y1, y2);
127 xmax = max(x1, x2);
128 ymax = max(y1, y2);
130 if (orientation == HORIZONTAL && wy == y1) {
131 if (wx == xmin) {
132 up = max(up, current_rules[1]);
133 down = max(down, current_rules[1]);
134 right = max(right, current_rules[0]);
135 left = max(left, current_rules[2]);
137 else if (wx == xmax) {
138 up = max(up, current_rules[1]);
139 down = max(down, current_rules[1]);
140 right = max(right, current_rules[2]);
141 left = max(left, current_rules[0]);
143 else if (xmin < wx && wx < xmax) {
144 up = max(up, current_rules[1]);
145 down = max(down, current_rules[1]);
146 right = max(right, current_rules[0]);
147 left = max(left, current_rules[0]);
149 else {
150 continue;
153 if (orientation == VERTICAL && wx == x1) {
154 if (wy == ymin) {
155 up = max(up, current_rules[0]);
156 down = max(down, current_rules[2]);
157 right = max(right, current_rules[1]);
158 left = max(left, current_rules[1]);
160 else if (wy == ymax) {
161 up = max(up, current_rules[2]);
162 down = max(down, current_rules[0]);
163 right = max(right, current_rules[1]);
164 left = max(left, current_rules[1]);
166 else if (ymin < wy && wy < ymax) {
167 up = max(up, current_rules[0]);
168 down = max(down, current_rules[0]);
169 right = max(right, current_rules[1]);
170 left = max(left, current_rules[1]);
172 else {
173 continue;
179 w_current->net_direction = 0;
180 w_current->net_direction |= up >= right ? 0 : QUADRANT1;
181 w_current->net_direction |= up >= left ? 0 : QUADRANT2;
182 w_current->net_direction |= down >= left ? 0 : QUADRANT3;
183 w_current->net_direction |= down >= right ? 0 : QUADRANT4;
185 #if 0
186 printf("o_net_guess_direction: up=%d down=%d left=%d right=%d direction=%d\n",
187 up, down, left, right, w_current->net_direction);
188 #endif
189 g_list_free (object_list);
192 /*! \brief find the closest possible location to connect to
193 * \par Function Description
194 * This function calculates the distance to all connectable objects
195 * and searches the closest connection point.
196 * It searches for pins, nets and busses.
198 * The connection point is stored in GschemToplevel->magnetic_wx and
199 * GschemToplevel->magnetic_wy. If no connection is found. Both variables
200 * are set to -1.
202 void o_net_find_magnetic(GschemToplevel *w_current,
203 int w_x, int w_y)
205 int x1, x2, y1, y2, min_x, min_y;
206 double mindist, minbest, dist1, dist2;
207 double weight, min_weight;
208 int magnetic_reach = 0;
209 OBJECT *o_current;
210 OBJECT *o_magnetic = NULL;
211 GList *object_list, *iter1, *iter2;
213 GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
214 g_return_if_fail (page_view != NULL);
216 PAGE *page = gschem_page_view_get_page (page_view);
217 g_return_if_fail (page != NULL);
219 minbest = min_x = min_y = 0;
220 min_weight = 0;
222 /* max distance of all the different reaches */
223 magnetic_reach = max(MAGNETIC_PIN_REACH, MAGNETIC_NET_REACH);
224 magnetic_reach = max(magnetic_reach, MAGNETIC_BUS_REACH);
226 object_list = g_list_append (NULL, page->connectible_list);
228 for (iter1 = object_list; iter1 != NULL; iter1 = g_list_next(iter1)) {
229 for (iter2 = (GList*) iter1->data; iter2 != NULL; iter2 = g_list_next(iter2)) {
230 int left, top, right, bottom;
231 o_current = (OBJECT*) iter2->data;
233 if (!world_get_single_object_bounds(page->toplevel, o_current,
234 &left, &top, &right, &bottom) ||
235 !visible (w_current, left, top, right, bottom))
236 continue; /* skip invisible objects */
238 if (o_current->type == OBJ_PIN) {
239 min_x = o_current->line->x[o_current->whichend];
240 min_y = o_current->line->y[o_current->whichend];
242 mindist = hypot(w_x - min_x, w_y - min_y);
243 weight = mindist / MAGNETIC_PIN_WEIGHT;
246 else if (o_current->type == OBJ_NET
247 || o_current->type == OBJ_BUS) {
248 /* we have 3 possible points to connect:
249 2 endpoints and 1 midpoint point */
250 x1 = o_current->line->x[0];
251 y1 = o_current->line->y[0];
252 x2 = o_current->line->x[1];
253 y2 = o_current->line->y[1];
254 /* endpoint tests */
255 dist1 = hypot(w_x - x1, w_y - y1);
256 dist2 = hypot(w_x - x2, w_y - y2);
257 if (dist1 < dist2) {
258 min_x = x1;
259 min_y = y1;
260 mindist = dist1;
262 else {
263 min_x = x2;
264 min_y = y2;
265 mindist = dist2;
268 /* midpoint tests */
269 if ((x1 == x2) /* vertical net */
270 && ((y1 >= w_y && w_y >= y2)
271 || (y2 >= w_y && w_y >= y1))) {
272 if (abs(w_x - x1) < mindist) {
273 mindist = abs(w_x - x1);
274 min_x = x1;
275 min_y = w_y;
278 if ((y1 == y2) /* horitontal net */
279 && ((x1 >= w_x && w_x >= x2)
280 || (x2 >= w_x && w_x >= x1))) {
281 if (abs(w_y - y1) < mindist) {
282 mindist = abs(w_y - y1);
283 min_x = w_x;
284 min_y = y1;
288 if (o_current->type == OBJ_BUS)
289 weight = mindist / MAGNETIC_BUS_WEIGHT;
290 else /* OBJ_NET */
291 weight = mindist / MAGNETIC_NET_WEIGHT;
293 else { /* neither pin nor net or bus */
294 continue;
297 if (o_magnetic == NULL
298 || weight < min_weight) {
299 minbest = mindist;
300 min_weight = weight;
301 o_magnetic = o_current;
302 w_current->magnetic_wx = min_x;
303 w_current->magnetic_wy = min_y;
308 /* check whether we found an object and if it's close enough */
309 if (o_magnetic != NULL) {
310 switch (o_magnetic->type) {
311 case (OBJ_PIN): magnetic_reach = MAGNETIC_PIN_REACH; break;
312 case (OBJ_NET): magnetic_reach = MAGNETIC_NET_REACH; break;
313 case (OBJ_BUS): magnetic_reach = MAGNETIC_BUS_REACH; break;
315 if (minbest > gschem_page_view_WORLDabs (page_view, magnetic_reach)) {
316 w_current->magnetic_wx = -1;
317 w_current->magnetic_wy = -1;
320 else {
321 w_current->magnetic_wx = -1;
322 w_current->magnetic_wy = -1;
325 g_list_free (object_list);
328 /*! \brief calcutates the net route to the magnetic marker
329 * \par Function Description
330 * Depending on the two rubbernet lines from start to last and from
331 * last to second, the 3 coordinates are manipulated to find
332 * a way to the magnetic marker.
334 void o_net_finishmagnetic(GschemToplevel *w_current)
336 int primary_zero_length, secondary_zero_length;
338 primary_zero_length = ((w_current->first_wx == w_current->second_wx)
339 && (w_current->first_wy == w_current->second_wy));
341 secondary_zero_length = ((w_current->second_wx == w_current->third_wx)
342 && (w_current->second_wy == w_current->third_wy));
344 if (!primary_zero_length && secondary_zero_length) {
345 if (w_current->first_wx == w_current->second_wx) {
346 /* expand vertical line to magnetic_wy */
347 w_current->second_wy = w_current->magnetic_wy;
349 else if (w_current->first_wy == w_current->second_wy) {
350 /* expand horitontal line to vertical to magnetic_wx */
351 w_current->second_wx = w_current->magnetic_wx;
353 /* connect to magnetic */
354 w_current->third_wx = w_current->magnetic_wx;
355 w_current->third_wy = w_current->magnetic_wy;
358 if (primary_zero_length && !secondary_zero_length) {
359 /* move second line to the first (empty line) */
360 w_current->first_wx = w_current->second_wx;
361 w_current->first_wy = w_current->second_wy;
362 if (w_current->second_wx == w_current->third_wx) {
363 /* expand vertical line to magnetic_wy */
364 w_current->second_wy = w_current->magnetic_wy;
366 else if (w_current->second_wy == w_current->third_wy) {
367 /* expand horitontal line to magnetic_wx */
368 w_current->second_wx = w_current->magnetic_wx;
370 /* connect to magnetic */
371 w_current->third_wx = w_current->magnetic_wx;
372 w_current->third_wy = w_current->magnetic_wy;
375 if (!primary_zero_length && !secondary_zero_length) {
376 /* expand line in both directions */
377 if (w_current->first_wx == w_current->second_wx) {
378 w_current->second_wy = w_current->magnetic_wy;
380 else {
381 w_current->second_wx = w_current->magnetic_wx;
383 w_current->third_wx = w_current->magnetic_wx;
384 w_current->third_wy = w_current->magnetic_wy;
388 /*! \brief callback function to draw a net marker in magnetic mode
389 * \par Function Description
390 * If the mouse is moved, this function is called to update the
391 * position of the magnetic marker.
392 * If the controllkey is pressed the magnetic marker follows the mouse.
394 void o_net_start_magnetic(GschemToplevel *w_current, int w_x, int w_y)
396 if (!(gschem_options_get_magnetic_net_mode (w_current->options))) {
397 return;
400 o_net_invalidate_rubber (w_current);
402 if (w_current->CONTROLKEY) {
403 w_current->magnetic_wx = w_x;
404 w_current->magnetic_wy = w_y;
406 else {
407 o_net_find_magnetic(w_current, w_x, w_y);
410 o_net_invalidate_rubber (w_current);
411 w_current->rubber_visible = 1;
414 /*! \brief set the start point of a new net
415 * \par Function Description
416 * This function sets the start point of a new net at the position of the
417 * cursor. If we have a visible magnetic marker, we use that instead of
418 * the cursor position
420 void o_net_start(GschemToplevel *w_current, int w_x, int w_y)
422 i_action_start (w_current);
424 if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
425 w_current->first_wx = w_current->magnetic_wx;
426 w_current->first_wy = w_current->magnetic_wy;
428 else {
429 w_current->first_wx = w_x;
430 w_current->first_wy = w_y;
433 w_current->second_wx = w_current->third_wx = w_current->first_wx;
434 w_current->second_wy = w_current->third_wy = w_current->first_wy;
436 if (w_current->first_wx != snap_grid (w_current, w_current->first_wx)
437 || w_current->first_wy != snap_grid (w_current, w_current->first_wy))
438 s_log_message(_("Warning: Starting net at off grid coordinate\n"));
440 if (w_current->net_direction_mode)
441 o_net_guess_direction(w_current, w_current->first_wx, w_current->first_wy);
444 /*! \brief finish a net drawing action
445 * \par Function Description
446 * This function finishes the drawing of a net. If we have a visible
447 * magnetic marker, we use that instead of the current cursor
448 * position.
450 * The rubber nets are removed, the nets and cues are drawn and the
451 * net is added to the TOPLEVEL structure.
453 * The function returns TRUE if it has drawn a net, FALSE otherwise.
455 void o_net_end(GschemToplevel *w_current, int w_x, int w_y)
457 int primary_zero_length, secondary_zero_length;
458 int found_primary_connection = FALSE;
459 int save_wx, save_wy;
461 GList *prev_conn_objects;
462 OBJECT *new_net = NULL;
464 /* Save a list of added objects to run the %add-objects-hook later */
465 GList *added_objects = NULL;
467 g_assert( w_current->inside_action != 0 );
469 GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
470 g_return_if_fail (page_view != NULL);
472 PAGE *page = gschem_page_view_get_page (page_view);
473 g_return_if_fail (page != NULL);
475 o_net_invalidate_rubber (w_current);
477 if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1)
478 o_net_finishmagnetic(w_current);
480 w_current->rubber_visible = 0;
482 /* See if either of the nets are zero length. We'll only add */
483 /* the non-zero ones */
484 primary_zero_length = (w_current->first_wx == w_current->second_wx) &&
485 (w_current->first_wy == w_current->second_wy);
487 secondary_zero_length = (w_current->second_wx == w_current->third_wx) &&
488 (w_current->second_wy == w_current->third_wy);
490 /* If both nets are zero length... */
491 /* this ends the net drawing behavior */
492 if ( primary_zero_length && secondary_zero_length ) {
493 o_net_reset(w_current);
494 return;
497 save_wx = w_current->third_wx;
498 save_wy = w_current->third_wy;
500 if (w_current->third_wx != snap_grid (w_current, w_current->third_wx)
501 || w_current->third_wy != snap_grid (w_current, w_current->third_wy))
502 s_log_message(_("Warning: Ending net at off grid coordinate\n"));
504 if (!primary_zero_length ) {
505 /* create primary net */
506 new_net = o_net_new(page->toplevel, OBJ_NET, NET_COLOR,
507 w_current->first_wx, w_current->first_wy,
508 w_current->second_wx, w_current->second_wy);
509 s_page_append (page->toplevel, page, new_net);
511 added_objects = g_list_prepend (added_objects, new_net);
513 /* conn stuff */
514 /* LEAK CHECK 1 */
515 prev_conn_objects = s_conn_return_others (NULL, new_net);
516 o_net_add_busrippers (w_current, new_net, prev_conn_objects);
517 g_list_free (prev_conn_objects);
519 #if DEBUG
520 printf("primary:\n");
521 s_conn_print(new_net->conn_list);
522 #endif
524 /* Go off and search for valid connection on this newly created net */
525 found_primary_connection = s_conn_net_search(new_net, 1,
526 new_net->conn_list);
527 if (found_primary_connection)
529 /* if a net connection is found, reset start point of next net */
530 save_wx = w_current->second_wx;
531 save_wy = w_current->second_wy;
536 /* If the second net is not zero length, add it as well */
537 /* Also, a valid net connection from the primary net was not found */
538 if (!secondary_zero_length && !found_primary_connection) {
540 /* Add secondary net */
541 new_net = o_net_new(page->toplevel, OBJ_NET, NET_COLOR,
542 w_current->second_wx, w_current->second_wy,
543 w_current->third_wx, w_current->third_wy);
544 s_page_append (page->toplevel, page, new_net);
546 added_objects = g_list_prepend (added_objects, new_net);
548 /* conn stuff */
549 /* LEAK CHECK 2 */
550 prev_conn_objects = s_conn_return_others (NULL, new_net);
551 o_net_add_busrippers (w_current, new_net, prev_conn_objects);
552 g_list_free (prev_conn_objects);
553 #if DEBUG
554 s_conn_print(new_net->conn_list);
555 #endif
558 /* Call add-objects-hook */
559 if (added_objects != NULL) {
560 g_run_hook_object_list (w_current, "%add-objects-hook", added_objects);
561 g_list_free (added_objects);
564 w_current->first_wx = save_wx;
565 w_current->first_wy = save_wy;
567 gschem_toplevel_page_content_changed (w_current, page);
568 o_undo_savestate_old (w_current, UNDO_ALL, _("Net"));
570 /* Continue net drawing */
571 o_net_start(w_current, w_current->first_wx, w_current->first_wy);
574 /*! \brief erase and redraw the rubber lines when drawing a net
575 * \par Function Description
576 * This function draws the rubbernet lines when drawing a net.
578 void o_net_motion (GschemToplevel *w_current, int w_x, int w_y)
580 int ortho, horizontal, quadrant;
581 gboolean magnetic_net_mode;
583 g_return_if_fail (w_current != NULL);
584 g_assert( w_current->inside_action != 0 );
586 magnetic_net_mode = gschem_options_get_magnetic_net_mode (w_current->options);
588 /* Orthognal mode enabled when Control Key is NOT pressed or
589 if we are using magnetic mode */
590 ortho = !w_current->CONTROLKEY || magnetic_net_mode;
592 if (w_current->rubber_visible)
593 o_net_invalidate_rubber (w_current);
595 if (magnetic_net_mode) {
596 if (w_current->CONTROLKEY) {
597 /* set the magnetic marker position to current xy if the
598 controlkey is pressed. Thus the net will not connect to
599 the closest net if we finish the net drawing */
600 w_current->magnetic_wx = w_x;
601 w_current->magnetic_wy = w_y;
603 else {
604 o_net_find_magnetic(w_current, w_x, w_y);
608 w_current->second_wx = w_x;
609 w_current->second_wy = w_y;
611 /* In orthogonal mode secondary line is the same as the first */
612 if (!ortho) {
613 w_current->third_wx = w_current->second_wx;
614 w_current->third_wy = w_current->second_wy;
616 /* If you press the control key then you can draw non-ortho nets */
617 else {
618 if (w_current->second_wy > w_current->first_wy)
619 quadrant = w_current->second_wx > w_current->first_wx ? QUADRANT1: QUADRANT2;
620 else
621 quadrant = w_current->second_wx > w_current->first_wx ? QUADRANT4: QUADRANT3;
623 horizontal = w_current->net_direction & quadrant;
625 if (!w_current->SHIFTKEY)
626 horizontal = !horizontal;
628 /* calculate the co-ordinates necessary to draw the lines*/
629 /* Pressing the shift key will cause the vertical and horizontal lines to switch places */
630 if ( horizontal ) {
631 w_current->second_wy = w_current->first_wy;
632 w_current->third_wx = w_current->second_wx;
633 w_current->third_wy = w_y;
634 } else {
635 w_current->second_wx = w_current->first_wx;
636 w_current->third_wx = w_x;
637 w_current->third_wy = w_current->second_wy;
641 o_net_invalidate_rubber (w_current);
642 w_current->rubber_visible = 1;
645 /*! \brief draw rubbernet lines to the gc
646 * \par Function Description
647 * This function draws the rubbernets to the graphic context
649 void
650 o_net_draw_rubber(GschemToplevel *w_current, EdaRenderer *renderer)
652 int size = NET_WIDTH, w_magnetic_halfsize;
653 cairo_t *cr = eda_renderer_get_cairo_context (renderer);
654 GArray *color_map = eda_renderer_get_color_map (renderer);
655 int flags = eda_renderer_get_cairo_flags (renderer);
656 gboolean magnetic_net_mode;
658 g_return_if_fail (w_current != NULL);
660 GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
661 g_return_if_fail (page_view != NULL);
663 eda_cairo_set_source_color (cr, SELECT_COLOR, color_map);
665 magnetic_net_mode = gschem_options_get_magnetic_net_mode (w_current->options);
667 if (magnetic_net_mode) {
668 if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
669 w_magnetic_halfsize = max (4 * size,
670 gschem_page_view_WORLDabs (page_view, MAGNETIC_HALFSIZE));
671 eda_cairo_arc (cr, flags, size,
672 w_current->magnetic_wx, w_current->magnetic_wy,
673 w_magnetic_halfsize, 0, 360);
677 /* Primary line */
678 eda_cairo_line (cr, flags, END_NONE, size,
679 w_current->first_wx, w_current->first_wy,
680 w_current->second_wx, w_current->second_wy);
682 /* Secondary line */
683 eda_cairo_line (cr, flags, END_NONE, size,
684 w_current->second_wx, w_current->second_wy,
685 w_current->third_wx, w_current->third_wy);
687 eda_cairo_stroke (cr, flags, TYPE_SOLID, END_NONE, size, -1, -1);
691 /*! \todo Finish function documentation!!!
692 * \brief
693 * \par Function Description
696 void o_net_invalidate_rubber (GschemToplevel *w_current)
698 int size = 0, magnetic_halfsize;
699 int magnetic_x, magnetic_y;
700 gboolean magnetic_net_mode;
702 g_return_if_fail (w_current != NULL);
704 GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
705 g_return_if_fail (page_view != NULL);
707 gschem_page_view_WORLDtoSCREEN (page_view,
708 w_current->magnetic_wx, w_current->magnetic_wy,
709 &magnetic_x, &magnetic_y);
711 size = gschem_page_view_SCREENabs (page_view, NET_WIDTH);
713 magnetic_net_mode = gschem_options_get_magnetic_net_mode (w_current->options);
715 if (magnetic_net_mode) {
716 if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
717 magnetic_halfsize = max (4 * size, MAGNETIC_HALFSIZE);
719 o_invalidate_rect (w_current, magnetic_x - magnetic_halfsize,
720 magnetic_y - magnetic_halfsize,
721 magnetic_x + magnetic_halfsize,
722 magnetic_y + magnetic_halfsize);
726 gschem_page_view_invalidate_world_rect (page_view,
727 w_current->first_wx,
728 w_current->first_wy,
729 w_current->second_wx,
730 w_current->second_wy);
732 gschem_page_view_invalidate_world_rect (page_view,
733 w_current->second_wx,
734 w_current->second_wy,
735 w_current->third_wx,
736 w_current->third_wy);
740 /*! \todo Finish function documentation!!!
741 * \brief
742 * \par Function Description
745 int o_net_add_busrippers(GschemToplevel *w_current, OBJECT *net_obj,
746 GList *prev_conn_objects)
749 OBJECT *new_obj;
750 GList *cl_current = NULL;
751 OBJECT *bus_object = NULL;
752 CONN *found_conn = NULL;
753 int done;
754 int otherone;
755 struct {
756 int x[2];
757 int y[2];
758 int angle;
759 int mirror;
760 } rippers[2];
761 int ripper_count = 0;
762 int i;
763 double length;
764 int sign;
765 double distance1, distance2;
766 int first, second;
767 int made_changes = FALSE;
768 const int ripper_size = w_current->bus_ripper_size;
769 const CLibSymbol *rippersym = NULL;
771 GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
772 g_return_val_if_fail (page_view != NULL, FALSE);
774 PAGE *page = gschem_page_view_get_page (page_view);
775 g_return_val_if_fail (page != NULL, FALSE);
777 length = o_line_length(net_obj);
779 if (!prev_conn_objects) {
780 return(FALSE);
783 if (length <= ripper_size) {
784 return(FALSE);
787 /* check for a bus connection and draw rippers if so */
788 cl_current = prev_conn_objects;
789 while (cl_current != NULL) {
791 bus_object = (OBJECT *) cl_current->data;
792 if (bus_object && bus_object->type == OBJ_BUS) {
793 /* yes, using the net routine is okay */
794 int bus_orientation = o_net_orientation(bus_object);
795 int net_orientation = o_net_orientation(net_obj);
797 /* find the CONN structure which is associated with this object */
798 GList *cl_current2 = net_obj->conn_list;
799 done = FALSE;
800 while (cl_current2 != NULL && !done) {
801 CONN *tmp_conn = (CONN *) cl_current2->data;
803 if (tmp_conn && tmp_conn->other_object &&
804 tmp_conn->other_object == bus_object) {
806 found_conn = tmp_conn;
807 done = TRUE;
810 cl_current2 = g_list_next(cl_current2);
813 if (!found_conn) {
814 return(FALSE);
817 otherone = !found_conn->whichone;
819 /* now deal with the found connection */
820 if (bus_orientation == HORIZONTAL && net_orientation == VERTICAL) {
821 /* printf("found horiz bus %s %d!\n", bus_object->name,
822 found_conn->whichone);*/
824 sign = bus_object->bus_ripper_direction;
825 if (!sign) {
826 if (bus_object->line->x[0] < bus_object->line->x[1]) {
827 first = 0;
828 second = 1;
829 } else {
830 first = 1;
831 second = 0;
834 distance1 = abs(bus_object->line->x[first] -
835 net_obj->line->x[found_conn->whichone]);
836 distance2 = abs(bus_object->line->x[second] -
837 net_obj->line->x[found_conn->whichone]);
839 if (distance1 <= distance2) {
840 sign = 1;
841 } else {
842 sign = -1;
844 bus_object->bus_ripper_direction = sign;
846 /* printf("hor sign: %d\n", sign); */
848 if (net_obj->line->y[otherone] < bus_object->line->y[0]) {
849 /* new net is below bus */
850 /*printf("below\n");*/
852 if (ripper_count >= 2) {
853 /* try to exit gracefully */
854 fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
855 made_changes = FALSE;
856 break;
859 /* up, right/left */
860 rippers[ripper_count].angle = 0;
861 rippers[ripper_count].mirror = sign == 1 ? 0 : 1;
863 net_obj->line->y[found_conn->whichone] -= ripper_size;
864 net_obj->w_bounds_valid_for = NULL;
865 rippers[ripper_count].x[0] =
866 net_obj->line->x[found_conn->whichone];
867 rippers[ripper_count].y[0] =
868 net_obj->line->y[found_conn->whichone];
869 rippers[ripper_count].x[1] =
870 net_obj->line->x[found_conn->whichone] + sign*ripper_size;
871 rippers[ripper_count].y[1] =
872 net_obj->line->y[found_conn->whichone] + ripper_size;
873 ripper_count++;
874 /* printf("done\n"); */
875 made_changes++;
877 } else {
878 /* new net is above bus */
879 /* printf("above\n"); */
881 if (ripper_count >= 2) {
882 /* try to exit gracefully */
883 fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
884 made_changes = FALSE;
885 break;
888 /* down, right/left */
889 rippers[ripper_count].angle = 180;
890 rippers[ripper_count].mirror = sign == 1 ? 1 : 0;
892 net_obj->line->y[found_conn->whichone] += ripper_size;
893 net_obj->w_bounds_valid_for = NULL;
894 rippers[ripper_count].x[0] =
895 net_obj->line->x[found_conn->whichone];
896 rippers[ripper_count].y[0] =
897 net_obj->line->y[found_conn->whichone];
898 rippers[ripper_count].x[1] =
899 net_obj->line->x[found_conn->whichone] + sign*ripper_size;
900 rippers[ripper_count].y[1] =
901 net_obj->line->y[found_conn->whichone] - ripper_size;
902 ripper_count++;
904 /* printf("done\n"); */
905 made_changes++;
909 } else if (bus_orientation == VERTICAL &&
910 net_orientation == HORIZONTAL) {
912 /* printf("found vert bus %s %d!\n", bus_object->name,
913 found_conn->whichone); */
915 sign = bus_object->bus_ripper_direction;
916 if (!sign) {
917 if (bus_object->line->y[0] < bus_object->line->y[1]) {
918 first = 0;
919 second = 1;
920 } else {
921 first = 1;
922 second = 0;
925 distance1 = abs(bus_object->line->y[first] -
926 net_obj->line->y[found_conn->whichone]);
927 distance2 = abs(bus_object->line->y[second] -
928 net_obj->line->y[found_conn->whichone]);
930 if (distance1 <= distance2) {
931 sign = 1;
932 } else {
933 sign = -1;
935 bus_object->bus_ripper_direction = sign;
937 /* printf("ver sign: %d\n", sign); */
940 if (net_obj->line->x[otherone] < bus_object->line->x[0]) {
941 /* new net is to the left of the bus */
942 /* printf("left\n"); */
944 if (ripper_count >= 2) {
945 /* try to exit gracefully */
946 fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
947 made_changes = FALSE;
948 break;
951 /* right, up/down */
952 rippers[ripper_count].angle = 270;
953 rippers[ripper_count].mirror = sign == 1 ? 1 : 0;
955 net_obj->line->x[found_conn->whichone] -= ripper_size;
956 net_obj->w_bounds_valid_for = NULL;
957 rippers[ripper_count].x[0] =
958 net_obj->line->x[found_conn->whichone];
959 rippers[ripper_count].y[0] =
960 net_obj->line->y[found_conn->whichone];
961 rippers[ripper_count].x[1] =
962 net_obj->line->x[found_conn->whichone] + ripper_size;
963 rippers[ripper_count].y[1] =
964 net_obj->line->y[found_conn->whichone] + sign*ripper_size;
965 ripper_count++;
967 made_changes++;
968 } else {
969 /* new net is to the right of the bus */
970 /* printf("right\n"); */
972 if (ripper_count >= 2) {
973 /* try to exit gracefully */
974 fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
975 made_changes = FALSE;
976 break;
979 /* left, up/down */
980 rippers[ripper_count].angle = 90;
981 rippers[ripper_count].mirror = sign == 1 ? 0 : 1;
983 net_obj->line->x[found_conn->whichone] += ripper_size;
984 net_obj->w_bounds_valid_for = NULL;
985 rippers[ripper_count].x[0] =
986 net_obj->line->x[found_conn->whichone];
987 rippers[ripper_count].y[0] =
988 net_obj->line->y[found_conn->whichone];
989 rippers[ripper_count].x[1] =
990 net_obj->line->x[found_conn->whichone] - ripper_size;
991 rippers[ripper_count].y[1] =
992 net_obj->line->y[found_conn->whichone] + sign*ripper_size;
993 ripper_count++;
995 made_changes++;
1001 cl_current = g_list_next(cl_current);
1004 if (made_changes) {
1005 s_conn_remove_object_connections (page->toplevel, net_obj);
1007 if (w_current->bus_ripper_type == COMP_BUS_RIPPER) {
1008 GList *symlist =
1009 s_clib_search (page->toplevel->bus_ripper_symname, CLIB_EXACT);
1010 if (symlist != NULL) {
1011 rippersym = (CLibSymbol *) symlist->data;
1013 g_list_free (symlist);
1016 for (i = 0; i < ripper_count; i++) {
1017 if (w_current->bus_ripper_type == NET_BUS_RIPPER) {
1018 new_obj = o_net_new(page->toplevel, OBJ_NET, NET_COLOR,
1019 rippers[i].x[0], rippers[i].y[0],
1020 rippers[i].x[1], rippers[i].y[1]);
1021 s_page_append (page->toplevel, page, new_obj);
1022 } else {
1024 if (rippersym != NULL) {
1025 new_obj = o_complex_new (page->toplevel, OBJ_COMPLEX, DEFAULT_COLOR,
1026 rippers[i].x[0], rippers[i].y[0],
1027 rippers[i].angle, rippers[i].mirror,
1028 rippersym,
1029 page->toplevel->bus_ripper_symname, 1);
1030 s_page_append_list (page->toplevel, page,
1031 o_complex_promote_attribs (page->toplevel, new_obj));
1032 s_page_append (page->toplevel, page, new_obj);
1033 } else {
1034 s_log_message(_("Bus ripper symbol [%s] was not found in any symbol library\n"),
1035 page->toplevel->bus_ripper_symname);
1040 s_conn_update_object (page, net_obj);
1041 return(TRUE);
1044 return(FALSE);