CadQuery / cadquery

A python parametric CAD scripting framework based on OCCT
https://cadquery.readthedocs.io
Other
2.98k stars 281 forks source link

Binary operations of 2D shapes? #1009

Closed TeddyMori closed 2 years ago

TeddyMori commented 2 years ago

I want to do something like:

shape1 = cq.Workplane('XY').pushPoints([(-10, 0). (10, 0)]).circle(15)
shape2 = cq.Workplane('XY').pushPoints([(-10, 10), (10, 10)]).circle(15)
shape1.union(shape2)

To create a a union-ed 2D shape, which isn't possible because I get the following error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/tmp/ipykernel_16486/391630060.py in <module>
      6 shape1 = cq.Workplane('XY').pushPoints(coords).circle(11)
      7 shape2 = cq.Workplane('XY').pushPoints([(-10, 10), (10, 10)]).circle(11)
----> 8 shape1.union(shape2)

/mnt/chromeos/MyFiles/repos/cadquery/cadquery/cq.py in union(self, toUnion, clean, glue, tol)
   3278             newS = cast(List[Shape], toUnion.solids().vals())
   3279             if len(newS) < 1:
-> 3280                 raise ValueError(
   3281                     "Workplane object must have at least one solid on the stack to union!"
   3282                 )

ValueError: Workplane object must have at least one solid on the stack to union!

It seems like not being able to perform binary operations on 2D shapes was intentional? What is the best way to do these sort of operations? Right now I basically extrude the shapes then perform a subtraction, union, etc. then grab the 2D shape with .faces(">Z"), but this seems kinda wonky.

lorenzncode commented 2 years ago

Take a look at Sketch. It provides many features for 2D!

import cadquery as cq

s1 = cq.Sketch().push([(-10, 0), (10, 0)]).circle(15).clean()
s2 = cq.Sketch().push([(-10, 10), (10, 10)]).circle(20).clean()

r = cq.Workplane().placeSketch(s1, s2).extrude(1)
TeddyMori commented 2 years ago

I swear I tried it and had problems but your code seems to work.

one last request and I guess this can be closed, but using the sketch API, any advice on adding a fillet on the intersection of the two circles?

The following code doesn't add any fillet, docs suggest calling reset after creating the circle but that results in an exception.

s2 = cq.Sketch().push([(-10, 10), (10, 10)]).circle(20).vertices().fillet(.25).clean()
r = cq.Workplane().placeSketch(s1).extrude(10)
lorenzncode commented 2 years ago
import cadquery as cq

s = (
    cq.Sketch()
    .push([(-10, 10), (10, 10)])
    .circle(20)
    .clean()
    .reset()
    .vertices()
    .fillet(5)
)

r = cq.Workplane().placeSketch(s).extrude(10)

I'm still learning Sketch usage but I think the above is similar to what you are looking for. clean is required to create the vertices for selection. Call reset before selecting vertices to reset selection (clear circle locations).

TeddyMori commented 2 years ago

That worked, seems to fail if the circles do not intersect though, probably because it's trying to fillet the one vert in the independent circles?

s = (
    cq.Sketch()
    .push([(0,10). (0,0), (0,100)])
    .circle(12)
    .clean()
    .reset()
    .vertices()
    .fillet(1)
)

r = cq.Workplane().placeSketch(s).extrude(5) # StdFail_NotDone: BRep_API: command not done

Probably for a different issue, this one has had its scope move far enough at this point.

Nokimann commented 2 years ago

@lorenzncode @TeddyMori

For exporting in 2D dxf format, It seems that using extrude(#) gives an error when loading in other software. Solved with faces('<Z') after extrude(#)!

s1 = cq.Sketch().push([(-4, 0), (4, 0)]).circle(5).clean()
s2 = cq.Sketch().push([(-4, 8), (4, 8)]).circle(5).clean()
s3 = cq.Sketch().push([(0, 16)]).circle(3).clean()

r = cq.Workplane().placeSketch(s1, s2, s3).extrude(1)
r = r.faces('<Z')

cq.exporters.export(r, 'r.dxf')