Пример #1
0
 def rotate_z(self, verts, angle):
     if abs(angle) < 1e-6:
         return verts
     projection = [self.to2d(v) for v in verts]
     x0, y0 = center(projection)
     c = self.from2d(x0, y0)
     rot = Matrix.Rotation(angle, 4, self.normal_axis)
     result = [(rot @ (v - c)) + c for v in verts]
     return result
Пример #2
0
 def ray_intersection(self, p, line):
     p = Vector(center(line.sites))
     intersection = self.circle.intersect_with_line(line)
     #info("RI: {line} X {self.circle} => {intersection}")
     if intersection is None:
         return None
     else:
         v1, v2 = intersection
         r1 = (p - v1).length
         r2 = (p - v2).length
         if r1 < r2:
             return v1
         else:
             return v2
Пример #3
0
 def init_from_sites(self, sites):
     self.x_max = -BIG_FLOAT
     self.x_min = BIG_FLOAT
     self.y_min = BIG_FLOAT
     self.y_max = -BIG_FLOAT
     x0, y0, z0 = center(sites)
     self.center = (x0, y0)
     # creates points in format for voronoi library, throwing away z
     for x, y, z in sites:
         r = sqrt((x-x0)**2 + (y-y0)**2)
         self.r_max = max(r, self.r_max)
         self.x_max = max(x, self.x_max)
         self.x_min = min(x, self.x_min)
         self.y_max = max(y, self.y_max)
         self.y_min = min(y, self.y_min)
Пример #4
0
 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
Пример #5
0
    def ray_intersection(self, p, line):
        p = Vector(center(line.sites))

        min_r = BIG_FLOAT
        nearest = None

        for v_i, v_j in self.edges:
            bound = LineEquation2D.from_two_points(v_i, v_j)
            intersection = bound.intersect_with_line(line)
            if intersection is not None:
                r = (p - intersection).length
                #info("INT: [%s - %s] X [%s] => %s (%s)", v_i, v_j, line, intersection, r)
                if r < min_r:
                    nearest = intersection
                    min_r = r

        return nearest
Пример #6
0
    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)
Пример #7
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_nesting_level(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 inset != 0.0:
                    scale = 1.0 - inset
                    if self.scale_center == 'SITE':
                        verts = [
                            scale_relative(vs, site, scale)
                            for vs, site in zip(verts, sites)
                        ]
                    else:
                        verts = [
                            scale_relative(vs, center(vs), scale)
                            for vs, site in zip(verts, sites)
                        ]

                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)
