示例#1
0
        def process(self):

            if not self.inputs['Vertices'].is_linked:
                return

            if not self.outputs['Vertices'].is_linked:
                return

            vertices_s = self.inputs['Vertices'].sv_get()
            points_s = self.inputs['GridPoints'].sv_get()
            smooth_s = self.inputs['Smooth'].sv_get()
            degree_s = self.inputs['Degree'].sv_get()
            weights_s = self.inputs['Weights'].sv_get(default=[[1.0]])
            matrices_s = self.inputs['Matrix'].sv_get(default=[[Matrix()]])

            verts_out = []
            edges_out = []
            faces_out = []
            for vertices, weights, degree, matrix, smooth, grid_points in zip_long_repeat(
                    vertices_s, weights_s, degree_s, matrices_s, smooth_s,
                    points_s):
                if isinstance(grid_points, (list, tuple)):
                    grid_points = grid_points[0]
                if isinstance(degree, (list, tuple)):
                    degree = degree[0]
                if isinstance(smooth, (list, tuple)):
                    smooth = smooth[0]
                if isinstance(matrix, list):
                    matrix = matrix[0]
                has_matrix = matrix is not None and matrix != Matrix()

                fullList(weights, len(vertices))

                smooth = smooth * len(vertices)

                XYZ = np.array(vertices)
                if has_matrix:
                    np_matrix = np.array(matrix.to_3x3())
                    inv_matrix = np.linalg.inv(np_matrix)
                    #print(matrix)
                    #print(XYZ)
                    translation = np.array(matrix.translation)
                    XYZ = np.matmul(inv_matrix, XYZ.T).T + translation
                if self.orientation == 'X':
                    reorder = np.array([1, 2, 0])
                    XYZ = XYZ[:, reorder]
                elif self.orientation == 'Y':
                    reorder = np.array([2, 0, 1])
                    XYZ = XYZ[:, reorder]
                else:  # Z
                    pass

                x_min = XYZ[:, 0].min()
                x_max = XYZ[:, 0].max()
                y_min = XYZ[:, 1].min()
                y_max = XYZ[:, 1].max()
                xi = np.linspace(x_min, x_max, grid_points)
                yi = np.linspace(y_min, y_max, grid_points)
                XI, YI = np.meshgrid(xi, yi)

                spline = SmoothBivariateSpline(XYZ[:, 0],
                                               XYZ[:, 1],
                                               XYZ[:, 2],
                                               kx=degree,
                                               ky=degree,
                                               w=weights,
                                               s=smooth)
                ZI = spline(xi, yi)

                if self.orientation == 'X':
                    YI, ZI, XI = XI, YI, ZI
                elif self.orientation == 'Y':
                    ZI, XI, YI = XI, YI, ZI
                else:  # Z
                    pass

                new_verts = np.dstack((YI, XI, ZI))
                if has_matrix:
                    new_verts = new_verts - translation
                    new_verts = np.apply_along_axis(lambda v: np_matrix @ v, 2,
                                                    new_verts)
                new_verts = new_verts.tolist()
                new_verts = sum(new_verts, [])
                new_edges = self.make_edges(grid_points)
                new_faces = self.make_faces(grid_points)
                verts_out.append(new_verts)
                edges_out.append(new_edges)
                faces_out.append(new_faces)

            self.outputs['Vertices'].sv_set(verts_out)
            self.outputs['Edges'].sv_set(edges_out)
            self.outputs['Faces'].sv_set(faces_out)
示例#2
0
    """
    Find vector rotation according to X axis.
    :arg vec: Input vector.
    :type vec: :class:'mathutils.Vector'
    :return: Angle in radians.
    :rtype: float
    """
    v0 = Vector((1,0))
    ang = Vector.angle_signed(vec, v0)
    if ang < 0: ang = 2*pi + ang
    return ang

verts_out = []
edges_out = []
faces_out = []
for verts, edges, faces, thickness, subdivisions in zip_long_repeat(verts_in, edges_in, faces_in, thickness_in, subdivisions_in):
    if isinstance(thickness, (list, tuple)):
        thickness = thickness[0]
    if isinstance(subdivisions, (list, tuple)):
        subdivisions = subdivisions[0]
    #faces = list(set([tuple(f) for f in faces]))
    uniq_faces = []
    for face in faces:
        if set(face) in [set(f) for f in uniq_faces]:
            pass
            #print(face)
        else:
            uniq_faces.append(face)
    bm = bmesh_from_pydata(verts, [], uniq_faces, normal_update=True)
    
    merge_dist = thickness*0.001
示例#3
0
    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        surfaces_s = self.inputs['Surface'].sv_get()
        surface_level = get_data_nesting_level(surfaces_s,
                                               data_types=(SvSurface, ))
        surfaces_s = ensure_nesting_level(surfaces_s,
                                          2,
                                          data_types=(SvSurface, ))
        src_point_s = self.inputs['UVPoints'].sv_get(default=[[]])
        src_point_s = ensure_nesting_level(src_point_s, 4)

        src_u_s = self.inputs['U'].sv_get()
        src_u_s = ensure_nesting_level(src_u_s, 3)
        src_v_s = self.inputs['V'].sv_get()
        src_v_s = ensure_nesting_level(src_v_s, 3)

        normal_out = []
        tangent_u_out = []
        tangent_v_out = []
        matrix_out = []
        area_out = []
        du_out = []
        dv_out = []

        for surfaces, src_points_i, src_u_i, src_v_i in zip_long_repeat(
                surfaces_s, src_point_s, src_u_s, src_v_s):
            new_normals = []
            new_tangent_u = []
            new_tangent_v = []
            new_area = []
            new_du = []
            new_dv = []
            for surface, src_points, src_us, src_vs in zip_long_repeat(
                    surfaces, src_points_i, src_u_i, src_v_i):
                if self.input_mode == 'VERTICES':
                    us, vs = self.parse_input(src_points)
                else:
                    maxlen = max(len(src_us), len(src_vs))
                    src_us = repeat_last_for_length(src_us, maxlen)
                    src_vs = repeat_last_for_length(src_vs, maxlen)
                    us, vs = np.array(src_us), np.array(src_vs)

                data = surface.derivatives_data_array(us, vs)

                new_normals.append(data.unit_normals().tolist())
                du, dv = data.unit_tangents()
                new_tangent_u.append(du.tolist())
                new_tangent_v.append(dv.tolist())

                normals_len = [n[0] for n in data.normals_len().tolist()]
                new_area.append(normals_len)

                du_len, dv_len = data.tangent_lens()
                du_len = [n[0] for n in du_len.tolist()]
                dv_len = [n[0] for n in dv_len.tolist()]
                new_du.append(du_len)
                new_dv.append(dv_len)

                matrix_out.extend(data.matrices(as_mathutils=True))

            normal_out.append(new_normals)
            tangent_u_out.append(new_tangent_u)
            tangent_v_out.append(new_tangent_v)
            area_out.append(new_area)
            if surface_level == 2:
                du_out.append(new_du)
                dv_out.append(new_dv)
            else:
                du_out.extend(new_du)
                dv_out.extend(new_dv)

        self.outputs['Normal'].sv_set(normal_out)
        self.outputs['TangentU'].sv_set(tangent_u_out)
        self.outputs['TangentV'].sv_set(tangent_v_out)
        self.outputs['Matrix'].sv_set(matrix_out)
        self.outputs['AreaStretch'].sv_set(area_out)
        self.outputs['StretchU'].sv_set(du_out)
        self.outputs['StretchV'].sv_set(dv_out)
