예제 #1
0
    def from_basis_vectors(cls, xaxis, yaxis):
        """Creates a ``Rotation`` from basis vectors (= orthonormal vectors).

        Parameters
        ----------
        xaxis : :class:`Vector`
            The x-axis of the frame.
        yaxis : :class:`Vector`
            The y-axis of the frame.

        Examples
        --------
        >>> xaxis = [0.68, 0.68, 0.27]
        >>> yaxis = [-0.67, 0.73, -0.15]
        >>> R = Rotation.from_basis_vectors(xaxis, yaxis)

        """
        xaxis = normalize_vector(list(xaxis))
        yaxis = normalize_vector(list(yaxis))
        zaxis = cross_vectors(xaxis, yaxis)
        yaxis = cross_vectors(zaxis, xaxis)  # correction

        R = cls()
        R.matrix[0][0], R.matrix[1][0], R.matrix[2][0] = xaxis
        R.matrix[0][1], R.matrix[1][1], R.matrix[2][1] = yaxis
        R.matrix[0][2], R.matrix[1][2], R.matrix[2][2] = zaxis
        return R
예제 #2
0
파일: matrices.py 프로젝트: yijiangh/compas
def matrix_from_basis_vectors(xaxis, yaxis):
    """Creates a rotation matrix from basis vectors (= orthonormal vectors).

    Parameters
    ----------
    xaxis : list of float
        The x-axis of the frame.
    yaxis : list of float
        The y-axis of the frame.

    Examples
    --------
    >>> xaxis = [0.68, 0.68, 0.27]
    >>> yaxis = [-0.67, 0.73, -0.15]
    >>> R = matrix_from_basis_vectors(xaxis, yaxis)

    """
    xaxis = normalize_vector(list(xaxis))
    yaxis = normalize_vector(list(yaxis))
    zaxis = cross_vectors(xaxis, yaxis)
    yaxis = cross_vectors(zaxis, xaxis)  # correction

    R = identity_matrix(4)
    R[0][0], R[1][0], R[2][0] = xaxis
    R[0][1], R[1][1], R[2][1] = yaxis
    R[0][2], R[1][2], R[2][2] = zaxis
    return R
예제 #3
0
def orthonormalize_axes(xaxis, yaxis):
    """Corrects xaxis and yaxis to be unit vectors and orthonormal.

    Parameters
    ----------
    xaxis: :class:`Vector` or list of float
    yaxis: :class:`Vector` or list of float

    Returns
    -------
    tuple: (xaxis, yaxis)
        The corrected axes.

    Raises
    ------
    ValueError: If xaxis and yaxis cannot span a plane.

    Examples
    --------
    >>> xaxis = [1, 4, 5]
    >>> yaxis = [1, 0, -2]
    >>> xaxis, yaxis = orthonormalize_axes(xaxis, yaxis)
    >>> allclose(xaxis, [0.1543, 0.6172, 0.7715], tol=0.001)
    True
    >>> allclose(yaxis, [0.6929, 0.4891, -0.5298], tol=0.001)
    True
    """
    xaxis = normalize_vector(xaxis)
    yaxis = normalize_vector(yaxis)
    zaxis = cross_vectors(xaxis, yaxis)
    if not norm_vector(zaxis):
        raise ValueError("Xaxis and yaxis cannot span a plane.")
    yaxis = cross_vectors(normalize_vector(zaxis), xaxis)
    return xaxis, yaxis
예제 #4
0
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
예제 #5
0
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
예제 #6
0
파일: matrices.py 프로젝트: yijiangh/compas
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
예제 #7
0
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]
예제 #8
0
def test_axis_and_angle_from_matrix():
    axis1 = normalize_vector([-0.043, -0.254, 0.617])
    angle1 = 0.1
    R = matrix_from_axis_and_angle(axis1, angle1)
    axis2, angle2 = axis_and_angle_from_matrix(R)
    assert allclose(axis1, axis2)
    assert allclose([angle1], [angle2])
예제 #9
0
def test_axis_and_angle():
    axis1 = normalize_vector([-0.043, -0.254, 0.617])
    angle1 = 0.1
    R = Rotation.from_axis_and_angle(axis1, angle1)
    axis2, angle2 = R.axis_and_angle
    assert allclose(axis1, axis2)
    assert allclose([angle1], [angle2])
