Example #1
0
    def face_subdiv_frame(self, fkey, rel_pos=None, move_z=None, **kwattr):
        if rel_pos == 1 or rel_pos == [1, 1, 1]:
            return self.face_subdiv_pyramid(fkey, move_z=move_z, **kwattr)

        face_center_pt = Point(*self.face_center(fkey))
        face_normal = Vector(*self.face_normal(fkey))
        face_coordinates = self.face_coordinates(fkey)
        face_halfedges = self.face_halfedges(fkey)

        self.delete_face(fkey)

        if move_z is None:
            move_z = cycle(to_list(0))

        if not isinstance(move_z, cycle):
            move_z = cycle(to_list(move_z))

        if rel_pos is None:
            rel_pos = cycle(to_list(0.5))

        if not isinstance(rel_pos, cycle):
            rel_pos = cycle(to_list(rel_pos))

        new_vkeys = []
        for x, y, z in face_coordinates:
            pt = Point(x, y, z)
            factor = next(rel_pos)

            v = face_center_pt - pt
            pt += v * factor
            if move_z:
                z_factor = next(move_z)
                pt += face_normal * z_factor
            new_vkeys.append(self.add_vertex(x=pt.x, y=pt.y, z=pt.z))

        new_fkeys = []
        for i, uv in enumerate(face_halfedges):
            u, v = uv
            vkeys = []
            vkeys.append(u)
            vkeys.append(v)
            vkeys.append(new_vkeys[(i + 1) % len(new_vkeys)])
            vkeys.append(new_vkeys[i])

            new_fkeys.append(self.add_face(vkeys))

        # add new center face
        new_fkeys.append(self.add_face(new_vkeys))

        return new_vkeys, new_fkeys
Example #2
0
 def _get_next_cycle(var):
     var = next(var)
     if hasattr(var, "__next__"):
         return var
     if not isinstance(var, Sequence):
         var = to_list(var)
     return cycle(var)
Example #3
0
    def ok_subd(
        self,
        old_vkeys,
        new_vkeys,
        max_degree=None,
        min_angle=None,
        edge_length_domain=None,
        **kwargs
    ):
        new_vkeys = to_list(new_vkeys)

        if max_degree:
            if not self.ok_degree(old_vkeys, max_degree):
                return False

        if min_angle:
            if not self.ok_edges_angles(flatten([old_vkeys + new_vkeys]), min_angle):
                return False

        if edge_length_domain:
            ekeys = [self.connected_edges(vkey) for vkey in new_vkeys]
            ekeys = flatten(ekeys)
            uv_sets = set(frozenset((u, v)) for u, v in ekeys)  # unique edges
            if not self.ok_edge_length(uv_sets, edge_length_domain):
                return False

        return True
Example #4
0
    def connect_nodes(
        self, start_nkey, end_nkeys, max_degree=None, min_angle=None, max_n_conn=None,
    ):
        """Create a line node to node."""
        u = start_nkey
        end_nkeys = to_list(end_nkeys)

        n_conns = len(list(self.nodes_where({"created_from": self.FROM_CONN})))
        for v in end_nkeys:
            if v is None:
                continue

            if max_n_conn:
                if n_conns > max_n_conn:
                    break

            # max_degree-1 because we will add one
            if self.ok_conn(u, v, max_degree - 1, min_angle):
                self.add_edge(
                    u,
                    v,
                    created_from=self.FROM_CONN,
                    # parent_fkey=(start_fkey, end_fkey),
                )
                n_conns += 1
Example #5
0
    def ok_degree(self, keys, max_degree):
        if isinstance(self, Network):
            degree_func = self.degree
        else:
            degree_func = self.vertex_degree

        keys = to_list(keys)
        for key in keys:
            if degree_func(key) > max_degree:
                return False
        return True
Example #6
0
    def _move_center_pt(self, pt, fkey, rel_pos, move_z):
        if not rel_pos and not move_z:
            return pt

        if rel_pos:
            rel_pos = cycle(to_list(rel_pos))
            for v_xyz in self.face_coordinates(fkey):
                v = pt - Point(*v_xyz)

                factor = next(rel_pos)
                pt += v * factor

        if move_z:
            # set up max dist
            normal = Vector(*self.face_normal(fkey, unitized=True))
            z_vec = normal * move_z
            pt += z_vec

        return pt