Пример #8
0
        def make_surface(self, face, degree_u, degree_v, vertices, planes,
                         vert_weights, tangent_weights, face_weight,
                         edge_weights_dict, edge_planes_dict):
            """
            V0 ------ [E01] --- [E0C] --- [E02] --- V1
            |          |         |        |         |
            |          |         |        |         |
            |          |         |        |         |
            [E11] --- [F1] ---- [E0F] --- [F2] --- [E21]
            |          |         |        |         |
            |          |         |        |         |
            |          |         |        |         |
            [E1C] --- [E1F] --- [CC] --- [E2F] --- [E2C]
            |          |         |        |         |
            |          |         |        |         |
            |          |         |        |         |
            [E12] --- [F3] ---- [E3F] --- [F4] --- [E22]
            |          |         |        |         |
            |          |         |        |         |
            |          |         |        |         |
            V3 ------ [E31] --- [E3C] --- [E32] --- V2
            """
            tangent_weights = [w / 3.0 for w in tangent_weights]
            vertices = [Vector(v) for v in vertices]

            def mk_edge_point(i, j):
                return (vertices[j] -
                        vertices[i]) * tangent_weights[i] + vertices[i]

            def mk_face_corner_point(i, j, k):
                dv1 = (vertices[j] - vertices[i]) * tangent_weights[i]
                dv2 = (vertices[k] - vertices[i]) * tangent_weights[i]
                #m = face_weight
                return planes[i].projection_of_point(vertices[i] + dv1 + dv2)

            # edge planes
            e0p = edge_planes_dict[(face[0], face[1])]
            e1p = edge_planes_dict[(face[0], face[3])]
            e2p = edge_planes_dict[(face[1], face[2])]
            e3p = edge_planes_dict[(face[2], face[3])]

            def mk_edge_center_point(ep1, ep2):
                return (ep1 + ep2) / 2.0

            def mk_face_edge_point(edge_plane, edge_point, edge_vec, vec1,
                                   vec2):
                length = (vec1.length + vec2.length) / 2.0
                vec = edge_plane.normal.cross(edge_vec)
                #print("EV: %s, N: %s, L: %s, Res: %s" % (edge_vec, edge_plane.normal, length, vec))
                vec = length * vec.normalized()
                return edge_point + vec

            e01 = planes[0].projection_of_point(mk_edge_point(0, 1))
            e02 = planes[1].projection_of_point(mk_edge_point(1, 0))
            e11 = planes[0].projection_of_point(mk_edge_point(0, 3))
            e21 = planes[1].projection_of_point(mk_edge_point(1, 2))
            f1 = mk_face_corner_point(0, 1, 3)
            f2 = mk_face_corner_point(1, 0, 2)
            e12 = planes[3].projection_of_point(mk_edge_point(3, 0))
            e31 = planes[3].projection_of_point(mk_edge_point(3, 2))
            e32 = planes[2].projection_of_point(mk_edge_point(2, 3))
            e22 = planes[2].projection_of_point(mk_edge_point(2, 1))
            f3 = mk_face_corner_point(3, 0, 2)
            f4 = mk_face_corner_point(2, 3, 1)

            e0c = mk_edge_center_point(e01, e02)
            e1c = mk_edge_center_point(e11, e12)
            e2c = mk_edge_center_point(e21, e22)
            e3c = mk_edge_center_point(e31, e32)

            e0f = mk_face_edge_point(e0p, e0c, (vertices[1] - vertices[0]),
                                     (f1 - e01), (f2 - e02))
            e1f = mk_face_edge_point(e1p, e1c, (vertices[0] - vertices[3]),
                                     (f3 - e12), (f1 - e11))
            e2f = mk_face_edge_point(e2p, e2c, (vertices[2] - vertices[1]),
                                     (f2 - e21), (f4 - e22))
            e3f = mk_face_edge_point(e3p, e3c, (vertices[3] - vertices[2]),
                                     (f3 - e31), (f4 - e32))

            cc = center([f1, e0f, f2, e2f, f4, e3f, f3, e1f])

            control_points = [
                vertices[0], e01, e0c, e02, vertices[1], e11, f1, e0f, f2, e21,
                e1c, e1f, cc, e2f, e2c, e12, f3, e3f, f4, e22, vertices[3],
                e31, e3c, e32, vertices[2]
            ]

            # edge point weights
            e0w = edge_weights_dict[(face[0], face[1])]
            e1w = edge_weights_dict[(face[0], face[3])]
            e2w = edge_weights_dict[(face[1], face[2])]
            e3w = edge_weights_dict[(face[2], face[3])]

            weights = [
                vert_weights[0], e0w, e0w, e0w, vert_weights[1], e1w,
                face_weight, face_weight, face_weight, e2w, e1w, face_weight,
                face_weight, face_weight, e2w, e1w, face_weight, face_weight,
                face_weight, e2w, vert_weights[3], e3w, e3w, e3w,
                vert_weights[2]
            ]

            surface = NURBS.Surface()
            surface.degree_u = degree_u
            surface.degree_v = degree_v
            surface.ctrlpts_size_u = 5
            surface.ctrlpts_size_v = 5
            surface.ctrlpts = control_points
            surface.weights = weights
            surface.knotvector_u = knotvector.generate(surface.degree_u, 5)
            surface.knotvector_v = knotvector.generate(surface.degree_v, 5)

            new_surf = SvExGeomdlSurface(surface)
            return new_surf, control_points, weights