コード例 #1
0
ファイル: intersections.py プロジェクト: Licini/compas
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
コード例 #2
0
def closest_point_on_line(point, line):
    """Computes closest point on line to a given point.

    Parameters
    ----------
    point : sequence of float
        XYZ coordinates.
    line : tuple
        Two points defining the line.

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

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

    See Also
    --------
    :func:`basic.transformations.project_point_line`

    """
    a, b = line
    ab = subtract_vectors(b, a)
    ap = subtract_vectors(point, a)
    c = vector_component(ap, ab)
    return add_vectors(a, c)
コード例 #3
0
def closest_point_on_line(point, line):
    """Computes closest point on line to a given point.

    Parameters
    ----------
    point : [float, float, float] | :class:`compas.geometry.Point`
        XYZ coordinates.
    line : [point, point] | :class:`compas.geometry.Line`
        Two points defining the line.

    Returns
    -------
    [float, float, float]
        XYZ coordinates of closest point.

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

    See Also
    --------
    :func:`basic.transformations.project_point_line`

    """
    a, b = line
    ab = subtract_vectors(b, a)
    ap = subtract_vectors(point, a)
    c = vector_component(ap, ab)
    return add_vectors(a, c)
コード例 #4
0
ファイル: intersections.py プロジェクト: Licini/compas
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
コード例 #5
0
ファイル: intersections.py プロジェクト: Licini/compas
def intersection_sphere_sphere(sphere1, sphere2):
    """Computes the intersection of 2 spheres.

    There are 4 cases of sphere-sphere intersection : 1) the spheres intersect
    in a circle, 2) they intersect in a point, 3) they overlap, 4) they do not
    intersect.

    Parameters
    ----------
    sphere1 : tuple
        center, radius of the sphere.
    sphere2 : tuple
        center, radius of the sphere.

    Returns
    -------
    case : str
        `point`, `circle`, or `sphere`
    result : tuple
        - point: xyz coordinates
        - circle: center, radius, normal
        - sphere: center, radius

    Examples
    --------
    >>> sphere1 = (3.0, 7.0, 4.0), 10.0
    >>> sphere2 = (7.0, 4.0, 0.0), 5.0
    >>> result = intersection_sphere_sphere(sphere1, sphere2)
    >>> if result:
    ...     case, res = result
    ...     if case == "circle":
    ...         center, radius, normal = res
    ...     elif case == "point":
    ...         point = res
    ...     elif case == "sphere":
    ...         center, radius = res

    References
    --------
    https://gamedev.stackexchange.com/questions/75756/sphere-sphere-intersection-and-circle-sphere-intersection

    """

    center1, radius1 = sphere1
    center2, radius2 = sphere2

    distance = distance_point_point(center1, center2)

    # Case 4: No intersection
    if radius1 + radius2 < distance:
        return None

    # Case 4: No intersection, sphere is within the other sphere
    elif distance + min(radius1, radius2) < max(radius1, radius2):
        return None

    # Case 3: sphere's overlap
    elif radius1 == radius2 and distance == 0:
        return "sphere", sphere1

    # Case 2: point intersection
    elif radius1 + radius2 == distance:
        ipt = subtract_vectors(center2, center1)
        ipt = scale_vector(ipt, radius1/distance)
        ipt = add_vectors(center1, ipt)
        return "point", ipt

    # Case 2: point intersection, smaller sphere is within the bigger
    elif distance + min(radius1, radius2) == max(radius1, radius2):
        if radius1 > radius2:
            ipt = subtract_vectors(center2, center1)
            ipt = scale_vector(ipt, radius1/distance)
            ipt = add_vectors(center1, ipt)
        else:
            ipt = subtract_vectors(center1, center2)
            ipt = scale_vector(ipt, radius2/distance)
            ipt = add_vectors(center2, ipt)
        return "point", ipt

    # Case 1: circle intersection
    h = 0.5 + (radius1**2 - radius2**2)/(2 * distance**2)
    ci = subtract_vectors(center2, center1)
    ci = scale_vector(ci, h)
    ci = add_vectors(center1, ci)
    ri = sqrt(radius1**2 - h**2 * distance**2)
    normal = scale_vector(subtract_vectors(center2, center1), 1/distance)
    return "circle", (ci, ri, normal)
コード例 #6
0
ファイル: average.py プロジェクト: yishizu/compas
def centroid_polyhedron(polyhedron):
    """Compute the center of mass of a polyhedron.

    Parameters
    ----------
    polyhedron : tuple
        The coordinates of the vertices,
        and the indices of the vertices forming the faces.

    Returns
    -------
    list
        XYZ coordinates of the center of mass.

    Warning
    -------
    This function assumes that the vertex cycles of the faces are such that the
    face normals are consistently pointing outwards, resulting in a *positive*
    polyhedron.

    Examples
    --------
    >>> from compas.geometry._core import Polyhedron
    >>> p = Polyhedron.generate(6)
    >>> centroid_polyhedron(p)
    [0.0, 0.0, 0.0]
    """
    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:
            centroid = centroid_points([vertices[index] for index in face])
            w = len(vertices)
            vertices.append(centroid)
            triangles = [[w, u, v] for u, v in pairwise(face + face[0:1])]

        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)

            ab = add_vectors(a, b)
            bc = add_vectors(b, c)
            ca = add_vectors(c, a)

            ab_x2 = dot_vectors(ab, ex)**2
            bc_x2 = dot_vectors(bc, ex)**2
            ca_x2 = dot_vectors(ca, ex)**2

            x += nx * (ab_x2 + bc_x2 + ca_x2)

            ab_y2 = dot_vectors(ab, ey)**2
            bc_y2 = dot_vectors(bc, ey)**2
            ca_y2 = dot_vectors(ca, ey)**2

            y += ny * (ab_y2 + bc_y2 + ca_y2)

            ab_z2 = dot_vectors(ab, ez)**2
            bc_z2 = dot_vectors(bc, ez)**2
            ca_z2 = dot_vectors(ca, ez)**2

            z += nz * (ab_z2 + bc_z2 + ca_z2)

            # 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

    V = V / 6.0

    if V < 1e-9:
        d = 1.0 / (2 * 24)
    else:
        d = 1.0 / (2 * 24 * V)

    x *= d
    y *= d
    z *= d

    return [x, y, z]