예제 #10
0
파일: matrices.py 프로젝트: yijiangh/compas
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
예제 #11
0
파일: matrices.py 프로젝트: yijiangh/compas
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
예제 #12
0
def plane_from_points(a, b, c):
    """Construct a plane from three points.

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

    Returns
    -------
    plane : tuple
        Base point and normal vector (normalized).

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

    """
    ab = subtract_vectors(b, a)
    ac = subtract_vectors(c, a)
    n = normalize_vector(cross_vectors(ab, ac))
    return a, n
예제 #13
0
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)
예제 #14
0
def bestfit_plane_numpy3(points):
    from numpy import asarray
    from numpy import sum
    from functools import partial
    from scipy.optimize import minimize

    def plane(x, y, abc):
        a, b, c = abc
        return a * x + b * y + c

    def error(abc, points):
        result = 0
        for x, y, z in points:
            znew = plane(x, y, abc)
            result += (znew - z)**2
        return result

    c = sum(asarray(points), axis=0) / len(points)
    objective = partial(error, points=points)
    res = minimize(objective, [0, 0, 0])
    a, b, c = res.x
    u = 1.0, 0.0, a
    v = 0.0, 1.0, b
    w = normalize_vector(cross_vectors(u, v))
    return c, w
예제 #15
0
def closest_point_on_plane(point, plane):
    """
    Compute closest point on a plane to a given point.

    Parameters
    ----------
    point : sequenceof float
        XYZ coordinates of point.
    plane : tuple
        The base point and normal defining the plane.

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

    Examples
    --------
    >>> plane = ([0.0, 0.0, 0.0], [0.0, 0.0, 1.0])
    >>> point = [1.0, 2.0, 3.0]
    >>> closest_point_on_plane(point, plane)

    References
    ----------
    http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_plane

    """
    base, normal = plane
    x, y, z = base
    a, b, c = normalize_vector(normal)
    x1, y1, z1 = point
    d = a * x + b * y + c * z
    k = (a * x1 + b * y1 + c * z1 - d) / (a**2 + b**2 + c**2)
    return [x1 - k * a, y1 - k * b, z1 - k * c]
예제 #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 lines_tangent_to_two_cylinder(base_point1, line_vect1, base_point2,
                                  line_vect2, ref_point, dist1, dist2):

    planes1 = p_planes_tangent_to_cylinder(base_point1, line_vect1, ref_point,
                                           dist1)
    planes2 = c_planes_tangent_to_cylinder(base_point2, line_vect2, ref_point,
                                           dist2)
    if planes1 == None or planes2 == None:
        return None
    s1 = intersect_plane_plane_u(planes1[0][1], planes1[0][2], planes2[0][0])
    s1 = normalize_vector(s1)
    s2 = intersect_plane_plane_u(planes1[0][1], planes1[0][2], planes2[1][0])
    s2 = normalize_vector(s2)
    s3 = intersect_plane_plane_u(planes1[1][1], planes1[1][2], planes2[0][0])
    s3 = normalize_vector(s3)
    s4 = intersect_plane_plane_u(planes1[1][1], planes1[1][2], planes2[1][0])
    s4 = normalize_vector(s4)

    return [s1, s2, s3, s4]
예제 #18
0
def test_matrix_from_axis_angle_vector():
    axis1 = normalize_vector([-0.043, -0.254, 0.617])
    angle1 = 0.1
    R = matrix_from_axis_and_angle(axis1, angle1)
    r = [[0.9950248278789664, -0.09200371122722178, -0.03822183963195913, 0.0],
         [0.09224781823368366, 0.9957251324831573, 0.004669108322156158, 0.0],
         [
             0.037628871037522216, -0.008171760019527692, 0.9992583701939277,
             0.0
         ], [0.0, 0.0, 0.0, 1.0]]
    assert np.allclose(R, r)
예제 #19
0
    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]
