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
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
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)
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
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)
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
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
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()]
#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
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()]