Files
IfcOpenShell/src/bonsai/scripts/dxf2ifc.py
T
Petru Conduraru 5d13791a01 Bonsai: make dxf2ifc.py example script skip unsupported DXF entities
The script called Polyline.get_mode() on every modelspace entity, but
that method only exists on POLYLINE entities, so any typical DXF
containing lines, circles or text crashed with AttributeError before
converting anything. Test for POLYLINE polyface meshes with
dxftype()/is_poly_face_mesh instead and skip other entities with a
message, only create the spatial containment relation when products
exist, and take the input/output paths from the command line (matching
obj2ifc.py) instead of a hardcoded input.dxf/test.ifc.

Fixes #2151

This change was written with the assistance of an AI coding tool.

(cherry picked from commit bb49822f2e)
2026-07-25 23:18:32 +10:00

126 lines
5.1 KiB
Python

# Bonsai - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of Bonsai.
#
# Bonsai is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bonsai is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import argparse
import ezdxf
import ifcopenshell
import ifcopenshell.guid
class Dxf2Ifc:
def __init__(self, dxf_path, outfile):
self.dxf_path = dxf_path
self.outfile = outfile
def execute(self):
self.create_ifc_file()
doc = ezdxf.readfile(self.dxf_path)
model = doc.modelspace()
products = []
for entity in model:
print(entity)
if entity.dxftype() == "POLYLINE" and entity.is_poly_face_mesh:
ifc_faces = []
for face in entity.faces():
ifc_faces.append(
self.file.createIfcFace(
[
self.file.createIfcFaceOuterBound(
self.file.createIfcPolyLoop(
[
self.file.createIfcCartesianPoint(face[index].dxf.location)
for index in range(len(face) - 1)
]
),
True,
)
]
)
)
representation = self.file.createIfcProductDefinitionShape(
None,
None,
[
self.file.createIfcShapeRepresentation(
self.subcontext,
"Body",
"Brep",
[self.file.createIfcFacetedBrep(self.file.createIfcClosedShell(ifc_faces))],
)
],
)
products.append(
self.file.create_entity(
"IfcBuildingElementProxy",
**{
"GlobalId": ifcopenshell.guid.new(),
"Name": entity.dxf.layer,
"ObjectPlacement": self.placement,
"Representation": representation,
},
)
)
else:
print(f"Skipping unsupported entity: {entity.dxftype()}")
if products:
self.file.createIfcRelContainedInSpatialStructure(
ifcopenshell.guid.new(), None, None, None, products, self.site
)
else:
print("No AcDbPolyFaceMesh entities found, writing an empty IFC")
self.file.write(self.outfile)
def create_ifc_file(self):
self.file = ifcopenshell.file()
units = self.file.createIfcUnitAssignment([self.file.createIfcSIUnit(None, "LENGTHUNIT", None, "METRE")])
self.origin = self.file.createIfcAxis2Placement3D(
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
self.file.createIfcDirection((0.0, 0.0, 1.0)),
self.file.createIfcDirection((1.0, 0.0, 0.0)),
)
self.placement = self.file.createIfcLocalPlacement(None, self.origin)
self.context = self.file.createIfcGeometricRepresentationContext(None, "Model", 3, 1.0e-05, self.origin)
self.subcontext = self.file.createIfcGeometricRepresentationSubcontext(
"Body", "Model", None, None, None, None, self.context, None, "MODEL_VIEW", None
)
self.project = self.file.create_entity(
"IfcProject",
**{
"GlobalId": ifcopenshell.guid.new(),
"Name": "DXF Conversion",
"RepresentationContexts": [self.context],
"UnitsInContext": units,
},
)
self.site = self.file.create_entity(
"IfcSite",
**{"GlobalId": ifcopenshell.guid.new(), "Name": "DXF Conversion Site", "ObjectPlacement": self.placement},
)
self.file.createIfcRelAggregates(ifcopenshell.guid.new(), None, None, None, self.project, [self.site])
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Converts DXF polyface meshes (AcDbPolyFaceMesh) to an IFC")
parser.add_argument("dxf", type=str, help="The input DXF file")
parser.add_argument("-o", "--output", type=str, help="The output IFC file", default="out.ifc")
args = parser.parse_args()
dxf2ifc = Dxf2Ifc(args.dxf, args.output)
dxf2ifc.execute()