/** * 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(); */ } }