diff --git a/src/offset.cc b/src/offset.cc index 08705907..d54da806 100644 --- a/src/offset.cc +++ b/src/offset.cc @@ -54,7 +54,7 @@ AbstractNode *OffsetModule::instantiate(const Context *ctx, const ModuleInstanti OffsetNode *node = new OffsetNode(inst); AssignmentList args; - args += Assignment("delta"); + args += Assignment("r"); Context c(ctx); c.setVariables(args, evalctx); @@ -64,30 +64,25 @@ AbstractNode *OffsetModule::instantiate(const Context *ctx, const ModuleInstanti node->fs = c.lookup_variable("$fs")->toDouble(); node->fa = c.lookup_variable("$fa")->toDouble(); - ValuePtr delta = c.lookup_variable("delta"); + // default with no argument at all is round / delta = 1 + // radius takes precedence if both r and delta are given. node->delta = 1; - delta->getDouble(node->delta); + node->chamfer = false; + node->join_type = ClipperLib::jtRound; + const ValuePtr r = c.lookup_variable("r", true); + const ValuePtr delta = c.lookup_variable("delta", true); + const ValuePtr chamfer = c.lookup_variable("chamfer", true); - ValuePtr miter_limit = c.lookup_variable("miter_limit", true); - node->miter_limit = 2; - miter_limit->getDouble(node->miter_limit); - - ValuePtr join_type = c.lookup_variable("join_type", true); - if (join_type->type() == Value::STRING) { - std::string jt = join_type->toString(); - if (std::string("bevel") == jt) { - node->join_type = ClipperLib::jtSquare; - } else if (std::string("round") == jt) { - node->join_type = ClipperLib::jtRound; - } else if (std::string("miter") == jt) { - node->join_type = ClipperLib::jtMiter; - } else { - PRINTB("WARNING: Unknown join_type for offset(): '%s'", jt); - } - - if ((node->join_type != ClipperLib::jtMiter) && !miter_limit->isUndefined()) { - PRINTB("WARNING: miter_limit is ignored in offset() for join_type: '%s'", jt); - } + if (r->isDefinedAs(Value::NUMBER)) { + r->getDouble(node->delta); + } else if (delta->isDefinedAs(Value::NUMBER)) { + delta->getDouble(node->delta); + + node->join_type = ClipperLib::jtMiter; + if (chamfer->isDefinedAs(Value::BOOL) && chamfer->toBool()) { + node->chamfer = true; + node->join_type = ClipperLib::jtSquare; + } } std::vector instantiatednodes = inst->instantiateChildren(evalctx); @@ -100,21 +95,17 @@ std::string OffsetNode::toString() const { std::stringstream stream; - stream << this->name() - << "(delta = " << std::dec << this->delta - << ", join_type = \"" - << (this->join_type == ClipperLib::jtSquare - ? "bevel" - : this->join_type == ClipperLib::jtRound - ? "round" - : "miter") << "\""; - if (this->join_type == ClipperLib::jtMiter) { - stream << ", miter_limit = " << this->miter_limit; + bool isRadius = this->join_type == ClipperLib::jtRound; + const char *var = isRadius ? "(r = " : "(delta = "; + + stream << this->name() << var << std::dec << this->delta; + if (!isRadius) { + stream << ", chamfer = " << (this->chamfer ? "true" : "false"); } stream << ", $fn = " << this->fn << ", $fa = " << this->fa << ", $fs = " << this->fs << ")"; - + return stream.str(); } diff --git a/src/offsetnode.h b/src/offsetnode.h index be651903..d8981fd4 100644 --- a/src/offsetnode.h +++ b/src/offsetnode.h @@ -8,13 +8,15 @@ class OffsetNode : public AbstractPolyNode { public: - OffsetNode(const ModuleInstantiation *mi) : AbstractPolyNode(mi), fn(0), fs(0), fa(0), delta(1), miter_limit(2.0), join_type(ClipperLib::jtMiter) { } + OffsetNode(const ModuleInstantiation *mi) : AbstractPolyNode(mi), fn(0), fs(0), fa(0), delta(1), miter_limit(1000000.0), join_type(ClipperLib::jtRound) { } virtual Response accept(class State &state, Visitor &visitor) const { return visitor.visit(state, *this); } virtual std::string toString() const; virtual std::string name() const { return "offset"; } - double fn, fs, fa, delta, miter_limit; + bool chamfer; + double fn, fs, fa, delta; + double miter_limit; // currently fixed high value to disable chamfers with jtMiter ClipperLib::JoinType join_type; }; diff --git a/src/value.cc b/src/value.cc index d3eea01a..4723b611 100644 --- a/src/value.cc +++ b/src/value.cc @@ -130,9 +130,19 @@ Value::ValueType Value::type() const return static_cast(this->value.which()); } +bool Value::isDefined() const +{ + return this->type() != UNDEFINED; +} + +bool Value::isDefinedAs(const ValueType type) const +{ + return this->type() == type; +} + bool Value::isUndefined() const { - return this->type() == UNDEFINED; + return !isDefined(); } bool Value::toBool() const diff --git a/src/value.h b/src/value.h index e3822309..63b57ce6 100644 --- a/src/value.h +++ b/src/value.h @@ -117,6 +117,8 @@ public: ~Value() {} ValueType type() const; + bool isDefined() const; + bool isDefinedAs(const ValueType type) const; bool isUndefined() const; double toDouble() const; diff --git a/testdata/scad/2D/features/offset-tests.scad b/testdata/scad/2D/features/offset-tests.scad index 06855c64..9148b26a 100644 --- a/testdata/scad/2D/features/offset-tests.scad +++ b/testdata/scad/2D/features/offset-tests.scad @@ -1,46 +1,55 @@ - -module shape1(x, y) { - translate([50 * x, 50 * y]) difference() { - square([30, 30], center = true); - square([8, 8], center = true); - } +module m(x, y) { + translate(60 * [x, y]) children(); } -module shape2(x, y) { - translate([50 * x, 50 * y]) { - polygon(points=[ - [-15, 80],[15, 80],[0,-15],[-8, 60],[8, 60],[0, 5] - ], paths=[ - [0,1,2],[3,4,5] - ]); - } +module shape1(w = 20) { + difference() { + square([ w, w], center = true); + square([10, 10], center = true); + } } -offset(delta = -1, join_type = "miter") shape2(-1, 2); -shape2(0, 2); -offset(delta = 1, join_type = "miter") shape2(1, 2); +module shape2() { + polygon(points=[ + [-15, 80],[15, 80],[0,-15],[-8, 60],[8, 60],[0, 5] + ], paths=[ + [0,1,2],[3,4,5] + ]); +} -offset(delta = -1, join_type = "miter", miter_limit = 10) shape2(2, 2); -offset(delta = 1, join_type = "miter", miter_limit = 10) shape2(3, 2); +m(-1, 0) shape1(); +m(-1, 2) shape2(); -offset(delta = -1, join_type = "bevel") shape2(2, -1); -offset(delta = 1, join_type = "bevel") shape2(3, -1); +m(0, 0) offset() shape1(); +m(0, 1) offset(5) shape1(); +m(0, 2) offset(5) shape2(); -offset(delta = -5, join_type = "round") shape1(-1, 1); -shape1(0, 1); -offset(delta = 5, join_type = "round") shape1(1, 1); +m(1, 0) offset(r = 1) shape1(30); +m(1, 1) offset(r = 5) shape1(30); +m(1, 2) offset(r = 5) shape2(); -offset(-4) shape1(-1, 0); -shape1(0, 0); -offset(4) shape1(1, 0); +m(2, 0) offset(r = -5) shape1(40); +m(2, 1) offset(r = -10.01) shape1(50); +m(2, 2) offset(r = -1) shape2(); -offset(delta = -5) shape1(2, 1); -shape1(0, -1); -offset(delta = 5) shape1(1, -1); +m(3, 0) offset(delta = 4) shape1(); +m(3, 1) offset(delta = 1) shape1(); +m(3, 2) offset(delta = 5) shape2(); + +m(4, 0) offset(delta = -2) shape1(30); +m(4, 1) offset(delta = -5) shape1(40); +m(4, 2) offset(delta = -1) shape2(); + +m(5, 0) offset(delta = 4, chamfer = true) shape1(); +m(5, 1) offset(delta = 1, chamfer = true) shape1(); +m(5, 2) offset(delta = 5, chamfer = true) shape2(); + +m(6, 0) offset(delta = -2, chamfer = true) shape1(30); +m(6, 1) offset(delta = -5, chamfer = true) shape1(40); +m(6, 2) offset(delta = -1, chamfer = true) shape2(); // Bug with fragment calculateion with delta < 1 due to abs() instead of std::abs() -translate([-50,-50]) scale([25,25,1]) - offset(delta = 0.9, join_type="round") square(.1); +m(-2, 1) scale([30, 30]) offset(r = 0.8) square(1); // Malformed offsets offset(); diff --git a/tests/regression/cgalpngtest/offset-tests-expected.png b/tests/regression/cgalpngtest/offset-tests-expected.png index c1f667be..fbcd7248 100644 Binary files a/tests/regression/cgalpngtest/offset-tests-expected.png and b/tests/regression/cgalpngtest/offset-tests-expected.png differ diff --git a/tests/regression/dumptest-examples/offset-expected.csg b/tests/regression/dumptest-examples/offset-expected.csg index 41de8cc3..5c640f8e 100644 --- a/tests/regression/dumptest-examples/offset-expected.csg +++ b/tests/regression/dumptest-examples/offset-expected.csg @@ -1,7 +1,7 @@ group() { group(); linear_extrude(height = 20, center = false, convexity = 1, scale = [0.5, 0.5], $fn = 40, $fa = 12, $fs = 2) { - offset(delta = 10, join_type = "round", $fn = 40, $fa = 12, $fs = 2) { + offset(r = 10, $fn = 40, $fa = 12, $fs = 2) { square(size = [50, 50], center = true); } } @@ -9,12 +9,12 @@ group() { linear_extrude(height = 20, center = false, convexity = 1, scale = [1, 1], $fn = 40, $fa = 12, $fs = 2) { group() { difference() { - offset(delta = 1, join_type = "miter", miter_limit = 2, $fn = 40, $fa = 12, $fs = 2) { + offset(r = 1, $fn = 40, $fa = 12, $fs = 2) { group() { circle($fn = 40, $fa = 12, $fs = 2, r = 15); } } - offset(delta = -1, join_type = "miter", miter_limit = 2, $fn = 40, $fa = 12, $fs = 2) { + offset(r = -1, $fn = 40, $fa = 12, $fs = 2) { group() { circle($fn = 40, $fa = 12, $fs = 2, r = 15); } diff --git a/tests/regression/dumptest/allmodules-expected.csg b/tests/regression/dumptest/allmodules-expected.csg index 653ca751..9af5da4b 100644 --- a/tests/regression/dumptest/allmodules-expected.csg +++ b/tests/regression/dumptest/allmodules-expected.csg @@ -39,6 +39,6 @@ group() { multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]); multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]); color([-1, -1, -1, 1]); - offset(delta = 1, join_type = "miter", miter_limit = 2, $fn = 0, $fa = 12, $fs = 2); + offset(r = 1, $fn = 0, $fa = 12, $fs = 2); text(text = "", size = 10, spacing = 1, font = "", direction = "ltr", language = "en", script = "latin", halign = "left", valign = "baseline", $fn = 0, $fa = 12, $fs = 2); } diff --git a/tests/regression/dumptest/offset-tests-expected.csg b/tests/regression/dumptest/offset-tests-expected.csg index 3f3888ee..39617983 100644 --- a/tests/regression/dumptest/offset-tests-expected.csg +++ b/tests/regression/dumptest/offset-tests-expected.csg @@ -1,144 +1,311 @@ group() { - offset(delta = -1, join_type = "miter", miter_limit = 2, $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, -50], [0, 1, 0, 100], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); - } - } - } group() { - multmatrix([[1, 0, 0, 0], [0, 1, 0, 100], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); - } - } - offset(delta = 1, join_type = "miter", miter_limit = 2, $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, 50], [0, 1, 0, 100], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); - } - } - } - offset(delta = -1, join_type = "miter", miter_limit = 10, $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, 100], [0, 1, 0, 100], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); - } - } - } - offset(delta = 1, join_type = "miter", miter_limit = 10, $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, 150], [0, 1, 0, 100], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); - } - } - } - offset(delta = -1, join_type = "bevel", $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, 100], [0, 1, 0, -50], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); - } - } - } - offset(delta = 1, join_type = "bevel", $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, 150], [0, 1, 0, -50], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); - } - } - } - offset(delta = -5, join_type = "round", $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, -50], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) { - difference() { - square(size = [30, 30], center = true); - square(size = [8, 8], center = true); + multmatrix([[1, 0, 0, -60], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + group() { + difference() { + square(size = [20, 20], center = true); + square(size = [10, 10], center = true); + } } } } } group() { - multmatrix([[1, 0, 0, 0], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) { - difference() { - square(size = [30, 30], center = true); - square(size = [8, 8], center = true); - } - } - } - offset(delta = 5, join_type = "round", $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, 50], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) { - difference() { - square(size = [30, 30], center = true); - square(size = [8, 8], center = true); - } - } - } - } - offset(delta = -4, join_type = "miter", miter_limit = 2, $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, -50], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - difference() { - square(size = [30, 30], center = true); - square(size = [8, 8], center = true); + multmatrix([[1, 0, 0, -60], [0, 1, 0, 120], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + group() { + polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); } } } } group() { multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - difference() { - square(size = [30, 30], center = true); - square(size = [8, 8], center = true); - } - } - } - offset(delta = 4, join_type = "miter", miter_limit = 2, $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, 50], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - difference() { - square(size = [30, 30], center = true); - square(size = [8, 8], center = true); - } - } - } - } - offset(delta = -5, join_type = "miter", miter_limit = 2, $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, 100], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) { - difference() { - square(size = [30, 30], center = true); - square(size = [8, 8], center = true); + group() { + offset(r = 1, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [20, 20], center = true); + square(size = [10, 10], center = true); + } + } } } } } group() { - multmatrix([[1, 0, 0, 0], [0, 1, 0, -50], [0, 0, 1, 0], [0, 0, 0, 1]]) { - difference() { - square(size = [30, 30], center = true); - square(size = [8, 8], center = true); - } - } - } - offset(delta = 5, join_type = "miter", miter_limit = 2, $fn = 0, $fa = 12, $fs = 2) { - group() { - multmatrix([[1, 0, 0, 50], [0, 1, 0, -50], [0, 0, 1, 0], [0, 0, 0, 1]]) { - difference() { - square(size = [30, 30], center = true); - square(size = [8, 8], center = true); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(r = 5, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [20, 20], center = true); + square(size = [10, 10], center = true); + } + } } } } } - multmatrix([[1, 0, 0, -50], [0, 1, 0, -50], [0, 0, 1, 0], [0, 0, 0, 1]]) { - multmatrix([[25, 0, 0, 0], [0, 25, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - offset(delta = 0.9, join_type = "round", $fn = 0, $fa = 12, $fs = 2) { - square(size = [0.1, 0.1], center = false); + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 120], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(r = 5, $fn = 0, $fa = 12, $fs = 2) { + group() { + polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); + } + } } } } - offset(delta = 1, join_type = "miter", miter_limit = 2, $fn = 0, $fa = 12, $fs = 2); - offset(delta = 1, join_type = "miter", miter_limit = 2, $fn = 0, $fa = 12, $fs = 2) { + group() { + multmatrix([[1, 0, 0, 60], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(r = 1, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [30, 30], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 60], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(r = 5, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [30, 30], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 60], [0, 1, 0, 120], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(r = 5, $fn = 0, $fa = 12, $fs = 2) { + group() { + polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 120], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(r = -5, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [40, 40], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 120], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(r = -10.01, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [50, 50], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 120], [0, 1, 0, 120], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(r = -1, $fn = 0, $fa = 12, $fs = 2) { + group() { + polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 180], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = 4, chamfer = false, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [20, 20], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 180], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = 1, chamfer = false, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [20, 20], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 180], [0, 1, 0, 120], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = 5, chamfer = false, $fn = 0, $fa = 12, $fs = 2) { + group() { + polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 240], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = -2, chamfer = false, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [30, 30], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 240], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = -5, chamfer = false, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [40, 40], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 240], [0, 1, 0, 120], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = -1, chamfer = false, $fn = 0, $fa = 12, $fs = 2) { + group() { + polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 300], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = 4, chamfer = true, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [20, 20], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 300], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = 1, chamfer = true, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [20, 20], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 300], [0, 1, 0, 120], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = 5, chamfer = true, $fn = 0, $fa = 12, $fs = 2) { + group() { + polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 360], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = -2, chamfer = true, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [30, 30], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 360], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = -5, chamfer = true, $fn = 0, $fa = 12, $fs = 2) { + group() { + difference() { + square(size = [40, 40], center = true); + square(size = [10, 10], center = true); + } + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, 360], [0, 1, 0, 120], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + offset(delta = -1, chamfer = true, $fn = 0, $fa = 12, $fs = 2) { + group() { + polygon(points = [[-15, 80], [15, 80], [0, -15], [-8, 60], [8, 60], [0, 5]], paths = [[0, 1, 2], [3, 4, 5]], convexity = 1); + } + } + } + } + } + group() { + multmatrix([[1, 0, 0, -120], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + multmatrix([[30, 0, 0, 0], [0, 30, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + offset(r = 0.8, $fn = 0, $fa = 12, $fs = 2) { + square(size = [1, 1], center = false); + } + } + } + } + } + offset(r = 1, $fn = 0, $fa = 12, $fs = 2); + offset(r = 1, $fn = 0, $fa = 12, $fs = 2) { square(size = [0, 0], center = false); } } diff --git a/tests/regression/opencsgtest/offset-tests-expected.png b/tests/regression/opencsgtest/offset-tests-expected.png index ea7eee89..a671a091 100644 Binary files a/tests/regression/opencsgtest/offset-tests-expected.png and b/tests/regression/opencsgtest/offset-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/offset-tests-expected.png b/tests/regression/throwntogethertest/offset-tests-expected.png index 3d6c93a2..cd845049 100644 Binary files a/tests/regression/throwntogethertest/offset-tests-expected.png and b/tests/regression/throwntogethertest/offset-tests-expected.png differ