InterpolatePy 3.1.0__tar.gz → 3.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/InterpolatePy.egg-info/PKG-INFO +1 -1
  2. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/PKG-INFO +1 -1
  3. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/bspline_interpolator.cpp +26 -13
  4. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/log_quaternion_interpolation.cpp +0 -3
  5. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/modified_log_quaternion_interpolation.cpp +0 -3
  6. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_bspline_variants.cpp +67 -4
  7. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/b_spline_interpolate.py +13 -9
  8. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/log_quat.py +0 -5
  9. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/version.py +1 -1
  10. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_b_spline_variants.py +65 -4
  11. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_log_quat.py +27 -8
  12. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/.editorconfig +0 -0
  13. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/.gitattributes +0 -0
  14. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/.github/FUNDING.yml +0 -0
  15. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/.github/workflows/docs.yml +0 -0
  16. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/.github/workflows/pre-commit.yml +0 -0
  17. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/.github/workflows/publish.yml +0 -0
  18. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/.github/workflows/test.yml +0 -0
  19. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/.gitignore +0 -0
  20. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/.pre-commit-config.yaml +0 -0
  21. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/.python-version +0 -0
  22. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/ALGORITHMS.md +0 -0
  23. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/InterpolatePy.egg-info/SOURCES.txt +0 -0
  24. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/InterpolatePy.egg-info/dependency_links.txt +0 -0
  25. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/InterpolatePy.egg-info/requires.txt +0 -0
  26. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/InterpolatePy.egg-info/top_level.txt +0 -0
  27. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/LICENSE +0 -0
  28. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/README.md +0 -0
  29. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/codecov.yml +0 -0
  30. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/CMakeLists.txt +0 -0
  31. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/CMakeLists.txt +0 -0
  32. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/bind_acc_splines.cpp +0 -0
  33. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/bind_bspline.cpp +0 -0
  34. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/bind_cubic_spline.cpp +0 -0
  35. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/bind_motion.cpp +0 -0
  36. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/bind_paths.cpp +0 -0
  37. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/bind_quaternion.cpp +0 -0
  38. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/bind_smoothing_search.cpp +0 -0
  39. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/bind_smoothing_spline.cpp +0 -0
  40. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/bind_tridiagonal.cpp +0 -0
  41. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/bindings/module.cpp +0 -0
  42. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/cmake/InterpolateCppConfig.cmake.in +0 -0
  43. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/cmake/version.hpp.in +0 -0
  44. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/CMakeLists.txt +0 -0
  45. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/bspline_approx_smooth_example.cpp +0 -0
  46. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/bspline_cubic_example.cpp +0 -0
  47. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/bspline_example.cpp +0 -0
  48. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/bspline_interpolator_example.cpp +0 -0
  49. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/concepts_example.cpp +0 -0
  50. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/cubic_smoothing_example.cpp +0 -0
  51. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/cubic_spline_acc1_example.cpp +0 -0
  52. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/cubic_spline_acc2_example.cpp +0 -0
  53. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/cubic_spline_example.cpp +0 -0
  54. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/double_s_example.cpp +0 -0
  55. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/parabolic_linear_example.cpp +0 -0
  56. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/paths_example.cpp +0 -0
  57. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/polynomial_example.cpp +0 -0
  58. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/quaternion_example.cpp +0 -0
  59. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/shared/example_utils.hpp +0 -0
  60. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/examples/trapezoidal_example.cpp +0 -0
  61. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/bspline/approximation_bspline.hpp +0 -0
  62. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/bspline/bspline.hpp +0 -0
  63. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/bspline/bspline_interpolator.hpp +0 -0
  64. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/bspline/bspline_parameters.hpp +0 -0
  65. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/bspline/cubic_bspline_interpolation.hpp +0 -0
  66. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/bspline/smoothing_cubic_bspline.hpp +0 -0
  67. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/concepts.hpp +0 -0
  68. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/config.hpp +0 -0
  69. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/motion/double_s_trajectory.hpp +0 -0
  70. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/motion/motion_types.hpp +0 -0
  71. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/motion/parabolic_blend_trajectory.hpp +0 -0
  72. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/motion/polynomial_trajectory.hpp +0 -0
  73. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/motion/trapezoidal_trajectory.hpp +0 -0
  74. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/path/circular_path.hpp +0 -0
  75. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/path/frenet_frame.hpp +0 -0
  76. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/path/linear_path.hpp +0 -0
  77. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/path/linear_traj.hpp +0 -0
  78. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/quat/log_quaternion_interpolation.hpp +0 -0
  79. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/quat/modified_log_quaternion_interpolation.hpp +0 -0
  80. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/quat/quaternion.hpp +0 -0
  81. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/quat/quaternion_spline.hpp +0 -0
  82. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/quat/squad_c2.hpp +0 -0
  83. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/spline/cubic_smoothing_spline.hpp +0 -0
  84. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/spline/cubic_spline.hpp +0 -0
  85. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/spline/cubic_spline_with_acc1.hpp +0 -0
  86. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/spline/cubic_spline_with_acc2.hpp +0 -0
  87. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/spline/smoothing_search.hpp +0 -0
  88. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/spline/spline_parameters.hpp +0 -0
  89. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/include/interpolatecpp/tridiagonal.hpp +0 -0
  90. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/approximation_bspline.cpp +0 -0
  91. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/bspline.cpp +0 -0
  92. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/circular_path.cpp +0 -0
  93. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/cubic_bspline_interpolation.cpp +0 -0
  94. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/cubic_smoothing_spline.cpp +0 -0
  95. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/cubic_spline.cpp +0 -0
  96. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/cubic_spline_with_acc1.cpp +0 -0
  97. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/cubic_spline_with_acc2.cpp +0 -0
  98. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/double_s_trajectory.cpp +0 -0
  99. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/frenet_frame.cpp +0 -0
  100. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/linear_path.cpp +0 -0
  101. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/linear_traj.cpp +0 -0
  102. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/parabolic_blend_trajectory.cpp +0 -0
  103. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/polynomial_trajectory.cpp +0 -0
  104. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/quaternion.cpp +0 -0
  105. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/quaternion_spline.cpp +0 -0
  106. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/smoothing_cubic_bspline.cpp +0 -0
  107. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/smoothing_search.cpp +0 -0
  108. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/squad_c2.cpp +0 -0
  109. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/src/trapezoidal_trajectory.cpp +0 -0
  110. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/CMakeLists.txt +0 -0
  111. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/shared/test_data.hpp +0 -0
  112. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_bspline.cpp +0 -0
  113. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_concepts.cpp +0 -0
  114. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_cubic_smoothing_spline.cpp +0 -0
  115. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_cubic_spline.cpp +0 -0
  116. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_cubic_spline_with_acc1.cpp +0 -0
  117. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_cubic_spline_with_acc2.cpp +0 -0
  118. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_double_s_trajectory.cpp +0 -0
  119. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_parabolic_blend_trajectory.cpp +0 -0
  120. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_paths.cpp +0 -0
  121. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_polynomial_trajectory.cpp +0 -0
  122. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_quaternion.cpp +0 -0
  123. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_quaternion_spline.cpp +0 -0
  124. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_smoothing_search.cpp +0 -0
  125. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_trapezoidal_trajectory.cpp +0 -0
  126. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/cpp/tests/test_tridiagonal.cpp +0 -0
  127. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/algorithms.md +0 -0
  128. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/api-reference.md +0 -0
  129. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/architecture.md +0 -0
  130. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/assets/extra.css +0 -0
  131. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/assets/extra.js +0 -0
  132. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/changelog.md +0 -0
  133. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/contributing.md +0 -0
  134. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/examples.md +0 -0
  135. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/index.md +0 -0
  136. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/installation.md +0 -0
  137. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/quickstart.md +0 -0
  138. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/troubleshooting.md +0 -0
  139. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/tutorials/motion-profiles.md +0 -0
  140. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/tutorials/path-planning.md +0 -0
  141. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/tutorials/quaternion-interpolation.md +0 -0
  142. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/tutorials/spline-interpolation.md +0 -0
  143. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/docs/user-guide.md +0 -0
  144. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/b_spline_approx_ex.py +0 -0
  145. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/b_spline_cubic_ex.py +0 -0
  146. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/b_spline_ex.py +0 -0
  147. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/b_spline_interpolate_ex.py +0 -0
  148. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/b_spline_smooth_ex.py +0 -0
  149. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/c_s_smoot_search_ex.py +0 -0
  150. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/c_s_smoothing_ex.py +0 -0
  151. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/c_s_with_acc1_ex.py +0 -0
  152. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/c_s_with_acc2_ex.py +0 -0
  153. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/cubic_spline_ex.py +0 -0
  154. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/double_s_ex.py +0 -0
  155. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/frenet_frame_ex.py +0 -0
  156. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/lin_poly_parabolic_ex.py +0 -0
  157. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/linear_ex.py +0 -0
  158. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/log_quat_new_ex.py +0 -0
  159. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/lqi_spiral_frenet_ex.py +0 -0
  160. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/main.py +0 -0
  161. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/mlqi_spiral_frenet_ex.py +0 -0
  162. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/polynomials_ex.py +0 -0
  163. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/protocols_ex.py +0 -0
  164. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/quat_visualization_ex.py +0 -0
  165. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/simple_paths_ex.py +0 -0
  166. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/squad_c2_ex.py +0 -0
  167. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/examples/trapezoidal_ex.py +0 -0
  168. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/__init__.py +0 -0
  169. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/_adapters/__init__.py +0 -0
  170. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/_adapters/_bspline.py +0 -0
  171. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/_adapters/_direct.py +0 -0
  172. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/_adapters/_motion.py +0 -0
  173. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/_adapters/_paths.py +0 -0
  174. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/_adapters/_quaternion.py +0 -0
  175. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/_adapters/_spline.py +0 -0
  176. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/_api.py +0 -0
  177. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/_backend.py +0 -0
  178. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/b_spline.py +0 -0
  179. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/b_spline_approx.py +0 -0
  180. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/b_spline_cubic.py +0 -0
  181. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/b_spline_smooth.py +0 -0
  182. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/c_s_smoot_search.py +0 -0
  183. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/c_s_smoothing.py +0 -0
  184. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/c_s_with_acc1.py +0 -0
  185. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/c_s_with_acc2.py +0 -0
  186. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/cubic_spline.py +0 -0
  187. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/double_s.py +0 -0
  188. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/frenet_frame.py +0 -0
  189. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/lin_poly_parabolic.py +0 -0
  190. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/linear.py +0 -0
  191. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/polynomials.py +0 -0
  192. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/protocols.py +0 -0
  193. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/quat_core.py +0 -0
  194. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/quat_spline.py +0 -0
  195. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/quat_visualization.py +0 -0
  196. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/simple_paths.py +0 -0
  197. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/squad_c2.py +0 -0
  198. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/trapezoidal.py +0 -0
  199. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/interpolatepy/tridiagonal_inv.py +0 -0
  200. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/mkdocs.yml +0 -0
  201. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/pyproject.toml +0 -0
  202. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/setup.cfg +0 -0
  203. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/__init__.py +0 -0
  204. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/inv_test.py +0 -0
  205. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_b_spline.py +0 -0
  206. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_backend.py +0 -0
  207. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_cubic_spline.py +0 -0
  208. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_lin_poly_parabolic.py +0 -0
  209. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_linear.py +0 -0
  210. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_motion_profiles.py +0 -0
  211. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_path_planning.py +0 -0
  212. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_polynomials.py +0 -0
  213. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_protocols.py +0 -0
  214. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_quat_interp.py +0 -0
  215. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_quat_visualization.py +0 -0
  216. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_smoothing.py +0 -0
  217. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/tests/test_squad_c2.py +0 -0
  218. {interpolatepy-3.1.0 → interpolatepy-3.2.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: InterpolatePy
3
- Version: 3.1.0
3
+ Version: 3.2.0
4
4
  Summary: A comprehensive Python library for generating smooth trajectories and curves with precise control over position, velocity, acceleration, and jerk profiles
5
5
  Author-email: Giorgio Medico <giorgio.medico11@gmail.com>
6
6
  Maintainer-email: Giorgio Medico <giorgio.medico11@gmail.com>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: InterpolatePy
3
- Version: 3.1.0
3
+ Version: 3.2.0
4
4
  Summary: A comprehensive Python library for generating smooth trajectories and curves with precise control over position, velocity, acceleration, and jerk profiles
5
5
  Author-email: Giorgio Medico <giorgio.medico11@gmail.com>
6
6
  Maintainer-email: Giorgio Medico <giorgio.medico11@gmail.com>
@@ -176,22 +176,32 @@ Eigen::MatrixXd BSplineInterpolator::compute_control_points(
176
176
  ++row;
177
177
  }
178
178
 
179
- // Fill remaining rows with natural spline conditions
180
- while (row < total_rows) {
181
- int deriv_order = std::min(p - 1, 2);
182
- double t = (row % 2 == 0) ? times[0] : times[n];
179
+ // Fill remaining rows with natural spline conditions (zero higher
180
+ // derivatives at the endpoints). Walk the (derivative order, endpoint)
181
+ // pairs from order 2 up to p-1, skipping any pair an explicit
182
+ // acceleration already pinned -- reusing one would duplicate a row and
183
+ // make the system rank-deficient.
184
+ const bool pinned[2] = {initial_acceleration_.has_value(),
185
+ final_acceleration_.has_value()};
186
+ for (int deriv_order = 2; deriv_order < p && row < total_rows; ++deriv_order) {
187
+ for (int endpoint = 0; endpoint < 2 && row < total_rows; ++endpoint) {
188
+ if (deriv_order == 2 && pinned[endpoint]) {
189
+ continue;
190
+ }
191
+ const double t = (endpoint == 0) ? times[0] : times[n];
183
192
 
184
- const int span = temp_spline.find_knot_span(t);
185
- const Eigen::MatrixXd ders =
186
- temp_spline.basis_function_derivatives(t, span, deriv_order);
193
+ const int span = temp_spline.find_knot_span(t);
194
+ const Eigen::MatrixXd ders =
195
+ temp_spline.basis_function_derivatives(t, span, deriv_order);
187
196
 
188
- for (int j = 0; j <= p; ++j) {
189
- int col = span - p + j;
190
- if (col >= 0 && col < num_cp) {
191
- a_matrix(row, col) = ders(deriv_order, j);
197
+ for (int j = 0; j <= p; ++j) {
198
+ int col = span - p + j;
199
+ if (col >= 0 && col < num_cp) {
200
+ a_matrix(row, col) = ders(deriv_order, j);
201
+ }
192
202
  }
203
+ ++row;
193
204
  }
194
- ++row;
195
205
  }
196
206
  }
197
207
 
@@ -223,7 +233,10 @@ BSplineInterpolator::BSplineInterpolator(
223
233
 
224
234
  Eigen::MatrixXd pts = points;
225
235
  const int num_points = static_cast<int>(pts.rows());
226
- const int min_points = degree + 1;
236
+ // The system has n+1 interpolation rows plus p-1 (odd p) or p (even p)
237
+ // boundary rows against the same number of control points, so it stays
238
+ // square and full rank down to two points.
239
+ const int min_points = 2;
227
240
 
228
241
  if (num_points < min_points) {
229
242
  throw std::invalid_argument(
@@ -74,9 +74,6 @@ LogQuaternionInterpolation::LogQuaternionInterpolation(
74
74
  if (degree < 3 || degree > 5) {
75
75
  throw std::invalid_argument("Degree must be 3, 4, or 5");
76
76
  }
77
- if (static_cast<int>(quaternions.size()) < degree + 1) {
78
- throw std::invalid_argument("Need at least degree+1 quaternions");
79
- }
80
77
  for (size_t i = 1; i < time_points.size(); ++i) {
81
78
  if (time_points[i] <= time_points[i - 1]) {
82
79
  throw std::invalid_argument("Time points must be strictly increasing");
@@ -45,9 +45,6 @@ ModifiedLogQuaternionInterpolation::ModifiedLogQuaternionInterpolation(
45
45
  if (degree < 3 || degree > 5) {
46
46
  throw std::invalid_argument("Degree must be 3, 4, or 5");
47
47
  }
48
- if (static_cast<int>(quaternions.size()) < degree + 1) {
49
- throw std::invalid_argument("Need at least degree+1 quaternions");
50
- }
51
48
  for (size_t i = 1; i < time_points.size(); ++i) {
52
49
  if (time_points[i] <= time_points[i - 1]) {
53
50
  throw std::invalid_argument("Time points must be strictly increasing");
@@ -9,6 +9,7 @@
9
9
  #include "test_data.hpp"
10
10
 
11
11
  #include <cmath>
12
+ #include <string>
12
13
 
13
14
  using namespace interpolatecpp::bspline;
14
15
  using namespace interpolatecpp::test;
@@ -172,10 +173,24 @@ TEST_CASE("BSplineInterpolator degree validation", "[bspline_interpolator]") {
172
173
  REQUIRE_THROWS_AS(BSplineInterpolator(2, pts), std::invalid_argument);
173
174
  }
174
175
 
175
- SECTION("Too few points") {
176
- Eigen::MatrixXd few_pts(3, 2);
177
- few_pts << 0, 0, 1, 1, 2, 4;
178
- REQUIRE_THROWS_AS(BSplineInterpolator(5, few_pts), std::invalid_argument);
176
+ SECTION("Two points suffice for every degree") {
177
+ Eigen::MatrixXd two_pts(2, 2);
178
+ two_pts << 0, 0, 1, 2;
179
+ for (int degree : {3, 4, 5}) {
180
+ BSplineInterpolator bsi(degree, two_pts);
181
+ auto p0 = bsi.evaluate(bsi.u_min());
182
+ auto p1 = bsi.evaluate(bsi.u_max());
183
+ REQUIRE_THAT(p0(0), WithinAbs(0.0, kNumericalAtol));
184
+ REQUIRE_THAT(p0(1), WithinAbs(0.0, kNumericalAtol));
185
+ REQUIRE_THAT(p1(0), WithinAbs(1.0, kNumericalAtol));
186
+ REQUIRE_THAT(p1(1), WithinAbs(2.0, kNumericalAtol));
187
+ }
188
+ }
189
+
190
+ SECTION("Fewer than two points") {
191
+ Eigen::MatrixXd one_pt(1, 2);
192
+ one_pt << 0, 0;
193
+ REQUIRE_THROWS_AS(BSplineInterpolator(3, one_pt), std::invalid_argument);
179
194
  }
180
195
  }
181
196
 
@@ -556,3 +571,51 @@ TEST_CASE("BSpline variant inheritance", "[bspline_variants]") {
556
571
  REQUIRE(base.evaluate(0.5).allFinite());
557
572
  }
558
573
  }
574
+
575
+ // ===== Explicit acceleration constraints =====
576
+
577
+ // The generated natural boundary rows start at the second derivative, so they
578
+ // must skip whichever endpoint an acceleration already pinned. Reusing one
579
+ // duplicates a row and the QR solve silently returns an inconsistent answer.
580
+ TEST_CASE("BSplineInterpolator honours explicit accelerations", "[bspline_variants]") {
581
+ const auto pts = make_quadratic_2d(5);
582
+ Eigen::VectorXd times(5);
583
+ times << 0, 1, 2, 3, 4;
584
+
585
+ Eigen::VectorXd a0(2);
586
+ a0 << 0.5, -0.5;
587
+ Eigen::VectorXd an(2);
588
+ an << -0.5, 0.5;
589
+ Eigen::VectorXd v0(2);
590
+ v0 << 1.0, 0.0;
591
+
592
+ for (int degree : {3, 4, 5}) {
593
+ SECTION("degree " + std::to_string(degree)) {
594
+ SECTION("initial acceleration only") {
595
+ BSplineInterpolator bsi(degree, pts, times, std::nullopt, std::nullopt, a0);
596
+ for (int i = 0; i < 5; ++i) {
597
+ REQUIRE((bsi.evaluate(times[i]) - pts.row(i).transpose()).norm() < 1e-6);
598
+ }
599
+ REQUIRE((bsi.evaluate_derivative(times[0], 2) - a0).norm() < 1e-6);
600
+ }
601
+
602
+ SECTION("final acceleration only") {
603
+ BSplineInterpolator bsi(degree, pts, times, std::nullopt, std::nullopt,
604
+ std::nullopt, an);
605
+ REQUIRE((bsi.evaluate_derivative(times[4], 2) - an).norm() < 1e-6);
606
+ }
607
+
608
+ SECTION("both accelerations") {
609
+ BSplineInterpolator bsi(degree, pts, times, std::nullopt, std::nullopt, a0, an);
610
+ REQUIRE((bsi.evaluate_derivative(times[0], 2) - a0).norm() < 1e-6);
611
+ REQUIRE((bsi.evaluate_derivative(times[4], 2) - an).norm() < 1e-6);
612
+ }
613
+
614
+ SECTION("initial velocity and acceleration") {
615
+ BSplineInterpolator bsi(degree, pts, times, v0, std::nullopt, a0);
616
+ REQUIRE((bsi.evaluate_derivative(times[0], 1) - v0).norm() < 1e-6);
617
+ REQUIRE((bsi.evaluate_derivative(times[0], 2) - a0).norm() < 1e-6);
618
+ }
619
+ }
620
+ }
621
+ }
@@ -102,7 +102,10 @@ class BSplineInterpolator(BSpline):
102
102
 
103
103
  # Validate number of points relative to degree
104
104
  num_points = len(points)
105
- min_points = degree + 1
105
+ # The system has n+1 interpolation rows plus p-1 (odd p) or p (even p)
106
+ # boundary rows against the same number of control points, so it stays
107
+ # square and full rank down to two points.
108
+ min_points = 2
106
109
  if num_points < min_points:
107
110
  raise ValueError(
108
111
  f"Not enough points for degree {degree} B-spline interpolation. "
@@ -342,14 +345,15 @@ class BSplineInterpolator(BSpline):
342
345
  row += 1
343
346
 
344
347
  # If we still need more constraints, add natural spline conditions
345
- # (zero second derivatives at endpoints)
346
- while row < n + 1 + num_additional:
347
- # For cubic splines, use zero second derivatives
348
- # For higher degree, can use higher derivatives
349
- deriv_order = min(p - 1, 2)
350
-
351
- # Alternate between initial and final endpoints
352
- t = times[0] if row % 2 == 0 else times[-1]
348
+ # (zero higher derivatives at the endpoints). Walk the
349
+ # (derivative order, endpoint) pairs from order 2 up to p-1, skipping
350
+ # any pair an explicit acceleration already pinned -- reusing one
351
+ # would duplicate a row and make the system rank-deficient.
352
+ pinned = (self.initial_acceleration is not None, self.final_acceleration is not None)
353
+ candidates = [(2, endpoint) for endpoint in (0, 1) if not pinned[endpoint]]
354
+ candidates += [(order, endpoint) for order in range(3, p) for endpoint in (0, 1)]
355
+ for deriv_order, endpoint in candidates[: n + 1 + num_additional - row]:
356
+ t = times[0] if endpoint == 0 else times[-1]
353
357
 
354
358
  span = self.temp_spline.find_knot_span(t)
355
359
  ders = self.temp_spline.basis_function_derivatives(t, span, deriv_order)
@@ -38,11 +38,6 @@ def _validate_inputs(
38
38
  raise ValueError("At least 2 quaternions are required for interpolation")
39
39
  if degree not in _VALID_DEGREES:
40
40
  raise ValueError(f"Degree must be 3, 4, or 5, got {degree}")
41
- if len(quaternions) < degree + 1:
42
- raise ValueError(
43
- f"Not enough quaternions for degree {degree} B-spline interpolation. "
44
- f"Need at least {degree + 1} quaternions, got {len(quaternions)}"
45
- )
46
41
  if not np.all(np.diff(time_points) > 0):
47
42
  raise ValueError("Time points must be strictly increasing")
48
43
 
@@ -2,4 +2,4 @@
2
2
  __version__ file.
3
3
  """
4
4
 
5
- __version__ = "3.1.0"
5
+ __version__ = "3.2.0"
@@ -24,6 +24,7 @@ from typing import Any
24
24
  import numpy as np
25
25
  import pytest
26
26
 
27
+ import interpolatepy
27
28
  from interpolatepy.b_spline_approx import ApproximationBSpline
28
29
  from interpolatepy.b_spline_cubic import CubicBSplineInterpolation
29
30
  from interpolatepy.b_spline_interpolate import BSplineInterpolator
@@ -480,10 +481,6 @@ class TestBSplineInterpolator:
480
481
  with pytest.raises(ValueError, match="Degree must be 3, 4, or 5"):
481
482
  BSplineInterpolator(2, data_points)
482
483
 
483
- # Test insufficient points for degree 5
484
- with pytest.raises(ValueError, match="Not enough points"):
485
- BSplineInterpolator(5, data_points) # Need at least 6 points for degree 5
486
-
487
484
  # Test only degree 3 to avoid complex constraints
488
485
  # Use more points to ensure system is well-conditioned
489
486
  sufficient_points = [[i, i] for i in range(8)] # 8 points
@@ -1121,3 +1118,67 @@ class TestBSplineVariantsPerformance:
1121
1118
  if __name__ == "__main__":
1122
1119
  # Run tests with detailed output
1123
1120
  pytest.main(["-xvs", __file__])
1121
+
1122
+
1123
+ @pytest.mark.parametrize("degree", [3, 4, 5])
1124
+ @pytest.mark.parametrize("num_points", [2, 3, 6])
1125
+ @pytest.mark.parametrize(
1126
+ "constraints",
1127
+ [
1128
+ {},
1129
+ {"initial_velocity": [0.0, 0.0], "final_velocity": [0.0, 0.0]},
1130
+ {"cyclic": True},
1131
+ ],
1132
+ )
1133
+ def test_public_api_interpolates_from_two_points(
1134
+ degree: int, num_points: int, constraints: dict[str, Any]
1135
+ ) -> None:
1136
+ """Any degree interpolates down to two points, on whichever backend is active.
1137
+
1138
+ Runs against ``interpolatepy.BSplineInterpolator``, which resolves to the C++
1139
+ implementation when it is compiled in, so the two backends stay in step.
1140
+ """
1141
+ points = np.array([[float(i), float(i * i)] for i in range(num_points)])
1142
+ times = [float(i) for i in range(num_points)]
1143
+
1144
+ spline = interpolatepy.BSplineInterpolator(degree, points, times=times, **constraints)
1145
+
1146
+ for t, expected in zip(times, points, strict=True):
1147
+ assert np.allclose(spline.evaluate(t), expected, atol=1e-6)
1148
+
1149
+
1150
+ @pytest.mark.parametrize("degree", [3, 4, 5])
1151
+ @pytest.mark.parametrize(
1152
+ "constraints",
1153
+ [
1154
+ {"initial_acceleration": [0.5, -0.5]},
1155
+ {"final_acceleration": [0.5, -0.5]},
1156
+ {"initial_acceleration": [0.5, -0.5], "final_acceleration": [-0.5, 0.5]},
1157
+ {"initial_velocity": [1.0, 0.0], "initial_acceleration": [0.5, -0.5]},
1158
+ {"final_velocity": [1.0, 0.0], "final_acceleration": [0.5, -0.5]},
1159
+ ],
1160
+ )
1161
+ def test_acceleration_constraints_are_honoured(
1162
+ degree: int, constraints: dict[str, Any]
1163
+ ) -> None:
1164
+ """Explicit accelerations must not collide with the generated natural rows.
1165
+
1166
+ The fallback boundary rows start at the second derivative, so they have to skip
1167
+ whichever endpoint an acceleration already pinned; otherwise the row is repeated
1168
+ and the system goes rank-deficient (Python) or solves inconsistently (C++).
1169
+ """
1170
+ points = np.array([[float(i), float(i * i)] for i in range(5)])
1171
+ times = [float(i) for i in range(5)]
1172
+
1173
+ spline = interpolatepy.BSplineInterpolator(degree, points, times=times, **constraints)
1174
+
1175
+ for t, expected in zip(times, points, strict=True):
1176
+ assert np.allclose(spline.evaluate(t), expected, atol=1e-6)
1177
+
1178
+ endpoints = {"initial": times[0], "final": times[-1]}
1179
+ orders = {"velocity": 1, "acceleration": 2}
1180
+ for name, value in constraints.items():
1181
+ when, _, what = name.partition("_")
1182
+ assert np.allclose(
1183
+ spline.evaluate_derivative(endpoints[when], orders[what]), value, atol=1e-6
1184
+ ), f"{name} not satisfied for degree {degree}"
@@ -12,12 +12,15 @@ robust behavior across different use cases.
12
12
  import numpy as np
13
13
  import pytest
14
14
 
15
+ import interpolatepy
15
16
  from interpolatepy.quat_core import Quaternion
16
17
  from interpolatepy.log_quat import (
17
18
  LogQuaternionInterpolation,
18
19
  ModifiedLogQuaternionInterpolation,
19
20
  )
20
21
 
22
+ _NUMERICAL_ATOL = 1e-6
23
+
21
24
 
22
25
  class TestLogQuaternionInterpolation:
23
26
  """Test suite for LogQuaternionInterpolation (LQI) class."""
@@ -80,10 +83,6 @@ class TestLogQuaternionInterpolation:
80
83
  with pytest.raises(ValueError, match="Degree must be 3, 4, or 5"):
81
84
  LogQuaternionInterpolation(time_points, quaternions, degree=2)
82
85
 
83
- # Not enough points for degree
84
- with pytest.raises(ValueError, match="Not enough quaternions for degree"):
85
- LogQuaternionInterpolation([0.0, 1.0], [Quaternion.identity(), Quaternion.identity()], degree=5)
86
-
87
86
  # Non-increasing time points
88
87
  bad_times = [0.0, 2.0, 1.0, 3.0, 4.0]
89
88
  with pytest.raises(ValueError, match="Time points must be strictly increasing"):
@@ -283,10 +282,6 @@ class TestModifiedLogQuaternionInterpolation:
283
282
  with pytest.raises(ValueError, match="Degree must be 3, 4, or 5"):
284
283
  ModifiedLogQuaternionInterpolation(time_points, quaternions, degree=2)
285
284
 
286
- # Not enough points for degree
287
- with pytest.raises(ValueError, match="Not enough quaternions for degree"):
288
- ModifiedLogQuaternionInterpolation([0.0, 1.0], [Quaternion.identity(), Quaternion.identity()], degree=5)
289
-
290
285
  # Non-increasing time points
291
286
  bad_times = [0.0, 2.0, 1.0, 3.0, 4.0]
292
287
  with pytest.raises(ValueError, match="Time points must be strictly increasing"):
@@ -432,6 +427,30 @@ class TestModifiedLogQuaternionInterpolation:
432
427
  assert abs(abs(dot_product) - 1.0) < self.NUMERICAL_ATOL
433
428
 
434
429
 
430
+ @pytest.mark.parametrize(
431
+ "cls_name", ["LogQuaternionInterpolation", "ModifiedLogQuaternionInterpolation"]
432
+ )
433
+ @pytest.mark.parametrize("degree", [3, 4, 5])
434
+ @pytest.mark.parametrize("num_quats", [2, 3, 5])
435
+ def test_public_api_interpolates_from_two_quaternions(
436
+ cls_name: str, degree: int, num_quats: int
437
+ ) -> None:
438
+ """Any degree interpolates down to two quaternions, on whichever backend is active.
439
+
440
+ Uses the ``interpolatepy`` public names, which resolve to the C++ implementation
441
+ when it is compiled in, so the two backends stay in step.
442
+ """
443
+ cls = getattr(interpolatepy, cls_name)
444
+ times = [float(i) for i in range(num_quats)]
445
+ quats = [Quaternion.from_euler_angles(0.3 * i, 0.2 * i, 0.1 * i) for i in range(num_quats)]
446
+
447
+ interp = cls(times, quats, degree=degree)
448
+
449
+ for t, expected in zip(times, quats, strict=True):
450
+ # Quaternions double-cover rotations, so compare |dot| against 1.
451
+ assert abs(abs(interp.evaluate(t).dot_prod(expected)) - 1.0) < _NUMERICAL_ATOL
452
+
453
+
435
454
  if __name__ == "__main__":
436
455
  # Run tests with detailed output
437
456
  pytest.main(["-xvs", __file__])
File without changes
File without changes
File without changes
File without changes