def test_orientation_functions(): P = get_poly() print("Testing predicate functions...") # is_outward_oriented CGAL_Polygon_mesh_processing.is_outward_oriented(P) # reverse_face_orientations CGAL_Polygon_mesh_processing.reverse_face_orientations(P) flist = [] for fh in P.facets(): flist.append(fh) CGAL_Polygon_mesh_processing.reverse_face_orientations(flist, P) # orient_polygon_soup points = Point_3_Vector() points.reserve(3) points.append(Point_3(0, 0, 0)) points.append(Point_3(0, 1, 0)) points.append(Point_3(1, 0, 0)) polygons = Polygon_Vector() polygon = Int_Vector() polygon.reserve(3) polygon.append(0) polygon.append(1) polygon.append(2) polygons.append(polygon) CGAL_Polygon_mesh_processing.orient_polygon_soup(points, polygons)
def test_insert_from_array(): print("test_insert_from_array") s1 = [1, 2, 3, 6, 4, 5] s2 = [1, 2, 3, 16, 41, 51] s3 = [1, 2, 3, 65, 45, 5] s4 = [1, 2, 3, 64, 44, 5] segments = [s1, s2, s3, s4] tree_seg = AABB_tree_Segment_3_soup() tree_seg.insert_from_array(segments) assert (tree_seg.size() == 4) s = Segment_3(Point_3(1, 2, 3), Point_3(0, 0, 0)) assert (tree_seg.do_intersect(s)) t1 = [0, 0, 0, 0, 0, 1, 0, 0, -1] t2 = [0, 0, 0, 0, 0, 1, 0, 1, -1] t3 = [0, 0, 0, 0, 0, 1, 0, 2, -1] t4 = [0, 0, 0, 0, 0, 1, 0, 3, -1] triangles = [t1, t2, t3, t4] tree_tri = AABB_tree_Triangle_3_soup() tree_tri.insert_from_array(triangles) assert (tree_tri.size() == 4) assert (tree_seg.do_intersect(s))
def test_side_of_triangle_mesh(): print("Testing Side_of_triangle_mesh...") P = get_poly() f = Side_of_triangle_mesh(P) assert (f.bounded_side(Point_3(0.25, 0.25, 0.25)) == ON_BOUNDED_SIDE) assert (f.bounded_side(Point_3(0, 0, 0)) == ON_BOUNDARY) assert (f.bounded_side(Point_3(4, 0, 0)) == ON_UNBOUNDED_SIDE)
def sample_distance(mesh, points, q): triangles = [] for tri in mesh.triangles: a = Point_3(tri[0][0], tri[0][1], tri[0][2]) b = Point_3(tri[1][0], tri[1][1], tri[1][2]) c = Point_3(tri[2][0], tri[2][1], tri[2][2]) triangles.append(Triangle_3(a, b, c)) tree = AABB_tree_Triangle_3_soup(triangles) tree.accelerate_distance_queries() vecs = [] i = 0 for query in points: i += 1 if i % 5000 == 0: q.put(1) p = Point_3(query[0], query[1], query[2]) nearest = tree.closest_point(p) vec = p - nearest vecs.append([vec.x(), vec.y(), vec.z()]) # absolute value because loss is for unsigned data out = np.array(vecs) distances = np.linalg.norm(out, axis=1)[:, None] grads = np.abs(out / distances) return distances, grads
def convex_hull_3d(): """Convex hull for three dimensions This is not implemented in CGAL swig """ from CGAL.CGAL_Kernel import Point_3 from CGAL.CGAL_Kernel import Plane_3 from CGAL import CGAL_Convex_hull_3 from CGAL.CGAL_Polyhedron_3 import Polyhedron_3 pts = [] pts.append(Point_3(0, 0, 0)) pts.append(Point_3(0, 1, 0)) pts.append(Point_3(1, 1, 0)) pts.append(Point_3(1, 0, 0)) pts.append(Point_3(0, 0, 1)) pts.append(Point_3(0, 1, 1)) pts.append(Point_3(1, 1, 1)) pts.append(Point_3(1, 0, 1)) res = Polyhedron_3() CGAL_Convex_hull_3.convex_hull_3(pts, res) print('Convex hull has {} vertices'.format(res.size_of_vertices())) print('is strongly convex: {}'.format(CGAL_Convex_hull_3.is_strongly_convex_3(res)))
def point_altitude(self, p, face_hint=None): p = to_cgal_point(p) fh, vh_or_i = self.locate_point(p, face_hint=face_hint) if fh is None: # point p is out of the convex hull of the triangulation return UNSPECIFIED_ALTITUDE if (isinstance(vh_or_i, Vertex_handle) and vh_or_i in self._input_vertices_infos): # Point is on a vertex, which is part of an input constraint. return self.altitude_for_input_vertex(vh_or_i) # point is on an edge and get a finite face if needed if isinstance(vh_or_i, int) and self.cdt.is_infinite(fh): fh, _ = self.mirror_half_edge(fh, vh_or_i) assert not self.cdt.is_infinite(fh) triangle = self.triangle3d_for_face(fh) p2 = Point_3(p.x(), p.y(), 0) vline = Line_3(p2, Z_VECTOR) inter = intersection(triangle, vline) if not inter.is_Point_3(): raise InconsistentGeometricModel("Can not compute elevation", witness_point=(p.x(), p.y())) p3 = inter.get_Point_3() alti = p3.z() dist = abs((p3 - p2).squared_length() - alti**2) assert dist <= _PROXIMITY_THRESHOLD * 1e-3 + _PROXIMITY_THRESHOLD * ( alti**2 ), ("unexpected distance between point and its projection : %f (threshold = %f, altitude = %f)" % (dist, _PROXIMITY_THRESHOLD, alti)) return alti
def run(self): self.geo = None geo = self.get_input_geometry_ref(0) if geo is None: return if geo.getNumVertexes() == 0: return pts = [Point_3(*i) for i in geo.getVertexes()] res = Polyhedron_3() CGAL_Convex_hull_3.convex_hull_3(pts, res) pts = {} [pts.update({v: idx}) for idx, v in enumerate(res.vertices())] ff = [] for f in res.facets(): he = f.halfedge() done = he faces = [] while True: faces.append(pts[he.vertex()]) he = he.next() if he == done: break ff.append(faces) self.geo = Mesh() self.geo.addVertices([[i.x(), i.y(), i.z()] for i in res.points()]) self.geo.addFaces(ff)
def process(self, mah, ma_idx, display=True): ma_idx, t = ma_idx T = Delaunay_triangulation_3() I = {} L = [Point_3(c[0],c[1],c[2]) for c in mah.D['ma_coords'][ma_idx].astype(np.double)] for p in L: vh = T.insert(p) I[vh]=True s_idx = mah.s_idx(ma_idx) L = [Point_3(c[0],c[1],c[2]) for c in mah.D['coords'][s_idx].astype(np.double)] for p in L: vh = T.insert(p) I[vh]=False return {'triangulation_3':T, 'info_map':I}
def _slice(zpos): plane_query = Plane_3(Point_3(0, 0, zpos), vec) intersections = list() tree.all_intersections(plane_query, intersections) if callback is not None: callback("Found intersections at %3.3f z" % zpos) return (zpos, self._intersection_to_segments(intersections, accuracy))
def point3d_for_vertex(self, vh): alti = self.vertices_info[vh].altitude x, y = vh.point().x(), vh.point().y() if alti is UNSPECIFIED_ALTITUDE: raise InconsistentGeometricModel("No altitude defined for vertex", witness_point=(x, y)) else: return Point_3(x, y, alti)
def __init__(self, vertices, gid): """ Constructs a list of CGAL::Point_3 objects that describe the polygon Input: list of vertices given as coordinate triplets [[1,2,3],[],...] """ self.id = gid self.vertex = [] for v in vertices: self.vertex.append(Point_3(v[0], v[1], v[2])) # x, y, z
def test_3d(): print("3D Tests") p1 = Point_3(0, 0, 0) p2 = Point_3(1, 2, 0) v1 = Vector_3(1, 1, 0) v2 = Vector_3(1, 2, 0) # operations on points assertion(p1 + v2 == p2, 1) assertion(p1 - v2 < p2, 2) assertion(p2 - p1 == v2, 3) assertion(p2 - ORIGIN == v2, 3.1) assertion(p2 > p1, 4) assertion(p2 >= p2, 5) assertion(p2 <= p2, 6) assertion(p2 != p1, 7) # operations on vector assertion(v1 + v2 == Vector_3(2, 3, 0), 8) assertion(v1 - v2 == Vector_3(0, -1, 0), 9) assertion(v2 * v1 == 3, 10) assertion(v2 * 2 == Vector_3(2, 4, 0), 11) assertion(2 * v2 == Vector_3(2, 4, 0), "11 bis") assertion(v1 / 2 == Vector_3(0.5, 0.5, 0), 12) assertion(v1 / 2.0 == Vector_3(0.5, 0.5, 0), 12) assertion(-v2 == Vector_3(-1, -2, 0), 13) assertion(v2 != v1, 14) # operations on ORIGIN/NULL_VECTOR assertion(ORIGIN - p2 == -v2, 14) assertion(ORIGIN + v2 == p2, 15) assertion(p1 == ORIGIN, 15.1) assertion(p1 - p1 == NULL_VECTOR, 15.2) # test inplace operations pt_tmp = p1.deepcopy() pt_tmp += v2 assertion(pt_tmp == p2, 16) vect_tmp = Vector_3(2, 3, 0) vect_tmp -= v1 assertion(vect_tmp == v2, 17)
def cgal_convexify_polyhedron(hrep): gen = np.array(cdd.Polyhedron(hrep).get_generators()) #If the polygon is empty or degenerate, return 0 if gen.shape[0] < 3: return 0 points = [Point_3(x, y, z) for x, y, z in gen[:, 1:]] poly = Polyhedron_3() convex_hull_3(points, poly) lines = [np.array([as_list(p)]) for p in poly.points()] return np.vstack(lines)
def verticesToTriangles( verts, triangleIndices, transforms ): #Transforms list of triangles, and then saves them as Triangle_3, a format used for morphing points onto meshes triangles = [] for i in range(0, len(triangleIndices)): ax, ay, az = transformPoint( transforms[1], transformPoint(transforms[0], verts[triangleIndices[i][0]])[0:3])[0:3] bx, by, bz = transformPoint( transforms[1], transformPoint(transforms[0], verts[triangleIndices[i][1]])[0:3])[0:3] cx, cy, cz = transformPoint( transforms[1], transformPoint(transforms[0], verts[triangleIndices[i][2]])[0:3])[0:3] triangles.append( Triangle_3(Point_3(ax, ay, az), Point_3(bx, by, bz), Point_3(cx, cy, cz))) return numpy.array(triangles)
def test_hole_filling_functions(): print("Testing hole filling functions...") P = get_poly() hlist = [] for hh in P.halfedges(): hlist.append(hh) h = P.make_hole(hlist[0]) outf = [] outv = [] # triangulate_hole CGAL_Polygon_mesh_processing.triangulate_hole(P, h, outf) # triangulate_and_refine_hole h = P.make_hole(hlist[0]) CGAL_Polygon_mesh_processing.triangulate_and_refine_hole(P, h, outf, outv) h = P.make_hole(hlist[0]) CGAL_Polygon_mesh_processing.triangulate_and_refine_hole( P, h, outf, outv, 1.4) # triangulate_refine_and_fair_hole h = P.make_hole(hlist[0]) CGAL_Polygon_mesh_processing.triangulate_refine_and_fair_hole( P, h, outf, outv) h = P.make_hole(hlist[0]) CGAL_Polygon_mesh_processing.triangulate_refine_and_fair_hole( P, h, outf, outv, 1.4) h = P.make_hole(hlist[0]) CGAL_Polygon_mesh_processing.triangulate_refine_and_fair_hole( P, h, outf, outv, 1.4, 1) # triangulate_hole_polyline points = [Point_3(0, 0, 0), Point_3(1, 0, 0), Point_3(0, 1, 0)] third_points = [Point_3(0.5, -1, 0), Point_3(1, 1, 0), Point_3(-1, 0.5, 0)] ints_out = [] CGAL_Polygon_mesh_processing.triangulate_hole_polyline( points, third_points, ints_out) CGAL_Polygon_mesh_processing.triangulate_hole_polyline(points, ints_out)
def _poly_from_mesh(self, mesh): """Refactoring out to make this independent.""" poly = Polyhedron_3() for facet in mesh: #Yes yes yes, I know, * magic, but it's _FASTER_ points = [Point_3(*point) for point in facet[0]] if len(points) == 3: poly.make_triangle(*points) else: raise RuntimeError, ( "Invalid point list for poly facet: %d sides" % len(points)) return poly
def to_polyhedron(self): polyhedron_modifier = Polyhedron_modifier() polyhedron_modifier.begin_surface(len(self.vertices), len(self.faces)) for vertex in self.vertices[1:]: polyhedron_modifier.add_vertex(Point_3(vertex[0], vertex[1], vertex[2])) for face in self.faces[1:]: polyhedron_modifier.begin_facet() for vertex in face: polyhedron_modifier.add_vertex_to_facet(vertex - 1) polyhedron_modifier.end_facet() polyhedron = Polyhedron_3() polyhedron.delegate(polyhedron_modifier) return polyhedron
def make_cube_3(P): # appends a cube of size [0,1]^3 to the polyhedron P. assert P.is_valid() h = P.make_tetrahedron(Point_3(1, 0, 0), Point_3(0, 0, 1), Point_3(0, 0, 0), Point_3(0, 1, 0)) g = h.next().opposite().next() P.split_edge(h.next()) P.split_edge(g.next()) P.split_edge(g) h.next().vertex().set_point(Point_3(1, 0, 1)) g.next().vertex().set_point(Point_3(0, 1, 1)) g.opposite().vertex().set_point(Point_3(1, 1, 0)) f = P.split_facet(g.next(), g.next().next().next()) e = P.split_edge(f) e.vertex().set_point(Point_3(1, 1, 1)) P.split_facet(e, f.next().next()) assert P.is_valid() return h
def cgal_volume_convex(hrep): gen = np.array(cdd.Polyhedron(hrep).get_generators()) #If the polygon is empty or degenerate, return 0 if gen.shape[0] < 3: return 0 #p = np.vstack([gen, gen[0, :]]) p = gen points = [Point_3(x, y, z) for x, y, z in p[:, 1:]] poly = Polyhedron_3() convex_hull_3(points, poly) points = list(poly.points()) center = mult_cgal(reduce(add_cgal, points), 1 / float(len(points))) tetrahedrons = [tetrahedron_from_facet(f, center) for f in poly.facets()] return sum([abs(t.volume()) for t in tetrahedrons])
def main(): # Construct two non-intersecting nested polygons polygon1 = [Point_2(0, 0), Point_2(2, 0), Point_2(2, 2), Point_2(0, 2)] polygon2 = [ Point_2(0.5, 0.5), Point_2(1.5, 0.5), Point_2(1.5, 1.5), Point_2(0.5, 1.5) ] polyhedron1 = [ Point_3(1, 1, -1), Point_3(1, -1, -1), Point_3(-1, -1, -1), Point_3(-1, -1, 1), Point_3(-1, 1, 1), Point_3(-1, 1, -1), Point_3(1, 1, 1), Point_3(1, -1, 1) ] # Insert the polygons into a constrained triangulation cdt = Constrained_Delaunay_triangulation_2() insert_polygon(cdt, polygon1) insert_polygon(cdt, polygon2) # Insert the polyhedron into a triangulation cdt2 = Delaunay_triangulation_3() insert_polyhedron(cdt2, polyhedron1) # Mark facest that are inside the domain bounded by the polygon face_info = mark_domain(cdt) #plot_triangulated_polygon(cdt, face_info) fig = plt.figure(figsize=(10, 10)) ax = fig.gca(projection='3d') ax.set_xlim3d(-1.1, 1.1) ax.set_ylim3d(-1.1, 1.1) ax.set_zlim3d(-1.1, 1.1) plot_triangulated_polyhedron(ax, cdt2)
def test_3d(): print("Test 3D") lst = [] lst.append(Point_3(0, 0, 1)) lst.append(Point_3(0, 4, 2)) lst.append(Point_3(44, 0, 3)) lst.append(Point_3(44, 5, 4)) lst.append(Point_3(444, 51, 5)) lst.append(Point_3(14, 1, 7)) tree = Orthogonal_incremental_neighbor_search_tree_3(lst) search = Orthogonal_incremental_neighbor_search_3( Orthogonal_incremental_neighbor_search_tree_3(lst), Point_3(0, 0, 0)) for p in search.iterator(): print(p[0], p[1])
def morphPoints( robot, grid, trianglesTransformed): #Morphs each point on grid onto surface of hand tris = getTris(robot, trianglesTransformed) tree = AABB_tree_Triangle_3_soup( tris) #Creates ordered hierarchy of triangles out of mesh print len(tris) print trianglesTransformed for i in range(0, len(grid)): #Iterates over all points on hand for j in range(0, len(grid[i])): #if j != 98 and j != 119 and j != 120 and j != 140 and j != 141 and j != 161 and j != 162 and j != 163: if trianglesTransformed != 1 or ( (i != 11 and i != 13) or (i == 11 and (j < 95 or j > 300)) or (i == 13 and j < 243) ): #Hack used to handle Shadow Hand, otherwise adding certain triangles results in Seg faults pt = grid[i][j][0] point_query = Point_3(pt[0], pt[1], pt[2]) point_morphed = tree.closest_point( point_query) #Closest point on surface of hand if trianglesTransformed == 1: grid[i][j][0] = [ point_morphed.x(), point_morphed.y() - 0.08, point_morphed.z() ] else: grid[i][j][0] = [ point_morphed.x(), point_morphed.y(), point_morphed.z() ] else: grid[i][j][0] = [ grid[i][j][0][0], grid[i][j][0][1] - 0.08, grid[i][j][0][2] ] print "finished morphing" return grid
from __future__ import print_function from CGAL.CGAL_Polyhedron_3 import Polyhedron_modifier from CGAL.CGAL_Polyhedron_3 import Polyhedron_3 from CGAL.CGAL_Polyhedron_3 import ABSOLUTE_INDEXING from CGAL.CGAL_Kernel import Point_3 # declare a modifier interfacing the incremental_builder m = Polyhedron_modifier() # define a triangle m.begin_surface(3, 1) m.add_vertex(Point_3(0, 0, 0)) m.add_vertex(Point_3(0, 1, 0)) m.add_vertex(Point_3(1, 0.5, 0)) m.begin_facet() m.add_vertex_to_facet(0) m.add_vertex_to_facet(1) m.add_vertex_to_facet(2) m.end_facet() P = Polyhedron_3() # create the triangle in P P.delegate(m) print("(v,f,e) = ", P.size_of_vertices(), P.size_of_facets(), divmod(P.size_of_halfedges(), 2)[0]) # clear the modifier m.clear() # define another triangle, reusing vertices in the polyhedron m.begin_surface(1, 1, 0, ABSOLUTE_INDEXING)
from __future__ import print_function from CGAL.CGAL_Kernel import Point_3 from CGAL.CGAL_Kernel import Vector_3 from CGAL.CGAL_Kernel import Plane_3 from CGAL.CGAL_Kernel import Segment_3 from CGAL.CGAL_Polyhedron_3 import Polyhedron_3 from CGAL.CGAL_AABB_tree import AABB_tree_Polyhedron_3_Facet_handle p = Point_3(1.0, 0.0, 0.0) q = Point_3(0.0, 1.0, 0.0) r = Point_3(0.0, 0.0, 1.0) s = Point_3(0.0, 0.0, 0.0) polyhedron = Polyhedron_3() polyhedron.make_tetrahedron(p, q, r, s) # constructs AABB tree tree = AABB_tree_Polyhedron_3_Facet_handle(polyhedron.facets()) # constructs segment query a = Point_3(-0.2, 0.2, -0.2) b = Point_3(1.3, 0.2, 1.3) segment_query = Segment_3(a, b) # tests intersections with segment query if tree.do_intersect(segment_query): print("intersection(s)") else: print("no intersection") # computes #intersections with segment query
def gen_vertices_cgal(vertices): t0 = time.time() vertices_cgal = [Point_3(x, y, z) for x, y, z in vertices] print('{:<21} {:>9.5f}'.format('gen_vertices_cgal', time.time() - t0)) return vertices_cgal
def gen_segment_tree_Nx6(soup): t0 = time.time() tree = AABB_tree_Segment_3_soup() tree.insert_from_array(soup) print('{:<21} {:>9.5f}'.format('gen_segment_tree_Nx6', time.time() - t0)) return tree #end # Set sizes. nx = 100 ny = 100 sepstring = '*' * 31 # Set up some testing primitives p1 = Point_3(-1, -1, -1) p2 = Point_3(1, 1, 1) p3 = Point_3(1, 1, -1) tri0 = Triangle_3(p1, p2, p3) seg0 = Segment_3(p1, p2) # Generate an initial set of points, faces, and edges. verts = gen_vertices(nx, ny) faces = gen_faces(nx, ny) edges = gen_edges(faces) nverts = len(verts) nfaces = len(faces) nedges = len(edges) # Convert points to list of CGAL Point_3 objects.
t3 = [0, 0, 0, 0, 0, 1, 0, 2, -1] t4 = [0, 0, 0, 0, 0, 1, 0, 3, -1] triangles = [t1, t2, t3, t4] tree_tri = AABB_tree_Triangle_3_soup() tree_tri.insert_from_array(triangles) assert (tree_tri.size() == 4) assert (tree_seg.do_intersect(s)) test_insert_from_array() poly = Polyhedron_3() poly.make_tetrahedron(Point_3(0, 0, 0), Point_3(1, 0, 0), Point_3(0, 1, 0), Point_3(0, 0, 1)) tree = AABB_tree_Polyhedron_3_Facet_handle() lst = [] for f in poly.facets(): lst.append(f) tree.rebuild(lst) tree = AABB_tree_Polyhedron_3_Facet_handle(lst) print(tree.size()) lst = [] for f in poly.facets(): p1 = f.halfedge().vertex().point()
from __future__ import print_function from CGAL.CGAL_Kernel import Point_3 from CGAL.CGAL_Kernel import Plane_3 from CGAL import CGAL_Convex_hull_3 from CGAL.CGAL_Polyhedron_3 import Polyhedron_3 pts = [] pts.append(Point_3(0, 0, 0)) pts.append(Point_3(0, 1, 0)) pts.append(Point_3(1, 1, 0)) pts.append(Point_3(1, 0, 0)) pts.append(Point_3(0, 0, 1)) pts.append(Point_3(0, 1, 1)) pts.append(Point_3(1, 1, 1)) pts.append(Point_3(1, 0, 1)) res = Polyhedron_3() CGAL_Convex_hull_3.convex_hull_3(pts, res) print("convex hull has ", res.size_of_vertices(), " vertices") print("is strongly convex: ", CGAL_Convex_hull_3.is_strongly_convex_3(res)) planes = [] planes.append(Plane_3(-1, 0, 0, 0)) planes.append(Plane_3(1, 0, 0, -1)) planes.append(Plane_3(0, -1, 0, 0)) planes.append(Plane_3(0, 1, 0, -1)) planes.append(Plane_3(0, 0, -1, 0)) planes.append(Plane_3(0, 0, 1, -1))
from CGAL.CGAL_Kernel import Point_3 from CGAL.CGAL_Kernel import Vector_3 from CGAL.CGAL_Point_set_3 import Point_set_3 import os datadir = os.environ.get('DATADIR', '../data') datafile = datadir + '/oni.xyz' points = Point_set_3() # Insertions idx = points.insert() print("Point", idx, "inserted =", points.point(idx)) idx = points.insert(Point_3(0, 1, 2)) print("Point", idx, "inserted =", points.point(idx)) points.insert_range([2., 4., 5., 2, 3, 4]) # Iterate and display points print("Point set:") for p in points.points(): print(" *", p) # With normal points.add_normal_map() idx = points.insert(Point_3(6, 7, 8), Vector_3(1, 1, 1)) print("Point", idx, "inserted = (", points.point(idx), "), (", points.normal(idx), ")") # Access/modification through normal map normal_map = points.normal_map() if normal_map.is_valid:
from __future__ import print_function from CGAL.CGAL_Kernel import Point_3 from CGAL.CGAL_Kernel import Weighted_point_3 from CGAL.CGAL_Triangulation_3 import Regular_triangulation_3 # generate points on a 3D grid P = [] number_of_points = 0 for z in range(0, 5): for y in range(0, 5): for x in range(0, 5): p = Point_3(x, y, z) w = (x + y - z * y * x) * 2.0 # let's say this is the weight. P.append(Weighted_point_3(p, w)) number_of_points += 1 T = Regular_triangulation_3() # insert all points in a row (this is faster than one insert() at a time). T.insert(P) assert T.is_valid() assert T.dimension() == 3 print("Number of vertices : ", T.number_of_vertices()) # removal of all vertices count = 0 while T.number_of_vertices() > 0: