Beispiel #1
0
def rotate_leaves_for_face_rec(ags_net, gtopt_net, plygn, plyln):
    """
    rotates the leaves of the gtopt_net and adds them to ags_net to facilitate face recognition.
    """
    ags_net_rot=gtopt_net.copy()
    leaf_pair_dic=leaf_pair_dict(ags_net)
    for key, pair in leaf_pair_dic.items():
        coor_key=ags_net.node_coordinates(pair[0][0])  # the common coordinate
        if len(pair)>1:  # if they are two pairs (sup/load) at one node
            coor_12=ags_net.node_coordinates(pair[0][1])
            coor_22=ags_net.node_coordinates(pair[1][1])
            plyln_bln_1=is_point_on_polyline(coor_12, plyln.points, tol=0.1)
            plyln_bln_2=is_point_on_polyline(coor_22, plyln.points, tol=0.1)
            if plyln_bln_1 or plyln_bln_2:  # the case when one is on polyline        
                if plyln_bln_1:
                    key_g=pair[0][1]
                    key_o=pair[1][1]
                    coor_g=coor_12
                    coor_o=coor_22
                elif plyln_bln_2:
                    key_g=pair[1][1]
                    key_o=pair[0][1]
                    coor_g=coor_22
                    coor_o=coor_12
                add_vec=add_vectors(vector_create(coor_o, coor_key).tolist(), vector_create(coor_g, coor_key).tolist())
                add_pt=subtract_vectors(coor_key, add_vec)  # bcs the origin is the key_coor
                ags_net_rot.add_node(key_g, {'x': add_pt[0], 'y': add_pt[1], 'z': add_pt[2]})
                ags_net_rot.add_node(key_o, {'x': coor_o[0], 'y': coor_o[1], 'z': coor_o[2]})
                ags_net_rot.add_edge(key, key_g)
                ags_net_rot.add_edge(key, key_o)
            else:  # the case when both are not on polyline 
                ags_net_rot.add_node(pair[0][1], {'x': coor_12[0], 'y': coor_12[1], 'z': coor_12[2]})
                ags_net_rot.add_node(pair[1][1], {'x': coor_22[0], 'y': coor_22[1], 'z': coor_22[2]})
                ags_net_rot.add_edge(key, pair[0][1])
                ags_net_rot.add_edge(key, pair[1][1])  
        else:  # for single leaf
            coor_12=ags_net.node_coordinates(pair[0][1])
            plyln_bln=is_point_on_polyline(coor_12, plyln.points, tol=0.1)
            if plyln_bln:
                uv=unit_vector(vector_create(coor_key, coor_12))
                if uv[0]-0.0<0.01:  # x=0
                    coor_g=add_vectors(coor_12, (1.0, 0.0, 0.0))
                    plygn_bln=is_point_in_polygon_xy(coor_g, plygn.points)
                    if plygn_bln:
                        coor_g=add_vectors(coor_12, (-1.0, 0.0, 0.0))
                elif uv[1]-0.0<0.01:  # y=0
                    coor_g=add_vectors(coor_12, (0.0, 1.0, 0.0))
                    plygn_bln=is_point_in_polygon_xy(coor_12, plygn.points)
                    if plygn_bln:
                        coor_g=add_vectors(coor_g, (0.0,-1.0, 0.0))            
                ags_net_rot.add_node(pair[0][1], {'x': coor_g[0], 'y': coor_g[1], 'z': coor_g[2]})
                ags_net_rot.add_edge(key, pair[0][1])
            else:  # when already in the correct position
                ags_net_rot.add_node(pair[0][1], {'x': coor_12[0], 'y': coor_12[1], 'z': coor_12[2]})
                ags_net_rot.add_edge(key, pair[0][1])
    # plot_network(ags_net_rot)
    
    return ags_net_rot
