cadquery icon indicating copy to clipboard operation
cadquery copied to clipboard

Sketch clean not working in some cases

Open diorcety opened this issue 1 year ago • 2 comments

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))])

diorcety avatar Mar 10 '24 18:03 diorcety

linked to https://tracker.dev.opencascade.org/view.php?id=30267

diorcety avatar Mar 11 '24 21:03 diorcety

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

diorcety avatar Mar 11 '24 21:03 diorcety