예제 #20
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]]
예제 #21
0
def tangent_from_point_one(base_point1, line_vect1, base_point2, line_vect2,
                           ref_point, dist1, dist2, nb):
    """[summary]

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

    Parameters
    ----------
    base_point1 : point
        start point of cylinder 1's axis
    line_vect1 : list of two points
        axis vector for cylinder 1, end pt 1 -> end pt 0
    base_point2 : [type]
        [description]
    line_vect2 : [type]
        axis vector for cylinder 2
    ref_point : point
        new vertex point Q
    dist1 : [type]
        [description]
    dist2 : [type]
        [description]
    nb : int
        tangent plane combination (two tangent planes per bar)

    Returns
    -------
    list of two points
        a vector representing the new bar's axis
    """
    planes1 = p_planes_tangent_to_cylinder(base_point1, line_vect1, ref_point,
                                           dist1)
    planes2 = c_planes_tangent_to_cylinder(base_point2, line_vect2, ref_point,
                                           dist2)
    if planes1 == None or planes2 == None:
        print("Tangent planes not found")
        return None
    if nb == 0 or nb == 1:
        _, plane_x_axis, plane_y_axis = planes1[0]
        s = intersect_plane_plane_u(plane_x_axis, plane_y_axis,
                                    planes2[nb % 2][0])
        # s = intersect_plane_plane_u(planes1[0][1], planes1[0][2], planes2[1][0])
    elif nb == 2 or nb == 3:
        _, plane_x_axis, plane_y_axis = planes1[1]
        s = intersect_plane_plane_u(plane_x_axis, plane_y_axis,
                                    planes2[nb % 2][0])
        # s = intersect_plane_plane_u(planes1[1][1], planes1[1][2], planes2[1][0])
    s = normalize_vector(s)
    return [s]
예제 #22
0
def calculate_offset_pos_two_side_two_point_locked(b_struct, v_key, vecs_con_1,
                                                   vecs_con_2, pts_con_1,
                                                   pts_con_2, d_o_1, d_o_2):
    """calculate offsetted plane when the bar's both ends have two contact points

    """
    assert len(vecs_con_1) == 2 and len(pts_con_1) == 2
    assert len(vecs_con_2) == 2 and len(pts_con_2) == 2

    map(normalize_vector, vecs_con_1)
    map(normalize_vector, vecs_con_2)
    v1_1, v1_2 = vecs_con_1
    v2_1, v2_2 = vecs_con_2
    pt_1_1, pt_1_2 = pts_con_1
    pt_2_1, pt_2_2 = pts_con_2

    vm_1 = scale_vector(normalize_vector(add_vectors(v1_1, v1_2)), -1. * d_o_1)
    # original contact point (assuming two bars have the same radius)
    pt_1 = centroid_points([pt_1_1, pt_1_2])
    pt_1_new = translate_points([pt_1], vm_1)[0]

    vm_2 = scale_vector(normalize_vector(add_vectors(v2_1, v2_2)), -1. * d_o_2)
    pt_2 = centroid_points([pt_2_1, pt_2_2])
    pt_2_new = translate_points([pt_2], vm_2)[0]

    vec_x_new = normalize_vector(vector_from_points(pt_1_new, pt_2_new))
    x_ax = b_struct.vertex[v_key]["gripping_plane"][1]

    if not angle_vectors(x_ax, vec_x_new, deg=True) < 90:
        vec_x_new = scale_vector(vec_x_new, -1.)

    pt_o = b_struct.vertex[v_key]["gripping_plane"][0]
    y_ax = b_struct.vertex[v_key]["gripping_plane"][2]
    vec_z = cross_vectors(vec_x_new, y_ax)
    l_n = (pt_1_new, pt_2_new)
    pt_o_n = closest_point_on_line(pt_o, l_n)

    return pt_o_n, vec_x_new, y_ax, vec_z
예제 #23
0
    def from_basis_vectors(cls, xaxis, yaxis):
        """Creates a ``Rotation`` from basis vectors (= orthonormal vectors).

        Args:
            xaxis (:obj:`list` oof :obj:`float`): The x-axis of the frame.
            yaxis (:obj:`list` oof :obj:`float`): The y-axis of the frame.

        Example:
            >>> xaxis = [0.68, 0.68, 0.27]
            >>> yaxis = [-0.67, 0.73, -0.15]
            >>> R = Rotation.from_basis_vectors(xaxis, yaxis)

        """
        xaxis = normalize_vector(list(xaxis))
        yaxis = normalize_vector(list(yaxis))
        zaxis = cross_vectors(xaxis, yaxis)
        yaxis = cross_vectors(zaxis, xaxis)  # correction

        R = cls()
        R.matrix[0][0], R.matrix[1][0], R.matrix[2][0] = xaxis
        R.matrix[0][1], R.matrix[1][1], R.matrix[2][1] = yaxis
        R.matrix[0][2], R.matrix[1][2], R.matrix[2][2] = zaxis
        return R
