示例#1
0
gint
node_store_count_items (NodeStore *store, NodeRect *rect)
{
	GList *list;
	SheetPos p1, p2;
	ItemData *data;
	gint n;

	g_return_val_if_fail (store != NULL, 0);
	g_return_val_if_fail (IS_NODE_STORE (store), 0);

	if (rect == NULL)
		return g_list_length (store->items);

	for (list = store->items, n = 0; list; list = list->next) {
		data = ITEM_DATA (list->data);
		item_data_get_absolute_bbox (data, &p1, &p2);
		if (p1.x <= rect->x1 && p1.y <= rect->y1 &&
			p2.x >= rect->x0 && p2.y >= rect->y0) {
			n++;
		}
	}
	g_list_free_full (list, g_object_unref);

	return n;
}
示例#2
0
void
node_store_get_bounds (NodeStore *store, NodeRect *rect)
{
	GList *list;
	SheetPos p1, p2;

	g_return_if_fail (store != NULL);
	g_return_if_fail (IS_NODE_STORE (store));
	g_return_if_fail (rect != NULL);

	rect->x0 = G_MAXDOUBLE;
	rect->y0 = G_MAXDOUBLE;
	rect->x1 = -G_MAXDOUBLE;
	rect->y1 = -G_MAXDOUBLE;

	for (list = store->items; list; list = list->next) {
		item_data_get_absolute_bbox (ITEM_DATA (list->data), &p1, &p2);

		rect->x0 = MIN (rect->x0, p1.x);
		rect->y0 = MIN (rect->y0, p1.y);
		rect->x1 = MAX (rect->x1, p2.x);
		rect->y1 = MAX (rect->y1, p2.y);
	}
	g_list_free_full (list, g_object_unref);
}
示例#3
0
Node *
node_store_get_or_create_node (NodeStore *self, SheetPos pos)
{
	Node *node;

	g_return_val_if_fail (self != NULL, NULL);
	g_return_val_if_fail (IS_NODE_STORE (self), NULL);

	node = g_hash_table_lookup (self->nodes, &pos);

	if (!node) {
		// Create a node at (x, y) and return it.
		node = node_new (pos);

		g_signal_connect_object (G_OBJECT (node), "node_dot_added",
			G_CALLBACK (node_dot_added_callback), G_OBJECT (self), 0);

		g_signal_connect_object (G_OBJECT (node), "node_dot_removed",
			G_CALLBACK (node_dot_removed_callback), G_OBJECT (self), 0);

		g_hash_table_insert (self->nodes, &node->key, node);
	}

	// If there was a previously stored node here, just
	// return that node.
	return node;
}
示例#4
0
/**
 * Call GHFunc for each node in the nodestore
 */
void node_store_node_foreach (NodeStore *store, GHFunc *func, gpointer user_data)
{
	g_return_if_fail (store != NULL);
	g_return_if_fail (IS_NODE_STORE (store));

	g_hash_table_foreach (store->nodes, (gpointer)func, user_data);
}
示例#5
0
/**
 * [transfer-none]
 */
