Example #1
0
// 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);
        }
    }
}
Example #2
0
// 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;
}