Beispiel #2
0
def add_vertex_edge_for_load_support(network, sup_dic, load_dic, bars_len, key_removed_dic):
    """
    Post-Processing Function:
    Adds vertices and edges in accordance with supports and loads
    returns the cured network
    """
    if not key_removed_dic:
        load_sup_dic=merge_two_dicts(sup_dic, load_dic)
    else:
        load_dic_2=load_dic.copy()
        for key in key_removed_dic:
            load_dic_2.pop(key)
            load_dic_2=merge_two_dicts(load_dic_2, key_removed_dic[key])
        load_sup_dic=merge_two_dicts(sup_dic, load_dic_2)
    # define arbitrary r to be added to get leaf vertex coordinates
    max_len=max(bars_len)
    r=max_len/3.0
    
    # make a polygon and polyline from outer vertices of network
    points = network.to_points()
    cycles = network_find_cycles(network)
    mesh = Mesh.from_vertices_and_faces(points, cycles)

    if 0 in mesh.face and len(mesh.face)>1:
        mesh.delete_face(0)
    if len(mesh.face)==1:  
        ver_lis=[key for key in mesh.vertices()]
    else:
        ver_lis=mesh.vertices_on_boundary(ordered=True)
     
    ver_lis_plyln=ver_lis[:]
    ver_lis_plyln.append(ver_lis[0])
    pt_lis_plygn=[mesh.vertex_coordinates(key) for key in ver_lis]
    pt_lis_plyln=[mesh.vertex_coordinates(key) for key in ver_lis_plyln]
    plygn=Polygon(pt_lis_plygn)
    plyln=Polyline(pt_lis_plyln)

    # add leaf vertices
    for key in load_sup_dic:
        if load_sup_dic[key][0]!=0.0:
            pt_1=add_vectors(network.node_coordinates(key), (+r, 0.0, 0.0))
            plyln_bln=is_point_on_polyline(pt_1, plyln.points, tol=0.001)
            plygn_bln=is_point_in_polygon_xy(pt_1, plygn.points)
            if plyln_bln or plygn_bln:
                pt_1=add_vectors(network.node_coordinates(key), (-r, 0.0, 0.0))
            key_2=network.add_node(x=np.asscalar(pt_1[0]), y=pt_1[1], z=0.0)
            network.add_edge(key, key_2)
        if load_sup_dic[key][1]!=0.0:
            pt_2=add_vectors(network.node_coordinates(key), (0.0,+r, 0.0))
            plyln_bln=is_point_on_polyline(pt_2, plyln.points, tol=0.001)
            plygn_bln=is_point_in_polygon_xy(pt_2, plygn.points)
            if plyln_bln or plygn_bln:
                pt_2=add_vectors(network.node_coordinates(key), (0.0,-r, 0.0))
            key_2=network.add_node(x=pt_2[0], y=np.asscalar(pt_2[1]), z=0.0)
            network.add_edge(key, key_2)
    
    return network, plygn, plyln
def boundary_triangulation(outer_boundary, inner_boundaries, polyline_features = [], point_features = [], src='numpy_rpc'):
	"""Generate Delaunay triangulation between a planar outer boundary and planar inner boundaries. All vertices lie the boundaries.

	Parameters
	----------
	outer_boundary : list
		Planar outer boundary as list of vertex coordinates.
	inner_boundaries : list
		List of planar inner boundaries as lists of vertex coordinates.
	polyline_features : list
		List of planar polyline_features as lists of vertex coordinates.
	point_features : list
		List of planar point_features as lists of vertex coordinates.
	src : str
		Source of Delaunay triangulation. Default is NumPy via RPC.

	Returns
	-------
	delaunay_mesh : Mesh
		The Delaunay mesh.

	"""

	# generate planar Delaunay triangulation
	vertices = [pt for boundary in [outer_boundary] + inner_boundaries + polyline_features for pt in boundary] + point_features
	if src == 'numpy_rpc':
		faces = delaunay_numpy_rpc(vertices)
	elif src == 'numpy':
		faces = delaunay_numpy(vertices)
	else:
		delaunay_compas(vertices)
	
	delaunay_mesh = Mesh.from_vertices_and_faces(vertices, faces)
	
	# delete false faces with aligned vertices
	for fkey in list(delaunay_mesh.faces()):
		a, b, c = [delaunay_mesh.vertex_coordinates(vkey) for vkey in delaunay_mesh.face_vertices(fkey)]
		ab = subtract_vectors(b, a)
		ac = subtract_vectors(c, a)
		if length_vector(cross_vectors(ab, ac)) == 0:
			delaunay_mesh.delete_face(fkey)

	# delete faces outisde the borders
	for fkey in list(delaunay_mesh.faces()):
		centre = trimesh_face_circle(delaunay_mesh, fkey)[0]
		if not is_point_in_polygon_xy(centre, outer_boundary) or any([is_point_in_polygon_xy(centre, inner_boundary) for inner_boundary in inner_boundaries]):
			delaunay_mesh.delete_face(fkey)

	# topological cut along the feature polylines through unwelding
	vertex_map = {geometric_key(delaunay_mesh.vertex_coordinates(vkey)): vkey for vkey in delaunay_mesh.vertices()}
	edges = [edge for polyline in polyline_features for edge in pairwise([vertex_map[geometric_key(point)] for point in polyline])]
	mesh_unweld_edges(delaunay_mesh, edges)

	return delaunay_mesh
