CadQuery / cadquery

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

Offset2D of circle changes Z-plane #896

Open MarSik opened 3 years ago

MarSik commented 3 years ago

I am trying to make two concentric circles on the top face of a box for further extrusion. However this code produces two circles with the right offset, but in different Z planes.

r = cq.Workplane("XY")
r = r.box(1,1,1)
r = r.faces(">Z")
r = r.circle(0.75)
r = r.tag("c")

r = r.offset2D(0.1)
show_object(r)

r = r.wires(tag="c")
show_object(r)

offset

I found a similar issue in FreeCAD (https://tracker.freecadweb.org/view.php?id=3020) and it seems they had to manipulate the location before executing the offset2d operation: https://github.com/FreeCAD/FreeCAD/commit/dbc09e3a2342af8784045d3d0ae3565ec869bef6

MarSik commented 3 years ago

This could be related to issue #753

MarSik commented 3 years ago

I would just like to add that this works fine with a rectangle:

r = cq.Workplane("XY")
r = r.box(1,1,1)
r = r.faces(">Z")
r = r.rect(0.75, 0.75)
r = r.tag("c")

r = r.offset2D(0.1)
show_object(r)

r = r.wires(tag="c")
show_object(r)

offset-rect

adam-urbanczyk commented 3 years ago

Confirmed

voneiden commented 2 years ago

Spotted this issue from a HN thread where users were desperately trying to dig out reasons to justify keep using OpenSCAD.

Any idea if this issue exists on OpenCASCADE bug tracker? I can't find a matching one.

@adam-urbanczyk should I implement a similar workaround as in FreeCAD? Something like

  1. (Optional I think?) Apply the trick only on wires with a single edge
  2. Store the original wire.wrapped.Location()
  3. Reset the original wire.wrapped.Location to TopLoc_Location()
  4. Apply BRepOffsetAPI_MakeOffset
  5. Restore Location to the original wire and the resulting shape(s)

Also just to document this somewhere online, I poked at the Inversion trick pointed out by Chris_G in the FreeCAD thread.

Mildly interestingly the trick needs to be applied only to the location of C2, subsequent C3 and C4 end up right where they should.

from cadquery import cq

box = cq.Workplane("XY").box(1, 1, 1)

c1 = box.faces(">Y").workplane().circle(0.75)
c1_loc = c1.objects[0].wrapped.Location().Inverted()

c2 = c1.offset2D(0.1)
# Workaround bug 896
c2.objects[0].wrapped.Location(c1_loc)

c3 = c2.offset2D(0.1)
c4 = c3.offset2D(0.1)

show_object(box, 'box')
show_object(c1, 'c1')
show_object(c2, 'c2')
show_object(c3, 'c3')
show_object(c4, 'c4')
voneiden commented 2 years ago

OCCT 7.6.0 has two commits that touch the circle offsetting algorithm. The latter one sounds promising.

https://github.com/Open-Cascade-SAS/OCCT/commit/7e187d6b22e782161450fbf09c5c7563faaecc66

https://github.com/Open-Cascade-SAS/OCCT/commit/55b5d19bd8d1a1803be5d53055d03db50e5af64d

Edit: Since afaik OCCT 7.6.0 is gonna land into CQ pretty soon best to just see if this this gets resolved.

adam-urbanczyk commented 2 years ago

Yes, there is a branch for 7.6 already https://github.com/CadQuery/cadquery/tree/occt7.6

voneiden commented 1 year ago

Replicates still in 7.7.0