Skip to content

Commit

Permalink
[flatten] Refine rules about tree flattening + added test case
Browse files Browse the repository at this point in the history
  • Loading branch information
ochafik committed Mar 16, 2023
1 parent 7cb439c commit 409dd3f
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 13 deletions.
39 changes: 26 additions & 13 deletions src/manifold/src/csg_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,21 +254,34 @@ std::shared_ptr<CsgNode> CsgOpNode::Boolean(
const std::shared_ptr<CsgNode> &second, OpType op) {
std::vector<std::shared_ptr<CsgNode>> children;

auto handleOperand = [&](const std::shared_ptr<CsgNode> &operand) {
if (auto opNode = std::dynamic_pointer_cast<CsgOpNode>(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<CsgOpNode>(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<CsgOpNode>(children, op);
}
Expand Down
28 changes: 28 additions & 0 deletions test/manifold_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 409dd3f

Please sign in to comment.