示例#4
0
    def process(self):

        if not any(socket.is_linked for socket in self.outputs):
            return

        solid_in = self.inputs['Solid'].sv_get()
        sites_in = self.inputs['Sites'].sv_get()
        inset_in = self.inputs['Inset'].sv_get()

        solid_in = ensure_nesting_level(solid_in, 2, data_types=(Part.Shape,))
        input_level = get_data_nesting_level(sites_in)
        sites_in = ensure_nesting_level(sites_in, 4)
        inset_in = ensure_min_nesting(inset_in, 2)

        nested_output = input_level > 3
        need_inner = self.outputs['InnerSolid'].is_linked
        need_outer = self.outputs['OuterSolid'].is_linked

        precision = 10 ** (-self.accuracy)

        inner_fragments_out = []
        outer_fragments_out = []
        for params in zip_long_repeat(solid_in, sites_in, inset_in):
            new_inner_fragments = []
            new_outer_fragments = []
            for solid, sites, inset in zip_long_repeat(*params):
                verts, edges, faces = voronoi_on_solid(solid, sites,
                            do_clip=True, clipping=None)

                if isinstance(inset, list):
                    inset = repeat_last_for_length(inset, len(sites))
                else:
                    inset = [inset for i in range(len(sites))]
                verts = self.scale_cells(verts, sites, inset, precision)
                fragments = [svmesh_to_solid(vs, fs, precision, method=BMESH, remove_splitter=False) for vs, fs in zip(verts, faces)]

                if self.mode == 'SURFACE':
                    if solid.Shells:
                        shell = solid.Shells[0]
                    else:
                        shell = Part.Shell(solid.Faces)
                    src = shell
                else: # VOLUME
                    src = solid

                if need_inner:
                    inner = [src.common(fragment) for fragment in fragments]
                    if self.flat_output:
                        new_inner_fragments.extend(inner)
                    else:
                        new_inner_fragments.append(inner)

                if need_outer:
                    outer = [src.cut(fragments)]
                    if self.flat_output:
                        new_outer_fragments.extend(outer)
                    else:
                        new_outer_fragments.append(outer)

            if nested_output:
                inner_fragments_out.append(new_inner_fragments)
                outer_fragments_out.append(new_outer_fragments)
            else:
                inner_fragments_out.extend(new_inner_fragments)
                outer_fragments_out.extend(new_outer_fragments)

        self.outputs['InnerSolid'].sv_set(inner_fragments_out)
        self.outputs['OuterSolid'].sv_set(outer_fragments_out)
