def test_area_square(square, R): assert close(area_polygon(square.points), 1) assert close(area_polygon_xy(square.points), 1) assert close(square.area, 1) square.transform(R) assert close(area_polygon(square.points), 1) assert close(area_polygon_xy(square.points), 0) assert close(square.area, 1)
def test_area_triangle(triangle, R): assert close(area_polygon(triangle.points), 0.5) assert close(area_polygon_xy(triangle.points), 0.5) assert close(area_triangle(triangle.points), 0.5) assert close(area_triangle_xy(triangle.points), 0.5) assert close(triangle.area, 0.5) triangle.transform(R) assert close(area_polygon(triangle.points), 0.5) assert close(area_polygon_xy(triangle.points), 0.0) assert close(area_triangle(triangle.points), 0.5) assert close(area_triangle_xy(triangle.points), 0.0) assert close(triangle.area, 0.5)
def area(self): """The area of the polygon. The area is computed as the sum of the areas of the triangles formed by each of the lines of the boundary and the centroid. """ return area_polygon(self.points)
def structure_face_surfaces(structure): eks = radiating_faces(structure) areas = [] for ek in eks: pl = [structure.nodes[nk].xyz() for nk in structure.elements[ek].nodes] areas.append(area_polygon(pl)) return areas
def compute_mass(self): mass = 0 for epk in self.element_properties: mat = self.element_properties[epk].material section = self.element_properties[epk].section thick = self.sections[section].geometry['t'] density = self.materials[mat].p elset = self.element_properties[epk].elset ekeys = self.sets[elset].selection for ek in ekeys: pl = [self.nodes[nk].xyz() for nk in self.elements[ek].nodes] mass += area_polygon(pl) * thick * density self.mass = mass
def face_area(self, fkey): """Compute the area of a face. Parameters ---------- fkey : int The identifier of the face. Returns ------- float The area of the face. """ return area_polygon(self.face_coordinates(fkey))
def bmesh_face_areas(bmesh): """ Retrieve the face areas of a Blender mesh. Parameters: bmesh (obj): Blender mesh object. Returns: list: Areas of each face. float: Total area. """ vertices, edges, faces = bmesh_data(bmesh) polygons = [[vertices[i] for i in face] for face in faces] areas = [area_polygon(polygon) for polygon in polygons] A = sum(areas) return areas, A
def area(self): """float: The area of the polygon.""" return area_polygon(self.points)
def face_area(self, fkey): """Return the area of a face.""" return area_polygon(self.face_coordinates(fkey))
# ============================================================================== if __name__ == "__main__": from compas.geometry import area_polygon from compas.geometry import centroid_points from compas_plotters import Plotter plotter = Plotter(figsize=(10, 7)) points = [[0, 0, 0], [1.0, 0, 0], [1.0, 1.0, 0], [0.5, 0.0, 0], [0, 1.0, 0]] polygon = points[::-1] print(polygon) print(area_polygon(polygon)) n = normal_polygon(polygon, unitized=False) print(n) if n[2] > 0: color = '#ff0000' else: color = '#0000ff' polygons = [{'points': polygon}] points = [{ 'pos': centroid_points(polygon), 'radius': 0.025, 'facecolor': color }]
def smooth_area(vertices, faces, adjacency, fixed=None, kmax=1, damping=0.5, callback=None, callback_args=None): """Smooth a set of connected vertices by moving each vertex to the centroid of the surrounding faces, weighted by the area of the face. Parameters ---------- vertices : dict A dictionary of vertex coordinates. faces : dict A dictionary of faces referencing the vertices dict. adjacency : dict Adjacency information for each of the vertices. fixed : list, optional The fixed vertices of the mesh. kmax : int, optional The maximum number of iterations. d : float, optional The damping factor. callback : callable, optional A user-defined callback function to be executed after every iteration. callback_args : list, optional A list of arguments to be passed to the callback. Raises ------ Exception If a callback is provided, but it is not callable. Examples -------- .. plot:: :include-source: import compas from compas.datastructures import Mesh from compas.plotters import MeshPlotter from compas.geometry import smooth_area mesh = Mesh.from_obj(compas.get('faces.obj')) vertices = mesh.get_vertices_attributes('xyz') faces = [mesh.face_vertices(fkey) for fkey in mesh.faces()] adjacency = [mesh.vertex_faces(key, ordered=True) for key in mesh.vertices()] fixed = [key for key in mesh.vertices() if mesh.vertex_degree(key) == 2] lines = [] for u, v in mesh.edges(): lines.append({ 'start': mesh.vertex_coordinates(u, 'xy'), 'end' : mesh.vertex_coordinates(v, 'xy'), 'color': '#cccccc', 'width': 1.0, }) smooth_area(vertices, faces, adjacency, fixed=fixed, kmax=100) for key, attr in mesh.vertices(True): attr['x'] = vertices[key][0] attr['y'] = vertices[key][1] attr['z'] = vertices[key][2] plotter = MeshPlotter(mesh) plotter.draw_lines(lines) plotter.draw_vertices(facecolor={key: '#ff0000' for key in fixed}) plotter.draw_edges() plotter.show() """ if callback: if not callable(callback): raise Exception('Callback is not callable.') fixed = fixed or [] fixed = set(fixed) for k in range(kmax): xyz_0 = [xyz[:] for xyz in vertices] centroid_0 = [ centroid_points([vertices[index] for index in corners]) for corners in faces ] area_0 = [ area_polygon([vertices[index] for index in corners]) for corners in faces ] for index, point in enumerate(xyz_0): if index in fixed: continue A = 0 x, y, z = 0, 0, 0 for nbr in adjacency[index]: if nbr is not None: a = area_0[nbr] c = centroid_0[nbr] x += a * c[0] y += a * c[1] z += a * c[2] A += a if A: x = x / A y = y / A z = z / A vertices[index][0] += damping * (x - point[0]) vertices[index][1] += damping * (y - point[1]) vertices[index][2] += damping * (z - point[2]) if callback: callback(k, callback_args)
def conforming(patch_decomposition, delaunay_mesh, medial_branches, boundary_polylines, edges_to_polyline, feature_points=[], feature_polylines=[]): # convert tri faces [a, b, c] into quad faces [a, b, c, c] # collect pole locations poles = [] poles += [ geometric_key([float(x), float(y), float(z)]) for x, y, z in feature_points ] for polyline in feature_polylines: start = [float(i) for i in polyline[0]] end = [float(i) for i in polyline[-1]] poles += [geometric_key(start), geometric_key(end)] # modify tri faces into quad faces with a double vertex as pole point for fkey in patch_decomposition.faces(): face_vertices = patch_decomposition.face_vertices(fkey) if len(face_vertices) == 3: # find pole location pole = None for vkey in face_vertices: geom_key = geometric_key( patch_decomposition.vertex_coordinates(vkey)) if geom_key in poles: pole = vkey break # modify face if pole is not None: new_face_vertices = face_vertices[:] idx = new_face_vertices.index(vkey) new_face_vertices.insert(idx, vkey) patch_decomposition.delete_face(fkey) patch_decomposition.add_face(new_face_vertices, fkey) # remove remaining tri faces that are not pseudo quads # loop over boundary vertices boundary_vertices = patch_decomposition.vertices_on_boundary() for vkey in boundary_vertices: vertex_faces = patch_decomposition.vertex_faces(vkey, ordered=True) vertex_neighbours = patch_decomposition.vertex_neighbors(vkey, ordered=True) for fkey in vertex_faces: # apply changes if there is an adjacent tri face (pseudo-quads are already transformed) if len(patch_decomposition.face_vertices(fkey)) == 3: # remove quad faces at each extremity tri_faces = vertex_faces[1:-1] vertex_left = vertex_neighbours[-1] vertex_right = vertex_neighbours[0] new_vertices = [] n = len(tri_faces) m = int(floor((n + 1) / 2)) # add new vertices on the adjacent boundary edges depending on the number of triangles to modify polyline_left = edges_to_polyline[(vertex_left, vkey)] point_left = polyline_point(polyline_left, t=.9, snap_to_point=True) if point_left == polyline_left[-1]: # assuming there is at least 3 points point_left = polyline_left[-2] #if geometric_key(point_left) == geometric_key(patch_decomposition.vertex_coordinates(vkey)): # point_left = patch_decomposition.edge_point(vertex_left, vkey, t = .9) vertices_left = [ line_point([ point_left, patch_decomposition.vertex_coordinates(vkey) ], t=float(i) / float(m)) for i in range(m) ] #vertices_left = [patch_decomposition.edge_point(vertex_left, vkey, t = .9 + float(i) / float(m) * .1) for i in range(m)] vertices_left = [ patch_decomposition.add_vertex(attr_dict={ 'x': x, 'y': y, 'z': z }) for x, y, z in vertices_left ] polyline_right = edges_to_polyline[(vertex_right, vkey)] point_right = polyline_point(polyline_right, t=.9, snap_to_point=True) if point_right == polyline_right[-1]: # assuming there is at least 3 points point_right = polyline_right[-2] #if geometric_key(point_right) == geometric_key(patch_decomposition.vertex_coordinates(vkey)): # point_right = patch_decomposition.edge_point(vertex_right, vkey, t = .9) vertices_right = [ line_point([ point_right, patch_decomposition.vertex_coordinates(vkey) ], t=float(i) / float(m)) for i in range(m) ] #vertices_right = [patch_decomposition.edge_point(vertex_right, vkey, t = .9 + float(i) / float(m) * .1) for i in range(m)] vertices_right = [ patch_decomposition.add_vertex(attr_dict={ 'x': x, 'y': y, 'z': z }) for x, y, z in vertices_right ] vertex_centre = [] # add existing vertex if there is an even number of triangles if n % 2 == 0: vertex_centre = [vkey] vertices = vertices_right + vertex_centre + list( reversed(vertices_left)) # modfiy the triangle face vertices for i, fkey in enumerate(tri_faces): face_vertices = patch_decomposition.face_vertices(fkey)[:] idx = face_vertices.index(vkey) face_vertices.insert(idx, vertices[i + 1]) face_vertices.insert(idx, vertices[i]) del face_vertices[idx + 2 - len(face_vertices)] # update edges_to_polyline b = face_vertices[idx - 3] c = face_vertices[idx - 2] d = face_vertices[idx - 1] a = face_vertices[idx] for u, v in [[a, b], [a, d], [b, c]]: if (u, v) in edges_to_polyline: del edges_to_polyline[(u, v)] if (v, u) in edges_to_polyline: del edges_to_polyline[(v, u)] edges_to_polyline[(u, v)] = [ patch_decomposition.vertex_coordinates(u), patch_decomposition.vertex_coordinates(v) ] edges_to_polyline[(v, u)] = [ patch_decomposition.vertex_coordinates(v), patch_decomposition.vertex_coordinates(u) ] # update faces patch_decomposition.delete_face(fkey) patch_decomposition.add_face(face_vertices, fkey) # update quad face on the left fkey_left = vertex_faces[-1] face_vertices = patch_decomposition.face_vertices(fkey_left)[:] idx = face_vertices.index(vkey) face_vertices[idx] = vertices[-1] patch_decomposition.delete_face(fkey_left) patch_decomposition.add_face(face_vertices, fkey_left) del edges_to_polyline[(vertex_left, vkey)] del edges_to_polyline[(vkey, vertex_left)] idx = polyline_left.index(point_left) edges_to_polyline[(vertex_left, vertices[-1])] = polyline_left[:idx + 1] edges_to_polyline[(vertices[-1], vertex_left)] = list( reversed(polyline_left[:idx + 1])) # update quad face on the right fkey_right = vertex_faces[0] face_vertices = patch_decomposition.face_vertices( fkey_right)[:] idx = face_vertices.index(vkey) face_vertices[idx] = vertices[0] patch_decomposition.delete_face(fkey_right) patch_decomposition.add_face(face_vertices, fkey_right) del edges_to_polyline[(vertex_right, vkey)] del edges_to_polyline[(vkey, vertex_right)] idx = polyline_right.index(point_right) edges_to_polyline[(vertex_right, vertices[0])] = polyline_right[:idx + 1] edges_to_polyline[(vertices[0], vertex_right)] = list( reversed(polyline_right[:idx + 1])) break # subidive low quality faces using reference to initial edge polyline faces = list(patch_decomposition.faces()) while len(faces) > 0: fkey = faces.pop() # face values face_normal = patch_decomposition.face_normal(fkey) face_area = patch_decomposition.face_area(fkey) face_vertices = patch_decomposition.face_vertices(fkey) # collect initial polylines polylines = [] for i in range(len(face_vertices)): # exception for pseudo-quads with poles if face_vertices[i - 1] != face_vertices[i]: polylines.append(edges_to_polyline[(face_vertices[i - 1], face_vertices[i])]) # patch values polygon = [] for polyline in polylines: polygon += polyline[:-1] patch_area = area_polygon(polygon) patch_normal = normal_polygon(polygon) signed_face_area = dot_vectors(face_normal, patch_normal) / abs( dot_vectors(face_normal, patch_normal)) * face_area # if degenerated face compared to patch, modify if signed_face_area < 0.1 * patch_area: for u, v in patch_decomposition.face_halfedges(fkey): # collect vertices if patch_decomposition.is_edge_on_boundary(u, v): w = patch_decomposition.face_vertex_descendant(fkey, v) x = patch_decomposition.face_vertex_descendant(fkey, w) fkey_bis = patch_decomposition.halfedge[x][w] if fkey_bis in faces: faces.remove(fkey_bis) z = patch_decomposition.face_vertex_descendant(fkey_bis, w) y = patch_decomposition.face_vertex_descendant(fkey_bis, z) # add new vertices on polylines xa, ya, za = polyline_point(edges_to_polyline[(u, v)], t=.5, snap_to_point=True) a = patch_decomposition.add_vertex(attr_dict={ 'x': xa, 'y': ya, 'z': za }) xb, yb, zb = polyline_point(edges_to_polyline[(w, x)], t=.5, snap_to_point=True) b = patch_decomposition.add_vertex(attr_dict={ 'x': xb, 'y': yb, 'z': zb }) xc, yc, zc = polyline_point(edges_to_polyline[(z, y)], t=.5, snap_to_point=True) c = patch_decomposition.add_vertex(attr_dict={ 'x': xc, 'y': yc, 'z': zc }) # update edges to polylines # uv -> ua + av (and flipped) polyline_uv = edges_to_polyline[(u, v)] del edges_to_polyline[(u, v)] del edges_to_polyline[(v, u)] idx_a = polyline_uv.index([xa, ya, za]) edges_to_polyline[(u, a)] = polyline_uv[:idx_a + 1] edges_to_polyline[(a, u)] = list( reversed(polyline_uv[:idx_a + 1])) edges_to_polyline[(a, v)] = polyline_uv[idx_a:] edges_to_polyline[(v, a)] = list( reversed(polyline_uv[idx_a:])) # wx -> wb + bx (and flipped) polyline_wx = edges_to_polyline[(w, x)] del edges_to_polyline[(w, x)] del edges_to_polyline[(x, w)] idx_b = polyline_wx.index([xb, yb, zb]) edges_to_polyline[(w, b)] = polyline_wx[:idx_b + 1] edges_to_polyline[(b, w)] = list( reversed(polyline_wx[:idx_b + 1])) edges_to_polyline[(b, x)] = polyline_wx[idx_b:] edges_to_polyline[(x, b)] = list( reversed(polyline_wx[idx_b:])) # zy -> zc + yc (and flipped) polyline_zy = edges_to_polyline[(z, y)] del edges_to_polyline[(z, y)] del edges_to_polyline[(y, z)] idx_c = polyline_zy.index([xc, yc, zc]) edges_to_polyline[(z, c)] = polyline_zy[:idx_c + 1] edges_to_polyline[(c, z)] = list( reversed(polyline_zy[:idx_c + 1])) edges_to_polyline[(c, y)] = polyline_zy[idx_c:] edges_to_polyline[(y, c)] = list( reversed(polyline_zy[idx_c:])) # + ab + bc (and flipped) edges_to_polyline[(a, b)] = [ patch_decomposition.vertex_coordinates(a), patch_decomposition.vertex_coordinates(b) ] edges_to_polyline[(b, a)] = [ patch_decomposition.vertex_coordinates(b), patch_decomposition.vertex_coordinates(a) ] edges_to_polyline[(b, c)] = [ patch_decomposition.vertex_coordinates(b), patch_decomposition.vertex_coordinates(c) ] edges_to_polyline[(c, b)] = [ patch_decomposition.vertex_coordinates(c), patch_decomposition.vertex_coordinates(b) ] # delete faces patch_decomposition.delete_face(fkey) patch_decomposition.delete_face(fkey_bis) # add new faces face_1 = patch_decomposition.add_face([u, a, b, x]) face_2 = patch_decomposition.add_face([a, v, w, b]) face_3 = patch_decomposition.add_face([b, w, z, c]) face_4 = patch_decomposition.add_face([b, c, y, x]) faces += [face_1, face_2, face_3, face_4] break initial_vertices = list(patch_decomposition.vertices()) # propagate across curve features if feature_polylines is not None: # store vertex keys on the polyline feature using the map of geometric keys feature_map = [ geometric_key([float(x), float(y), float(z)]) for polyline in feature_polylines for x, y, z in polyline ] vertices_on_feature = [ vkey for vkey in patch_decomposition.vertices() if geometric_key( patch_decomposition.vertex_coordinates(vkey)) in feature_map ] # dictionary mapping vertex geometric keys to vertex indices vertex_map = { geometric_key(patch_decomposition.vertex_coordinates(vkey)): vkey for vkey in patch_decomposition.vertices() } count = patch_decomposition.number_of_faces() * 100 while count > 0 and not patch_decomposition.is_quadmesh(): count -= 1 for fkey in patch_decomposition.faces(): face_vertices = patch_decomposition.face_vertices(fkey) if len(face_vertices) > 4: regular_vertices = [] for i in range(len(face_vertices)): a = face_vertices[i - 2] b = face_vertices[i - 1] c = face_vertices[i] if b in initial_vertices: if b not in vertices_on_feature or a not in vertices_on_feature or c not in vertices_on_feature: regular_vertices.append(b) face_propagation(patch_decomposition, fkey, regular_vertices) break return patch_decomposition # propagate across curve features if feature_polylines is not None: # store vertex keys on the polyline feature using the map of geometric keys feature_map = [ geometric_key([float(x), float(y), float(z)]) for polyline in feature_polylines for x, y, z in polyline ] vertices_on_feature = [ vkey for vkey in patch_decomposition.vertices() if geometric_key( patch_decomposition.vertex_coordinates(vkey)) in feature_map ] # dictionary mapping vertex geometric keys to vertex indices vertex_map = { geometric_key(patch_decomposition.vertex_coordinates(vkey)): vkey for vkey in patch_decomposition.vertices() } # list of edges on curve features polyline_keys = [[ geometric_key([float(x), float(y), float(z)]) for x, y, z in polyline ] for polyline in feature_polylines] feature_edges = [] for u, v in patch_decomposition.edges(): u_key = geometric_key(patch_decomposition.vertex_coordinates(u)) v_key = geometric_key(patch_decomposition.vertex_coordinates(v)) for polyline in polyline_keys: if u_key in polyline and v_key in polyline: feature_edges.append((u, v)) break # store face keys along the polyline faces_along_feature = [] for vkey in vertices_on_feature: for fkey in patch_decomposition.vertex_faces(vkey): if fkey not in faces_along_feature: faces_along_feature.append(fkey) for fkey in faces_along_feature: # check if face has not been deleted in-between if fkey not in list(patch_decomposition.faces()): continue face_vertices = patch_decomposition.face_vertices(fkey) # check if not quad patch if len(face_vertices) > 4: print 'to split' for u, v in patch_decomposition.face_halfedges(fkey): # check where to make the split if u not in vertices_on_feature and v in vertices_on_feature: vkey = patch_decomposition.face_vertex_descendant( fkey, v) wkey = poly_poly_1(patch_decomposition, fkey, vkey) faces_along_feature.append( patch_decomposition.halfedge[wkey][vkey]) # update feature_edges b = patch_decomposition.face_vertex_descendant( patch_decomposition.halfedge[vkey][wkey], wkey) c = patch_decomposition.face_vertex_ancestor( patch_decomposition.halfedge[wkey][vkey], wkey) if (b, c) in feature_edges or (c, b) in feature_edges: if (b, c) in feature_edges: feature_edges.remove((b, c)) else: feature_edges.remove((c, b)) feature_edges.append((b, wkey)) feature_edges.append((wkey, c)) # propagate until boundary or closed loop count = patch_decomposition.number_of_faces() while count > 0: count -= 1 next_fkey = patch_decomposition.halfedge[vkey][ wkey] ukey = patch_decomposition.face_vertex_descendant( next_fkey, wkey) if wkey in patch_decomposition.halfedge[ ukey] and patch_decomposition.halfedge[ ukey][wkey] is not None: next_fkey = patch_decomposition.halfedge[ukey][ wkey] print next_fkey if len( patch_decomposition.face_vertices( next_fkey)) == 5: vkey = wkey old_neighbours = patch_decomposition.vertex_neighbors( vkey) wkey = penta_quad_1( patch_decomposition, next_fkey, wkey) print next_fkey original_vertices = patch_decomposition.face_vertices( next_fkey) original_vertices.remove(vkey) face_propagation(patch_decomposition, next_fkey, original_vertices) new_neighbours = patch_decomposition.vertex_neighbors( vkey) for nbr in new_neighbours: if nbr not in old_neighbours: wkey = nbr break # update feature_edges b = patch_decomposition.face_vertex_descendant( patch_decomposition.halfedge[vkey] [wkey], wkey) c = patch_decomposition.face_vertex_ancestor( patch_decomposition.halfedge[wkey] [vkey], wkey) if (b, c) in feature_edges or ( c, b) in feature_edges: if (b, c) in feature_edges: feature_edges.remove((b, c)) else: feature_edges.remove((c, b)) feature_edges.append((b, wkey)) feature_edges.append((wkey, c)) # add to faces along feature to check faces_along_feature.append( patch_decomposition.halfedge[vkey] [wkey]) faces_along_feature.append( patch_decomposition.halfedge[wkey] [vkey]) continue elif len( patch_decomposition.face_vertices( next_fkey)) == 6: vkey = wkey face_vertices = patch_decomposition.face_vertices( next_fkey) idx = face_vertices.index(vkey) wkey = face_vertices[idx - 3] wkey = hexa_quad_1(patch_decomposition, next_fkey, wkey) original_vertices = patch_decomposition.face_vertices( next_fkey) original_vertices.remove(vkey) original_vertices.remove(wkey) face_propagation(patch_decomposition, next_fkey, original_vertices) # add to faces along feature to check faces_along_feature.append( patch_decomposition.halfedge[vkey] [wkey]) faces_along_feature.append( patch_decomposition.halfedge[wkey] [vkey]) break #elif len(patch_decomposition.face_vertices(next_fkey)) == 4: # vkey = wkey # wkey = quad_tri_1(patch_decomposition, next_fkey, wkey) # # add to faces along feature to check # faces_along_feature.append(patch_decomposition.halfedge[vkey][wkey]) # faces_along_feature.append(patch_decomposition.halfedge[wkey][vkey]) # break break return patch_decomposition
def three_orthonorm_vectors(u, v): v1 = u v2 = u.cross(v) v3 = v2.cross(u) return v1.unitized(), v2.unitized(), v3.unitized() u = cg.Vector(4, 5, -1) v = cg.Vector(2, 3, 5) print(three_orthonorm_vectors(u, v)) ### geometry 2 polygon = [[4, 5, 0], [0, 6, 0], [-3, 2, 0], [-1, 2, 0]] print(cg.area_polygon(polygon)) ### geometry 3i #create arrays of n length array_length = 10 vector_dimension = 3 array_1 = [gen_rand_vector(vector_dimension) for x in range(array_length)] array_2 = [gen_rand_vector(vector_dimension) for x in range(array_length)] ### geometry 3ii cross_products = [] for x in range(array_length): cross_products.append([ array_1[x][1] * array_2[x][2] - array_1[x][2] * array_2[x][1],
1b. Use the cross product to compute the area of a convex, 2D polygon with more than 3 sides. """ from compas.geometry import Vector from compas.geometry import area_polygon #Input points a = #... b = #... c = #... # additional points polygon = [a,b,c] # add additional points here ab = #Vector1 ac = #Vector2 # additional vectors #Calculate area A = #Area # Display area print(A) # Area as computed by the area_polygon function of compas A2 = area_polygon(polygon) print(A2) #and check your result print("Area correct:", A == A2)
def area(self): return area_polygon(self.points)