Example #7
0
    def ok_subd(
        self,
        old_vkeys,
        new_vkeys,
        new_fkeys,
        degree_domain=None,
        min_angle=None,
        edge_length_domain=None,
        max_edge_ratio_diff=None,
        **kwargs
    ):
        new_vkeys = to_list(new_vkeys)

        if degree_domain:
            if not self.ok_degrees(old_vkeys, degree_domain):
                # print("Not ok_subd due to vertex degrees")
                return False

        if min_angle:
            if not self.ok_edges_angles(flatten([old_vkeys + new_vkeys]), min_angle):
                # print("Not ok_subd due to edge angles.")
                return False

        if edge_length_domain:
            ekeys = [self.connected_edges(vkey) for vkey in new_vkeys]
            ekeys = flatten(ekeys)
            uv_sets = set(frozenset((u, v)) for u, v in ekeys)  # unique edges
            if not self.ok_edge_lengths(uv_sets, edge_length_domain):
                # print("Not ok_subd due to edge length constraints.")
                return False

        if max_edge_ratio_diff:
            for fkey in new_fkeys:
                if not self.ok_edge_length_ratios(fkey, max_edge_ratio_diff):
                    return False

        return True
Example #8
0
    def face_subdiv_frame(self, fkey, rel_pos=None, move_z=None, **kwattr):
        """Subdivide a face by offsetting its edges inwards

        Creates ``verts+1`` new faces.

        Parameters
        ----------
        fkey : :obj:`int`
        rel_pos: :obj:`list` of :obj:`float`
        rel_pos: :obj:`float`

        Returns
        -------
        :obj:`list` of :obj:`int`
            Keys of newly created vertices.
        :obj:`list` of :obj:`int`
            Keys of newly created faces.
        :obj:`tuple` of :obj:`int` and :obj:`tuple` of :obj:`int`
            Face keys of removed faces and their vertex keys.
        """

        if rel_pos == 1 or rel_pos == [1, 1, 1]:
            return self.face_subdiv_pyramid(fkey, move_z=move_z, **kwattr)

        face_center_pt = Point(*self.face_center(fkey))
        face_normal = Vector(*self.face_normal(fkey))
        face_coordinates = self.face_coordinates(fkey)
        face_halfedges = self.face_halfedges(fkey)

        deleted_faces = [(fkey, self.face_vertices(fkey))]
        self.delete_face(fkey)

        if move_z is None:
            move_z = cycle(to_list(0))

        if not isinstance(move_z, cycle):
            move_z = cycle(to_list(move_z))

        if rel_pos is None:
            rel_pos = cycle(to_list(0.5))

        if not isinstance(rel_pos, cycle):
            rel_pos = cycle(to_list(rel_pos))

        new_vkeys = []
        for x, y, z in face_coordinates:
            pt = Point(x, y, z)
            factor = next(rel_pos)

            v = face_center_pt - pt
            pt += v * factor
            if move_z:
                z_factor = next(move_z)
                pt += face_normal * z_factor
            new_vkeys.append(self.add_vertex(x=pt.x, y=pt.y, z=pt.z))

        new_fkeys = []
        for i, uv in enumerate(face_halfedges):
            u, v = uv
            vkeys = []
            vkeys.append(u)
            vkeys.append(v)
            vkeys.append(new_vkeys[(i + 1) % len(new_vkeys)])
            vkeys.append(new_vkeys[i])

            new_fkeys.append(self.add_face(vkeys))

        # add new center face
        new_fkeys.append(self.add_face(new_vkeys))

        return new_vkeys, new_fkeys, deleted_faces
