def angle_vectors_xy(u, v, deg=False, tol=1e-4): """Compute the smallest angle between the XY components of two vectors. Parameters ---------- u : sequence of float The first 2D or 3D vector (Z will be ignored). v : sequence of float) The second 2D or 3D vector (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. Examples -------- >>> """ L = length_vector_xy(u) * length_vector_xy(v) if L < tol: return 0 a = dot_vectors_xy(u, v) / L a = max(min(a, 1), -1) if deg: return degrees(acos(a)) return acos(a)
def angle_vectors_xy(u, v, deg=False, tol=1e-4): """Compute the smallest angle between the XY components of two vectors. Parameters ---------- u : [float, float] or [float, float, float] | :class:`compas.geometry.Vector` The first 2D or 3D vector (Z will be ignored). v : [float, float] or [float, float, float] | :class:`compas.geometry.Vector` The second 2D or 3D vector (Z will be ignored). deg : bool, optional If True, returns the angle in degrees. tol : float, optional Tolerance for the length of the vectors. Returns ------- float The smallest angle in radians (in degrees if ``deg == True``). The angle is always positive. Examples -------- >>> """ L = length_vector_xy(u) * length_vector_xy(v) if L < tol: return 0 a = dot_vectors_xy(u, v) / L a = max(min(a, 1), -1) if deg: return degrees(acos(a)) return acos(a)
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 distance_point_line_xy(point, line): """Compute the distance between a point and a line, assuming they lie in the XY-plane. 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. 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 lvec = length_vector_xy(n) return n[0] / lvec, n[1] / lvec, n[2] / lvec
def centroid_polygon_edges_xy(polygon): """Compute the centroid of the edges of a polygon prohected to the XY plane. Parameters ---------- polygon : sequence[[float, float] or [float, float, float] | :class:`compas.geometry.Point`] A sequence of polygon point coordinates. The Z coordinates will be ignored. Returns ------- [float, float, 0.0] The XYZ coordinates of the centroid in the XY plane. Notes ----- The centroid of the edges is the centroid of the midpoints of the edges, with each midpoint weighted by the length of the corresponding edge proportional to the total length of the boundary. """ 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 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 area_triangle_xy(triangle): """Compute the area of a triangle defined by three points lying in the XY-plane. Parameters ---------- triangle : list of list XY(Z) coordinates of the corners of the triangle. Returns ------- float The area of the triangle. """ return 0.5 * length_vector_xy(normal_triangle_xy(triangle, False))
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 < fabs(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