Fix #2743. obj2ifc scripts updated to support multiple OBJ files.

This commit is contained in:
Dion Moult
2023-02-23 22:17:34 +11:00
parent d396d32a8f
commit 2fe2c349fd
2 changed files with 80 additions and 57 deletions
+37 -31
View File
@@ -27,13 +27,20 @@ from pathlib import Path
import numpy as np
class Obj2Ifc:
def __init__(self, path):
self.path = path
def __init__(self, paths, outfile):
self.paths = paths
self.outfile = outfile
self.basename = Path(outfile).stem
def execute(self, version="IFC4"):
self.basename = Path(self.path).stem
self.create_ifc_file(version)
for path in self.paths:
self.path = path
self._execute()
def _execute(self):
mesh_set = pymeshlab.MeshSet()
mesh_set.load_new_mesh(self.path)
@@ -45,25 +52,20 @@ class Obj2Ifc:
faces = mesh.face_matrix()
vertices = mesh.vertex_matrix()
ifc_faces = np.zeros([len(faces)], dtype=object)
for i, face in enumerate(faces):
ifc_faces[i] = (
self.file.createIfcFace(
[
self.file.createIfcFaceOuterBound(
self.file.createIfcPolyLoop(
[
self.file.createIfcCartesianPoint(
self.get_coordinates(vertices[index].tolist())
)
for index in face
]
),
True,
)
]
)
ifc_faces[i] = self.file.createIfcFace(
[
self.file.createIfcFaceOuterBound(
self.file.createIfcPolyLoop(
[
self.file.createIfcCartesianPoint(self.get_coordinates(vertices[index].tolist()))
for index in face
]
),
True,
)
]
)
representation = self.file.createIfcProductDefinitionShape(
None,
@@ -79,15 +81,14 @@ class Obj2Ifc:
)
product = self.file.create_entity(
"IfcBuildingElementProxy",
**{
"GlobalId": ifcopenshell.guid.new(),
"Name": mesh.label() or self.basename,
"ObjectPlacement": self.placement,
"Representation": representation,
}
GlobalId=ifcopenshell.guid.new(),
Name=mesh.label() or self.basename,
Representation=representation,
)
ifcopenshell.api.run("spatial.assign_container", self.file, product=product, relating_structure=self.storey)
self.file.write(self.path + ".ifc")
product.ObjectPlacement = self.placement
self.file.write(self.outfile)
def get_coordinates(self, coordinates):
if self.format == "obj":
@@ -108,7 +109,7 @@ class Obj2Ifc:
ifcopenshell.api.owner.settings.get_application = lambda ifc: application
project = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject", name=self.basename)
lengthunit = ifcopenshell.api.run("unit.add_si_unit", self.file, unit_type="LENGTHUNIT", name="METRE")
lengthunit = ifcopenshell.api.run("unit.add_si_unit", self.file, unit_type="LENGTHUNIT")
ifcopenshell.api.run("unit.assign_unit", self.file, units=[lengthunit])
model = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
self.context = ifcopenshell.api.run(
@@ -128,19 +129,24 @@ class Obj2Ifc:
ifcopenshell.api.run("aggregate.assign_object", self.file, product=building, relating_object=site)
ifcopenshell.api.run("aggregate.assign_object", self.file, product=self.storey, relating_object=building)
ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=site)
ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=building)
ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=self.storey)
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.placement = self.file.createIfcLocalPlacement(self.storey.ObjectPlacement, self.origin)
self.history = ifcopenshell.api.run("owner.create_owner_history", self.file)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Converts an OBJ to an IFC")
parser.add_argument("obj", type=str, help="The OBJ file")
parser.add_argument("obj", type=str, nargs="+", help="One or more OBJ files")
parser.add_argument("-o", "--output", type=str, help="The output file to save the patched IFC", default="out.ifc")
args = parser.parse_args()
obj2ifc = Obj2Ifc(args.obj)
obj2ifc = Obj2Ifc(args.obj, args.output)
obj2ifc.execute()
+43 -26
View File
@@ -27,30 +27,39 @@ from pathlib import Path
import numpy as np
class Obj2Ifc:
def __init__(self, path):
self.path = path
def __init__(self, paths, outfile):
self.paths = paths
self.outfile = outfile
self.basename = Path(outfile).stem
def execute(self, version="IFC4"):
self.basename = Path(self.path).stem
self.create_ifc_file(version)
for path in self.paths:
self.path = path
self._execute()
def _execute(self):
self.scene = pywavefront.Wavefront(self.path, create_materials=True, collect_faces=True)
for mesh in self.scene.mesh_list:
faces = mesh.faces
ifc_faces = np.zeros([len(faces)], dtype=object)
for i, face in enumerate(faces):
ifc_faces[i] = (
self.file.createIfcFace(
[
self.file.createIfcFaceOuterBound(
self.file.createIfcPolyLoop(
[self.file.createIfcCartesianPoint(self.scene.vertices[index]) for index in face]
),
True,
)
]
)
ifc_faces[i] = self.file.createIfcFace(
[
self.file.createIfcFaceOuterBound(
self.file.createIfcPolyLoop(
[
self.file.createIfcCartesianPoint(self.get_coordinates(self.scene.vertices[index]))
for index in face
]
),
True,
)
]
)
representation = self.file.createIfcProductDefinitionShape(
None,
@@ -66,15 +75,18 @@ class Obj2Ifc:
)
product = self.file.create_entity(
"IfcBuildingElementProxy",
**{
"GlobalId": ifcopenshell.guid.new(),
"Name": mesh.name or self.basename,
"ObjectPlacement": self.placement,
"Representation": representation,
}
GlobalId=ifcopenshell.guid.new(),
Name=mesh.name or self.basename,
Representation=representation,
)
ifcopenshell.api.run("spatial.assign_container", self.file, product=product, relating_structure=self.storey)
self.file.write(self.path.replace(".obj", ".ifc"))
product.ObjectPlacement = self.placement
self.file.write(self.outfile)
def get_coordinates(self, coordinates):
# OBJ swaps Y and Z axis
return [coordinates[0], -coordinates[2], coordinates[1]]
def create_ifc_file(self, version):
self.file = ifcopenshell.api.run("project.create_file", version=version)
@@ -90,7 +102,7 @@ class Obj2Ifc:
ifcopenshell.api.owner.settings.get_application = lambda ifc: application
project = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject", name=self.basename)
lengthunit = ifcopenshell.api.run("unit.add_si_unit", self.file, unit_type="LENGTHUNIT", name="METRE")
lengthunit = ifcopenshell.api.run("unit.add_si_unit", self.file, unit_type="LENGTHUNIT")
ifcopenshell.api.run("unit.assign_unit", self.file, units=[lengthunit])
model = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
self.context = ifcopenshell.api.run(
@@ -110,19 +122,24 @@ class Obj2Ifc:
ifcopenshell.api.run("aggregate.assign_object", self.file, product=building, relating_object=site)
ifcopenshell.api.run("aggregate.assign_object", self.file, product=self.storey, relating_object=building)
ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=site)
ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=building)
ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=self.storey)
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.placement = self.file.createIfcLocalPlacement(self.storey.ObjectPlacement, self.origin)
self.history = ifcopenshell.api.run("owner.create_owner_history", self.file)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Converts an OBJ to an IFC")
parser.add_argument("obj", type=str, help="The OBJ file")
parser.add_argument("obj", type=str, nargs="+", help="One or more OBJ files")
parser.add_argument("-o", "--output", type=str, help="The output file to save the patched IFC", default="out.ifc")
args = parser.parse_args()
obj2ifc = Obj2Ifc(args.obj)
obj2ifc = Obj2Ifc(args.obj, args.output)
obj2ifc.execute()