예제 #24
0
def f_tangent_point_2(x, *args):

    ptM, ex, ey, radius, pt_b_1, l_1, pt_b_2, l_2, d1, d2, ind = args

    r_c = 2 * radius
    ref_point_tmp = add_vectors(scale_vector(ex, x),
                                scale_vector(ey, math.sqrt(r_c * r_c - x * x)))
    ref_point = add_vectors(ref_point_tmp, ptM)

    vecs_l_all = tangent_from_point_one(pt_b_1, l_1, pt_b_2, l_2, ref_point,
                                        d1, d2, ind)

    if vecs_l_all:
        vec_l = vecs_l_all[0]
    else:
        print("error in f")
        f = 1
        return f

    f = abs(
        dot_vectors(normalize_vector(vec_l),
                    normalize_vector(vector_from_points(ptM, ref_point))))

    return f
예제 #25
0
def calculate_offset_pos_two_side_one_point_locked(b_struct, v_key, pt_1, pt_2,
                                                   v1, v2, d_o_1, d_o_2):
    """calculate offsetted plane when the bar's both sides are blocked by vector v1 and v2

    # ! Note: the old y axis is kept in this function, local x axis is updated

    Parameters
    ----------
    b_struct : [type]
        [description]
    v_key : int
        vertex key in BarStructure, representing a physical bar
    pt_1 : list
        first contact point's projection on the bar's axis
    pt_2 : list
        second contact point's projection on the bar's axis
    v1 : list
        first contact point - contact point vector
    v2 : list
        second contact point - contact point vector
    d_o_1 : float
        offset distance for end point #1
    d_o_2 : float
        offset distance for end point #2

    Returns
    -------
    tuple
        offset plane's origin, x-, y-, z-axis
    """

    pt_1_new = add_vectors(pt_1, scale_vector(v1, -1. * d_o_1))
    pt_2_new = add_vectors(pt_2, scale_vector(v2, -1. * d_o_2))

    vec_x_new = normalize_vector(vector_from_points(pt_1_new, pt_2_new))
    x_ax = b_struct.vertex[v_key]["gripping_plane"][1]

    if not angle_vectors(x_ax, vec_x_new, deg=True) < 90:
        vec_x_new = scale_vector(vec_x_new, -1.)

    # transform gripping plane
    pt_o = b_struct.vertex[v_key]["gripping_plane"][0]
    y_ax = b_struct.vertex[v_key]["gripping_plane"][2]
    vec_z = cross_vectors(vec_x_new, y_ax)
    l_n = (pt_1_new, pt_2_new)
    pt_o_new = closest_point_on_line(pt_o, l_n)

    return pt_o_new, vec_x_new, y_ax, vec_z
예제 #26
0
def bestfit_plane_numpy2(points):
    from numpy import asarray
    from numpy import sum
    from numpy import hstack
    from numpy import ones
    from scipy.linalg import solve

    xyz = asarray(points).reshape((-1, 3))
    n = xyz.shape[0]
    c = (sum(xyz, axis=0) / n).reshape((-1, 3))
    A = hstack((xyz[:, 0:2], ones((xyz.shape[0], 1))))
    b = xyz[:, 2:]
    a, b, c = solve(A.T.dot(A), A.T.dot(b))
    u = 1.0, 0.0, a[0]
    v = 0.0, 1.0, b[0]
    w = normalize_vector(cross_vectors(u, v))
    return c, w
예제 #27
0
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
예제 #28
0
def offset_line(line, distance, normal=[0., 0., 1.]):
    """Offset a line by a distance

    Parameters:
        line (tuple): Two points defining the line.
        distances (float or tuples of floats): The offset distance as float.
            A single value determines a constant offset. Alternatively, two
            offset values for the start and end point of the line can be used to
            a create variable offset.
        normal (tuple): The normal of the offset plane.

    Returns:
        offset line (tuple): Two points defining the offset line.

    Examples:

        .. code-block:: python

            line = [(0.0, 0.0, 0.0), (3.0, 3.0, 0.0)]

            distance = 0.2 # constant offset
            line_offset = offset_line(line, distance)
            print(line_offset)

            distance = [0.2, 0.1] # variable offset
            line_offset = offset_line(line, distance)
            print(line_offset)

    """
    pt1, pt2 = line[0], line[1]
    vec = subtract_vectors(pt1, pt2)
    dir_vec = normalize_vector(cross_vectors(vec, normal))

    if isinstance(distance, list):
        distances = distance
    else:
        distances = [distance, distance]

    vec_pt1 = scale_vector(dir_vec, distances[0])
    vec_pt2 = scale_vector(dir_vec, distances[1])
    pt1_new = add_vectors(pt1, vec_pt1)
    pt2_new = add_vectors(pt2, vec_pt2)
    return pt1_new, pt2_new
예제 #29
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)
예제 #30
0
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