示例#5
0
        def process(self):
            if not any(socket.is_linked for socket in self.outputs):
                return

            field_s = self.inputs['Field'].sv_get()
            bounds_s = self.inputs['Bounds'].sv_get()
            samples_xy_s = self.inputs['SamplesXY'].sv_get()
            samples_z_s = self.inputs['SamplesZ'].sv_get()
            samples_value_s = self.inputs['ValueSamples'].sv_get()

            verts_out = []
            edges_out = []
            faces_out = []

            inputs = zip_long_repeat(field_s, bounds_s, samples_xy_s,
                                     samples_z_s, samples_value_s)
            for field, bounds, samples_xy, samples_z, samples_value in inputs:
                if isinstance(samples_xy, (list, tuple)):
                    samples_xy = samples_xy[0]
                if isinstance(samples_z, (list, tuple)):
                    samples_z = samples_z[0]
                if isinstance(samples_value, (list, tuple)):
                    samples_value = samples_value[0]

                b1, b2 = self.get_bounds(bounds)
                min_x, max_x = b1[0], b2[0]
                min_y, max_y = b1[1], b2[1]
                min_z, max_z = b1[2], b2[2]

                x_size = (max_x - min_x) / samples_xy
                y_size = (max_y - min_y) / samples_xy

                x_range = np.linspace(min_x, max_x, num=samples_xy)
                y_range = np.linspace(min_y, max_y, num=samples_xy)
                z_range = np.linspace(min_z, max_z, num=samples_z)
                xs, ys, zs = np.meshgrid(x_range,
                                         y_range,
                                         z_range,
                                         indexing='ij')
                xs, ys, zs = xs.flatten(), ys.flatten(), zs.flatten()
                field_values = field.evaluate_grid(xs, ys, zs)
                min_field = field_values.min()
                max_field = field_values.max()
                field_values = field_values.reshape(
                    (samples_xy, samples_xy, samples_z))
                field_stops = np.linspace(min_field,
                                          max_field,
                                          num=samples_value)

                new_verts = []
                new_edges = []
                new_faces = []
                for i in range(samples_z):
                    z_value = zs[i]
                    z_verts = []
                    z_edges = []
                    z_faces = []
                    for j in range(samples_value):
                        value = field_stops[j]
                        contours = measure.find_contours(field_values[:, :, i],
                                                         level=value)

                        value_verts, value_edges, value_faces = make_contours(
                            samples_xy,
                            samples_xy,
                            min_x,
                            x_size,
                            min_y,
                            y_size,
                            z_value,
                            contours,
                            make_faces=self.make_faces,
                            connect_bounds=self.connect_bounds)
                        if value_verts:
                            z_verts.extend(value_verts)
                            z_edges.extend(value_edges)
                            z_faces.extend(value_faces)

                    new_verts.extend(z_verts)
                    new_edges.extend(z_edges)
                    new_faces.extend(z_faces)

                if self.join:
                    new_verts, new_edges, new_faces = mesh_join(
                        new_verts, new_edges, new_faces)

                    verts_out.append(new_verts)
                    edges_out.append(new_edges)
                    faces_out.append(new_faces)
                else:
                    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 process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        obj_vertices_s = self.inputs['ObjVertices'].sv_get()
        obj_edges_s = self.inputs['ObjEdges'].sv_get(default=[[]])
        obj_faces_s = self.inputs['ObjFaces'].sv_get()
        surf_vertices_s = self.inputs['SurfVertices'].sv_get()
        surf_edges_s = self.inputs['SurfEdges'].sv_get(default=[[]])
        surf_faces_s = self.inputs['SurfFaces'].sv_get()
        fill_sides_s = self.inputs['FillSides'].sv_get()

        def remember_connection(edges_by_face, bm_edge, bm_intersection):
            for face in bm_edge.link_faces:
                edges_by_face[face].append((bm_intersection, bm_edge.index))

        cut_verts_out = []
        cut_edges_out = []
        cut_faces_out = []
        obj_verts_out = []
        obj_edges_out = []
        obj_faces_out = []
        inputs = zip_long_repeat(obj_vertices_s, obj_edges_s, obj_faces_s,
                                 surf_vertices_s, surf_edges_s, surf_faces_s,
                                 fill_sides_s)
        for obj_vertices, obj_edges, obj_faces, surf_vertices, surf_edges, surf_faces, fill_sides in inputs:
            if self.fill:
                if isinstance(fill_sides, (list, tuple)):
                    fill_sides = fill_sides[0]

            # We are using bvh's raycast to calculate intersections of object's edges
            # with the surface.
            bvh = mathutils.bvhtree.BVHTree.FromPolygons(
                surf_vertices, surf_faces)
            bm_obj = bmesh_from_pydata(obj_vertices, obj_edges, obj_faces)
            bm_cut = bmesh.new()
            edges_by_face = defaultdict(list)
            bm_obj.verts.index_update()
            bm_obj.edges.index_update()
            for bm_edge in bm_obj.edges:
                v1, v2 = bm_edge.verts
                edge = v1.co - v2.co
                # Distance restriction is used to find only intersections which are within the edge,
                # not anywhere on the ray.
                distance = edge.length

                # Since raycast's ray is single-directioned, we have to check for intersections
                # twice: from V1 to V2 and from V2 to V1.
                cast = bvh.ray_cast(v1.co, -edge, distance)
                #self.debug("Edge %s: %s -> %s, Cast 0: %s", bm_edge.index, v1.co, edge, cast)
                intersection = cast[0]
                if intersection is not None:
                    bm_intersection = bm_cut.verts.new(intersection)
                    remember_connection(edges_by_face, bm_edge,
                                        bm_intersection)
                else:
                    cast = bvh.ray_cast(v2.co, edge, distance)
                    #self.debug("Edge %s: %s -> %s, Cast 1: %s", bm_edge.index, v2.co, -edge, cast)
                    intersection = cast[0]
                    if intersection is not None:
                        bm_intersection = bm_cut.verts.new(intersection)
                        remember_connection(edges_by_face, bm_edge,
                                            bm_intersection)

            bm_cut.verts.index_update()

            # Make "cut surface" object.
            # Of each object's face we are cutting, make an edge.
            bm_cut_edges = []
            for intersections in edges_by_face.values():
                if len(intersections) == 1:
                    self.debug(
                        "Only one of object face's edges intersects the surface"
                    )
                    continue
                if len(intersections) > 2:
                    # Some day we may support splitting the face in more than two pieces;
                    # but the algorithm will be more complicated then.
                    raise Exception(
                        "Unsupported: more than two edges of the face intersect the surface"
                    )
                v1, v2 = intersections[0][0], intersections[1][0]
                bm_edge = bm_cut.edges.new((v1, v2))
                bm_cut_edges.append(bm_edge)

            if len(bm_cut.verts) > 0:
                if self.fill:
                    bmesh.ops.holes_fill(bm_cut,
                                         edges=bm_cut_edges,
                                         sides=fill_sides)

            new_verts_cut, new_edges_cut, new_faces_cut = pydata_from_bmesh(
                bm_cut)

            if self.make_pieces:
                new_verts_by_old_edge = dict()
                new_verts_by_old_face = dict()
                for old_obj_face in edges_by_face:
                    intersections = edges_by_face[old_obj_face]
                    if len(intersections) == 1:
                        continue
                    int1, int2 = intersections
                    intersection1, intersection2 = int1[0].co, int2[0].co
                    old_edge1, old_edge2 = int1[1], int2[1]
                    # Create a vertex in the "object" mesh at each intersection of
                    # it's edge with the surface.
                    # Remember which of new vertices corresponds to which edge.
                    if old_edge1 not in new_verts_by_old_edge:
                        new_vert_1 = bm_obj.verts.new(intersection1)
                        new_verts_by_old_edge[old_edge1] = new_vert_1
                    else:
                        new_vert_1 = new_verts_by_old_edge[old_edge1]
                    if old_edge2 not in new_verts_by_old_edge:
                        new_vert_2 = bm_obj.verts.new(intersection2)
                        new_verts_by_old_edge[old_edge2] = new_vert_2
                    else:
                        new_vert_2 = new_verts_by_old_edge[old_edge2]
                    new_verts_by_old_face[old_obj_face] = (new_vert_1,
                                                           new_vert_2)
                    bm_obj.verts.index_update()

                faces_to_remove = []
                edges_to_remove = []
                for old_obj_face in edges_by_face:
                    intersections = edges_by_face[old_obj_face]
                    if len(intersections) == 1:
                        continue

                    # Walk through the edges of each face we are cutting, in order.
                    # Of each such face, we are making two. So in this loop we have
                    # two states: new_face_state == True means we are on the one side of
                    # the cut, False means we are on the another. Note that we do not know
                    # which is which (for example, which one is "inside" the surface); but
                    # it does not matter for us.
                    # So new_face_verts[True] will contain vertices of one piece,
                    # new_face_verts[False] - of another one.
                    new_face_verts = defaultdict(list)
                    new_face_side = True
                    old_vert_pairs = list(
                        zip(old_obj_face.verts, old_obj_face.verts[1:])) + [
                            (old_obj_face.verts[-1], old_obj_face.verts[0])
                        ]
                    need_split = False
                    for old_vert_1, old_vert_2 in old_vert_pairs:
                        old_edge = bm_obj.edges.get((old_vert_1, old_vert_2))
                        if old_edge.index in new_verts_by_old_edge:
                            edges_to_remove.append(
                                (old_edge.verts[0], old_edge.verts[1]))
                            need_split = True
                            new_vert_1 = new_verts_by_old_edge[old_edge.index]
                            self.debug(
                                "Old edge %s - %s is to be split; use new vert %s",
                                old_vert_1.index, old_vert_2.index,
                                new_vert_1.index)
                            new_face_verts[new_face_side].append(new_vert_1)
                            # if this edge is to be split, then we are stepping from one piece of
                            # the face to another
                            new_face_side = not new_face_side
                            new_face_verts[new_face_side].append(new_vert_1)
                            new_face_verts[new_face_side].append(old_vert_2)
                        else:
                            self.debug("Old edge %s - %s is not to be split",
                                       old_vert_1.index, old_vert_2.index)
                            new_face_verts[new_face_side].append(old_vert_2)

                    if need_split:
                        faces_to_remove.append(old_obj_face)
                        self.debug("Splitting face: %s",
                                   [v.index for v in old_obj_face.verts])
                        for new_face_list in new_face_verts.values():
                            bm_obj.faces.new(new_face_list)

                # remove old faces and edges (ones we cut in two)
                for old_face in faces_to_remove:
                    bm_obj.faces.remove(old_face)
                for old_v1, old_v2 in edges_to_remove:
                    # we can't just remember BMEdge instances themselve,
                    # since they will be invalidated when we remove faces.
                    old_edge = bm_obj.edges.get((old_v1, old_v2))
                    if old_edge:
                        bm_obj.edges.remove(old_edge)

                edges_to_split = []
                for new_vert_1, new_vert_2 in new_verts_by_old_face.values():
                    edge = bm_obj.edges.get((new_vert_1, new_vert_2))
                    edges_to_split.append(edge)

                # Split "object" by remembered cut edges. There will be "holes"
                # at places we cut.
                split_result = bmesh.ops.split_edges(bm_obj,
                                                     edges=edges_to_split)
                if self.fill:
                    bmesh.ops.holes_fill(bm_obj,
                                         edges=split_result['edges'],
                                         sides=fill_sides)

                new_verts_obj, new_edges_obj, new_faces_obj = pydata_from_bmesh(
                    bm_obj)
            else:
                new_verts_obj, new_edges_obj, new_faces_obj = [], [], []

            bm_cut.free()
            bm_obj.free()

            cut_verts_out.append(new_verts_cut)
            cut_edges_out.append(new_edges_cut)
            cut_faces_out.append(new_faces_cut)
            obj_verts_out.append(new_verts_obj)
            obj_edges_out.append(new_edges_obj)
            obj_faces_out.append(new_faces_obj)

        self.outputs['CutVertices'].sv_set(cut_verts_out)
        self.outputs['CutEdges'].sv_set(cut_edges_out)
        self.outputs['CutFaces'].sv_set(cut_faces_out)
        self.outputs['ObjVertices'].sv_set(obj_verts_out)
        self.outputs['ObjEdges'].sv_set(obj_edges_out)
        self.outputs['ObjFaces'].sv_set(obj_faces_out)
示例#7
0
        def process(self):
            if not any(socket.is_linked for socket in self.outputs):
                return

            fields_s = self.inputs['Field'].sv_get()
            min_x_s = self.inputs['MinX'].sv_get()
            max_x_s = self.inputs['MaxX'].sv_get()
            min_y_s = self.inputs['MinY'].sv_get()
            max_y_s = self.inputs['MaxY'].sv_get()
            value_s = self.inputs['Value'].sv_get()
            z_value_s = self.inputs['Z'].sv_get()
            samples_s = self.inputs['Samples'].sv_get()
            matrix_s = self.inputs['Matrix'].sv_get(default=[Matrix()])

            if isinstance(value_s[0], (list, tuple)):
                value_s = value_s[0]
            if isinstance(z_value_s[0], (list, tuple)):
                z_value_s = z_value_s[0]

            parameters = zip_long_repeat(fields_s, matrix_s, min_x_s, max_x_s, min_y_s, max_y_s, z_value_s, value_s, samples_s)

            verts_out = []
            edges_out = []
            faces_out = []
            for field, matrix, min_x, max_x, min_y, max_y, z_value, value, samples in parameters:
                if isinstance(samples, (list, tuple)):
                    samples = samples[0]
                if isinstance(value, (list, tuple)):
                    value = value[0]
                if isinstance(min_x, (list, tuple)):
                    min_x = min_x[0]
                if isinstance(max_x, (list, tuple)):
                    max_x = max_x[0]
                if isinstance(min_y, (list, tuple)):
                    min_y = min_y[0]
                if isinstance(max_y, (list, tuple)):
                    max_y = max_y[0]
                if isinstance(z_value, (list, tuple)):
                    z_value = z_value[0]

                has_matrix = matrix != Matrix()

                x_range = np.linspace(min_x, max_x, num=samples)
                y_range = np.linspace(min_y, max_y, num=samples)
                z_range = np.array([z_value])
                xs, ys, zs = np.meshgrid(x_range, y_range, z_range, indexing='ij')
                xs, ys, zs = xs.flatten(), ys.flatten(), zs.flatten()
                if has_matrix:
                    xs, ys, zs = self.apply_matrix(matrix, xs, ys, zs)
                field_values = field.evaluate_grid(xs, ys, zs)
                field_values = field_values.reshape((samples, samples))

                contours = measure.find_contours(field_values, level=value)

                x_size = (max_x - min_x)/samples
                y_size = (max_y - min_y)/samples

                new_verts, new_edges, new_faces = make_contours(samples, min_x, x_size, min_y, y_size, z_value, contours, make_faces=self.make_faces, connect_bounds = self.connect_bounds)
                if has_matrix:
                    new_verts = self.unapply_matrix(matrix, new_verts)
                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)
示例#8
0
    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        solids_out = []
        edge_masks_out = []
        edge_srcs_out = []
        face_masks_out = []
        face_srcs_out = []
        if self.nest_objs:
            solids_in = self.inputs['Solids'].sv_get()
            #level = get_data_nesting_level(solids_in, data_types=(Part.Shape,))
            solids_in = ensure_nesting_level(solids_in,
                                             2,
                                             data_types=(Part.Shape, ))

            for solids in solids_in:
                result = self.make_solid(solids)
                solids_out.append(result.solid)
                edge_masks_out.append(result.edge_mask)
                edge_srcs_out.append(result.edge_map)
                face_masks_out.append(result.face_mask)
                face_srcs_out.append(result.face_map)

        else:
            solids_a_in = self.inputs['Solid A'].sv_get()
            solids_b_in = self.inputs['Solid B'].sv_get()
            level_a = get_data_nesting_level(solids_a_in,
                                             data_types=(Part.Shape, ))
            level_b = get_data_nesting_level(solids_b_in,
                                             data_types=(Part.Shape, ))
            solids_a_in = ensure_nesting_level(solids_a_in,
                                               2,
                                               data_types=(Part.Shape, ))
            solids_b_in = ensure_nesting_level(solids_b_in,
                                               2,
                                               data_types=(Part.Shape, ))
            level = max(level_a, level_b)

            for params in zip_long_repeat(solids_a_in, solids_b_in):
                new_solids = []
                new_edge_masks = []
                new_edge_srcs = []
                new_face_masks = []
                new_face_srcs = []
                for solid_a, solid_b in zip_long_repeat(*params):
                    result = self.make_solid([solid_a, solid_b])
                    new_solids.append(result.solid)
                    new_edge_masks.append(result.edge_mask)
                    new_edge_srcs.append(result.edge_map)
                    new_face_masks.append(result.face_mask)
                    new_face_srcs.append(result.face_map)
                if level == 1:
                    solids_out.extend(new_solids)
                    edge_masks_out.extend(new_edge_masks)
                    edge_srcs_out.extend(new_edge_srcs)
                    face_masks_out.extend(new_face_masks)
                    face_srcs_out.extend(new_face_srcs)
                else:
                    solids_out.append(new_solids)
                    edge_masks_out.append(new_edge_masks)
                    edge_srcs_out.append(new_edge_srcs)
                    face_masks_out.append(new_face_masks)
                    face_srcs_out.append(new_face_srcs)

        self.outputs['Solid'].sv_set(solids_out)
        if 'EdgesMask' in self.outputs:
            self.outputs['EdgesMask'].sv_set(edge_masks_out)
        if 'EdgeSources' in self.outputs:
            self.outputs['EdgeSources'].sv_set(edge_srcs_out)
        if 'FacesMask' in self.outputs:
            self.outputs['FacesMask'].sv_set(face_masks_out)
        if 'FaceSources' in self.outputs:
            self.outputs['FaceSources'].sv_set(face_srcs_out)
示例#9
0
    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        curve_s = self.inputs['Curve'].sv_get()
        surface_s = self.inputs['Surface'].sv_get()
        offset_s = self.inputs['Offset'].sv_get()
        offset_curve_s = self.inputs['OffsetCurve'].sv_get(default=[[None]])

        curve_s = ensure_nesting_level(curve_s, 2, data_types=(SvCurve, ))
        surface_s = ensure_nesting_level(surface_s,
                                         2,
                                         data_types=(SvSurface, ))
        offset_s = ensure_nesting_level(offset_s, 2)
        if self.inputs['OffsetCurve'].is_linked:
            offset_curve_s = ensure_nesting_level(offset_curve_s,
                                                  2,
                                                  data_types=(SvCurve, ))

        curves_out = []
        uv_curves_out = []
        for curves, surfaces, offsets, offset_curves in zip_long_repeat(
                curve_s, surface_s, offset_s, offset_curve_s):
            new_curves = []
            new_uv_curves = []
            for curve, surface, offset, offset_curve in zip_long_repeat(
                    curves, surfaces, offsets, offset_curves):
                if self.offset_type == 'CONST':
                    new_curve = SvCurveOffsetOnSurface(curve,
                                                       surface,
                                                       offset=offset,
                                                       uv_space=False,
                                                       axis=self.curve_axis)
                    new_uv_curve = SvCurveOffsetOnSurface(curve,
                                                          surface,
                                                          offset=offset,
                                                          uv_space=True,
                                                          axis=self.curve_axis)
                else:
                    if offset_curve is None:
                        raise SvNoDataError(socket=self.inputs['OffsetCurve'],
                                            node=self)

                    new_curve = SvCurveOffsetOnSurface(
                        curve,
                        surface,
                        offset_curve=offset_curve,
                        offset_curve_type=self.offset_curve_type,
                        len_resolution=self.len_resolution,
                        uv_space=False,
                        axis=self.curve_axis)
                    new_uv_curve = SvCurveOffsetOnSurface(
                        curve,
                        surface,
                        offset_curve=offset_curve,
                        offset_curve_type=self.offset_curve_type,
                        len_resolution=self.len_resolution,
                        uv_space=True,
                        axis=self.curve_axis)

                new_curves.append(new_curve)
                new_uv_curves.append(new_uv_curve)
            curves_out.append(new_curves)
            uv_curves_out.append(new_uv_curves)

        self.outputs['Curve'].sv_set(curves_out)
        self.outputs['UVCurve'].sv_set(uv_curves_out)
