# Path: third_party/xiuminglib/xiuminglib/linalg.py
# def project_onto(pts, basis):
#     """Projects points onto a basis vector.
# 
#     Args:
#         pts (array_like): 1D array for one vector; 2D N-by-M array for N
#             M-D points.
#         basis (array_like): 1D M-array specifying which basis vector to
#             project to.
# 
#     Returns:
#         numpy.ndarray: Projected point(s) of the same shape.
#     """
#     pts = np.array(pts)
#     if pts.ndim == 1:
#         pts = np.reshape(pts, (1, -1))
#     # Guaranteed N-by-M
#     basis = np.array(basis)
# 
#     w = np.dot(pts, basis) / (np.linalg.norm(basis) ** 2) # length N
#     w = np.tile(w.reshape((-1, 1)), (1, len(basis))) # N-by-M
# 
#     proj = w * basis # N-by-M
# 
#     return proj
# 
# def normalize(vecs, axis=0):
#     """Normalizes vectors.
# 
#     Args:
#         vecs (array_like): 1D array for a single vector, 2D array for multiple
#             vectors, 3D array for an "image" of vectors, etc.
#         axis (int, optional): Along which axis normalization is done.
# 
#     Raises:
#         ValueError: If ``axis`` is illegal.
# 
#     Returns:
#         numpy.ndarray: Normalized vector(s) of the same shape as input.
#     """
#     vecs = np.array(vecs)
# 
#     if axis < 0:
#         raise ValueError("Negative index not allowed for safety")
#     n_dims = vecs.ndim
#     if axis >= n_dims:
#         raise ValueError((
#             "Can't normalize along axis %d when you only have %d dimension(s)"
#         ) % (axis, n_dims))
# 
#     norms = np.linalg.norm(vecs, axis=axis)
#     broadcastable = list(vecs.shape)
#     broadcastable[axis] = 1
#     vecs_normalized = np.divide(vecs, norms.reshape(broadcastable))
# 
#     return vecs_normalized


import numpy as np
from ..linalg import project_onto, normalize



def project_onto_plane(pts, v1, v2, v3):
    """Projects 3D points onto a 2D plane defined by three vertices.

    Since the 2D space can freely rotate and translate on the 3D plane, the
    first vertex will be used as the origin, and the vector from the first to
    the second vertex will be the x-axis.

    WIP.
    """
    pts = np.array(pts)
    v1, v2, v3 = np.array(v1), np.array(v2), np.array(v3)

    # Get +x, +y, and +z directions
    dx = v2 - v1
    dx = normalize(dx)
    dz = np.cross(dx, v3 - v1)

# Path: third_party/xiuminglib/xiuminglib/linalg.py
# def project_onto(pts, basis):
#     """Projects points onto a basis vector.
# 
#     Args:
#         pts (array_like): 1D array for one vector; 2D N-by-M array for N
#             M-D points.
#         basis (array_like): 1D M-array specifying which basis vector to
#             project to.
# 
#     Returns:
#         numpy.ndarray: Projected point(s) of the same shape.
#     """
#     pts = np.array(pts)
#     if pts.ndim == 1:
#         pts = np.reshape(pts, (1, -1))
#     # Guaranteed N-by-M
#     basis = np.array(basis)
# 
#     w = np.dot(pts, basis) / (np.linalg.norm(basis) ** 2) # length N
#     w = np.tile(w.reshape((-1, 1)), (1, len(basis))) # N-by-M
# 
#     proj = w * basis # N-by-M
# 
#     return proj
# 
# def normalize(vecs, axis=0):
#     """Normalizes vectors.
# 
#     Args:
#         vecs (array_like): 1D array for a single vector, 2D array for multiple
#             vectors, 3D array for an "image" of vectors, etc.
#         axis (int, optional): Along which axis normalization is done.
# 
#     Raises:
#         ValueError: If ``axis`` is illegal.
# 
#     Returns:
#         numpy.ndarray: Normalized vector(s) of the same shape as input.
#     """
#     vecs = np.array(vecs)
# 
#     if axis < 0:
#         raise ValueError("Negative index not allowed for safety")
#     n_dims = vecs.ndim
#     if axis >= n_dims:
#         raise ValueError((
#             "Can't normalize along axis %d when you only have %d dimension(s)"
#         ) % (axis, n_dims))
# 
#     norms = np.linalg.norm(vecs, axis=axis)
#     broadcastable = list(vecs.shape)
#     broadcastable[axis] = 1
#     vecs_normalized = np.divide(vecs, norms.reshape(broadcastable))
# 
#     return vecs_normalized


# Path: third_party/xiuminglib/xiuminglib/geometry/pt.py
import numpy as np
from ..linalg import project_onto, normalize




def project_onto_plane(pts, v1, v2, v3):
    """Projects 3D points onto a 2D plane defined by three vertices.

    Since the 2D space can freely rotate and translate on the 3D plane, the
    first vertex will be used as the origin, and the vector from the first to
    the second vertex will be the x-axis.

    WIP.
    """
    pts = np.array(pts)
    v1, v2, v3 = np.array(v1), np.array(v2), np.array(v3)

    # Get +x, +y, and +z directions
    dx = v2 - v1
    dx = normalize(dx)
    dz = np.cross(dx, v3 - v1)

    dz = normalize(dz)