Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

offset2D for construction #639

Merged
merged 4 commits into from
Feb 19, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions cadquery/cq.py
Original file line number Diff line number Diff line change
Expand Up @@ -3742,22 +3742,31 @@ 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).
"""

ws = self._consolidateWires()
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
marcus7070 marked this conversation as resolved.
Show resolved Hide resolved

return self.newObject(rv)

Expand Down
76 changes: 72 additions & 4 deletions doc/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
-----------------------------

Expand Down
9 changes: 9 additions & 0 deletions tests/test_cadquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -3887,6 +3887,15 @@ 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)
# make sure the resulting wire has forConstruction set
self.assertEqual(w6.val().forConstruction, True)

def testConsolidateWires(self):

w1 = Workplane().lineTo(0, 1).lineTo(1, 1).consolidateWires()
Expand Down