From 75ae501ff9a1eba73106c553b6c8a8de68921d19 Mon Sep 17 00:00:00 2001 From: s-leger Date: Fri, 28 May 2021 00:57:22 +0200 Subject: [PATCH] Evaluate coplanar vertex in faces (#1489) The idea is to only triangulate non co-planar faces when required. Timings for evaluation with matrix based algo. IfcRoof/Roof found 3927 of 116178 polygons: 0.366638 sec IfcWall/Wall.012 found 0 of 6 polygons: 0.000046 sec So should be acceptable for common use cases But with single precision in blender we may still be over occ precision with a 1e-6 epsilon. --- .../api/geometry/add_representation.py | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py index 971a003546..d36af57ed9 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py @@ -1,9 +1,13 @@ import bpy import bmesh import ifcopenshell.util.unit -from mathutils import Vector +from mathutils import Vector, Matrix from blenderbim.bim.module.geometry.helper import Helper +Z_AXIS = Vector((0, 0, 1)) +X_AXIS = Vector((1, 0, 0)) +EPSILON = 1e-6 + class Usecase: def __init__(self, file, **settings): @@ -45,7 +49,26 @@ class Usecase: elif self.settings["context"].ContextType == "Plan": return self.create_plan_representation() return self.create_variable_representation() + + def should_triangulate_face(self, face, threshold=EPSILON): + vz = face.normal + co = face.verts[0].co + if vz.length < 0.5: + return True + if abs(vz.z) < 0.5: + vx = vz.cross(Z_AXIS) + else: + vx = vz.cross(X_AXIS) + vy = vx.cross(vz) + tM = Matrix([ + [vx.x, vy.x, vz.x, co.x], + [vx.y, vy.y, vz.y, co.y], + [vx.z, vy.z, vz.z, co.z], + [0, 0, 0, 1] + ]).inverted() + return any([abs(tM @ v.co).z) > threshold for v in face.verts]) + def evaluate_geometry(self): for modifier in self.settings["blender_object"].modifiers: if modifier.type == "BOOLEAN": @@ -54,17 +77,11 @@ class Usecase: mesh = self.settings["blender_object"].evaluated_get(bpy.context.evaluated_depsgraph_get()).to_mesh() bm = bmesh.new() bm.from_mesh(mesh) - bmesh.ops.triangulate(bm, faces=bm.faces) - - if not self.settings["should_force_triangulation"]: - bmesh.ops.dissolve_limit( - bm, - angle_limit=0.00174533, # 1 degree - use_dissolve_boundaries=False, - verts=bm.verts[:], - edges=bm.edges[:], - delimit={"MATERIAL"}, - ) + if self.settings["should_force_triangulation"]: + faces = bm.faces + else: + faces = [f for f in bm.faces if self.should_triangulate_face(f)] + bmesh.ops.triangulate(bm, faces=faces) bm.to_mesh(mesh) bm.free() del bm