示例#10
0
    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        vertices_s = self.inputs['Vertices'].sv_get()
        edges_s = self.inputs['Edges'].sv_get()
        faces_s = self.inputs['Faces'].sv_get()
        vertex_weight_s = self.inputs['VertexWeight'].sv_get()
        edge_weight_s = self.inputs['EdgeWeight'].sv_get()
        face_weight_s = self.inputs['FaceWeight'].sv_get()
        tangent_weight_s = self.inputs['TangentWeight'].sv_get()
        degree_u_s = self.inputs['DegreeU'].sv_get()
        degree_v_s = self.inputs['DegreeV'].sv_get()
        
        surface_out = []
        control_points_out = []
        weights_out = []
        inputs = zip_long_repeat(vertices_s, edges_s, faces_s, degree_u_s, degree_v_s, vertex_weight_s, edge_weight_s, face_weight_s, tangent_weight_s)
        for vertices, edges, faces, degree_u, degree_v, vertex_weights, edge_weights, face_weights, tangent_weights in inputs:
            fullList(degree_u, len(faces))
            fullList(degree_v, len(faces))

            if not edges:
                edges = polygons_to_edges([faces], True)[0]

            fullList(vertex_weights, len(vertices))
            fullList(tangent_weights, len(vertices))
            fullList(edge_weights, len(edges))
            fullList(face_weights, len(faces))

            bm = bmesh_from_pydata(vertices, edges, faces, normal_update=True, markup_edge_data=True)
            normals = [vertex.normal for vertex in bm.verts]
            edge_planes_dict = dict()
            for edge in bm.edges:
                edge_v = edge.verts[1].co - edge.verts[0].co
                edge_c = (edge.verts[0].co + edge.verts[1].co) / 2.0
                edge_ort_plane = PlaneEquation.from_normal_and_point(edge_v, edge_c)
                face_normals = [face.normal for face in edge.link_faces]
                faces_normal = sum(face_normals, Vector())
                projected_faces_normal = edge_ort_plane.projection_of_point(faces_normal)
                #print("EV: %s, No.sum: %s, Pr.N: %s" % (edge_v, faces_normal, projected_faces_normal))
                edge_plane = PlaneEquation.from_normal_and_point(projected_faces_normal, edge_c)
                edge_planes_dict[(edge.verts[0].index, edge.verts[1].index)] = edge_plane
                edge_planes_dict[(edge.verts[1].index, edge.verts[0].index)] = edge_plane
            bm.free()

            vert_planes = [PlaneEquation.from_normal_and_point(normal, point) for normal, point in zip(normals, vertices)]

            edge_weights_dict = dict()
            #edge_planes_dict = dict()
            for (i, j), edge_weight in zip(edges, edge_weights):
                edge_weights_dict[(i, j)] = edge_weight
                edge_weights_dict[(j, i)] = edge_weight
                #edge_planes_dict[(i, j)] = edge_plane
                #edge_planes_dict[(j, i)] = edge_plane

            for i, (face, degree_u, degree_v, face_weight) in enumerate(zip(faces, degree_u, degree_v, face_weights)):
                if len(face) != 4:
                    self.info("Face #%s is not a Quad, skip it", i)
                    continue
                face_verts = [vertices[i] for i in face]
                face_planes = [vert_planes[i] for i in face]
                face_vert_weights = [vertex_weights[i] for i in face]
                face_tangent_weights = [tangent_weights[i] for i in face]
                #face_edges = list(zip(face, face[1:])) + [(face[-1], face[0])]
                #face_edge_weights = [edge_weights_dict[edge] for edge in face_edges]
                surface, ctrlpts, weights = self.make_surface(face,
                                degree_u, degree_v,
                                face_verts, face_planes,
                                face_vert_weights, face_tangent_weights, face_weight,
                                edge_weights_dict, edge_planes_dict)
                surface_out.append(surface)
                control_points_out.append(list(map(tuple,ctrlpts)))
                weights_out.append(weights)

        self.outputs['Surfaces'].sv_set(surface_out)
        self.outputs['ControlPoints'].sv_set(control_points_out)
        self.outputs['Weights'].sv_set(weights_out)
示例#11
0
        def process(self):
            if not any(socket.is_linked for socket in self.outputs):
                return

            vertices_s = self.inputs['ControlPoints'].sv_get()
            has_weights = self.inputs['Weights'].is_linked
            weights_s = self.inputs['Weights'].sv_get(default = [[1.0]])
            knots_s = self.inputs['Knots'].sv_get(default = [[]])
            degree_s = self.inputs['Degree'].sv_get()

            curves_out = []
            knots_out = []
            for vertices, weights, knots, degree in zip_long_repeat(vertices_s, weights_s, knots_s, degree_s):
                if isinstance(degree, (tuple, list)):
                    degree = degree[0]

                n_source = len(vertices)
                fullList(weights, n_source)
                if self.knot_mode == 'AUTO' and self.is_cyclic:
                    vertices = vertices + vertices[:degree+1]
                    weights = weights + weights[:degree+1]
                n_total = len(vertices)

                # Create a 3-dimensional B-spline Curve
                if self.surface_mode == 'NURBS':
                    curve = NURBS.Curve(normalize_kv = self.normalize_knots)
                else:
                    curve = BSpline.Curve(normalize_kv = self.normalize_knots)

                # Set degree
                curve.degree = degree

                # Set control points (weights vector will be 1 by default)
                # Use curve.ctrlptsw is if you are using homogeneous points as Pw
                curve.ctrlpts = vertices
                if has_weights and self.surface_mode == 'NURBS':
                    curve.weights = weights

                # Set knot vector
                if self.knot_mode == 'AUTO':
                    if self.is_cyclic:
                        self.debug("N: %s, degree: %s", n_total, degree)
                        knots = list(range(n_total + degree + 1))
                    else:
                        knots = knotvector.generate(curve.degree, n_total)
                    self.debug('Auto knots: %s', knots)
                    curve.knotvector = knots
                else:
                    self.debug('Manual knots: %s', knots)
                    #if not knotvector.check(curve.degree, knots, len(curve.ctrlpts)):
                    #    raise Exception("Explicitly provided knot vector is incorrect!")
                    curve.knotvector = knots

                new_curve = SvExGeomdlCurve(curve)
                if self.is_cyclic:
                    u_min = curve.knotvector[degree]
                    u_max = curve.knotvector[-degree-2]
                    new_curve.u_bounds = u_min, u_max
                else:
                    u_min = min(curve.knotvector)
                    u_max = max(curve.knotvector)
                    new_curve.u_bounds = (u_min, u_max)
                curves_out.append(new_curve)
                knots_out.append(curve.knotvector)

            self.outputs['Curve'].sv_set(curves_out)
            self.outputs['Knots'].sv_set(knots_out)
