Skip to content

Commit

Permalink
Refactor|BSP Builder|EdgeTips: Cleaned up EdgeTips ahead of removing …
Browse files Browse the repository at this point in the history
…LineOwner rings
  • Loading branch information
danij-deng committed Oct 4, 2013
1 parent 7a44449 commit d260e79
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 80 deletions.
122 changes: 97 additions & 25 deletions doomsday/client/include/world/bsp/edgetip.h
Expand Up @@ -114,63 +114,135 @@ class EdgeTip
};

/**
* Provides an always-sorted EdgeTip data set.
*
* @ingroup bsp
*/
class EdgeTips
{
public:
typedef std::list<EdgeTip> All;

EdgeTips() : _tips(0) {}
/**
* Construct a new edge tip set.
*/
EdgeTips() : _tips(0)
{}

~EdgeTips() { clear(); }
~EdgeTips()
{
clear();
}

bool isEmpty() const { return _tips.empty(); }
/// @see insert()
inline EdgeTips &operator << (EdgeTip const &tip) {
insert(tip);
return *this;
}

/// Clear all tips in the set.
void clear() { _tips.clear(); }
/**
* Returns @c true iff the set contains zero edge tips.
*/
bool isEmpty() const
{
return _tips.empty();
}

/**
* Add a new edge tip to the set in it's rightful place according to
* Insert a copy of @a tip into the set, in it's rightful place according to
* an anti-clockwise (increasing angle) order.
*
* @param angleEpsilon Smallest difference between two angles before being
* considered equal (in degrees).
* @param epsilon Angle equivalence threshold (in degrees).
*/
void insert(EdgeTip const &tip, ddouble epsilon = 1.0 / 1024)
{
Tips::reverse_iterator after = _tips.rbegin();
while(after != _tips.rend() && tip.angle() + epsilon < (*after).angle())
{
after++;
}
_tips.insert(after.base(), tip);
}

/**
* Returns the tip from the set with the smallest angle; otherwise @c 0 if
* the set is empty.
*/
EdgeTip const *smallest() const
{
return _tips.empty()? 0 : &_tips.front();
}

/**
* Returns the tip from the set with the largest angle; otherwise @c 0 if
* the set is empty.
*/
EdgeTip &add(coord_t angle, LineSegment::Side *front = 0, LineSegment::Side *back = 0,
coord_t angleEpsilon = 1.0 / 1024.0)
EdgeTip const *largest() const
{
All::reverse_iterator after;
return _tips.empty()? 0 : &_tips.back();
}

/**
* @param epsilon Angle equivalence threshold (in degrees).
*/
EdgeTip const *at(ddouble angle, ddouble epsilon = 1.0 / 1024) const
{
DENG2_FOR_EACH_CONST(Tips, it, _tips)
{
coord_t delta = de::abs(it->angle() - angle);
if(delta < epsilon || delta > (360.0 - epsilon))
{
return &(*it);
}
}
return 0;
}

for(after = _tips.rbegin();
after != _tips.rend() && angle + angleEpsilon < (*after).angle(); after++)
{}
/**
* @param epsilon Angle equivalence threshold (in degrees).
*/
EdgeTip const *after(ddouble angle, ddouble epsilon = 1.0 / 1024.0) const
{
DENG2_FOR_EACH_CONST(Tips, it, _tips)
{
if(angle + epsilon < it->angle())
{
return &(*it);
}
}
return 0;
}

return *_tips.insert(after.base(), EdgeTip(angle, front, back));
/**
* Clear all tips in the set.
*/
void clear()
{
_tips.clear();
}

/**
* Clear all tips attributed to the specified line segment @a seg.
*/
void clearByLineSegment(LineSegment &seg)
{
All::iterator i = _tips.begin();
while(i != _tips.end())
Tips::iterator it = _tips.begin();
while(it != _tips.end())
{
EdgeTip &tip = *i;
EdgeTip &tip = *it;
if((tip.hasFront() && &tip.front().line() == &seg) ||
(tip.hasBack() && &tip.back().line() == &seg))
{
i = _tips.erase(i);
it = _tips.erase(it);
}
else
{
++i;
++it;
}
}
}

All const &all() const { return _tips; }

private:
All _tips;
typedef std::list<EdgeTip> Tips;
Tips _tips;
};

} // namespace bsp
Expand Down
35 changes: 12 additions & 23 deletions doomsday/client/src/world/bsp/hplane.cpp
Expand Up @@ -224,36 +224,25 @@ void HPlane::configure(LineSegmentSide const &newBaseSeg)
*/
static LineSegmentSide *lineSegAtAngle(EdgeTips const &tips, coord_t angle)
{
DENG_ASSERT(!tips.isEmpty());
// Is there a tip exactly at this angle?
if(tips.at(angle))
return 0; // Closed.

// First check whether there's a wall_tip that lies in the exact
// direction of the given direction (which is relative to the vertex).
DENG2_FOR_EACH_CONST(EdgeTips::All, it, tips.all())
// Find the first tip after (larger) than this angle. If present the side
// we're interested in is the front.
if(EdgeTip const *tip = tips.after(angle))
{
EdgeTip const &tip = *it;
coord_t diff = de::abs(tip.angle() - angle);
if(diff < ANG_EPSILON || diff > (360.0 - ANG_EPSILON))
{
return 0; // Yes, found one.
}
return tip->hasFront()? &tip->front() : 0;
}

// OK, now just find the first wall_tip whose angle is greater than
// the angle we're interested in. Therefore we'll be on the front side
// of that tip edge.
DENG2_FOR_EACH_CONST(EdgeTips::All, it, tips.all())
// The open sector must therefore be on the back of the tip with the largest
// angle (if present).
if(EdgeTip const *tip = tips.largest())
{
EdgeTip const &tip = *it;
if(angle + ANG_EPSILON < tip.angle())
{
return tip.hasFront()? &tip.front() : 0;
}
return tip->hasBack()? &tip->back() : 0;
}

// Not found. The open sector will therefore be on the back of the tip
// at the greatest angle.
EdgeTip const &tip = tips.all().back();
return tip.hasBack()? &tip.back() : 0;
return 0; // No edge tips.
}

