CadQuery / cadquery

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

DXF importer cannot load wires #1465

Open sam-vdp opened 11 months ago

sam-vdp commented 11 months ago

The DXF importer at cadquery/occ_impl/importers/dxf.py tries to assemble the loaded file into faces and throws an error if this is not successful. It would be nice to be able to load DXF files that contain wires and edges, but no faces.

for name, layer in layers.items():
    if name.lower() in selected:
        res = _dxf_convert(layers[name], tol)
        wire_sets = sortWiresByBuildOrder(res)
        for wire_set in wire_sets:
            faces.append(Face.makeFromWires(wire_set[0], wire_set[1:]))

Removing the last three lines and returning a list of wires is basically sufficient.

adam-urbanczyk commented 11 months ago

That should be doable. Could you provide an example DXF/MRE for testing?

sam-vdp commented 11 months ago

This is the file I was trying to load: dxf_with_lines.zip

As a workaround I patched a dxf wires importer in my construction file like this:

def importDXFWires(filename: str, tol: float = 1e-6, exclude = [], include = []):  

    if exclude and include:
        raise ValueError("you may specify either 'include' or 'exclude' but not both")

    dxf = ezdxf.readfile(filename)
    wires = []

    layers = dxf.modelspace().groupby(dxfattrib="layer")

    # normalize layer names to conform the DXF spec
    names = set([name.lower() for name in layers.keys()])

    if include:
        selected = names & set([name.lower() for name in include])
    elif exclude:
        selected = names - set([name.lower() for name in exclude])
    else:
        selected = names

    if not selected:
        raise ValueError("no DXF layers selected")

    for name, layer in layers.items():
        if name.lower() in selected:
            res = dxf_import._dxf_convert(layers[name], tol)
            wires.extend(res)

    return cq.Workplane("XY").newObject(wires)

cq.importers.importDXFWires = importDXFWires