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

2D offset fails if multiple faces would be created #800

Open
CarpeNecopinum opened this issue Nov 24, 2024 · 2 comments
Open

2D offset fails if multiple faces would be created #800

CarpeNecopinum opened this issue Nov 24, 2024 · 2 comments

Comments

@CarpeNecopinum
Copy link

There are two cases in which offsetting a single face could create multiple resulting faces:

  1. A face with a "choke point" breaks apart due to a negative offset larger than the choke point:
cs = Circle(2) + Pos(3.9, 0) * Circle(2)
cso = offset(cs, -0.5)
# -> RuntimeError: Multiple Wires generated
  1. A face with a hole is cut apart by the whole growing through some thin sections:
f = Rectangle(15, 10) - Circle(4.9)
fo = offset(f, -0.15)
# -> AttributeError: 'Compound' object has no attribute 'normal_at'

both of these currently fail (with different errors)

@CarpeNecopinum
Copy link
Author

CarpeNecopinum commented Nov 24, 2024

My current workaround is

def wireOffset(wire: Wire, dist: float):
    builder = BRepOffsetAPI_MakeOffset()
    builder.Init(GeomAbs_JoinType.GeomAbs_Arc)
    builder.AddWire(wire.wrapped)
    builder.Perform(dist)
    obj = downcast(builder.Shape())
    if isinstance(obj, TopoDS_Compound):
        return Compound(obj).wires()
    elif isinstance(obj, TopoDS_Wire):
        return ShapeList[Wire]([Wire(obj)])
    else:
        raise RuntimeError("Unexpected result type")

def safeOffset(face: Face, dist: float):
    outer = wireOffset(face.wire(), dist)
    inner = [x for i in face.inner_wires() for x in wireOffset(i, -dist) ]
    main = Sketch(Face(wire) for wire in outer)
    if len(inner) > 0:
        return main.cut(*(Face(i) for i in inner))
    return main

which works for both cases (but is otherwise a lot less flexible than the offset part of build123d)

@MarcWeber
Copy link

from OCP.GeomAbs import GeomAbs_JoinType
from OCP.BRepOffsetAPI import BRepOffsetAPI_MakeOffset
from OCP.TopoDS import ( TopoDS_Compound, TopoDS_Wire )

from build123d import ( Wire, ShapeList, Face, Sketch)
from build123d.topology import downcast, Compound

missing imports :-)

Alternative libraries for Python which can do wires and offsets
which build123 could import/export to / from:

  • Inkex (Librarie of Inkscape)
  • svgpathtools
  • shapely

My current case doesn't turn one into 2. But I create code for cadquery once (positive and negative side for paper embossing and eventually hitting a similar case. And using any line art from inkscape gallery likely causes issues as mentioned here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants