mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-11 22:31:55 +00:00
Fix #2743. obj2ifc scripts updated to support multiple OBJ files.
This commit is contained in:
@@ -27,13 +27,20 @@ from pathlib import Path
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class Obj2Ifc:
|
class Obj2Ifc:
|
||||||
def __init__(self, path):
|
def __init__(self, paths, outfile):
|
||||||
self.path = path
|
self.paths = paths
|
||||||
|
self.outfile = outfile
|
||||||
|
self.basename = Path(outfile).stem
|
||||||
|
|
||||||
def execute(self, version="IFC4"):
|
def execute(self, version="IFC4"):
|
||||||
self.basename = Path(self.path).stem
|
|
||||||
self.create_ifc_file(version)
|
self.create_ifc_file(version)
|
||||||
|
for path in self.paths:
|
||||||
|
self.path = path
|
||||||
|
self._execute()
|
||||||
|
|
||||||
|
def _execute(self):
|
||||||
mesh_set = pymeshlab.MeshSet()
|
mesh_set = pymeshlab.MeshSet()
|
||||||
mesh_set.load_new_mesh(self.path)
|
mesh_set.load_new_mesh(self.path)
|
||||||
|
|
||||||
@@ -45,25 +52,20 @@ class Obj2Ifc:
|
|||||||
faces = mesh.face_matrix()
|
faces = mesh.face_matrix()
|
||||||
vertices = mesh.vertex_matrix()
|
vertices = mesh.vertex_matrix()
|
||||||
|
|
||||||
|
|
||||||
ifc_faces = np.zeros([len(faces)], dtype=object)
|
ifc_faces = np.zeros([len(faces)], dtype=object)
|
||||||
for i, face in enumerate(faces):
|
for i, face in enumerate(faces):
|
||||||
ifc_faces[i] = (
|
ifc_faces[i] = self.file.createIfcFace(
|
||||||
self.file.createIfcFace(
|
[
|
||||||
[
|
self.file.createIfcFaceOuterBound(
|
||||||
self.file.createIfcFaceOuterBound(
|
self.file.createIfcPolyLoop(
|
||||||
self.file.createIfcPolyLoop(
|
[
|
||||||
[
|
self.file.createIfcCartesianPoint(self.get_coordinates(vertices[index].tolist()))
|
||||||
self.file.createIfcCartesianPoint(
|
for index in face
|
||||||
self.get_coordinates(vertices[index].tolist())
|
]
|
||||||
)
|
),
|
||||||
for index in face
|
True,
|
||||||
]
|
)
|
||||||
),
|
]
|
||||||
True,
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
representation = self.file.createIfcProductDefinitionShape(
|
representation = self.file.createIfcProductDefinitionShape(
|
||||||
None,
|
None,
|
||||||
@@ -79,15 +81,14 @@ class Obj2Ifc:
|
|||||||
)
|
)
|
||||||
product = self.file.create_entity(
|
product = self.file.create_entity(
|
||||||
"IfcBuildingElementProxy",
|
"IfcBuildingElementProxy",
|
||||||
**{
|
GlobalId=ifcopenshell.guid.new(),
|
||||||
"GlobalId": ifcopenshell.guid.new(),
|
Name=mesh.label() or self.basename,
|
||||||
"Name": mesh.label() or self.basename,
|
Representation=representation,
|
||||||
"ObjectPlacement": self.placement,
|
|
||||||
"Representation": representation,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
ifcopenshell.api.run("spatial.assign_container", self.file, product=product, relating_structure=self.storey)
|
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):
|
def get_coordinates(self, coordinates):
|
||||||
if self.format == "obj":
|
if self.format == "obj":
|
||||||
@@ -108,7 +109,7 @@ class Obj2Ifc:
|
|||||||
ifcopenshell.api.owner.settings.get_application = lambda ifc: application
|
ifcopenshell.api.owner.settings.get_application = lambda ifc: application
|
||||||
|
|
||||||
project = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject", name=self.basename)
|
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])
|
ifcopenshell.api.run("unit.assign_unit", self.file, units=[lengthunit])
|
||||||
model = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
|
model = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
|
||||||
self.context = ifcopenshell.api.run(
|
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=building, relating_object=site)
|
||||||
ifcopenshell.api.run("aggregate.assign_object", self.file, product=self.storey, relating_object=building)
|
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.origin = self.file.createIfcAxis2Placement3D(
|
||||||
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
|
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
|
||||||
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
||||||
self.file.createIfcDirection((1.0, 0.0, 0.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)
|
self.history = ifcopenshell.api.run("owner.create_owner_history", self.file)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Converts an OBJ to an IFC")
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
obj2ifc = Obj2Ifc(args.obj)
|
obj2ifc = Obj2Ifc(args.obj, args.output)
|
||||||
obj2ifc.execute()
|
obj2ifc.execute()
|
||||||
|
|||||||
@@ -27,30 +27,39 @@ from pathlib import Path
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class Obj2Ifc:
|
class Obj2Ifc:
|
||||||
def __init__(self, path):
|
def __init__(self, paths, outfile):
|
||||||
self.path = path
|
self.paths = paths
|
||||||
|
self.outfile = outfile
|
||||||
|
self.basename = Path(outfile).stem
|
||||||
|
|
||||||
def execute(self, version="IFC4"):
|
def execute(self, version="IFC4"):
|
||||||
self.basename = Path(self.path).stem
|
|
||||||
self.create_ifc_file(version)
|
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)
|
self.scene = pywavefront.Wavefront(self.path, create_materials=True, collect_faces=True)
|
||||||
for mesh in self.scene.mesh_list:
|
for mesh in self.scene.mesh_list:
|
||||||
|
|
||||||
faces = mesh.faces
|
faces = mesh.faces
|
||||||
ifc_faces = np.zeros([len(faces)], dtype=object)
|
ifc_faces = np.zeros([len(faces)], dtype=object)
|
||||||
for i, face in enumerate(faces):
|
for i, face in enumerate(faces):
|
||||||
ifc_faces[i] = (
|
ifc_faces[i] = self.file.createIfcFace(
|
||||||
self.file.createIfcFace(
|
[
|
||||||
[
|
self.file.createIfcFaceOuterBound(
|
||||||
self.file.createIfcFaceOuterBound(
|
self.file.createIfcPolyLoop(
|
||||||
self.file.createIfcPolyLoop(
|
[
|
||||||
[self.file.createIfcCartesianPoint(self.scene.vertices[index]) for index in face]
|
self.file.createIfcCartesianPoint(self.get_coordinates(self.scene.vertices[index]))
|
||||||
),
|
for index in face
|
||||||
True,
|
]
|
||||||
)
|
),
|
||||||
]
|
True,
|
||||||
)
|
)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
representation = self.file.createIfcProductDefinitionShape(
|
representation = self.file.createIfcProductDefinitionShape(
|
||||||
None,
|
None,
|
||||||
@@ -66,15 +75,18 @@ class Obj2Ifc:
|
|||||||
)
|
)
|
||||||
product = self.file.create_entity(
|
product = self.file.create_entity(
|
||||||
"IfcBuildingElementProxy",
|
"IfcBuildingElementProxy",
|
||||||
**{
|
GlobalId=ifcopenshell.guid.new(),
|
||||||
"GlobalId": ifcopenshell.guid.new(),
|
Name=mesh.name or self.basename,
|
||||||
"Name": mesh.name or self.basename,
|
Representation=representation,
|
||||||
"ObjectPlacement": self.placement,
|
|
||||||
"Representation": representation,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
ifcopenshell.api.run("spatial.assign_container", self.file, product=product, relating_structure=self.storey)
|
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):
|
def create_ifc_file(self, version):
|
||||||
self.file = ifcopenshell.api.run("project.create_file", version=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
|
ifcopenshell.api.owner.settings.get_application = lambda ifc: application
|
||||||
|
|
||||||
project = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject", name=self.basename)
|
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])
|
ifcopenshell.api.run("unit.assign_unit", self.file, units=[lengthunit])
|
||||||
model = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
|
model = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
|
||||||
self.context = ifcopenshell.api.run(
|
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=building, relating_object=site)
|
||||||
ifcopenshell.api.run("aggregate.assign_object", self.file, product=self.storey, relating_object=building)
|
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.origin = self.file.createIfcAxis2Placement3D(
|
||||||
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
|
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
|
||||||
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
||||||
self.file.createIfcDirection((1.0, 0.0, 0.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)
|
self.history = ifcopenshell.api.run("owner.create_owner_history", self.file)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Converts an OBJ to an IFC")
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
obj2ifc = Obj2Ifc(args.obj)
|
obj2ifc = Obj2Ifc(args.obj, args.output)
|
||||||
obj2ifc.execute()
|
obj2ifc.execute()
|
||||||
|
|||||||
Reference in New Issue
Block a user