double HPlane::intersect(LineSegmentSide const &lineSeg, int edge)
Expand Down
72 changes: 40 additions & 32 deletions doomsday/client/src/world/bsp/partitioner.cpp
Expand Up @@ -134,7 +134,7 @@ DENG2_PIMPL(Partitioner)
/**
* Returns the associated EdgeTips set for the given @a vertex.
*/
EdgeTips &edgeTips(Vertex const &vertex)
EdgeTips &edgeTipSet(Vertex const &vertex)
{
EdgeTipSetMap::iterator found = edgeTipSets.find(const_cast<Vertex *>(&vertex));
if(found == edgeTipSets.end())
Expand Down Expand Up @@ -189,13 +189,14 @@ DENG2_PIMPL(Partitioner)
}

/// @todo edge tips should be created when line segments are created.
edgeTips(line->from()).add(angle,
seg? &seg->front() : 0,
seg && seg->back().hasSector()? &seg->back() : 0);

edgeTips(line->to() ).add(M_InverseAngle(angle),
seg && seg->back().hasSector()? &seg->back() : 0,
seg? &seg->front() : 0);
edgeTipSet(line->from())
<< EdgeTip(angle, seg? &seg->front() : 0,
seg && seg->back().hasSector()? &seg->back() : 0);

edgeTipSet(line->to())
<< EdgeTip(M_InverseAngle(angle),
seg && seg->back().hasSector()? &seg->back() : 0,
seg? &seg->front() : 0);
}
}

Expand Down Expand Up @@ -657,27 +658,31 @@ DENG2_PIMPL(Partitioner)
/**
* @todo Optimize: Avoid clearing tips by implementing update logic.
*/
edgeTips(oldSeg.from()).clearByLineSegment(oldSeg);
edgeTips(oldSeg.to() ).clearByLineSegment(oldSeg);

edgeTips(newSeg.from()).clearByLineSegment(newSeg);
edgeTips(newSeg.to() ).clearByLineSegment(newSeg);

edgeTips(oldSeg.from()).add(oldSeg.front().angle(),
oldSeg.front().hasSector()? &oldSeg.front() : 0,
oldSeg.back().hasSector()? &oldSeg.back() : 0);

edgeTips(oldSeg.to() ).add(oldSeg.back().angle(),
oldSeg.back().hasSector()? &oldSeg.back() : 0,
oldSeg.front().hasSector()? &oldSeg.front() : 0);

edgeTips(newSeg.from()).add(newSeg.front().angle(),
newSeg.front().hasSector()? &newSeg.front() : 0,
newSeg.back().hasSector()? &newSeg.back() : 0);

edgeTips(newSeg.to() ).add(newSeg.back().angle(),
newSeg.back().hasSector()? &newSeg.back() : 0,
newSeg.front().hasSector()? &newSeg.front() : 0);
edgeTipSet(oldSeg.from()).clearByLineSegment(oldSeg);
edgeTipSet(oldSeg.to() ).clearByLineSegment(oldSeg);

edgeTipSet(newSeg.from()).clearByLineSegment(newSeg);
edgeTipSet(newSeg.to() ).clearByLineSegment(newSeg);

edgeTipSet(oldSeg.from())
<< EdgeTip(oldSeg.front().angle(),
oldSeg.front().hasSector()? &oldSeg.front() : 0,
oldSeg.back().hasSector()? &oldSeg.back() : 0);

edgeTipSet(oldSeg.to())
<< EdgeTip(oldSeg.back().angle(),
oldSeg.back().hasSector()? &oldSeg.back() : 0,
oldSeg.front().hasSector()? &oldSeg.front() : 0);

edgeTipSet(newSeg.from())
<< EdgeTip(newSeg.front().angle(),
newSeg.front().hasSector()? &newSeg.front() : 0,
newSeg.back().hasSector()? &newSeg.back() : 0);

edgeTipSet(newSeg.to())
<< EdgeTip(newSeg.back().angle(),
newSeg.back().hasSector()? &newSeg.back() : 0,
newSeg.front().hasSector()? &newSeg.front() : 0);
}

return frontRight;
Expand Down Expand Up @@ -720,7 +725,7 @@ DENG2_PIMPL(Partitioner)
/// @todo refactor away
inline void interceptPartition(LineSegmentSide &seg, int edge)
{
hplane.intercept(seg, edge, edgeTips(seg.vertex(edge)));
hplane.intercept(seg, edge, edgeTipSet(seg.vertex(edge)));
}

/**
Expand Down Expand Up @@ -988,8 +993,11 @@ DENG2_PIMPL(Partitioner)
sector, sector, 0 /*no map line*/,
partSeg? &partSeg->mapLine() : 0);

edgeTips(newSeg.from()).add(newSeg.front().angle(), &newSeg.front(), &newSeg.back());
edgeTips(newSeg.to() ).add(newSeg.back().angle(), &newSeg.back(), &newSeg.front());
edgeTipSet(newSeg.from())
<< EdgeTip(newSeg.front().angle(), &newSeg.front(), &newSeg.back());

edgeTipSet(newSeg.to())
<< EdgeTip(newSeg.back().angle(), &newSeg.back(), &newSeg.front());

// Add each new line segment to the appropriate set.
linkSegmentInSuperBlockmap(rights, newSeg.front());
Expand Down

0 comments on commit d260e79

Please sign in to comment.