Source code for fibomat.curve_tools.biarc_approximation

from typing import List, Union, TYPE_CHECKING

import numpy as np

from fibomat.shapes.line import Line
from fibomat.shapes.arc import Arc
from fibomat.shapes.biarc import Biarc


if TYPE_CHECKING:
    from fibomat.shapes.parametric_curve import ParametricCurve

from fibomat.curve_tools.biarc_approximation.monotone_intervals import intervals_by_osculating_circles, IntervalType
from fibomat.curve_tools.biarc_approximation.spiral_segment import _approximate_param_curve_greedy
from fibomat.curve_tools.biarc_approximation.utils import _make_fixed_tangent_curvature


[docs]def approximate_parametric_curve( param_curve: 'ParametricCurve', rasterize_pitch: float, epsilon: float ) -> List[Union[Arc, Line]]: """Approximate a ParametricCurve with an ArcSpline. Seems to work good: rasterize_pitch > 10 * epsilon rasterize_pitch > epsilon Args: param_curve (ParametricCurve): curve to be approximated rasterize_pitch (float): pitch used for rasterization. epsilon (float): maximal distance between original and approximated curve. Returns: ArcSpline References: - https://www.sciencedirect.com/science/article/pii/037704279400029Z - https://epub.jku.at/obvulihs/content/titleinfo/2474921 - https://www.sciencedirect.com/science/article/abs/pii/S0010448508001681 - (https://www.sciencedirect.com/science/article/pii/S0925772112000326?via%3Dihub) """ if rasterize_pitch <= epsilon: raise ValueError('rasterize_pitch must be large than epsilon.') parameter_values = param_curve.rasterize(rasterize_pitch, safety=1, add_endpoint=True) # For testing of FLUSH_WITHOUT_TRANSITION # parameter_values = np.roll(parameter_values, 10) monotone_curvature_intervals = intervals_by_osculating_circles(param_curve, parameter_values, epsilon) curve_segments = [] for interval_type, monotone_interval in monotone_curvature_intervals: p_0 = param_curve.f(monotone_interval[0]) p_1 = param_curve.f(monotone_interval[-1]) t_0, _ = _make_fixed_tangent_curvature(param_curve, monotone_interval[0], epsilon, 'left') t_1, _ = _make_fixed_tangent_curvature(param_curve, monotone_interval[-1], epsilon, 'right') if interval_type == IntervalType.LINE: curve_segments.append(Line(p_0, p_1)) elif interval_type == IntervalType.BIARC: # todo fix tangents curve_segments.append(Biarc(p_0, p_1, t_0, t_1)) elif interval_type == IntervalType.ARC: if np.allclose(p_0, p_1): raise NotImplementedError( 'Cannot handle closed circles in biarc fitting currently. ' 'Please report this as a bug if you need this.' ) intermediate = param_curve.f(monotone_interval[len(monotone_interval) // 2]) curve_segments.append(Arc.from_points(p_0, intermediate, p_1)) else: new_segs = _approximate_param_curve_greedy( param_curve, monotone_interval, epsilon ) curve_segments.extend( new_segs ) # return parameter_values, curve_segments return curve_segments