Skip to content

Commit

Permalink
Refactor|BSP Builder|SuperBlockmap: Added SuperBlock::collateAllSegme…
Browse files Browse the repository at this point in the history
…nts()
  • Loading branch information
danij-deng committed May 29, 2013
1 parent cfec772 commit 6299f79
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 128 deletions.
9 changes: 8 additions & 1 deletion doomsday/client/include/map/bsp/superblockmap.h
Expand Up @@ -273,7 +273,14 @@ class SuperBlock
LineSegment::Side *pop();

/**
* Provides access to the list of line segments for efficient traversal.
* Collate (unlink) all line segments from "this" and all child blocks
* to a new segment list.
*/
Segments collateAllSegments();

/**
* Provides access to the list of line segments in the block, for efficient
* traversal.
*/
Segments const &segments() const;

Expand Down
164 changes: 37 additions & 127 deletions doomsday/client/src/map/bsp/partitioner.cpp
Expand Up @@ -648,35 +648,35 @@ DENG2_PIMPL(Partitioner)
}

void chooseNextPartitionFromSuperBlock(SuperBlock const &partList,
SuperBlock const &lineSegList, LineSegment::Side **best, PartitionCost &bestCost)
SuperBlock const &segs, LineSegment::Side **best, PartitionCost &bestCost)
{
DENG2_ASSERT(best != 0);

//LOG_AS("chooseNextPartitionFromSuperBlock");

// Test each line segment as a potential partition.
foreach(LineSegment::Side *lineSeg, partList.segments())
foreach(LineSegment::Side *seg, partList.segments())
{
//LOG_DEBUG("%sline segment %p sector:%d %s -> %s")
// << (lineSeg->hasMapLineSide()? "" : "mini-") << de::dintptr(*lineSeg)
// << (lineSeg->sector? lineSeg->sector->indexInMap() : -1)
// << lineSeg->fromOrigin().asText()
// << lineSeg->toOrigin().asText();
// << (seg->hasMapLineSide()? "" : "mini-") << de::dintptr(*seg)
// << (seg->sector? seg->sector->indexInMap() : -1)
// << seg->fromOrigin().asText()
// << seg->toOrigin().asText();

// Optimization: Only the first line segment produced from a given
// line is tested per round of partition costing (they are all
// collinear).
if(lineSeg->hasMapSide())
if(seg->hasMapSide())
{
// Can we skip this line segment?
if(lineSeg->mapLine().validCount() == validCount) continue; // Yes.
if(seg->mapLine().validCount() == validCount) continue; // Yes.

lineSeg->mapLine().setValidCount(validCount);
seg->mapLine().setValidCount(validCount);
}

// Calculate the cost metrics for this line segment.
PartitionCost cost;
if(evalPartition(lineSegList, *best, bestCost, *lineSeg, cost))
if(evalPartition(segs, *best, bestCost, *seg, cost))
{
// Suitable for use as a partition.
if(!*best || cost < bestCost)
Expand All @@ -685,7 +685,7 @@ DENG2_PIMPL(Partitioner)
bestCost = cost;

// Remember which line segment.
*best = lineSeg;
*best = seg;
}
}
}
Expand Down Expand Up @@ -995,51 +995,12 @@ DENG2_PIMPL(Partitioner)
* @param rights Set of line segments on the right side of the partition.
* @param lefts Set of line segments on the left side of the partition.
*/
void partitionSegments(SuperBlock &segments, SuperBlock &rights,
void partitionSegments(LineSegmentList &segments, SuperBlock &rights,
SuperBlock &lefts)
{
// Iterative pre-order traversal of SuperBlock.
SuperBlock *cur = &segments;
SuperBlock *prev = 0;
while(cur)
while(!segments.isEmpty())
{
while(cur)
{
LineSegment::Side *seg;
while((seg = cur->pop()))
{
// Disassociate the line segment from the blockmap.
seg->setBMapBlock(0);

partitionOneSegment(*seg, rights, lefts);
}

if(prev == cur->parentPtr())
{
// Descending - right first, then left.
prev = cur;
if(cur->hasRight()) cur = cur->rightPtr();
else cur = cur->leftPtr();
}
else if(prev == cur->rightPtr())
{
// Last moved up the right branch - descend the left.
prev = cur;
cur = cur->leftPtr();
}
else if(prev == cur->leftPtr())
{
// Last moved up the left branch - continue upward.
prev = cur;
cur = cur->parentPtr();
}
}

if(prev)
{
// No left child - back up.
cur = prev->parentPtr();
}
partitionOneSegment(*segments.takeFirst(), rights, lefts);
}

// Sanity checks...
Expand Down Expand Up @@ -1225,59 +1186,61 @@ DENG2_PIMPL(Partitioner)
* If the line segments on the right side are convex create another leaf
* else put the line segments into the right list.
*
* @param lineSegs Set of line segments in the plane to be carved into
* convex regions.
* @param bmap SuperBlockmap containing the set of line segments in the
* plane to be partitioned into convex subspaces.
*
* @return Newly created subtree; otherwise @c 0 (degenerate).
*/
BspTreeNode *partitionSpace(SuperBlock &segs)
BspTreeNode *partitionSpace(SuperBlock &bmap)
{
LOG_AS("Partitioner::partitionSpace");

MapElement *bspElement = 0; ///< Built BSP map element at this node.
BspTreeNode *rightTree = 0, *leftTree = 0;

// Pick a line segment to use as the next partition plane.
LineSegment::Side *partLineSeg = chooseNextPartition(segs);
if(partLineSeg)
LineSegment::Side *partSeg = chooseNextPartition(bmap);
if(partSeg)
{
// Reconfigure the half-plane for the next round of partitioning.
hplane.configure(*partLineSeg);
hplane.configure(*partSeg);

//LOG_TRACE("%s, line segment %p %s %s.")
// << hplane.partition().asText()
// << de::dintptr(*partLineSeg)
// << partLineSeg->fromOrigin().asText()
// << partLineSeg->toOrigin().asText()
// << de::dintptr(*partSeg)
// << partSeg->fromOrigin().asText()
// << partSeg->toOrigin().asText()

// Take a copy of the current partition - we'll need this for any
// BspNode we produce later.
Partition partition(hplane.partition());

// Create left and right super blockmaps.
// Create left and right blockmaps.
/// @todo There should be no need to use additional independent
/// structures to contain these subsets.
// Copy the bounding box of the edge list to the superblocks.
SuperBlockmap rightSegs(segs.bounds());
SuperBlockmap leftSegs(segs.bounds());
SuperBlockmap rightBMap(bmap.bounds());
SuperBlockmap leftBMap(bmap.bounds());

// Partition the line segements into two subsets according to their
// spacial relationship with the half-plane (splitting any which
// intersect).
partitionSegments(segs, rightSegs, leftSegs);
LineSegmentList segments = bmap.collateAllSegments();
bmap.clear(); // Should be empty.

segs.clear(); // Should be empty.
partitionSegments(segments, rightBMap, leftBMap);
DENG_ASSERT(segments.isEmpty());

addPartitionLineSegments(rightSegs, leftSegs);
addPartitionLineSegments(rightBMap, leftBMap);

// Take a copy of the geometry bounds for each child/sub space
// - we'll need this for any BspNode we produce later.
AABoxd rightBounds = rightSegs.findSegmentBounds();
AABoxd leftBounds = leftSegs.findSegmentBounds();
AABoxd rightBounds = rightBMap.findSegmentBounds();
AABoxd leftBounds = leftBMap.findSegmentBounds();

// Recurse on each suspace, first the right space then left.
rightTree = partitionSpace(rightSegs);
leftTree = partitionSpace(leftSegs);
rightTree = partitionSpace(rightBMap);
leftTree = partitionSpace(leftBMap);

// Collapse degenerates upward.
if(!rightTree || !leftTree)
Expand All @@ -1290,7 +1253,8 @@ DENG2_PIMPL(Partitioner)
else
{
// No partition required/possible -- already convex (or degenerate).
LineSegmentList segments = collectLineSegments(segs);
LineSegmentList segments = bmap.collateAllSegments();
bmap.clear(); // Should be empty.

convexSubspaces.append(ConvexSubspace());
ConvexSubspace &convexSet = convexSubspaces.last();
Expand All @@ -1313,9 +1277,6 @@ DENG2_PIMPL(Partitioner)
// Attribute the leaf to the convex subspace.
convexSet.setBspLeaf(leaf);

// We have finished with the SuperBlock at this node.
segs.clear();

bspElement = leaf;
}

Expand Down Expand Up @@ -1541,57 +1502,6 @@ DENG2_PIMPL(Partitioner)
return vtx;
}

LineSegmentList collectLineSegments(SuperBlock &superblock)
{
LineSegmentList segments;

// Iterative pre-order traversal of SuperBlock.
SuperBlock *cur = &superblock;
SuperBlock *prev = 0;
while(cur)
{
while(cur)
{
LineSegment::Side *seg;
while((seg = cur->pop()))
{
// Disassociate the line segment from the blockmap.
seg->setBMapBlock(0);

segments << seg;
}

if(prev == cur->parentPtr())
{
// Descending - right first, then left.
prev = cur;
if(cur->hasRight()) cur = cur->rightPtr();
else cur = cur->leftPtr();
}
else if(prev == cur->rightPtr())
{
// Last moved up the right branch - descend the left.
prev = cur;
cur = cur->leftPtr();
}
else if(prev == cur->leftPtr())
{
// Last moved up the left branch - continue upward.
prev = cur;
cur = cur->parentPtr();
}
}

if(prev)
{
// No left child - back up.
cur = prev->parentPtr();
}
}

return segments;
}

bool release(MapElement *elm)
{
switch(elm->type())
Expand Down
55 changes: 55 additions & 0 deletions doomsday/client/src/map/bsp/superblockmap.cpp
Expand Up @@ -150,6 +150,61 @@ SuperBlock *SuperBlock::addChild(ChildId childId, bool splitVertical)
return new SuperBlock(*this, childId, splitVertical);
}

SuperBlock::Segments SuperBlock::collateAllSegments()
{
Segments segments;

#ifdef DENG2_QT_4_7_OR_NEWER
segments.reserve(totalSegmentCount());
#endif

// Iterative pre-order traversal of SuperBlock.
SuperBlock *cur = this;
SuperBlock *prev = 0;
while(cur)
{
while(cur)
{
LineSegment::Side *seg;
while((seg = cur->pop()))
{
// Disassociate the line segment from the blockmap.
seg->setBMapBlock(0);

segments << seg;
}

if(prev == cur->parentPtr())
{
// Descending - right first, then left.
prev = cur;
if(cur->hasRight()) cur = cur->rightPtr();
else cur = cur->leftPtr();
}
else if(prev == cur->rightPtr())
{
// Last moved up the right branch - descend the left.
prev = cur;
cur = cur->leftPtr();
}
else if(prev == cur->leftPtr())
{
// Last moved up the left branch - continue upward.
prev = cur;
cur = cur->parentPtr();
}
}

if(prev)
{
// No left child - back up.
cur = prev->parentPtr();
}
}

return segments;
}

SuperBlock::Segments const &SuperBlock::segments() const
{
return d->segments;
Expand Down

0 comments on commit 6299f79

Please sign in to comment.