bezier.hazmat.helpers module

Pure Python generic geometry and floating point helpers.

bezier.hazmat.helpers.vector_close(vec1, vec2, eps=9.094947017729282e-13)

Checks that two vectors are equal to some threshold.

Does so by computing \(s_1 = \|v_1\|_2\) and \(s_2 = \|v_2\|_2\) and then checking if

\[\|v_1 - v_2\|_2 \leq \varepsilon \min(s_1, s_2)\]

where \(\varepsilon = 2^{-40} \approx 10^{-12}\) is a fixed threshold. In the rare case that one of vec1 or vec2 is the zero vector (i.e. when \(\min(s_1, s_2) = 0\)) instead checks that the other vector is close enough to zero:

\[\|v_1\|_2 = 0 \Longrightarrow \|v_2\|_2 \leq \varepsilon\]

Note

This function assumes that both vectors have finite values, i.e. that no NaN or infinite numbers occur. NumPy provides numpy.allclose() for coverage of all cases.

Note

There is also a Fortran implementation of this function, which will be used if it can be built.

Parameters
  • vec1 (numpy.ndarray) – First vector (1D) for comparison.

  • vec2 (numpy.ndarray) – Second vector (1D) for comparison.

  • eps (float) – Error threshold. Defaults to \(2^{-40}\).

Returns

Flag indicating if they are close to precision.

Return type

bool

bezier.hazmat.helpers.in_interval(value, start, end)

Checks if a value is an interval (inclusive).

Note

The current implementation does the most basic check, however, in the future, a more generic check may be desired that allows wiggle room around the endpoints to account for round-off.

Note

There is also a Fortran implementation of this function, which will be used if it can be built.

Parameters
  • value (float) – The value to check.

  • start (float) – The (inclusive) start of the interval.

  • end (float) – The (inclusive) end of the interval.

Returns

Indicating if the value is in the interval.

Return type

bool

bezier.hazmat.helpers.bbox(nodes)

Get the bounding box for set of points.

Note

There is also a Fortran implementation of this function, which will be used if it can be built.

Parameters

nodes (numpy.ndarray) – A set of points.

Returns

The left, right, bottom and top bounds for the box.

Return type

Tuple [ float, float, float, float ]

bezier.hazmat.helpers.contains_nd(nodes, point)

Predicate indicating if a point is within a bounding box.

Note

There is also a Fortran implementation of this function, which will be used if it can be built.

Parameters
  • nodes (numpy.ndarray) – A set of points.

  • point (numpy.ndarray) – A 1D NumPy array representing a point in the same dimension as nodes.

Returns

Indicating containment.

Return type

bool

bezier.hazmat.helpers.cross_product(vec0, vec1)

Compute the cross product of vectors in \(\mathbf{R}^2\).

Utilizes the fact that

\[\begin{split}\left[\begin{array}{c} A \\ B \\ 0 \end{array}\right] \times \left[\begin{array}{c} C \\ D \\ 0 \end{array}\right] = \left[\begin{array}{c} 0 \\ 0 \\ AD - BC \end{array}\right]\end{split}\]

and just returns the \(z\) component.

Note

There is also a Fortran implementation of this function, which will be used if it can be built.

Parameters
  • vec0 (numpy.ndarray) – A vector as a 1D NumPy array with two values.

  • vec1 (numpy.ndarray) – A vector as a 1D NumPy array with two values.

Returns

The cross product (or rather, its \(z\) component).

Return type

float

bezier.hazmat.helpers.matrix_product(mat1, mat2)

Compute the product of two Fortran contiguous matrices.

This is to avoid the overhead of NumPy converting to C-contiguous before computing a matrix product.

Does so via A B = (B^T A^T)^T since B^T and A^T will be C-contiguous without a copy, then the product P = B^T A^T will be C-contiguous and we can return the view P^T without a copy.

Parameters
Returns

The product of the two matrices.

Return type

numpy.ndarray

bezier.hazmat.helpers.wiggle_interval(value, wiggle=5.684341886080802e-14)

Check if value is in \(\left[0, 1\right]\).

Allows a little bit of wiggle room outside the interval. A value within wiggle of 0.0 will be converted to 0.0 and similar for 1.0.

Note

There is also a Fortran implementation of this function, which will be used if it can be built.

Parameters
  • value (float) – Value to check in interval.

  • wiggle (Optional [ float ]) – The amount of wiggle room around the the endpoints 0.0 and 1.0. Defaults to \(2^{-44}\).

Returns

Pair of

  • The value if it’s in the interval, or 0.0 or 1.0 if the value lies slightly outside. If the value is too far outside the unit interval, will be NaN.

  • Boolean indicating if the value is inside the unit interval.

