mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 10:57:49 +00:00
New hacktastic IFC patch to fix ArchiCAD spaces being loaded into Revit.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
class Patcher:
|
||||
def __init__(self, src, file, logger, args=None):
|
||||
self.src = src
|
||||
self.file = file
|
||||
self.logger = logger
|
||||
self.args = args
|
||||
|
||||
def patch(self):
|
||||
# The underlying problem is that Revit does not bring in IFC spaces as
|
||||
# spaces / rooms in Revit when you link an IFC in Revit. This has been
|
||||
# broken for at least 3 years and counting. This is a problem typically
|
||||
# for ArchiCAD architects who want to send rooms to MEP folks using
|
||||
# Revit.
|
||||
#
|
||||
# See bug: https://github.com/Autodesk/revit-ifc/issues/15
|
||||
#
|
||||
# The solution is to open an IFC in Revit instead of linking it, which
|
||||
# will convert IFC spaces into Revit rooms. However, there are very
|
||||
# specific scenarios where Revit will convert these rooms, which have
|
||||
# been painstakingly reverse engineered through trial and error.
|
||||
# Firstly, the rooms should have a lower bound with a Z value matching
|
||||
# the Z value of the storey it is on. Secondly, although faceted breps
|
||||
# do work in some scenarios (I assume Revit has an internal topological
|
||||
# analysis tool), conversion to an extruded area solid yield much more
|
||||
# robust results. Finally, changing the Precision value to an obscene
|
||||
# number very strangely seems to cause a lot more rooms to be converted
|
||||
# successfully.
|
||||
#
|
||||
# This patch is designed to only work on ArchiCAD IFC exports where the
|
||||
# only contents of the IFC is IFC space and _nothing else_. It also
|
||||
# requires you to run it using Blender, as the geometric modification
|
||||
# uses the Blender geometry engine.
|
||||
import bpy
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from mathutils import Vector, Matrix
|
||||
|
||||
if len(bpy.data.objects) > 0:
|
||||
while bpy.data.objects:
|
||||
bpy.data.objects.remove(bpy.data.objects[0])
|
||||
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
|
||||
|
||||
bpy.ops.bim.load_project(filepath=self.src)
|
||||
|
||||
def recalculate_origin(wall):
|
||||
new_origin = wall.matrix_world @ Vector(wall.bound_box[0])
|
||||
if (wall.matrix_world.translation - new_origin).length < 0.001:
|
||||
return
|
||||
wall.data.transform(
|
||||
Matrix.Translation(
|
||||
(wall.matrix_world.inverted().to_quaternion() @ (wall.matrix_world.translation - new_origin))
|
||||
)
|
||||
)
|
||||
wall.matrix_world.translation = new_origin
|
||||
|
||||
for obj in bpy.context.visible_objects:
|
||||
if "IfcBuildingStorey" in obj.name and len(bpy.data.collections.get(obj.name).children) > 0:
|
||||
target_z = obj.location.z
|
||||
|
||||
for obj in bpy.context.visible_objects:
|
||||
bpy.context.view_layer.update()
|
||||
if "IfcSpace" not in obj.name:
|
||||
continue
|
||||
local_target_z = (obj.matrix_world.inverted() @ Vector((0, 0, target_z))).z
|
||||
local_target_zup = (obj.matrix_world.inverted() @ Vector((0, 0, target_z + 3))).z
|
||||
for v in obj.data.vertices:
|
||||
if round(v.co.z, 3) == 0:
|
||||
v.co.z = local_target_z
|
||||
bpy.context.view_layer.update()
|
||||
recalculate_origin(obj)
|
||||
obj.select_set(True)
|
||||
|
||||
bpy.ops.bim.update_representation(
|
||||
ifc_representation_class="IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids"
|
||||
)
|
||||
for context in IfcStore.get_file().by_type("IfcGeometricRepresentationContext"):
|
||||
if context.Precision:
|
||||
context.Precision = 10
|
||||
|
||||
self.file = IfcStore.get_file()
|
||||
Reference in New Issue
Block a user