# SPDX-License-Identifier: GPL-2.0-or-later # Script copyright (C) Blender Foundation 2012 def points_as_bmesh_cells( verts, points, points_scale=None, margin_bounds=0.05, margin_cell=0.0, ): from math import sqrt import mathutils from mathutils import Vector cells = [] points_sorted_current = [p for p in points] plane_indices = [] vertices = [] if points_scale is not None: points_scale = tuple(points_scale) if points_scale == (1.0, 1.0, 1.0): points_scale = None # there are many ways we could get planes - convex hull for eg # but it ends up fastest if we just use bounding box if 1: xa = [v[0] for v in verts] ya = [v[1] for v in verts] za = [v[2] for v in verts] xmin, xmax = min(xa) - margin_bounds, max(xa) + margin_bounds ymin, ymax = min(ya) - margin_bounds, max(ya) + margin_bounds zmin, zmax = min(za) - margin_bounds, max(za) + margin_bounds convexPlanes = [ Vector((+1.0, 0.0, 0.0, -xmax)), Vector((-1.0, 0.0, 0.0, +xmin)), Vector((0.0, +1.0, 0.0, -ymax)), Vector((0.0, -1.0, 0.0, +ymin)), Vector((0.0, 0.0, +1.0, -zmax)), Vector((0.0, 0.0, -1.0, +zmin)), ] for i, point_cell_current in enumerate(points): planes = [None] * len(convexPlanes) for j in range(len(convexPlanes)): planes[j] = convexPlanes[j].copy() planes[j][3] += planes[j].xyz.dot(point_cell_current) distance_max = 10000000000.0 # a big value! points_sorted_current.sort(key=lambda p: (p - point_cell_current).length_squared) for j in range(1, len(points)): normal = points_sorted_current[j] - point_cell_current nlength = normal.length if points_scale is not None: normal_alt = normal.copy() normal_alt.x *= points_scale[0] normal_alt.y *= points_scale[1] normal_alt.z *= points_scale[2] # rotate plane to new distance # should always be positive!! - but abs incase scalar = normal_alt.normalized().dot(normal.normalized()) # assert(scalar >= 0.0) nlength *= scalar normal = normal_alt if nlength > distance_max: break plane = normal.normalized() plane.resize_4d() plane[3] = (-nlength / 2.0) + margin_cell planes.append(plane) vertices[:], plane_indices[:] = mathutils.geometry.points_in_planes(planes) if len(vertices) == 0: break if len(plane_indices) != len(planes): planes[:] = [planes[k] for k in plane_indices] # for comparisons use length_squared and delay # converting to a real length until the end. distance_max = 10000000000.0 # a big value! for v in vertices: distance = v.length_squared if distance_max < distance: distance_max = distance distance_max = sqrt(distance_max) # make real length distance_max *= 2.0 if len(vertices) == 0: continue cells.append((point_cell_current, vertices[:])) del vertices[:] return cells