Skip to content

Commit

Permalink
Fixed|BSP Builder: Space partitioner logic error resulting in duplica…
Browse files Browse the repository at this point in the history
…te line segments

When building line segments along the partitioning half-plane care
must be taken to ensure that new segments are not creating on top of
the one chosen as the partition line. Otherwise duplicate edges will
find their way into the BSP leaf geometries.

Also removed Partitioner's PartialBspLeafBuilt notification as any
malformed geometry should be considered the net result of a bug in
partitioning algorithm.
  • Loading branch information
danij-deng committed May 18, 2013
1 parent 8263107 commit 8921204
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 125 deletions.
20 changes: 17 additions & 3 deletions doomsday/client/include/map/bsp/hplane.h
Expand Up @@ -64,8 +64,8 @@ class HPlane
/// Sector on each side of the vertex (along the partition), or @c 0
/// if that direction is "closed" (i.e., the intercept point is along
/// a map line that has no Sector on the relevant side).
Sector *before;
Sector *after;
Sector *front;
Sector *back;

public:
Intercept(double distance, LineSegment::Side &lineSeg, int edge);
Expand Down Expand Up @@ -138,6 +138,20 @@ class HPlane
*/
void configure(LineSegment::Side const &newLineSeg);

/**
* Perform intersection of the half-plane with the specified @a lineSeg
* to determine the distance (along the partition line) at which the
* @a edge vertex can be found.
*
* @param lineSeg Line segment to perform intersection with.
* @param edge Line segment edge identifier of the vertex to use
* for intersection.
*
* @return Distance to intersection point along the half-plane (relative
* to the origin).
*/
double intersect(LineSegment::Side const &lineSeg, int edge);

/**
* Perform intersection of the half-plane with the specified @a lineSeg.
* If the two are found to intersect -- a new intercept will be added to
Expand Down Expand Up @@ -222,7 +236,7 @@ class HPlane
* chosen as the half-plane partition. May return @c 0 (if no map line was
* attributed).
*/
Line *mapLine() const;
LineSegment::Side *lineSegment() const;

