def locate_point(nodes, degree, x_val, y_val): r"""Locate a point on a triangle. .. note:: There is also a Fortran implementation of this function, which will be used if it can be built. Does so by recursively subdividing the triangle and rejecting sub-triangles with bounding boxes that don't contain the point. After the sub-triangles are sufficiently small, uses Newton's method to narrow in on the pre-image of the point. Args: nodes (numpy.ndarray): Control points for B |eacute| zier triangle (assumed to be two-dimensional). degree (int): The degree of the triangle. x_val (float): The :math:`x`-coordinate of a point on the triangle. y_val (float): The :math:`y`-coordinate of a point on the triangle. Returns: Optional[Tuple[float, float]]: The :math:`s` and :math:`t` values corresponding to ``x_val`` and ``y_val`` or :data:`None` if the point is not on the ``triangle``. """ # We track the centroid rather than base_x/base_y/width (by storing triple # the centroid -- to avoid division by three until needed). We also need # to track the width (or rather, just the sign of the width). candidates = [(1.0, 1.0, 1.0, nodes)] for _ in range(MAX_LOCATE_SUBDIVISIONS + 1): next_candidates = [] for candidate in candidates: update_locate_candidates( candidate, next_candidates, x_val, y_val, degree ) candidates = next_candidates if not candidates: return None # We take the average of all centroids from the candidates # that may contain the point. s_approx, t_approx = mean_centroid(candidates) s, t = newton_refine(nodes, degree, x_val, y_val, s_approx, t_approx) actual = triangle_helpers.evaluate_barycentric( nodes, degree, 1.0 - s - t, s, t ) expected = np.asfortranarray([x_val, y_val]) if not _py_helpers.vector_close( actual.ravel(order="F"), expected, eps=LOCATE_EPS ): s, t = newton_refine(nodes, degree, x_val, y_val, s, t) return s, t
def _call_function_under_test(vec1, vec2, **kwargs): from bezier.hazmat import helpers return helpers.vector_close(vec1, vec2, **kwargs)