def area_polygon_xy(polygon): """Compute the area of a polygon lying in the XY-plane. Parameters ---------- polygon : sequence[point] | :class:`compas.geometry.Polygon` A sequence of XY(Z) coordinates of 2D or 3D points representing the locations of the corners of a polygon. The vertices are assumed to be in order. The polygon is assumed to be closed: the first and last vertex in the sequence should not be the same. Returns ------- float The area of the polygon. """ o = centroid_points_xy(polygon) u = subtract_vectors_xy(polygon[-1], o) v = subtract_vectors_xy(polygon[0], o) a = 0.5 * cross_vectors_xy(u, v)[2] for i in range(0, len(polygon) - 1): u = v v = subtract_vectors_xy(polygon[i + 1], o) a += 0.5 * cross_vectors_xy(u, v)[2] return fabs(a)
def distance_point_line_sqrd_xy(point, line): """Compute the squared distance between a point and a line lying in the XY-plane. Parameters ---------- point : sequence of float XY(Z) coordinates of a 2D or 3D point (Z will be ignored). line : list, tuple Line defined by two points. Returns ------- float The squared distance between the point and the line. Notes ----- This implementation computes the orthogonal squared distance from a point P to a line defined by points A and B as twice the area of the triangle ABP divided by the length of AB [1]_. References ---------- .. [1] Wikipedia. *Distance from a point to a line*. Available at: https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line. """ a, b = line ab = subtract_vectors_xy(b, a) pa = subtract_vectors_xy(a, point) pb = subtract_vectors_xy(b, point) length = cross_vectors_xy(pa, pb)[2]**2 length_ab = length_vector_sqrd_xy(ab) return length / length_ab
def distance_point_line_xy(point, line): """Compute the distance between a point and a line, assuming they lie in the XY-plane. Parameters ---------- point : [float, float] or [float, float, float] | :class:`compas.geometry.Point` XY(Z) coordinates of the point. line : [point, point] | :class:`compas.geometry.Line` Line defined by two points. Returns ------- float The distance between the point and the line. Notes ----- This implementation computes the orthogonal distance from a point P to a line defined by points A and B as twice the area of the triangle ABP divided by the length of AB [1]_. References ---------- .. [1] Wikipedia. *Distance from a point to a line*. Available at: https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line. """ a, b = line ab = subtract_vectors_xy(b, a) pa = subtract_vectors_xy(a, point) pb = subtract_vectors_xy(b, point) length = fabs(cross_vectors_xy(pa, pb)[2]) length_ab = length_vector_xy(ab) return length / length_ab
def normal_triangle_xy(triangle, unitized=True): """Compute the normal vector of a triangle assumed to lie in the XY plane. Parameters ---------- triangle : list of list A list of triangle point coordinates. Z-coordinates are ignored. Returns ------- list The normal vector, which is a vector perpendicular to the XY plane. Raises ------ ValueError If the triangle does not have three vertices. """ a, b, c = triangle ab = subtract_vectors_xy(b, a) ac = subtract_vectors_xy(c, a) n = cross_vectors_xy(ab, ac) if not unitized: return n return [0, 0, n[2] / length_vector(n)]
def normal_triangle_xy(triangle, unitized=True): """Compute the normal vector of a triangle assumed to lie in the XY plane. Parameters ---------- triangle : [point, point, point] | :class:`compas.geometry.Polygon` A list of triangle point coordinates. Z-coordinates are ignored. unitized : bool, optional If True, unitize the normal vector. Returns ------- [float, float, float] The normal vector, which is a vector perpendicular to the XY plane. Raises ------ AssertionError If the triangle does not have three vertices. """ a, b, c = triangle ab = subtract_vectors_xy(b, a) ac = subtract_vectors_xy(c, a) n = cross_vectors_xy(ab, ac) if not unitized: return n return [0, 0, n[2] / length_vector(n)]
def centroid_polygon_xy(polygon): r"""Compute the centroid of the surface of a polygon projected to the XY plane. Parameters ---------- polygon : list of point A sequence of polygon point XY(Z) coordinates. The Z coordinates are ignored. Returns ------- list The XYZ coordinates of the centroid. The Z coodinate is zero. Notes ----- The centroid is the centre of gravity of the polygon surface if mass would be uniformly distributed over it. It is calculated by triangulating the polygon surface with respect to the centroid of the polygon vertices, and then computing the centroid of the centroids of the individual triangles, weighted by the corresponding triangle area in proportion to the total surface area. .. math:: c_x = \frac{1}{A} \sum_{i=1}^{N} A_i \cdot c_{x,i} c_y = \frac{1}{A} \sum_{i=1}^{N} A_i \cdot c_{y,i} c_z = 0 Warning ------- The polygon need not be convex. The polygon may be self-intersecting. However, it is unclear what the meaning of the centroid is in that case. Examples -------- >>> polygon = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.1, 0.1, 0.0], [0.0, 1.0, 0.0]] >>> centroid_polygon_xy(polygon) """ p = len(polygon) assert p > 2, "At least three points required" if p == 3: return centroid_points_xy(polygon) cx, cy = 0.0, 0.0 A2 = 0 o = centroid_points_xy(polygon) a = polygon[-1] b = polygon[0] oa = subtract_vectors_xy(a, o) ob = subtract_vectors_xy(b, o) n0 = cross_vectors_xy(oa, ob) x, y, z = centroid_points_xy([o, a, b]) a2 = fabs(n0[2]) A2 += a2 cx += a2 * x cy += a2 * y for i in range(1, len(polygon)): a = b b = polygon[i] oa = ob ob = subtract_vectors_xy(b, o) n = cross_vectors_xy(oa, ob) x, y, z = centroid_points_xy([o, a, b]) if n[2] * n0[2] > 0: a2 = fabs(n[2]) else: a2 = -fabs(n[2]) A2 += a2 cx += a2 * x cy += a2 * y return [cx / A2, cy / A2, 0.0]