// This method traverses the hyperedge tree removing zero length edges. // void HyperEdgeTreeNode::removeZeroLengthEdges(HyperEdgeTreeEdge *ignored) { for (std::list<HyperEdgeTreeEdge *>::iterator curr = edges.begin(); curr != edges.end(); ++curr) { HyperEdgeTreeEdge *edge = *curr; if (edge != ignored) { if (edge->zeroLength()) { HyperEdgeTreeNode *other = edge->followFrom(this); HyperEdgeTreeNode *target = NULL; HyperEdgeTreeNode *source = NULL; if (other->junction && ! junction) { target = other; source = this; } else if ( ! other->junction && junction) { target = this; source = other; } else if ( ! other->junction && ! junction) { target = this; source = other; } if (target) { edge->disconnectEdge(); delete edge; target->spliceEdgesFrom(source); delete source; target->removeZeroLengthEdges(ignored); return; } // XXX Deal with merging two junctions? } // Recursive call. edge->removeZeroLengthEdges(this); } } }
// This method moves the junction at the given node along any shared paths // (so long as this action would not create any additional shared paths), // while also removing and freeing merged edges and nodes in the process. // It returns the new node where the junction is now located. // HyperEdgeTreeNode *HyperEdgeTreeNode::moveJunctionAlongCommonEdge( HyperEdgeTreeNode *self) { COLA_ASSERT(self->junction); HyperEdgeTreeNode *newSelf = NULL; std::vector<HyperEdgeTreeEdge *> commonEdges; std::vector<HyperEdgeTreeEdge *> otherEdges; // Consider each edge from this node in turn. for (std::list<HyperEdgeTreeEdge *>::iterator curr = self->edges.begin(); curr != self->edges.end(); ++curr) { HyperEdgeTreeEdge *currEdge = *curr; HyperEdgeTreeNode *currNode = currEdge->followFrom(self); commonEdges.clear(); otherEdges.clear(); if (currNode->junction) { // Don't shift junctions onto other junctions. continue; } // The current edge is a common edge we are looking to shift along. commonEdges.push_back(currEdge); // Consider each of the other edges. for (std::list<HyperEdgeTreeEdge *>::iterator curr2 = self->edges.begin(); curr2 != self->edges.end(); ++curr2) { if (curr == curr2) { // Except the current (curr) one. continue; } HyperEdgeTreeEdge *otherEdge = *curr2; HyperEdgeTreeNode *otherNode = otherEdge->followFrom(self); if (otherNode->point == currNode->point) { // A common edge can be at the same point, but can't have // a junction at it. if (otherNode->junction) { otherEdges.push_back(otherEdge); } else { commonEdges.push_back(otherEdge); } } else if (pointOnLine(self->point, otherNode->point, currNode->point)) { // A common edge can be a (longer) collinear line, but we // need to split the longer line at the other end of curr. otherEdge->splitFromNodeAtPoint(self, currNode->point); commonEdges.push_back(otherEdge); } else { // If the edge goes in another direction it is not common. otherEdges.push_back(otherEdge); } } if ((commonEdges.size() > 1) && (otherEdges.size() <= 1)) { // One of the common nodes becomes the target node, we move // all connections from the other common nodes to this node. // We also move the junction there and remove it from the // current node. HyperEdgeTreeNode *targetNode = commonEdges[0]->followFrom(self); for (size_t i = 1; i < commonEdges.size(); ++i) { HyperEdgeTreeNode *thisNode = commonEdges[i]->followFrom(self); commonEdges[i]->disconnectEdge(); targetNode->spliceEdgesFrom(thisNode); delete thisNode; delete commonEdges[i]; } targetNode->junction = self->junction; self->junction = NULL; if (otherEdges.empty()) { // Nothing else connected to this node, so remove the node // and the edge to the target node. commonEdges[0]->disconnectEdge(); delete commonEdges[0]; delete self; } else { // We need to mark commonEdges[0] as being from the connector // of the otherEdges[0]. commonEdges[0]->conn = otherEdges[0]->conn; } newSelf = targetNode; break; } } return newSelf; }