1#  Copyright (c) 2021, Manfred Moitzi
2#  License: MIT License
3
4import pytest
5import math
6from ezdxf.math.bspline import bspline_basis_vector, open_uniform_knot_vector
7from ezdxf.math._bspline import Basis
8from ezdxf.acc import USE_C_EXT
9
10basis_functions = [Basis]
11
12if USE_C_EXT:
13    pass
14
15
16@pytest.fixture(params=basis_functions)
17def basis_cls(request):
18    return request.param
19
20
21def make_knots(count, degree):
22    return tuple(open_uniform_knot_vector(count, order=degree + 1))
23
24
25def make_basic_func(count, degree, cls):
26    knots = make_knots(count, degree)
27    return cls(knots=knots, order=degree + 1, count=count)
28
29
30def test_property_exists(basis_cls):
31    degree = 3
32    count = 10
33    knots = make_knots(count, degree)
34    basis_func = basis_cls(knots=knots, order=degree + 1, count=count)
35    assert basis_func.degree == degree
36    assert basis_func.order == degree + 1
37    assert basis_func.max_t == max(knots)
38    assert basis_func.knots == knots
39    assert basis_func.weights == tuple()
40    assert basis_func.is_rational is False
41
42
43def test_bspline_basis_vector(basis_cls):
44    degree = 3
45    count = 10
46    knots = make_knots(count, degree)
47    max_t = max(knots)
48    basis_func = basis_cls(knots=knots, order=degree + 1, count=count)
49    for u in (0, 2, 2.5, 3.5, 4, max_t):
50        basis = bspline_basis_vector(u, count=count, degree=degree, knots=knots)
51        basis2 = basis_func.basis_vector(u)
52        assert len(basis) == len(basis2)
53        for v1, v2 in zip(basis, basis2):
54            assert v1 == pytest.approx(v2)
55
56
57def test_find_span(basis_cls):
58    degree = 3
59    basis_func = make_basic_func(10, degree, basis_cls)
60    for u in [0, 2, 2.5, 3.5, 4]:
61        result = basis_func.find_span(u)
62        span = math.floor(u) + degree
63        assert result == span
64    assert basis_func.find_span(basis_func.max_t) == 9
65
66
67if __name__ == '__main__':
68    pytest.main([__file__])
69