1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "libgeda_priv.h"
30 #ifdef HAVE_LIBDMALLOC
35 * \brief The connection system
37 * The connection system stores and tracks the connections between
38 * connected <b>OBJECTS</b>. The connected OBJECTS are either
39 * <b>pins</b>, <b>nets</b> and <b>busses</b>.
41 * Each connection object with the type <b>st_conn</b> represents a
42 * single unidirectional relation to another object.
44 * The following figure with two nets and a pin shows the relations
45 * between connections and OBJECTS:
47 * \image html s_conn_overview.png
48 * \image latex s_conn_overview.pdf "Connection overview" width=14cm
52 /*! \brief create a new connection object
53 * \par Function Description
54 * create a single st_conn object and initialize it with the
57 * \return The new connection object
59 CONN
*s_conn_return_new(OBJECT
* other_object
, int type
, int x
, int y
,
60 int whichone
, int other_whichone
)
64 new_conn
= (CONN
*) g_malloc(sizeof(CONN
));
67 printf("** creating: %s %d %d\n", other_object
->name
, x
, y
);
70 new_conn
->other_object
= other_object
;
71 new_conn
->type
= type
;
74 new_conn
->whichone
= whichone
;
75 new_conn
->other_whichone
= other_whichone
;
80 /*! \brief check if a connection is uniq in a list
81 * \par Function Description
82 * This function checks if there's no identical connection
83 * in the list of connections.
84 * \param conn_list list of connection objects
85 * \param input_conn single connection object.
86 * \return TRUE if the CONN structure is unique, FALSE otherwise.
88 int s_conn_uniq(GList
* conn_list
, CONN
* input_conn
)
93 c_current
= conn_list
;
94 while (c_current
!= NULL
) {
95 conn
= (CONN
*) c_current
->data
;
97 if (conn
->other_object
== input_conn
->other_object
&&
98 conn
->x
== input_conn
->x
&& conn
->y
== input_conn
->y
&&
99 conn
->type
== input_conn
->type
) {
103 c_current
= g_list_next(c_current
);
109 /*! \brief remove a object from the connection list of another object
110 * \par Function Description
111 * This function removes the OBJECT <b>to_remove</b> from the connection
112 * list of the OBJECT <b>other_object</b>.
113 * \param toplevel (currently not used)
114 * \param other_object OBJECT from that the to_remove OBJECT needs to be removed
115 * \param to_remove OBJECT to remove
116 * \return TRUE if a connection has been deleted, FALSE otherwise
118 int s_conn_remove_other (TOPLEVEL
*toplevel
, OBJECT
*other_object
,
121 GList
*c_current
= NULL
;
124 o_emit_pre_change_notify (toplevel
, other_object
);
126 c_current
= other_object
->conn_list
;
127 while (c_current
!= NULL
) {
128 conn
= (CONN
*) c_current
->data
;
130 if (conn
->other_object
== to_remove
) {
131 other_object
->conn_list
=
132 g_list_remove(other_object
->conn_list
, conn
);
135 printf("Found other_object in remove_other\n");
136 printf("Freeing other: %s %d %d\n", conn
->other_object
->name
,
140 /* Do not write modify c_current like this, since this will cause */
141 /* very nasty data corruption and upset glib's memory slice */
143 /* c_current->data = NULL; Do not comment in */
147 #if 0 /* this does not work right */
148 if (other_object
->type
== OBJ_BUS
&&
149 other_object
->conn_list
== NULL
) {
150 other_object
->bus_ripper_direction
= 0;
157 c_current
= g_list_next(c_current
);
160 o_emit_change_notify (toplevel
, other_object
);
165 /*! \brief removes a GList of OBJECTs from the connection system
167 * \par Function Description
168 * This function removes all connections from and to the OBJECTS
169 * of the given GList.
171 * \param toplevel (currently not used)
172 * \param obj_list GList of OBJECTs to unconnected from all other objects
174 static void s_conn_remove_glist (TOPLEVEL
*toplevel
, GList
*obj_list
)
179 for (iter
= obj_list
; iter
!= NULL
; iter
= g_list_next (iter
)) {
180 o_current
= iter
->data
;
181 s_conn_remove_object (toplevel
, o_current
);
185 /*! \brief remove an OBJECT from the connection system
186 * \par Function Description
187 * This function removes all connections from and to the OBJECT
189 * \param toplevel (currently not used)
190 * \param to_remove OBJECT to unconnected from all other objects
192 void s_conn_remove_object (TOPLEVEL
*toplevel
, OBJECT
*to_remove
)
197 switch (to_remove
->type
) {
201 for (c_iter
= to_remove
->conn_list
;
203 c_iter
= g_list_next (c_iter
)) {
206 /* keep calling this till it returns false (all refs removed) */
207 /* there is NO body to this while loop */
208 while (s_conn_remove_other (toplevel
, conn
->other_object
, to_remove
));
214 g_list_free (to_remove
->conn_list
);
215 to_remove
->conn_list
= NULL
;
219 case OBJ_PLACEHOLDER
:
220 s_conn_remove_glist (toplevel
, to_remove
->complex->prim_objs
);
225 /*! \brief Checks if a point is a midpoint of an OBJECT
226 * \par Function Description
227 * Checks if the point (<b>x</b>,<b>y</b>) is on the OBJECT
228 * and between it's endpoints.
229 * \return TRUE if the point is a midpoint of the OBJECT. FALSE
230 * if the point is not a midpoinit or if the OBJECT is not a
231 * NET a PIN or a BUS or if the OBJECT
232 * has neither horizontal nor vertical orientation.
234 OBJECT
*s_conn_check_midpoint(OBJECT
*o_current
, int x
, int y
)
236 int min_x
, min_y
, max_x
, max_y
;
238 switch(o_current
->type
) {
242 min_y
= min(o_current
->line
->y
[0],
243 o_current
->line
->y
[1]);
244 max_y
= max(o_current
->line
->y
[0],
245 o_current
->line
->y
[1]);
248 if ( (o_current
->line
->x
[0] == x
) &&
249 (y
> min_y
) && (y
< max_y
) &&
250 (o_current
->line
->x
[0] ==
251 o_current
->line
->x
[1]) ) {
253 printf("Found vertical point\n");
258 min_x
= min(o_current
->line
->x
[0],
259 o_current
->line
->x
[1]);
260 max_x
= max(o_current
->line
->x
[0],
261 o_current
->line
->x
[1]);
264 if ( (o_current
->line
->y
[0] == y
) &&
265 (x
> min_x
) && (x
< max_x
) &&
266 (o_current
->line
->y
[0] ==
267 o_current
->line
->y
[1]) ) {
269 printf("Found horizontal point\n");
279 /*! \brief adds a GList of OBJECTs to the connection system
281 * \par Function Description
282 * This function adds all connections from and to the OBJECTS
283 * of the given GList.
285 * \param toplevel (currently not used)
286 * \param obj_list GList of OBJECTs to add into the connection system
288 void s_conn_update_glist (TOPLEVEL
*toplevel
, GList
*obj_list
)
293 for (iter
= obj_list
; iter
!= NULL
; iter
= g_list_next (iter
)) {
294 o_current
= iter
->data
;
295 s_conn_update_object (toplevel
, o_current
);
300 /*! \brief Checks if an object is bus, or a bus pin
302 * \par Function Description
303 * Checks if an object is a bus or a bus pin
305 * \param object The OBJECT to test
306 * \return TRUE if the objects is a bis, or bus pin
308 static int is_bus_related (OBJECT
*object
)
310 return (object
->type
== OBJ_BUS
||
311 (object
->type
== OBJ_PIN
&& object
->pin_type
== PIN_TYPE_BUS
));
315 /*! \brief Checks if two objects are of compatible types to be connected
317 * \par Function Description
318 * Checks if two objects are legal to be connected together
320 * \param object1 First OBJECT
321 * \param object2 Second OBJECT
322 * \return TRUE if the objects are compatible, FALSE if not
324 static int check_direct_compat (OBJECT
*object1
, OBJECT
*object2
)
326 return (is_bus_related (object1
) == is_bus_related (object2
));
330 static void add_connection (OBJECT
*object
, OBJECT
*other_object
,
331 int type
, int x
, int y
,
332 int whichone
, int other_whichone
)
334 /* Describe the connection */
335 CONN
*new_conn
= s_conn_return_new (other_object
, type
, x
, y
,
336 whichone
, other_whichone
);
337 /* Do uniqness check */
338 if (s_conn_uniq (object
->conn_list
, new_conn
)) {
339 object
->conn_list
= g_list_append (object
->conn_list
, new_conn
);
345 /*! \brief add a line OBJECT to the connection system
346 * \par Function Description
347 * This function searches for all geometrical conections of the OBJECT
348 * <b>object</b> to all other connectable objects. It adds connections
349 * to the object and from all other
350 * objects to this one.
351 * \param toplevel (currently not used)
352 * \param object OBJECT to add into the connection system
354 static void s_conn_update_line_object (TOPLEVEL
*toplevel
, OBJECT
*object
)
359 OBJECT
*other_object
;
363 /* loop over all tiles which object appears in */
364 for (tl_current
= object
->tiles
;
366 tl_current
= g_list_next (tl_current
)) {
367 t_current
= tl_current
->data
;
369 for (object_list
= t_current
->objects
;
371 object_list
= g_list_next (object_list
)) {
372 other_object
= object_list
->data
;
374 if (object
== other_object
)
377 /* Here is where you check the end points */
378 /* Check both end points of the other object */
379 for (k
= 0; k
< 2; k
++) {
381 /* If the other object is a pin, only check the correct end */
382 if (other_object
->type
== OBJ_PIN
&& other_object
->whichend
!= k
)
385 /* Check both end points of the object */
386 for (j
= 0; j
< 2; j
++) {
388 /* If the object is a pin, only check the correct end */
389 if (object
->type
== OBJ_PIN
&& object
->whichend
!= j
)
392 /* Check for coincidence and compatability between
393 the objects being tested. */
394 if (object
->line
->x
[j
] == other_object
->line
->x
[k
] &&
395 object
->line
->y
[j
] == other_object
->line
->y
[k
] &&
396 check_direct_compat (object
, other_object
)) {
398 o_emit_pre_change_notify (toplevel
, other_object
);
400 add_connection (object
, other_object
, CONN_ENDPOINT
,
401 other_object
->line
->x
[k
],
402 other_object
->line
->y
[k
], j
, k
);
404 add_connection (other_object
, object
, CONN_ENDPOINT
,
406 object
->line
->y
[j
], k
, j
);
408 o_emit_change_notify (toplevel
, other_object
);
413 /* Check both end points of the object against midpoints of the other */
414 for (k
= 0; k
< 2; k
++) {
416 /* If the object is a pin, only check the correct end */
417 if (object
->type
== OBJ_PIN
&& object
->whichend
!= k
)
420 /* check for midpoint of other object, k endpoint of current obj*/
421 found
= s_conn_check_midpoint (other_object
, object
->line
->x
[k
],
424 /* Pins are not allowed midpoint connections onto them. */
425 /* Allow nets to connect to the middle of buses. */
426 /* Allow compatible objects to connect. */
427 if (found
&& other_object
->type
!= OBJ_PIN
&&
428 ((object
->type
== OBJ_NET
&& other_object
->type
== OBJ_BUS
) ||
429 check_direct_compat (object
, other_object
))) {
431 add_connection (object
, other_object
, CONN_MIDPOINT
,
433 object
->line
->y
[k
], k
, -1);
435 add_connection (other_object
, object
, CONN_MIDPOINT
,
437 object
->line
->y
[k
], -1, k
);
441 /* Check both end points of the other object against midpoints of the first */
442 for (k
= 0; k
< 2; k
++) {
444 /* If the other object is a pin, only check the correct end */
445 if (other_object
->type
== OBJ_PIN
&& other_object
->whichend
!= k
)
448 /* do object's endpoints cross the middle of other_object? */
449 /* check for midpoint of other object, k endpoint of current obj*/
450 found
= s_conn_check_midpoint (object
, other_object
->line
->x
[k
],
451 other_object
->line
->y
[k
]);
453 /* Pins are not allowed midpoint connections onto them. */
454 /* Allow nets to connect to the middle of buses. */
455 /* Allow compatible objects to connect. */
456 if (found
&& object
->type
!= OBJ_PIN
&&
457 ((object
->type
== OBJ_BUS
&& other_object
->type
== OBJ_NET
) ||
458 check_direct_compat (object
, other_object
))) {
460 add_connection (object
, other_object
, CONN_MIDPOINT
,
461 other_object
->line
->x
[k
],
462 other_object
->line
->y
[k
], -1, k
);
464 add_connection (other_object
, object
, CONN_MIDPOINT
,
465 other_object
->line
->x
[k
],
466 other_object
->line
->y
[k
], k
, -1);
474 s_conn_print(object
->conn_list
);
478 /*! \brief add an OBJECT to the connection system
480 * \par Function Description
481 * This function searches for all geometrical conections of the OBJECT
482 * <b>object</b> to all other connectable objects. It adds connections
483 * to the object and from all other objects to this one.
485 * \param toplevel (currently not used)
486 * \param object OBJECT to add into the connection system
488 void s_conn_update_object (TOPLEVEL
*toplevel
, OBJECT
*object
)
490 switch (object
->type
) {
494 s_conn_update_line_object (toplevel
, object
);
498 case OBJ_PLACEHOLDER
:
499 s_conn_update_glist (toplevel
, object
->complex->prim_objs
);
504 /*! \brief print all connections of a connection list
505 * \par Function Description
506 * This is a debugging function to print a List of connections.
507 * \param conn_list GList of connection objects
509 void s_conn_print(GList
* conn_list
)
514 printf("\nStarting s_conn_print\n");
515 cl_current
= conn_list
;
516 while (cl_current
!= NULL
) {
518 conn
= (CONN
*) cl_current
->data
;
519 printf("-----------------------------------\n");
520 printf("other object: %s\n", conn
->other_object
->name
);
521 printf("type: %d\n", conn
->type
);
522 printf("x: %d y: %d\n", conn
->x
, conn
->y
);
523 printf("whichone: %d\n", conn
->whichone
);
524 printf("other_whichone: %d\n", conn
->other_whichone
);
525 printf("-----------------------------------\n");
527 cl_current
= g_list_next(cl_current
);
532 /*! \brief Search for net in existing connections.
533 * \par Function Description
534 * This method searches the connection list for the first matching
535 * connection with the given x, y, and whichone endpoint.
537 * \param [in] new_net Net OBJECT to compare to.
538 * \param [in] whichone The connection number to check.
539 * \param [in] conn_list List of existing connections to compare
541 * \return TRUE if a matching connection is found, FALSE otherwise.
543 int s_conn_net_search(OBJECT
* new_net
, int whichone
, GList
* conn_list
)
548 cl_current
= conn_list
;
549 while (cl_current
!= NULL
) {
551 conn
= (CONN
*) cl_current
->data
;
552 if (conn
!= NULL
&& conn
->whichone
== whichone
&&
553 conn
->x
== new_net
->line
->x
[whichone
] &&
554 conn
->y
== new_net
->line
->y
[whichone
])
559 cl_current
= g_list_next(cl_current
);
565 /*! \brief get a list of all objects connected to a list of OBJECTs.
567 * \par Function Description
568 * This function gets all other_object from the connection
569 * list of the OBJECTs in the pased list.
571 * \param [in] input_list GList of OBJECT's or NULL
572 * \param [in] obj_list The GList of OBJECT to get connections from
573 * \return A GList of objects
576 * Caller must g_list_free returned GList pointer.
577 * Do not free individual data items in list.
579 static GList
*s_conn_return_glist_others (GList
*input_list
, GList
*obj_list
)
585 return_list
= input_list
;
587 for (iter
= obj_list
; iter
!= NULL
; iter
= g_list_next (iter
)) {
588 o_current
= iter
->data
;
589 return_list
= s_conn_return_others (return_list
, o_current
);
595 /*! \brief get a list of all objects connected to this one
597 * \par Function Description
598 * This function gets all other_object from the connection list of the current object.
599 * COMPLEX objects are entered, and their prim_objs processed. If an <b>input_list</b>
600 * is given, the other objects are appended to that list.
602 * \param [in] input_list GList of OBJECT's
603 * \param [in] object OBJECT to get other OBJECTs from
604 * \return A GList of OBJECTs
607 * Caller must g_list_free returned GList pointer.
608 * Do not free individual data items in list.
610 GList
*s_conn_return_others(GList
*input_list
, OBJECT
*object
)
615 return_list
= input_list
;
617 switch (object
->type
) {
621 for (c_iter
= object
->conn_list
;
622 c_iter
!= NULL
; c_iter
= g_list_next (c_iter
)) {
623 CONN
*conn
= c_iter
->data
;
625 if (conn
->other_object
&& conn
->other_object
!= object
) {
626 return_list
= g_list_append(return_list
, conn
->other_object
);
632 case OBJ_PLACEHOLDER
:
633 return_list
= s_conn_return_glist_others (return_list
,
634 object
->complex->prim_objs
);