Sketch clean not working in some cases
I fall on strange issue with clean on sketch, some faces of complexe sketch are not correctly removed. I tried to create a simple test case From svg containing two path, I recreate edges, then face and making union from these two faces. The second face is completly inside the first one. But following the path rotation of the second one (which is 2 arcs for a full circle) the clean function doesn't work
eddddd_ok.svg file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
height="398px"
version="1.1"
viewBox="-0.9757118500000002 31.906598149999994 17.6351237 11.672203700000022"
width="600px"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<path
d="M 5.2941,38.7 8.0133,38.3941 4.3021,35.4 l 0.992,3.3"
fill="#000000"
id="path5" />
<path
d="M 5.3882,37.5328 A 0.35,0.35 0.0 0,0 6.0882,37.5328 A 0.35,0.35 0.0 0,0 5.3882,37.5328"
fill="black"
id="path1207" />
</svg>
eddddd_ko.svg file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
height="398px"
version="1.1"
viewBox="-0.9757118500000002 31.906598149999994 17.6351237 11.672203700000022"
width="600px"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<path
d="M 5.2941,38.7 8.0133,38.3941 4.3021,35.4 l 0.992,3.3"
fill="#000000"
id="path5" />
<path
d="M 5.3882,37.5328 A 0.35,0.35 0.0 0,1 6.0882,37.5328 A 0.35,0.35 0.0 0,1 5.3882,37.5328"
fill="black"
id="path1207" />
</svg>
test.py file:
import numpy as np
import svgpathtools
import cadquery as cq
from typing import Union
from cadquery import Edge, Wire
def euclid_to_tuple(p, dim3=False):
if dim3:
return np.real(p), np.imag(p), 0
else:
return np.real(p), np.imag(p)
def to_wire(path, support: Union[cq.Workplane, cq.Sketch] = cq.Workplane("front"), mode="a"):
def convert(seg):
if isinstance(seg, svgpathtools.Line):
return Edge.makeLine(euclid_to_tuple(seg.start), euclid_to_tuple(seg.end))
elif isinstance(seg, svgpathtools.Arc):
points = euclid_to_tuple(seg.start), euclid_to_tuple(seg.point(0.5)), euclid_to_tuple(seg.end)
return Edge.makeThreePointArc(*points)
else:
raise Exception("Not supported: {0}".format(type(seg)))
edges = [convert(seg) for seg in path]
wires = Wire.combine(edges)
assert len(wires) == 1
wire = wires[0]
ret = support.face(wire, mode=mode)
return ret
for file in ['eddddd_ok.svg', 'eddddd_ko.svg']:
paths, attributes = svgpathtools.svg2paths(file)
sketch = cq.Sketch()
for path in paths:
sketch = to_wire(path, sketch, "a")
sketch = sketch.clean()
r = cq.Workplane("front").placeSketch(sketch).extrude(1, combine=False)
cq.exporters.export(r, file.replace("svg", "step"))
And here the results: https://imgur.com/a/4JZ0p26
The only difference here is: Wire.combine([ Edge.makeThreePointArc((5.3882, 37.5328), (5.7382, 37.1828), (6.0882, 37.5328)) Edge.makeThreePointArc((6.0882, 37.5328), (5.7382, 37.8828), (5.3882, 37.5328))])
vs
Wire.combine([ Edge.makeThreePointArc((5.3882, 37.5328), (5.7382, 37.8828), (6.0882, 37.5328)) Edge.makeThreePointArc((6.0882, 37.5328), (5.7382, 37.1828), (5.3882, 37.5328))])
linked to https://tracker.dev.opencascade.org/view.php?id=30267
Using following function before running clean seems to work
def normalize_faces(sketch):
sketch._faces = Compound.makeCompound([Face(f.wrapped.Reversed()) if f.normalAt().z < 0 else f for f in sketch.faces()])
return sketch