mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
Implement experimental clash detection with a tolerance
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.geom
|
||||
import numpy as np
|
||||
import fcl
|
||||
|
||||
class IfcClasher:
|
||||
def __init__(self):
|
||||
self.settings = ifcopenshell.geom.settings()
|
||||
self.tolerance = 0.01
|
||||
self.a = None
|
||||
self.b = None
|
||||
self.a_geoms = []
|
||||
self.b_geoms = []
|
||||
self.a_objs = []
|
||||
self.b_objs = []
|
||||
self.a_global_ids = []
|
||||
self.b_global_ids = []
|
||||
self.a_geom_to_global_id = {}
|
||||
self.b_geom_to_global_id = {}
|
||||
self.a_manager = None
|
||||
self.b_manager = None
|
||||
self.clashes = []
|
||||
|
||||
def clash(self):
|
||||
self.load_files()
|
||||
for ab in ('a', 'b'):
|
||||
self.create_collision_objects(ab)
|
||||
self.create_manager(ab)
|
||||
self.create_data_maps(ab)
|
||||
|
||||
req = fcl.CollisionRequest(num_max_contacts=1, enable_contact=True)
|
||||
rdata = fcl.CollisionData(request = req)
|
||||
self.a_manager.collide(self.b_manager, rdata, fcl.defaultCollisionCallback)
|
||||
for contact in rdata.result.contacts:
|
||||
if contact.penetration_depth < self.tolerance:
|
||||
continue
|
||||
self.clashes.append({
|
||||
'a': self.a_geom_to_global_id[id(contact.o1)],
|
||||
'b': self.b_geom_to_global_id[id(contact.o2)],
|
||||
'normal': contact.normal,
|
||||
'position': contact.pos,
|
||||
'penetration_depth': contact.penetration_depth
|
||||
})
|
||||
|
||||
def load_files(self):
|
||||
self.a = ifcopenshell.open('/home/dion/a.ifc')
|
||||
self.b = ifcopenshell.open('/home/dion/b.ifc')
|
||||
|
||||
def create_collision_objects(self, ab):
|
||||
elements = getattr(self, ab).by_type('IfcElement')
|
||||
for element in elements:
|
||||
shape = ifcopenshell.geom.create_shape(self.settings, element)
|
||||
mesh = self.create_mesh(element, shape)
|
||||
transform = self.get_transform(element)
|
||||
getattr(self, '{}_geoms'.format(ab)).append(mesh)
|
||||
getattr(self, '{}_objs'.format(ab)).append(fcl.CollisionObject(mesh, transform))
|
||||
getattr(self, '{}_global_ids'.format(ab)).append(element.GlobalId)
|
||||
|
||||
def create_manager(self, ab):
|
||||
name = '{}_manager'.format(ab)
|
||||
setattr(self, name, fcl.DynamicAABBTreeCollisionManager())
|
||||
getattr(self, name).registerObjects(getattr(self, '{}_objs'.format(ab)))
|
||||
getattr(self, name).setup()
|
||||
|
||||
def create_data_maps(self, ab):
|
||||
setattr(self, '{}_geom_to_global_id'.format(ab),
|
||||
{
|
||||
id(geom) : global_id
|
||||
for geom, global_id
|
||||
in zip(
|
||||
getattr(self, '{}_geoms'.format(ab)),
|
||||
getattr(self, '{}_global_ids'.format(ab))
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
def get_transform(self, element):
|
||||
m = self.get_local_placement(element.ObjectPlacement)
|
||||
R = np.array(
|
||||
[
|
||||
[m[0][0], m[1][0], m[2][0]],
|
||||
[m[0][1], m[1][1], m[2][1]],
|
||||
[m[0][2], m[1][2], m[2][2]]
|
||||
]
|
||||
)
|
||||
T = np.array([m[0][3], m[1][3], m[2][3]])
|
||||
return fcl.Transform(R, T)
|
||||
|
||||
def create_mesh(self, element, shape):
|
||||
f = shape.geometry.faces
|
||||
v = shape.geometry.verts
|
||||
vertices = np.array([[v[i], v[i + 1], v[i + 2]]
|
||||
for i in range(0, len(v), 3)])
|
||||
faces = np.array([[f[i], f[i + 1], f[i + 2]]
|
||||
for i in range(0, len(f), 3)])
|
||||
m = fcl.BVHModel()
|
||||
m.beginModel(len(vertices), len(faces))
|
||||
m.addSubModel(vertices, faces)
|
||||
m.endModel()
|
||||
return m
|
||||
|
||||
def get_local_placement(self, plc):
|
||||
if plc.PlacementRelTo is None:
|
||||
parent = np.eye(4)
|
||||
else:
|
||||
parent = self.get_local_placement(plc.PlacementRelTo)
|
||||
return np.dot(self.get_axis2placement(plc.RelativePlacement), parent)
|
||||
|
||||
def a2p(self, o, z, x):
|
||||
y = np.cross(z, x)
|
||||
r = np.eye(4)
|
||||
r[:-1,:-1] = x,y,z
|
||||
r[-1,:-1] = o
|
||||
return r.T
|
||||
|
||||
def get_axis2placement(self, plc):
|
||||
z = np.array(plc.Axis.DirectionRatios if plc.Axis else (0,0,1))
|
||||
x = np.array(plc.RefDirection.DirectionRatios if plc.RefDirection else (1,0,0))
|
||||
o = plc.Location.Coordinates
|
||||
return self.a2p(o,z,x)
|
||||
|
||||
ifc_clasher = IfcClasher()
|
||||
ifc_clasher.clash()
|
||||
import pprint
|
||||
pprint.pprint(ifc_clasher.clashes)
|
||||
Reference in New Issue
Block a user