GList *node_store_get_items (NodeStore *store)
{
	g_return_val_if_fail (store != NULL, NULL);
	g_return_val_if_fail (IS_NODE_STORE (store), NULL);

	return store->items;
}
示例#6
0
int
node_store_is_wire_at_pos (NodeStore *store, SheetPos pos)
{
	GList *list;
	Wire *wire;
	SheetPos wire_pos, wire_length;
	double x1, y1, x2, y2;

	g_return_val_if_fail (store != NULL, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (store), FALSE);

	for (list = store->wires; list; list = list->next) {
		wire = list->data;

		wire_get_pos_and_length (wire, &wire_pos, &wire_length);
		x1 = wire_pos.x;
		y1 = wire_pos.y;
		x2 = x1 + wire_length.x;
		y2 = y1 + wire_length.y;

		if (is_wire_at_pos (x1, y1, x2, y2, pos))
			return TRUE;
	}
	g_list_free_full (list, g_object_unref);

	return FALSE;
}
示例#7
0
static void node_dot_removed_callback (Node *node, Coords *pos, NodeStore *store)
{
	g_return_if_fail (store);
	g_return_if_fail (IS_NODE_STORE (store));

	g_signal_emit_by_name (G_OBJECT (store), "node_dot_removed", pos);
}
示例#8
0
static void
node_dot_added_callback (Node *node, SheetPos *pos, NodeStore *store)
{
	g_return_if_fail (store != NULL);
	g_return_if_fail (IS_NODE_STORE (store));

	g_signal_emit_by_name (G_OBJECT (store), "node_dot_added", pos);
}
示例#9
0
static GSList *
wire_intersect_parts (NodeStore *store, Wire *wire)
{
	GList *list;
	GSList *ip_list;
	Node *node;
	SheetPos lookup_pos;
	SheetPos part_pos, wire_pos, wire_length;
	Part *part;
	double x, y, wire_x1, wire_y1, wire_x2, wire_y2;
	int i, num_pins;

	g_return_val_if_fail (store != NULL, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
	g_return_val_if_fail (wire != NULL, FALSE);
	g_return_val_if_fail (IS_WIRE (wire), FALSE);

	ip_list = NULL;

	wire_get_pos_and_length (wire, &wire_pos, &wire_length);

	wire_x1 = wire_pos.x;
	wire_x2 = wire_pos.x + wire_length.x;
	wire_y1 = wire_pos.y;
	wire_y2 = wire_pos.y + wire_length.y;

	// Go through all the parts and see which of their
	// pins that intersect the wire.
	for (list = store->parts; list; list = list->next) {
		part = list->data;

		num_pins = part_get_num_pins (part);
		item_data_get_pos (ITEM_DATA (part), &part_pos);

		for (i = 0; i < num_pins; i++) {
			Pin *pins;

			pins = part_get_pins (part);
			x = part_pos.x + pins[i].offset.x;
			y = part_pos.y + pins[i].offset.y;

			lookup_pos.x = x;
			lookup_pos.y = y;

			// If there is a wire at this pin's position,
			// add it to the return list.
			if (is_wire_at_pos (wire_x1, wire_y1, wire_x2, wire_y2, lookup_pos)) {
				node = node_store_get_node (store, lookup_pos);

				if (node != NULL)
					ip_list = g_slist_prepend (ip_list, node);
			}
		}
	}
	g_list_free_full (list, g_object_unref);

	return ip_list;
}
示例#10
0
int
node_store_add_part (NodeStore *self, Part *part)
{
	GSList *wire_list, *list;
	Node *node;
	SheetPos lookup_key;
	SheetPos part_pos;
	gdouble x, y;
	int i, num_pins;

	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (self), FALSE);
	g_return_val_if_fail (part != NULL, FALSE);
	g_return_val_if_fail (IS_PART (part), FALSE);

	num_pins = part_get_num_pins (part);

	item_data_get_pos (ITEM_DATA (part), &part_pos);

	for (i = 0; i < num_pins; i++) {
		Pin *pins;

		pins = part_get_pins (part);
		x = part_pos.x + pins[i].offset.x;
		y = part_pos.y + pins[i].offset.y;

		//Use the position of the pin as hash key.
		lookup_key.x = x;
		lookup_key.y = y;

		// Retrieve a node for this position.
		node = node_store_get_or_create_node (self, lookup_key);

		// Add all the wires that intersect this pin to the node store.
		wire_list = wires_at_pos (self, lookup_key);

		for (list = wire_list; list; list = list->next) {
			Wire *wire = list->data;

		    NG_DEBUG ("Add pin to wire.\n");

			node_add_wire (node, wire);
			wire_add_node (wire, node);
		}

		g_slist_free (wire_list);

		node_add_pin (node, &pins[i]);
	}

	g_object_set (G_OBJECT (part), "store", self, NULL);
	self->parts = g_list_prepend (self->parts, part);
	self->items = g_list_prepend (self->items, part);

	return TRUE;
}
示例#11
0
/**
 * the caller has to free the list himself, but not the actual data items!
 */
GList *node_store_get_nodes (NodeStore *store)
{
	GList *result;

	g_return_val_if_fail (store != NULL, NULL);
	g_return_val_if_fail (IS_NODE_STORE (store), NULL);

	result = NULL;
	g_hash_table_foreach (store->nodes, (GHFunc)add_node, &result);

	return result;
}
示例#12
0
int
node_store_remove_part (NodeStore *self, Part *part)
{
	Node *node;
	SheetPos lookup_key;
	SheetPos pos;
	gdouble x, y;
	int i, num_pins;
	Pin *pins;

	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (self), FALSE);
	g_return_val_if_fail (part != NULL, FALSE);
	g_return_val_if_fail (IS_PART (part), FALSE);

	self->parts = g_list_remove (self->parts, part);
	self->items = g_list_remove (self->items, part);

	num_pins = part_get_num_pins (part);
	item_data_get_pos (ITEM_DATA (part), &pos);

	pins = part_get_pins (part);
	for (i = 0; i < num_pins; i++) {
		x = pos.x + pins[i].offset.x;
		y = pos.y + pins[i].offset.y;

		// Use the position of the pin as lookup key.
		lookup_key.x = x;
		lookup_key.y = y;

		node = g_hash_table_lookup (self->nodes, &lookup_key);
		if (node) {
			if (!node_remove_pin (node, &pins[i])) {
				g_warning ("Couldn't remove pin.");
				return FALSE;
			}

			// If the node is empty after removing the pin,
			// remove the node as well.
			if (node_is_empty (node)) {
				g_hash_table_remove (self->nodes, &lookup_key);
				g_object_unref (G_OBJECT (node));
			}
		} 
		else {
			return FALSE;
		}
	}

	return TRUE;
}
示例#13
0
/**
 * check if there is at least one wire at the specified position
 *
 * @param store which NodeStore to check
 * @param pos the position
 * @returns TRUE or FALSE
 */
gboolean node_store_is_wire_at_pos (NodeStore *store, Coords pos)
{
	GList *iter;

	g_return_val_if_fail (store, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (store), FALSE);

	for (iter = store->wires; iter; iter = iter->next) {
		Wire *wire = iter->data;

		if (is_point_on_wire (wire, &pos))
			return TRUE;
	}
	return FALSE;
}
示例#14
0
/**
 * register a part to the nodestore
 */
gboolean node_store_add_part (NodeStore *self, Part *part)
{
	NG_DEBUG ("-0-");
	g_return_val_if_fail (self, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (self), FALSE);
	g_return_val_if_fail (part, FALSE);
	g_return_val_if_fail (IS_PART (part), FALSE);

	GSList *iter, *copy;
	Node *node;
	Coords pin_pos;
	Coords part_pos;
	int i, num_pins;
	Pin *pins;

	num_pins = part_get_num_pins (part);
	pins = part_get_pins (part);

	item_data_get_pos (ITEM_DATA (part), &part_pos);

	for (i = 0; i < num_pins; i++) {
		// Use the position of the pin as hash key.
		pin_pos.x = part_pos.x + pins[i].offset.x;
		pin_pos.y = part_pos.y + pins[i].offset.y;

		// Retrieve a node for this position.
		node = node_store_get_or_create_node (self, pin_pos);

		// Add all the wires that intersect this pin to the node store.
		copy = get_wires_at_pos (self, pin_pos);
		for (iter = copy; iter; iter = iter->next) {
			Wire *wire = copy->data;

			node_add_wire (node, wire);
			wire_add_node (wire, node);
		}

		g_slist_free (copy);

		node_add_pin (node, &pins[i]);
	}

	g_object_set (G_OBJECT (part), "store", self, NULL);
	self->parts = g_list_prepend (self->parts, part);
	self->items = g_list_prepend (self->items, part);

	return TRUE;
}
示例#15
0
void node_store_print_items (NodeStore *store, cairo_t *cr, SchematicPrintContext *ctx)
{
	GList *list;
	ItemData *data;

	g_return_if_fail (store != NULL);
	g_return_if_fail (IS_NODE_STORE (store));

	cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
	for (list = store->items; list; list = list->next) {
		data = ITEM_DATA (list->data);
		item_data_print (data, cr, ctx);
	}

	g_hash_table_foreach (store->nodes, (GHFunc)draw_dot, cr);
}
示例#16
0
/**
 * lookup node at specified position
 *
 * @param store which store to check
 * @param pos where to check in that store
 * @returns the node pointer if there is a node, else NULL
 */
