mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 10:57:49 +00:00
Standalone Blender import script now available for debugging
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.geom
|
||||
import multiprocessing
|
||||
|
||||
|
||||
class BlenderImporter:
|
||||
def __init__(self):
|
||||
self.file = ifcopenshell.open('/home/dion/untitled.ifc')
|
||||
self.cache_path = "cache.h5"
|
||||
self.should_use_cpu_multiprocessing = True
|
||||
self.deflection_tolerance = 0.001
|
||||
self.angular_tolerance = 0.5
|
||||
|
||||
def execute(self):
|
||||
self.created_guids = set()
|
||||
|
||||
self.settings = ifcopenshell.geom.settings()
|
||||
self.settings.set_deflection_tolerance(self.deflection_tolerance)
|
||||
self.settings.set_angular_tolerance(self.angular_tolerance)
|
||||
self.settings.set(self.settings.STRICT_TOLERANCE, True)
|
||||
self.settings_2d = ifcopenshell.geom.settings()
|
||||
self.settings_2d.set(self.settings_2d.INCLUDE_CURVES, True)
|
||||
self.settings_2d.set(self.settings.STRICT_TOLERANCE, True)
|
||||
|
||||
self.process_element_filter()
|
||||
self.process_context_filter()
|
||||
self.create_elements(self.elements)
|
||||
|
||||
def process_element_filter(self):
|
||||
# Blender users can typically customise a filtered set of elements to import.
|
||||
# For simplicity, let's select everything:
|
||||
self.elements = set(self.file.by_type("IfcProduct"))
|
||||
|
||||
def process_context_filter(self):
|
||||
# Facetation is to accommodate broken Revit files
|
||||
# See https://forums.buildingsmart.org/t/suggestions-on-how-to-improve-clarity-of-representation-context-usage-in-documentation/3663/6?u=moult
|
||||
self.body_contexts = [
|
||||
c.id()
|
||||
for c in self.file.by_type("IfcGeometricRepresentationSubContext")
|
||||
if c.ContextIdentifier in ["Body", "Facetation"]
|
||||
]
|
||||
# Ideally, all representations should be in a subcontext, but some BIM programs don't do this correctly
|
||||
self.body_contexts.extend(
|
||||
[
|
||||
c.id()
|
||||
for c in self.file.by_type("IfcGeometricRepresentationContext", include_subtypes=False)
|
||||
if c.ContextType == "Model"
|
||||
]
|
||||
)
|
||||
if self.body_contexts:
|
||||
self.settings.set_context_ids(self.body_contexts)
|
||||
# Annotation is to accommodate broken Revit files
|
||||
# See https://github.com/Autodesk/revit-ifc/issues/187
|
||||
self.plan_contexts = [
|
||||
c.id()
|
||||
for c in self.file.by_type("IfcGeometricRepresentationContext")
|
||||
if c.ContextType in ["Plan", "Annotation"]
|
||||
]
|
||||
if self.plan_contexts:
|
||||
self.settings_2d.set_context_ids(self.plan_contexts)
|
||||
|
||||
def create_elements(self, elements):
|
||||
# Based on my experience in viewing BIM models, representations are prioritised as follows:
|
||||
# 1. 3D Body, 2. 2D Plans, 3. Point clouds, 4. No representation
|
||||
# If an element has a representation that doesn't follow 1, 2, or 3, it will not show by default.
|
||||
# The user can load them later if they want to view them.
|
||||
products = self.create_products(elements)
|
||||
elements -= products
|
||||
products = self.create_products(elements, is_curve=True)
|
||||
elements -= products
|
||||
# Creating point clouds and non geometric objects are specific to Blender so no code is shown.
|
||||
pass
|
||||
|
||||
def create_products(self, products, is_curve=False):
|
||||
results = set()
|
||||
if not products:
|
||||
return results
|
||||
settings = self.settings_2d if is_curve else self.settings
|
||||
if self.should_use_cpu_multiprocessing:
|
||||
iterator = ifcopenshell.geom.iterator(
|
||||
settings, self.file, multiprocessing.cpu_count(), include=products
|
||||
)
|
||||
else:
|
||||
iterator = ifcopenshell.geom.iterator(settings, self.file, include=products)
|
||||
cache = self.get_cache()
|
||||
if cache:
|
||||
iterator.set_cache(cache)
|
||||
valid_file = iterator.initialize()
|
||||
if not valid_file:
|
||||
return results
|
||||
total = 0
|
||||
while True:
|
||||
total += 1
|
||||
if total % 250 == 0:
|
||||
print(f"{total} elements processed")
|
||||
shape = iterator.get()
|
||||
if shape:
|
||||
product = self.file.by_id(shape.guid)
|
||||
if self.body_contexts:
|
||||
print("Created", product)
|
||||
self.created_guids.add(shape.guid)
|
||||
results.add(product)
|
||||
else:
|
||||
if shape.context not in ["Body", "Facetation"] and shape.guid in self.created_guids:
|
||||
# We only load a single context, and we prioritise the Body context. See #1290.
|
||||
pass
|
||||
else:
|
||||
print("Created", product)
|
||||
self.created_guids.add(shape.guid)
|
||||
results.add(product)
|
||||
if not iterator.next():
|
||||
break
|
||||
print("Done creating geometry")
|
||||
return results
|
||||
|
||||
def get_cache(self):
|
||||
cache_settings = ifcopenshell.geom.settings()
|
||||
cache_settings.set(cache_settings.STRICT_TOLERANCE, True)
|
||||
try:
|
||||
return ifcopenshell.geom.serializers.hdf5(self.cache_path, cache_settings)
|
||||
except:
|
||||
return
|
||||
|
||||
BlenderImporter().execute()
|
||||
Reference in New Issue
Block a user