Esempio n. 1
0
    /**
     * Analyze the half-plane intercepts, building new line segments to cap
     * any gaps (new segments are added onto the end of the appropriate list
     * (rights to @a rightList and lefts to @a leftList)).
     *
     * @param rights  Set of line segments on the right of the partition.
     * @param lefts   Set of line segments on the left of the partition.
     */
    void addPartitionLineSegments(LineSegmentBlockTreeNode &rights,
                                  LineSegmentBlockTreeNode &lefts)
    {
        LOG_TRACE("Building line segments along partition %s")
                << hplane.partition().asText();

        // First, fix any near-distance issues with the intercepts.
        hplane.sortAndMergeIntercepts();

        //hplane.printIntercepts();

        // We must not create new line segments on top of the source partition
        // line segment (as this will result in duplicate edges finding their
        // way into the BSP leaf geometries).
        LineSegmentSide *partSeg = hplane.lineSegment();
        double nearDist = 0, farDist = 0;

        if(partSeg)
        {
            nearDist = hplane.intersect(*partSeg, LineSegment::From);
            farDist  = hplane.intersect(*partSeg, LineSegment::To);
        }

        // Create new line segments.
        for(int i = 0; i < hplane.interceptCount() - 1; ++i)
        {
            HPlaneIntercept const &cur  = hplane.intercepts()[i];
            HPlaneIntercept const &next = hplane.intercepts()[i+1];

            // Does this range overlap the partition line segment?
            if(partSeg && cur.distance() >= nearDist && next.distance() <= farDist)
                continue;

            // Void space or an existing segment between the two intercepts?
            if(!cur.after() && !next.before())
                continue;

            // Check for some nasty open/closed or close/open cases.
            if(cur.after() && !next.before())
            {
                if(!cur.lineSegmentIsSelfReferencing())
                {
                    Vector2d nearPoint = (cur.vertex().origin() + next.vertex().origin()) / 2;
                    notifyUnclosedSectorFound(*cur.after(), nearPoint);
                }
                continue;
            }

            if(!cur.after() && next.before())
            {
                if(!next.lineSegmentIsSelfReferencing())
                {
                    Vector2d nearPoint = (cur.vertex().origin() + next.vertex().origin()) / 2;
                    notifyUnclosedSectorFound(*next.before(), nearPoint);
                }
                continue;
            }

            /*
             * This is definitely open space.
             */
            Vertex &fromVertex = cur.vertex();
            Vertex &toVertex   = next.vertex();

            Sector *sector = cur.after();
            if(!cur.before() && next.before() == next.after())
            {
                sector = next.before();
            }
            // Choose the non-self-referencing sector when we can.
            else if(cur.after() != next.before())
            {
                if(!cur.lineSegmentIsSelfReferencing() &&
                   !next.lineSegmentIsSelfReferencing())
                {
                    LOG_DEBUG("Sector mismatch #%d %s != #%d %s")
                            << cur.after()->indexInMap()
                            << cur.vertex().origin().asText()
                            << next.before()->indexInMap()
                            << next.vertex().origin().asText();
                }

                LineSegmentSide *afterSeg = cur.afterLineSegment();
                if(afterSeg->hasMapLine() && afterSeg->mapLine().isSelfReferencing())
                {
                    LineSegmentSide *beforeSeg = next.beforeLineSegment();
                    if(beforeSeg->hasMapLine() && !beforeSeg->mapLine().isSelfReferencing())
                    {
                        sector = next.before();
                    }
                }
            }

            DENG2_ASSERT(sector);

            LineSegment &newSeg = *makeLineSegment(fromVertex, toVertex,
                                                   sector, sector, nullptr /*no map line*/,
                                                   partSeg? &partSeg->mapLine() : nullptr);

            edgeTipSet(newSeg.from()) << EdgeTip(newSeg.front());
            edgeTipSet(newSeg.to())   << EdgeTip(newSeg.back());

            // Add each new line segment to the appropriate set.
            linkLineSegmentInBlockTree(rights, newSeg.front());
            linkLineSegmentInBlockTree(lefts,  newSeg.back());

            /*
            LOG_DEBUG("Built line segment from %s to %s (sector #%i)")
                    << fromVertex.origin().asText()
                    << toVertex.origin().asText()
                    << sector->indexInArchive();
            */
        }
    }