def face_flatness(self, face, maxdev=0.02): """Compute the flatness of a face. Parameters ---------- face : int The identifier of the face. Returns ------- float The flatness. Note ---- compas.geometry.mesh_flatness function currently only works for quadrilateral faces. This function uses the distance between each face vertex and its projected point on the best-fit plane of the face as the flatness metric. """ deviation = 0 polygon = self.face_coordinates(face) plane = bestfit_plane(polygon) for pt in polygon: pt_proj = project_point_plane(pt, plane) dev = distance_point_point(pt, pt_proj) if dev > deviation: deviation = dev return deviation
def face_curvature(self, fkey): """Dimensionless face curvature. Face curvature is defined as the maximum face vertex deviation from the best-fit plane of the face vertices divided by the average lengths of the face vertices to the face centroid. Parameters ---------- fkey : int The face key. Returns ------- float The dimensionless curvature. """ vertices = self.face_vertices(fkey) points = [self.vertex_coordinates(key) for key in vertices] centroid = self.face_centroid(fkey) plane = bestfit_plane(points) max_deviation = max( [distance_point_plane(point, plane) for point in points]) average_distances = vector_average( [distance_point_point(point, centroid) for point in points]) return max_deviation / average_distances
def polygon_flatness(polygon): """Comput the flatness of a polygon. Parameters ---------- polygon : list of lists A list of polygon point coordinates. Returns ------- float The flatness. Note ---- compas.geometry.mesh_flatness function currently only works for quadrilateral faces. This function uses the distance between each face vertex and its projected point on the best-fit plane of the face as the flatness metric. """ deviation = 0 plane = bestfit_plane(polygon) for pt in polygon: pt_proj = project_point_plane(pt, plane) dev = distance_point_point(pt, pt_proj) if dev > deviation: deviation = dev return deviation
def planarize_faces(vertices, faces, fixed=None, kmax=100, callback=None, callback_args=None): """Planarise a set of connected faces. Planarisation is implemented as a two-step iterative procedure. At every iteration, faces are first individually projected to their best-fit plane, and then the vertices are projected to the centroid of the disconnected corners of the faces. Parameters ---------- vertices : list The vertex coordinates. faces : list The vertex indices per face. fixed : list, optional [None] A list of fixed vertices. kmax : int, optional [100] The number of iterations. callback : callable, optional [None] A user-defined callback that is called after every iteration. callback_args : list, optional [None] A list of arguments to be passed to the callback function. """ if callback: if not callable(callback): raise Exception('The callback is not callable.') fixed = fixed or [] fixed = set(fixed) for k in range(kmax): positions = [[] for _ in range(len(vertices))] for face in iter(faces): points = [vertices[index] for index in face] plane = bestfit_plane(points) projections = project_points_plane(points, plane) for i, index in enumerate(face): positions[index].append(projections[i]) for index, vertex in enumerate(vertices): if index in fixed: continue x, y, z = centroid_points(positions[index]) vertex[0] = x vertex[1] = y vertex[2] = z if callback: callback(k, callback_args)
def mesh_planarize_faces(mesh, fixed=None, kmax=100, callback=None, callback_args=None): """Planarise a set of connected faces. Planarisation is implemented as a two-step iterative procedure. At every iteration, faces are first individually projected to their best-fit plane, and then the vertices are projected to the centroid of the disconnected corners of the faces. Parameters ---------- mesh : :class:`compas.datastructures.Mesh` A mesh object. fixed : list[int], optional A list of fixed vertices. kmax : int, optional The number of iterations. d : float, optional A damping factor. callback : callable, optional A user-defined callback that is called after every iteration. callback_args : list[Any], optional A list of arguments to be passed to the callback function. Returns ------- None """ if callback: if not callable(callback): raise Exception('The callback is not callable.') fixed = fixed or [] fixed = set(fixed) for k in range(kmax): positions = {key: [] for key in mesh.vertices()} for fkey in mesh.faces(): vertices = mesh.face_vertices(fkey) points = [mesh.vertex_coordinates(key) for key in vertices] plane = bestfit_plane(points) projections = project_points_plane(points, plane) for index, key in enumerate(vertices): positions[key].append(projections[index]) for key, attr in mesh.vertices(True): if key in fixed: continue x, y, z = centroid_points(positions[key]) attr['x'] = x attr['y'] = y attr['z'] = z if callback: callback(k, callback_args)