Implemented CSG tree pruning - this should significantly improve performance of difficult models in OpenCSG preview mode

felipesanches-svg
Marius Kintel 2011-12-22 04:12:15 +01:00
parent d7ca192077
commit 8d5be2c524
3 changed files with 150 additions and 57 deletions

View File

@ -48,11 +48,11 @@ void CSGTermEvaluator::applyToChildren(const AbstractNode &node, CSGTermEvaluato
t1 = t2;
} else if (t2 && t1) {
if (op == CSGT_UNION) {
t1.reset(new CSGTerm(CSGTerm::TYPE_UNION, t1, t2));
t1 = CSGTerm::createCSGTerm(CSGTerm::TYPE_UNION, t1, t2);
} else if (op == CSGT_DIFFERENCE) {
t1.reset(new CSGTerm(CSGTerm::TYPE_DIFFERENCE, t1, t2));
t1 = CSGTerm::createCSGTerm(CSGTerm::TYPE_DIFFERENCE, t1, t2);
} else if (op == CSGT_INTERSECTION) {
t1.reset(new CSGTerm(CSGTerm::TYPE_INTERSECTION, t1, t2));
t1 = CSGTerm::createCSGTerm(CSGTerm::TYPE_INTERSECTION, t1, t2);
}
}
}

View File

