def populate_mesh(verts, faces, count, seed, all_triangles, safe_check): bvh = bvh_tree_from_polygons(verts, faces, all_triangles=all_triangles, epsilon=0.0, safe_check=safe_check) np.random.seed(seed) x_min, x_max, y_min, y_max, z_min, z_max = calc_bounds(verts) low = np.array([x_min, y_min, z_min]) high = np.array([x_max, y_max, z_max]) result = [] done = 0 iterations = 0 while True: if iterations > MAX_ITERATIONS: raise Exception("Iterations limit is reached") max_pts = max(count, count - done) points = np.random.uniform(low, high, size=(max_pts, 3)).tolist() points = [p for p in points if point_inside_mesh(bvh, p)] n = len(points) result.extend(points) done += n iterations += 1 if done >= count: break return result, []
def lloyd_in_mesh(verts, faces, sites, n_iterations, thickness=None, weight_field=None): bvh = BVHTree.FromPolygons(verts, faces) if thickness is None: x_min, x_max, y_min, y_max, z_min, z_max = calc_bounds(verts) thickness = max(x_max - x_min, y_max - y_min, z_max - z_min) / 4.0 epsilon = 1e-8 def iteration(points): n = len(points) all_points = points[:] k = 0.5 * thickness for p in points: p = Vector(p) loc, normal, index, distance = bvh.find_nearest(p) if distance <= epsilon: p1 = p + k * normal all_points.append(tuple(p1)) diagram = Voronoi(all_points) centers = [] for site_idx in range(n): region_idx = diagram.point_region[site_idx] region = diagram.regions[region_idx] region_verts = np.array([diagram.vertices[i] for i in region]) center = weighted_center(region_verts, weight_field) centers.append(tuple(center)) return centers def restrict(points): result = [] for p in points: if point_inside_mesh(bvh, p): result.append(p) else: loc, normal, index, distance = bvh.find_nearest(p) if loc is not None: result.append(tuple(loc)) return result points = restrict(sites) for i in range(n_iterations): points = iteration(points) points = restrict(points) return points
def voronoi_on_mesh(verts, faces, sites, thickness, spacing=0.0, clip_inner=True, clip_outer=True, do_clip=True, clipping=1.0, mode='REGIONS', precision=1e-8): bvh = BVHTree.FromPolygons(verts, faces) npoints = len(sites) if clipping is None: x_min, x_max, y_min, y_max, z_min, z_max = calc_bounds(verts) clipping = max(x_max - x_min, y_max - y_min, z_max - z_min) / 2.0 if mode in {'REGIONS', 'RIDGES'}: if clip_inner or clip_outer: normals = calc_bvh_normals(bvh, sites) k = 0.5 * thickness sites = np.array(sites) all_points = sites.tolist() if clip_outer: plus_points = sites + k * normals all_points.extend(plus_points.tolist()) if clip_inner: minus_points = sites - k * normals all_points.extend(minus_points.tolist()) return voronoi3d_layer(npoints, all_points, make_regions=(mode == 'REGIONS'), do_clip=do_clip, clipping=clipping) else: # VOLUME, SURFACE all_points = sites[:] if do_clip: for site in sites: loc, normal, index, distance = bvh.find_nearest(site) if loc is not None: p1 = loc + clipping * normal all_points.append(p1) verts, edges, faces = voronoi_on_mesh_bmesh(verts, faces, len(sites), all_points, spacing=spacing, fill=(mode == 'VOLUME'), precision=precision) return verts, edges, faces, all_points
def process(self): if not any(socket.is_linked for socket in self.outputs): return vertices_s = self.inputs['Vertices'].sv_get() clipping_s = self.inputs['Clipping'].sv_get() verts_out = [] edges_out = [] faces_out = [] for sites, clipping in zip_long_repeat(vertices_s, clipping_s): if isinstance(clipping, (list, tuple)): clipping = clipping[0] diagram = Voronoi(sites) if self.do_clip: bounds = calc_bounds(sites, clipping) if self.out_mode == 'RIDGES': new_verts = diagram.vertices.tolist() new_faces = [e for e in diagram.ridge_vertices if not -1 in e] new_edges = polygons_to_edges([new_faces], True)[0] if self.join: if self.do_clip: new_verts, new_edges, new_faces = self.clip_mesh(bounds, new_verts, new_edges, new_faces, fill=False) verts_out.append(new_verts) edges_out.append(new_edges) faces_out.append(new_faces) else: new_verts, new_edges, new_faces = self.split_ridges(new_verts, new_edges, new_faces) if self.do_clip: new_verts, new_edges, new_faces = self.clip_mesh(bounds, new_verts, new_edges, new_faces, fill=False, iterate=True) verts_out.extend(new_verts) edges_out.extend(new_edges) faces_out.extend(new_faces) else: # REGIONS new_verts, new_edges, new_faces = self.make_regions(diagram) if self.join: new_verts, new_edges, new_faces = mesh_join(new_verts, new_edges, new_faces) new_verts = [new_verts] new_edges = [new_edges] new_faces = [new_faces] if self.do_clip: new_verts, new_edges, new_faces = self.clip_mesh(bounds, new_verts, new_edges, new_faces, fill=True) verts_out.extend(new_verts) edges_out.extend(new_edges) faces_out.extend(new_faces) self.outputs['Vertices'].sv_set(verts_out) self.outputs['Edges'].sv_set(edges_out) self.outputs['Faces'].sv_set(faces_out)
def voronoi3d_regions(sites, closed_only=True, recalc_normals=True, do_clip=False, clipping=1.0): diagram = Voronoi(sites) faces_per_site = defaultdict(list) nsites = len(diagram.point_region) nridges = len(diagram.ridge_points) open_sites = set() for ridge_idx in range(nridges): site_idx_1, site_idx_2 = diagram.ridge_points[ridge_idx] face = diagram.ridge_vertices[ridge_idx] if -1 in face: open_sites.add(site_idx_1) open_sites.add(site_idx_2) continue faces_per_site[site_idx_1].append(face) faces_per_site[site_idx_2].append(face) new_verts = [] new_edges = [] new_faces = [] for site_idx in sorted(faces_per_site.keys()): if closed_only and site_idx in open_sites: continue done_verts = dict() bm = bmesh.new() add_vert = bm.verts.new add_face = bm.faces.new for face in faces_per_site[site_idx]: face_bm_verts = [] for vertex_idx in face: if vertex_idx not in done_verts: bm_vert = add_vert(diagram.vertices[vertex_idx]) done_verts[vertex_idx] = bm_vert else: bm_vert = done_verts[vertex_idx] face_bm_verts.append(bm_vert) add_face(face_bm_verts) bm.verts.index_update() bm.verts.ensure_lookup_table() bm.faces.index_update() bm.edges.index_update() if closed_only and any(v.is_boundary for v in bm.verts): bm.free() continue if recalc_normals: bm.normal_update() bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:]) region_verts, region_edges, region_faces = pydata_from_bmesh(bm) bm.free() new_verts.append(region_verts) new_edges.append(region_edges) new_faces.append(region_faces) if do_clip: verts_n, edges_n, faces_n = [], [], [] bounds = calc_bounds(sites, clipping) for verts_i, edges_i, faces_i in zip(new_verts, new_edges, new_faces): bm = bmesh_from_pydata(verts_i, edges_i, faces_i) bmesh_clip(bm, bounds, fill=True) bm.normal_update() bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:]) verts_i, edges_i, faces_i = pydata_from_bmesh(bm) bm.free() verts_n.append(verts_i) edges_n.append(edges_i) faces_n.append(faces_i) new_verts, new_edges, new_faces = verts_n, edges_n, faces_n return new_verts, new_edges, new_faces
def voronoi3d_layer(n_src_sites, all_sites, make_regions, do_clip, clipping, skip_added=True): diagram = Voronoi(all_sites) src_sites = all_sites[:n_src_sites] region_verts = dict() region_verts_map = dict() n_sites = n_src_sites if skip_added else len(all_sites) for site_idx in range(n_sites): region_idx = diagram.point_region[site_idx] region = diagram.regions[region_idx] vertices = [tuple(diagram.vertices[i, :]) for i in region] region_verts[site_idx] = vertices region_verts_map[site_idx] = { vert_idx: i for i, vert_idx in enumerate(region) } open_sites = set() region_faces = defaultdict(list) for ridge_idx, sites in enumerate(diagram.ridge_points): site_from, site_to = sites ridge = diagram.ridge_vertices[ridge_idx] if -1 in ridge: open_sites.add(site_from) open_sites.add(site_to) site_from_ok = not skip_added or site_from < n_src_sites site_to_ok = not skip_added or site_to < n_src_sites if make_regions: if site_from_ok: face_from = [region_verts_map[site_from][i] for i in ridge] region_faces[site_from].append(face_from) if site_to_ok: face_to = [region_verts_map[site_to][i] for i in ridge] region_faces[site_to].append(face_to) else: if site_from_ok and site_to_ok: face_from = [region_verts_map[site_from][i] for i in ridge] region_faces[site_from].append(face_from) face_to = [region_verts_map[site_to][i] for i in ridge] region_faces[site_to].append(face_to) verts = [region_verts[i] for i in range(n_sites) if i not in open_sites] faces = [region_faces[i] for i in range(n_sites) if i not in open_sites] empty_faces = [len(f) == 0 for f in faces] verts = [vs for vs, mask in zip(verts, empty_faces) if not mask] faces = [fs for fs, mask in zip(faces, empty_faces) if not mask] edges = polygons_to_edges(faces, True) if not make_regions: verts_n, edges_n, faces_n = [], [], [] for verts_i, edges_i, faces_i in zip(verts, edges, faces): used_verts = set(sum(faces_i, [])) mask = [i in used_verts for i in range(len(verts_i))] verts_i, edges_i, faces_i = mask_vertices(verts_i, edges_i, faces_i, mask) verts_n.append(verts_i) edges_n.append(edges_i) faces_n.append(faces_i) verts, edges, faces = verts_n, edges_n, faces_n if do_clip: verts_n, edges_n, faces_n = [], [], [] bounds = calc_bounds(src_sites, clipping) for verts_i, edges_i, faces_i in zip(verts, edges, faces): bm = bmesh_from_pydata(verts_i, edges_i, faces_i) bmesh_clip(bm, bounds, fill=True) verts_i, edges_i, faces_i = pydata_from_bmesh(bm) bm.free() verts_n.append(verts_i) edges_n.append(edges_i) faces_n.append(faces_i) verts, edges, faces = verts_n, edges_n, faces_n return verts, edges, faces