Loading src/csg/levelset_3d.cpp +14 −2 Original line number Diff line number Diff line Loading @@ -145,10 +145,22 @@ double signed_distance_3d(const LinearExtrude &lin_ext, double xx, double yy, double signed_distance_3d(const RotateExtrude &rot_ext, double xx, double yy, double zz) { // TODO: support angle double tt = atan(yy / xx) * 180 / M_PI; if ((xx < 0 && yy >= 0) || (xx < 0 && yy < 0)) tt += 180; // Quadrants II & III else if (xx >= 0 && yy < 0) tt += 360; // Quadrant IV double sign_t = (tt >= 0 && tt <= rot_ext.angle) ? -1.0 : 1.0; double dist_t = std::min(std::fabs(rot_ext.angle - tt), std::fabs(360 - tt)); auto XX = std::hypot(xx, yy); auto YY = zz; return signed_distance_2d(rot_ext.group, XX, YY); auto sd_2d = signed_distance_2d(rot_ext.group, XX, YY); double sign_2d = sd_2d >= 0 ? -1.0 : 1.0; auto dist_2d = std::fabs(sd_2d); return EXTERNAL_FLOW * std::max(sign_t * dist_t, sign_2d * dist_2d); } double signed_distance_3d(const Polyhedron &polyhedron, double xx, double yy, Loading src/csg/parser.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -468,6 +468,12 @@ template <> struct action<extrude_rot> { auto &curr_attr = st.curr_attrs.back(); rot_ext.angle = std::get<double>(curr_attr["angle"]); if (rot_ext.angle < 0 || rot_ext.angle > 360) { throw csg::Exception("action<extrude_rot>", "angle=" + std::to_string(rot_ext.angle) + "; must be between 0 and 360!"); } for (const auto &curr_obj : st.current_2d_group) { rot_ext.group.objs.push_back(curr_obj); } Loading src/csg/tests/levelset/extrude.t.cpp +35 −1 Original line number Diff line number Diff line Loading @@ -133,7 +133,7 @@ TEST_CASE("two shape linear extrude", "[Levelset Extrude]") { } TEST_CASE("simple torus", "[Levelset Extrude]") { auto my_rot_ext = csg::RotateExtrude(); auto my_rot_ext = csg::RotateExtrude{.angle = 360, .group = csg::Union2D()}; csg::Circle my_cir{.name = std::nullopt, .radius = 1}; auto my_mat = csg::Mulmatrix2D({{1, 0}}, {{0, 1}}); Loading Loading @@ -245,4 +245,38 @@ TEST_CASE("Linear extrude of a triangle with hole", "[Levelset Primitives]") { } } TEST_CASE("sliced torus", "[Levelset Extrude]") { auto my_rot_ext = csg::RotateExtrude{.angle = 45, .group = csg::Union2D()}; csg::Circle my_cir{.name = std::nullopt, .radius = 1}; auto my_mat = csg::Mulmatrix2D({{1, 0}}, {{0, 1}}); my_mat.translation = {2, 0}; my_mat.group.objs.push_back(my_cir); my_rot_ext.group.objs.push_back(my_mat); auto my_tree = std::make_shared<csg::Tree>(); my_tree->top.objs.push_back(my_rot_ext); csg::CsgIF my_levelset(my_tree); SECTION("Outside") { CHECK_FALSE(0 < my_levelset(0, 0, 0)); CHECK_FALSE(0 < my_levelset(0.9, 0, 0)); CHECK_FALSE(0 < my_levelset(-0.9, 0, 0)); CHECK_FALSE(0 < my_levelset(2, 0, 1.1)); CHECK_FALSE(0 < my_levelset(-2, 0, -1.1)); CHECK_FALSE(0 < my_levelset(2, -0.01, 0)); CHECK_FALSE(0 < my_levelset(1.5, 1.6, 0.9)); CHECK_FALSE(0 < my_levelset(-1.1, 0.0, 0)); CHECK_FALSE(0 < my_levelset(1.5, 1.6, -0.5)); CHECK_FALSE(0 < my_levelset(-2, 0.0, -0.9)); } SECTION("Inside") { CHECK(0 < my_levelset(2, 0.01, 0)); CHECK(0 < my_levelset(1.1, 0.01, 0)); CHECK(0 < my_levelset(2, 0.01, 0.9)); CHECK(0 < my_levelset(1.5, 1.4, 0.9)); CHECK(0 < my_levelset(1.5, 1.4, -0.5)); } } } // namespace src/csg/tests/parser/extrude.t.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,17 @@ angle = 90 CHECK(yy == 3); } TEST_CASE("rotate extrude with bad angle", "[csg]") { CHECK_THROWS_WITH(csg::parse_csg(R"( rotate_extrude( angle = 370 ) { square(size = [2, 3], center = false); } )"), Catch::Contains("action<extrude_rot>")); } TEST_CASE("extrude two shapes", "[csg]") { auto st = *csg::parse_csg(R"( linear_extrude( Loading Loading
src/csg/levelset_3d.cpp +14 −2 Original line number Diff line number Diff line Loading @@ -145,10 +145,22 @@ double signed_distance_3d(const LinearExtrude &lin_ext, double xx, double yy, double signed_distance_3d(const RotateExtrude &rot_ext, double xx, double yy, double zz) { // TODO: support angle double tt = atan(yy / xx) * 180 / M_PI; if ((xx < 0 && yy >= 0) || (xx < 0 && yy < 0)) tt += 180; // Quadrants II & III else if (xx >= 0 && yy < 0) tt += 360; // Quadrant IV double sign_t = (tt >= 0 && tt <= rot_ext.angle) ? -1.0 : 1.0; double dist_t = std::min(std::fabs(rot_ext.angle - tt), std::fabs(360 - tt)); auto XX = std::hypot(xx, yy); auto YY = zz; return signed_distance_2d(rot_ext.group, XX, YY); auto sd_2d = signed_distance_2d(rot_ext.group, XX, YY); double sign_2d = sd_2d >= 0 ? -1.0 : 1.0; auto dist_2d = std::fabs(sd_2d); return EXTERNAL_FLOW * std::max(sign_t * dist_t, sign_2d * dist_2d); } double signed_distance_3d(const Polyhedron &polyhedron, double xx, double yy, Loading
src/csg/parser.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -468,6 +468,12 @@ template <> struct action<extrude_rot> { auto &curr_attr = st.curr_attrs.back(); rot_ext.angle = std::get<double>(curr_attr["angle"]); if (rot_ext.angle < 0 || rot_ext.angle > 360) { throw csg::Exception("action<extrude_rot>", "angle=" + std::to_string(rot_ext.angle) + "; must be between 0 and 360!"); } for (const auto &curr_obj : st.current_2d_group) { rot_ext.group.objs.push_back(curr_obj); } Loading
src/csg/tests/levelset/extrude.t.cpp +35 −1 Original line number Diff line number Diff line Loading @@ -133,7 +133,7 @@ TEST_CASE("two shape linear extrude", "[Levelset Extrude]") { } TEST_CASE("simple torus", "[Levelset Extrude]") { auto my_rot_ext = csg::RotateExtrude(); auto my_rot_ext = csg::RotateExtrude{.angle = 360, .group = csg::Union2D()}; csg::Circle my_cir{.name = std::nullopt, .radius = 1}; auto my_mat = csg::Mulmatrix2D({{1, 0}}, {{0, 1}}); Loading Loading @@ -245,4 +245,38 @@ TEST_CASE("Linear extrude of a triangle with hole", "[Levelset Primitives]") { } } TEST_CASE("sliced torus", "[Levelset Extrude]") { auto my_rot_ext = csg::RotateExtrude{.angle = 45, .group = csg::Union2D()}; csg::Circle my_cir{.name = std::nullopt, .radius = 1}; auto my_mat = csg::Mulmatrix2D({{1, 0}}, {{0, 1}}); my_mat.translation = {2, 0}; my_mat.group.objs.push_back(my_cir); my_rot_ext.group.objs.push_back(my_mat); auto my_tree = std::make_shared<csg::Tree>(); my_tree->top.objs.push_back(my_rot_ext); csg::CsgIF my_levelset(my_tree); SECTION("Outside") { CHECK_FALSE(0 < my_levelset(0, 0, 0)); CHECK_FALSE(0 < my_levelset(0.9, 0, 0)); CHECK_FALSE(0 < my_levelset(-0.9, 0, 0)); CHECK_FALSE(0 < my_levelset(2, 0, 1.1)); CHECK_FALSE(0 < my_levelset(-2, 0, -1.1)); CHECK_FALSE(0 < my_levelset(2, -0.01, 0)); CHECK_FALSE(0 < my_levelset(1.5, 1.6, 0.9)); CHECK_FALSE(0 < my_levelset(-1.1, 0.0, 0)); CHECK_FALSE(0 < my_levelset(1.5, 1.6, -0.5)); CHECK_FALSE(0 < my_levelset(-2, 0.0, -0.9)); } SECTION("Inside") { CHECK(0 < my_levelset(2, 0.01, 0)); CHECK(0 < my_levelset(1.1, 0.01, 0)); CHECK(0 < my_levelset(2, 0.01, 0.9)); CHECK(0 < my_levelset(1.5, 1.4, 0.9)); CHECK(0 < my_levelset(1.5, 1.4, -0.5)); } } } // namespace
src/csg/tests/parser/extrude.t.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,17 @@ angle = 90 CHECK(yy == 3); } TEST_CASE("rotate extrude with bad angle", "[csg]") { CHECK_THROWS_WITH(csg::parse_csg(R"( rotate_extrude( angle = 370 ) { square(size = [2, 3], center = false); } )"), Catch::Contains("action<extrude_rot>")); } TEST_CASE("extrude two shapes", "[csg]") { auto st = *csg::parse_csg(R"( linear_extrude( Loading