예제 #1
0
    /**
     * Find the intersection point between a line segment and the current
     * partition plane. Takes advantage of some common situations like
     * horizontal and vertical lines to choose a 'nicer' intersection point.
     */
    Vector2d intersectPartition(LineSegmentSide const &seg, coord_t fromDist,
                                coord_t toDist) const
    {
        // Horizontal partition vs vertical line segment.
        if(hplane.slopeType() == ST_HORIZONTAL && seg.slopeType() == ST_VERTICAL)
        {
            return Vector2d(seg.from().origin().x, hplane.partition().origin.y);
        }

        // Vertical partition vs horizontal line segment.
        if(hplane.slopeType() == ST_VERTICAL && seg.slopeType() == ST_HORIZONTAL)
        {
            return Vector2d(hplane.partition().origin.x, seg.from().origin().y);
        }

        // 0 = start, 1 = end.
        coord_t ds = fromDist / (fromDist - toDist);

        Vector2d point = seg.from().origin();
        if(seg.slopeType() != ST_VERTICAL)
            point.x += seg.direction().x * ds;

        if(seg.slopeType() != ST_HORIZONTAL)
            point.y += seg.direction().y * ds;

        return point;
    }
예제 #2
0
void HPlane::distance(LineSegmentSide const &lineSeg, coord_t *fromDist, coord_t *toDist) const
{
    // Any work to do?
    if(!fromDist && !toDist) return;

    /// @attention Ensure line segments produced from the partition's source
    /// line are always treated as collinear. This special case is only
    /// necessary due to precision inaccuracies when a line is split into
    /// multiple segments.
    if(d->lineSegment && &d->lineSegment->mapSide().line() == lineSeg.partitionMapLine())
    {
        if(fromDist) *fromDist = 0;
        if(toDist)   *toDist   = 0;
        return;
    }

    coord_t toSegDirectionV1[2] = { d->partition.direction.x, d->partition.direction.y } ;

    if(fromDist)
    {
        coord_t fromV1[2] = { lineSeg.from().origin().x, lineSeg.from().origin().y };
        *fromDist = V2d_PointLinePerpDistance(fromV1, toSegDirectionV1, d->perp, d->length);
    }
    if(toDist)
    {
        coord_t toV1[2]   = { lineSeg.to().origin().x, lineSeg.to().origin().y };
        *toDist = V2d_PointLinePerpDistance(toV1, toSegDirectionV1, d->perp, d->length);
    }
}
예제 #3
0
    /**
     * Link @a seg into the line segment block tree.
     *
     * Performs k-d tree subdivision of the 2D coordinate space, splitting the node
     * tree as necessary, however new nodes are created only when they need to be
     * populated (i.e., a split does not generate two nodes at the same time).
     */
    void linkLineSegmentInBlockTree(LineSegmentBlockTreeNode &node_, LineSegmentSide &seg)
    {
        // Traverse the node tree beginning at "this" node.
        for(LineSegmentBlockTreeNode *node = &node_; ;)
        {
            LineSegmentBlock &block = *node->userData();
            AABox const &bounds     = block.bounds();

            // The segment "touches" this node; increment the ref counters.
            block.addRef(seg);

            // Determine whether further subdivision is necessary/possible.
            Vector2i dimensions(Vector2i(bounds.max) - Vector2i(bounds.min));
            if(dimensions.x <= 256 && dimensions.y <= 256)
            {
                // Thats as small as we go; link it in and return.
                block.link(seg);
                seg.setBlockTreeNode(node);
                return;
            }

            // Determine whether the node should be split and on which axis.
            int const splitAxis = (dimensions.x < dimensions.y); // x=0, y=1
            int const midOnAxis = (bounds.min[splitAxis] + bounds.max[splitAxis]) / 2;
            LineSegmentBlockTreeNode::ChildId fromSide = LineSegmentBlockTreeNode::ChildId(seg.from().origin()[splitAxis] >= midOnAxis);
            LineSegmentBlockTreeNode::ChildId toSide   = LineSegmentBlockTreeNode::ChildId(seg.to  ().origin()[splitAxis] >= midOnAxis);

            // Does the segment lie entirely within one half of this node?
            if(fromSide != toSide)
            {
                // No, the segment crosses @var midOnAxis; link it in and return.
                block.link(seg);
                seg.setBlockTreeNode(node);
                return;
            }

            // Do we need to create the child node?
            if(!node->hasChild(fromSide))
            {
                bool const toLeft = (fromSide == LineSegmentBlockTreeNode::Left);

                AABox childBounds;
                if(splitAxis)
                {
                    // Vertical split.
                    int division = bounds.minY + 0.5 + (bounds.maxY - bounds.minY) / 2;

                    childBounds.minX = bounds.minX;
                    childBounds.minY = (toLeft? division : bounds.minY);

                    childBounds.maxX = bounds.maxX;
                    childBounds.maxY = (toLeft? bounds.maxY : division);
                }
                else
                {
                    // Horizontal split.
                    int division = bounds.minX + 0.5 + (bounds.maxX - bounds.minX) / 2;

                    childBounds.minX = (toLeft? division : bounds.minX);
                    childBounds.minY = bounds.minY;

                    childBounds.maxX = (toLeft? bounds.maxX : division);
                    childBounds.maxY = bounds.maxY;
                }

                // Add a new child node and link it to its parent.
                LineSegmentBlock *childBlock = new LineSegmentBlock(childBounds);
                node->setChild(fromSide, new LineSegmentBlockTreeNode(childBlock, node));
            }

            // Descend to the child node.
            node = node->childPtr(fromSide);
        }
    }