trajectopy 5.0.2__tar.gz → 5.0.3__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 (212) hide show
  1. {trajectopy-5.0.2 → trajectopy-5.0.3}/PKG-INFO +22 -24
  2. {trajectopy-5.0.2 → trajectopy-5.0.3}/README.md +21 -23
  3. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_fast_reading.py +30 -0
  4. trajectopy-5.0.3/trajectopy/__version__.py +1 -0
  5. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/cli/main.py +2 -2
  6. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/core/trajectory.py +1 -1
  7. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/models/entries.py +1 -1
  8. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/io/ascii.py +10 -9
  9. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/results/ate_result.py +2 -1
  10. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/index.md +1 -0
  11. trajectopy-5.0.3/trajectopy-docs/docs/api/io/rosbag.md +3 -0
  12. trajectopy-5.0.3/trajectopy-docs/docs/file_formats.md +204 -0
  13. trajectopy-5.0.3/trajectopy-docs/docs/index.md +149 -0
  14. trajectopy-5.0.3/trajectopy-docs/docs/settings.md +201 -0
  15. trajectopy-5.0.3/trajectopy-docs/docs/user_guide.md +379 -0
  16. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/mkdocs.yml +1 -0
  17. trajectopy-5.0.2/trajectopy/__version__.py +0 -1
  18. trajectopy-5.0.2/trajectopy-docs/docs/file_formats.md +0 -178
  19. trajectopy-5.0.2/trajectopy-docs/docs/index.md +0 -145
  20. trajectopy-5.0.2/trajectopy-docs/docs/settings.md +0 -183
  21. trajectopy-5.0.2/trajectopy-docs/docs/user_guide.md +0 -270
  22. {trajectopy-5.0.2 → trajectopy-5.0.3}/.gitattributes +0 -0
  23. {trajectopy-5.0.2 → trajectopy-5.0.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  24. {trajectopy-5.0.2 → trajectopy-5.0.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  25. {trajectopy-5.0.2 → trajectopy-5.0.3}/.github/workflows/ci.yml +0 -0
  26. {trajectopy-5.0.2 → trajectopy-5.0.3}/.github/workflows/release.yml +0 -0
  27. {trajectopy-5.0.2 → trajectopy-5.0.3}/.gitignore +0 -0
  28. {trajectopy-5.0.2 → trajectopy-5.0.3}/.pre-commit-config.yaml +0 -0
  29. {trajectopy-5.0.2 → trajectopy-5.0.3}/.pylintrc +0 -0
  30. {trajectopy-5.0.2 → trajectopy-5.0.3}/CITATION.cff +0 -0
  31. {trajectopy-5.0.2 → trajectopy-5.0.3}/LICENSE +0 -0
  32. {trajectopy-5.0.2 → trajectopy-5.0.3}/example_data/KITTI_ORB.traj +0 -0
  33. {trajectopy-5.0.2 → trajectopy-5.0.3}/example_data/KITTI_SPTAM.traj +0 -0
  34. {trajectopy-5.0.2 → trajectopy-5.0.3}/example_data/KITTI_gt.traj +0 -0
  35. {trajectopy-5.0.2 → trajectopy-5.0.3}/example_scripts/align.py +0 -0
  36. {trajectopy-5.0.2 → trajectopy-5.0.3}/example_scripts/alignment.py +0 -0
  37. {trajectopy-5.0.2 → trajectopy-5.0.3}/example_scripts/ate.py +0 -0
  38. {trajectopy-5.0.2 → trajectopy-5.0.3}/example_scripts/deviation_plots.py +0 -0
  39. {trajectopy-5.0.2 → trajectopy-5.0.3}/example_scripts/rpe.py +0 -0
  40. {trajectopy-5.0.2 → trajectopy-5.0.3}/example_scripts/trajectory_plot.py +0 -0
  41. {trajectopy-5.0.2 → trajectopy-5.0.3}/installer/trajectopy.iss +0 -0
  42. {trajectopy-5.0.2 → trajectopy-5.0.3}/pyproject.toml +0 -0
  43. {trajectopy-5.0.2 → trajectopy-5.0.3}/requirements.txt +0 -0
  44. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/__init__.py +0 -0
  45. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/data/abs_dev.result +0 -0
  46. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/data/align_entry.result +0 -0
  47. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/data/generated_trajectory.traj +0 -0
  48. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/data/noisy_trajectory.traj +0 -0
  49. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/data/open_loop_trajectory.traj +0 -0
  50. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/data/rel_dev_meter.result +0 -0
  51. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/data/rel_dev_second.result +0 -0
  52. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_alignment.py +0 -0
  53. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_approximation.py +0 -0
  54. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_architecture.py +0 -0
  55. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_comparison.py +0 -0
  56. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_context_menus.py +0 -0
  57. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_gui_models.py +0 -0
  58. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_gui_smoke.py +0 -0
  59. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_inplace_contract.py +0 -0
  60. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_io.py +0 -0
  61. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_kml.py +0 -0
  62. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_manual_alignment.py +0 -0
  63. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_matching.py +0 -0
  64. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_merging.py +0 -0
  65. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_pipeline.py +0 -0
  66. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_positions_rotations.py +0 -0
  67. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_processing_edge_cases.py +0 -0
  68. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_processing_errors.py +0 -0
  69. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_readers_edge_cases.py +0 -0
  70. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_readers_errors.py +0 -0
  71. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_regressions.py +0 -0
  72. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_settings.py +0 -0
  73. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_settings_edge_cases.py +0 -0
  74. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_settings_serialization.py +0 -0
  75. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_settings_validation.py +0 -0
  76. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_sorting.py +0 -0
  77. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_trajectory.py +0 -0
  78. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_trajectory_validation.py +0 -0
  79. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_update_check.py +0 -0
  80. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/test_visualization.py +0 -0
  81. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/testdata.py +0 -0
  82. {trajectopy-5.0.2 → trajectopy-5.0.3}/test/util.py +0 -0
  83. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/LICENSE +0 -0
  84. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/__init__.py +0 -0
  85. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/__main__.py +0 -0
  86. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/cli/__init__.py +0 -0
  87. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/core/__init__.py +0 -0
  88. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/core/parameters.py +0 -0
  89. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/core/positions.py +0 -0
  90. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/core/rotations.py +0 -0
  91. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/core/settings.py +0 -0
  92. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/exceptions.py +0 -0
  93. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/__init__.py +0 -0
  94. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/app.py +0 -0
  95. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/managers/__init__.py +0 -0
  96. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/managers/file_manager.py +0 -0
  97. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/managers/plot_manager.py +0 -0
  98. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/managers/requests.py +0 -0
  99. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/managers/session_manager.py +0 -0
  100. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/managers/trajectory_manager.py +0 -0
  101. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/managers/ui_manager.py +0 -0
  102. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/models/__init__.py +0 -0
  103. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/models/property_model.py +0 -0
  104. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/models/result_model.py +0 -0
  105. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/models/selection.py +0 -0
  106. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/models/table_model.py +0 -0
  107. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/models/trajectory_model.py +0 -0
  108. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/resources/full-icon-poppins.png +0 -0
  109. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/resources/icon-bg.ico +0 -0
  110. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/resources/icon-bg.png +0 -0
  111. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/resources/icon.png +0 -0
  112. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/themes.py +0 -0
  113. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/update_check.py +0 -0
  114. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/utils.py +0 -0
  115. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/__init__.py +0 -0
  116. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/about_window.py +0 -0
  117. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/alignment_edit_window.py +0 -0
  118. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/dof_organizer.py +0 -0
  119. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/entry_table_view.py +0 -0
  120. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/json_settings_view.py +0 -0
  121. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/kml_dialog.py +0 -0
  122. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/main_window.py +0 -0
  123. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/manual_alignment_window.py +0 -0
  124. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/menu_helpers.py +0 -0
  125. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/playback_window.py +0 -0
  126. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/preview_plot.py +0 -0
  127. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/progress_window.py +0 -0
  128. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/properties_panel.py +0 -0
  129. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/result_context_menu.py +0 -0
  130. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/result_selection_window.py +0 -0
  131. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/result_table_view.py +0 -0
  132. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/timeline_widget.py +0 -0
  133. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/trajectory_context_menu.py +0 -0
  134. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/views/trajectory_table_view.py +0 -0
  135. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/gui/worker.py +0 -0
  136. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/io/__init__.py +0 -0
  137. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/io/header.py +0 -0
  138. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/io/kml.py +0 -0
  139. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/io/results_io.py +0 -0
  140. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/io/rosbag.py +0 -0
  141. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/io/rosmsg.py +0 -0
  142. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/io/trajectory_io.py +0 -0
  143. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/io/utils.py +0 -0
  144. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/__init__.py +0 -0
  145. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/alignment.py +0 -0
  146. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/approximation.py +0 -0
  147. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/evaluation.py +0 -0
  148. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/interpolation.py +0 -0
  149. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/__init__.py +0 -0
  150. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/alignment/__init__.py +0 -0
  151. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/alignment/data.py +0 -0
  152. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/alignment/direct.py +0 -0
  153. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/alignment/egrad_interface.py +0 -0
  154. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/alignment/equations.py +0 -0
  155. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/alignment/estimation.py +0 -0
  156. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/alignment/parameters.py +0 -0
  157. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/approximation/__init__.py +0 -0
  158. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/approximation/cubic_approximation.py +0 -0
  159. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/approximation/line_approximation.py +0 -0
  160. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/lib/approximation/voxelizer.py +0 -0
  161. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/matching.py +0 -0
  162. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/merging.py +0 -0
  163. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/processing/sorting.py +0 -0
  164. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/py.typed +0 -0
  165. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/readers/__init__.py +0 -0
  166. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/readers/ascii.py +0 -0
  167. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/readers/rosbag.py +0 -0
  168. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/readers/rosmsg.py +0 -0
  169. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/readers/utils.py +0 -0
  170. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/results/__init__.py +0 -0
  171. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/results/alignment_result.py +0 -0
  172. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/results/rpe_result.py +0 -0
  173. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/utils/__init__.py +0 -0
  174. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/utils/colors.py +0 -0
  175. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/utils/common.py +0 -0
  176. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/utils/definitions.py +0 -0
  177. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/utils/formatting.py +0 -0
  178. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/utils/geometry.py +0 -0
  179. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/utils/linalg.py +0 -0
  180. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/utils/numeric.py +0 -0
  181. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/utils/resources.py +0 -0
  182. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/visualization/__init__.py +0 -0
  183. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/visualization/_svg_export.py +0 -0
  184. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/visualization/axes.py +0 -0
  185. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/visualization/figure.py +0 -0
  186. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/visualization/plots.py +0 -0
  187. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy/visualization/style.py +0 -0
  188. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/core/parameters.md +0 -0
  189. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/core/positions.md +0 -0
  190. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/core/rotations.md +0 -0
  191. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/core/settings.md +0 -0
  192. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/core/trajectory.md +0 -0
  193. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/io/kml.md +0 -0
  194. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/io/results_io.md +0 -0
  195. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/io/trajectory_io.md +0 -0
  196. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/processing/alignment.md +0 -0
  197. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/processing/approximation.md +0 -0
  198. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/processing/evaluation.md +0 -0
  199. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/processing/interpolation.md +0 -0
  200. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/processing/matching.md +0 -0
  201. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/processing/merging.md +0 -0
  202. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/processing/sorting.md +0 -0
  203. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/results/alignment_result.md +0 -0
  204. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/results/ate_result.md +0 -0
  205. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/results/rpe_result.md +0 -0
  206. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/visualization/display.md +0 -0
  207. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/api/visualization/figures.md +0 -0
  208. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/assets/icon.png +0 -0
  209. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/javascripts/mathjax.js +0 -0
  210. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy-docs/docs/stylesheets/extra.css +0 -0
  211. {trajectopy-5.0.2 → trajectopy-5.0.3}/trajectopy.spec +0 -0
  212. {trajectopy-5.0.2 → trajectopy-5.0.3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: trajectopy
3
- Version: 5.0.2
3
+ Version: 5.0.3
4
4
  Summary: Trajectory Evaluation in Python
5
5
  Project-URL: Homepage, https://gereon-t.github.io/trajectopy/
6
6
  Project-URL: Documentation, https://gereon-t.github.io/trajectopy/
@@ -62,44 +62,42 @@ Description-Content-Type: text/markdown
62
62
 
63
63
  ## Installation
64
64
 
65
- Windows app: download `Trajectopy-<version>-setup.exe` from the [latest release](https://github.com/gereon-t/trajectopy/releases/latest) and run it. No Python installation or administrator rights are needed; `.traj` files can then be opened by double-click, and the app reports new versions (Help → Check for Updates).
65
+ **Windows app**: download `Trajectopy-<version>-setup.exe` from the [latest release](https://github.com/gereon-t/trajectopy/releases/latest) and run it. No Python installation or administrator rights are needed; `.traj` files can then be opened by double-click, and the app reports new versions (Help → Check for Updates).
66
66
 
67
- Full version (with GUI):
67
+ **Python package** (Python 3.10 or newer):
68
68
 
69
- ```bash
70
- pip install "trajectopy[gui]"
71
- ```
72
-
73
- Python package with plotting (no GUI):
69
+ | Command | Contents |
70
+ | --- | --- |
71
+ | `pip install "trajectopy[gui]"` | Python package and GUI (recommended) |
72
+ | `pip install "trajectopy[plot]"` | Python package with plotting, without the GUI |
73
+ | `pip install trajectopy` | Python package only |
74
74
 
75
- ```bash
76
- pip install "trajectopy[plot]"
77
- ```
75
+ Loading large trajectory files (millions of poses) is several times faster with the `fast` extra, which can be combined with the others: `pip install "trajectopy[gui,fast]"`.
78
76
 
79
- Python package only:
77
+ ## Quick Start
80
78
 
81
- ```bash
82
- pip install trajectopy
83
- ```
79
+ ```python
80
+ import trajectopy as tpy
84
81
 
85
- Loading large trajectory files (millions of poses) is several times faster with the `fast` extra, which can be combined with the others:
82
+ reference = tpy.Trajectory.from_file("./example_data/KITTI_gt.traj")
83
+ estimate = tpy.Trajectory.from_file("./example_data/KITTI_ORB.traj")
86
84
 
87
- ```bash
88
- pip install "trajectopy[gui,fast]"
85
+ ate_result = tpy.ate(trajectory=estimate, other=reference) # aligns the estimate first
86
+ print(f"Position ATE: {ate_result.pos_ate:.3f} m")
89
87
  ```
90
88
 
89
+ Or start the GUI with `trajectopy` (or from the Start menu), drop trajectory files onto it, right-click the ground truth → *Set as Reference*, then right-click another trajectory → *Compare with Reference*.
90
+
91
91
  ## Documentation
92
92
 
93
93
  <a href="https://gereon-t.github.io/trajectopy/" target="_blank">https://gereon-t.github.io/trajectopy/</a>
94
94
 
95
95
  ## Key Features
96
96
 
97
- Trajectopy offers a range of features, including:
98
-
99
- - __Interactive GUI__: A user-friendly interface that enables seamless interaction with your trajectory data, making it easy to visualize, align, and compare trajectories.
100
- - __Alignment__: An advanced trajectory alignment algorithm that can be tailored to the specific application and supports a similarity transformation, a leverarm and a time shift estimation.
101
- - __Comparison__: Absolute and relative trajectory comparison metrics (__ATE and RPE__) that can be computed using various pose-matching methods.
102
- - __Data Import/Export__: Support for importing and exporting data, ensuring compatibility with your existing workflows.
97
+ - __Interactive GUI__: Load, plot, align and compare trajectories without writing code. Every action explains itself in the context menus, and trajectories can be aligned interactively if an automatic alignment is not possible.
98
+ - __Alignment__: A spatio-temporal least squares alignment that can be tailored to the application: similarity transformation, leverarm and time shift, each of them optional.
99
+ - __Comparison__: Absolute and relative trajectory error (__ATE and RPE__), computed with various pose-matching methods.
100
+ - __Data Import/Export__: ASCII files with configurable columns, time formats and coordinate systems (any EPSG code), and ROS bags.
103
101
  - __Fast, Interactive Visualization__: Powered by [pyqtgraph](https://www.pyqtgraph.org/), the same plots are available in the GUI and in Python scripts, stay fluid for large trajectories, and can be exported to PNG, JPG or SVG. Georeferenced trajectories and ATE results can be exported to Google Earth, colored by speed, height or deviations, on the terrain or at their own heights, with playback.
104
102
 
105
103
  ## Web Application (Docker)
@@ -22,44 +22,42 @@
22
22
 
23
23
  ## Installation
24
24
 
25
- Windows app: download `Trajectopy-<version>-setup.exe` from the [latest release](https://github.com/gereon-t/trajectopy/releases/latest) and run it. No Python installation or administrator rights are needed; `.traj` files can then be opened by double-click, and the app reports new versions (Help → Check for Updates).
25
+ **Windows app**: download `Trajectopy-<version>-setup.exe` from the [latest release](https://github.com/gereon-t/trajectopy/releases/latest) and run it. No Python installation or administrator rights are needed; `.traj` files can then be opened by double-click, and the app reports new versions (Help → Check for Updates).
26
26
 
27
- Full version (with GUI):
27
+ **Python package** (Python 3.10 or newer):
28
28
 
29
- ```bash
30
- pip install "trajectopy[gui]"
31
- ```
32
-
33
- Python package with plotting (no GUI):
29
+ | Command | Contents |
30
+ | --- | --- |
31
+ | `pip install "trajectopy[gui]"` | Python package and GUI (recommended) |
32
+ | `pip install "trajectopy[plot]"` | Python package with plotting, without the GUI |
33
+ | `pip install trajectopy` | Python package only |
34
34
 
35
- ```bash
36
- pip install "trajectopy[plot]"
37
- ```
35
+ Loading large trajectory files (millions of poses) is several times faster with the `fast` extra, which can be combined with the others: `pip install "trajectopy[gui,fast]"`.
38
36
 
39
- Python package only:
37
+ ## Quick Start
40
38
 
41
- ```bash
42
- pip install trajectopy
43
- ```
39
+ ```python
40
+ import trajectopy as tpy
44
41
 
45
- Loading large trajectory files (millions of poses) is several times faster with the `fast` extra, which can be combined with the others:
42
+ reference = tpy.Trajectory.from_file("./example_data/KITTI_gt.traj")
43
+ estimate = tpy.Trajectory.from_file("./example_data/KITTI_ORB.traj")
46
44
 
47
- ```bash
48
- pip install "trajectopy[gui,fast]"
45
+ ate_result = tpy.ate(trajectory=estimate, other=reference) # aligns the estimate first
46
+ print(f"Position ATE: {ate_result.pos_ate:.3f} m")
49
47
  ```
50
48
 
49
+ Or start the GUI with `trajectopy` (or from the Start menu), drop trajectory files onto it, right-click the ground truth → *Set as Reference*, then right-click another trajectory → *Compare with Reference*.
50
+
51
51
  ## Documentation
52
52
 
53
53
  <a href="https://gereon-t.github.io/trajectopy/" target="_blank">https://gereon-t.github.io/trajectopy/</a>
54
54
 
55
55
  ## Key Features
56
56
 
57
- Trajectopy offers a range of features, including:
58
-
59
- - __Interactive GUI__: A user-friendly interface that enables seamless interaction with your trajectory data, making it easy to visualize, align, and compare trajectories.
60
- - __Alignment__: An advanced trajectory alignment algorithm that can be tailored to the specific application and supports a similarity transformation, a leverarm and a time shift estimation.
61
- - __Comparison__: Absolute and relative trajectory comparison metrics (__ATE and RPE__) that can be computed using various pose-matching methods.
62
- - __Data Import/Export__: Support for importing and exporting data, ensuring compatibility with your existing workflows.
57
+ - __Interactive GUI__: Load, plot, align and compare trajectories without writing code. Every action explains itself in the context menus, and trajectories can be aligned interactively if an automatic alignment is not possible.
58
+ - __Alignment__: A spatio-temporal least squares alignment that can be tailored to the application: similarity transformation, leverarm and time shift, each of them optional.
59
+ - __Comparison__: Absolute and relative trajectory error (__ATE and RPE__), computed with various pose-matching methods.
60
+ - __Data Import/Export__: ASCII files with configurable columns, time formats and coordinate systems (any EPSG code), and ROS bags.
63
61
  - __Fast, Interactive Visualization__: Powered by [pyqtgraph](https://www.pyqtgraph.org/), the same plots are available in the GUI and in Python scripts, stay fluid for large trajectories, and can be exported to PNG, JPG or SVG. Georeferenced trajectories and ATE results can be exported to Google Earth, colored by speed, height or deviations, on the terrain or at their own heights, with playback.
64
62
 
65
63
  ## Web Application (Docker)
@@ -119,6 +119,36 @@ class TestReadTrajectory(unittest.TestCase):
119
119
  self._assert_same_as_general_reader(text)
120
120
 
121
121
 
122
+ class TestDatetimeTimeSystems(unittest.TestCase):
123
+ TEMPLATE = (
124
+ "#fields t,px,py,pz\n#time_format datetime\n{header}"
125
+ "2024-01-01 12:00:00.000,0,0,0\n2024-01-01 12:00:00.100,1,0,0\n"
126
+ )
127
+ UTC_2024 = 1704110400.0 # 2024-01-01 12:00:00 UTC
128
+
129
+ def _timestamps(self, header: str) -> np.ndarray:
130
+ with tempfile.TemporaryDirectory() as directory:
131
+ filename = os.path.join(directory, "trajectory.traj")
132
+ with open(filename, "w", encoding="utf-8") as file:
133
+ file.write(self.TEMPLATE.format(header=header))
134
+ return read_trajectory(filename).timestamps
135
+
136
+ def test_utc(self):
137
+ for header_lines in ("", "#datetime_timezone UTC\n"):
138
+ np.testing.assert_allclose(self._timestamps(header_lines), [self.UTC_2024, self.UTC_2024 + 0.1])
139
+
140
+ def test_gps_time_subtracts_the_leap_seconds(self):
141
+ np.testing.assert_allclose(
142
+ self._timestamps("#datetime_timezone GPS\n"), [self.UTC_2024 - 18, self.UTC_2024 - 18 + 0.1]
143
+ )
144
+
145
+ def test_other_time_zones_are_read_as_utc_with_a_warning(self):
146
+ with self.assertLogs(ascii.logger, level="WARNING") as logs:
147
+ timestamps = self._timestamps("#datetime_timezone Europe/Berlin\n")
148
+ np.testing.assert_allclose(timestamps, [self.UTC_2024, self.UTC_2024 + 0.1])
149
+ self.assertTrue(any("Europe/Berlin" in message for message in logs.output))
150
+
151
+
122
152
  class TestFastExtraHint(unittest.TestCase):
123
153
  FILE = "test/data/generated_trajectory.traj"
124
154
 
@@ -0,0 +1 @@
1
+ __version__ = "5.0.3"
@@ -8,13 +8,13 @@ from trajectopy.__version__ import __version__ as VERSION
8
8
 
9
9
  def main():
10
10
  """Main CLI entry point."""
11
- parser = argparse.ArgumentParser(description="Trajectopy - Trajectory Evaluation in Python")
11
+ parser = argparse.ArgumentParser(prog="trajectopy", description="Trajectopy - Trajectory Evaluation in Python")
12
12
  parser.add_argument(
13
13
  "files",
14
14
  nargs="*",
15
15
  help="Trajectory (.traj, .bag) or result (.result) files to open (also used when opening files from Windows).",
16
16
  )
17
- parser.add_argument("--version", "-v", action="store_true")
17
+ parser.add_argument("--version", "-v", action="store_true", help="Show the version and exit")
18
18
  parser.add_argument(
19
19
  "--single-thread",
20
20
  action="store_true",
@@ -644,7 +644,7 @@ class Trajectory:
644
644
 
645
645
  write_trajectory(self, filename=filename, mode=mode)
646
646
 
647
- def to_kml(self, filename: str, precision: float = 1e-6, color: str = "#ff0000", **options) -> None:
647
+ def to_kml(self, filename: str, precision: float = 1e-6, color: str = "#ff0000", **options: Any) -> None:
648
648
  """
649
649
  Exports the trajectory to a Google Earth KML file, as a time-stamped track that the time slider of
650
650
  Google Earth plays back.
@@ -141,7 +141,7 @@ class TrajectoryEntry(Entry):
141
141
  traj_settings = ProcessingSettings.from_file(str(settings_filename))
142
142
  else:
143
143
  logger.info(
144
- "No settings file found. Settings can be provided by storing a yaml file with the same name in the same directory."
144
+ "No settings file found. Settings can be provided by storing a JSON file with the same name in the same directory."
145
145
  )
146
146
  traj_settings = ProcessingSettings()
147
147
 
@@ -309,19 +309,20 @@ def _parse_datetime(trajectory_data: np.ndarray, time_columns: list[int], header
309
309
 
310
310
  datetime_strings = np.apply_along_axis(concatenate_strings, 1, trajectory_data[:, time_columns])
311
311
 
312
- ts_datetime = pd.to_datetime(datetime_strings, format=header_data.datetime_format, utc=True)
312
+ # Date/time strings are UTC or GPS time; other time zones are not supported (and are read as UTC).
313
+ time_system = header_data.datetime_timezone.upper()
314
+ if time_system not in ("UTC", "GPS"):
315
+ logger.warning(
316
+ "Unsupported #datetime_timezone '%s': date/time strings must be UTC or GPS time. Reading them as UTC.",
317
+ header_data.datetime_timezone,
318
+ )
313
319
 
314
- if header_data.datetime_timezone.upper() == "GPS":
320
+ ts_datetime = pd.DatetimeIndex(pd.to_datetime(datetime_strings, format=header_data.datetime_format, utc=True))
321
+ if time_system == "GPS":
315
322
  ts_datetime -= pd.Timedelta(seconds=GPS_LEAP_SECONDS)
316
- time_zone = "UTC"
317
323
  logger.info("Applied GPS leap seconds.")
318
- else:
319
- time_zone = header_data.datetime_timezone
320
-
321
- ts_datetime = pd.DatetimeIndex(ts_datetime).tz_convert(tz=time_zone)
322
- logger.info("Timezone: %s", time_zone)
323
324
 
324
- return np.array([dt_i.timestamp() for dt_i in ts_datetime])
325
+ return np.asarray((ts_datetime - pd.Timestamp(0, tz="UTC")) / pd.Timedelta(seconds=1), dtype=float)
325
326
 
326
327
 
327
328
  def _parse_gps_sow(trajectory_data: np.ndarray, time_columns: list[int], header_data: HeaderData) -> np.ndarray:
@@ -1,5 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from functools import cached_property
3
+ from typing import Any
3
4
 
4
5
  import numpy as np
5
6
  import pandas as pd
@@ -501,7 +502,7 @@ class ATEResult:
501
502
 
502
503
  return pd.DataFrame(all_data, columns=self.columns)
503
504
 
504
- def to_kml(self, filename: str, field: str = "position", max_std: float = 3.0, **options) -> None:
505
+ def to_kml(self, filename: str, field: str = "position", max_std: float = 3.0, **options: Any) -> None:
505
506
  """Exports the result to a Google Earth KML file: the trajectory colored by a deviation field, with
506
507
  playback in Google Earth's time slider. Requires a trajectory with a known EPSG code.
507
508
 
@@ -25,6 +25,7 @@ Welcome to the Trajectopy API reference. This section provides detailed document
25
25
  - **[Trajectory I/O](io/trajectory_io.md)** - Read and write trajectories (ASCII)
26
26
  - **[Results I/O](io/results_io.md)** - Read and write ATE/RPE/alignment results and parameters
27
27
  - **[Google Earth (KML)](io/kml.md)** - Export trajectories and ATE results to Google Earth
28
+ - **[ROS Bags](io/rosbag.md)** - Read trajectories from ROS1 bag files
28
29
 
29
30
  ## Results
30
31
 
@@ -0,0 +1,3 @@
1
+ # ROS Bags
2
+
3
+ ::: trajectopy.io.rosbag
@@ -0,0 +1,204 @@
1
+ # File Formats
2
+
3
+ Trajectopy reads trajectories from:
4
+
5
+ - **ASCII files** (`.traj`, `.txt`, `.csv`, …): one pose per line; a header describes the columns.
6
+ - **ROS1 bag files** (`.bag`): `geometry_msgs/PoseStamped` and `geometry_msgs/PointStamped` messages.
7
+
8
+ ## ASCII Files
9
+
10
+ ### Structure
11
+
12
+ Each line holds one pose. Lines starting with `#` are header lines, which describe how the data is interpreted.
13
+ Without a header, the columns are `t,px,py,pz,qx,qy,qz,qw` (time, position, quaternion), separated by commas:
14
+
15
+ ```
16
+ 1000.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0
17
+ 1000.1,0.1,0.0,0.0,0.0,0.0,0.0,1.0
18
+ 1000.2,0.2,0.0,0.0,0.0,0.0,0.0,1.0
19
+ ```
20
+
21
+ With a header:
22
+
23
+ ```
24
+ #name MyTrajectory
25
+ #epsg 25832
26
+ #fields t,px,py,pz,qx,qy,qz,qw
27
+ 1000.0,364000.0,5621000.0,60.0,0.0,0.0,0.0,1.0
28
+ 1000.1,364000.1,5621000.0,60.0,0.0,0.0,0.0,1.0
29
+ ```
30
+
31
+ ### Header Lines
32
+
33
+ | Header | Description | Default | Options |
34
+ |--------|-------------|---------|---------|
35
+ | `#name` | Display name | `Trajectory` | Any string |
36
+ | `#epsg` | EPSG code of the positions | `0` | Any EPSG code; `0` = local coordinates without a known datum |
37
+ | `#fields` | Meaning of the columns | `t,px,py,pz,qx,qy,qz,qw` | Comma-separated [field names](#field-names) |
38
+ | `#delimiter` | Column separator, in quotes | `','` | Any single character, e.g. `#delimiter ';'` |
39
+ | `#nframe` | Navigation frame of the data | `enu` | Order of east, north and up/down, e.g. `enu`, `ned`, `neu` |
40
+ | `#rot_unit` | Unit of Euler angles | `rad` | `rad`, `deg` |
41
+ | `#euler_rot_seq` | Axis sequence of Euler angles | `xyz` | Up to 3 of `x`, `y`, `z` for extrinsic or `X`, `Y`, `Z` for intrinsic rotations (not mixed) |
42
+ | `#time_format` | Format of the time column(s) | `unix` | `unix`, `datetime`, `gps_sow` |
43
+ | `#time_offset` | Offset in seconds added to all timestamps | `0.0` | Any number |
44
+ | `#datetime_format` | Format of date/time strings | `%Y-%m-%d %H:%M:%S.%f` | [strftime format](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) |
45
+ | `#datetime_timezone` | Time system of date/time strings | `UTC` | `UTC` or `GPS` |
46
+ | `#gps_week` | GPS week of `gps_sow` timestamps | `0` | Integer |
47
+ | `#sorting` | Order of the poses | `time` | `time`, `path_length` (or `arc_length`) |
48
+
49
+ Notes:
50
+
51
+ - **Delimiter**: the character must be in quotes; without them, the line is ignored and a comma is used.
52
+ Whitespace-separated files (spaces or tabs) are detected automatically and need no `#delimiter` line.
53
+ - **Navigation frame**: positions, velocities and orientations are converted to ENU. Positions are only
54
+ converted if `#epsg` is `0`; with an EPSG code, their axes are defined by the coordinate system.
55
+ - **GPS time**: `gps_sow` timestamps are seconds of the GPS week given by `#gps_week`; they are converted to UTC
56
+ (including leap seconds). `#datetime_timezone GPS` does the same for date/time strings.
57
+ - **Time systems**: date/time strings must be UTC or GPS time; local time zones are not supported (other values
58
+ are read as UTC, with a warning). A constant offset can be corrected with `#time_offset`.
59
+ - Header lines may also appear after the data (e.g. comments), but files with all header lines at the top load
60
+ faster.
61
+
62
+ ### Field Names
63
+
64
+ | Field | Description | Can repeat? |
65
+ |-------|-------------|-------------|
66
+ | `t` | Time | Yes, for date and time in separate columns (`#time_format datetime`) |
67
+ | `l` | Path length (arc length) in meters | No |
68
+ | `px`, `py`, `pz` | Position (in the order of the coordinate system, e.g. latitude, longitude, height for EPSG 4326) | No |
69
+ | `qx`, `qy`, `qz`, `qw` | Orientation as quaternion | No |
70
+ | `ex`, `ey`, `ez` | Orientation as Euler angles (roll, pitch, yaw; see `#rot_unit` and `#euler_rot_seq`) | No |
71
+ | `vx`, `vy`, `vz` | Velocity in meters per second | No |
72
+ | `-` | Column that is not used | Yes |
73
+
74
+ Only `px`, `py` and `pz` are required. Without time column, the line number is used as timestamp; without
75
+ orientation, the trajectory has positions only (no rotation deviations, no leverarm estimation). If both
76
+ quaternions and Euler angles are given, the quaternions are used.
77
+
78
+ ### Examples
79
+
80
+ **Positions only**
81
+
82
+ ```
83
+ #name PositionOnly
84
+ #fields t,px,py,pz
85
+ 1000.0,0.0,0.0,0.0
86
+ 1000.1,0.1,0.0,0.0
87
+ 1000.2,0.2,0.0,0.0
88
+ ```
89
+
90
+ **Euler angles in degrees**
91
+
92
+ ```
93
+ #name EulerTrajectory
94
+ #fields t,px,py,pz,ex,ey,ez
95
+ #rot_unit deg
96
+ 1000.0,0.0,0.0,0.0,0.0,0.0,0.0
97
+ 1000.1,0.1,0.0,0.0,0.0,0.0,5.0
98
+ ```
99
+
100
+ **Space-separated, with unused columns**
101
+
102
+ ```
103
+ #name SpaceSeparated
104
+ #fields t,-,-,px,py,pz
105
+ 1000.0 17 ok 0.0 0.0 0.0
106
+ 1000.1 17 ok 0.1 0.0 0.0
107
+ ```
108
+
109
+ **Geographic coordinates (latitude, longitude, ellipsoidal height)**
110
+
111
+ ```
112
+ #name GNSS
113
+ #epsg 4979
114
+ #fields t,px,py,pz
115
+ 1000.0,50.7374,7.0982,120.5
116
+ 1000.1,50.7375,7.0983,121.2
117
+ ```
118
+
119
+ **Date and time strings**
120
+
121
+ ```
122
+ #name DatetimeTrajectory
123
+ #fields t,px,py,pz,qx,qy,qz,qw
124
+ #time_format datetime
125
+ #datetime_format %Y-%m-%d %H:%M:%S.%f
126
+ #datetime_timezone UTC
127
+ 2024-01-01 12:00:00.000,0.0,0.0,0.0,0.0,0.0,0.0,1.0
128
+ 2024-01-01 12:00:00.100,0.1,0.0,0.0,0.0,0.0,0.0,1.0
129
+ ```
130
+
131
+ Date and time can also be in separate columns: `#fields t,t,px,py,pz` (they are joined with a space).
132
+
133
+ **GPS time (seconds of week), NED frame, semicolon-separated**
134
+
135
+ ```
136
+ #name GPSTime
137
+ #fields t,px,py,pz,qx,qy,qz,qw
138
+ #delimiter ';'
139
+ #nframe ned
140
+ #time_format gps_sow
141
+ #gps_week 2250
142
+ 345600.0;0.0;0.0;0.0;0.0;0.0;0.0;1.0
143
+ 345600.1;0.1;0.0;0.0;0.0;0.0;0.0;1.0
144
+ ```
145
+
146
+ ### Large Files
147
+
148
+ Files with millions of poses load several times faster with the optional pyarrow reader:
149
+ `pip install "trajectopy[fast]"`. It is used automatically when installed, for files without date/time strings.
150
+
151
+ ## ROS Bags
152
+
153
+ ROS1 bag files (`.bag`) can be opened in the GUI like ASCII files, or read in Python:
154
+
155
+ ```python
156
+ from trajectopy.io.rosbag import trajectories_from_rosbag
157
+
158
+ trajectories = trajectories_from_rosbag("recording.bag")
159
+ ```
160
+
161
+ Every topic with `geometry_msgs/PoseStamped` (position and orientation) or `geometry_msgs/PointStamped`
162
+ (position only) messages becomes one trajectory, named after the topic; the timestamps are taken from the message
163
+ headers. Messages of other types are skipped.
164
+
165
+ ## Files Written by Trajectopy
166
+
167
+ - **Trajectories** (`Trajectory.to_file`, *Export…* in the GUI) are ASCII files as described above, with the
168
+ fields `t,l,px,py,pz,qx,qy,qz,qw,vx,vy,vz` (without `qx`…`qw` for trajectories without orientation).
169
+ - **Results** (`.result`): ATE, RPE and alignment results (`ATEResult.to_file`, `RPEResult.to_file`,
170
+ `AlignmentResult.to_file`). They are text files with a header, too, and can be opened in the GUI.
171
+ - **Settings** (`.json`): [processing settings](settings.md#processing-settings) and
172
+ [plot settings](settings.md#plot-settings).
173
+ - **Sessions** (GUI): a folder with all trajectories, results and settings, see
174
+ [Using the GUI](user_guide.md#menu-bar).
175
+
176
+ ## Creating Trajectories in Python
177
+
178
+ ```python
179
+ import numpy as np
180
+ import trajectopy as tpy
181
+
182
+ timestamps = np.arange(0, 10, 0.1)
183
+ positions = np.column_stack(
184
+ [
185
+ timestamps, # x increases with time
186
+ np.sin(timestamps), # y is sinusoidal
187
+ np.zeros_like(timestamps), # z is zero
188
+ ]
189
+ )
190
+ quaternions = np.tile([0, 0, 0, 1], (len(timestamps), 1)) # identity (x, y, z, w)
191
+
192
+ trajectory = tpy.Trajectory.from_arrays(
193
+ xyz=positions,
194
+ quat=quaternions, # or rpy=... (roll, pitch, yaw in radians)
195
+ timestamps=timestamps,
196
+ name="CustomTrajectory",
197
+ )
198
+ trajectory.to_file("custom.traj")
199
+ ```
200
+
201
+ ## See Also
202
+
203
+ - [User Guide](user_guide.md): loading files in Python and the GUI
204
+ - [API Reference](api/io/trajectory_io.md): reading and writing trajectories
@@ -0,0 +1,149 @@
1
+ <div align="center">
2
+ <h1>Trajectopy - Trajectory Evaluation in Python</h1>
3
+ <a href="https://github.com/gereon-t/trajectopy/releases"><img src="https://img.shields.io/github/v/release/gereon-t/trajectopy?label=version" /></a>
4
+ <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.10+-blue.svg" /></a>
5
+ <a href="https://github.com/gereon-t/trajectopy/blob/main/LICENSE"><img src="https://img.shields.io/github/license/gereon-t/trajectopy" /></a>
6
+ <a href="https://github.com/astral-sh/ruff"><img alt="Code style: ruff" src="https://img.shields.io/badge/code%20style-ruff-000000.svg"></a>
7
+ <br />
8
+ <a href="https://github.com/gereon-t/trajectopy"><img src="https://img.shields.io/badge/Windows-0078D6?st&logo=windows&logoColor=white" /></a>
9
+ <a href="https://github.com/gereon-t/trajectopy"><img src="https://img.shields.io/badge/Linux-FCC624?logo=linux&logoColor=black" /></a>
10
+ <a href="https://github.com/gereon-t/trajectopy"><img src="https://img.shields.io/badge/mac%20os-000000?&logo=apple&logoColor=white" /></a>
11
+
12
+ <h4>Trajectopy is a Python package with an optional graphical user interface for empirical trajectory evaluation. </h4>
13
+
14
+ <p align="center">
15
+ <img style="border-radius: 10px;" src="https://raw.githubusercontent.com/gereon-t/trajectopy/main/.images/trajectopy_gif_low_quality.gif">
16
+ </p>
17
+
18
+ </div>
19
+
20
+
21
+ ## Key Features
22
+
23
+ - __Interactive GUI__: Load, plot, align and compare trajectories without writing code. Every action explains
24
+ itself in the context menus, and trajectories can be aligned interactively if an automatic alignment is not possible.
25
+ - __Alignment__: A spatio-temporal least squares alignment that can be tailored to the application: similarity
26
+ transformation, leverarm and time shift, each of them optional.
27
+ - __Comparison__: Absolute and relative trajectory error (__ATE and RPE__), computed with various pose-matching methods.
28
+ - __Data Import/Export__: ASCII files with configurable columns, time formats and coordinate systems
29
+ (any EPSG code), and ROS bags.
30
+ - __Fast, Interactive Visualization__: Powered by [pyqtgraph](https://www.pyqtgraph.org/), the same plots are
31
+ available in the GUI and in Python scripts, stay fluid for large trajectories, and can be exported to PNG, JPG
32
+ or SVG. Georeferenced trajectories and ATE results can be exported to Google Earth, colored by speed, height or
33
+ deviations, on the terrain or at their own heights, with playback.
34
+
35
+ ## Installation
36
+
37
+ ### Windows App
38
+
39
+ Download `Trajectopy-<version>-setup.exe` from the [latest release](https://github.com/gereon-t/trajectopy/releases/latest)
40
+ and run it. No Python installation or administrator rights are needed. The installer adds Trajectopy to the Start
41
+ menu and, optionally, opens `.traj` files with it on double-click. The app reports new versions (Help → Check for
42
+ Updates); installing a newer version over an existing one updates it.
43
+
44
+ As the installer is not signed, Windows SmartScreen may warn about an unknown publisher: choose
45
+ *More info → Run anyway*.
46
+
47
+ ### Python Package
48
+
49
+ | Command | Contents |
50
+ | --- | --- |
51
+ | `pip install "trajectopy[gui]"` | Python package and GUI (recommended) |
52
+ | `pip install "trajectopy[plot]"` | Python package with plotting, without the GUI |
53
+ | `pip install trajectopy` | Python package only |
54
+
55
+ Trajectopy requires Python 3.10 or newer.
56
+
57
+ **Faster loading of large files**: trajectory files with millions of poses load several times faster with the
58
+ optional `fast` extra, which installs [pyarrow](https://arrow.apache.org/docs/python/) for reading. It can be
59
+ combined with the other extras:
60
+
61
+ ```console
62
+ pip install "trajectopy[gui,fast]"
63
+ ```
64
+
65
+ ## Quick Start
66
+
67
+ ### Python
68
+
69
+ Load two trajectories and compute the absolute and relative trajectory error. The example files are in the
70
+ [`example_data`](https://github.com/gereon-t/trajectopy/tree/main/example_data) folder of the repository.
71
+
72
+ ```python
73
+ import trajectopy as tpy
74
+
75
+ reference = tpy.Trajectory.from_file("./example_data/KITTI_gt.traj")
76
+ estimate = tpy.Trajectory.from_file("./example_data/KITTI_ORB.traj")
77
+
78
+ # ATE: the estimate is aligned to the reference first (similarity transformation)
79
+ ate_result = tpy.ate(trajectory=estimate, other=reference)
80
+ print(f"Position ATE: {ate_result.pos_ate:.3f} m")
81
+
82
+ # RPE: drift per 100 m to 800 m (see the relative comparison settings)
83
+ rpe_result = tpy.rpe(trajectory=estimate, other=reference)
84
+ print(f"Position RPE: {rpe_result.pos_rpe:.3f} {rpe_result.pos_drift_unit}")
85
+ ```
86
+
87
+ The [User Guide](user_guide.md) covers alignment, evaluation, plots and the GUI in detail.
88
+
89
+ ### GUI
90
+
91
+ Start the Windows app from the Start menu, or run:
92
+
93
+ ```console
94
+ trajectopy
95
+ ```
96
+
97
+ Drop trajectory files onto the trajectory table, right-click the ground truth and choose *Set as Reference*,
98
+ then right-click another trajectory and choose *Compare with Reference*. See [Using the GUI](user_guide.md#6-using-the-gui).
99
+
100
+ ## Command Line
101
+
102
+ ```console
103
+ trajectopy [-h] [--version] [--single-thread] [--plot-settings PLOT_SETTINGS] [files ...]
104
+ ```
105
+
106
+ | Argument | Description |
107
+ | --- | --- |
108
+ | `files` | Trajectory (`.traj`, `.bag`) or result (`.result`) files to open at start. |
109
+ | `--version`, `-v` | Show the version and exit. |
110
+ | `--single-thread` | Process in the GUI thread instead of a background thread, e.g. for debugging. The GUI does not respond while processing. |
111
+ | `--plot-settings PLOT_SETTINGS` | JSON file with [plot settings](settings.md#plot-settings); settings missing in the file keep their default values. |
112
+ | `-h`, `--help` | Show the help and exit. |
113
+
114
+ Examples:
115
+
116
+ ```console
117
+ trajectopy ground_truth.traj slam.traj
118
+ trajectopy --plot-settings my_session/plot_settings.json
119
+ ```
120
+
121
+ A session saved from the GUI contains its plot settings in `plot_settings.json`.
122
+
123
+ ## Citation
124
+
125
+ If you use Trajectopy for academic work, please cite our [paper](https://www.degruyter.com/document/doi/10.1515/jag-2024-0040/html):
126
+
127
+ ```bibtex
128
+ @article{Tombrink2024,
129
+ title = {Spatio-temporal trajectory alignment for trajectory evaluation},
130
+ author = {Gereon Tombrink and Ansgar Dreier and Lasse Klingbeil and Heiner Kuhlmann},
131
+ journal = {Journal of Applied Geodesy},
132
+ year = {2024},
133
+ doi = {10.1515/jag-2024-0040},
134
+ url = {https://doi.org/10.1515/jag-2024-0040},
135
+ codeurl = {https://github.com/gereon-t/trajectopy}
136
+ }
137
+ ```
138
+
139
+ ## License
140
+
141
+ Trajectopy is released under the GNU General Public License v3.0.
142
+
143
+ ## Contributing
144
+
145
+ Contributions are welcome! Please see our [GitHub repository](https://github.com/gereon-t/trajectopy) for details.
146
+
147
+ ---
148
+
149
+ *Developed at the Institute of Geodesy and Geoinformation, University of Bonn*