def intersection_segment_segment(ab, cd, tol=1e-6): """Compute the intersection of two lines segments. Parameters ---------- ab : tuple XYZ coordinates of two points defining a line segment. cd : tuple XYZ coordinates of two points defining another line segment. tol : float, optional A tolerance for membership verification. Default is ``1e-6``. Returns ------- None If there is no intersection point. list XYZ coordinates of intersection point if one exists. """ x1, x2 = intersection_line_line(ab, cd, tol=tol) if not x1 or not x2: return None if is_point_on_segment(x1, ab, tol=tol) and is_point_on_segment(x2, cd, tol=tol): return centroid_points([x1, x2])
def normal_polygon(polygon, unitized=True): """Compute the normal of a polygon defined by a sequence of points. Parameters ---------- polygon : list of list A list of polygon point coordinates. Returns ------- list The normal vector. Raises ------ ValueError If less than three points are provided. Notes ----- The points in the list should be unique. For example, the first and last point in the list should not be the same. """ p = len(polygon) assert p > 2, "At least three points required" nx = 0 ny = 0 nz = 0 o = centroid_points(polygon) a = polygon[-1] oa = subtract_vectors(a, o) for i in range(p): b = polygon[i] ob = subtract_vectors(b, o) n = cross_vectors(oa, ob) oa = ob nx += n[0] ny += n[1] nz += n[2] if not unitized: return nx, ny, nz length = length_vector([nx, ny, nz]) return nx / length, ny / length, nz / length
def normal_polygon(polygon, unitized=True): """Compute the normal of a polygon defined by a sequence of points. Parameters ---------- polygon : sequence[point] | :class:`compas.geometry.Polygon` A list of polygon point coordinates. unitized : bool, optional If True, unitize the normal vector. Returns ------- [float, float, float] The normal vector. Raises ------ AssertionError If less than three points are provided. Notes ----- The points in the list should be unique. For example, the first and last point in the list should not be the same. """ p = len(polygon) assert p > 2, "At least three points required" nx = 0 ny = 0 nz = 0 o = centroid_points(polygon) a = polygon[-1] oa = subtract_vectors(a, o) for i in range(p): b = polygon[i] ob = subtract_vectors(b, o) n = cross_vectors(oa, ob) oa = ob nx += n[0] ny += n[1] nz += n[2] if not unitized: return [nx, ny, nz] return normalize_vector([nx, ny, nz])
def is_point_in_polyhedron(point, polyhedron): """Determine if the point lies inside the given polyhedron. Parameters ---------- point : (x, y, z) or :class:`compas.geometry.Point` polyhedron : (vertices, faces) or :class:`compas.geometry.Polyhedron`. Returns ------- bool True, if the point lies in the polyhedron. False, otherwise. """ vertices, faces = polyhedron polygons = [[vertices[index] for index in face] for face in faces] planes = [[centroid_points(polygon), normal_polygon(polygon)] for polygon in polygons] return all(is_point_behind_plane(point, plane) for plane in planes)
def is_point_in_polyhedron(point, polyhedron): """Determine if the point lies inside the given polyhedron. Parameters ---------- point : [float, float, float] | :class:`compas.geometry.Point` The test point. polyhedron : [sequence[point], sequence[sequence[int]]] | :class:`compas.geometry.Polyhedron`. The polyhedron defined by a sequence of points and a sequence of faces, with each face defined as a sequence of indices into the sequence of points. Returns ------- bool True, if the point lies in the polyhedron. False, otherwise. """ vertices, faces = polyhedron polygons = [[vertices[index] for index in face] for face in faces] planes = [[centroid_points(polygon), normal_polygon(polygon)] for polygon in polygons] return all(is_point_behind_plane(point, plane) for plane in planes)
def area_polygon(polygon): """Compute the area of a polygon. Parameters ---------- polygon : sequence[point] | :class:`compas.geometry.Polygon` The XYZ coordinates of the vertices/corners of the 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. Examples -------- >>> """ o = centroid_points(polygon) a = polygon[-1] b = polygon[0] oa = subtract_vectors(a, o) ob = subtract_vectors(b, o) n0 = cross_vectors(oa, ob) area = 0.5 * length_vector(n0) for i in range(0, len(polygon) - 1): oa = ob b = polygon[i + 1] ob = subtract_vectors(b, o) n = cross_vectors(oa, ob) if dot_vectors(n, n0) > 0: area += 0.5 * length_vector(n) else: area -= 0.5 * length_vector(n) return area
def volume_polyhedron(polyhedron): r"""Compute the volume of a polyhedron represented by a closed mesh. Parameters ---------- polyhedron : tuple[sequence[[float, float, float] | :class:`compas.geometry.Point`], sequence[sequence[int]]] The vertices and faces of the polyhedron. Returns ------- float The volume of the polyhedron. Notes ----- This implementation is based on the divergence theorem, the fact that the *area vector* is constant for each face, and the fact that the area of each face can be computed as half the length of the cross product of two adjacent edge vectors [1]_. .. math:: :nowrap: \begin{align} V = \int_{P} 1 &= \frac{1}{3} \int_{\partial P} \mathbf{x} \cdot \mathbf{n} \\ &= \frac{1}{3} \sum_{i=0}^{N-1} \int{A_{i}} a_{i} \cdot n_{i} \\ &= \frac{1}{6} \sum_{i=0}^{N-1} a_{i} \cdot \hat n_{i} \end{align} Warnings -------- The volume computed by this funtion is only correct if the polyhedron is convex, has planar faces, and is positively oriented (all face normals point outwards). References ---------- .. [1] Nurnberg, R. *Calculating the area and centroid of a polygon in 2d*. Available at: http://wwwf.imperial.ac.uk/~rn/centroid.pdf """ xyz, faces = polyhedron V = 0 for vertices in faces: if len(vertices) == 3: triangles = [vertices] else: centroid = centroid_points([xyz[i] for i in vertices]) i = len(xyz) xyz.append(centroid) triangles = [] for u, v in pairwise(vertices + vertices[0:1]): triangles.append([i, u, v]) for u, v, w in triangles: a = xyz[u] b = xyz[v] c = xyz[w] ab = subtract_vectors(b, a) ac = subtract_vectors(c, a) n = cross_vectors(ab, ac) V += dot_vectors(a, n) return V / 6.