Node *node_store_get_node (NodeStore *store, Coords pos)
{
	Node *node;

	g_return_val_if_fail (store != NULL, NULL);
	g_return_val_if_fail (IS_NODE_STORE (store), NULL);

	node = g_hash_table_lookup (store->nodes, &pos);

	if (!node) {
		NG_DEBUG ("No node at (%g, %g)", pos.x, pos.y);
	} else {
		NG_DEBUG ("Found node at (%g, %g)", pos.x, pos.y);
	}
	return node;
}
示例#17
0
int
node_store_remove_wire (NodeStore *store, Wire *wire)
{
	GSList *list;
	SheetPos lookup_key, pos, length;

	g_return_val_if_fail (store != NULL, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
	g_return_val_if_fail (wire != NULL, FALSE);
	g_return_val_if_fail (IS_WIRE (wire), FALSE);

	if (item_data_get_store (ITEM_DATA (wire)) == NULL) {
		g_warning ("Trying to remove non-stored wire.");
		return FALSE;
	}

	wire_get_pos_and_length (wire, &pos, &length);

	store->wires = g_list_remove (store->wires, wire);
	store->items = g_list_remove (store->items, wire);

	// If the nodes that this wire passes through will be
	// empty when the wire is removed, remove the node as well.

	// We must work on a copy of the nodes list, since it
	// changes as we remove nodes.
	list = g_slist_copy (wire_get_nodes (wire));

	for (; list; list = list->next) {
		Node *node = list->data;

		lookup_key = node->key;

		node_remove_wire (node, wire);

		wire_remove_node (wire, node);

		if (node_is_empty (node))
			g_hash_table_remove (store->nodes, &lookup_key);
	}

	g_slist_free (list);

	return TRUE;
}
示例#18
0
/**
 * remove/unregister a part from the nodestore
 * this does _not_ free the part!
 */
gboolean node_store_remove_part (NodeStore *self, Part *part)
{
	Node *node;
	Coords pin_pos;
	Coords part_pos;
	int i, num_pins;
	Pin *pins;

	g_return_val_if_fail (self, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (self), FALSE);
	g_return_val_if_fail (part, FALSE);
	g_return_val_if_fail (IS_PART (part), FALSE);

	self->parts = g_list_remove (self->parts, part);
	self->items = g_list_remove (self->items, part);

	num_pins = part_get_num_pins (part);
	item_data_get_pos (ITEM_DATA (part), &part_pos);

	pins = part_get_pins (part);
	for (i = 0; i < num_pins; i++) {
		pin_pos.x = part_pos.x + pins[i].offset.x;
		pin_pos.y = part_pos.y + pins[i].offset.y;

		node = g_hash_table_lookup (self->nodes, &pin_pos);
		if (node) {
			if (!node_remove_pin (node, &pins[i])) {
				g_warning ("Could not remove pin[%i] from node %p.", i, node);
				return FALSE;
			}

			// If the node is empty after removing the pin,
			// remove the node as well.
			if (node_is_empty (node)) {
				g_hash_table_remove (self->nodes, &pin_pos);
				g_object_unref (G_OBJECT (node));
			}
		} else {
			return FALSE;
		}
	}

	return TRUE;
}
示例#19
0
/**
 * removes/unregisters a wire from the nodestore
 * this does _not_ free the wire itself!
 */
gboolean node_store_remove_wire (NodeStore *store, Wire *wire)
{
	GSList *copy, *iter;
	Coords lookup_key;

	g_return_val_if_fail (store, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
	g_return_val_if_fail (wire, FALSE);
	g_return_val_if_fail (IS_WIRE (wire), FALSE);

	if (item_data_get_store (ITEM_DATA (wire)) == NULL) {
		g_warning ("Trying to remove not-stored wire %p.", wire);
		return FALSE;
	}

	store->wires = g_list_remove (store->wires, wire);
	store->items = g_list_remove (store->items, wire);

	// If the nodes that this wire passes through will be
	// empty when the wire is removed, remove the node as well.

	// FIXME if done properly, a list copy is _not_ necessary
	copy = g_slist_copy (wire_get_nodes (wire));
	for (iter = copy; iter; iter = iter->next) {
		Node *node = iter->data;

		lookup_key = node->key;

		node_remove_wire (node, wire);
		wire_remove_node (wire, node);

		if (node_is_empty (node))
			g_hash_table_remove (store->nodes, &lookup_key);
	}

	g_slist_free (copy);

	return TRUE;
}
示例#20
0
static GSList *
wires_intersect (NodeStore *store, double x1, double y1, double x2, double y2)
{
	GList *list;
	GSList *ip_list;
	Wire *wire;
	SheetPos pos, wire_pos, wire_length;
	double wire_x1, wire_y1, wire_x2, wire_y2;

	g_return_val_if_fail (store != NULL, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (store), FALSE);

	// Search through all the wires. Is there a better way?
	ip_list = NULL;
	for (list = store->wires; list; list = list->next) {
		wire = list->data;

		wire_get_pos_and_length (wire, &wire_pos, &wire_length);
		wire_x1 = wire_pos.x;
		wire_y1 = wire_pos.y;
		wire_x2 = wire_x1 + wire_length.x;
		wire_y2 = wire_y1 + wire_length.y;

		if (do_wires_intersect (x1, y1, x2, y2, wire_x1, wire_y1,
								wire_x2, wire_y2, &pos)) {
			IntersectionPoint *ip;

			ip = g_new0 (IntersectionPoint, 1);

			ip->wire = wire;
			ip->pos = pos;
			ip_list = g_slist_prepend (ip_list, ip);
		}
	}
	g_list_free_full (list, g_object_unref);

	return ip_list;
}
示例#21
0
/**
 * lookup if a node at @pos exists, if so return it, otherwise
 * create one, add it to the nodestore and return it
 */
Node *node_store_get_or_create_node (NodeStore *self, Coords pos)
{
	Node *node;

	g_return_val_if_fail (self, NULL);
	g_return_val_if_fail (IS_NODE_STORE (self), NULL);

	node = g_hash_table_lookup (self->nodes, &pos);

	if (!node) {
		// Create a node at (x, y) and return it.
		node = node_new (pos);

		g_signal_connect_object (G_OBJECT (node), "node_dot_added",
		                         G_CALLBACK (node_dot_added_callback), G_OBJECT (self), 0);

		g_signal_connect_object (G_OBJECT (node), "node_dot_removed",
		                         G_CALLBACK (node_dot_removed_callback), G_OBJECT (self), 0);

		g_hash_table_insert (self->nodes, &node->key, node);
	}

	return node;
}
示例#22
0
/**
 * add/register the wire to the nodestore
 *
 * @param store
 * @param wire
 * @returns TRUE if the wire was added or merged, else FALSE
 */
gboolean node_store_add_wire (NodeStore *store, Wire *wire)
{
	GList *list;
	Node *node;
	int i = 0;

	g_return_val_if_fail (store, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
	g_return_val_if_fail (wire, FALSE);
	g_return_val_if_fail (IS_WIRE (wire), FALSE);

	// Check for intersection with other wires.
	for (list = store->wires; list; list = list->next) {
		g_assert (list->data != NULL);
		g_assert (IS_WIRE (list->data));

		Coords where = {-77.77, -77.77};
		Wire *other = list->data;
		if (do_wires_intersect (wire, other, &where)) {
			if (is_t_crossing (wire, other, &where) || is_t_crossing (other, wire, &where)) {

				node = node_store_get_or_create_node (store, where);

				node_add_wire (node, wire);
				node_add_wire (node, other);

				wire_add_node (wire, node);
				wire_add_node (other, node);

				NG_DEBUG ("Add wire %p to wire %p @ %lf,%lf.\n", wire, other, where.x, where.y);
			} else {
				// magic node removal if a x crossing is overlapped with another wire
				node = node_store_get_node (store, where);
				NG_DEBUG ("Nuke that node [ %p ] at coords inbetween", node);
				if (node) {
					Coords c[4];
					wire_get_start_and_end_pos (other, c + 0, c + 1);
					wire_get_start_and_end_pos (wire, c + 2, c + 3);
					if (!coords_equal (&where, c + 0) && !coords_equal (&where, c + 1) &&
					    !coords_equal (&where, c + 2) && !coords_equal (&where, c + 3)) {

						wire_remove_node (wire, node);
						wire_remove_node (other, node);
						node_remove_wire (node, wire);
						node_remove_wire (node, other);
					}
				}
			}
		}
	}

	// Check for overlapping with other wires.
	do {
		for (list = store->wires; list; list = list->next) {
			g_assert (list->data != NULL);
			g_assert (IS_WIRE (list->data));
			Wire *other = list->data;
			Coords so, eo;
			const gboolean overlap = do_wires_overlap (wire, other, &so, &eo);
			NG_DEBUG ("overlap [ %p] and [ %p ] -- %s", wire, other,
			          overlap == TRUE ? "YES" : "NO");
			if (overlap) {
				Node *sn = node_store_get_node (store, eo);
				Node *en = node_store_get_node (store, so);
#if 1
				wire = vulcanize_wire (store, wire, other, &so, &eo);
				node_store_remove_wire (store, g_object_ref (other)); // equiv
				                                                      // wire_unregister
				                                                      // XXX FIXME this
				                                                      // modifies the list
				                                                      // we iterate over!
				// delay this until idle, so all handlers like adding view
				// representation are completed so existing wire-items can be deleted
				// properly
				// this is not fancy nor nice but seems to work fairly nicly
				g_idle_add (delayed_wire_delete, other);
				break;
				NG_DEBUG ("overlapping of %p with %p ", wire, other);
#else
				if (!sn && !en) {
					wire = vulcanize_wire (store, wire, other, &so, &eo);
				} else if (!sn) {
					NG_DEBUG ("do_something(TM) : %p sn==NULL ", other);
				} else if (!en) {
					NG_DEBUG ("do_something(TM) : %p en==NULL ", other);
				} else {
					NG_DEBUG ("do_something(TM) : %p else ", other);
				}
#endif
			} else {
				NG_DEBUG ("not of %p with %p ", wire, other);
			}
		}
	} while (list);

	// Check for intersection with parts (pins).
	for (list = store->parts; list; list = list->next) {
		g_assert (list->data != NULL);
		g_assert (IS_PART (list->data));

		Coords part_pos;
		gint num_pins = -1;
		Part *part = list->data;

		num_pins = part_get_num_pins (part);
		item_data_get_pos (ITEM_DATA (part), &part_pos);

		// Go through all the parts and see which of their
		// pins that intersect the wire.
		for (i = 0; i < num_pins; i++) {
			Pin *pins;
			Coords lookup_pos;

			pins = part_get_pins (part);
			lookup_pos.x = part_pos.x + pins[i].offset.x;
			lookup_pos.y = part_pos.y + pins[i].offset.y;

			// If there is a wire at this pin's position,
			// add it to the return list.
			if (is_point_on_wire (wire, &lookup_pos)) {
				Node *node;
				node = node_store_get_node (store, lookup_pos);

				if (node != NULL) {
					// Add the wire to the node (pin) that it intersected.
					node_add_wire (node, wire);
					wire_add_node (wire, node);
					NG_DEBUG ("Add wire %p to pin (node) %p.\n", wire, node);
				} else {
					g_warning ("Bug: Found no node at pin at (%g %g).\n", lookup_pos.x,
					           lookup_pos.y);
				}
			}
		}
	}

	g_object_set (G_OBJECT (wire), "store", store, NULL);
	store->wires = g_list_prepend (store->wires, wire);
	store->items = g_list_prepend (store->items, wire);

	return TRUE;
}
示例#23
0
int
node_store_add_wire (NodeStore *store, Wire *wire)
{
	gdouble x1, y1, x2, y2;
	GSList *ip_list, *list;
	IntersectionPoint *ipoint;
	Node *node;
	SheetPos pos, length;

	g_return_val_if_fail (store != NULL, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
	g_return_val_if_fail (wire != NULL, FALSE);
	g_return_val_if_fail (IS_WIRE (wire), FALSE);

	wire_get_pos_and_length (wire, &pos, &length);

	x1 = pos.x;
	y1 = pos.y;
	x2 = x1 + length.x;
	y2 = y1 + length.y;

	// Check for intersection with other wires.
	ip_list = wires_intersect (store, x1, y1, x2, y2);

	for (list = ip_list; list; list = list->next) {
		ipoint = list->data;

		if (IS_EQ (x1, x2) && ((ipoint->pos.y == y1) || (ipoint->pos.y == y2))) {
			SheetPos w_pos, w_length;
			gboolean can_join;
			GSList *nodes;

			wire_get_pos_and_length (ipoint->wire, &w_pos, &w_length);
			gdouble _x1, _x2, _y1, _y2;

			_x1 = w_pos.x;
			_y1 = w_pos.y;
			_x2 = _x1 + w_length.x;
			_y2 = _y1 + w_length.y;

			can_join = TRUE;
			nodes = wire_get_nodes (wire);
			for (; nodes; nodes = nodes->next) {
				SheetPos p1;
				Node *node = (Node *)nodes->data;

				p1.x = _x1;
				p1.y = _y1;
				if ((fabs (node->key.x - p1.x) < 1e-3) && 
				    (fabs (node->key.y - p1.y) < 1e-3)){
					can_join = FALSE;
					break;
				}
				p1.x = _x2;
				p1.y = _y2;
				if ((fabs (node->key.x - p1.x) < 1e-3) && 
				    (fabs (node->key.y - p1.y) < 1e-3)){    
					can_join = FALSE;
					break;
				}
			}

			if (IS_EQ(_x1, _x2) && can_join) {
				if (w_pos.x < pos.x) pos.x = w_pos.x;
				if (w_pos.y < pos.y) pos.y = w_pos.y;
				length.x += w_length.x;
				length.y += w_length.y;

				// Update the new size and pos of the wire
				item_data_unregister (ITEM_DATA (ipoint->wire));
				wire_set_length (ipoint->wire, &length);
				item_data_set_pos (ITEM_DATA (ipoint->wire), &pos);
				wire_update_bbox (ipoint->wire);
				item_data_register (ITEM_DATA (ipoint->wire));

				// Done!, return -1 so wire is deleted
				return -1;
			}
		}
		else if (IS_EQ (y1, y2)          && 
		         ((ipoint->pos.x == x1)  || 
				  (ipoint->pos.x == x2))) {
			SheetPos w_pos, w_length;
			gboolean can_join;
			GSList *nodes;

			wire_get_pos_and_length (ipoint->wire, &w_pos, &w_length);
			gdouble _x1, _x2, _y1, _y2;

			_x1 = w_pos.x;
			_y1 = w_pos.y;
			_x2 = _x1 + w_length.x;
			_y2 = _y1 + w_length.y;

			can_join = TRUE;
			nodes = wire_get_nodes (wire);
			for (; nodes; nodes = nodes->next) {
				SheetPos p;
				Node *node = (Node *)nodes->data;

				p.x = _x1;
				p.y = _y1;
				if ((fabs (node->key.x - p.x) < 1e-3) && 
				    (fabs (node->key.y - p.y) < 1e-3)){  
					can_join = FALSE;
					break;
				}
				p.x = _x2;
				p.y = _y2;
				if ((fabs (node->key.x - p.x) < 1e-3) && 
				    (fabs (node->key.y - p.y) < 1e-3)){  
					can_join = FALSE;
					break;
				}
			}

			if (IS_EQ(_y1, _y2) && can_join) {
				if (w_pos.x < pos.x) pos.x = w_pos.x;
				if (w_pos.y < pos.y) pos.y = w_pos.y;
				length.x += w_length.x;
				length.y += w_length.y;

				// Update the new size and pos of the wire
				item_data_unregister (ITEM_DATA (ipoint->wire));
				wire_set_length (ipoint->wire, &length);
				item_data_set_pos (ITEM_DATA (ipoint->wire), &pos);
				wire_update_bbox (ipoint->wire);
				item_data_register (ITEM_DATA (ipoint->wire));

				// Done!, return -1 so wire si deleted
				return -1;
			}
		}

		node = node_store_get_or_create_node (store, ipoint->pos);

		// Add the wire, and also the wire that is intersected.
		node_add_wire (node, wire);
		node_add_wire (node, ipoint->wire);

		wire_add_node (wire, node);
		wire_add_node (ipoint->wire, node);

		NG_DEBUG ("Add wire to wire.\n");

		g_free (ipoint);
	}
	g_slist_free (ip_list);

	// Check for intersection with parts (pins).
	ip_list = wire_intersect_parts (store, wire);

	for (list = ip_list; list; list = list->next) {
		node = list->data;

		// Add the wire to the node (pin) that it intersected.
		node_add_wire (node, wire);
		wire_add_node (wire, node);

		NG_DEBUG ("Add wire to pin.\n");
	}

	g_slist_free (ip_list);

	g_object_set (G_OBJECT (wire), "store", store, NULL);
	store->wires = g_list_prepend (store->wires, wire);
	store->items = g_list_prepend (store->items, wire);

	return TRUE;
}