def is_intersection_segment_plane(segment, plane, epsilon=1e-6): """Verify if a line segment intersects with a plane. Parameters: segment (tuple): Two points defining the line segment. plane (tuple): The base point and normal defining the plane. Returns: (bool): True if the line segment intersects with the plane, False otherwise. """ pt1 = segment[0] pt2 = segment[1] p_cent = plane[0] p_norm = plane[1] v1 = subtract_vectors(pt2, pt1) dot = dot_vectors(p_norm, v1) if fabs(dot) > epsilon: v2 = subtract_vectors(pt1, p_cent) fac = -dot_vectors(p_norm, v2) / dot if fac > 0. and fac < 1.: return True return False else: return False
def is_intersection_line_line(l1, l2, tol=1e-6): """Verifies if two lines intersect. Parameters ---------- l1 : tuple A sequence of XYZ coordinates of two 3D points representing two points on the line. l2 : tuple A sequence of XYZ coordinates of two 3D points representing two points on the line. tol : float, optional A tolerance for intersection verification. Default is ``1e-6``. Returns -------- bool ``True``if the lines intersect in one point. ``False`` if the lines are skew, parallel or lie on top of each other. """ a, b = l1 c, d = l2 e1 = normalize_vector(subtract_vectors(b, a)) e2 = normalize_vector(subtract_vectors(d, c)) # check for parallel lines if abs(dot_vectors(e1, e2)) > 1.0 - tol: return False # check for intersection d_vector = cross_vectors(e1, e2) if dot_vectors(d_vector, subtract_vectors(c, a)) == 0: return True return False
def is_intersection_segment_plane(segment, plane, tol=1e-6): """Determine if a line segment intersects with a plane. Parameters ---------- segment : tuple Two points defining the segment. plane : tuple The base point and normal defining the plane. tol : float, optional A tolerance for intersection verification. Default is ``1e-6``. Returns ------- bool ``True`` if the segment intersects with the plane, ``False`` otherwise. """ pt1 = segment[0] pt2 = segment[1] p_cent = plane[0] p_norm = plane[1] v1 = subtract_vectors(pt2, pt1) dot = dot_vectors(p_norm, v1) if fabs(dot) > tol: v2 = subtract_vectors(pt1, p_cent) fac = -dot_vectors(p_norm, v2) / dot if fac > 0. and fac < 1.: return True return False else: return False
def intersection_segment_plane(segment, plane, epsilon=1e-6): """Computes the intersection point of a line segment and a plane Parameters: segment (tuple): Two points defining the line segment. plane (tuple): The base point and normal defining the plane. Returns: point (tuple) if the line segment intersects with the plane, None otherwise. """ pt1 = segment[0] pt2 = segment[1] p_cent = plane[0] p_norm = plane[1] v1 = subtract_vectors(pt2, pt1) dot = dot_vectors(p_norm, v1) if fabs(dot) > epsilon: v2 = subtract_vectors(pt1, p_cent) fac = -dot_vectors(p_norm, v2) / dot if fac > 0. and fac < 1.: vec = scale_vector(v1, fac) return add_vectors(pt1, vec) return None else: return None
def is_intersection_line_line(l1, l2, epsilon=1e-6): """Verifies if two lines intersection in one point. Parameters: ab: (tuple): A sequence of XYZ coordinates of two 3D points representing two points on the line. cd: (tuple): A sequence of XYZ coordinates of two 3D points representing two points on the line. Returns: True (bool): if the lines intersect in one point, False is the lines are skew, parallel or lie on top of each other. """ a, b = l1 c, d = l2 e1 = normalize_vector(subtract_vectors(b, a)) e2 = normalize_vector(subtract_vectors(d, c)) # check for parallel lines if abs(dot_vectors(e1, e2)) > 1.0 - epsilon: return False # check for intersection d_vector = cross_vectors(e1, e2) if dot_vectors(d_vector, subtract_vectors(c, a)) == 0: return True return False
def intersection_line_plane(line, plane, epsilon=1e-6): """Computes the intersection point of a line (ray) and a plane Parameters ---------- line : tuple Two points defining the line. plane : tuple The base point and normal defining the plane. Returns ------- point : tuple if the line (ray) intersects with the plane, None otherwise. """ pt1 = line[0] pt2 = line[1] p_cent = plane[0] p_norm = plane[1] v1 = subtract_vectors(pt2, pt1) dot = dot_vectors(p_norm, v1) if fabs(dot) > epsilon: v2 = subtract_vectors(pt1, p_cent) fac = -dot_vectors(p_norm, v2) / dot vec = scale_vector(v1, fac) return add_vectors(pt1, vec) return None
def matrix_from_parallel_projection(point, normal, direction): """Returns an parallel projection matrix to project onto a plane defined by point, normal and direction. Parameters ---------- point : list of float Base point of the plane. normal : list of float Normal vector of the plane. direction : list of float Direction of the projection. Examples -------- >>> point = [0, 0, 0] >>> normal = [0, 0, 1] >>> direction = [1, 1, 1] >>> P = matrix_from_parallel_projection(point, normal, direction) """ T = identity_matrix(4) normal = normalize_vector(normal) scale = dot_vectors(direction, normal) for j in range(3): for i in range(3): T[i][j] -= direction[i] * normal[j] / scale T[0][3], T[1][3], T[2][3] = scale_vector( direction, dot_vectors(point, normal) / scale) return T
def intersection_line_triangle(line, triangle, epsilon=1e-6): """Computes the intersection point of a line (ray) and a triangle based on the Moeller Trumbore intersection algorithm Parameters ---------- line : tuple Two points defining the line. triangle : sequence of sequence of float XYZ coordinates of the triangle corners. Returns ------- point : tuple if the line (ray) intersects with the triangle, None otherwise. Notes ----- The line is treated as continues, directed ray and not as line segment with a start and end point """ a, b, c = triangle v1 = subtract_vectors(line[1], line[0]) p1 = line[0] # Find vectors for two edges sharing V1 e1 = subtract_vectors(b, a) e2 = subtract_vectors(c, a) # Begin calculating determinant - also used to calculate u parameter p = cross_vectors(v1, e2) # if determinant is near zero, ray lies in plane of triangle det = dot_vectors(e1, p) # NOT CULLING if (det > -epsilon and det < epsilon): return None inv_det = 1.0 / det # calculate distance from V1 to ray origin t = subtract_vectors(p1, a) # Calculate u parameter and make_blocks bound u = dot_vectors(t, p) * inv_det # The intersection lies outside of the triangle if (u < 0.0 or u > 1.0): return None # Prepare to make_blocks v parameter q = cross_vectors(t, e1) # Calculate V parameter and make_blocks bound v = dot_vectors(v1, q) * inv_det # The intersection lies outside of the triangle if (v < 0.0 or u + v > 1.0): return None t = dot_vectors(e2, q) * inv_det if t > epsilon: return add_vectors(p1, scale_vector(v1, t)) # No hit return None
def matrix_from_shear(angle, direction, point, normal): """Constructs a shear matrix by an angle along the direction vector on the shear plane (defined by point and normal). Parameters ---------- angle : float The angle in radians. direction : list of float The direction vector as list of 3 numbers. It must be orthogonal to the normal vector. point : list of float The point of the shear plane as list of 3 numbers. normal : list of float The normal of the shear plane as list of 3 numbers. Raises ------ ValueError If direction and normal are not orthogonal. Notes ----- A point P is transformed by the shear matrix into P" such that the vector P-P" is parallel to the direction vector and its extent is given by the angle of P-P'-P", where P' is the orthogonal projection of P onto the shear plane (defined by point and normal). Examples -------- >>> angle = 0.1 >>> direction = [0.1, 0.2, 0.3] >>> point = [4, 3, 1] >>> normal = cross_vectors(direction, [1, 0.3, -0.1]) >>> S = matrix_from_shear(angle, direction, point, normal) """ normal = normalize_vector(normal) direction = normalize_vector(direction) if math.fabs(dot_vectors(normal, direction)) > _EPS: raise ValueError('Direction and normal vectors are not orthogonal') angle = math.tan(angle) M = [[1. if i == j else 0. for i in range(4)] for j in range(4)] for j in range(3): for i in range(3): M[i][j] += angle * direction[i] * normal[j] M[0][3], M[1][3], M[2][3] = scale_vector( direction, -angle * dot_vectors(point, normal)) return M
def c_planes_tangent_to_cylinder(base_point, line_vect, ref_point, dist): tangent_pts = lines_tangent_to_cylinder(base_point, line_vect, ref_point, dist) if tangent_pts == None: return None _, upper_tang_pt, lower_tang_pt = tangent_pts pv = ref_point dot_1 = dot_vectors(pv, upper_tang_pt) dot_2 = dot_vectors(pv, lower_tang_pt) return [[upper_tang_pt, dot_1], [lower_tang_pt, dot_2]]
def is_intersection_line_plane(line, plane, tol=1e-6): """Determine if a line (ray) intersects with a plane. Parameters ---------- line : tuple Two points defining the line. plane : tuple The base point and normal defining the plane. tol : float, optional A tolerance for intersection verification. Default is ``1e-6``. Returns ------- bool ``True`` if the line intersects with the plane. ``False`` otherwise. """ pt1 = line[0] pt2 = line[1] p_norm = plane[1] v1 = subtract_vectors(pt2, pt1) dot = dot_vectors(p_norm, v1) if fabs(dot) > tol: return True return False
def intersection_plane_plane(plane1, plane2, epsilon=1e-6): """Computes the intersection of two planes Parameters ---------- plane1 : tuple The base point and normal (normalized) defining the 1st plane. plane2 : tuple The base point and normal (normalized) defining the 2nd plane. Returns ------- line : tuple Two points defining the intersection line. None if planes are parallel. """ # check for parallelity of planes if abs(dot_vectors(plane1[1], plane2[1])) > 1 - epsilon: return None vec = cross_vectors(plane1[1], plane2[1]) # direction of intersection line p1 = plane1[0] vec_inplane = cross_vectors(vec, plane1[1]) p2 = add_vectors(p1, vec_inplane) px1 = intersection_line_plane((p1, p2), plane2) px2 = add_vectors(px1, vec) return px1, px2
def intersection_plane_plane(plane1, plane2, tol=1e-6): """Computes the intersection of two planes Parameters ---------- plane1 : tuple The base point and normal (normalized) defining the 1st plane. plane2 : tuple The base point and normal (normalized) defining the 2nd plane. tol : float, optional A tolerance for membership verification. Default is ``1e-6``. Returns ------- line : tuple Two points defining the intersection line. None if planes are parallel. """ o1, n1 = plane1 o2, n2 = plane2 if fabs(dot_vectors(n1, n2)) >= 1 - tol: return None # direction of intersection line d = cross_vectors(n1, n2) # vector in plane 1 perpendicular to the direction of the intersection line v1 = cross_vectors(d, n1) # point on plane 1 p1 = add_vectors(o1, v1) x1 = intersection_line_plane((o1, p1), plane2, tol=tol) x2 = add_vectors(x1, d) return x1, x2
def project_point_plane(point, plane): """Project a point onto a plane. The projection is in the direction perpendicular to the plane. The projected point is thus the closest point on the plane to the original point. Parameters: point (sequence of float): XYZ coordinates of the original point. plane (tuple): Base poin.t and normal vector defining the plane Returns: list: XYZ coordinates of the projected point. Examples: >>> from compas.geometry.transformations import project_point_plane >>> point = [3.0, 3.0, 3.0] >>> plane = ([0.0, 0.0, 0.0], [0.0, 0.0, 1.0]) # the XY plane >>> project_point_plane(point, plane) [3.0, 3.0, 3.0] References: http://stackoverflow.com/questions/8942950/how-do-i-find-the-orthogonal-projection-of-a-point-onto-a-plane http://math.stackexchange.com/questions/444968/project-a-point-in-3d-on-a-given-plane """ base, normal = plane normal = normalize_vector(normal) vector = subtract_vectors(point, base) snormal = scale_vector(normal, dot_vectors(vector, normal)) return subtract_vectors(point, snormal)
def matrix_from_orthogonal_projection(point, normal): """Returns an orthogonal projection matrix to project onto a plane defined by point and normal. Parameters ---------- point : list of float Base point of the plane. normal : list of float Normal vector of the plane. Examples -------- >>> point = [0, 0, 0] >>> normal = [0, 0, 1] >>> P = matrix_from_orthogonal_projection(point, normal) """ T = identity_matrix(4) normal = normalize_vector(normal) for j in range(3): for i in range(3): T[i][j] -= normal[i] * normal[j] # outer_product T[0][3], T[1][3], T[2][3] = scale_vector( normal, dot_vectors(point, normal)) return T
def mirror_vector_vector(v1, v2): """Mirrors vector about vector. Parameters ---------- v1 : list of float The vector. v2 : list of float The normalized vector as mirror axis Returns ------- list of float The mirrored vector. Notes ----- For more info, see [1]_. References ---------- .. [1] Math Stack Exchange. *How to get a reflection vector?* Available at: https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector. """ return subtract_vectors(v1, scale_vector(v2, 2 * dot_vectors(v1, v2)))
def angle_vectors(u, v, deg=False): """Compute the smallest angle between two vectors. Parameters ---------- u : sequence of float XYZ components of the first vector. v : sequence of float XYZ components of the second vector. deg : boolean returns angle in degrees if True Returns ------- float The smallest angle in radians (in degrees if deg == True). The angle is always positive. Examples -------- >>> angle_vectors([0.0, 1.0, 0.0], [1.0, 0.0, 0.0]) """ a = dot_vectors(u, v) / (length_vector(u) * length_vector(v)) a = max(min(a, 1), -1) if deg: return degrees(acos(a)) return acos(a)
def is_coplanar(points, tol=0.01): """Determine if the points are coplanar. Parameters ---------- points : sequence A sequence of locations in three-dimensional space. tol : float, optional A tolerance for planarity validation. Default is ``0.01``. Returns ------- bool ``True`` if the points are coplanar. ``False`` otherwise. Notes ----- Compute the normal vector (cross product) of the vectors formed by the first three points. Include one more vector at a time to compute a new normal and compare with the original normal. If their cross product is not zero, they are not parallel, which means the point are not in the same plane. Four points are coplanar if the volume of the tetrahedron defined by them is 0. Coplanarity is equivalent to the statement that the pair of lines determined by the four points are not skew, and can be equivalently stated in vector form as (x2 - x0).[(x1 - x0) x (x3 - x2)] = 0. """ tol2 = tol**2 if len(points) == 4: v01 = subtract_vectors(points[1], points[0]) v02 = subtract_vectors(points[2], points[0]) v23 = subtract_vectors(points[3], points[0]) res = dot_vectors(v02, cross_vectors(v01, v23)) return res**2 < tol2 # len(points) > 4 # compare length of cross product vector to tolerance a, b, c = sample(points, 3) u = subtract_vectors(b, a) v = subtract_vectors(c, a) w = cross_vectors(u, v) for i in range(0, len(points) - 2): u = v v = subtract_vectors(points[i + 2], points[i + 1]) wuv = cross_vectors(w, cross_vectors(u, v)) if wuv[0]**2 > tol2 or wuv[1]**2 > tol2 or wuv[2]**2 > tol2: return False return True
def intersection_segment_plane(segment, plane, tol=1e-6): """Computes the intersection point of a line segment and a plane Parameters ---------- segment : tuple Two points defining the line segment. plane : tuple The base point and normal defining the plane. tol : float, optional A tolerance for membership verification. Default is ``1e-6``. Returns ------- point : tuple if the line segment intersects with the plane, None otherwise. """ a, b = segment o, n = plane ab = subtract_vectors(b, a) cosa = dot_vectors(n, ab) if fabs(cosa) <= tol: # if the dot product (cosine of the angle between segment and plane) # is close to zero the line and the normal are almost perpendicular # hence there is no intersection return None # based on the ratio = -dot_vectors(n, ab) / dot_vectors(n, oa) # there are three scenarios # 1) 0.0 < ratio < 1.0: the intersection is between a and b # 2) ratio < 0.0: the intersection is on the other side of a # 3) ratio > 1.0: the intersection is on the other side of b oa = subtract_vectors(a, o) ratio = -dot_vectors(n, oa) / cosa if 0.0 <= ratio and ratio <= 1.0: ab = scale_vector(ab, ratio) return add_vectors(a, ab) return None
def volume_polyhedron(polyhedron): r"""Compute the volume of a polyhedron represented by a closed mesh. Parameters ---------- polyhedron : tuple 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} 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: triangles = [] for i in range(1, len(vertices) - 1): triangles.append(vertices[0:1] + vertices[i:i + 2]) 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.
def circle_from_points(a, b, c): """Construct a circle from three points. Parameters ---------- a : sequence of float XYZ coordinates. b : sequence of float XYZ coordinates. c : sequence of float XYZ coordinates. Returns ------- circle : tuple Center, radius, normal of the circle. References ---------- https://en.wikipedia.org/wiki/Circumscribed_circle Examples -------- >>> """ ab = subtract_vectors(b, a) cb = subtract_vectors(b, c) ba = subtract_vectors(a, b) ca = subtract_vectors(a, c) ac = subtract_vectors(c, a) bc = subtract_vectors(c, b) normal = normalize_vector(cross_vectors(ab, ac)) d = 2 * length_vector_sqrd(cross_vectors(ba, cb)) A = length_vector_sqrd(cb) * dot_vectors(ba, ca) / d B = length_vector_sqrd(ca) * dot_vectors(ab, cb) / d C = length_vector_sqrd(ba) * dot_vectors(ac, bc) / d Aa = scale_vector(a, A) Bb = scale_vector(b, B) Cc = scale_vector(c, C) center = sum_vectors([Aa, Bb, Cc]) radius = length_vector(subtract_vectors(a, center)) return center, radius, normal
def is_on_same_side(p1, p2, segment): a, b = segment v = subtract_vectors(b, a) c1 = cross_vectors(v, subtract_vectors(p1, a)) c2 = cross_vectors(v, subtract_vectors(p2, a)) if dot_vectors(c1, c2) >= 0: return True return False
def distance_point_plane(point, plane): r"""Compute the distance from a point to a plane defined by three points. Parameters ---------- point : list Point coordinates. plane : tuple A point and a vector defining a plane. Returns ------- d : float Distance between point and plane. Notes ----- The distance from a pioint to a planbe can be computed from the coefficients of the equation of the plane and the coordinates of the point [1]_. The equation of a plane is .. math:: Ax + By + Cz + D = 0 where .. math:: :nowrap: \begin{align} D &= - Ax_0 - Bx_0 - Cz_0 \\ Q &= (x_0, y_0, z_0) \\ N &= (A, B, C) \end{align} with :math:`Q` a point on the plane, and :math:`N` the normal vector at that point. The distance of any point :math:`P` to a plane is the absolute value of the dot product of the vector from :math:`Q` to :math:`P` and the normal at :math:`Q`. References ---------- .. [1] Nykamp, D. *Distance from point to plane*. Available at: http://mathinsight.org/distance_point_plane. Examples -------- >>> """ base, normal = plane vector = subtract_vectors(point, base) return fabs(dot_vectors(vector, normal))
def __init__(self, point, normal): super(Reflection, self).__init__() normal = normalize_vector((list(normal))) for i in range(3): for j in range(3): self.matrix[i][j] -= 2.0 * normal[i] * normal[j] for i in range(3): self.matrix[i][3] = 2 * dot_vectors(point, normal) *\ normal[i]
def matrix_from_perspective_projection(point, normal, perspective): """Returns a perspective projection matrix to project onto a plane defined by point, normal and perspective. Parameters ---------- point : list of float Base point of the projection plane. normal : list of float Normal vector of the projection plane. perspective : list of float Perspective of the projection. Examples -------- >>> point = [0, 0, 0] >>> normal = [0, 0, 1] >>> perspective = [1, 1, 0] >>> P = matrix_from_perspective_projection(point, normal, perspective) """ T = identity_matrix(4) normal = normalize_vector(normal) T[0][0] = T[1][1] = T[2][2] = dot_vectors( subtract_vectors(perspective, point), normal) for j in range(3): for i in range(3): T[i][j] -= perspective[i] * normal[j] T[0][3], T[1][3], T[2][3] = scale_vector(perspective, dot_vectors(point, normal)) for i in range(3): T[3][i] -= normal[i] T[3][3] = dot_vectors(perspective, normal) return T
def lines_tangent_to_cylinder(base_point, line_vect, ref_point, dist): """Calculating of plane tangents to one cylinder See SP dissertation 3.1.3.b (p. 74) .. image:: ../images/plane_tangent_to_one_cylinder.png :scale: 80 % :align: center Parameters ---------- base_point : [type] [description] line_vect : [type] vector [other end of the axis, base_point], **the direction here is very important!** ref_point : point new point Q dist : float radius of the cylinder Returns ------- list [origin point M, vector MB, -1 * vector MB], the latter two entries represent the tangent points' local coordinate in the plane [point M, e_x, e_y] """ l_vect = normalize_vector(line_vect) line_QMprime = subtract_vectors(ref_point, base_point) # ppol = point M, project out longitutude axis component of base_point ppol = add_vectors(base_point, scale_vector(l_vect, dot_vectors(line_QMprime, l_vect))) # ppolr_vect = line QB line_QM = subtract_vectors(ref_point, ppol) e_x = normalize_vector(line_QM) e_y = cross_vectors(e_x, l_vect) if length_vector(line_QM) == 0: return None x = dist / length_vector(line_QM) # x coordinate in the local axis d_e1 = scale_vector(e_x, dist * x) # d(radius of bar section) has to be larger than l(distance from point to bar axis), otherwise the sqrt turns negative # if d < l: change ref_point if x * x < 1.0: # y coordinate in the local axis d_e2 = scale_vector(e_y, dist * math.sqrt(1.0 - x * x)) else: return None # upper tangent point d_e_add = add_vectors(d_e1, d_e2) # lower tangent point d_e_sub = subtract_vectors(d_e1, d_e2) return [ppol, d_e_add, d_e_sub]
def is_intersection_plane_plane(plane1, plane2, epsilon=1e-6): """Computes the intersection of two planes Parameters: plane1 (tuple): The base point and normal (normalized) defining the 1st plane. plane2 (tuple): The base point and normal (normalized) defining the 2nd plane. Returns: (bool): True if the planes intersect, False otherwise. """ # check for parallelity of planes if abs(dot_vectors(plane1[1], plane2[1])) > 1 - epsilon: return False return True
def mirror_vector_vector(v1, v2): """Mirrors vector about vector. Parameters: v1 (tuple, list, Vector): The vector. v2 (tuple, list, Vector): The normalized vector as mirror axis Returns: Tuple: mirrored vector Resources: http://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector """ return subtract_vectors(v1, scale_vector(v2, 2 * dot_vectors(v1, v2)))
def reflect_line_triangle(line, triangle, tol=1e-6): """Bounce a line of a reflection triangle. Parameters ---------- line : tuple Two points defining the line. triangle : tuple The triangle vertices. tol : float, optional A tolerance for membership verification. Default is ``1e-6``. Returns ------- tuple The reflected line defined by the intersection point of the line and triangle and the mirrored start point of the line with respect to a line perpendicular to the triangle through the intersection. Notes ----- The direction of the line and triangle are important. The line is only reflected if it points towards the front of the triangle. This is true if the dot product of the direction vector of the line and the normal vector of the triangle is smaller than zero. Examples -------- >>> triangle = [1.0, 0, 0], [-1.0, 0, 0], [0, 0, 1.0] >>> line = [-1, 1, 0], [-0.5, 0.5, 0] >>> reflect_line_triangle(line, triangle) ([0.0, 0.0, 0.0], [1.0, 1.0, 0.0]) """ x = intersection_line_triangle(line, triangle, tol=tol) if not x: return a, b = line t1, t2, t3 = triangle ab = subtract_vectors(b, a) n = cross_vectors(subtract_vectors(t2, t1), subtract_vectors(t3, t1)) if dot_vectors(ab, n) > 0: # the line does not point towards the front of the triangle return mirror = x, add_vectors(x, n) return x, mirror_point_line(a, mirror)
def center_of_mass_polyhedron(polyhedron): """Compute the center of mass of a polyhedron""" vertices, faces = polyhedron V = 0 x = 0.0 y = 0.0 z = 0.0 ex = [1.0, 0.0, 0.0] ey = [0.0, 1.0, 0.0] ez = [0.0, 0.0, 1.0] for face in faces: if len(face) == 3: triangles = [face] else: triangles = [] # for i in range(1, len(face) - 1): # triangles.append(face[0:1] + vertices[i:i + 2]) for triangle in triangles: a = vertices[triangle[0]] b = vertices[triangle[1]] c = vertices[triangle[2]] ab = subtract_vectors(b, a) ac = subtract_vectors(c, a) n = cross_vectors(ab, ac) V += dot_vectors(a, n) nx = dot_vectors(n, ex) ny = dot_vectors(n, ey) nz = dot_vectors(n, ez) for j in (-1, 0, 1): ab = add_vectors(vertices[triangle[j]], vertices[triangle[j + 1]]) x += nx * dot_vectors(ab, ex)**2 y += ny * dot_vectors(ab, ey)**2 z += nz * dot_vectors(ab, ez)**2 if V < 1e-9: V = 0.0 d = 1.0 / 48.0 else: V = V / 6.0 d = 1.0 / 48.0 / V x *= d y *= d z *= d return x, y, z