Beispiel #4
0
    def in_polygon(self, polygon):
        """Determine if the point lies inside the given polygon.

        Parameters
        ----------
        polygon : :class:`compas.geometry.Polygon` or list of points.
            The polygon.

        Returns
        -------
        bool
            True, if the point lies in the polygon.
            False, otherwise.

        Examples
        --------
        >>> from compas.geometry import Polygon
        >>> poly = Polygon([Point(0.0, 0.0, 0.0), Point(1.0, 0.0, 0.0), Point(1.0, 1.0, 0.0), Point(0.0, 1.0, 0.0)])
        >>> point = Point(0.5, 0.5, 0.0)
        >>> point.in_polygon(poly)
        True
        """
        if is_polygon_convex_xy(polygon):
            return is_point_in_convex_polygon_xy(self, polygon)
        return is_point_in_polygon_xy(self, polygon)
Beispiel #5
0
    def get_distance(self, point):
        """
        single point distance function

        Parameters
        ----------
        point: :class:`compas.geometry.Point`
            The point in R<sup>3</sup> space to query for it's distance.
        Returns
        -------
        float
            The distance from the query point to the surface of the object.
        """

        if not isinstance(point, Point):
            point = Point(*point)

        point.transform(self.inversetransform)

        tp = Point(point[0], point[1], 0)
        cp = closest_point_on_polyline_xy(tp, self.polyline)
        d = tp.distance_to_point(cp)
        if is_point_in_polygon_xy(tp, self.polyline):
            d = -1.*d
        d = max(d, abs(point.z) - self.height / 2.0)
        return d
Beispiel #6
0
    def in_polygon(self, polygon, convex=None):
        """Determine if the point lies inside the given polygon.

        Parameters
        ----------
        polygon : :class:`compas.geometry.Polygon` or list of points.
            The polygon.
        convex : {None, True, False}, optional
            Is the polygon convex.
            If ``None``, determine if the polygon is convex.
            If ``False``, use the non-convex algorithm.
            If ``True``, use the convex algorithm.

        Returns
        -------
        bool
            True, if the point lies in the polygon.
            False, otherwise.

        Examples
        --------
        >>> from compas.geometry import Polygon
        >>> poly = Polygon([Point(0.0, 0.0, 0.0), Point(1.0, 0.0, 0.0), Point(1.0, 1.0, 0.0), Point(0.0, 1.0, 0.0)])
        >>> point = Point(0.5, 0.5, 0.0)
        >>> point.in_polygon(poly)
        True
        """
        if convex is None:
            convex = is_polygon_convex_xy(polygon)
        if convex:
            return is_point_in_convex_polygon_xy(self, polygon)
        return is_point_in_polygon_xy(self, polygon)