Example #9
0
    def subdiv_faces(
        self,
        fkeys,
        n_iters=None,
        scheme=[0],
        rel_pos=None,
        move_z=None,
        max_iters=None,
        **kwargs
    ):
        subdiv_funcs = [
            self.face_subdiv_pyramid,
            self.face_subdiv_mid2center,
            self.face_subdiv_mids2mids,
            self.face_subdiv_split_in_half,
            self.face_subdiv_split_mid2mid,
            self.face_subdiv_frame,
        ]
        repeating_n_iters = cycle(n_iters) if n_iters else None
        subdiv_cycler = cycle(scheme)
        repeating_rel_pos = cycle(to_list(rel_pos)) if rel_pos else None
        repeating_move_z = cycle(to_list(move_z)) if move_z else None

        fkeys = set(fkeys)

        while len(fkeys) > 0:
            fkey = fkeys.pop()

            if n_iters:
                n_iters = next(repeating_n_iters)
            elif self.face_attribute(fkey, "n_iters"):
                n_iters = self.face_attribute(fkey, "n_iters")
            else:
                n_iters = 0

            if max_iters:
                n_iters = n_iters if n_iters < max_iters else max_iters

            if repeating_rel_pos:
                kwargs.update({"rel_pos": next(repeating_rel_pos)})
            if repeating_move_z:
                kwargs.update({"move_z": next(repeating_move_z)})

            subdiv_func_per_parent_face = self._get_next_cycle(subdiv_cycler)

            i = 0
            next_to_subd = set([fkey])
            while i < n_iters:

                to_subd = next_to_subd
                next_to_subd = set()

                while len(to_subd) > 0:
                    parent_fkey = to_subd.pop()
                    parent_face_verts = self.face_vertices(parent_fkey)
                    part = self.face_attribute(parent_fkey, "part")
                    # parent_attrs = self.face_attributes(parent_fkey)

                    subd_func_idx = next(subdiv_func_per_parent_face)

                    subdiv_func = subdiv_funcs[subd_func_idx]

                    new_vkeys, new_fkeys, deleted_faces = subdiv_func(
                        parent_fkey, **kwargs
                    )

                    for vkey in new_vkeys:
                        self.vertex_attribute(vkey, "part", part)

                    if not self.ok_subd(
                        parent_face_verts, new_vkeys, new_fkeys, **kwargs
                    ):
                        self.undo_face_subd(
                            new_fkeys, new_vkeys, deleted_faces,
                        )
                        continue

                    deleted_fkeys = set([fkey for fkey, _ in deleted_faces])

                    # add new fkeys to set for next iteration
                    next_to_subd |= set(new_fkeys)
                    next_to_subd -= deleted_fkeys

                    # remove deleted faces from input list of fkeys
                    fkeys -= deleted_fkeys

                    # remove deleted faces from list for this iteration
                    to_subd -= deleted_fkeys

                i += 1

        self.cull_vertices()
Example #10
0
 def ok_edges_angles(self, keys, min_angle, **kwargs):
     vkeys = to_list(keys)
     for vkey in vkeys:
         if not self.ok_edge_angles(vkey, min_angle, **kwargs):
             return False
     return True
Example #11
0
    def subdiv_faces(
        self, fkeys, n_iters, scheme=[0], rel_pos=None, move_z=None, **kwargs
    ):
        subdiv_funcs = [
            self.face_subdiv_pyramid,
            self.face_subdiv_mid_cent,
            self.face_subdiv_mids,
            self.face_subdiv_split,
            self.face_subdiv_frame,
        ]
        repeating_n_iters = cycle(n_iters)
        subdiv_cycler = cycle(scheme)
        repeating_rel_pos = cycle(to_list(rel_pos)) if rel_pos else None
        repeating_move_z = cycle(to_list(move_z)) if move_z else None

        new_subd_fkeys = []
        for fkey in fkeys:
            n_iters = next(repeating_n_iters)
            if repeating_rel_pos:
                kwargs.update({"rel_pos": next(repeating_rel_pos)})
            if repeating_move_z:
                kwargs.update({"move_z": next(repeating_move_z)})

            subdiv_parent_face = next(subdiv_cycler)
            if not hasattr(subdiv_parent_face, "__next__"):
                subdiv_parent_face = cycle(to_list(subdiv_parent_face))

            i = 0
            next_to_subd = [fkey]
            while i < n_iters:

                to_subd = next_to_subd
                next_to_subd = []

                subdiv_iteration = next(subdiv_parent_face)
                if not hasattr(subdiv_iteration, "__next__"):
                    subdiv_iteration = cycle(to_list(subdiv_iteration))

                for parent_fkey in to_subd:
                    parent_face_verts = self.face_vertices(parent_fkey)
                    parent_attrs = self.face_attributes(parent_fkey)

                    subdiv_child_face = next(subdiv_iteration)

                    subdiv_func = subdiv_funcs[subdiv_child_face]

                    new_vkeys, new_fkeys = subdiv_func(parent_fkey, **kwargs)

                    if not self.ok_subd(parent_face_verts, new_vkeys, **kwargs):
                        self.undo_face_subd(
                            new_fkeys, parent_fkey, parent_face_verts, parent_attrs
                        )
                        continue

                    next_to_subd += new_fkeys
                    new_subd_fkeys += new_fkeys

                i += 1

        self.cull_vertices()

        return [fkey for fkey in new_fkeys if self.has_face(fkey)]
Example #12
0
 def ok_degrees(self, keys, degree_domain):
     keys = to_list(keys)
     for key in keys:
         if not self.ok_degree(key, degree_domain):
             return False
     return True