Example #1
0
def smoothen_cut(zero_contours,
                 mesh,
                 saddle_vkeys,
                 iterations,
                 strength,
                 distance_threshold=20.0 * 20.0):
    """ Iterative smoothing of the cut around the saddle point. """
    for _ in range(iterations):
        saddles = [mesh.vertex_coordinates(key) for key in saddle_vkeys]
        count = 0

        for cluster_key in zero_contours.sorted_point_clusters:
            pts = zero_contours.sorted_point_clusters[cluster_key]
            edges = zero_contours.sorted_edge_clusters[cluster_key]
            for i, pt in enumerate(pts):
                if 0.01 < min(
                    [distance_point_point_sqrd(pt, s)
                     for s in saddles]) < distance_threshold:
                    count += 1
                    edge = edges[i]
                    prev = pts[i - 1]
                    next_p = pts[(i + 1) % len(pts)]
                    avg = [(prev[0] + next_p[0]) * 0.5,
                           (prev[1] + next_p[1]) * 0.5,
                           (prev[2] + next_p[2]) * 0.5]
                    point = np.array(avg) * strength + np.array(pt) * (
                        1 - strength)
                    line = Line(mesh.vertex_coordinates(edge[0]),
                                mesh.vertex_coordinates(edge[1]))
                    projected_pt = project_point_line(point, line)
                    pts[i] = projected_pt
                    zero_contours.sorted_point_clusters[cluster_key][
                        i] = projected_pt

    return zero_contours
def try_to_create_connection(G, isoV, ei, ej, i, j, side_i, side_j, connections_found, tol):
    vi = isoV[ei[side_i]]
    vj = isoV[ej[side_j]]
    if distance_point_point_sqrd(vi, vj) < tol:
        G.add_edge(i, j)
        connections_found[i][side_i] = True
        connections_found[j][side_j] = True
        return True
    return False
Example #3
0
 def close_paths(self):
     """ For paths that are labeled as closed, it makes sure that the first and the last point are identical. """
     for layer in self.layers:
         for path in layer.paths:
             if path.is_closed:  # if the path is closed, first and last point should be the same.
                 if distance_point_point_sqrd(
                         path.points[0], path.points[-1]
                 ) > 0.00001:  # if not already the same
                     path.points.append(path.points[0])
 def is_valid(self):
     if len(self.sorted_point_clusters) > 0:
         for key in self.sorted_point_clusters:
             pts = self.sorted_point_clusters[key]
             if len(pts) > 3:
                 path_total_length = 0.0
                 for p1, p2 in pairwise(pts):
                     path_total_length += distance_point_point_sqrd(p1, p2)
                 if path_total_length > 1.0:
                     return True  # make sure there is at least one path with acceptable length
     return False
Example #5
0
def restore_mesh_attributes(mesh, v_attributes_dict):
    """
    Restores the cut and boundary attributes on the mesh vertices from the dictionary of the previously saved attributes
    """
    mesh.update_default_vertex_attributes({'boundary': 0})
    mesh.update_default_vertex_attributes({'cut': 0})

    D_THRESHOLD = 0.01

    welded_mesh_vertices = []
    indices_to_vkeys = {}
    for i, vkey in enumerate(mesh.vertices()):
        v_coords = mesh.vertex_coordinates(vkey)
        pt = Point(x=v_coords[0], y=v_coords[1], z=v_coords[2])
        welded_mesh_vertices.append(pt)
        indices_to_vkeys[i] = vkey

    for v_coords in v_attributes_dict['boundary_1']:
        closest_index = utils.get_closest_pt_index(pt=v_coords,
                                                   pts=welded_mesh_vertices)
        c_vkey = indices_to_vkeys[closest_index]
        if distance_point_point_sqrd(
                v_coords, mesh.vertex_coordinates(c_vkey)) < D_THRESHOLD:
            mesh.vertex_attribute(c_vkey, 'boundary', value=1)

    for v_coords in v_attributes_dict['boundary_2']:
        closest_index = utils.get_closest_pt_index(pt=v_coords,
                                                   pts=welded_mesh_vertices)
        c_vkey = indices_to_vkeys[closest_index]
        if distance_point_point_sqrd(
                v_coords, mesh.vertex_coordinates(c_vkey)) < D_THRESHOLD:
            mesh.vertex_attribute(c_vkey, 'boundary', value=2)

    for cut_index in v_attributes_dict['cut']:
        for v_coords in v_attributes_dict['cut'][cut_index]:
            closest_index = utils.get_closest_pt_index(
                pt=v_coords, pts=welded_mesh_vertices)
            c_vkey = indices_to_vkeys[closest_index]
            if distance_point_point_sqrd(
                    v_coords, mesh.vertex_coordinates(c_vkey)) < D_THRESHOLD:
                mesh.vertex_attribute(c_vkey, 'cut', value=int(cut_index))
