def draw_xpolygons_xy(polygons, axes): facecolors = [] edgecolors = [] linewidths = [] patches = [] for attr in polygons: points = attr['points'] text = attr.get('text') textcolor = attr.get('textcolor', '#000000') facecolors.append(attr.get('facecolor', '#ffffff')) edgecolors.append(attr.get('edgecolor', '#000000')) linewidths.append(attr.get('edgewidth', 1.0)) patches.append(Polygon(points)) if text: c = centroid_points_xy(points) axes.text(c[0], c[1], text, fontsize=attr.get('fontsize', 10.0), zorder=ZORDER_LABELS, ha='center', va='center', color=textcolor) coll = PatchCollection(patches, facecolor=facecolors, edgecolor=edgecolors, lw=linewidths, zorder=ZORDER_POLYGONS) axes.add_collection(coll) return coll
def draw_xpolygons_xy(polygons, axes): """Creates a polygon collection and adds it to the axis. Parameters ---------- polygons : list of dict List of dictionaries containing the polygon properties. The following properties can be specified in the dict. * points (list): XY(Z) coordinates of the polygon vertices. * text (str, optional): The text of the label. Default is ``None``. * textcolor (rgb tuple or hex string, optional): Color of the label text. Default is black. * fontsize (int, optional): The size of the font of the label text. Default is ```12``. * facecolor (rgb tuple or hex string, optional): Color of the polygon face. Default is white. * edgecolor (rgb tuple or hex string, optional): Color of the edge of the polygon. Default is black. * edgewidth (float): Width of the polygon edge. Default is ``1.0``. axes : object Matplotlib axes. Returns ------- object The matplotlib polygon collection object. """ facecolors = [] edgecolors = [] linewidths = [] patches = [] for attr in polygons: points = attr['points'] text = attr.get('text') textcolor = color_to_rgb(attr.get('textcolor', '#000000'), normalize=True) facecolors.append( color_to_rgb(attr.get('facecolor', '#ffffff'), normalize=True)) edgecolors.append( color_to_rgb(attr.get('edgecolor', '#000000'), normalize=True)) linewidths.append(attr.get('edgewidth', 1.0)) patches.append(Polygon([point[0:2] for point in points])) if text: c = centroid_points_xy(points) axes.text(c[0], c[1], text, fontsize=attr.get('fontsize', 10.0), zorder=ZORDER_LABELS, ha='center', va='center', color=textcolor) coll = PatchCollection(patches, facecolor=facecolors, edgecolor=edgecolors, lw=linewidths, zorder=ZORDER_POLYGONS) axes.add_collection(coll) return coll
def draw_facelabels(self, text: Optional[Dict[int, str]] = None) -> None: """Draw a selection of face labels. Parameters ---------- text : dict of int to str A face-label map. Returns ------- None """ if self._facelabelcollection: for artist in self._facelabelcollection: artist.remove() if text: self.face_text = text labels = [] for face in self.faces: text = self.face_text.get(face, None) if text is None: continue x, y, _ = centroid_points_xy([ self.vertex_xyz[vertex] for vertex in self.mesh.face_vertices(face) ]) artist = self.plotter.axes.text(x, y, f'{text}', fontsize=self.plotter.fontsize, family='monospace', ha='center', va='center', zorder=10000, color=(0, 0, 0), bbox=dict( boxstyle='circle, pad=0.5', facecolor=(1, 1, 1), edgecolor=(0.5, 0.5, 0.5), linestyle=':')) labels.append(artist) self._facelabelcollection = labels
def draw_xpolygons_xy(polygons, axes): """Creates a polygon collection and adds it to the axis. Parameters: polygons (list): List of dictionaries containing the polygon properties. axes (object): Matplotlib axes. Returns: object: The matplotlib polygon collection object. """ facecolors = [] edgecolors = [] linewidths = [] patches = [] for attr in polygons: points = attr['points'] text = attr.get('text') textcolor = color_to_rgb(attr.get('textcolor', '#000000'), normalize=True) facecolors.append( color_to_rgb(attr.get('facecolor', '#ffffff'), normalize=True)) edgecolors.append( color_to_rgb(attr.get('edgecolor', '#000000'), normalize=True)) linewidths.append(attr.get('edgewidth', 1.0)) patches.append(Polygon(points)) if text: c = centroid_points_xy(points) axes.text(c[0], c[1], text, fontsize=attr.get('fontsize', 10.0), zorder=ZORDER_LABELS, ha='center', va='center', color=textcolor) coll = PatchCollection(patches, facecolor=facecolors, edgecolor=edgecolors, lw=linewidths, zorder=ZORDER_POLYGONS) axes.add_collection(coll) return coll
import compas from compas.datastructures import Mesh from compas.geometry import centroid_points_xy from compas_plotters import MeshPlotter import compas_libigl as igl V = [[0, 0, 0], [10, 0, 0], [10, 10, 0], [0, 10, 0], [3, 3, 0], [7, 3, 0], [7, 7, 0], [3, 7, 0]] E = [[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 4], [0, 4], [6, 2]] H = [centroid_points_xy(V[4:])] V2, F2 = igl.conforming_delaunay_triangulation(V, E, H, area=0.5) mesh = Mesh.from_vertices_and_faces(V2, F2) lines = [] for u, v in E: lines.append({'start': V[u], 'end': V[v], 'color': '#ff0000', 'width': 0.5}) plotter = MeshPlotter(mesh, figsize=(8, 5)) plotter.draw_faces() plotter.draw_lines(lines) plotter.show()
gkey_index = {gkey: index for index, gkey in enumerate(gkey_xyz.keys())} xyz = list(gkey_xyz.values()) edges = [] edges += [(gkey_index[geometric_key(a)], gkey_index[geometric_key(b)]) for a, b in pairwise(boundary)] edges += [(gkey_index[geometric_key(a)], gkey_index[geometric_key(b)]) for a, b in pairwise(segments)] edges += [(gkey_index[geometric_key(a)], gkey_index[geometric_key(b)]) for a, b in pairwise(hole)] holes = [] holes += [ centroid_points_xy( [xyz[gkey_index[geometric_key(point)]] for point in hole[:-1]]) ] # ============================================================================== # Triangulate # ============================================================================== vertices, faces = igl.conforming_delaunay_triangulation(xyz, edges, holes, area=0.5) mesh = Mesh.from_vertices_and_faces(vertices, faces) # ============================================================================== # Visualize
Point(1, 2, 2), Point(2, 2, 2), Point(3, 2, 0)], [Point(0, 3, 0), Point(1, 3, 0), Point(2, 3, 0), Point(3, 3, 0)], ] surface = OCCNurbsSurface.from_points(points=points) # ============================================================================== # Intersections # ============================================================================== base = Point(*centroid_points_xy(list(flatten(points)))) line = Line(base, base + Vector(0, 0, 1)) Ry = Rotation.from_axis_and_angle(Vector.Yaxis(), radians(30), point=base) line.transform(Ry) lines = [] for i in range(30): Rz = Rotation.from_axis_and_angle(Vector.Zaxis(), radians(i * 360 / 30), point=base) lines.append(line.transformed(Rz)) intersections = [] for line in lines: x = surface.intersections_with_line(line)
import numpy import compas from compas.datastructures import Mesh from compas.geometry import centroid_points_xy from compas_plotters import MeshPlotter import compas_libigl as igl V = numpy.array([[0, 0, 0], [10, 0, 0], [10, 10, 0], [0, 10, 0], [3, 3, 0], [7, 3, 0], [7, 7, 0], [3, 7, 0]], dtype=numpy.float64) E = numpy.array([[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 4], [0, 4], [6, 2]], dtype=numpy.int32) H = numpy.array([centroid_points_xy(V[4:])], dtype=numpy.float64) V2, F2 = igl.conforming_delaunay_triangulation(V, E, H, area=0.5) mesh = Mesh.from_vertices_and_faces(V2, F2) lines = [] for u, v in E: lines.append({ 'start': V[u], 'end': V[v], 'color': '#ff0000', 'width': 0.5 }) plotter = MeshPlotter(mesh, figsize=(8, 5)) plotter.draw_faces()
def constrained_delaunay_triangulation(boundary, polylines=None, polygons=None, area=None): """Construct a Delaunay triangulation of set of vertices, constrained to the specified segments. Parameters ---------- boundary : list Ordered points on the boundary. polylines : list, optional Lists of ordered points defining internal guide curves. polygons : list, optional Lists of ordered points defining holes in the triangulation. area : float, optional Area constraint for the triangulation. Returns ------- tuple * The vertices of the triangulation. * The faces of the triangulation. Notes ----- No additional vertices (Steiner points) will be inserted. Therefore not all faces of the triangulation will be Delaunay. Examples -------- >>> References ---------- https://www.cs.cmu.edu/~quake/triangle.delaunay.html """ gkey_xyz = {geo(point): point[:2] for point in boundary} if polylines: for polyline in polylines: gkey_xyz.update({geo(point): point[:2] for point in polyline}) if polygons: for polygon in polygons: gkey_xyz.update({geo(point): point[:2] for point in polygon}) gkey_index = {gkey: index for index, gkey in enumerate(gkey_xyz)} vertices = list(gkey_xyz.values()) segments = [(gkey_index[geo(a)], gkey_index[geo(b)]) for a, b in pairwise(boundary)] holes = [] if polylines: for polyline in polylines: segments += [(gkey_index[geo(a)], gkey_index[geo(b)]) for a, b in pairwise(polyline)] if polygons: for polygon in polygons: segments += [(gkey_index[geo(a)], gkey_index[geo(b)]) for a, b in pairwise(polygon)] points = [vertices[gkey_index[geo(point)]] for point in polygon] centroid = centroid_points_xy(points) holes.append(centroid[:2]) data = {'vertices': vertices, 'segments': segments} if len(holes) > 0: data['holes'] = holes if area: result = triangulate(data, opts='pa{}q'.format(area)) else: result = triangulate(data, opts='pq') vertices = [[x, y, 0] for x, y in result['vertices']] faces = result['triangles'] return vertices, faces