diff options
author | Marius Kintel <marius@kintel.net> | 2011-12-22 03:12:15 (GMT) |
---|---|---|
committer | Marius Kintel <marius@kintel.net> | 2011-12-22 03:12:15 (GMT) |
commit | 8d5be2c5247f806fb3ec9c9a197ae97b5d565dc7 (patch) | |
tree | 154a4c2a15a52e99cdd82e181db3b6298a7ad44b /src/csgterm.cc | |
parent | d7ca192077f127a2d05bed73d1814a8045823335 (diff) |
Implemented CSG tree pruning - this should significantly improve performance of difficult models in OpenCSG preview mode
Diffstat (limited to 'src/csgterm.cc')
-rw-r--r-- | src/csgterm.cc | 177 |
1 files changed, 129 insertions, 48 deletions
diff --git a/src/csgterm.cc b/src/csgterm.cc index 1b9cb1d..426adca 100644 --- a/src/csgterm.cc +++ b/src/csgterm.cc @@ -26,6 +26,7 @@ #include "csgterm.h" #include "polyset.h" +#include "linalg.h" #include <sstream> /*! @@ -47,29 +48,102 @@ */ +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) + : 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; } |