MCPcopy Create free account
hub / github.com/IfcOpenShell/IfcOpenShell / substitute_with_box

Method substitute_with_box

src/exterior-shell-extractor/main.py:203–301  ·  view source on GitHub ↗

Computes a (somewhat) optimal oriented bounding box around the triangulated geometry described in elem by constructing a local reference frame based on the prevalent triangle normals Args: file (ifcopenshell.file): file containing elem elem (TriangulationEle

(self, file, elem, min_thickness=0.01, force=False)

Source from the content-addressed store, hash-verified

201 return len(ConvexHull(points[:, 0:2]).vertices) == len(points)
202
203 def substitute_with_box(self, file, elem, min_thickness=0.01, force=False):
204 """
205 Computes a (somewhat) optimal oriented bounding box around the triangulated geometry described in elem by constructing a local reference frame based on the prevalent triangle normals
206
207 Args:
208 file (ifcopenshell.file): file containing elem
209 elem (TriangulationElement): triangulated geometry
210 min_thickness (float, optional): minimal thickness of the oriented bounding box to create around elem
211
212 Returns:
213 tuple: <guid, <3x4 matrix, min, max>> with min and max being the local coords in the matrix
214 """
215 vs = numpy.array(elem.geometry.verts).reshape((-1, 3))
216 fs = numpy.array(elem.geometry.faces).reshape((-1, 3))
217
218 def _():
219 for f in fs:
220 p, q, r = vs[f]
221 pq = q - p
222 pr = r - p
223 pq /= numpy.linalg.norm(pq)
224 pr /= numpy.linalg.norm(pr)
225 pqr = numpy.cross(pq, pr)
226 pqr /= numpy.linalg.norm(pqr)
227 yield pqr
228
229 tri_norms = numpy.array(list(_()))
230
231 def _():
232 for f in fs:
233 p, q, r = vs[f]
234 pq = q - p
235 pr = r - p
236 pqr = numpy.cross(pq, pr)
237 yield numpy.linalg.norm(pqr) / 2.
238
239 tri_areas = numpy.array(list(_()))
240
241 _, inv, cnts = numpy.unique(numpy.int_(tri_norms * 1000), return_counts=True, return_inverse=True, axis=0)
242 di = utils.make_default(sorted((j, i) for i, j in enumerate(inv)))
243 summed_area = [v[1] for v in sorted((k, sum(tri_areas[v])) for k, v in di.items())]
244 sorted_summed_areas = numpy.argsort(summed_area)
245 V = numpy.average(tri_norms[di[sorted_summed_areas[-1]]], axis=0)
246 candidates = []
247 for i in range(1, min(10, len(cnts))):
248 ref = numpy.average(tri_norms[di[sorted_summed_areas[-i]]], axis=0)
249 candidates.append((abs(ref @ V), ref))
250 if not candidates:
251 refs = [(0, 0, 1), (1, 0, 0)]
252 for ref in refs:
253 candidates.append((abs(ref @ V), ref))
254 ref = min(candidates, key=operator.itemgetter(0))[1]
255 Y = numpy.cross(V, ref)
256 X = numpy.cross(V, Y)
257 M = numpy.array((X, -Y, V))
258
259 Mi = numpy.linalg.inv(M)
260 vsi = numpy.array([v @ Mi for v in vs])

Callers 1

Calls 6

calculate_unit_scaleFunction · 0.90
uniqueMethod · 0.80
_Function · 0.50
rangeFunction · 0.50
itemsMethod · 0.45
appendMethod · 0.45

Tested by

no test coverage detected