Beispiel #7
0
    def in_polygon(self, polygon, convex=None):
        """Determine if the point lies inside the given polygon.

        Parameters
        ----------
        polygon : sequence[point] | :class:`compas.geometry.Polygon`
            The polygon.
        convex : Literal[None, True, False], optional
            If None, determine if the polygon is convex.
            If False, use the non-convex algorithm.
            If True, use the convex algorithm.

        Returns
        -------
        bool
            True, if the point lies in the polygon.
            False, otherwise.

        Examples
        --------
        >>> from compas.geometry import Polygon
        >>> poly = Polygon([Point(0.0, 0.0, 0.0), Point(1.0, 0.0, 0.0), Point(1.0, 1.0, 0.0), Point(0.0, 1.0, 0.0)])
        >>> point = Point(0.5, 0.5, 0.0)
        >>> point.in_polygon(poly)
        True

        """
        if convex is None:
            convex = is_polygon_convex_xy(polygon)
        if convex:
            return is_point_in_convex_polygon_xy(self, polygon)
        return is_point_in_polygon_xy(self, polygon)
        def gluepath_creator(int_surf, path_width):
            def interval_checker(dimension):
                underflow = dimension % path_width
                if underflow > 0.2:
                    no_paths = dimension // path_width + 1
                    new_path_width = dimension / no_paths
                    return new_path_width
                else:
                    return path_width

            wid_gap = int_surf[1] - int_surf[0]
            wid_vec = Vector(wid_gap[0], wid_gap[1], wid_gap[2])
            wid = wid_vec.length
            wid_vec.unitize()
            len_gap = int_surf[2] - int_surf[1]
            len_vec = Vector(len_gap[0], len_gap[1], len_gap[2])
            len = len_vec.length
            len_vec.unitize()
            wid_path = interval_checker(wid)
            len_path = interval_checker(len)
            path_dims = [wid_path, len_path]
            path_points = []
            iteration = 0
            path_unfinished = True
            current_pt = int_surf[0] + scale_vector(
                wid_vec, wid_path / 2) + scale_vector(len_vec, len_path / 2)
            current_vec = len_vec.unitized()
            len_left = len - len_path
            wid_left = wid - wid_path
            dims_left = [len_left, wid_left]
            path_points.append(current_pt)
            R = Rotation.from_axis_and_angle([0, 0, 1], -math.pi / 2)
            while path_unfinished:
                current_index = iteration % 2
                current_dim = dims_left[current_index]
                if iteration > 2:
                    current_dim -= path_dims[current_index]
                    dims_left[current_index] = current_dim

                if current_dim < path_width * 0.95:
                    break
                current_pt = current_pt + scale_vector(current_vec,
                                                       current_dim)
                path_points.append(current_pt)
                current_vec.transform(R)
                current_vec.unitize()
                iteration += 1
                if not is_point_in_polygon_xy(current_pt, int_surf):
                    print("Error: Point not in polygon")

            return path_points
Beispiel #9
0
    def get_distance(self, point):
        if not isinstance(point, Point):
            point = Point(*point)

        m = matrix_from_frame(self.frame)
        mi = matrix_inverse(m)
        point.transform(mi)

        tp = Point(point[0], point[1], 0)
        cp = closest_point_on_polyline_xy(tp, self.polyline)
        d = tp.distance_to_point(cp)
        if is_point_in_polygon_xy(tp, self.polyline):
            d = -1. * d
        d = max(d, abs(point.z) - self.height / 2.0)
        return d
