Skip to content

Commit

Permalink
World|Sector: Improved sector cluster containment determination
Browse files Browse the repository at this point in the history
Comparing cluster bounding boxes is not always enough to accurately
determine whether one cluster contains another. If this simpler test
suggests that containment is possible we now perform a more complex
check, comparing the bounding boxes of each contiguous boundary.

The elevator near the blue/turquoise key in Back To Saturn X MAP04
is now interpreted and rendered correctly.
  • Loading branch information
danij-deng committed Sep 24, 2013
1 parent 4a32c66 commit 49e5df0
Showing 1 changed file with 72 additions and 5 deletions.
77 changes: 72 additions & 5 deletions doomsday/client/src/world/sectorcluster.cpp
Expand Up @@ -20,6 +20,7 @@

#include <QRect>
#include <QMap>
#include <QMutableMapIterator>
#include <QSet>
#include <QtAlgorithms>

Expand Down Expand Up @@ -345,19 +346,85 @@ DENG2_OBSERVES(Plane, HeightChange)
}

boundaryInfo.reset(new BoundaryInfo);
if(extClusterMap.isEmpty())
return;

QRectF boundingRect = qrectFromAABox(self.aaBox());
foreach(HEdge *hedge, extClusterMap)

// First try to quickly decide by comparing cluster bounding boxes.
QMutableMapIterator<Cluster *, HEdge *> iter(extClusterMap);
while(iter.hasNext())
{
Cluster &extCluster = hedge->twin().face().mapElement()->as<BspLeaf>().cluster();
iter.next();
Cluster &extCluster = iter.value()->twin().face().mapElement()->as<BspLeaf>().cluster();
if(!boundingRect.contains(qrectFromAABox(extCluster.aaBox())))
{
boundaryInfo->uniqueOuterEdges.append(iter.value());
iter.remove();
}
}

if(extClusterMap.isEmpty())
return;

if(boundingRect.contains(qrectFromAABox(extCluster.aaBox())))
// More extensive tests are necessary. At this point we know that all
// clusters which remain in the map are inside according to the bounding
// box of "this" cluster.
QList<HEdge *> const boundaryEdges = extClusterMap.values();
QList<QRectF> boundaries;
for(int i = 0; i < boundaryEdges.count(); ++i)
{
HEdge *base = boundaryEdges[i];

QRectF bounds = QRectF(QPointF(base->origin().x, base->origin().y),
QPointF(base->twin().origin().x, base->twin().origin().y))
.normalized();

HEdge *hedge = &base->next();
do
{
boundaryInfo->uniqueInnerEdges.append(hedge);
while(hedge->twin().hasFace())
{
Cluster &backCluster = hedge->twin().face().mapElement()->as<BspLeaf>().cluster();
if(&backCluster == thisPublic)
{
hedge = &hedge->twin().next();
}
else
{
break;
}
}

if(hedge == base)
break;

bounds |= QRectF(QPointF(hedge->origin().x, hedge->origin().y),
QPointF(hedge->twin().origin().x, hedge->twin().origin().y))
.normalized();
} while((hedge = &hedge->next()) != base);

boundaries.append(bounds);
}

QRectF const *largest = 0;
foreach(QRectF const &boundary, boundaries)
{
if(!largest || boundary.contains(*largest))
largest = &boundary;
}

for(int i = 0; i < boundaryEdges.count(); ++i)
{
HEdge *hedge = boundaryEdges[i];
QRectF const &boundary = boundaries[i];
if(&boundary == largest || boundary == *largest)
{
boundaryInfo->uniqueOuterEdges.append(hedge);
}
else
{
boundaryInfo->uniqueOuterEdges.append(hedge);
boundaryInfo->uniqueInnerEdges.append(hedge);
}
}
}
Expand Down

0 comments on commit 49e5df0

Please sign in to comment.