From 409dd3fe9d2fec0185e123edef568cfb3f9f947d Mon Sep 17 00:00:00 2001 From: ochafik Date: Thu, 16 Mar 2023 03:41:09 +0000 Subject: [PATCH] [flatten] Refine rules about tree flattening + added test case --- src/manifold/src/csg_tree.cpp | 39 +++++++++++++++++++++++------------ test/manifold_test.cpp | 28 +++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/src/manifold/src/csg_tree.cpp b/src/manifold/src/csg_tree.cpp index cf94ddb60..07796ce83 100644 --- a/src/manifold/src/csg_tree.cpp +++ b/src/manifold/src/csg_tree.cpp @@ -254,21 +254,34 @@ std::shared_ptr CsgOpNode::Boolean( const std::shared_ptr &second, OpType op) { std::vector> children; - auto handleOperand = [&](const std::shared_ptr &operand) { - if (auto opNode = std::dynamic_pointer_cast(operand)) { - if ((opNode->IsOp(op) || - (op == OpType::Subtract && opNode->IsOp(OpType::Add))) && - opNode->impl_.UseCount() == 1) { - for (auto &child : opNode->GetChildren(/* forceToLeafNodes= */ false)) { - children.push_back(child); - } - return; - } + if (IsOp(op) && (impl_.UseCount() == 1)) { + auto impl = impl_.GetGuard(); + std::copy(impl->children_.begin(), impl->children_.end(), + std::back_inserter(children)); + } else { + children.push_back(shared_from_this()); + } + + auto secondOp = std::dynamic_pointer_cast(second); + auto canInlineSecondOp = [&]() { + switch (op) { + case OpType::Add: + case OpType::Intersect: + return secondOp->IsOp(op); + case OpType::Subtract: + return secondOp->IsOp(OpType::Add); + default: + return false; } - children.push_back(operand); }; - handleOperand(shared_from_this()); - handleOperand(second); + + if (secondOp && (secondOp->impl_.UseCount() == 1) && canInlineSecondOp()) { + auto secondImpl = secondOp->impl_.GetGuard(); + std::copy(secondImpl->children_.begin(), secondImpl->children_.end(), + std::back_inserter(children)); + } else { + children.push_back(second); + } return std::make_shared(children, op); } diff --git a/test/manifold_test.cpp b/test/manifold_test.cpp index 52a8135bb..f00f3a8e5 100644 --- a/test/manifold_test.cpp +++ b/test/manifold_test.cpp @@ -505,3 +505,31 @@ TEST(Manifold, MirrorUnion) { EXPECT_FLOAT_EQ(vol_a * 2.75, result.GetProperties().volume); EXPECT_TRUE(a.Mirror(glm::vec3(0)).IsEmpty()); } + +TEST(Manifold, BooleanVolumes) { + glm::mat4 m = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f)); + + // Define solids which volumes are easy to compute w/ bit arithmetics: + // m1, m2, m4 are unique, non intersecting "bits" (of volume 1, 2, 4) + // m3 = m1 + m2 + // m7 = m1 + m2 + m3 + auto m1 = Manifold::Cube({1, 1, 1}); + auto m2 = Manifold::Cube({2, 1, 1}).Transform( + glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 0, 0))); + auto m4 = Manifold::Cube({4, 1, 1}).Transform( + glm::translate(glm::mat4(1.0f), glm::vec3(3.0f, 0, 0))); + auto m3 = Manifold::Cube({3, 1, 1}); + auto m7 = Manifold::Cube({7, 1, 1}); + + EXPECT_FLOAT_EQ((m1 ^ m2).GetProperties().volume, 0); + EXPECT_FLOAT_EQ((m1 + m2 + m4).GetProperties().volume, 7); + EXPECT_FLOAT_EQ((m1 + m2 - m4).GetProperties().volume, 3); + EXPECT_FLOAT_EQ((m1 + (m2 ^ m4)).GetProperties().volume, 1); + EXPECT_FLOAT_EQ((m7 ^ m4).GetProperties().volume, 4); + EXPECT_FLOAT_EQ((m7 ^ m3 ^ m1).GetProperties().volume, 1); + EXPECT_FLOAT_EQ((m7 ^ (m1 + m2)).GetProperties().volume, 3); + EXPECT_FLOAT_EQ((m7 - m4).GetProperties().volume, 3); + EXPECT_FLOAT_EQ((m7 - m4 - m2).GetProperties().volume, 1); + EXPECT_FLOAT_EQ((m7 - (m7 - m1)).GetProperties().volume, 1); + EXPECT_FLOAT_EQ((m7 - (m1 + m2)).GetProperties().volume, 4); +}