def are_neighboring_point_clouds(pts1, pts2, threshold):
    """
    Returns True if 3 or more points of the point clouds are closer than the threshold. False otherwise.

    Parameters
    ----------
    pts1: list, :class: 'compas.geometry.Point'
    pts2: list, :class: 'compas.geometry.Point'
    threshold: float
    """
    count = 0
    for pt in pts1:
        if distance_point_point_sqrd(pt, utils.get_closest_pt(pt, pts2)) < threshold:
            count += 1
            if count > 2:
                return True
    return False
Example #7
0
        def search(node):
            if node is None:
                return

            d2 = distance_point_point_sqrd(point, node.point)
            if d2 < best[2]:
                if node.label not in exclude:
                    best[:] = node.point, node.label, d2

            d = point[node.axis] - node.point[node.axis]
            if d <= 0:
                close, far = node.left, node.right
            else:
                close, far = node.right, node.left

            search(close)
            if d ** 2 < best[2]:
                search(far)
Example #8
0
        def recursive_search(node):
            if node is None:
                return

            xyz, axis, label, left, right = node

            d2 = distance_point_point_sqrd(point, xyz)

            if d2 < best[2] and label not in exclude:
                best[:] = xyz, label, d2

            diff = point[axis] - xyz[axis]

            if diff <= 0:
                close, far = left, right
            else:
                close, far = right, left

            recursive_search(close)

            if diff**2 < best[2]:
                recursive_search(far)
Example #9
0
def get_closest_mesh_vkey_to_pt(mesh, pt):
    """
    Finds the vertex key that is the closest to the point.

    Parameters
    ----------
    mesh: :class: 'compas.datastructures.Mesh'
    pt: :class: 'compas.geometry.Point'

    Returns
    ----------
    int
        the closest vertex key
    """
    # cloud = [Point(data['x'], data['y'], data['z']) for v_key, data in mesh.vertices(data=True)]
    # closest_index = compas.geometry.closest_point_in_cloud(pt, cloud)[2]
    vertex_tupples = [(v_key, Point(data['x'], data['y'], data['z']))
                      for v_key, data in mesh.vertices(data=True)]
    vertex_tupples = sorted(
        vertex_tupples,
        key=lambda v_tupple: distance_point_point_sqrd(pt, v_tupple[1]))
    closest_vkey = vertex_tupples[0][0]
    return closest_vkey
def is_true_mesh_adjacency(all_meshes, key1, key2):
    """
    Returns True if the two meshes share 3 or more vertices. False otherwise.

    Parameters
    ----------
    all_meshes: list, :class: 'compas.datastructures.Mesh'
    key1: int, index of mesh1
    key2: int, index of mesh2
    """
    count = 0
    mesh1 = all_meshes[key1]
    mesh2 = all_meshes[key2]
    pts_mesh2 = [mesh2.vertex_coordinates(vkey) for vkey, data in mesh2.vertices(data=True)
                 if (data['cut'] > 0 or data['boundary'] > 0)]
    for vkey, data in mesh1.vertices(data=True):
        if data['cut'] > 0 or data['boundary'] > 0:
            pt = mesh1.vertex_coordinates(vkey)
            ci = utils.get_closest_pt_index(pt, pts_mesh2)
            if distance_point_point_sqrd(pt, pts_mesh2[ci]) < 0.00001:
                count += 1
                if count == 3:
                    return True
    return False
