summaryrefslogtreecommitdiff
path: root/src/csgterm.cc
diff options
context:
space:
mode:
authorMarius Kintel <marius@kintel.net>2011-12-22 03:12:15 (GMT)
committerMarius Kintel <marius@kintel.net>2011-12-22 03:12:15 (GMT)
commit8d5be2c5247f806fb3ec9c9a197ae97b5d565dc7 (patch)
tree154a4c2a15a52e99cdd82e181db3b6298a7ad44b /src/csgterm.cc
parentd7ca192077f127a2d05bed73d1814a8045823335 (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.cc177
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;
}
contact: Jan Huwald // Impressum