dhermes / bezier

Helper for Bézier Curves, Triangles, and Higher Order Objects
Apache License 2.0
262 stars 36 forks source link

Determine a threshold for determining if a curve is a line. #112

Open dhermes opened 6 years ago

dhermes commented 6 years ago

My plan to do this: degree elevate some random lines until the linearization error isn't 0.

dhermes commented 6 years ago
import matplotlib.pyplot as plt
import numpy as np
import seaborn

from bezier._curve_helpers import elevate_nodes
from bezier._geometric_intersection import linearization_error

def experiment(nodes=None, machine_precision=0.5**52):
    if nodes is None:
        nodes = np.asfortranarray(np.random.random((2, 2)))

    line_length = np.linalg.norm(nodes[:, 1] - nodes[:, 0], ord=2)
    original = nodes

    err_vals = []
    for _ in range(9):
        error = linearization_error(nodes)
        rel_error = (error / line_length) / machine_precision
        err_vals.append(rel_error)
        # Elevate for next iteration
        nodes = elevate_nodes(nodes)

    # Don't waste the last computation
    error = linearization_error(nodes)
    rel_error = (error / line_length) / machine_precision
    err_vals.append(rel_error)

    return original, err_vals

seaborn.set()

degrees = np.arange(1, 10 + 1)
random_errs = [experiment() for _ in range(50)]
for _, err_vals in random_errs:
    plt.plot(degrees, err_vals)

plt.show()

results in (and this is typical)

figure_1

dhermes commented 6 years ago

It seems the worst case is usually on the order of eps * d^2 * L (where eps is 2^{-52}, i.e. machine precision, d is the degree, and L is the "true" length of the line).