mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +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
|
||||
|
||||
|
||||
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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user