nrl-tracker 0.21.4__py3-none-any.whl → 0.22.0__py3-none-any.whl
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.
- {nrl_tracker-0.21.4.dist-info → nrl_tracker-0.22.0.dist-info}/METADATA +2 -2
- nrl_tracker-0.22.0.dist-info/RECORD +150 -0
- pytcl/__init__.py +9 -11
- pytcl/assignment_algorithms/__init__.py +32 -42
- pytcl/assignment_algorithms/data_association.py +9 -10
- pytcl/assignment_algorithms/gating.py +7 -5
- pytcl/assignment_algorithms/jpda.py +10 -14
- pytcl/assignment_algorithms/three_dimensional/__init__.py +6 -8
- pytcl/assignment_algorithms/three_dimensional/assignment.py +6 -2
- pytcl/assignment_algorithms/two_dimensional/__init__.py +9 -13
- pytcl/assignment_algorithms/two_dimensional/assignment.py +5 -2
- pytcl/assignment_algorithms/two_dimensional/kbest.py +9 -9
- pytcl/astronomical/__init__.py +130 -89
- pytcl/astronomical/ephemerides.py +524 -0
- pytcl/astronomical/lambert.py +6 -15
- pytcl/astronomical/orbital_mechanics.py +1 -3
- pytcl/astronomical/reference_frames.py +1 -3
- pytcl/astronomical/relativity.py +466 -0
- pytcl/astronomical/time_systems.py +2 -1
- pytcl/atmosphere/__init__.py +12 -14
- pytcl/atmosphere/models.py +5 -5
- pytcl/clustering/__init__.py +28 -36
- pytcl/clustering/dbscan.py +5 -2
- pytcl/clustering/gaussian_mixture.py +10 -10
- pytcl/clustering/hierarchical.py +7 -7
- pytcl/clustering/kmeans.py +7 -5
- pytcl/containers/__init__.py +29 -43
- pytcl/containers/cluster_set.py +13 -20
- pytcl/containers/covertree.py +8 -2
- pytcl/containers/kd_tree.py +6 -2
- pytcl/containers/measurement_set.py +11 -16
- pytcl/containers/rtree.py +8 -7
- pytcl/containers/track_list.py +13 -13
- pytcl/containers/vptree.py +7 -2
- pytcl/coordinate_systems/__init__.py +69 -74
- pytcl/coordinate_systems/conversions/__init__.py +20 -24
- pytcl/coordinate_systems/conversions/geodetic.py +7 -17
- pytcl/coordinate_systems/conversions/spherical.py +4 -2
- pytcl/coordinate_systems/jacobians/__init__.py +10 -12
- pytcl/coordinate_systems/jacobians/jacobians.py +2 -1
- pytcl/coordinate_systems/projections/__init__.py +27 -23
- pytcl/coordinate_systems/projections/projections.py +14 -39
- pytcl/coordinate_systems/rotations/__init__.py +20 -22
- pytcl/coordinate_systems/rotations/rotations.py +3 -4
- pytcl/core/__init__.py +16 -22
- pytcl/core/array_utils.py +7 -7
- pytcl/core/constants.py +1 -3
- pytcl/core/validation.py +13 -19
- pytcl/dynamic_estimation/__init__.py +77 -86
- pytcl/dynamic_estimation/imm.py +10 -15
- pytcl/dynamic_estimation/information_filter.py +8 -6
- pytcl/dynamic_estimation/kalman/__init__.py +40 -48
- pytcl/dynamic_estimation/kalman/extended.py +4 -5
- pytcl/dynamic_estimation/kalman/linear.py +7 -3
- pytcl/dynamic_estimation/kalman/square_root.py +7 -8
- pytcl/dynamic_estimation/kalman/unscented.py +8 -6
- pytcl/dynamic_estimation/particle_filters/__init__.py +12 -14
- pytcl/dynamic_estimation/particle_filters/bootstrap.py +8 -8
- pytcl/dynamic_estimation/smoothers.py +9 -10
- pytcl/dynamic_models/__init__.py +37 -41
- pytcl/dynamic_models/continuous_time/__init__.py +11 -11
- pytcl/dynamic_models/continuous_time/dynamics.py +4 -2
- pytcl/dynamic_models/discrete_time/__init__.py +11 -17
- pytcl/dynamic_models/process_noise/__init__.py +11 -17
- pytcl/dynamic_models/process_noise/polynomial.py +2 -6
- pytcl/gravity/__init__.py +55 -65
- pytcl/gravity/clenshaw.py +4 -7
- pytcl/gravity/egm.py +9 -6
- pytcl/gravity/models.py +1 -3
- pytcl/gravity/spherical_harmonics.py +6 -11
- pytcl/gravity/tides.py +9 -17
- pytcl/magnetism/__init__.py +26 -36
- pytcl/magnetism/emm.py +7 -13
- pytcl/magnetism/igrf.py +5 -6
- pytcl/magnetism/wmm.py +4 -10
- pytcl/mathematical_functions/__init__.py +69 -87
- pytcl/mathematical_functions/basic_matrix/__init__.py +25 -19
- pytcl/mathematical_functions/basic_matrix/decompositions.py +6 -5
- pytcl/mathematical_functions/basic_matrix/special_matrices.py +2 -1
- pytcl/mathematical_functions/combinatorics/__init__.py +18 -14
- pytcl/mathematical_functions/combinatorics/combinatorics.py +5 -4
- pytcl/mathematical_functions/geometry/__init__.py +15 -15
- pytcl/mathematical_functions/geometry/geometry.py +10 -15
- pytcl/mathematical_functions/interpolation/__init__.py +11 -13
- pytcl/mathematical_functions/interpolation/interpolation.py +8 -5
- pytcl/mathematical_functions/numerical_integration/__init__.py +16 -10
- pytcl/mathematical_functions/numerical_integration/quadrature.py +6 -2
- pytcl/mathematical_functions/signal_processing/__init__.py +42 -30
- pytcl/mathematical_functions/signal_processing/detection.py +9 -9
- pytcl/mathematical_functions/signal_processing/filters.py +7 -8
- pytcl/mathematical_functions/signal_processing/matched_filter.py +8 -7
- pytcl/mathematical_functions/special_functions/__init__.py +75 -77
- pytcl/mathematical_functions/special_functions/bessel.py +2 -1
- pytcl/mathematical_functions/special_functions/debye.py +4 -2
- pytcl/mathematical_functions/special_functions/elliptic.py +3 -4
- pytcl/mathematical_functions/special_functions/error_functions.py +2 -1
- pytcl/mathematical_functions/special_functions/gamma_functions.py +3 -4
- pytcl/mathematical_functions/special_functions/hypergeometric.py +2 -1
- pytcl/mathematical_functions/special_functions/lambert_w.py +3 -4
- pytcl/mathematical_functions/special_functions/marcum_q.py +2 -1
- pytcl/mathematical_functions/statistics/__init__.py +27 -31
- pytcl/mathematical_functions/statistics/distributions.py +21 -40
- pytcl/mathematical_functions/statistics/estimators.py +3 -4
- pytcl/mathematical_functions/transforms/__init__.py +45 -51
- pytcl/mathematical_functions/transforms/fourier.py +5 -2
- pytcl/mathematical_functions/transforms/stft.py +8 -11
- pytcl/mathematical_functions/transforms/wavelets.py +13 -20
- pytcl/navigation/__init__.py +96 -102
- pytcl/navigation/geodesy.py +13 -33
- pytcl/navigation/great_circle.py +7 -13
- pytcl/navigation/ins.py +12 -16
- pytcl/navigation/ins_gnss.py +24 -37
- pytcl/navigation/rhumb.py +7 -12
- pytcl/performance_evaluation/__init__.py +21 -25
- pytcl/performance_evaluation/estimation_metrics.py +3 -1
- pytcl/performance_evaluation/track_metrics.py +4 -4
- pytcl/plotting/__init__.py +30 -38
- pytcl/plotting/coordinates.py +8 -18
- pytcl/plotting/ellipses.py +5 -2
- pytcl/plotting/metrics.py +5 -10
- pytcl/plotting/tracks.py +7 -12
- pytcl/static_estimation/__init__.py +37 -41
- pytcl/static_estimation/least_squares.py +5 -4
- pytcl/static_estimation/maximum_likelihood.py +8 -5
- pytcl/static_estimation/robust.py +5 -2
- pytcl/terrain/__init__.py +28 -34
- pytcl/terrain/dem.py +6 -9
- pytcl/terrain/loaders.py +9 -14
- pytcl/terrain/visibility.py +4 -8
- pytcl/trackers/__init__.py +17 -25
- pytcl/trackers/hypothesis.py +8 -8
- pytcl/trackers/mht.py +18 -24
- pytcl/trackers/multi_target.py +8 -6
- pytcl/trackers/single_target.py +5 -2
- nrl_tracker-0.21.4.dist-info/RECORD +0 -148
- {nrl_tracker-0.21.4.dist-info → nrl_tracker-0.22.0.dist-info}/LICENSE +0 -0
- {nrl_tracker-0.21.4.dist-info → nrl_tracker-0.22.0.dist-info}/WHEEL +0 -0
- {nrl_tracker-0.21.4.dist-info → nrl_tracker-0.22.0.dist-info}/top_level.txt +0 -0
pytcl/clustering/hierarchical.py
CHANGED
|
@@ -12,11 +12,15 @@ References
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
from enum import Enum
|
|
15
|
-
from typing import List
|
|
15
|
+
from typing import List
|
|
16
|
+
from typing import Literal
|
|
17
|
+
from typing import NamedTuple
|
|
18
|
+
from typing import Optional
|
|
16
19
|
|
|
17
20
|
import numpy as np
|
|
18
21
|
from numba import njit
|
|
19
|
-
from numpy.typing import ArrayLike
|
|
22
|
+
from numpy.typing import ArrayLike
|
|
23
|
+
from numpy.typing import NDArray
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
class LinkageType(Enum):
|
|
@@ -152,11 +156,7 @@ def _ward_linkage(
|
|
|
152
156
|
"""Ward's linkage: minimum variance merge."""
|
|
153
157
|
total = size_i + size_j + size_k
|
|
154
158
|
return np.sqrt(
|
|
155
|
-
(
|
|
156
|
-
(size_i + size_k) * dist_i**2
|
|
157
|
-
+ (size_j + size_k) * dist_j**2
|
|
158
|
-
- size_k * dist_ij**2
|
|
159
|
-
)
|
|
159
|
+
((size_i + size_k) * dist_i**2 + (size_j + size_k) * dist_j**2 - size_k * dist_ij**2)
|
|
160
160
|
/ total
|
|
161
161
|
)
|
|
162
162
|
|
pytcl/clustering/kmeans.py
CHANGED
|
@@ -10,10 +10,14 @@ References
|
|
|
10
10
|
Careful Seeding," SODA 2007.
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
-
from typing import Literal
|
|
13
|
+
from typing import Literal
|
|
14
|
+
from typing import NamedTuple
|
|
15
|
+
from typing import Optional
|
|
16
|
+
from typing import Union
|
|
14
17
|
|
|
15
18
|
import numpy as np
|
|
16
|
-
from numpy.typing import ArrayLike
|
|
19
|
+
from numpy.typing import ArrayLike
|
|
20
|
+
from numpy.typing import NDArray
|
|
17
21
|
from scipy.spatial.distance import cdist
|
|
18
22
|
|
|
19
23
|
|
|
@@ -250,9 +254,7 @@ def kmeans(
|
|
|
250
254
|
raise ValueError(f"n_clusters ({n_clusters}) > n_samples ({n_samples})")
|
|
251
255
|
|
|
252
256
|
# Check if initial centers are provided
|
|
253
|
-
if isinstance(init, np.ndarray) or (
|
|
254
|
-
isinstance(init, (list, tuple)) and len(init) > 0
|
|
255
|
-
):
|
|
257
|
+
if isinstance(init, np.ndarray) or (isinstance(init, (list, tuple)) and len(init) > 0):
|
|
256
258
|
init_centers = np.asarray(init, dtype=np.float64)
|
|
257
259
|
if init_centers.shape != (n_clusters, n_features):
|
|
258
260
|
raise ValueError(
|
pytcl/containers/__init__.py
CHANGED
|
@@ -5,49 +5,35 @@ This module provides spatial data structures for efficient
|
|
|
5
5
|
nearest neighbor queries, spatial indexing, and tracking containers.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from pytcl.containers.cluster_set import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
from pytcl.containers.covertree import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
from pytcl.containers.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
from pytcl.containers.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
from pytcl.containers.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
box_from_point,
|
|
38
|
-
box_from_points,
|
|
39
|
-
merge_boxes,
|
|
40
|
-
)
|
|
41
|
-
from pytcl.containers.track_list import (
|
|
42
|
-
TrackList,
|
|
43
|
-
TrackListStats,
|
|
44
|
-
TrackQuery,
|
|
45
|
-
)
|
|
46
|
-
from pytcl.containers.vptree import (
|
|
47
|
-
VPNode,
|
|
48
|
-
VPTree,
|
|
49
|
-
VPTreeResult,
|
|
50
|
-
)
|
|
8
|
+
from pytcl.containers.cluster_set import ClusterSet
|
|
9
|
+
from pytcl.containers.cluster_set import ClusterStats
|
|
10
|
+
from pytcl.containers.cluster_set import TrackCluster
|
|
11
|
+
from pytcl.containers.cluster_set import cluster_tracks_dbscan
|
|
12
|
+
from pytcl.containers.cluster_set import cluster_tracks_kmeans
|
|
13
|
+
from pytcl.containers.cluster_set import compute_cluster_centroid
|
|
14
|
+
from pytcl.containers.covertree import CoverTree
|
|
15
|
+
from pytcl.containers.covertree import CoverTreeNode
|
|
16
|
+
from pytcl.containers.covertree import CoverTreeResult
|
|
17
|
+
from pytcl.containers.kd_tree import BallTree
|
|
18
|
+
from pytcl.containers.kd_tree import KDNode
|
|
19
|
+
from pytcl.containers.kd_tree import KDTree
|
|
20
|
+
from pytcl.containers.kd_tree import NearestNeighborResult
|
|
21
|
+
from pytcl.containers.measurement_set import Measurement
|
|
22
|
+
from pytcl.containers.measurement_set import MeasurementQuery
|
|
23
|
+
from pytcl.containers.measurement_set import MeasurementSet
|
|
24
|
+
from pytcl.containers.rtree import BoundingBox
|
|
25
|
+
from pytcl.containers.rtree import RTree
|
|
26
|
+
from pytcl.containers.rtree import RTreeNode
|
|
27
|
+
from pytcl.containers.rtree import RTreeResult
|
|
28
|
+
from pytcl.containers.rtree import box_from_point
|
|
29
|
+
from pytcl.containers.rtree import box_from_points
|
|
30
|
+
from pytcl.containers.rtree import merge_boxes
|
|
31
|
+
from pytcl.containers.track_list import TrackList
|
|
32
|
+
from pytcl.containers.track_list import TrackListStats
|
|
33
|
+
from pytcl.containers.track_list import TrackQuery
|
|
34
|
+
from pytcl.containers.vptree import VPNode
|
|
35
|
+
from pytcl.containers.vptree import VPTree
|
|
36
|
+
from pytcl.containers.vptree import VPTreeResult
|
|
51
37
|
|
|
52
38
|
__all__ = [
|
|
53
39
|
# K-D Tree
|
pytcl/containers/cluster_set.py
CHANGED
|
@@ -7,19 +7,18 @@ that move together (formations, convoys, etc.).
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
from typing import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Union,
|
|
19
|
-
)
|
|
10
|
+
from typing import Dict
|
|
11
|
+
from typing import Iterable
|
|
12
|
+
from typing import Iterator
|
|
13
|
+
from typing import List
|
|
14
|
+
from typing import NamedTuple
|
|
15
|
+
from typing import Optional
|
|
16
|
+
from typing import Tuple
|
|
17
|
+
from typing import Union
|
|
20
18
|
|
|
21
19
|
import numpy as np
|
|
22
|
-
from numpy.typing import ArrayLike
|
|
20
|
+
from numpy.typing import ArrayLike
|
|
21
|
+
from numpy.typing import NDArray
|
|
23
22
|
|
|
24
23
|
from pytcl.clustering.dbscan import dbscan
|
|
25
24
|
from pytcl.clustering.kmeans import kmeans
|
|
@@ -299,9 +298,7 @@ class ClusterSet:
|
|
|
299
298
|
self._clusters = list(clusters)
|
|
300
299
|
|
|
301
300
|
# Build lookups
|
|
302
|
-
self._id_to_idx: Dict[int, int] = {
|
|
303
|
-
c.id: i for i, c in enumerate(self._clusters)
|
|
304
|
-
}
|
|
301
|
+
self._id_to_idx: Dict[int, int] = {c.id: i for i, c in enumerate(self._clusters)}
|
|
305
302
|
self._track_to_cluster: Dict[int, int] = {}
|
|
306
303
|
for cluster in self._clusters:
|
|
307
304
|
for track_id in cluster.track_ids:
|
|
@@ -418,9 +415,7 @@ class ClusterSet:
|
|
|
418
415
|
return self.get_cluster(cluster_id)
|
|
419
416
|
return None
|
|
420
417
|
|
|
421
|
-
def clusters_in_region(
|
|
422
|
-
self, center: ArrayLike, radius: float
|
|
423
|
-
) -> List[TrackCluster]:
|
|
418
|
+
def clusters_in_region(self, center: ArrayLike, radius: float) -> List[TrackCluster]:
|
|
424
419
|
"""
|
|
425
420
|
Get clusters with centroids within a spatial region.
|
|
426
421
|
|
|
@@ -569,9 +564,7 @@ class ClusterSet:
|
|
|
569
564
|
"""
|
|
570
565
|
result = {}
|
|
571
566
|
for cluster in self._clusters:
|
|
572
|
-
stats = self.cluster_stats(
|
|
573
|
-
cluster.id, tracks, state_indices, velocity_indices
|
|
574
|
-
)
|
|
567
|
+
stats = self.cluster_stats(cluster.id, tracks, state_indices, velocity_indices)
|
|
575
568
|
if stats is not None:
|
|
576
569
|
result[cluster.id] = stats
|
|
577
570
|
return result
|
pytcl/containers/covertree.py
CHANGED
|
@@ -11,10 +11,16 @@ References
|
|
|
11
11
|
neighbor," ICML 2006.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
from typing import Callable
|
|
14
|
+
from typing import Callable
|
|
15
|
+
from typing import List
|
|
16
|
+
from typing import NamedTuple
|
|
17
|
+
from typing import Optional
|
|
18
|
+
from typing import Set
|
|
19
|
+
from typing import Tuple
|
|
15
20
|
|
|
16
21
|
import numpy as np
|
|
17
|
-
from numpy.typing import ArrayLike
|
|
22
|
+
from numpy.typing import ArrayLike
|
|
23
|
+
from numpy.typing import NDArray
|
|
18
24
|
|
|
19
25
|
|
|
20
26
|
class CoverTreeResult(NamedTuple):
|
pytcl/containers/kd_tree.py
CHANGED
|
@@ -13,10 +13,14 @@ References
|
|
|
13
13
|
Finding Best Matches in Logarithmic Expected Time," ACM TOMS, 1977.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
from typing import List
|
|
16
|
+
from typing import List
|
|
17
|
+
from typing import NamedTuple
|
|
18
|
+
from typing import Optional
|
|
19
|
+
from typing import Tuple
|
|
17
20
|
|
|
18
21
|
import numpy as np
|
|
19
|
-
from numpy.typing import ArrayLike
|
|
22
|
+
from numpy.typing import ArrayLike
|
|
23
|
+
from numpy.typing import NDArray
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
class KDNode:
|
|
@@ -7,18 +7,17 @@ with spatial query support.
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
from typing import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
Union,
|
|
18
|
-
)
|
|
10
|
+
from typing import Iterable
|
|
11
|
+
from typing import Iterator
|
|
12
|
+
from typing import List
|
|
13
|
+
from typing import NamedTuple
|
|
14
|
+
from typing import Optional
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
19
17
|
|
|
20
18
|
import numpy as np
|
|
21
|
-
from numpy.typing import ArrayLike
|
|
19
|
+
from numpy.typing import ArrayLike
|
|
20
|
+
from numpy.typing import NDArray
|
|
22
21
|
|
|
23
22
|
from pytcl.containers.kd_tree import KDTree
|
|
24
23
|
|
|
@@ -211,9 +210,7 @@ class MeasurementSet:
|
|
|
211
210
|
MeasurementSet
|
|
212
211
|
Measurements at the specified time.
|
|
213
212
|
"""
|
|
214
|
-
measurements = [
|
|
215
|
-
m for m in self._measurements if abs(m.time - time) <= tolerance
|
|
216
|
-
]
|
|
213
|
+
measurements = [m for m in self._measurements if abs(m.time - time) <= tolerance]
|
|
217
214
|
return MeasurementSet(measurements)
|
|
218
215
|
|
|
219
216
|
def in_time_window(self, start: float, end: float) -> MeasurementSet:
|
|
@@ -354,9 +351,7 @@ class MeasurementSet:
|
|
|
354
351
|
return np.zeros((0, 0))
|
|
355
352
|
return np.array([m.value for m in self._measurements])
|
|
356
353
|
|
|
357
|
-
def values_at_time(
|
|
358
|
-
self, time: float, tolerance: float = 1e-9
|
|
359
|
-
) -> NDArray[np.float64]:
|
|
354
|
+
def values_at_time(self, time: float, tolerance: float = 1e-9) -> NDArray[np.float64]:
|
|
360
355
|
"""
|
|
361
356
|
Extract measurement values at a specific time.
|
|
362
357
|
|
pytcl/containers/rtree.py
CHANGED
|
@@ -13,10 +13,14 @@ References
|
|
|
13
13
|
Method for Points and Rectangles," ACM SIGMOD, 1990.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
from typing import List
|
|
16
|
+
from typing import List
|
|
17
|
+
from typing import NamedTuple
|
|
18
|
+
from typing import Optional
|
|
19
|
+
from typing import Tuple
|
|
17
20
|
|
|
18
21
|
import numpy as np
|
|
19
|
-
from numpy.typing import ArrayLike
|
|
22
|
+
from numpy.typing import ArrayLike
|
|
23
|
+
from numpy.typing import NDArray
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
class BoundingBox(NamedTuple):
|
|
@@ -281,9 +285,7 @@ class RTree:
|
|
|
281
285
|
|
|
282
286
|
# Simple split: sort by center x-coordinate and split in half
|
|
283
287
|
if node.is_leaf:
|
|
284
|
-
sorted_entries = sorted(
|
|
285
|
-
entries, key=lambda e: e[0].center[0] if e[0] else 0
|
|
286
|
-
)
|
|
288
|
+
sorted_entries = sorted(entries, key=lambda e: e[0].center[0] if e[0] else 0)
|
|
287
289
|
else:
|
|
288
290
|
sorted_entries = sorted(
|
|
289
291
|
entries,
|
|
@@ -481,8 +483,7 @@ class RTree:
|
|
|
481
483
|
else:
|
|
482
484
|
# Sort children by distance and search closest first
|
|
483
485
|
child_dists = [
|
|
484
|
-
(min_dist_to_box(query, c.bbox) if c.bbox else np.inf, c)
|
|
485
|
-
for c in node.children
|
|
486
|
+
(min_dist_to_box(query, c.bbox) if c.bbox else np.inf, c) for c in node.children
|
|
486
487
|
]
|
|
487
488
|
child_dists.sort(key=lambda x: x[0])
|
|
488
489
|
for _, child in child_dists:
|
pytcl/containers/track_list.py
CHANGED
|
@@ -7,22 +7,22 @@ with filtering, querying, and batch operations.
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
from typing import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Union,
|
|
20
|
-
)
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
from typing import Callable
|
|
12
|
+
from typing import Iterable
|
|
13
|
+
from typing import Iterator
|
|
14
|
+
from typing import List
|
|
15
|
+
from typing import NamedTuple
|
|
16
|
+
from typing import Optional
|
|
17
|
+
from typing import Tuple
|
|
18
|
+
from typing import Union
|
|
21
19
|
|
|
22
20
|
import numpy as np
|
|
23
|
-
from numpy.typing import ArrayLike
|
|
21
|
+
from numpy.typing import ArrayLike
|
|
22
|
+
from numpy.typing import NDArray
|
|
24
23
|
|
|
25
|
-
from pytcl.trackers.multi_target import Track
|
|
24
|
+
from pytcl.trackers.multi_target import Track
|
|
25
|
+
from pytcl.trackers.multi_target import TrackStatus
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
28
28
|
from pytcl.trackers.multi_target import MultiTargetTracker
|
pytcl/containers/vptree.py
CHANGED
|
@@ -11,10 +11,15 @@ References
|
|
|
11
11
|
neighbor search in general metric spaces," SODA 1993.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
from typing import Callable
|
|
14
|
+
from typing import Callable
|
|
15
|
+
from typing import List
|
|
16
|
+
from typing import NamedTuple
|
|
17
|
+
from typing import Optional
|
|
18
|
+
from typing import Tuple
|
|
15
19
|
|
|
16
20
|
import numpy as np
|
|
17
|
-
from numpy.typing import ArrayLike
|
|
21
|
+
from numpy.typing import ArrayLike
|
|
22
|
+
from numpy.typing import NDArray
|
|
18
23
|
|
|
19
24
|
|
|
20
25
|
class VPTreeResult(NamedTuple):
|
|
@@ -15,89 +15,84 @@ systems commonly used in tracking applications:
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
# Import submodules for easy access
|
|
18
|
-
from pytcl.coordinate_systems import conversions
|
|
18
|
+
from pytcl.coordinate_systems import conversions
|
|
19
|
+
from pytcl.coordinate_systems import jacobians
|
|
20
|
+
from pytcl.coordinate_systems import projections
|
|
21
|
+
from pytcl.coordinate_systems import rotations
|
|
19
22
|
|
|
20
23
|
# Geodetic conversions
|
|
21
24
|
# Spherical/polar conversions
|
|
22
|
-
from pytcl.coordinate_systems.conversions import
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
sphere2cart,
|
|
43
|
-
)
|
|
25
|
+
from pytcl.coordinate_systems.conversions import cart2cyl
|
|
26
|
+
from pytcl.coordinate_systems.conversions import cart2pol
|
|
27
|
+
from pytcl.coordinate_systems.conversions import cart2ruv
|
|
28
|
+
from pytcl.coordinate_systems.conversions import cart2sphere
|
|
29
|
+
from pytcl.coordinate_systems.conversions import cyl2cart
|
|
30
|
+
from pytcl.coordinate_systems.conversions import ecef2enu
|
|
31
|
+
from pytcl.coordinate_systems.conversions import ecef2geodetic
|
|
32
|
+
from pytcl.coordinate_systems.conversions import ecef2ned
|
|
33
|
+
from pytcl.coordinate_systems.conversions import enu2ecef
|
|
34
|
+
from pytcl.coordinate_systems.conversions import enu2ned
|
|
35
|
+
from pytcl.coordinate_systems.conversions import geocentric_radius
|
|
36
|
+
from pytcl.coordinate_systems.conversions import geodetic2ecef
|
|
37
|
+
from pytcl.coordinate_systems.conversions import geodetic2enu
|
|
38
|
+
from pytcl.coordinate_systems.conversions import meridional_radius
|
|
39
|
+
from pytcl.coordinate_systems.conversions import ned2ecef
|
|
40
|
+
from pytcl.coordinate_systems.conversions import ned2enu
|
|
41
|
+
from pytcl.coordinate_systems.conversions import pol2cart
|
|
42
|
+
from pytcl.coordinate_systems.conversions import prime_vertical_radius
|
|
43
|
+
from pytcl.coordinate_systems.conversions import ruv2cart
|
|
44
|
+
from pytcl.coordinate_systems.conversions import sphere2cart
|
|
44
45
|
|
|
45
46
|
# Jacobians
|
|
46
|
-
from pytcl.coordinate_systems.jacobians import
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
spherical_jacobian_inv,
|
|
57
|
-
)
|
|
47
|
+
from pytcl.coordinate_systems.jacobians import cross_covariance_transform
|
|
48
|
+
from pytcl.coordinate_systems.jacobians import enu_jacobian
|
|
49
|
+
from pytcl.coordinate_systems.jacobians import geodetic_jacobian
|
|
50
|
+
from pytcl.coordinate_systems.jacobians import ned_jacobian
|
|
51
|
+
from pytcl.coordinate_systems.jacobians import numerical_jacobian
|
|
52
|
+
from pytcl.coordinate_systems.jacobians import polar_jacobian
|
|
53
|
+
from pytcl.coordinate_systems.jacobians import polar_jacobian_inv
|
|
54
|
+
from pytcl.coordinate_systems.jacobians import ruv_jacobian
|
|
55
|
+
from pytcl.coordinate_systems.jacobians import spherical_jacobian
|
|
56
|
+
from pytcl.coordinate_systems.jacobians import spherical_jacobian_inv
|
|
58
57
|
|
|
59
58
|
# Projections
|
|
60
|
-
from pytcl.coordinate_systems.projections import
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
utm_zone,
|
|
76
|
-
)
|
|
59
|
+
from pytcl.coordinate_systems.projections import azimuthal_equidistant
|
|
60
|
+
from pytcl.coordinate_systems.projections import azimuthal_equidistant_inverse
|
|
61
|
+
from pytcl.coordinate_systems.projections import geodetic2utm
|
|
62
|
+
from pytcl.coordinate_systems.projections import lambert_conformal_conic
|
|
63
|
+
from pytcl.coordinate_systems.projections import lambert_conformal_conic_inverse
|
|
64
|
+
from pytcl.coordinate_systems.projections import mercator
|
|
65
|
+
from pytcl.coordinate_systems.projections import mercator_inverse
|
|
66
|
+
from pytcl.coordinate_systems.projections import polar_stereographic
|
|
67
|
+
from pytcl.coordinate_systems.projections import stereographic
|
|
68
|
+
from pytcl.coordinate_systems.projections import stereographic_inverse
|
|
69
|
+
from pytcl.coordinate_systems.projections import transverse_mercator
|
|
70
|
+
from pytcl.coordinate_systems.projections import transverse_mercator_inverse
|
|
71
|
+
from pytcl.coordinate_systems.projections import utm2geodetic
|
|
72
|
+
from pytcl.coordinate_systems.projections import utm_central_meridian
|
|
73
|
+
from pytcl.coordinate_systems.projections import utm_zone
|
|
77
74
|
|
|
78
75
|
# Rotation operations
|
|
79
|
-
from pytcl.coordinate_systems.rotations import
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
slerp,
|
|
100
|
-
)
|
|
76
|
+
from pytcl.coordinate_systems.rotations import axisangle2rotmat
|
|
77
|
+
from pytcl.coordinate_systems.rotations import dcm_rate
|
|
78
|
+
from pytcl.coordinate_systems.rotations import euler2quat
|
|
79
|
+
from pytcl.coordinate_systems.rotations import euler2rotmat
|
|
80
|
+
from pytcl.coordinate_systems.rotations import is_rotation_matrix
|
|
81
|
+
from pytcl.coordinate_systems.rotations import quat2euler
|
|
82
|
+
from pytcl.coordinate_systems.rotations import quat2rotmat
|
|
83
|
+
from pytcl.coordinate_systems.rotations import quat_conjugate
|
|
84
|
+
from pytcl.coordinate_systems.rotations import quat_inverse
|
|
85
|
+
from pytcl.coordinate_systems.rotations import quat_multiply
|
|
86
|
+
from pytcl.coordinate_systems.rotations import quat_rotate
|
|
87
|
+
from pytcl.coordinate_systems.rotations import rodrigues2rotmat
|
|
88
|
+
from pytcl.coordinate_systems.rotations import rotmat2axisangle
|
|
89
|
+
from pytcl.coordinate_systems.rotations import rotmat2euler
|
|
90
|
+
from pytcl.coordinate_systems.rotations import rotmat2quat
|
|
91
|
+
from pytcl.coordinate_systems.rotations import rotmat2rodrigues
|
|
92
|
+
from pytcl.coordinate_systems.rotations import rotx
|
|
93
|
+
from pytcl.coordinate_systems.rotations import roty
|
|
94
|
+
from pytcl.coordinate_systems.rotations import rotz
|
|
95
|
+
from pytcl.coordinate_systems.rotations import slerp
|
|
101
96
|
|
|
102
97
|
# Re-export commonly used functions at the top level
|
|
103
98
|
|
|
@@ -8,30 +8,26 @@ This module provides:
|
|
|
8
8
|
- Direction cosine representations (r-u-v)
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
from pytcl.coordinate_systems.conversions.geodetic import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
from pytcl.coordinate_systems.conversions.spherical import
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
pol2cart,
|
|
32
|
-
ruv2cart,
|
|
33
|
-
sphere2cart,
|
|
34
|
-
)
|
|
11
|
+
from pytcl.coordinate_systems.conversions.geodetic import ecef2enu
|
|
12
|
+
from pytcl.coordinate_systems.conversions.geodetic import ecef2geodetic
|
|
13
|
+
from pytcl.coordinate_systems.conversions.geodetic import ecef2ned
|
|
14
|
+
from pytcl.coordinate_systems.conversions.geodetic import enu2ecef
|
|
15
|
+
from pytcl.coordinate_systems.conversions.geodetic import enu2ned
|
|
16
|
+
from pytcl.coordinate_systems.conversions.geodetic import geocentric_radius
|
|
17
|
+
from pytcl.coordinate_systems.conversions.geodetic import geodetic2ecef
|
|
18
|
+
from pytcl.coordinate_systems.conversions.geodetic import geodetic2enu
|
|
19
|
+
from pytcl.coordinate_systems.conversions.geodetic import meridional_radius
|
|
20
|
+
from pytcl.coordinate_systems.conversions.geodetic import ned2ecef
|
|
21
|
+
from pytcl.coordinate_systems.conversions.geodetic import ned2enu
|
|
22
|
+
from pytcl.coordinate_systems.conversions.geodetic import prime_vertical_radius
|
|
23
|
+
from pytcl.coordinate_systems.conversions.spherical import cart2cyl
|
|
24
|
+
from pytcl.coordinate_systems.conversions.spherical import cart2pol
|
|
25
|
+
from pytcl.coordinate_systems.conversions.spherical import cart2ruv
|
|
26
|
+
from pytcl.coordinate_systems.conversions.spherical import cart2sphere
|
|
27
|
+
from pytcl.coordinate_systems.conversions.spherical import cyl2cart
|
|
28
|
+
from pytcl.coordinate_systems.conversions.spherical import pol2cart
|
|
29
|
+
from pytcl.coordinate_systems.conversions.spherical import ruv2cart
|
|
30
|
+
from pytcl.coordinate_systems.conversions.spherical import sphere2cart
|
|
35
31
|
|
|
36
32
|
__all__ = [
|
|
37
33
|
# Spherical/polar
|
|
@@ -6,10 +6,12 @@ longitude, altitude) and Earth-centered coordinate systems (ECEF), as well
|
|
|
6
6
|
as local tangent plane coordinates (ENU, NED).
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from typing import Optional
|
|
9
|
+
from typing import Optional
|
|
10
|
+
from typing import Tuple
|
|
10
11
|
|
|
11
12
|
import numpy as np
|
|
12
|
-
from numpy.typing import ArrayLike
|
|
13
|
+
from numpy.typing import ArrayLike
|
|
14
|
+
from numpy.typing import NDArray
|
|
13
15
|
|
|
14
16
|
from pytcl.core.constants import WGS84
|
|
15
17
|
|
|
@@ -147,9 +149,7 @@ def ecef2geodetic(
|
|
|
147
149
|
# Bowring's iterative method
|
|
148
150
|
# Initial estimate
|
|
149
151
|
theta = np.arctan2(z * a, p * b)
|
|
150
|
-
lat = np.arctan2(
|
|
151
|
-
z + ep2 * b * np.sin(theta) ** 3, p - e2 * a * np.cos(theta) ** 3
|
|
152
|
-
)
|
|
152
|
+
lat = np.arctan2(z + ep2 * b * np.sin(theta) ** 3, p - e2 * a * np.cos(theta) ** 3)
|
|
153
153
|
|
|
154
154
|
# Iterate for improved accuracy
|
|
155
155
|
for _ in range(5):
|
|
@@ -378,18 +378,8 @@ def enu2ecef(
|
|
|
378
378
|
cos_lon = np.cos(lon_ref)
|
|
379
379
|
|
|
380
380
|
# ECEF = R^T @ ENU + ECEF_ref
|
|
381
|
-
x =
|
|
382
|
-
|
|
383
|
-
- sin_lat * cos_lon * north
|
|
384
|
-
+ cos_lat * cos_lon * up
|
|
385
|
-
+ ecef_ref[0]
|
|
386
|
-
)
|
|
387
|
-
y = (
|
|
388
|
-
cos_lon * east
|
|
389
|
-
- sin_lat * sin_lon * north
|
|
390
|
-
+ cos_lat * sin_lon * up
|
|
391
|
-
+ ecef_ref[1]
|
|
392
|
-
)
|
|
381
|
+
x = -sin_lon * east - sin_lat * cos_lon * north + cos_lat * cos_lon * up + ecef_ref[0]
|
|
382
|
+
y = cos_lon * east - sin_lat * sin_lon * north + cos_lat * sin_lon * up + ecef_ref[1]
|
|
393
383
|
z = cos_lat * north + sin_lat * up + ecef_ref[2]
|
|
394
384
|
|
|
395
385
|
if x.size == 1:
|
|
@@ -5,10 +5,12 @@ This module provides functions for converting between Cartesian and
|
|
|
5
5
|
spherical/polar coordinate systems, following tracking conventions.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from typing import Literal
|
|
8
|
+
from typing import Literal
|
|
9
|
+
from typing import Tuple
|
|
9
10
|
|
|
10
11
|
import numpy as np
|
|
11
|
-
from numpy.typing import ArrayLike
|
|
12
|
+
from numpy.typing import ArrayLike
|
|
13
|
+
from numpy.typing import NDArray
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
def cart2sphere(
|