Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BSP Builder|ConvexSubspace: Added ConvexSubspace
Will assume responsibility for analyzing the partitioned segments and assigning them to "continuity" groups for geometry construction.
- Loading branch information
1 parent
9f34606
commit 5b5c3e2
Showing
4 changed files
with
386 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/** @file map/bsp/convexsubspace.h BSP Builder Convex Subspace. | ||
* | ||
* @authors Copyright © 2013 Daniel Swanson <danij@dengine.net> | ||
* | ||
* @par License | ||
* GPL: http://www.gnu.org/licenses/gpl.html | ||
* | ||
* <small>This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by the | ||
* Free Software Foundation; either version 2 of the License, or (at your | ||
* option) any later version. This program is distributed in the hope that it | ||
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty | ||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
* Public License for more details. You should have received a copy of the GNU | ||
* General Public License along with this program; if not, write to the Free | ||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
* 02110-1301 USA</small> | ||
*/ | ||
|
||
#ifndef DENG_WORLD_MAP_BSP_CONVEXSUBSPACE | ||
#define DENG_WORLD_MAP_BSP_CONVEXSUBSPACE | ||
|
||
#include <QSet> | ||
|
||
#include <de/Error> | ||
|
||
#include "map/bsp/linesegment.h" | ||
|
||
class BspLeaf; | ||
class Sector; | ||
|
||
namespace de { | ||
namespace bsp { | ||
|
||
/** | ||
* Models a @em logical convex subspace in the partition plane, providing the | ||
* analysis functionality necessary to classify and then separate the segments | ||
* into unique geometries. | ||
* | ||
* Here infinity (i.e., a subspace containing no segments) is considered to be | ||
* convex. Accordingly any segments linked to the subspace are @em not "owned" | ||
* by it. | ||
* | ||
* @note Important: It is the user's responsibility to ensure convexity else | ||
* many of the operations on the set of segments will be illogical. | ||
* | ||
* @ingroup bsp | ||
*/ | ||
class ConvexSubspace | ||
{ | ||
/// The set of line segments. | ||
typedef QSet<LineSegment::Side *> Segments; | ||
|
||
public: | ||
/** | ||
* Construct an empty convex subspace. | ||
*/ | ||
ConvexSubspace(); | ||
|
||
/** | ||
* Construct a convex subspace from a list of line @a segments. | ||
* | ||
* @param segments List of line segments which are assumed to define a | ||
* convex subspace in the plane. Ownership of the segments | ||
* is @em NOT given to the subspace. Note that duplicates | ||
* are pruned automatically. | ||
*/ | ||
ConvexSubspace(QList<LineSegment::Side *> const &segments); | ||
|
||
ConvexSubspace(ConvexSubspace const &other); | ||
|
||
/** | ||
* Add more line segments to the subspace. It is assumed that the new set | ||
* conforms to, or is compatible with the subspace. | ||
* | ||
* @param segments List of line segments to add to the subspace. Ownership | ||
* of the segments is @em NOT given to the subspace. Note | ||
* that duplicates or any which are already present are | ||
* pruned automatically. | ||
*/ | ||
void addSegments(QList<LineSegment::Side *> const &segments); | ||
|
||
/** | ||
* Add a single line segment to the subspace which is assumed to conform to, | ||
* or is compatible with the subspace. | ||
* | ||
* @param segment Line segment to add. Ownership is @em NOT given to the | ||
* subspace. Note that if the segment is already present in | ||
* the set it will be pruned (nothing will happen). | ||
*/ | ||
void addOneSegment(LineSegment::Side const &segment); | ||
|
||
/** | ||
* Determines from the set of line segments which set to attribute to any | ||
* BSP leaf we might subsequently produce for them. | ||
* | ||
* This choice is determined with a heuristic accounting of the number of | ||
* references to each candidate sector. References are divided into groups | ||
* according to the "type" of the referencing line segment for rating. | ||
*/ | ||
Sector *chooseSectorForBspLeaf() const; | ||
|
||
/** | ||
* The BspLeaf to which the subspace has been attributed. May return @c 0 | ||
* if not attributed. | ||
*/ | ||
BspLeaf *bspLeaf() const; | ||
|
||
/** | ||
* Change the BspLeaf to which the subspace is attributed. | ||
* | ||
* @param newBspLeaf BSP leaf to attribute (ownership is not affected). | ||
* Can be @c 0 (to clear the attribution). | ||
*/ | ||
void setBspLeaf(BspLeaf *newBspLeaf); | ||
|
||
/** | ||
* Provides access to the set line segments for efficient traversal. | ||
*/ | ||
Segments const &segments() const; | ||
|
||
private: | ||
DENG2_PRIVATE(d) | ||
}; | ||
|
||
} // namespace bsp | ||
} // namespace de | ||
|
||
#endif // DENG_WORLD_MAP_BSP_CONVEXSUBSPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
/** @file map/bsp/convexsubspace.cpp BSP Builder Convex Subspace. | ||
* | ||
* @authors Copyright © 2013 Daniel Swanson <danij@dengine.net> | ||
* | ||
* @par License | ||
* GPL: http://www.gnu.org/licenses/gpl.html | ||
* | ||
* <small>This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by the | ||
* Free Software Foundation; either version 2 of the License, or (at your | ||
* option) any later version. This program is distributed in the hope that it | ||
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty | ||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
* Public License for more details. You should have received a copy of the GNU | ||
* General Public License along with this program; if not, write to the Free | ||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
* 02110-1301 USA</small> | ||
*/ | ||
|
||
#include <QHash> | ||
|
||
#include "Line" | ||
#include "Sector" | ||
#include "map/bsp/linesegment.h" | ||
|
||
#include "render/r_main.h" /// validCount @todo Remove me | ||
|
||
#include "map/bsp/convexsubspace.h" | ||
|
||
namespace de { | ||
namespace bsp { | ||
|
||
/** | ||
* Represents a choice of sector for BSP leaf attribution. | ||
*/ | ||
struct Choice | ||
{ | ||
/// The sector choice. | ||
Sector *sector; | ||
|
||
/// Number of referencing line segments of each type: | ||
int norm; | ||
int part; | ||
int self; | ||
|
||
Choice(Sector §or) | ||
: sector(§or), norm(0), part(0), self(0) | ||
{} | ||
|
||
/** | ||
* Perform heuristic comparison between two choices to determine | ||
* a preference order. The algorithm used weights the two choices | ||
* according to the number and "type" of the referencing line | ||
* segments. | ||
* | ||
* @return @c true if "this" choice is rated better than @a other. | ||
*/ | ||
bool operator < (Choice const &other) const | ||
{ | ||
if(norm == other.norm) | ||
{ | ||
if(part == other.part) | ||
{ | ||
if(self == other.self) | ||
{ | ||
// All equal; use the unique indices to stablize. | ||
return sector->indexInMap() < other.sector->indexInMap(); | ||
} | ||
return self > other.self; | ||
} | ||
return part > other.part; | ||
} | ||
return norm > other.norm; | ||
} | ||
|
||
/** | ||
* Account for a new line segment which references this choice. | ||
* Consider collinear segments only once. | ||
*/ | ||
void account(LineSegment::Side &seg) | ||
{ | ||
// Determine the type of reference and increment the count. | ||
if(!seg.hasMapSide()) | ||
{ | ||
Line *mapLine = seg.partitionMapLine(); | ||
if(mapLine && mapLine->validCount() == validCount) | ||
return; | ||
|
||
part += 1; | ||
|
||
if(mapLine) | ||
mapLine->setValidCount(validCount); | ||
} | ||
else | ||
{ | ||
if(seg.mapLine().validCount() == validCount) | ||
return; | ||
|
||
if(seg.mapLine().isSelfReferencing()) | ||
{ | ||
self += 1; | ||
} | ||
else | ||
{ | ||
norm += 1; | ||
} | ||
|
||
seg.mapLine().setValidCount(validCount); | ||
} | ||
} | ||
}; | ||
typedef QHash<Sector *, Choice> ChoiceHash; | ||
|
||
DENG2_PIMPL_NOREF(ConvexSubspace) | ||
{ | ||
/// The set of line segments. | ||
Segments segments; | ||
|
||
/// Chosen map sector for this subspace (if any). | ||
Sector *sector; | ||
|
||
/// Set to @c true when should to rethink our chosen sector. | ||
bool needChooseSector; | ||
|
||
/// BSP leaf attributed to the subspace (if any). | ||
BspLeaf *bspLeaf; | ||
|
||
Instance() | ||
: sector(0), | ||
needChooseSector(true), | ||
bspLeaf(0) | ||
{} | ||
|
||
Instance(Instance const &other) | ||
: de::IPrivate(), | ||
segments (other.segments), | ||
sector (other.sector), | ||
needChooseSector(other.needChooseSector), | ||
bspLeaf (other.bspLeaf) | ||
{} | ||
|
||
void chooseSector() | ||
{ | ||
sector = 0; | ||
|
||
// We will consider collinear segments only once. | ||
validCount++; | ||
|
||
ChoiceHash candidates; | ||
foreach(LineSegment::Side *seg, segments) | ||
{ | ||
// Segments with no sector can't help us. | ||
if(!seg->hasSector()) continue; | ||
|
||
Sector *cand = seg->sectorPtr(); | ||
|
||
// Is this a new choice? | ||
ChoiceHash::iterator found = candidates.find(cand); | ||
if(found == candidates.end()) | ||
{ | ||
// Yes, record it. | ||
found = candidates.insert(sector, Choice(*cand)); | ||
} | ||
|
||
// Account for a new segment referencing this sector. | ||
found.value().account(*seg); | ||
} | ||
|
||
if(candidates.isEmpty()) return; // Eeek! | ||
|
||
// Sort our choices such that our preferred sector appears first. This | ||
// shouldn't take too long, typically there is no more than two or three | ||
// to choose from. | ||
QList<Choice> sortedCandidates = candidates.values(); | ||
qSort(sortedCandidates.begin(), sortedCandidates.end()); | ||
|
||
// We'll choose the highest rated choice. | ||
sector = sortedCandidates.first().sector; | ||
|
||
needChooseSector = false; | ||
} | ||
|
||
private: | ||
Instance &operator = (Instance const &); // no assignment | ||
}; | ||
|
||
ConvexSubspace::ConvexSubspace() | ||
: d(new Instance()) | ||
{} | ||
|
||
ConvexSubspace::ConvexSubspace(QList<LineSegment::Side *> const &segments) | ||
: d(new Instance()) | ||
{ | ||
addSegments(segments); | ||
} | ||
|
||
ConvexSubspace::ConvexSubspace(ConvexSubspace const &other) | ||
: d(new Instance(*other.d)) | ||
{} | ||
|
||
void ConvexSubspace::addSegments(QList<LineSegment::Side *> const &segments) | ||
{ | ||
int sizeBefore = d->segments.size(); | ||
|
||
d->segments.unite(segments.toSet()); | ||
|
||
if(d->segments.size() != sizeBefore) | ||
{ | ||
// We'll need to rethink our sector choice. | ||
d->needChooseSector = true; | ||
} | ||
} | ||
|
||
void ConvexSubspace::addOneSegment(LineSegment::Side const &segment) | ||
{ | ||
int sizeBefore = d->segments.size(); | ||
|
||
d->segments.insert(const_cast<LineSegment::Side *>(&segment)); | ||
|
||
if(d->segments.size() != sizeBefore) | ||
{ | ||
// We'll need to rethink our sector choice. | ||
d->needChooseSector = true; | ||
} | ||
} | ||
|
||
Sector *ConvexSubspace::chooseSectorForBspLeaf() const | ||
{ | ||
// Do we need to rethink our choice? | ||
if(d->needChooseSector) | ||
{ | ||
d->chooseSector(); | ||
} | ||
return d->sector; | ||
} | ||
|
||
BspLeaf *ConvexSubspace::bspLeaf() const | ||
{ | ||
return d->bspLeaf; | ||
} | ||
|
||
void ConvexSubspace::setBspLeaf(BspLeaf *newBspLeaf) | ||
{ | ||
d->bspLeaf = newBspLeaf; | ||
} | ||
|
||
ConvexSubspace::Segments const &ConvexSubspace::segments() const | ||
{ | ||
return d->segments; | ||
} | ||
|
||
} // namespace bsp | ||
} // namespace de |
Oops, something went wrong.