Return type

Tuple [ float, bool ]

bezier.hazmat.helpers.cross_product_compare(start, candidate1, candidate2)

Compare two relative changes by their cross-product.

This is meant to be a way to determine which vector is more “inside” relative to start.

Note

This is a helper for simple_convex_hull().

Parameters
  • start (numpy.ndarray) – The start vector (as 1D NumPy array with 2 elements).

  • candidate1 (numpy.ndarray) – The first candidate vector (as 1D NumPy array with 2 elements).

  • candidate2 (numpy.ndarray) – The second candidate vector (as 1D NumPy array with 2 elements).

Returns

The cross product of the two differences.

Return type

float

bezier.hazmat.helpers.in_sorted(values, value)

Checks if a value is in a sorted list.

Uses the bisect builtin to find the insertion point for value.

Parameters
  • values (List [ int ]) – Integers sorted in ascending order.

  • value (int) – Value to check if contained in values.

Returns

Indicating if the value is contained.

Return type

bool

bezier.hazmat.helpers.simple_convex_hull(points)

Compute the convex hull for a set of points.

This uses Andrew’s monotone chain convex hull algorithm and this code used a wikibooks implementation as motivation. The code there is licensed CC BY-SA 3.0.

Note

There is also a Fortran implementation of this function, which will be used if it can be built. Note that scipy.spatial.ConvexHull can do this as well (via Qhull), but that would require a hard dependency on scipy and that helper computes much more than we need.

Note

This computes the convex hull in a “naive” way. It’s expected that internal callers of this function will have a small number of points so n log n vs. n^2 vs. n aren’t that relevant.

Parameters

points (numpy.ndarray) – A 2 x N array (float64) of points.

Returns

The 2 x N array (float64) of ordered points in the polygonal convex hull.

Return type

numpy.ndarray

bezier.hazmat.helpers.is_separating(direction, polygon1, polygon2)

Checks if a given direction is a separating line for two polygons.

Note

This is a helper for polygon_collide().

Parameters
  • direction (numpy.ndarray) – A 1D 2-array (float64) of a potential separating line for the two polygons.

  • polygon1 (numpy.ndarray) – A 2 x N array (float64) of ordered points in a polygon.

  • polygon2 (numpy.ndarray) – A 2 x N array (float64) of ordered points in a polygon.

Returns

Flag indicating if direction is a separating line.

Return type

bool

bezier.hazmat.helpers.polygon_collide(polygon1, polygon2)

Determines if two convex polygons collide.

This code uses the Separating axis theorem (SAT) to quickly determine if the polygons intersect. See also.

Note

There is also a Fortran implementation of this function, which will be used if it can be built.

Parameters
  • polygon1 (numpy.ndarray) – A 2 x N array (float64) of ordered points in a polygon.

  • polygon2 (numpy.ndarray) – A 2 x N array (float64) of ordered points in a polygon.

Returns

Flag indicating if the two polygons collide.

Return type

bool

bezier.hazmat.helpers.solve2x2(lhs, rhs)

Solve a square 2 x 2 system via LU factorization.

This is meant to be a stand-in for LAPACK’s dgesv, which just wraps two calls to dgetrf and dgetrs. We wrap for two reasons:

  • We seek to avoid exceptions as part of the control flow (which is what numpy.linalg.solve() does).

  • We seek to avoid excessive type- and size-checking, since this special case is already known.

Parameters
Returns

A triple of

  • A flag indicating if lhs is a singular matrix.

  • The first component of the solution.

  • The second component of the solution.

Return type

Tuple [ bool, float, float ]

exception bezier.hazmat.helpers.UnsupportedDegree(degree, supported=())

Bases: NotImplementedError

Custom exception to indicate the given degree is unsupported.

This is intentionally a subclass of a NotImplementedError since it’s intended to indicate a lack of an implementation. For example, Curve.reduce_() uses hard-coded matrices for a small subset of possible degrees, so the implementation is degree-specific:

>>> degree = 5
>>> nodes = np.empty((2, degree + 1), order="F")
>>> curve = bezier.Curve(nodes, degree=degree)
>>> curve.reduce_()
Traceback (most recent call last):
  ...
bezier.hazmat.helpers.UnsupportedDegree: The only degrees supported at
                                         this time are 1, 2, 3 and
                                         4 (degree=5)
Parameters
  • degree (int) – The degree that is not possible to support.

  • supported (Tuple [ int, … ]) – The degrees that are actually supported by the failing method.

degree = None

The degree that the caller attempted to use.

Type

int

args
supported = None

The degrees supported by the failing method.

Type

Tuple [ int, … ]

with_traceback()

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.