From 8187ebadfe09ddf1faeac3fd387a1883e975cd6d Mon Sep 17 00:00:00 2001 From: Marcus Boyd Date: Mon, 15 Feb 2021 10:26:29 +1030 Subject: [PATCH 1/3] Added forConstruction option to Workplane.offset2D --- cadquery/cq.py | 19 ++++++++++++++----- tests/test_cadquery.py | 7 +++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/cadquery/cq.py b/cadquery/cq.py index 9659b79a0..63448db71 100644 --- a/cadquery/cq.py +++ b/cadquery/cq.py @@ -3742,14 +3742,18 @@ def toPending(self) -> "Workplane": return self def offset2D( - self, d: float, kind: Literal["arc", "intersection", "tangent"] = "arc" + self, + d: float, + kind: Literal["arc", "intersection", "tangent"] = "arc", + forConstruction: bool = False, ) -> "Workplane": """ Creates a 2D offset wire. - - :param float d: thickness. Negative thickness denotes offset to inside. + + :param d: thickness. Negative thickness denotes offset to inside. :param kind: offset kind. Use "arc" for rounded and "intersection" for sharp edges (default: "arc") - + :param forConstruction: Should the result be added to pending wires? + :return: CQ object with resulting wire(s). """ @@ -3757,7 +3761,12 @@ def offset2D( rv = list(chain.from_iterable(w.offset2D(d, kind) for w in ws)) self.ctx.pendingEdges = [] - self.ctx.pendingWires = rv + if forConstruction: + for wire in rv: + wire.forConstruction = True + self.ctx.pendingWires = [] + else: + self.ctx.pendingWires = rv return self.newObject(rv) diff --git a/tests/test_cadquery.py b/tests/test_cadquery.py index ad0b103bc..49ca72965 100644 --- a/tests/test_cadquery.py +++ b/tests/test_cadquery.py @@ -3887,6 +3887,13 @@ def testOffset2D(self): ) self.assertEqual(s.solids().size(), 4) + # test forConstruction + # forConstruction=True should place results in objects, not ctx.pendingWires + w6 = Workplane().hLine(1).vLine(1).close().offset2D(0.5, forConstruction=True) + self.assertEqual(len(w6.ctx.pendingWires), 0) + self.assertEqual(w6.size(), 1) + self.assertEqual(type(w6.val()), Wire) + def testConsolidateWires(self): w1 = Workplane().lineTo(0, 1).lineTo(1, 1).consolidateWires() From d3d6882bf08f04c8b0d58fb661e8434611700d73 Mon Sep 17 00:00:00 2001 From: Marcus Boyd Date: Mon, 15 Feb 2021 10:28:47 +1030 Subject: [PATCH 2/3] Added Workplane.offset2D example --- doc/examples.rst | 76 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/doc/examples.rst b/doc/examples.rst index ab8dfab64..1552b9745 100644 --- a/doc/examples.rst +++ b/doc/examples.rst @@ -617,17 +617,24 @@ and a circular section. * :py:meth:`Workplane.circle` * :py:meth:`Workplane.rect` -Making Counter-bored and counter-sunk holes +Making Counter-bored and Counter-sunk Holes ---------------------------------------------- Counterbored and countersunk holes are so common that CadQuery creates macros to create them in a single step. -Similar to :py:meth:`Workplane.hole` , these functions operate on a list of points as well as a single point. +Similar to :py:meth:`Workplane.hole`, these functions operate on a list of points as well as a single point. .. cadquery:: - result = (cq.Workplane(cq.Plane.XY()).box(4,2, 0.5).faces(">Z").workplane().rect(3.5, 1.5, forConstruction=True) - .vertices().cboreHole(0.125, 0.25, 0.125, depth=None)) + result = ( + cq.Workplane(cq.Plane.XY()) + .box(4, 2, 0.5) + .faces(">Z") + .workplane() + .rect(3.5, 1.5, forConstruction=True) + .vertices() + .cboreHole(0.125, 0.25, 0.125, depth=None) + ) .. topic:: Api References @@ -644,6 +651,67 @@ Similar to :py:meth:`Workplane.hole` , these functions operate on a list of poin * :py:meth:`Workplane.faces` * :py:meth:`Workplane` +Offsetting wires in 2D +---------------------- + +Two dimensional wires can be transformed with :py:meth:`Workplane.offset2D`. They can be offset +inwards or outwards, and with different techniques for extending the corners. + +.. cadquery:: + + original = cq.Workplane().polygon(5, 10).extrude(0.1).translate((0, 0, 2)) + arc = ( + cq.Workplane() + .polygon(5, 10) + .offset2D(1, "arc") + .extrude(0.1) + .translate((0, 0, 1)) + ) + intersection = cq.Workplane().polygon(5, 10).offset2D(1, "intersection").extrude(0.1) + result = original.add(arc).add(intersection) + + +Using the forConstruction argument you can do the common task of offsetting a series of bolt holes +from the outline of an object. Here is the counterbore example from above but with the bolt holes +offset from the edges. + +.. cadquery:: + + result = ( + cq.Workplane() + .box(4, 2, 0.5) + .faces(">Z") + .edges() + .toPending() + .offset2D(-0.25, forConstruction=True) + .vertices() + .cboreHole(0.125, 0.25, 0.125, depth=None) + ) + + +Note that :py:meth:`Workplane.edges` is for selecting objects. It does not add the selected edges to +pending edges in the modelling context, because this would result in your next extrusion including +everything you had only selected in addition to the lines you had drawn. To specify you want these +edges to be used in :py:meth:`Workplane.offset2D`, you call :py:meth:`Workplane.toPending` to +explicitly put them in the list of pending edges. + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.offset2D` **!** + * :py:meth:`Workplane.cboreHole` + * :py:meth:`Workplane.cskHole` + * :py:meth:`Workplane.box` + * :py:meth:`Workplane.polygon` + * :py:meth:`Workplane.workplane` + * :py:meth:`Workplane.vertices` + * :py:meth:`Workplane.edges` + * :py:meth:`Workplane.faces` + * :py:meth:`Workplane` + + Rounding Corners with Fillet ----------------------------- From fc6fe7e87a81164cee57da725691508643c24258 Mon Sep 17 00:00:00 2001 From: Marcus Boyd Date: Mon, 15 Feb 2021 10:49:17 +1030 Subject: [PATCH 3/3] Additional test for offset2d --- tests/test_cadquery.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_cadquery.py b/tests/test_cadquery.py index 49ca72965..5145fe67d 100644 --- a/tests/test_cadquery.py +++ b/tests/test_cadquery.py @@ -3893,6 +3893,8 @@ def testOffset2D(self): self.assertEqual(len(w6.ctx.pendingWires), 0) self.assertEqual(w6.size(), 1) self.assertEqual(type(w6.val()), Wire) + # make sure the resulting wire has forConstruction set + self.assertEqual(w6.val().forConstruction, True) def testConsolidateWires(self):