Beispiel #10
0
def delaunay_from_points(points, boundary=None, holes=None, tiny=1e-12):
    """Computes the delaunay triangulation for a list of points.

    Parameters
    ----------
    points : sequence of tuple
        XYZ coordinates of the original points.
    boundary : sequence of tuples
        list of ordered points describing the outer boundary (optional)
    holes : list of sequences of tuples
        list of polygons (ordered points describing internal holes (optional)

    Returns
    -------
    list
        The faces of the triangulation.
        Each face is a triplet of indices referring to the list of point coordinates.

    Notes
    -----
    For more info, see [1]_.

    References
    ----------
    .. [1] Sloan, S. W., 1987 *A fast algorithm for constructing Delaunay triangulations in the plane*
           Advances in Engineering Software 9(1): 34-55, 1978.

    Example
    -------
    .. plot::
        :include-source:

        from compas.datastructures import Mesh
        from compas.geometry import pointcloud_xy
        from compas.geometry import delaunay_from_points
        from compas_plotters import MeshPlotter

        points = pointcloud_xy(20, (0, 50))
        faces = delaunay_from_points(points)

        delaunay = Mesh.from_vertices_and_faces(points, faces)

        plotter = MeshPlotter(delaunay)
        plotter.draw_vertices(radius=0.1)
        plotter.draw_faces()
        plotter.show()

    """
    from compas.datastructures import Mesh
    from compas.datastructures import trimesh_swap_edge

    def super_triangle(coords):
        centpt = centroid_points(coords)
        bbpts = bounding_box(coords)
        dis = distance_point_point(bbpts[0], bbpts[2])
        dis = dis * 300
        v1 = (0 * dis, 2 * dis, 0)
        v2 = (1.73205 * dis, -1.0000000000001 * dis, 0)  # due to numerical issues
        v3 = (-1.73205 * dis, -1 * dis, 0)
        pt1 = add_vectors(centpt, v1)
        pt2 = add_vectors(centpt, v2)
        pt3 = add_vectors(centpt, v3)
        return pt1, pt2, pt3

    mesh = Mesh()

    # to avoid numerical issues for perfectly structured point sets
    points = [(point[0] + random.uniform(-tiny, tiny), point[1] + random.uniform(-tiny, tiny), 0.0) for point in points]

    # create super triangle
    pt1, pt2, pt3 = super_triangle(points)

    # add super triangle vertices to mesh
    n = len(points)
    super_keys = n, n + 1, n + 2

    mesh.add_vertex(super_keys[0], {'x': pt1[0], 'y': pt1[1], 'z': pt1[2]})
    mesh.add_vertex(super_keys[1], {'x': pt2[0], 'y': pt2[1], 'z': pt2[2]})
    mesh.add_vertex(super_keys[2], {'x': pt3[0], 'y': pt3[1], 'z': pt3[2]})

    mesh.add_face(super_keys)

    # iterate over points
    for i, pt in enumerate(points):
        key = i

        # newtris should be intialised here

        # check in which triangle this point falls
        for fkey in list(mesh.faces()):
            # abc = mesh.face_coordinates(fkey) #This is slower
            # This is faster:
            keya, keyb, keyc = mesh.face_vertices(fkey)

            dicta = mesh.vertex[keya]
            dictb = mesh.vertex[keyb]
            dictc = mesh.vertex[keyc]

            a = [dicta['x'], dicta['y']]
            b = [dictb['x'], dictb['y']]
            c = [dictc['x'], dictc['y']]

            if is_point_in_triangle_xy(pt, [a, b, c], True):
                # generate 3 new triangles (faces) and delete surrounding triangle
                key, newtris = mesh.insert_vertex(fkey, key=key, xyz=pt, return_fkeys=True)
                break

        while newtris:
            fkey = newtris.pop()

            # get opposite_face
            keys = mesh.face_vertices(fkey)
            s = list(set(keys) - set([key]))
            u, v = s[0], s[1]
            fkey1 = mesh.halfedge[u][v]

            if fkey1 != fkey:
                fkey_op, u, v = fkey1, u, v
            else:
                fkey_op, u, v = mesh.halfedge[v][u], u, v

            if fkey_op:
                keya, keyb, keyc = mesh.face_vertices(fkey_op)
                dicta = mesh.vertex[keya]
                a = [dicta['x'], dicta['y']]
                dictb = mesh.vertex[keyb]
                b = [dictb['x'], dictb['y']]
                dictc = mesh.vertex[keyc]
                c = [dictc['x'], dictc['y']]

                circle = circle_from_points_xy(a, b, c)

                if is_point_in_circle_xy(pt, circle):
                    fkey, fkey_op = trimesh_swap_edge(mesh, u, v)
                    newtris.append(fkey)
                    newtris.append(fkey_op)

    # Delete faces adjacent to supertriangle
    for key in super_keys:
        mesh.delete_vertex(key)

    # Delete faces outside of boundary
    if boundary:
        for fkey in list(mesh.faces()):
            centroid = mesh.face_centroid(fkey)
            if not is_point_in_polygon_xy(centroid, boundary):
                mesh.delete_face(fkey)

    # Delete faces inside of inside boundaries
    if holes:
        for polygon in holes:
            for fkey in list(mesh.faces()):
                centroid = mesh.face_centroid(fkey)
                if is_point_in_polygon_xy(centroid, polygon):
                    mesh.delete_face(fkey)

    return [mesh.face_vertices(fkey) for fkey in mesh.faces()]