@ -26,6 +26,7 @@
#include "csgterm.h"
#include "polyset.h"
#include "linalg.h"
#include <sstream>
/*!
@ -47,29 +48,102 @@
*/
CSGTerm::CSGTerm(const shared_ptr<PolySet> &polyset, const Transform3d &matrix, const double color[4], const std::string &label)
: type(TYPE_PRIMITIVE), polyset(polyset), label(label)
shared_ptr<CSGTerm> CSGTerm::createCSGTerm(type_e type, shared_ptr<CSGTerm> left, shared_ptr<CSGTerm> right)
{
if (type != TYPE_PRIMITIVE) {
// In case we're creating a CSG terms from a pruned tree, left/right can be NULL
if (!right) {
if (type == TYPE_UNION || type == TYPE_DIFFERENCE) return left;
else return right;
}
if (!left) {
if (type == TYPE_UNION) return right;
else return left;
}
}
// Pruning the tree. For details, see:
// http://www.cc.gatech.edu/~turk/my_papers/pxpl_csg.pdf
const BoundingBox &leftbox = left->getBoundingBox();
const BoundingBox &rightbox = right->getBoundingBox();
if (type == TYPE_INTERSECTION) {
BoundingBox newbox(leftbox.min().cwise().max(rightbox.min()),
leftbox.max().cwise().min(rightbox.max()));
if (newbox.isNull()) {
return shared_ptr<CSGTerm>(); // Prune entire product
}
}
else if (type == TYPE_DIFFERENCE) {
BoundingBox newbox(leftbox.min().cwise().max(rightbox.min()),
leftbox.max().cwise().min(rightbox.max()));
if (newbox.isNull()) {
return left; // Prune the negative component
}
}
return shared_ptr<CSGTerm>(new CSGTerm(type, left, right));
}
shared_ptr<CSGTerm> CSGTerm::createCSGTerm(type_e type, CSGTerm *left, CSGTerm *right)
{
return createCSGTerm(type, shared_ptr<CSGTerm>(left), shared_ptr<CSGTerm>(right));
}
CSGTerm::CSGTerm(const shared_ptr<PolySet> &polyset, const Transform3d &matrix, const double color[4], const std::string &label)
: type(TYPE_PRIMITIVE), polyset(polyset), label(label), m(matrix)
{
this->m = matrix;
for (int i = 0; i < 4; i++) this->color[i] = color[i];
initBoundingBox();
}
CSGTerm::CSGTerm(type_e type, shared_ptr<CSGTerm> left, shared_ptr<CSGTerm> right)
: type(type), left(left), right(right)
: type(type), left(left), right(right), m(Transform3d::Identity())
{
initBoundingBox();
}
CSGTerm::CSGTerm(type_e type, CSGTerm *left, CSGTerm *right)
: type(type), left(left), right(right)
: type(type), left(left), right(right), m(Transform3d::Identity())
{
initBoundingBox();
}
CSGTerm::~CSGTerm()
{
}
void CSGTerm::initBoundingBox()
{
if (this->type == TYPE_PRIMITIVE) {
BoundingBox polybox = this->polyset->getBoundingBox();
this->bbox.extend(this->m * polybox.min());
this->bbox.extend(this->m * polybox.max());
}
else {
const BoundingBox &leftbox = this->left->getBoundingBox();
const BoundingBox &rightbox = this->right->getBoundingBox();
switch (this->type) {
case TYPE_UNION:
this->bbox.extend(this->m * leftbox.min().cwise().min(rightbox.min()));
this->bbox.extend(this->m * leftbox.max().cwise().max(rightbox.max()));
break;
case TYPE_INTERSECTION:
this->bbox.extend(this->m * leftbox.min().cwise().max(rightbox.min()));
this->bbox.extend(this->m * leftbox.max().cwise().min(rightbox.max()));
break;
case TYPE_DIFFERENCE:
this->bbox.extend(this->m * leftbox.min());
this->bbox.extend(this->m * leftbox.max());
break;
case TYPE_PRIMITIVE:
break;
default:
assert(false);
}
}
}
shared_ptr<CSGTerm> CSGTerm::normalize(shared_ptr<CSGTerm> &term)
shared_ptr<CSGTerm> CSGTerm::normalize(shared_ptr<CSGTerm> term)
{
// This function implements the CSG normalization
// Reference:
@ -79,27 +153,34 @@ shared_ptr<CSGTerm> CSGTerm::normalize(shared_ptr<CSGTerm> &term)
// 1989.
// http://www.cc.gatech.edu/~turk/my_papers/pxpl_csg.pdf
if (term->type == TYPE_PRIMITIVE) return term;
if (term->type == TYPE_PRIMITIVE) {
return term;
}
// FIXME: We can optimize the normalized tree by pruning based on bounding boxes
// as described in the above mentioned paper:
// 1) If the bounding boxes of two intersected nodes don't intersect, prune the
// intersection node
// 2) If the bounding boxes of two subtracted nodes don't intersect, replace the
// difference node with the positive operator
do {
while (normalize_tail(term)) {}
normalize(term->left);
while (term && normalize_tail(term)) { }
if (!term || term->type == TYPE_PRIMITIVE) return term;
term->left = normalize(term->left);
} while (term->type != TYPE_UNION &&
(term->right->type != TYPE_PRIMITIVE || term->left->type == TYPE_UNION));
normalize(term->right);
term->right = normalize(term->right);
// FIXME: Do we need to take into account any transformation of item here?
if (!term->right) {
if (term->type == TYPE_UNION || term->type == TYPE_DIFFERENCE) return term->left;
else return term->right;
}
if (!term->left) {
if (term->type == TYPE_UNION) return term->right;
else return term->left;
}
return term;
}
bool CSGTerm::normalize_tail(shared_ptr<CSGTerm> &term)
{
if (term->type == TYPE_UNION) return false; // Don't normalize outer union
if (term->type == TYPE_UNION || term->type == TYPE_PRIMITIVE) return false;
// Part A: The 'x . (y . z)' expressions
@ -107,46 +188,48 @@ bool CSGTerm::normalize_tail(shared_ptr<CSGTerm> &term)
shared_ptr<CSGTerm> y = term->right->left;
shared_ptr<CSGTerm> z = term->right->right;
CSGTerm *result = NULL;
shared_ptr<CSGTerm> result = term;
// 1. x - (y + z) -> (x - y) - z
if (term->type == TYPE_DIFFERENCE && term->right->type == TYPE_UNION) {
result = new CSGTerm(TYPE_DIFFERENCE,
shared_ptr<CSGTerm>(new CSGTerm(TYPE_DIFFERENCE, x, y)),
term = createCSGTerm(TYPE_DIFFERENCE,
createCSGTerm(TYPE_DIFFERENCE, x, y),
z);
return true;
}
// 2. x * (y + z) -> (x * y) + (x * z)
else if (term->type == TYPE_INTERSECTION && term->right->type == TYPE_UNION) {
result = new CSGTerm(TYPE_UNION,
new CSGTerm(TYPE_INTERSECTION, x, y),
new CSGTerm(TYPE_INTERSECTION, x, z));
term = createCSGTerm(TYPE_UNION,
createCSGTerm(TYPE_INTERSECTION, x, y),
createCSGTerm(TYPE_INTERSECTION, x, z));
return true;
}
// 3. x - (y * z) -> (x - y) + (x - z)
else if (term->type == TYPE_DIFFERENCE && term->right->type == TYPE_INTERSECTION) {
result = new CSGTerm(TYPE_UNION,
new CSGTerm(TYPE_DIFFERENCE, x, y),
new CSGTerm(TYPE_DIFFERENCE, x, z));
term = createCSGTerm(TYPE_UNION,
createCSGTerm(TYPE_DIFFERENCE, x, y),
createCSGTerm(TYPE_DIFFERENCE, x, z));
return true;
}
// 4. x * (y * z) -> (x * y) * z
else if (term->type == TYPE_INTERSECTION && term->right->type == TYPE_INTERSECTION) {
result = new CSGTerm(TYPE_INTERSECTION,
shared_ptr<CSGTerm>(new CSGTerm(TYPE_INTERSECTION, x, y)),
term = createCSGTerm(TYPE_INTERSECTION,
createCSGTerm(TYPE_INTERSECTION, x, y),
z);
return true;
}
// 5. x - (y - z) -> (x - y) + (x * z)
else if (term->type == TYPE_DIFFERENCE && term->right->type == TYPE_DIFFERENCE) {
result = new CSGTerm(TYPE_UNION,
new CSGTerm(TYPE_DIFFERENCE, x, y),
new CSGTerm(TYPE_INTERSECTION, x, z));
term = createCSGTerm(TYPE_UNION,
createCSGTerm(TYPE_DIFFERENCE, x, y),
createCSGTerm(TYPE_INTERSECTION, x, z));
return true;
}
// 6. x * (y - z) -> (x * y) - z
else if (term->type == TYPE_INTERSECTION && term->right->type == TYPE_DIFFERENCE) {
result = new CSGTerm(TYPE_DIFFERENCE,
shared_ptr<CSGTerm>(new CSGTerm(TYPE_INTERSECTION, x, y)),
term = createCSGTerm(TYPE_DIFFERENCE,
createCSGTerm(TYPE_INTERSECTION, x, y),
z);
}
if (result) {
term.reset(result);
return true;
}
@ -158,28 +241,26 @@ bool CSGTerm::normalize_tail(shared_ptr<CSGTerm> &term)
// 7. (x - y) * z -> (x * z) - y
if (term->left->type == TYPE_DIFFERENCE && term->type == TYPE_INTERSECTION) {
result = new CSGTerm(TYPE_DIFFERENCE,
shared_ptr<CSGTerm>(new CSGTerm(TYPE_INTERSECTION, x, z)),
term = createCSGTerm(TYPE_DIFFERENCE,
createCSGTerm(TYPE_INTERSECTION, x, z),
y);
return true;
}
// 8. (x + y) - z -> (x - z) + (y - z)
else if (term->left->type == TYPE_UNION && term->type == TYPE_DIFFERENCE) {
result = new CSGTerm(TYPE_UNION,
new CSGTerm(TYPE_DIFFERENCE, x, z),
new CSGTerm(TYPE_DIFFERENCE, y, z));
term = createCSGTerm(TYPE_UNION,
createCSGTerm(TYPE_DIFFERENCE, x, z),
createCSGTerm(TYPE_DIFFERENCE, y, z));
return true;
}
// 9. (x + y) * z -> (x * z) + (y * z)
else if (term->left->type == TYPE_UNION && term->type == TYPE_INTERSECTION) {
result = new CSGTerm(TYPE_UNION,
new CSGTerm(TYPE_INTERSECTION, x, z),
new CSGTerm(TYPE_INTERSECTION, y, z));
}
if (result) {
term.reset(result);
term = createCSGTerm(TYPE_UNION,
createCSGTerm(TYPE_INTERSECTION, x, z),
createCSGTerm(TYPE_INTERSECTION, y, z));
return true;
}
return false;
}

View File

@ -18,23 +18,35 @@ public:
TYPE_DIFFERENCE
};
static shared_ptr<CSGTerm> createCSGTerm(type_e type, shared_ptr<CSGTerm> left, shared_ptr<CSGTerm> right);
static shared_ptr<CSGTerm> createCSGTerm(type_e type, CSGTerm *left, CSGTerm *right);
type_e type;
shared_ptr<PolySet> polyset;
std::string label;
shared_ptr<CSGTerm> left;
shared_ptr<CSGTerm> right;
Transform3d m;
double color[4];
BoundingBox bbox;
CSGTerm(const shared_ptr<PolySet> &polyset, const Transform3d &matrix, const double color[4], const std::string &label);
CSGTerm(type_e type, shared_ptr<CSGTerm> left, shared_ptr<CSGTerm> right);
CSGTerm(type_e type, CSGTerm *left, CSGTerm *right);
~CSGTerm();
static shared_ptr<CSGTerm> normalize(shared_ptr<CSGTerm> &term);
const BoundingBox &getBoundingBox() const { return this->bbox; }
static shared_ptr<CSGTerm> normalize(shared_ptr<CSGTerm> term);
static bool normalize_tail(shared_ptr<CSGTerm> &term);
std::string dump();
private:
CSGTerm(type_e type, shared_ptr<CSGTerm> left, shared_ptr<CSGTerm> right);
CSGTerm(type_e type, CSGTerm *left, CSGTerm *right);
void initBoundingBox();
Transform3d m;
double color[4];
friend class CSGChain;
};
class CSGChain