예제 #1
0
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
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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.

    Note:
        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
예제 #5
0
파일: distance.py 프로젝트: tclim/compas
def distance_point_point_sqrd(a, b):
    """Compute the squared distance bewteen points a and b.

    Parameters
    ----------
    a : sequence of float
        XYZ coordinates of point a.
    b : sequence of float
        XYZ coordinates of point b.

    Returns
    -------
    d2 : float
        Squared distance bewteen a and b.

    Examples
    --------
    >>> distance_point_point_sqrd([0.0, 0.0, 0.0], [2.0, 0.0, 0.0])
    4.0

    See Also
    --------
    distance_point_point_sqrd_xy

    """
    ab = subtract_vectors(b, a)
    return length_vector_sqrd(ab)
예제 #6
0
파일: frame.py 프로젝트: yijiangh/compas
    def represent_point_in_local_coordinates(self, point):
        """Represents a point in the frame's local coordinate system.

        Parameters
        ----------
        point : :obj:`list` of :obj:`float` or :class:`Point`
            A point in world XY.

        Returns
        -------
        :class:`Point`
            A point in the local coordinate system of the frame.

        Examples
        --------
        >>> from compas.geometry import Frame
        >>> f = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15])
        >>> pw1 = [2, 2, 2]
        >>> pf = f.represent_point_in_local_coordinates(pw1)
        >>> pw2 = f.represent_point_in_global_coordinates(pf)
        >>> allclose(pw1, pw2)
        True

        """
        pt = Point(*subtract_vectors(point, self.point))
        T = inverse(matrix_from_basis_vectors(self.xaxis, self.yaxis))
        pt.transform(T)
        return pt
예제 #7
0
파일: distance.py 프로젝트: tclim/compas
def distance_point_point(a, b):
    """Compute the distance bewteen a and b.

    Parameters
    ----------
    a : sequence of float
        XYZ coordinates of point a.
    b : sequence of float
        XYZ coordinates of point b.

    Returns
    -------
    d : float
        Distance bewteen a and b.

    Examples
    --------
    >>> distance_point_point([0.0, 0.0, 0.0], [2.0, 0.0, 0.0])
    2.0

    See Also
    --------
    distance_point_point_xy

    """
    ab = subtract_vectors(b, a)
    return length_vector(ab)
