def process(self): if not any(socket.is_linked for socket in self.outputs): return if not self.inputs['Vertices'].is_linked: return vertices_s = self.inputs['Vertices'].sv_get() vertices_s = ensure_nesting_level(vertices_s, 4) surfaces = self.inputs['Surface'].sv_get() surfaces = ensure_nesting_level(surfaces, 4) objects = match_long_repeat([vertices_s, surfaces]) result_vertices = [] for vertices, surface in zip(*objects): if self.transpose: surface = transpose_list(surface) #print("Surface: {} of {} of {}".format(type(surface), type(surface[0]), type(surface[0][0]))) spline = self.build_spline(surface) # uv_coords will be list[m] of lists[n] of 2-tuples of floats # number of "rows" and "columns" in uv_coords will match so of vertices. src_size_u, src_size_v, uv_coords = self.get_uv(vertices) if self.autoscale: u_index, v_index = self.get_other_axes() surface_flattened = [v for col in surface for v in col] scale_u = diameter(surface_flattened, u_index) / src_size_u scale_v = diameter(surface_flattened, v_index) / src_size_v scale_z = sqrt(scale_u * scale_v) else: scale_z = 1.0 if self.flip: scale_z = -scale_z new_vertices = [] for uv_row, vertices_row in zip(uv_coords, vertices): new_row = [] for ((u, v), src_vertex) in zip(uv_row, vertices_row): #print("UV: ({}, {}), SRC: {}".format(u, v, src_vertex)) spline_vertex = np.array(spline.eval(u, v)) spline_normal = np.array( spline.normal(u, v, h=self.normal_precision)) #print("Spline: M {}, N {}".format(spline_vertex, spline_normal)) # Coordinate of source vertex corresponding to orientation axis z = src_vertex[self.orient_axis] new_vertex = tuple(spline_vertex + scale_z * z * spline_normal) new_row.append(new_vertex) new_vertices.append(new_row) result_vertices.append(new_vertices) if not self.grouped: result_vertices = result_vertices[0] self.outputs['Vertices'].sv_set(result_vertices)
def process(self): if not any(socket.is_linked for socket in self.outputs): return if not self.inputs['Vertices'].is_linked: return vertices_s = self.inputs['Vertices'].sv_get() vertices_s = ensure_nesting_level(vertices_s, 4) surfaces = self.inputs['Surface'].sv_get() surfaces = ensure_nesting_level(surfaces, 4) objects = match_long_repeat([vertices_s, surfaces]) result_vertices = [] for vertices, surface in zip(*objects): if self.transpose: surface = transpose_list(surface) #print("Surface: {} of {} of {}".format(type(surface), type(surface[0]), type(surface[0][0]))) spline = self.build_spline(surface) # uv_coords will be list[m] of lists[n] of 2-tuples of floats # number of "rows" and "columns" in uv_coords will match so of vertices. src_size_u, src_size_v, uv_coords = self.get_uv(vertices) if self.autoscale: u_index, v_index = self.get_other_axes() surface_flattened = [v for col in surface for v in col] scale_u = diameter(surface_flattened, u_index) / src_size_u scale_v = diameter(surface_flattened, v_index) / src_size_v scale_z = sqrt(scale_u * scale_v) else: scale_z = 1.0 if self.flip: scale_z = - scale_z new_vertices = [] for uv_row, vertices_row in zip(uv_coords,vertices): new_row = [] for ((u, v), src_vertex) in zip(uv_row, vertices_row): #print("UV: ({}, {}), SRC: {}".format(u, v, src_vertex)) spline_vertex = np.array(spline.eval(u, v)) spline_normal = np.array(spline.normal(u, v, h=self.normal_precision)) #print("Spline: M {}, N {}".format(spline_vertex, spline_normal)) # Coordinate of source vertex corresponding to orientation axis z = src_vertex[self.orient_axis] new_vertex = tuple(spline_vertex + scale_z * z * spline_normal) new_row.append(new_vertex) new_vertices.append(new_row) result_vertices.append(new_vertices) if not self.grouped: result_vertices = result_vertices[0] self.outputs['Vertices'].sv_set(result_vertices)
def test_diameter_2(self): p1 = (0, 0, 0) p2 = (0, 1, 0) p3 = (1, 0, 0) diam = diameter([p1, p2, p3], None) expected = sqrt(2) self.assert_sverchok_data_equal(diam, expected, precision=8)
def test_diameter_3(self): p1 = (0, 0, 0) p2 = (0, 1, 0) p3 = (1, 0, 0) direction = (1, 0, 0) diam = diameter([p1, p2, p3], direction) expected = 1 self.assert_sverchok_data_equal(diam, expected, precision=8)
def duplicate_vertices(self, v1, v2, vertices, edges, faces, count, p): direction = v2 - v1 edge_length = (1.0 - 2 * p) * direction.length one_item_length = edge_length / count actual_length = diameter(vertices, self.orient_axis) if actual_length != 0.0: x_scale = one_item_length / actual_length else: x_scale = 1.0 x = all_axes[self.orient_axis] # for actual_length = 1.0 and edge_length = 3.0, let origins be [0.5, 1.5, 2.5] u = direction.normalized() alphas = np.linspace(0.0, 1.0, count + 1) origins = [ v1 + (1 - 2 * p) * direction * alpha + p * direction + 0.5 * one_item_length * u for alpha in alphas ][:-1] assert len(origins) == count if self.scale_off: scale = None else: if self.scale_all: scale = Matrix.Scale(x_scale, 4) else: scale = Matrix.Scale(x_scale, 4, x) need_flip = False if self.algorithm == 'householder': rot = autorotate_householder(x, direction).inverted() # Since Householder transformation is reflection, we need to reflect things back need_flip = True elif self.algorithm == 'track': rot = autorotate_track(self.orient_axis_, direction, self.up_axis) elif self.algorithm == 'diff': rot = autorotate_diff(x, direction).inverted() else: raise Exception("Unsupported algorithm") if need_flip: flip = Matrix([[-1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) else: flip = Matrix.Identity(4) if scale is None: matrices = [Matrix.Translation(o) * rot * flip for o in origins] else: matrices = [ Matrix.Translation(o) * rot * scale * flip for o in origins ] if self.apply_matrices: result_vertices = [[m * vertex for vertex in vertices] for m in matrices] else: result_vertices = [vertices] * count return matrices, result_vertices
def duplicate_vertices(self, v1, v2, vertices, edges, faces, count, p): direction = v2 - v1 edge_length = (1.0 - 2*p) * direction.length one_item_length = edge_length / count actual_length = diameter(vertices, self.orient_axis) if actual_length != 0.0: x_scale = one_item_length / actual_length else: x_scale = 1.0 x = all_axes[self.orient_axis] # for actual_length = 1.0 and edge_length = 3.0, let origins be [0.5, 1.5, 2.5] u = direction.normalized() alphas = np.linspace(0.0, 1.0, count+1) origins = [v1 + (1-2*p)*direction*alpha + p*direction + 0.5*one_item_length*u for alpha in alphas][:-1] assert len(origins) == count if self.scale_off: scale = None else: if self.scale_all: scale = Matrix.Scale(x_scale, 4) else: scale = Matrix.Scale(x_scale, 4, x) need_flip = False if self.algorithm == 'householder': rot = autorotate_householder(x, direction).inverted() # Since Householder transformation is reflection, we need to reflect things back need_flip = True elif self.algorithm == 'track': rot = autorotate_track(self.orient_axis_, direction, self.up_axis) elif self.algorithm == 'diff': rot = autorotate_diff(x, direction).inverted() else: raise Exception("Unsupported algorithm") if need_flip: flip = Matrix([[-1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]) else: flip = Matrix.Identity(4) if scale is None: matrices = [Matrix.Translation(o)*rot*flip for o in origins] else: matrices = [Matrix.Translation(o)*rot*scale*flip for o in origins] if self.apply_matrices: result_vertices = [[m * vertex for vertex in vertices] for m in matrices] else: result_vertices = [vertices] * count return matrices, result_vertices
def scale_cells(self, verts, sites, insets, precision): if all(i == 0.0 for i in insets): return verts verts_out = [] for vs, site, inset in zip(verts, sites, insets): if inset >= 1.0: continue if self.scale_center == 'SITE': c = site else: c = center(vs) vs1 = scale_relative(vs, c, 1.0 - inset) if diameter(vs1, axis=None) <= precision: continue verts_out.append(vs1) return verts_out
def process(self): if not self.inputs['Vertices'].is_linked: return if not any(s.is_linked for s in self.outputs): return any_direction = not self.inputs['Direction'].is_linked out_results = [] vertices_s = self.inputs['Vertices'].sv_get(default=[[]]) directions_s = self.inputs['Direction'].sv_get(default=[[]]) objects = match_long_repeat([vertices_s, directions_s]) for vertices, directions in zip(*objects): if any_direction: direction = None else: direction = directions[0] diam = diameter(vertices, direction) out_results.append([diam]) self.outputs['Diameter'].sv_set(out_results)
def count_down(self, edge_length, vertices, count): donor_size = diameter(vertices, self.orient_axis) if donor_size == 0.0: return 1 return ceil(edge_length / donor_size)
def _process(self, verts_recpt, faces_recpt, verts_donor, faces_donor, face_data_donor, frame_widths, zcoefs, zoffsets, zrotations, wcoefs, facerots, mask): bm = bmesh_from_pydata(verts_recpt, [], faces_recpt, normal_update=True) bm.verts.ensure_lookup_table() single_donor = self.matching_mode == 'LONG' frame_level = get_data_nesting_level(frame_widths) if single_donor: # Original (unrotated) donor vertices donor_verts_o = [Vector(v) for v in verts_donor] verts_donor = [verts_donor] faces_donor = [faces_donor] face_data_donor = [face_data_donor] if frame_level == 0: frame_widths = [frame_widths] n_faces_recpt = len(faces_recpt) fullList(verts_donor, n_faces_recpt) fullList(faces_donor, n_faces_recpt) fullList(face_data_donor, n_faces_recpt) fullList(frame_widths, n_faces_recpt) X, Y = self.get_other_axes() Z = self.normal_axis_idx() donor = DonorData() # Vertices of the unit triangle. # In case xy_mode != BOUNDS, we will never # have to recalculate these. if self.tri_bound_mode == 'EQUILATERAL': donor.tri_vert_1 = self.from2d(-0.5, -sqrt_3_6) donor.tri_vert_2 = self.from2d(0.5, -sqrt_3_6) donor.tri_vert_3 = self.from2d(0, sqrt_3_3) else: donor.tri_vert_1 = self.from2d(-1, 0) donor.tri_vert_2 = self.from2d(1, 0) donor.tri_vert_3 = self.from2d(0, 1) if single_donor: # We will be rotating the donor object around Z axis, # so it's size along Z is not going to change. z_size = diameter(donor_verts_o, Z) output = OutputData() prev_angle = None face_data = zip(faces_recpt, bm.faces, frame_widths, verts_donor, faces_donor, face_data_donor, zcoefs, zoffsets, zrotations, wcoefs, facerots, mask) recpt_face_idx = 0 for recpt_face, recpt_face_bm, frame_width, donor_verts_i, donor_faces_i, donor_face_data_i, zcoef, zoffset, angle, wcoef, facerot, m in face_data: recpt_face_data = RecptFaceData() recpt_face_data.index = recpt_face_idx recpt_face_data.normal = recpt_face_bm.normal recpt_face_data.center = recpt_face_bm.calc_center_median() recpt_face_data.vertices_co = [bm.verts[i].co for i in recpt_face] if self.use_shell_factor: recpt_face_data.vertices_normal = [bm.verts[i].normal * bm.verts[i].calc_shell_factor() for i in recpt_face] else: recpt_face_data.vertices_normal = [bm.verts[i].normal for i in recpt_face] recpt_face_data.vertices_idxs = recpt_face[:] if not isinstance(frame_width, (int, float)): raise Exception(f"Unexpected data type for frame_width: {frame_width}") recpt_face_data.frame_width = frame_width donor.faces_i = donor_faces_i donor.face_data_i = donor_face_data_i if not single_donor: # Original (unrotated) donor vertices donor_verts_o = [Vector(v) for v in donor_verts_i] z_size = diameter(donor_verts_o, Z) # We have to recalculate rotated vertices only if # the rotation angle have changed. if prev_angle is None or angle != prev_angle or not single_donor: donor.verts_v = self.rotate_z(donor_verts_o, angle) if self.xy_mode == 'BOUNDS' or self.z_scale == 'AUTO' : donor.max_x = max(v[X] for v in donor.verts_v) donor.min_x = min(v[X] for v in donor.verts_v) donor.max_y = max(v[Y] for v in donor.verts_v) donor.min_y = min(v[Y] for v in donor.verts_v) if self.xy_mode == 'BOUNDS': donor.tri_vert_1, donor.tri_vert_2, donor.tri_vert_3 = self.bounding_triangle(donor.verts_v) prev_angle = angle if self.z_scale == 'CONST': if abs(z_size) < 1e-6: zcoef = 0 else: zcoef = zcoef / z_size # Define TRI/QUAD mode based on node settings. n = len(recpt_face) if not m: map_mode = self.mask_mode else: if n == 3: if self.frame_mode == 'ALWAYS': map_mode = 'FRAME' else: if self.map_mode == 'QUADTRI': map_mode = 'TRI' else: # self.map_mode == 'QUADS': map_mode = 'QUAD' elif n == 4: if self.frame_mode in ['ALWAYS', 'NGONQUAD']: map_mode = 'FRAME' else: map_mode = 'QUAD' else: if self.frame_mode in ['ALWAYS', 'NGONQUAD', 'NGONS']: map_mode = 'FRAME' else: if self.ngon_mode == 'QUADS': map_mode = 'QUAD' elif self.ngon_mode == 'ASIS': map_mode = 'ASIS' else: map_mode = 'SKIP' if map_mode == 'SKIP': # Skip this recipient's face - do not produce any vertices/faces for it continue self._process_face(map_mode, output, recpt_face_data, donor, zcoef, zoffset, angle, wcoef, facerot) recpt_face_idx += 1 bm.free() return output
def count_down(self, edge_length, vertices, count): donor_size = diameter(vertices, self.orient_axis) if donor_size == 0.0: return 1 return ceil( edge_length / donor_size )
def test_diameter_1(self): p1 = (0, 0, 0) p2 = (0, 1, 0) diam = diameter([p1, p2], None) expected = 1.0 self.assert_sverchok_data_equal(diam, expected, precision=8)