def create_planar_paths_igl(mesh, n):
    """
    Creates planar contours using the libigl function: https://libigl.github.io/libigl-python-bindings/igl_docs/#isolines
    TODO: ??? It is currently the only method that can return identify OPEN versus CLOSED paths.

    Parameters
    ----------
    mesh: :class: 'compas.datastructures.Mesh'
        The mesh to be sliced
    n: number of contours
    """
    utils.check_package_is_installed('igl')
    import igl
    v, f = mesh.to_vertices_and_faces()

    ds = np.array([vertex[2] for vertex in v])
    # save distances of each vertex from the floor: this will be the scalar field for the slicing operation.

    # --- generate disconnected segments of isolines using the libigl function
    v = np.array(v)
    f = np.array(f)
    isoV, isoE = igl.isolines(v, f, ds, n)

    # --- group resulting segments per level
    print('Grouping segments per level')
    segments_per_level = {}
    tol = 1e-6
    for e in isoE:
        v0 = isoV[e[0]]
        v1 = isoV[e[1]]
        assert(abs(v0[2] - v1[2]) < tol)
        h = v0[2]

        found = False
        for key in segments_per_level:
            if abs(key - h) < tol:
                if e[0] != e[1]:  # do not add null segments
                    segments_per_level[key].append(e)
                    found = True

        if not found:
            segments_per_level[h] = [e]

    #assert(len(segments_per_level) == n)

    utils.save_to_json(utils.point_list_to_dict(isoV), "/examples/1_planar_slicing_simple/data/output", 'isoV.json')

    sorted_keys = [key for key in segments_per_level]
    sorted(sorted_keys)

    layers = []

    # --- Create connectivity graph G for every group, and sort edges based on G
    with progressbar.ProgressBar(max_value=len(segments_per_level)) as bar:
        for index, key in enumerate(sorted_keys):
            #print(' Creating connectivity for level z = ', key)

            es = segments_per_level[key]  # list of the current edges, which whose indices we are working below

            G = nx.Graph()

            connections_found = [[False, False] for _ in es]

            for i, e in enumerate(es):
                G.add_node(i)  # node, attribute

            for i, ei in enumerate(es):  # ei here is the edge, not the index!
                for side_i in range(2):
                    if not connections_found[i][side_i]:
                        for jj, ej in enumerate(es[i+1:]):  # ej here is the edge, not the index!
                            j = i + jj + 1
                            for side_j in range(2):
                                if not connections_found[j][side_j]:
                                    vi = isoV[ei[side_i]]
                                    vj = isoV[ej[side_j]]
                                    if distance_point_point_sqrd(vi, vj) < tol:
                                        G.add_edge(i, j)
                                        connections_found[i][side_i] = True
                                        connections_found[j][side_j] = True

            # sort connected components of G
            sorted_indices_dict = sort_graph_connected_components(G)

            # for i, s_key in enumerate(sorted_indices_dict):
            #     sorted_eis = sorted_indices_dict[s_key]
            #     this_segment_pts = []
            #
            #     for j, ei in enumerate(sorted_eis):
            #         e = es[ei]
            #         # segment pts
            #         for k in range(2):
            #             this_segment_pts.append(isoV[e[k]])
            #
            #     utils.save_to_json(utils.point_list_to_dict(this_segment_pts),
            #                        "C:/dev/compas_slicer/examples/1_planar_slicing_simple/data/output", 'isoV.json')
            #     print('saved')

            # get points list from sorted edge indices (for each connected component)
            paths_pts = [[] for _ in sorted_indices_dict]
            are_closed = [True for _ in sorted_indices_dict]
            for i, s_key in enumerate(sorted_indices_dict):
                sorted_indices = sorted_indices_dict[s_key]

                for j, s_ei in enumerate(sorted_indices):
                    v0 = isoV[es[s_ei][0]]
                    v1 = isoV[es[s_ei][1]]
                    if j == 0:
                        s_ei_next = sorted_indices[j+1]
                        v0_next = isoV[es[s_ei_next][0]]
                        v1_next = isoV[es[s_ei_next][1]]
                        v_mid_next = (Point(*v0_next) + Point(*v1_next)) * 0.5
                        if distance_point_point_sqrd(v0, v_mid_next) < distance_point_point_sqrd(v1, v_mid_next):
                            paths_pts[i].extend([Point(*v1), Point(*v0)])
                        else:
                            paths_pts[i].extend([Point(*v0), Point(*v1)])

                    else:
                        v_prev = paths_pts[i][-1]
                        if distance_point_point_sqrd(v0, v_prev) < distance_point_point_sqrd(v1, v_prev):
                            paths_pts[i].append(Point(*v1))
                        else:
                            paths_pts[i].append(Point(*v0))

                if distance_point_point_sqrd(paths_pts[i][0], paths_pts[i][1]) > tol:
                    are_closed[i] = False

            paths = []
            for i in range(len(sorted_indices_dict)):
                paths.append(Path(points=paths_pts[i], is_closed=are_closed[i]))

            layers.append(Layer(paths))
            bar.update(index)

    return layers