示例#12
0
        def process(self):
            if not any(socket.is_linked for socket in self.outputs):
                return

            fields_s = self.inputs['Field'].sv_get()
            min_x_s = self.inputs['MinX'].sv_get()
            max_x_s = self.inputs['MaxX'].sv_get()
            min_y_s = self.inputs['MinY'].sv_get()
            max_y_s = self.inputs['MaxY'].sv_get()
            value_s = self.inputs['Value'].sv_get()
            z_value_s = self.inputs['Z'].sv_get()
            samples_s = self.inputs['Samples'].sv_get()
            matrix_s = self.inputs['Matrix'].sv_get(default=[Matrix()])

            value_s = ensure_nesting_level(value_s, 2)
            z_value_s = ensure_nesting_level(z_value_s, 2)
            input_level = get_data_nesting_level(fields_s,
                                                 data_types=(SvScalarField, ))
            nested_output = input_level > 1
            fields_s = ensure_nesting_level(fields_s,
                                            2,
                                            data_types=(SvScalarField, ))
            matrix_s = ensure_nesting_level(matrix_s, 2, data_types=(Matrix, ))

            parameters = zip_long_repeat(fields_s, matrix_s, min_x_s, max_x_s,
                                         min_y_s, max_y_s, z_value_s, value_s,
                                         samples_s)

            verts_out = []
            edges_out = []
            faces_out = []
            for field_i, matrix_i, min_x_i, max_x_i, min_y_i, max_y_i, z_value_i, value_i, samples_i in parameters:
                new_verts = []
                new_edges = []
                new_faces = []
                objects = zip_long_repeat(field_i, matrix_i, min_x_i, max_x_i,
                                          min_y_i, max_y_i, z_value_i, value_i,
                                          samples_i)
                for field, matrix, min_x, max_x, min_y, max_y, z_value, value, samples in objects:

                    has_matrix = matrix != Matrix()

                    x_range = np.linspace(min_x, max_x, num=samples)
                    y_range = np.linspace(min_y, max_y, num=samples)
                    z_range = np.array([z_value])
                    xs, ys, zs = np.meshgrid(x_range,
                                             y_range,
                                             z_range,
                                             indexing='ij')
                    xs, ys, zs = xs.flatten(), ys.flatten(), zs.flatten()
                    if has_matrix:
                        xs, ys, zs = self.apply_matrix(matrix, xs, ys, zs)
                    field_values = field.evaluate_grid(xs, ys, zs)
                    field_values = field_values.reshape((samples, samples))

                    contours = measure.find_contours(field_values, level=value)

                    x_size = (max_x - min_x) / samples
                    y_size = (max_y - min_y) / samples

                    value_verts, value_edges, value_faces = make_contours(
                        samples,
                        samples,
                        min_x,
                        x_size,
                        min_y,
                        y_size,
                        z_value,
                        contours,
                        make_faces=self.make_faces,
                        connect_bounds=self.connect_bounds)
                    if has_matrix:
                        new_verts = self.unapply_matrix(matrix, new_verts)

                    if self.join:
                        new_verts.extend(value_verts)
                        new_edges.extend(value_edges)
                        new_faces.extend(value_faces)
                    else:
                        new_verts.append(value_verts)
                        new_edges.append(value_edges)
                        new_faces.append(value_faces)

                if nested_output:
                    verts_out.append(new_verts)
                    edges_out.append(new_edges)
                    faces_out.append(new_faces)
                else:
                    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)
示例#13
0
    def process(self):
        if not self.activate:
            return

        vertices_s = self.inputs['ControlPoints'].sv_get()
        has_weights = self.inputs['Weights'].is_linked
        weights_s = self.inputs['Weights'].sv_get(default = [[1.0]])
        u_size_s = self.inputs['USize'].sv_get()
        degree_u_s = self.inputs['DegreeU'].sv_get()
        degree_v_s = self.inputs['DegreeV'].sv_get()

        if self.input_mode == '1D':
            vertices_s = ensure_nesting_level(vertices_s, 3)
        else:
            vertices_s = ensure_nesting_level(vertices_s, 4)
            
        # we need to suppress depsgraph updates emminating from this part of the process/            
        with self.sv_throttle_tree_update():
            inputs = zip_long_repeat(vertices_s, weights_s, u_size_s, degree_u_s, degree_v_s)
            object_index = 0
            for vertices, weights, u_size, degree_u, degree_v in inputs:
                if not vertices or not weights:
                    continue
                object_index += 1

                if isinstance(u_size, (list, tuple)):
                    u_size = u_size[0]
                if isinstance(degree_u, (tuple, list)):
                    degree_u = degree_u[0]
                if isinstance(degree_v, (tuple, list)):
                    degree_v = degree_v[0]
                if self.input_mode == '1D':
                    fullList(weights, len(vertices))
                else:
                    if isinstance(weights[0], (int, float)):
                        weights = [weights]
                    fullList(weights, len(vertices))
                    for verts_u, weights_u in zip(vertices, weights):
                        fullList(weights_u, len(verts_u))

                surface_object = self.create_surface(object_index)
                self.debug("Object: %s", surface_object)
                if not surface_object:
                    continue

                if self.input_mode == '1D':
                    n_v = u_size
                    n_u = len(vertices) // n_v

                    vertices = grouper(vertices, n_u)
                    weights = grouper(weights, n_u)
                else:
                    n_v = len(vertices)
                    n_u = len(vertices[0])

                surface_object.data.splines.clear()
                for vertices_row, weights_row in zip(vertices, weights):
                    spline = surface_object.data.splines.new(type='NURBS')
                    spline.use_bezier_u = False
                    spline.use_bezier_v = False
                    spline.points.add(n_u - 1)

                    for p, new_co, new_weight in zip(spline.points, vertices_row, weights_row):
                        p.co = Vector(list(new_co) + [new_weight])
                        p.select = True

                    spline.use_cyclic_v = self.is_cyclic_u
                    spline.use_cyclic_u = self.is_cyclic_v
                    spline.use_endpoint_u = not self.is_cyclic_v and self.use_endpoint_v
                    spline.use_endpoint_v = not self.is_cyclic_u and self.use_endpoint_u

                surface_object = self.find_surface(object_index)
                bpy.context.view_layer.objects.active = surface_object
                bpy.ops.object.mode_set(mode = 'EDIT')
                bpy.ops.curve.make_segment()
                bpy.ops.object.mode_set(mode = 'OBJECT')
                spline = surface_object.data.splines[0]
                spline.order_u = degree_u + 1
                spline.order_v = degree_v + 1
                spline.resolution_u = self.resolution_v
                spline.resolution_v = self.resolution_u
                spline.use_smooth = self.smooth

            self.remove_non_updated_objects(object_index)
            self.set_corresponding_materials()
            objects = self.get_children()

            self.outputs['Objects'].sv_set(objects)