예제 #8
0
def centroid_polygon_edges(polygon):
    """Compute the centroid of the edges of a polygon.

    Parameters
    ----------
    polygon : list of point
        A sequence of polygon point coordinates.

    Returns
    -------
    list
        The XYZ coordinates of the centroid.

    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
    cz = 0
    p = len(polygon)
    for i in range(-1, p - 1):
        p1 = polygon[i]
        p2 = polygon[i + 1]
        d = length_vector(subtract_vectors(p2, p1))
        cx += 0.5 * d * (p1[0] + p2[0])
        cy += 0.5 * d * (p1[1] + p2[1])
        cz += 0.5 * d * (p1[2] + p2[2])
        L += d
    return [cx / L, cy / L, cz / L]
예제 #9
0
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)))
예제 #10
0
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
예제 #11
0
파일: distance.py 프로젝트: tclim/compas
def distance_line_line(l1, l2, tol=0.0):
    """Compute the shortest distance between two lines.

    Parameters
    ----------
    l1 : tuple
        Two points defining a line.
    l2 : tuple
        Two points defining a line.

    Returns
    -------
    d : float
        The distance between the two lines.

    Notes
    -----
    The distance is the absolute value of the dot product of a unit vector that
    is perpendicular to the two lines, and the vector between two points on the lines ([1]_, [2]_).

    If each of the lines is defined by two points (:math:`l_1 = (\mathbf{x_1}, \mathbf{x_2})`,
    :math:`l_2 = (\mathbf{x_3}, \mathbf{x_4})`), then the unit vector that is
    perpendicular to both lines is...

    References
    ----------
    .. [1] Weisstein, E.W. *Line-line Distance*.
           Available at: http://mathworld.wolfram.com/Line-LineDistance.html.
    .. [2] Wikipedia. *Skew lines Distance*.
           Available at: https://en.wikipedia.org/wiki/Skew_lines#Distance.

    Examples
    --------
    >>>

    """
    a, b = l1
    c, d = l2
    ab = subtract_vectors(b, a)
    cd = subtract_vectors(d, c)
    ac = subtract_vectors(c, a)
    n = cross_vectors(ab, cd)
    l = length_vector(n)
    if l <= tol:
        return distance_point_point(closest_point_on_line(l1[0], l2), l1[0])
    n = scale_vector(n, 1.0 / l)
    return fabs(dot_vectors(n, ac))
예제 #12
0
def orient_points(points, reference_plane=None, target_plane=None):
    """Orient points from one plane to another.

    Parameters:
        points (sequence of sequence of float): XYZ coordinates of the points.
        reference_plane (tuple): Base point and normal defining a reference plane.
        target_plane (tuple): Base point and normal defining a target plane.

    Returns:
        points (sequence of sequence of float): XYZ coordinates of the oriented points.

    Note:
        This function is useful to orient a planar problem in the xy-plane to simplify
        the calculation (see example).

    Examples:

        .. code-block:: python

            from compas.geometry.spatial import orient_points
            from compas.geometry.planar import intersection_segment_segment_2d

            reference_plane = [(0.57735,0.57735,0.57735),(1.0, 1.0, 1.0)]

            line_a = [
                (0.288675,0.288675,1.1547),
                (0.866025,0.866025, 0.)
                ]

            line_b = [
                (1.07735,0.0773503,0.57735),
                (0.0773503,1.07735,0.57735)
                ]

            # orient lines to lie in the xy-plane
            line_a_xy = orient_points(line_a, reference_plane)
            line_b_xy = orient_points(line_b, reference_plane)

            # compute intersection in 2d in the xy-plane
            intx_point_xy = intersection_segment_segment_2d(line_a_xy, line_b_xy)

            # re-orient resulting intersection point to lie in the reference plane
            intx_point = orient_points([intx_point_xy], target_plane=reference_plane)[0]
            print(intx_point)

    """

    if not target_plane:
        target_plane = [(0., 0., 0.,), (0., 0., 1.)]

    if not reference_plane:
        reference_plane = [(0., 0., 0.,), (0., 0., 1.)]

    vec_rot = cross_vectors(reference_plane[1], target_plane[1])
    angle = angle_smallest_vectors(reference_plane[1], target_plane[1])
    points = rotate_points(points, vec_rot, angle, reference_plane[0])
    vec_trans = subtract_vectors(target_plane[0], reference_plane[0])
    points = translate_points(points, vec_trans)
    return points
예제 #13
0
def check_length_sol_one(solution, pt_mean, pt, b1, b2, b1_key, b2_key,
                         b_struct):

    vec_sol = solution
    dpp = dropped_perpendicular_points(pt, add_vectors(pt, vec_sol),
                                       b1["axis_endpoints"][0],
                                       b1["axis_endpoints"][1])
    pt_x1 = dpp[0]
    pt_1 = dpp[1]
    dpp = dropped_perpendicular_points(pt, add_vectors(pt, vec_sol),
                                       b2["axis_endpoints"][0],
                                       b2["axis_endpoints"][1])
    pt_x2 = dpp[0]
    pt_2 = dpp[1]

    if pt_x1 == None:
        return None
    if pt_x2 == None:
        return None

    pts_all_b1 = []
    b_vert_n = b_struct.vertex_neighbors(b1_key)
    pts_all_b1.append(b_struct.vertex[b1_key]["axis_endpoints"][0])
    pts_all_b1.append(b_struct.vertex[b1_key]["axis_endpoints"][1])
    for n in b_vert_n:
        pts_all_b1.append(
            dropped_perpendicular_points(
                b1["axis_endpoints"][0], b1["axis_endpoints"][1],
                b_struct.vertex[n]["axis_endpoints"][0],
                b_struct.vertex[n]["axis_endpoints"][1])[0])

    pts_all_b1.append(pt_1)
    pts_b1 = find_points_extreme(pts_all_b1, b1["axis_endpoints"])

    pts_all_b2 = []
    b_vert_n = b_struct.vertex_neighbors(b2_key)
    pts_all_b2.append(b_struct.vertex[b2_key]["axis_endpoints"][0])
    pts_all_b2.append(b_struct.vertex[b2_key]["axis_endpoints"][1])
    for n in b_vert_n:
        pts_all_b2.append(
            dropped_perpendicular_points(
                b2["axis_endpoints"][0], b2["axis_endpoints"][1],
                b_struct.vertex[n]["axis_endpoints"][0],
                b_struct.vertex[n]["axis_endpoints"][1])[0])

    pts_all_b2.append(pt_2)
    pts_b2 = find_points_extreme(pts_all_b2, b2["axis_endpoints"])

    vec_test_dir_1 = subtract_vectors(pt_mean, pt)
    if not check_dir(vec_sol, vec_test_dir_1):
        vec_sol = scale_vector(vec_sol, -1)

    lx1 = distance_point_point(pt, pt_x1)
    lx2 = distance_point_point(pt, pt_x2)
    l_max = lx1 if lx1 > lx2 else lx2

    sol = [vec_sol, l_max, pts_b1, pts_b2]

    return sol
예제 #14
0
def orient_points(points, reference_plane, target_plane):
    """Orient points from one plane to another.

    Parameters
    ----------
    points : list of points
        XYZ coordinates of the points.
    reference_plane : plane
        Base point and normal defining a reference plane.
    target_plane : plane
        Base point and normal defining a target plane.

    Returns
    -------
    points : list of point
        XYZ coordinates of the oriented points.

    Notes
    -----
    This function is useful to orient a planar problem in the xy-plane to simplify
    the calculation (see example).

    Examples
    --------
    >>> from compas.geometry import orient_points
    >>> from compas.geometry import intersection_segment_segment_xy
    >>>
    >>> refplane = ([0.57735, 0.57735, 0.57735], [1.0, 1.0, 1.0])
    >>> tarplane = ([0.0, 0.0, 0.0], [0.0, 0.0, 1.0])
    >>>
    >>> points = [\
            [0.288675, 0.288675, 1.1547],\
            [0.866025, 0.866025, 0.0],\
            [1.077350, 0.077350, 0.57735],\
            [0.077350, 1.077350, 0.57735]\
        ]
    >>>
    >>> points = orient_points(points, refplane, tarplane)
    >>>
    >>> ab = points[0], points[1]
    >>> cd = points[2], points[3]
    >>>
    >>> point = intersection_segment_segment_xy(ab, cd)
    >>>
    >>> points = orient_points([point], tarplane, refplane)
    >>> Point(*points[0])
    Point(0.577, 0.577, 0.577)
    """
    axis = cross_vectors(reference_plane[1], target_plane[1])
    angle = angle_vectors(reference_plane[1], target_plane[1])
    origin = reference_plane[0]

    if angle:
        points = rotate_points(points, angle, axis, origin)

    vector = subtract_vectors(target_plane[0], reference_plane[0])
    points = translate_points(points, vector)

    return points
예제 #15
0
def mirror_point_point(point, mirror):
    """Mirror a point about a point.

    Parameters:
        point (sequence of float): XYZ coordinates of the point to mirror.
        mirror (sequence of float): XYZ coordinates of the mirror point.

    """
    return add_vectors(mirror, subtract_vectors(mirror, point))
예제 #16
0
def intersection_line_line(l1, l2, tol=1e-6):
    """Computes the intersection of two lines.

    Parameters
    ----------
    l1 : tuple, list
        XYZ coordinates of two points defining the first line.
    l2 : tuple, list
        XYZ coordinates of two points defining the second line.
    tol : float, optional
        A tolerance for membership verification.
        Default is ``1e-6``.

    Returns
    -------
    list
        XYZ coordinates of the two points marking the shortest distance between the lines.
        If the lines intersect, these two points are identical.
        If the lines are skewed and thus only have an apparent intersection, the two
        points are different.
        If the lines are parallel, the return value is [None, None].

    Examples
    --------
    >>>

    """
    a, b = l1
    c, d = l2

    ab = subtract_vectors(b, a)
    cd = subtract_vectors(d, c)

    n = cross_vectors(ab, cd)
    n1 = normalize_vector(cross_vectors(ab, n))
    n2 = normalize_vector(cross_vectors(cd, n))

    plane_1 = (a, n1)
    plane_2 = (c, n2)

    i1 = intersection_line_plane(l1, plane_2, tol=tol)
    i2 = intersection_line_plane(l2, plane_1, tol=tol)

    return i1, i2
예제 #17
0
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
예제 #18
0
def volume_polyhedron(polyhedron):
    r"""Compute the volume of a polyhedron represented by a closed mesh.

    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

    """
    V = 0
    for fkey in polyhedron.face:
        vertices = polyhedron.face_vertices(fkey, ordered=True)
        if len(vertices) == 3:
            faces = [vertices]
        else:
            faces = []
            for i in range(1, len(vertices) - 1):
                faces.append(vertices[0:1] + vertices[i:i + 2])
        for face in faces:
            a = polyhedron.vertex_coordinates(face[0])
            b = polyhedron.vertex_coordinates(face[1])
            c = polyhedron.vertex_coordinates(face[2])
            ab = subtract_vectors(b, a)
            ac = subtract_vectors(c, a)
            n = cross_vectors(ab, ac)
            V += dot_vectors(a, n)
    return V / 6.
예제 #19
0
파일: distance.py 프로젝트: tclim/compas
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))
예제 #20
0
def project_point_line(point, line):
    """Project a point onto a line.

    Parameters:
        point (sequence of float): XYZ coordinates.
        line (tuple): Two points defining a line.

    Returns:
        list: XYZ coordinates of the projected point.

    References:
        https://en.wikibooks.org/wiki/Linear_Algebra/Orthogonal_Projection_Onto_a_Line

    """
    a, b = line
    ab = subtract_vectors(b, a)
    ap = subtract_vectors(point, a)
    c = vector_component(ap, ab)

    return add_vectors(a, c)
예제 #21
0
def intersection_line_line(l1, l2):
    """Computes the intersection of two lines.

    Parameters
    ----------
    l1 : tuple, list
        XYZ coordinates of two points defining the first line.
    l2 : tuple, list
        XYZ coordinates of two points defining the second line.

    Returns
    -------
    list
        XYZ coordinates of the two points marking the shortest distance between the lines.
        If the lines intersect, these two points are identical.
        If the lines are skewed and thus only have an apparent intersection, the two
        points are different.
        If the lines are parallel, ...

    Examples
    --------
    >>>

    """
    a, b = l1
    c, d = l2

    ab = subtract_vectors(b, a)
    cd = subtract_vectors(d, c)

    n = cross_vectors(ab, cd)
    n1 = cross_vectors(ab, n)
    n2 = cross_vectors(cd, n)

    plane_1 = (a, n1)
    plane_2 = (c, n2)

    i1 = intersection_line_plane(l1, plane_2)
    i2 = intersection_line_plane(l2, plane_1)

    return [i1, i2]
예제 #22
0
def p_planes_tangent_to_cylinder(
    base_point,
    line_vect,
    ref_point,
    dist,
):
    """find tangent planes of a cylinder passing through a given point ()

    .. image:: ../images/plane_tangent_to_one_cylinder.png
        :scale: 80 %
        :align: center

    Parameters
    ----------
    base_point : point
        point M
    line_vect : vector
        direction of the existing bar's axis, direction [the other pt, base_pt], **direction very important!**
    ref_point : point
        point Q
    dist : float
        cylinder radius

    Returns
    -------
    list of two [ref_point, local_y, local_x]
        local x = QB
        local_y // line_vect
    """
    l_vect = normalize_vector(line_vect)
    tangent_pts = lines_tangent_to_cylinder(base_point, line_vect, ref_point,
                                            dist)
    if tangent_pts is None:
        return None
    base_pt, upper_tang_pt, lower_tang_pt = tangent_pts
    r1 = subtract_vectors(add_vectors(base_pt, upper_tang_pt), ref_point)
    r1 = normalize_vector(r1)
    r2 = subtract_vectors(add_vectors(base_pt, lower_tang_pt), ref_point)
    r2 = normalize_vector(r2)
    return [[ref_point, l_vect, r1], [ref_point, l_vect, r2]]
예제 #23
0
def project_point_plane(point, plane):
    """Project a point onto a plane.

    Parameters
    ----------
    point : list of float
        XYZ coordinates of the point.
    plane : tuple
        Base point and normal vector defining the projection plane.

    Returns
    -------
    list
        XYZ coordinates of the projected point.

    Notes
    -----
    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 [1]_.

    References
    ----------
    .. [1] Math Stack Exchange. *Project a point in 3D on a given plane*.
           Available at: https://math.stackexchange.com/questions/444968/project-a-point-in-3d-on-a-given-plane.

    Examples
    --------
    >>> from compas.geometry 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, 0.0]

    """
    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)
예제 #24
0
def is_polygon_convex(polygon):
    """Determine if a polygon is convex.

    Parameters
    ----------
    polygon : sequence of sequence of floats
        The XYZ coordinates of the corners of the polygon.

    Notes
    -----
    Use this function for *spatial* polygons.
    If the polygon is in a horizontal plane, use :func:`is_polygon_convex_xy` instead.

    Returns
    -------
    bool
        ``True`` if the polygon is convex.
        ``False`` otherwise.

    See Also
    --------
    is_polygon_convex_xy

    """
    c = centroid_polygon(polygon)

    for i in range(-1, len(polygon) - 1):
        p0 = polygon[i]
        p1 = polygon[i - 1]
        p2 = polygon[i + 1]
        v0 = subtract_vectors(c, p0)
        v1 = subtract_vectors(p1, p0)
        v2 = subtract_vectors(p2, p0)
        a1 = angle_vectors(v1, v0)
        a2 = angle_vectors(v0, v2)
        if a1 + a2 > pi:
            return False

    return True
예제 #25
0
def tangent_through_two_points(base_point1, line_vect1, ref_point1,
                               base_point2, line_vect2, ref_point2, dist1,
                               dist2):

    ind = [0, 1]

    sols_vec = []
    sols_pts = []

    # print("tangent_through_two_points", base_point1, line_vect1, ref_point1, base_point2, line_vect2, ref_point2, dist1, dist2)

    for i in ind:
        ret_p1 = p_planes_tangent_to_cylinder(base_point1, line_vect1,
                                              ref_point2,
                                              dist1 + dist2 + dist1 + dist2)
        ret1 = ret_p1[i]
        z_vec = cross_vectors(line_vect1, ret1[2])
        plane1 = (ret1[0], z_vec)
        # print("plane1", plane1)
        pp1 = project_points_plane([ref_point1], plane1)[0]
        vec_move = scale_vector(subtract_vectors(ref_point1, pp1), 0.5)
        pt1 = add_vectors(pp1, vec_move)

        for j in ind:
            ret_p2 = p_planes_tangent_to_cylinder(
                base_point2, line_vect2, ref_point1,
                dist1 + dist2 + dist1 + dist2)
            ret2 = ret_p2[j]
            z_vec = cross_vectors(line_vect2, ret2[2])
            plane2 = (ret2[0], z_vec)
            pp2 = project_points_plane([ref_point2], plane2)[0]
            vec_move = scale_vector(subtract_vectors(ref_point2, pp2), 0.5)
            pt2 = add_vectors(pp2, vec_move)

            sols_pts.append([pt1, pt2])
            sol_vec = subtract_vectors(pt1, pt2)
            sols_vec.append(sol_vec)
    return sols_pts
예제 #26
0
파일: distance.py 프로젝트: tclim/compas
def distance_point_line(point, line):
    """Compute the distance between a point and a line.

    Parameters
    ----------
    point : list, tuple
        Point location.
    line : list, tuple
        Line defined by two points.

    Returns
    -------
    d : float
        The distance between the point and the line.

    Notes
    -----
    This implementation computes the *right angle 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

    Examples
    --------
    >>>

    """
    a, b = line
    ab = subtract_vectors(b, a)
    pa = subtract_vectors(a, point)
    pb = subtract_vectors(b, point)
    l = length_vector(cross_vectors(pa, pb))
    l_ab = length_vector(ab)
    return l / l_ab
예제 #27
0
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)))
예제 #28
0
def angles_points(a, b, c, deg=False):
    r"""Compute the two angles between two vectors defined by three points.

    Parameters
    ----------
    a : sequence of float)
        XYZ coordinates.
    b : sequence of float)
        XYZ coordinates.
    c : sequence of float)
        XYZ 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}

    Examples
    --------
    >>>

    """
    u = subtract_vectors(b, a)
    v = subtract_vectors(c, a)
    return angles_vectors(u, v, deg)
예제 #29
0
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
예제 #30
0
def angles_points(a, b, c):
    r"""Compute the two angles (radians) define by three points.

    Parameters
    ----------
    a : sequence of float)
        XYZ coordinates.
    b : sequence of float)
        XYZ coordinates.
    c : sequence of float)
        XYZ coordinates.

    Returns
    -------
    tuple
        The two angles in radians.
        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(b, a)
    v = subtract_vectors(c, a)
    return angles_vectors(u, v)