def process(self): if not self.inputs['Vertices'].is_linked: return if not self.outputs['Vertices'].is_linked: return points_in = self.inputs['Vertices'].sv_get() pts_out = [] # polys_out = [] edges_out = [] for obj in points_in: pt_list = [] x_max = obj[0][0] x_min = obj[0][0] y_min = obj[0][1] y_max = obj[0][1] # creates points in format for voronoi library, throwing away z for pt in obj: x, y = pt[0], pt[1] x_max = max(x, x_max) x_min = min(x, x_min) y_max = max(y, y_max) y_min = min(x, x_min) pt_list.append(Site(pt[0], pt[1])) res = computeVoronoiDiagram(pt_list) edges = res[2] delta = self.clip x_max = x_max + delta y_max = y_max + delta x_min = x_min - delta y_min = y_min - delta # clipping box to bounding box. pts_tmp = [] for pt in res[0]: x, y = pt[0], pt[1] if x < x_min: x = x_min if x > x_max: x = x_max if y < y_min: y = y_min if y > y_max: y = y_max pts_tmp.append((x, y, 0)) pts_out.append(pts_tmp) edges_out.append([(edge[1], edge[2]) for edge in edges if -1 not in edge]) # outputs self.outputs['Vertices'].sv_set(pts_out) self.outputs['Edges'].sv_set(edges_out)
def get_delaunay_triangulation(verts_in): pt_list = [Site(pt[0], pt[1]) for pt in verts_in] res = computeDelaunayTriangulation(pt_list) polys_in = [tri for tri in res if -1 not in tri] #all faces hase normals -Z, should be reversed polys_in = [pol[::-1] for pol in polys_in] edges_in = pols_edges([polys_in], unique_edges=True)[0] return edges_in, polys_in
def delaunay_triangulatrion(samples_u, samples_v, us_list, vs_list, u_coeff, v_coeff, epsilon): #if delaunay_2d_cdt is None: # Pure-python implementation points_uv = [ Site(u * u_coeff, v * v_coeff) for u, v in zip(us_list, vs_list) ] faces = computeDelaunayTriangulation(points_uv) return faces
def process(self): if not self.inputs['Vertices'].is_linked: return if not self.outputs['Polygons'].is_linked: return tris_out = [] points_in = [] points_in = self.inputs['Vertices'].sv_get() for obj in points_in: pt_list = [Site(pt[0], pt[1]) for pt in obj] res = computeDelaunayTriangulation(pt_list) tris_out.append([tri for tri in res if -1 not in tri]) self.outputs['Polygons'].sv_set(tris_out)
def process(self): points_in = [] if not ('Polygons' in self.outputs and self.outputs['Polygons'].is_linked): return if 'Vertices' in self.inputs and self.inputs['Vertices'].is_linked: points_in = SvGetSocketAnyType(self, self.inputs['Vertices']) tris_out = [] for obj in points_in: pt_list = [Site(pt[0], pt[1]) for pt in obj] res = computeDelaunayTriangulation(pt_list) tris_out.append([tri for tri in res if -1 not in tri]) if 'Polygons' in self.outputs and self.outputs['Polygons'].is_linked: SvSetSocketAnyType(self, 'Polygons', tris_out)
def delaunay_triangulatrion(samples_u, samples_v, us_list, vs_list, u_coeff, v_coeff, epsilon): if delaunay_2d_cdt is None: # Pure-python implementation points_uv = [ Site(u * u_coeff, v * v_coeff) for u, v in zip(us_list, vs_list) ] faces = computeDelaunayTriangulation(points_uv) return faces else: points_scaled = [(u * u_coeff, v * v_coeff) for u, v in zip(us_list, vs_list)] INNER = 1 # delaunay_2d_cdt function wont' work if we do not provide neither edges nor faces. # So let's just construct the outer faces of the rectangular grid # (indices in `edges' depend on the fact that in `adaptive_subdivide` we # add randomly generated points to the end of us_list/vs_list). edges = make_outer_edges(samples_v, samples_u) vert_coords, edges, faces, orig_verts, orig_edges, orig_faces = delaunay_2d_cdt( points_scaled, edges, [], INNER, epsilon) return faces
def process(self): if not self.inputs['Vertices'].is_linked: return if not self.outputs['Vertices'].is_linked: return points_in = self.inputs['Vertices'].sv_get() pts_out = [] # polys_out = [] edges_out = [] for obj in points_in: bounds = Bounds.new(self.bound_mode) source_sites = [] bounds.x_max = -BIG_FLOAT bounds.x_min = BIG_FLOAT bounds.y_min = BIG_FLOAT bounds.y_max = -BIG_FLOAT x0, y0, z0 = center(obj) bounds.center = (x0, y0) # creates points in format for voronoi library, throwing away z for x, y, z in obj: r = sqrt((x - x0)**2 + (y - y0)**2) bounds.r_max = max(r, bounds.r_max) bounds.x_max = max(x, bounds.x_max) bounds.x_min = min(x, bounds.x_min) bounds.y_max = max(y, bounds.y_max) bounds.y_min = min(y, bounds.y_min) source_sites.append(Site(x, y)) delta = self.clip bounds.x_max = bounds.x_max + delta bounds.y_max = bounds.y_max + delta bounds.x_min = bounds.x_min - delta bounds.y_min = bounds.y_min - delta bounds.r_max = bounds.r_max + delta voronoi_data = computeVoronoiDiagram(source_sites) verts = voronoi_data.vertices lines = voronoi_data.lines all_edges = voronoi_data.edges finite_edges = [(edge[1], edge[2]) for edge in all_edges if -1 not in edge] bm = Mesh2D.from_pydata(verts, finite_edges) # clipping box to bounding box. verts_to_remove = set() edges_to_remove = set() bounding_verts = [] # For each diagram vertex that is outside of the bounds, # cut each edge connected with that vertex by bounding line. # Remove such vertices, remove such edges, and instead add # vertices lying on the bounding line and corresponding edges. for vert_idx, vert in enumerate(bm.verts[:]): x, y = tuple(vert) if not bounds.contains((x, y)): verts_to_remove.add(vert_idx) for other_vert_idx in list(bm.linked_verts[vert_idx]): edges_to_remove.add((vert_idx, other_vert_idx)) if self.draw_hangs or self.draw_bounds: other_vert = bm.verts[other_vert_idx] if other_vert is not None: x2, y2 = tuple(other_vert) intersection = bounds.segment_intersection( (x, y), (x2, y2)) if intersection is not None: intersection = tuple(intersection) new_vert_idx = bm.new_vert(intersection) bounding_verts.append(new_vert_idx) #info("CLIP: Added point: %s => %s", (x_i, y_i), new_vert_idx) bm.new_edge(other_vert_idx, new_vert_idx) # Diagram lines that go infinitely from one side of diagram to another infinite_lines = [] # Lines that start at the one vertex of the diagram and go to infinity rays = defaultdict(list) if self.draw_hangs or self.draw_bounds: sites_by_line = defaultdict(list) for site_idx in voronoi_data.polygons.keys(): for line_index, i1, i2 in voronoi_data.polygons[site_idx]: if i1 == -1 or i2 == -1: site = source_sites[site_idx] sites_by_line[line_index].append((site.x, site.y)) for line_index, i1, i2 in all_edges: if i1 == -1 or i2 == -1: line = lines[line_index] a, b, c = line eqn = LineEquation2D(a, b, -c) if i1 == -1 and i2 != -1: eqn.sites = sites_by_line[line_index] rays[i2].append(eqn) elif i2 == -1 and i1 != -1: eqn.sites = sites_by_line[line_index] rays[i1].append(eqn) elif i1 == -1 and i2 == -1: infinite_lines.append(eqn) # For each (half-infinite) ray, calculate it's intersection # with the bounding line and draw an edge from ray's beginning to # the bounding line. # NB: The data returned from voronoi.py for such lines # is a vertex and a line equation. The line obviously intersects # the bounding line in two points; which one should we choose? # Let's choose that one which is closer to site points which the # line is dividing. for vert_index in rays.keys(): x, y = bm.verts[vert_index] vert = Vector((x, y)) if vert_index not in verts_to_remove: for line in rays[vert_index]: intersection = bounds.ray_intersection(vert, line) intersection = tuple(intersection) new_vert_idx = bm.new_vert(intersection) bounding_verts.append(new_vert_idx) #info("INF: Added point: %s: %s => %s", (x,y), (x_i, y_i), new_vert_idx) bm.new_edge(vert_index, new_vert_idx) # For each infinite (in two directions) line, # calculate two it's intersections with the bounding # line and connect them by an edge. for eqn in infinite_lines: intersections = bounds.line_intersection(eqn) if len(intersections) == 2: v1, v2 = intersections new_vert_1_idx = bm.new_vert(tuple(v1)) new_vert_2_idx = bm.new_vert(tuple(v2)) bounding_verts.append(new_vert_1_idx) bounding_verts.append(new_vert_2_idx) bm.new_edge(new_vert_1_idx, new_vert_2_idx) else: self.error( "unexpected number of intersections of infinite line %s with area bounds: %s", eqn, intersections) # TODO: there could be (finite) edges, which have both ends # outside of the bounding line. We could detect such edges and # process similarly to infinite lines - calculate two intersections # with the bounding line and connect them by an edge. # Currently I consider such cases as rare, so this is a low priority issue. # Btw, such edges do not fall under definition of either "bounding edge" # or "hanging edge"; so should we add a separate checkbox for such edges?... if self.draw_bounds and bounding_verts: bounding_verts.sort( key=lambda idx: atan2(bm.verts[idx][1], bm.verts[idx][0])) for i, j in zip(bounding_verts, bounding_verts[1:]): bm.new_edge(i, j) bm.new_edge(bounding_verts[-1], bounding_verts[0]) for i, j in edges_to_remove: bm.remove_edge(i, j) for vert_idx in verts_to_remove: bm.verts[vert_idx] = None verts, edges = bm.to_pydata() verts3d = [(vert[0], vert[1], 0) for vert in verts] pts_out.append(verts3d) edges_out.append(edges) #edges_out.append(finite_edges) # outputs self.outputs['Vertices'].sv_set(pts_out) self.outputs['Edges'].sv_set(edges_out)