示例#14
0
    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        vertices_s = self.inputs['Vertices'].sv_get()
        volume_threshold_s = self.inputs['PlanarThreshold'].sv_get()
        edge_threshold_s = self.inputs['EdgeThreshold'].sv_get()

        input_level = get_data_nesting_level(vertices_s)

        vertices_s = ensure_nesting_level(vertices_s, 4)
        volume_threshold_s = ensure_nesting_level(volume_threshold_s, 2)
        edge_threshold_s = ensure_nesting_level(edge_threshold_s, 2)

        nested_output = input_level > 3

        verts_out = []
        edges_out = []
        faces_out = []
        for params in zip_long_repeat(vertices_s, volume_threshold_s,
                                      edge_threshold_s):
            verts_item = []
            edges_item = []
            faces_item = []
            for vertices, volume_threshold, edge_threshold in zip_long_repeat(
                    *params):

                tri = Delaunay(np.array(vertices))
                if self.join:
                    verts_new = vertices
                    edges_new = set()
                    faces_new = set()
                    for simplex_idx, simplex in enumerate(tri.simplices):
                        if self.is_too_long(vertices, simplex,
                                            edge_threshold) or self.is_planar(
                                                vertices, simplex,
                                                volume_threshold):
                            continue
                        edges_new.update(set(self.make_edges(simplex)))
                        faces_new.update(set(self.make_faces(simplex)))
                    verts_item.append(verts_new)
                    edges_item.append(list(edges_new))
                    faces_item.append(list(faces_new))
                else:
                    verts_new = []
                    edges_new = []
                    faces_new = []
                    for simplex in tri.simplices:
                        if self.is_too_long(vertices, simplex,
                                            edge_threshold) or self.is_planar(
                                                vertices, simplex,
                                                volume_threshold):
                            continue
                        verts_simplex = self.get_verts(vertices, simplex)
                        edges_simplex = self.make_edges([0, 1, 2, 3])
                        faces_simplex = self.make_faces([0, 1, 2, 3])
                        verts_new.append(verts_simplex)
                        edges_new.append(edges_simplex)
                        faces_new.append(faces_simplex)
                    verts_item.extend(verts_new)
                    edges_item.extend(edges_new)
                    faces_item.extend(faces_new)

                if nested_output:
                    verts_out.append(verts_item)
                    edges_out.append(edges_item)
                    faces_out.append(faces_item)
                else:
                    verts_out.extend(verts_item)
                    edges_out.extend(edges_item)
                    faces_out.extend(faces_item)

        self.outputs['Vertices'].sv_set(verts_out)
        self.outputs['Edges'].sv_set(edges_out)
        self.outputs['Faces'].sv_set(faces_out)
示例#15
0
import random

from sverchok.data_structure import zip_long_repeat
from sverchok.utils.sv_bmesh_utils import bmesh_from_pydata
from sverchok.utils.logging import debug, info
from sverchok.utils.turtle import Turtle

if in_select_mask is None:
    in_select_mask = [[]]
if in_paint_mask is None:
    in_paint_mask = [[]]

out_face_mask = []
out_face_data = []
objects = zip_long_repeat(in_verts, in_faces, in_start_face_idx, in_steps,
            in_select_mask, in_paint_mask, in_seed)
for verts, faces, start_face, steps, select_mask, paint_mask, seed in objects:
    info(seed)
    if isinstance(seed, (list, tuple)):
        seed = seed[0]
    random.seed(seed)
    if isinstance(start_face, (list, tuple)):
        if not start_face:
            start_face = random.choice(range(len(faces)))
        else:
            start_face = start_face[0]
    if isinstance(steps, (list, tuple)):
        steps = steps[0]
    
    bm = bmesh_from_pydata(verts, [], faces, normal_update=True)
    bm.verts.ensure_lookup_table()
示例#16
0
    def process(self):

        if not any(socket.is_linked for socket in self.outputs):
            return

        verts_in = self.inputs['Vertices'].sv_get(deepcopy=False)
        faces_in = self.inputs['Faces'].sv_get(deepcopy=False)
        sites_in = self.inputs['Sites'].sv_get(deepcopy=False)
        #thickness_in = self.inputs['Thickness'].sv_get()
        spacing_in = self.inputs['Spacing'].sv_get(deepcopy=False)

        verts_in = ensure_nesting_level(verts_in, 4)
        input_level = get_data_nesting_level(sites_in)
        sites_in = ensure_nesting_level(sites_in, 4)
        faces_in = ensure_nesting_level(faces_in, 4)
        #thickness_in = ensure_nesting_level(thickness_in, 2)
        spacing_in = ensure_min_nesting(spacing_in, 2)

        nested_output = input_level > 3

        precision = 10 ** (-self.accuracy)

        verts_out = []
        edges_out = []
        faces_out = []
        sites_out = []
        for params in zip_long_repeat(verts_in, faces_in, sites_in, spacing_in):
            new_verts = []
            new_edges = []
            new_faces = []
            new_sites = []
            for verts, faces, sites, spacing in zip_long_repeat(*params):
                verts, edges, faces, sites = voronoi_on_mesh(verts, faces, sites, thickness=0,
                            spacing = spacing,
                            #clip_inner = self.clip_inner, clip_outer = self.clip_outer,
                            do_clip=True, clipping=None,
                            mode = self.mode,
                            precision = precision)
                if self.mode == 'VOLUME' and self.normals:
                    verts, edges, faces = recalc_normals(verts, edges, faces, loop=True)

                if self.join_mode == 'FLAT':
                    new_verts.extend(verts)
                    new_edges.extend(edges)
                    new_faces.extend(faces)
                    new_sites.extend(sites)
                elif self.join_mode == 'SEPARATE':
                    new_verts.append(verts)
                    new_edges.append(edges)
                    new_faces.append(faces)
                    new_sites.append(sites)
                else: # JOIN
                    verts, edges, faces = mesh_join(verts, edges, faces)
                    new_verts.append(verts)
                    new_edges.append(edges)
                    new_faces.append(faces)
                    new_sites.append(sites)

            if nested_output:
                verts_out.append(new_verts)
                edges_out.append(new_edges)
                faces_out.append(new_faces)
                sites_out.append(new_sites)
            else:
                verts_out.extend(new_verts)
                edges_out.extend(new_edges)
                faces_out.extend(new_faces)
                sites_out.extend(new_sites)

        self.outputs['Vertices'].sv_set(verts_out)
        self.outputs['Edges'].sv_set(edges_out)
        self.outputs['Faces'].sv_set(faces_out)