Ejemplo n.º 1
0
def intersect_curves(nodes1, nodes2):
    r"""Intersect two parametric B |eacute| zier curves.

    Args:
        nodes1 (numpy.ndarray): The nodes in the first curve.
        nodes2 (numpy.ndarray): The nodes in the second curve.

    Returns:
        numpy.ndarray: ``Nx2`` array of intersection parameters.
        Each row contains a pair of values :math:`s` and :math:`t`
        (each in :math:`\left[0, 1\right]`) such that the curves
        intersect: :math:`B_1(s) = B_2(t)`.

    Raises:
        NotImplementedError: If the "intersection polynomial" is
        all zeros -- which indicates coincident curves.
    """
    nodes1 = _curve_helpers.full_reduce(nodes1)
    nodes2 = _curve_helpers.full_reduce(nodes2)

    num_nodes1, _ = nodes1.shape
    num_nodes2, _ = nodes2.shape
    swapped = False
    if num_nodes1 > num_nodes2:
        nodes1, nodes2 = nodes2, nodes1
        swapped = True

    coeffs = normalize_polynomial(to_power_basis(nodes1, nodes2))
    if np.all(coeffs == 0.0):
        raise NotImplementedError(_COINCIDENT_ERR)

    _check_non_simple(coeffs)
    t_vals = roots_in_unit_interval(coeffs)

    final_s = []
    final_t = []
    for t_val in t_vals:
        (x_val,
         y_val), = _curve_helpers.evaluate_multi(nodes2,
                                                 np.asfortranarray([t_val]))
        s_val = locate_point(nodes1, x_val, y_val)
        if s_val is not None:
            _resolve_and_add(nodes1, s_val, final_s, nodes2, t_val, final_t)

    result = np.zeros((len(final_s), 2), order='F')
    if swapped:
        final_s, final_t = final_t, final_s

    result[:, 0] = final_s
    result[:, 1] = final_t

    return result
Ejemplo n.º 2
0
def locate_point(nodes, x_val, y_val):
    r"""Find the parameter corresponding to a point on a curve.

    .. note::

       This assumes that the curve :math:`B(s, t)` defined by ``nodes``
       lives in :math:`\mathbf{R}^2`.

    Args:
        nodes (numpy.ndarray): The nodes defining a B |eacute| zier curve.
        x_val (float): The :math:`x`-coordinate of the point.
        y_val (float): The :math:`y`-coordinate of the point.

    Returns:
        Optional[float]: The parameter on the curve (if it exists).
    """
    # First, reduce to the true degree of x(s) and y(s).
    zero1 = _curve_helpers.full_reduce(nodes[:, [0]]) - x_val
    zero2 = _curve_helpers.full_reduce(nodes[:, [1]]) - y_val

    # Make sure we have the lowest degree in front, to make the polynomial
    # solve have the fewest number of roots.
    if zero1.shape[0] > zero2.shape[0]:
        zero1, zero2 = zero2, zero1

    # If the "smallest" is a constant, we can't find any roots from it.
    if zero1.shape[0] == 1:
        # NOTE: We assume that callers won't pass ``nodes`` that are
        #       degree 0, so if ``zero1`` is a constant, ``zero2`` won't be.
        zero1, zero2 = zero2, zero1

    power_basis1 = poly_to_power_basis(zero1[:, 0])
    all_roots = roots_in_unit_interval(power_basis1)
    if all_roots.size == 0:
        return

    # NOTE: We normalize ``power_basis2`` because we want to check for
    #       "zero" values, i.e. f2(s) == 0.
    power_basis2 = normalize_polynomial(poly_to_power_basis(zero2[:, 0]))

    near_zero = np.abs(polynomial.polyval(all_roots, power_basis2))
    index = np.argmin(near_zero)

    if near_zero[index] < _ZERO_THRESHOLD:
        return all_roots[index]
Ejemplo n.º 3
0
    def _call_function_under_test(nodes):
        from bezier import _curve_helpers

        return _curve_helpers.full_reduce(nodes)