Beispiel #11
0
    #process holes/openings
    if not crvs_openings: crvs_openings = []

    #divide curves per hole based on target length
    crvs_openings_pts = [
        rs.DivideCurve(crv, max(rs.CurveLength(crv) / trg_length, 3))
        for crv in crvs_openings
    ]

    #check which holes are inside which face / assign holes to faces
    for fkey, attr in mesh.faces(True):
        polygon = attr['polygon']
        holes = []
        for crvs_opening_pts in crvs_openings_pts:
            if is_point_in_polygon_xy(crvs_opening_pts[0], polygon):
                holes.append(crvs_opening_pts)
                # could be more efficient since holes already
                # assigned to another face are checked again
        attr['hole_polygons'] = holes

    #create triangular mesh for each face
    delaunay_meshes = []
    count = 1
    for fkey, attr in mesh.faces(True):
        polygon = attr['polygon']
        holes = attr['hole_polygons']
        #create flat list of all points
        points = polygon + [item for hole in holes for item in hole]

        #compute initial delaunay mesh based on all points for the current face
Beispiel #12
0
def delaunay_from_points(points, boundary=None, holes=None, tiny=1e-12):
    """Computes the delaunay triangulation for a list of points.

    Parameters
    ----------
    points : sequence[[float, float, float] | :class:`compas.geometry.Point`]
        XYZ coordinates of the original points.
    boundary : sequence[[float, float, float] | :class:`compas.geometry.Point`] | :class:`compas.geometry.Polygon`, optional
        List of ordered points describing the outer boundary.
    holes : sequence[sequence[[float, float, float] | :class:`compas.geometry.Point`] | :class:`compas.geometry.Polygon`], optional
        List of polygons (ordered points describing internal holes.

    Returns
    -------
    list[[int, int, int]]
        The faces of the triangulation.
        Each face is a triplet of indices referring to the list of point coordinates.

    Notes
    -----
    For more info, see [1]_.

    References
    ----------
    .. [1] Sloan, S. W., 1987 *A fast algorithm for constructing Delaunay triangulations in the plane*
           Advances in Engineering Software 9(1): 34-55, 1978.

    Examples
    --------
    >>>

    """
    from compas.datastructures import Mesh
    from compas.datastructures import trimesh_swap_edge

    def super_triangle(coords, ccw=True):
        centpt = centroid_points(coords)
        bbpts = bounding_box(coords)
        dis = distance_point_point(bbpts[0], bbpts[2])
        dis = dis * 300
        v1 = (0 * dis, 2 * dis, 0)
        v2 = (1.73205 * dis, -1.0000000000001 * dis, 0
              )  # due to numerical issues
        v3 = (-1.73205 * dis, -1 * dis, 0)
        pt1 = add_vectors(centpt, v1)
        pt2 = add_vectors(centpt, v2)
        pt3 = add_vectors(centpt, v3)
        if ccw:
            return pt1, pt3, pt2
        return pt1, pt2, pt3

    mesh = Mesh()

    # to avoid numerical issues for perfectly structured point sets
    points = [(point[0] + random.uniform(-tiny, tiny),
               point[1] + random.uniform(-tiny, tiny), 0.0)
              for point in points]

    # create super triangle
    pt1, pt2, pt3 = super_triangle(points)

    # add super triangle vertices to mesh
    n = len(points)
    super_keys = n, n + 1, n + 2

    mesh.add_vertex(super_keys[0], {'x': pt1[0], 'y': pt1[1], 'z': pt1[2]})
    mesh.add_vertex(super_keys[1], {'x': pt2[0], 'y': pt2[1], 'z': pt2[2]})
    mesh.add_vertex(super_keys[2], {'x': pt3[0], 'y': pt3[1], 'z': pt3[2]})

    mesh.add_face(super_keys)

    # iterate over points
    for key, point in enumerate(points):
        # newtris should be intialised here

        # check in which triangle this point falls
        for fkey in list(mesh.faces()):
            abc = mesh.face_coordinates(fkey)

            if is_point_in_triangle_xy(point, abc, True):
                # generate 3 new triangles (faces) and delete surrounding triangle
                key, newtris = mesh.insert_vertex(fkey,
                                                  key=key,
                                                  xyz=point,
                                                  return_fkeys=True)
                break

        while newtris:
            fkey = newtris.pop()

            face = mesh.face_vertices(fkey)
            i = face.index(key)
            u = face[i - 2]
            v = face[i - 1]

            nbr = mesh.halfedge[v][u]

            if nbr is not None:
                a, b, c = mesh.face_coordinates(nbr)
                circle = circle_from_points_xy(a, b, c)

                if is_point_in_circle_xy(point, circle):
                    fkey, nbr = trimesh_swap_edge(mesh, u, v)
                    newtris.append(fkey)
                    newtris.append(nbr)

    # Delete faces adjacent to supertriangle
    for key in super_keys:
        mesh.delete_vertex(key)

    # Delete faces outside of boundary
    if boundary:
        for fkey in list(mesh.faces()):
            centroid = mesh.face_centroid(fkey)
            if not is_point_in_polygon_xy(centroid, boundary):
                mesh.delete_face(fkey)

    # Delete faces inside of inside boundaries
    if holes:
        for polygon in holes:
            for fkey in list(mesh.faces()):
                centroid = mesh.face_centroid(fkey)
                if is_point_in_polygon_xy(centroid, polygon):
                    mesh.delete_face(fkey)

    return [mesh.face_vertices(fkey) for fkey in mesh.faces()]
