def angle_points_xy(a, b, c, deg=False): r"""Compute the smallest angle between the vectors defined by the XY components of three points. Parameters ---------- a : sequence of float XY(Z) coordinates of a 2D or 3D point (Z will be ignored). b : sequence of float) XY(Z) coordinates of a 2D or 3D point (Z will be ignored). c : sequence of float) XY(Z) coordinates of a 2D or 3D point (Z will be ignored). deg : boolean returns angle in degrees if True Returns ------- float The smallest angle between the vectors in radians (in degrees if deg == True). The angle is always positive. Notes ----- The vectors are defined in the following way .. math:: \mathbf{u} = \mathbf{b} - \mathbf{a} \\ \mathbf{v} = \mathbf{c} - \mathbf{a} Z components may be provided, but are simply ignored. """ u = subtract_vectors_xy(b, a) v = subtract_vectors_xy(c, a) return angle_vectors_xy(u, v, deg)
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) l = cross_vectors_xy(pa, pb)[2]**2 l_ab = length_vector_sqrd_xy(ab) return l / l_ab
def distance_point_line_xy(point, line): """Compute the distance between a point and a line, assuming they lie in the XY-plane. 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. Parameters ---------- point : sequence of float XY(Z) coordinates of the point. line : list, tuple Line defined by two points. Returns ------- float The distance between the point and the line. References ---------- 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) l = fabs(cross_vectors_xy(pa, pb)[2]) l_ab = length_vector_xy(ab) return l / l_ab
def area_polygon_xy(polygon): """Compute the area of a polygon lying in the XY-plane. Parameters ---------- polygon : sequence 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 abs(a)
def angle_smallest_points_xy(a, b, c): r"""Compute the smallest angle defined by the XY components of three points lying in the XY-plane where the angle is computed at point A in the triangle ABC Parameters ---------- a : sequence of float XY(Z) coordinates of a 2D or 3D point (Z will be ignored). b : sequence of float) XY(Z) coordinates of a 2D or 3D point (Z will be ignored). c : sequence of float) XY(Z) coordinates of a 2D or 3D point (Z will be ignored). Returns ------- float The smallest angle between the vectors. The angle is always positive. Notes ----- The vectors are defined in the following way .. math:: \mathbf{u} = \mathbf{b} - \mathbf{a} \\ \mathbf{v} = \mathbf{c} - \mathbf{a} Z components may be provided, but are simply ignored. """ u = subtract_vectors_xy(b, a) v = subtract_vectors_xy(c, a) a = angle_smallest_vectors_xy(u, v) return a
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 lvec = length_vector_xy(n) return n[0] / lvec, n[1] / lvec, n[2] / lvec
def project_point_line_xy(point, line): """Project a point onto a line in the XY plane. Parameters ---------- point : list of float XY(Z) coordinates of the point. line : tuple Two points defining the projection line. Returns ------- list XYZ coordinates of the projected point, with Z=0. Notes ----- For more info, see [1]_. References ---------- .. [1] Wiki Books. *Linear Algebra/Orthogonal Projection Onto a Line*. Available at: https://en.wikibooks.org/wiki/Linear_Algebra/Orthogonal_Projection_Onto_a_Line. """ a, b = line ab = subtract_vectors_xy(b, a) ap = subtract_vectors_xy(point, a) c = vector_component_xy(ap, ab) return add_vectors_xy(a, c)
def normal_triangle_xy(triangle, normalised=True): a, b, c = triangle ab = subtract_vectors_xy(b, a) ac = subtract_vectors_xy(c, a) n = cross_vectors_xy(ab, ac) if not normalised: return n lvec = length_vector_xy(n) return n[0] / lvec, n[1] / lvec, n[2] / lvec
def normal_triangle_xy(triangle, unitized=True): """Compute the normal vector of a triangle assumed to lie in the XY plane. """ 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 lvec = length_vector_xy(n) return n[0] / lvec, n[1] / lvec, n[2] / lvec
def distance_point_point_sqrd_xy(a, b): """Compute the squared distance between points a and b lying in the XY plane. Parameters ---------- a : sequence of float XY(Z) coordinates of the first point. b : sequence of float) XY(Z) coordinates of the second point. Returns ------- float Squared distance between a and b in the XY-plane. Examples -------- >>> distance([0.0, 0.0], [2.0, 0.0]) 4.0 >>> distance([0.0, 0.0, 0.0], [2.0, 0.0, 0.0]) 4.0 >>> distance([0.0, 0.0, 1.0], [2.0, 0.0, 1.0]) 4.0 """ ab = subtract_vectors_xy(b, a) return length_vector_sqrd_xy(ab)
def distance_point_point_xy(a, b): """Compute the distance between points a and b, assuming they lie in the XY plane. Parameters ---------- a : sequence of float XY(Z) coordinates of a 2D or 3D point (Z will be ignored). b : sequence of float XY(Z) coordinates of a 2D or 3D point (Z will be ignored). Returns ------- float Distance between a and b in the XY-plane. Examples -------- >>> distance_point_point_xy([0.0, 0.0], [2.0, 0.0]) 2.0 >>> distance_point_point_xy([0.0, 0.0, 0.0], [2.0, 0.0, 0.0]) 2.0 >>> distance_point_point_xy([0.0, 0.0, 1.0], [2.0, 0.0, 1.0]) 2.0 """ ab = subtract_vectors_xy(b, a) return length_vector_xy(ab)
def intersection_circle_circle_xy(circle1, circle2): """Calculates the intersection points of two circles in 2d lying in the XY plane. Parameters: circle1 (tuple): center, radius of the first circle in the xy plane. circle2 (tuple): center, radius of the second circle in the xy plane. Returns: points (list of tuples): the intersection points if there are any None: if there are no intersection points """ p1, r1 = circle1[0], circle1[1] p2, r2 = circle2[0], circle2[1] d = length_vector_xy(subtract_vectors_xy(p2, p1)) if d > r1 + r2: return None if d < abs(r1 - r2): return None if (d == 0) and (r1 == r2): return None a = (r1 * r1 - r2 * r2 + d * d) / (2 * d) h = (r1 * r1 - a * a)**0.5 cx2 = p1[0] + a * (p2[0] - p1[0]) / d cy2 = p1[1] + a * (p2[1] - p1[1]) / d i1 = ((cx2 + h * (p2[1] - p1[1]) / d), (cy2 - h * (p2[0] - p1[0]) / d), 0) i2 = ((cx2 - h * (p2[1] - p1[1]) / d), (cy2 + h * (p2[0] - p1[0]) / d), 0) return i1, i2
def mirror_point_point_xy(point, mirror): """Mirror a point about a point. Parameters: point (sequence of float): XY coordinates of the point to mirror. mirror (sequence of float): XY coordinates of the mirror point. """ return add_vectors_xy(mirror, subtract_vectors_xy(mirror, point))
def project_point_line_xy(point, line): """Project a point onto a line. Parameters: point (sequence of float): XY coordinates. line (tuple): Two points defining a line. Returns: list: XY coordinates of the projected point. References: https://en.wikibooks.org/wiki/Linear_Algebra/Orthogonal_Projection_Onto_a_Line """ a, b = line ab = subtract_vectors_xy(b, a) ap = subtract_vectors_xy(point, a) c = vector_component_xy(ap, ab) return add_vectors_xy(a, c)
def closest_point_on_line_xy(point, line): """Compute closest point on line (continuous) to a given point lying in the XY-plane. Parameters ---------- point : sequence of float XY(Z) coordinates of a point. line : tuple Two XY(Z) points defining a line. Returns ------- list XYZ coordinates of closest point (Z = 0.0). """ a, b = line ab = subtract_vectors_xy(b, a) ap = subtract_vectors_xy(point, a) c = vector_component_xy(ap, ab) return add_vectors_xy(a, c)
def angles_points_xy(a, b, c, deg=False): r"""Compute the two angles between the two vectors defined by the XY components of three points. Parameters ---------- a : sequence of float) XY(Z) coordinates. b : sequence of float) XY(Z) coordinates. c : sequence of float) XY(Z) coordinates. deg : boolean returns angles in degrees if True Returns ------- tuple The smallest angle between the vectors in radians (in degrees if deg == True). The smallest angle is returned first. Notes ----- The vectors are defined in the following way .. math:: \mathbf{u} = \mathbf{b} - \mathbf{a} \\ \mathbf{v} = \mathbf{c} - \mathbf{a} Z components may be provided, but are simply ignored. Examples -------- >>> """ u = subtract_vectors_xy(b, a) v = subtract_vectors_xy(c, a) return angles_vectors_xy(u, v, deg)
def centroid_polygon_edges_xy(polygon): """""" L = 0 cx = 0 cy = 0 p = len(polygon) for i in range(-1, p - 1): p1 = polygon[i] p2 = polygon[i + 1] d = length_vector_xy(subtract_vectors_xy(p2, p1)) cx += 0.5 * d * (p1[0] + p2[0]) cy += 0.5 * d * (p1[1] + p2[1]) L += d return [cx / L, cy / L, 0.0]
def mirror_point_point_xy(point, mirror): """Mirror a point about a point. Parameters ---------- point : list of float XY(Z) coordinates of the point to mirror. mirror : list of float XY(Z) coordinates of the mirror point. Returns ------- list of float The mirrored point, with Z=0. """ return add_vectors_xy(mirror, subtract_vectors_xy(mirror, point))
def mirror_point_line_xy(point, line): """Mirror a point about a line. Parameters ---------- point : list of float XY(Z) coordinates of the point to mirror. line : tuple Two points defining the line. XY(Z) coordinates of the two points defining the mirror line. Returns ------- list of float The mirrored point, with Z=0. """ closest = closest_point_on_line_xy(point, line) return add_vectors_xy(closest, subtract_vectors_xy(closest, point))
def center_of_mass_polygon_xy(polygon): """Compute the center of mass of a polygon defined as a sequence of points lying in the XY-plane. The center of mass of a polygon is the centroid of the midpoints of the edges, each weighted by the length of the corresponding edge. Parameters ---------- polygon : sequence A sequence of XY(Z) coordinates of 2D or 3D points (Z will be ignored) representing the locations of the corners of a polygon. Returns ------- tuple of floats The XYZ coordinates of the center of mass (Z = 0.0). Examples -------- >>> """ L = 0 cx = 0 cy = 0 p = len(polygon) for i in range(-1, p - 1): p1 = polygon[i] p2 = polygon[i + 1] d = length_vector_xy(subtract_vectors_xy(p2, p1)) cx += 0.5 * d * (p1[0] + p2[0]) cy += 0.5 * d * (p1[1] + p2[1]) L += d cx = cx / L cy = cy / L return cx, cy, 0.0
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. Examples -------- .. code-block:: python from compas.geometry import centroid_polygon_xy polygon = [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0] ] c = centroid_polygon_xy(polygon) print(c) # [0.5, 0.5, 0.0] .. code-block:: python from compas.geometry import centroid_polygon_xy from compas.geometry import centroid_points_xy polygon = [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.5, 1.0, 0.0], [0.0, 1.0, 0.0] ] c = centroid_polygon(polygon) print(c) # [0.5, 0.5, 0.0] c = centroid_points(polygon) print(c) # [0.5, 0.6, 0.0] 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. """ 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]
def angles_points_xy(a, b, c): u = subtract_vectors_xy(b, a) v = subtract_vectors_xy(c, a) return angles_vectors_xy(u, v)