/**
* Calculate @em perpendicular distances from one or both of the vertexe(s)
Expand Down
3 changes: 0 additions & 3 deletions doomsday/client/include/map/bsp/partitioner.h
Expand Up @@ -66,9 +66,6 @@ class Partitioner
DENG2_DEFINE_AUDIENCE(MigrantHEdgeBuilt,
void migrantHEdgeBuilt(HEdge &hedge, Sector &facingSector))

DENG2_DEFINE_AUDIENCE(PartialBspLeafBuilt,
void partialBspLeafBuilt(BspLeaf &bspLeaf, uint gapCount))

public:
Partitioner(GameMap const &map, int splitCostFactor = 7);

Expand Down
83 changes: 45 additions & 38 deletions doomsday/client/src/map/bsp/hplane.cpp
Expand Up @@ -45,8 +45,8 @@ namespace bsp {

HPlane::Intercept::Intercept(ddouble distance, LineSegment::Side &lineSeg, int edge)
: selfRef(false),
before(0),
after(0),
back(0),
front(0),
_distance(distance),
_lineSeg(&lineSeg),
_edge(edge)
Expand All @@ -68,8 +68,8 @@ void HPlane::Intercept::debugPrint() const
LOG_INFO("Vertex #%i %s beforeSector: #%d afterSector: #%d %s")
<< vertex().indexInMap()
<< vertex().origin().asText()
<< (before? before->indexInMap() : -1)
<< (after? after->indexInMap() : -1)
<< (back? back->indexInMap() : -1)
<< (front? front->indexInMap() : -1)
<< (selfRef? "SELFREF" : "");
}
#endif
Expand All @@ -94,8 +94,8 @@ DENG2_PIMPL(HPlane)
/// Parallel scale factor.
coord_t para;

/// Map line from which the partition line was derived (if any).
Line *mapLine;
/// Line segment from which the partition line was derived (if any).
LineSegment::Side *lineSegment;

/// Intercept points along the half-plane.
Intercepts intercepts;
Expand All @@ -112,7 +112,7 @@ DENG2_PIMPL(HPlane)
slopeType(M_SlopeTypeXY(partition.direction.x, partition.direction.y)),
perp(partition.origin.y * partition.direction.x - partition.origin.x * partition.direction.y),
para(-partition.origin.x * partition.direction.x - partition.origin.y * partition.direction.y),
mapLine(0),
lineSegment(0),
needSortIntercepts(false)
{}

Expand Down Expand Up @@ -156,13 +156,14 @@ void HPlane::configure(LineSegment::Side const &newBaseSeg)
// Clear the list of intersection points.
clearIntercepts();

// Reconfigure the partition line.
Line::Side &mapSide = newBaseSeg.mapSide();
d->mapLine = &mapSide.line();

// Reconfigure the partition line.
d->partition.origin = mapSide.from().origin();
d->partition.direction = mapSide.to().origin() - mapSide.from().origin();

d->lineSegment = const_cast<LineSegment::Side *>(&newBaseSeg);

d->length = d->partition.direction.length();
d->angle = M_DirectionToAngleXY(d->partition.direction.x, d->partition.direction.y);
d->slopeType = M_SlopeTypeXY(d->partition.direction.x, d->partition.direction.y);
Expand Down Expand Up @@ -220,25 +221,30 @@ static Sector *openSectorAtAngle(EdgeTips const &tips, coord_t angle)
return (tip.hasBack()? tip.back().sectorPtr() : 0);
}

double HPlane::intersect(LineSegment::Side const &lineSeg, int edge)
{
Vertex &vertex = lineSeg.vertex(edge);
coord_t pointV1[2] = { vertex.origin().x, vertex.origin().y };
coord_t directionV1[2] = { d->partition.direction.x, d->partition.direction.y };
return V2d_PointLineParaDistance(pointV1, directionV1, d->para, d->length);
}

HPlane::Intercept *HPlane::intercept(LineSegment::Side const &lineSeg, int edge,
EdgeTips const &edgeTips)
{
// Already present for this vertex?
Vertex &vertex = lineSeg.vertex(edge);
if(d->haveInterceptForVertex(vertex)) return 0;

coord_t pointV1[2] = { vertex.origin().x, vertex.origin().y };
coord_t directionV1[2] = { d->partition.direction.x, d->partition.direction.y };
coord_t distToVertex = V2d_PointLineParaDistance(pointV1, directionV1,
d->para, d->length);
coord_t distToVertex = intersect(lineSeg, edge);

d->intercepts.append(Intercept(distToVertex, const_cast<LineSegment::Side &>(lineSeg), edge));
Intercept *newIntercept = &d->intercepts.last();

newIntercept->selfRef = lineSeg.sectorPtr() == lineSeg.back().sectorPtr(); //(lineSeg.hasMapSide() && lineSeg.mapLine().isSelfReferencing());

newIntercept->before = openSectorAtAngle(edgeTips, inverseAngle());
newIntercept->after = openSectorAtAngle(edgeTips, angle());
newIntercept->front = openSectorAtAngle(edgeTips, angle());
newIntercept->back = openSectorAtAngle(edgeTips, inverseAngle());

// The addition of a new intercept means we'll need to resort.
d->needSortIntercepts = true;
Expand All @@ -257,20 +263,20 @@ static void mergeIntercepts(HPlane::Intercept &final,

if(final.selfRef && !other.selfRef)
{
if(final.before && other.before)
final.before = other.before;
if(final.back && other.back)
final.back = other.back;

if(final.after && other.after)
final.after = other.after;
if(final.front && other.front)
final.front = other.front;

final.selfRef = false;
}

if(!final.before && other.before)
final.before = other.before;
if(!final.back && other.back)
final.back = other.back;

if(!final.after && other.after)
final.after = other.after;
if(!final.front && other.front)
final.front = other.front;

/*
LOG_TRACE("Result:");
Expand Down Expand Up @@ -317,18 +323,6 @@ void HPlane::sortAndMergeIntercepts()
d->needSortIntercepts = false;
}

#ifdef DENG_DEBUG
void HPlane::printIntercepts() const
{
uint index = 0;
foreach(Intercept const &icpt, d->intercepts)
{
LOG_DEBUG(" %u: >%1.2f ") << (index++) << icpt.distance();
icpt.debugPrint();
}
}
#endif

Partition const &HPlane::partition() const
{
return d->partition;
Expand All @@ -344,9 +338,9 @@ slopetype_t HPlane::slopeType() const
return d->slopeType;
}

Line *HPlane::mapLine() const
LineSegment::Side *HPlane::lineSegment() const
{
return d->mapLine;
return d->lineSegment;
}

void HPlane::distance(LineSegment::Side const &lineSeg, coord_t *fromDist, coord_t *toDist) const
Expand All @@ -358,7 +352,8 @@ void HPlane::distance(LineSegment::Side const &lineSeg, coord_t *fromDist, coord
/// 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->mapLine != 0 && d->mapLine == lineSeg.partitionMapLine())
if(d->lineSegment != 0 &&
&d->lineSegment->mapSide().line() == lineSeg.partitionMapLine())
{
if(fromDist) *fromDist = 0;
if(toDist) *toDist = 0;
Expand Down Expand Up @@ -398,5 +393,17 @@ HPlane::Intercepts const &HPlane::intercepts() const
return d->intercepts;
}

#ifdef DENG_DEBUG
void HPlane::printIntercepts() const
{
uint index = 0;
foreach(Intercept const &icpt, d->intercepts)
{
LOG_DEBUG(" %u: >%1.2f ") << (index++) << icpt.distance();
icpt.debugPrint();
}
}
#endif

} // namespace bsp
} // namespace de

0 comments on commit 8921204

Please sign in to comment.