Beispiel #1
0
def rytz_axis_construction(d1: Vec3, d2: Vec3) -> Tuple[Vec3, Vec3, float]:
    """ The Rytz’s axis construction is a basic method of descriptive Geometry
    to find the axes, the semi-major axis and semi-minor axis, starting from two
    conjugated half-diameters.

    Source: `Wikipedia <https://en.m.wikipedia.org/wiki/Rytz%27s_construction>`_

    Given conjugated diameter `d1` is the vector from center C to point P and
    the given conjugated diameter `d2` is the vector from center C to point Q.
    Center of ellipse is always ``(0, 0, 0)``. This algorithm works for
    2D/3D vectors.

    Args:
        d1: conjugated semi-major axis as :class:`Vec3`
        d2: conjugated semi-minor axis as :class:`Vec3`

    Returns:
         Tuple of (major axis, minor axis, ratio)

    """
    Q = Vec3(d1)  # vector CQ
    # calculate vector CP', location P'
    if math.isclose(d1.z, 0, abs_tol=1e-9) and math.isclose(
            d2.z, 0, abs_tol=1e-9):
        # Vec3.orthogonal() works only for vectors in the xy-plane!
        P1 = Vec3(d2).orthogonal(ccw=False)
    else:
        extrusion = d1.cross(d2)
        P1 = extrusion.cross(d2).normalize(d2.magnitude)

    D = P1.lerp(Q)  # vector CD, location D, midpoint of P'Q
    radius = D.magnitude
    radius_vector = (Q - P1).normalize(radius)  # direction vector P'Q
    A = D - radius_vector  # vector CA, location A
    B = D + radius_vector  # vector CB, location B
    if A.isclose(NULLVEC) or B.isclose(NULLVEC):
        raise ArithmeticError('Conjugated axis required, invalid source data.')
    major_axis_length = (A - Q).magnitude
    minor_axis_length = (B - Q).magnitude
    if math.isclose(major_axis_length, 0.) or math.isclose(
            minor_axis_length, 0.):
        raise ArithmeticError('Conjugated axis required, invalid source data.')
    ratio = minor_axis_length / major_axis_length
    major_axis = B.normalize(major_axis_length)
    minor_axis = A.normalize(minor_axis_length)
    return major_axis, minor_axis, ratio
Beispiel #2
0
def minor_axis(major_axis: Vec3, extrusion: Vec3, ratio: float) -> Vec3:
    return extrusion.cross(major_axis).normalize(major_axis.magnitude * ratio)