plotter.zoom_extents()
plotter.pause(1)

# move points in the direction of the randomly assigned translation vectors
# bounce the points of the walls of the box
# color points red when they paas through the polygon
for _ in range(100):
    for i in range(N):
        T = transformations[i]
        a = cloud[i]
        b = a.transformed(T)
        artist = plotter.find(a)

        for side in box.lines:
            x = intersection_segment_segment_xy((a, b), side)
            if x:
                x1 = Point(*x)
                x2 = Point(* mirror_points_line_xy([x1 + (b - a)], side)[0])
                T = Translation.from_vector(x2 - x1)
                transformations[i] = T
                break

        a.transform(T)
        artist.facecolor = (1, 0, 0) if is_point_in_polygon_xy(a, polygon) else (1, 1, 1)

    # redraw the plotter view with a specific timeout
    plotter.redraw(pause=0.1)

# keep the window alive after completion of the script
plotter.show()
def mesh_delaunay_from_points(points, polygon=None, polygons=None):
    """Computes the delaunay triangulation for a list of points.

    Parameters:
        points (sequence of tuple): XYZ coordinates of the original points.
        polygon (sequence of tuples): list of ordered points describing the outer boundary (optional)
        polygons (list of sequences of tuples): list of polygons (ordered points describing internal holes (optional)

    Returns:
        list of lists: list of faces (face = list of vertex indices as integers)

    References:
        Sloan, S. W. (1987) A fast algorithm for constructing Delaunay triangulations in the plane

    Example:

        .. plot::
            :include-source:

            import compas
            from compas.datastructures.mesh import Mesh
            from compas.visualization.plotters import MeshPlotter
            from compas.datastructures.mesh.algorithms import mesh_delaunay_from_points

            mesh = Mesh.from_obj(compas.get_data('faces.obj'))

            vertices = [mesh.vertex_coordinates(key) for key in mesh]
            faces = mesh_delaunay_from_points(vertices)

            delaunay = Mesh.from_vertices_and_faces(vertices, faces)

            plotter = MeshPlotter(delaunay)

            plotter.draw_vertices(radius=0.1)
            plotter.draw_faces()

            plotter.show()

    """
    def super_triangle(coords):
        centpt = centroid_points(coords)
        bbpts = bounding_box(coords)
        dis = distance_point_point(bbpts[0], bbpts[2])
        dis = dis * 300
        v1 = (0 * dis, 2 * dis, 0)
        v2 = (1.73205 * dis, -1.0000000000001 * dis, 0
              )  # due to numerical issues
        v3 = (-1.73205 * dis, -1 * dis, 0)
        pt1 = add_vectors(centpt, v1)
        pt2 = add_vectors(centpt, v2)
        pt3 = add_vectors(centpt, v3)
        return pt1, pt2, pt3

    mesh = Mesh()

    # to avoid numerical issues for perfectly structured point sets
    tiny = 1e-8
    pts = [(point[0] + random.uniform(-tiny, tiny),
            point[1] + random.uniform(-tiny, tiny), 0.0) for point in points]

    # create super triangle
    pt1, pt2, pt3 = super_triangle(points)

    # add super triangle vertices to mesh
    n = len(points)
    super_keys = n, n + 1, n + 2

    mesh.add_vertex(super_keys[0], {'x': pt1[0], 'y': pt1[1], 'z': pt1[2]})
    mesh.add_vertex(super_keys[1], {'x': pt2[0], 'y': pt2[1], 'z': pt2[2]})
    mesh.add_vertex(super_keys[2], {'x': pt3[0], 'y': pt3[1], 'z': pt3[2]})

    mesh.add_face(super_keys)

    # iterate over points
    for i, pt in enumerate(pts):
        key = i

        # check in which triangle this point falls
        for fkey in list(mesh.faces()):
            # abc = mesh.face_coordinates(fkey) #This is slower
            # This is faster:
            keya, keyb, keyc = mesh.face_vertices(fkey)

            dicta = mesh.vertex[keya]
            dictb = mesh.vertex[keyb]
            dictc = mesh.vertex[keyc]

            a = [dicta['x'], dicta['y']]
            b = [dictb['x'], dictb['y']]
            c = [dictc['x'], dictc['y']]

            if is_point_in_triangle_xy(pt, [a, b, c]):
                # generate 3 new triangles (faces) and delete surrounding triangle
                newtris = mesh.insert_vertex(fkey, key=key, xyz=pt)
                break

        while newtris:
            fkey = newtris.pop()

            # get opposite_face
            keys = mesh.face_vertices(fkey)
            s = list(set(keys) - set([key]))
            u, v = s[0], s[1]
            fkey1 = mesh.halfedge[u][v]

            if fkey1 != fkey:
                fkey_op, u, v = fkey1, u, v
            else:
                fkey_op, u, v = mesh.halfedge[v][u], u, v

            if fkey_op:
                keya, keyb, keyc = mesh.face_vertices(fkey_op)
                dicta = mesh.vertex[keya]
                a = [dicta['x'], dicta['y']]
                dictb = mesh.vertex[keyb]
                b = [dictb['x'], dictb['y']]
                dictc = mesh.vertex[keyc]
                c = [dictc['x'], dictc['y']]

                circle = circle_from_points_xy(a, b, c)

                if is_point_in_circle_xy(pt, circle):
                    fkey, fkey_op = trimesh_swap_edge(mesh, u, v)
                    newtris.append(fkey)
                    newtris.append(fkey_op)

    # Delete faces adjacent to supertriangle
    for key in super_keys:
        mesh.remove_vertex(key)

    # Delete faces outside of boundary
    if polygon:
        for fkey in list(mesh.faces()):
            cent = mesh.face_centroid(fkey)
            if not is_point_in_polygon_xy(cent, polygon):
                mesh.delete_face(fkey)

    # Delete faces inside of inside boundaries
    if polygons:
        for polygon in polygons:
            for fkey in list(mesh.faces()):
                cent = mesh.face_centroid(fkey)
                if is_point_in_polygon_xy(cent, polygon):
                    mesh.delete_face(fkey)

    return [[int(key) for key in mesh.face_vertices(fkey, True)]
            for fkey in mesh.faces()]