Skip to content

Geometry.from_dxf can only ever import one shape #246

Open
@mfeif

Description

@mfeif

Describe the bug
When importing shapes from a clean/well-formed DXF file, only one shape is ever found.

To Reproduce
Steps to reproduce the behaviour:

  1. Import shapes with Geometry.from_dxf()
  2. Notice that only one shape exists

Expected behaviour
When working with a clean/well-formed DXF file, .from_dxf() should be able to import multiple shapes for analysis.

Additional context
I have a clean DXF file with some closed polylines in it, and all other entities purged/removed. I can import this DXF into shapely. I can also import this file into the cad_to_shapely shim. In both cases, the multiple-shape geometry is preserved.

However, when I do the same via Geometry.from_dxf() only one shape ever comes back. Digging deeper into the code in from_dxf I found this:

my_dxf = c2s.dxf.DxfImporter(dxf_filepath)
my_dxf.process()
my_dxf.cleanup()

polygons = my_dxf.polygons
new_polygons = c2s.utils.find_holes(polygons)
if isinstance(new_polygons, MultiPolygon):
    return CompoundGeometry(new_polygons)
elif isinstance(new_polygons, Polygon):
    return Geometry(new_polygons)
else:
    print(f"No shapely.Polygon objects found in file: {dxf_filepath}")

Looking into find_holes, we find that this behavior is by design:

def find_holes(polygons : List[sg.Polygon]) -> sg.Polygon:
    """
    Construct single polygon from imported CAD goemetry. 
    Assumes there is only one parent shape (the one with the largest gross area.)
    Access external perimeter with *polygon.exterior*
    Access holes perimeter(s, if there are any) with *polygon.interiors*
    Returns:
        Shapely Polygon with holes 
    """
    for p in polygons:
        if p.interiors:
            return p

    #sort by areas, largest first.
    polygons.sort(key=lambda x: x.area, reverse=True)
    parent = polygons.pop(0)

    keepers = []
    for p in polygons:
        if p.within(parent):
            valid = True
            for q in polygons:
                if (p.intersects(q) or p.within(q)) and p is not q:
                    valid = False
           
            if valid: keepers.append(p)


    new = sg.Polygon(parent,holes=keepers)
    return new

So by using this utility function, sectionproperties can never support more than one shape in a DXF. This is not a "bug" in cad_to_shapely, per-se, as its the desired behavior, but by using this utility function, we're throwing out data.

I went through the analogous process by hand, NOT throwing out polygons and manually made a CompoundGeometry object, and it worked:

from cad_to_shapely.dxf import DxfImporter
from shapely.geometry.multipolygon import MultiPolygon

doc = DxfImporter('polylines.dxf')
doc.process()
doc.cleanup()
polys = MultiPolygon(doc.polygons)

g = CompoundGeometry(polys)
g.create_mesh(mesh_sizes=[0.1])

(this showed a little thumbnail of an object in a Jupyter Notebook)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions