antioch-py 2.2.3__py3-none-any.whl → 3.0.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.
Potentially problematic release.
This version of antioch-py might be problematic. Click here for more details.
- antioch/__init__.py +101 -0
- antioch/{module/execution.py → execution.py} +1 -1
- antioch/{module/input.py → input.py} +2 -4
- antioch/{module/module.py → module.py} +17 -34
- antioch/{module/node.py → node.py} +17 -16
- {antioch_py-2.2.3.dist-info → antioch_py-3.0.0.dist-info}/METADATA +8 -11
- antioch_py-3.0.0.dist-info/RECORD +61 -0
- {antioch_py-2.2.3.dist-info → antioch_py-3.0.0.dist-info}/WHEEL +1 -1
- antioch_py-3.0.0.dist-info/licenses/LICENSE +21 -0
- common/ark/__init__.py +6 -16
- common/ark/ark.py +23 -62
- common/ark/hardware.py +1 -1
- common/ark/kinematics.py +1 -1
- common/ark/module.py +22 -0
- common/ark/node.py +46 -3
- common/ark/scheduler.py +2 -29
- common/ark/sim.py +1 -1
- {antioch/module → common/ark}/token.py +17 -0
- common/assets/rigging.usd +0 -0
- common/constants.py +63 -5
- common/core/__init__.py +37 -24
- common/core/auth.py +87 -112
- common/core/container.py +261 -0
- common/core/registry.py +131 -152
- common/core/rome.py +251 -0
- common/core/telemetry.py +176 -0
- common/core/types.py +219 -0
- common/message/__init__.py +19 -5
- common/message/annotation.py +174 -23
- common/message/array.py +25 -1
- common/message/camera.py +23 -1
- common/message/color.py +32 -6
- common/message/detection.py +40 -0
- common/message/foxglove.py +20 -0
- common/message/frame.py +71 -7
- common/message/image.py +58 -9
- common/message/imu.py +24 -4
- common/message/joint.py +69 -10
- common/message/log.py +52 -7
- common/message/pir.py +23 -8
- common/message/plot.py +57 -0
- common/message/point.py +55 -6
- common/message/point_cloud.py +55 -19
- common/message/pose.py +59 -19
- common/message/quaternion.py +105 -92
- common/message/radar.py +195 -29
- common/message/twist.py +34 -0
- common/message/types.py +40 -5
- common/message/vector.py +180 -245
- common/sim/__init__.py +49 -0
- common/{session/config.py → sim/objects.py} +97 -27
- common/sim/state.py +11 -0
- common/utils/comms.py +30 -12
- common/utils/logger.py +26 -7
- antioch/message.py +0 -87
- antioch/module/__init__.py +0 -53
- antioch/session/__init__.py +0 -152
- antioch/session/ark.py +0 -500
- antioch/session/asset.py +0 -65
- antioch/session/error.py +0 -80
- antioch/session/objects/__init__.py +0 -40
- antioch/session/objects/animation.py +0 -162
- antioch/session/objects/articulation.py +0 -180
- antioch/session/objects/basis_curve.py +0 -180
- antioch/session/objects/camera.py +0 -65
- antioch/session/objects/collision.py +0 -46
- antioch/session/objects/geometry.py +0 -58
- antioch/session/objects/ground_plane.py +0 -48
- antioch/session/objects/imu.py +0 -53
- antioch/session/objects/joint.py +0 -49
- antioch/session/objects/light.py +0 -123
- antioch/session/objects/pir_sensor.py +0 -98
- antioch/session/objects/radar.py +0 -62
- antioch/session/objects/rigid_body.py +0 -197
- antioch/session/objects/xform.py +0 -119
- antioch/session/record.py +0 -158
- antioch/session/scene.py +0 -1544
- antioch/session/session.py +0 -211
- antioch/session/task.py +0 -309
- antioch_py-2.2.3.dist-info/RECORD +0 -85
- antioch_py-2.2.3.dist-info/entry_points.txt +0 -2
- common/core/agent.py +0 -324
- common/core/task.py +0 -36
- common/message/velocity.py +0 -11
- common/rome/__init__.py +0 -9
- common/rome/client.py +0 -430
- common/rome/error.py +0 -16
- common/session/__init__.py +0 -31
- common/session/environment.py +0 -31
- common/session/sim.py +0 -129
- common/utils/usd.py +0 -12
- /antioch/{module/clock.py → clock.py} +0 -0
- {antioch_py-2.2.3.dist-info → antioch_py-3.0.0.dist-info}/top_level.txt +0 -0
- /common/message/{base.py → message.py} +0 -0
common/message/vector.py
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
|
-
from
|
|
6
|
+
from foxglove.schemas import Vector2 as FoxgloveVector2, Vector3 as FoxgloveVector3
|
|
7
|
+
from pydantic import Field, model_validator
|
|
7
8
|
|
|
8
|
-
from common.message.
|
|
9
|
+
from common.message.message import Message
|
|
9
10
|
from common.message.point import Point2, Point3
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from common.message.quaternion import Quaternion
|
|
11
|
+
from common.message.quaternion import Quaternion
|
|
13
12
|
|
|
14
13
|
try:
|
|
15
14
|
from pxr import Gf # type: ignore
|
|
@@ -23,37 +22,32 @@ class Vector2(Message):
|
|
|
23
22
|
"""
|
|
24
23
|
A 2D vector (x, y).
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
- Dicts: Vector2.from_any({"x": 1.0, "y": 2.0})
|
|
31
|
-
- Numpy arrays: Vector2.from_any(np.array([1.0, 2.0]))
|
|
32
|
-
|
|
33
|
-
When used as a field in Messages, conversion happens automatically:
|
|
34
|
-
pose = SomeMessage(position_2d=[10.0, 20.0]) # List auto-converts!
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
_type = "antioch/vector2"
|
|
38
|
-
data: tuple[float, float]
|
|
39
|
-
|
|
40
|
-
@property
|
|
41
|
-
def x(self) -> float:
|
|
42
|
-
"""Get the x component.
|
|
25
|
+
Supports multiple construction styles:
|
|
26
|
+
- Vector2(x=1.0, y=2.0) - keyword args
|
|
27
|
+
- Vector2.from_any([1.0, 2.0]) - from list/tuple
|
|
28
|
+
- Vector2.from_any((1.0, 2.0)) - from tuple
|
|
43
29
|
|
|
44
|
-
|
|
45
|
-
|
|
30
|
+
Example:
|
|
31
|
+
```python
|
|
32
|
+
from common.message import Vector2
|
|
46
33
|
|
|
47
|
-
|
|
34
|
+
# Create a 2D vector
|
|
35
|
+
v = Vector2(x=3.0, y=4.0)
|
|
48
36
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
# Vector operations
|
|
38
|
+
magnitude = v.magnitude() # 5.0
|
|
39
|
+
normalized = v.normalize()
|
|
52
40
|
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
# Arithmetic operations
|
|
42
|
+
v2 = Vector2(x=1.0, y=2.0)
|
|
43
|
+
sum_v = v + v2
|
|
44
|
+
scaled = v * 2.0
|
|
45
|
+
```
|
|
46
|
+
"""
|
|
55
47
|
|
|
56
|
-
|
|
48
|
+
_type = "antioch/vector2"
|
|
49
|
+
x: float = Field(default=0.0, description="X component")
|
|
50
|
+
y: float = Field(default=0.0, description="Y component")
|
|
57
51
|
|
|
58
52
|
def __len__(self) -> int:
|
|
59
53
|
"""
|
|
@@ -71,7 +65,7 @@ class Vector2(Message):
|
|
|
71
65
|
:return: Iterator over [x, y].
|
|
72
66
|
"""
|
|
73
67
|
|
|
74
|
-
return iter(self.
|
|
68
|
+
return iter((self.x, self.y))
|
|
75
69
|
|
|
76
70
|
def __getitem__(self, index: int) -> float:
|
|
77
71
|
"""
|
|
@@ -81,7 +75,7 @@ class Vector2(Message):
|
|
|
81
75
|
:return: The component value.
|
|
82
76
|
"""
|
|
83
77
|
|
|
84
|
-
return self.
|
|
78
|
+
return (self.x, self.y)[index]
|
|
85
79
|
|
|
86
80
|
def __eq__(self, other: object) -> bool:
|
|
87
81
|
"""
|
|
@@ -93,7 +87,7 @@ class Vector2(Message):
|
|
|
93
87
|
|
|
94
88
|
if not isinstance(other, Vector2):
|
|
95
89
|
return False
|
|
96
|
-
return self.
|
|
90
|
+
return self.x == other.x and self.y == other.y
|
|
97
91
|
|
|
98
92
|
def __repr__(self) -> str:
|
|
99
93
|
"""
|
|
@@ -102,7 +96,7 @@ class Vector2(Message):
|
|
|
102
96
|
:return: String representation.
|
|
103
97
|
"""
|
|
104
98
|
|
|
105
|
-
return f"Vector2(
|
|
99
|
+
return f"Vector2({self.x}, {self.y})"
|
|
106
100
|
|
|
107
101
|
def __str__(self) -> str:
|
|
108
102
|
"""
|
|
@@ -111,7 +105,7 @@ class Vector2(Message):
|
|
|
111
105
|
:return: String representation.
|
|
112
106
|
"""
|
|
113
107
|
|
|
114
|
-
return f"Vector2(
|
|
108
|
+
return f"Vector2({self.x}, {self.y})"
|
|
115
109
|
|
|
116
110
|
def __add__(self, other: Vector2) -> Vector2:
|
|
117
111
|
"""
|
|
@@ -121,7 +115,7 @@ class Vector2(Message):
|
|
|
121
115
|
:return: The sum vector.
|
|
122
116
|
"""
|
|
123
117
|
|
|
124
|
-
return Vector2(
|
|
118
|
+
return Vector2(x=self.x + other.x, y=self.y + other.y)
|
|
125
119
|
|
|
126
120
|
def __sub__(self, other: Vector2) -> Vector2:
|
|
127
121
|
"""
|
|
@@ -131,7 +125,7 @@ class Vector2(Message):
|
|
|
131
125
|
:return: The difference vector.
|
|
132
126
|
"""
|
|
133
127
|
|
|
134
|
-
return Vector2(
|
|
128
|
+
return Vector2(x=self.x - other.x, y=self.y - other.y)
|
|
135
129
|
|
|
136
130
|
def __mul__(self, scalar: float) -> Vector2:
|
|
137
131
|
"""
|
|
@@ -141,7 +135,7 @@ class Vector2(Message):
|
|
|
141
135
|
:return: The scaled vector.
|
|
142
136
|
"""
|
|
143
137
|
|
|
144
|
-
return Vector2(
|
|
138
|
+
return Vector2(x=self.x * scalar, y=self.y * scalar)
|
|
145
139
|
|
|
146
140
|
def __rmul__(self, scalar: float) -> Vector2:
|
|
147
141
|
"""
|
|
@@ -164,7 +158,7 @@ class Vector2(Message):
|
|
|
164
158
|
|
|
165
159
|
if scalar == 0:
|
|
166
160
|
raise ZeroDivisionError("Cannot divide vector by zero")
|
|
167
|
-
return Vector2(
|
|
161
|
+
return Vector2(x=self.x / scalar, y=self.y / scalar)
|
|
168
162
|
|
|
169
163
|
def __neg__(self) -> Vector2:
|
|
170
164
|
"""
|
|
@@ -173,56 +167,7 @@ class Vector2(Message):
|
|
|
173
167
|
:return: The negated vector.
|
|
174
168
|
"""
|
|
175
169
|
|
|
176
|
-
return Vector2(
|
|
177
|
-
|
|
178
|
-
@model_validator(mode="before")
|
|
179
|
-
@classmethod
|
|
180
|
-
def convert_iterables(cls, data: Any) -> Any:
|
|
181
|
-
"""
|
|
182
|
-
Automatically convert lists, tuples, dicts, and numpy arrays to Vector2 format.
|
|
183
|
-
"""
|
|
184
|
-
|
|
185
|
-
# Already a Vector2 instance
|
|
186
|
-
if isinstance(data, cls):
|
|
187
|
-
return {"data": data.data}
|
|
188
|
-
|
|
189
|
-
# Tuple format - already correct
|
|
190
|
-
if isinstance(data, tuple) and len(data) == 2:
|
|
191
|
-
return {"data": (float(data[0]), float(data[1]))}
|
|
192
|
-
|
|
193
|
-
# Dict format with x, y - convert to tuple
|
|
194
|
-
if isinstance(data, dict):
|
|
195
|
-
if "data" in data:
|
|
196
|
-
return data
|
|
197
|
-
if "x" in data and "y" in data:
|
|
198
|
-
return {"data": (float(data["x"]), float(data["y"]))}
|
|
199
|
-
raise ValueError("Dict must have either 'data' or 'x' and 'y' fields")
|
|
200
|
-
|
|
201
|
-
# Numpy array - convert
|
|
202
|
-
if isinstance(data, np.ndarray):
|
|
203
|
-
if data.shape != (2,):
|
|
204
|
-
raise ValueError(f"Vector2 array must have shape (2,), got {data.shape}")
|
|
205
|
-
return {"data": (float(data[0]), float(data[1]))}
|
|
206
|
-
|
|
207
|
-
# List - convert
|
|
208
|
-
if isinstance(data, list):
|
|
209
|
-
if len(data) != 2:
|
|
210
|
-
raise ValueError(f"Vector2 requires 2 values, got {len(data)}")
|
|
211
|
-
return {"data": (float(data[0]), float(data[1]))}
|
|
212
|
-
|
|
213
|
-
return data
|
|
214
|
-
|
|
215
|
-
@classmethod
|
|
216
|
-
def new(cls, x: float, y: float) -> Vector2:
|
|
217
|
-
"""
|
|
218
|
-
Create a new 2D vector.
|
|
219
|
-
|
|
220
|
-
:param x: The x component.
|
|
221
|
-
:param y: The y component.
|
|
222
|
-
:return: A 2D vector.
|
|
223
|
-
"""
|
|
224
|
-
|
|
225
|
-
return cls(data=(x, y))
|
|
170
|
+
return Vector2(x=-self.x, y=-self.y)
|
|
226
171
|
|
|
227
172
|
@classmethod
|
|
228
173
|
def zeros(cls) -> Vector2:
|
|
@@ -232,7 +177,7 @@ class Vector2(Message):
|
|
|
232
177
|
:return: A zero vector.
|
|
233
178
|
"""
|
|
234
179
|
|
|
235
|
-
return cls(
|
|
180
|
+
return cls(x=0.0, y=0.0)
|
|
236
181
|
|
|
237
182
|
@classmethod
|
|
238
183
|
def ones(cls) -> Vector2:
|
|
@@ -242,27 +187,29 @@ class Vector2(Message):
|
|
|
242
187
|
:return: A ones vector.
|
|
243
188
|
"""
|
|
244
189
|
|
|
245
|
-
return cls(
|
|
190
|
+
return cls(x=1.0, y=1.0)
|
|
246
191
|
|
|
247
192
|
@classmethod
|
|
248
|
-
def from_any(cls,
|
|
193
|
+
def from_any(cls, value: Vector2 | tuple | list | dict | np.ndarray | None) -> Vector2:
|
|
249
194
|
"""
|
|
250
|
-
Create Vector2 from any
|
|
195
|
+
Create Vector2 from any compatible type.
|
|
196
|
+
|
|
197
|
+
Accepts:
|
|
198
|
+
- Vector2 instance (returned as-is)
|
|
199
|
+
- Tuple/list of 2 floats: (x, y)
|
|
200
|
+
- Dict with 'x' and 'y' keys
|
|
201
|
+
- Numpy array of shape (2,)
|
|
202
|
+
- None (returns zero vector)
|
|
251
203
|
|
|
252
|
-
:param
|
|
204
|
+
:param value: Any compatible input type.
|
|
253
205
|
:return: A Vector2 instance.
|
|
254
|
-
:raises ValueError: If conversion fails.
|
|
255
206
|
"""
|
|
256
207
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
# Will be handled by validator
|
|
263
|
-
return cls.model_validate(data)
|
|
264
|
-
except Exception as e:
|
|
265
|
-
raise ValueError(f"Cannot convert to Vector2: {e}") from None
|
|
208
|
+
if value is None:
|
|
209
|
+
return cls(x=0.0, y=0.0)
|
|
210
|
+
if isinstance(value, cls):
|
|
211
|
+
return value
|
|
212
|
+
return cls.model_validate(value)
|
|
266
213
|
|
|
267
214
|
@classmethod
|
|
268
215
|
def from_numpy(cls, array: np.ndarray) -> Vector2:
|
|
@@ -276,7 +223,7 @@ class Vector2(Message):
|
|
|
276
223
|
|
|
277
224
|
if array.shape != (2,):
|
|
278
225
|
raise ValueError(f"Vector2 array must have shape (2,), got {array.shape}")
|
|
279
|
-
return cls(
|
|
226
|
+
return cls(x=float(array[0]), y=float(array[1]))
|
|
280
227
|
|
|
281
228
|
@classmethod
|
|
282
229
|
def from_list(cls, values: list[float]) -> Vector2:
|
|
@@ -290,7 +237,7 @@ class Vector2(Message):
|
|
|
290
237
|
|
|
291
238
|
if len(values) != 2:
|
|
292
239
|
raise ValueError(f"Vector2 requires 2 values, got {len(values)}")
|
|
293
|
-
return cls(
|
|
240
|
+
return cls(x=values[0], y=values[1])
|
|
294
241
|
|
|
295
242
|
def dot(self, other: Vector2) -> float:
|
|
296
243
|
"""
|
|
@@ -340,7 +287,7 @@ class Vector2(Message):
|
|
|
340
287
|
:return: The numpy array.
|
|
341
288
|
"""
|
|
342
289
|
|
|
343
|
-
return np.array(self.
|
|
290
|
+
return np.array([self.x, self.y], dtype=np.float32)
|
|
344
291
|
|
|
345
292
|
def to_list(self) -> list[float]:
|
|
346
293
|
"""
|
|
@@ -349,7 +296,16 @@ class Vector2(Message):
|
|
|
349
296
|
:return: The list of values.
|
|
350
297
|
"""
|
|
351
298
|
|
|
352
|
-
return
|
|
299
|
+
return [self.x, self.y]
|
|
300
|
+
|
|
301
|
+
def to_tuple(self) -> tuple[float, float]:
|
|
302
|
+
"""
|
|
303
|
+
Convert to a tuple.
|
|
304
|
+
|
|
305
|
+
:return: The tuple of values.
|
|
306
|
+
"""
|
|
307
|
+
|
|
308
|
+
return (self.x, self.y)
|
|
353
309
|
|
|
354
310
|
def to_point(self) -> Point2:
|
|
355
311
|
"""
|
|
@@ -360,60 +316,67 @@ class Vector2(Message):
|
|
|
360
316
|
|
|
361
317
|
return Point2(x=self.x, y=self.y)
|
|
362
318
|
|
|
363
|
-
def
|
|
319
|
+
def to_foxglove(self) -> FoxgloveVector2:
|
|
364
320
|
"""
|
|
365
|
-
Convert to
|
|
321
|
+
Convert to Foxglove Vector2 for telemetry.
|
|
366
322
|
|
|
367
|
-
:return:
|
|
323
|
+
:return: Foxglove Vector2 schema.
|
|
368
324
|
"""
|
|
369
325
|
|
|
370
|
-
return self.
|
|
326
|
+
return FoxgloveVector2(x=self.x, y=self.y)
|
|
371
327
|
|
|
328
|
+
@model_validator(mode="before")
|
|
329
|
+
@classmethod
|
|
330
|
+
def _convert_input(cls, data: Any) -> Any:
|
|
331
|
+
"""
|
|
332
|
+
Convert various input types to Vector2 format.
|
|
333
|
+
"""
|
|
372
334
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
335
|
+
if isinstance(data, cls):
|
|
336
|
+
return {"x": data.x, "y": data.y}
|
|
337
|
+
if isinstance(data, (tuple, list)) and len(data) == 2:
|
|
338
|
+
return {"x": float(data[0]), "y": float(data[1])}
|
|
339
|
+
if isinstance(data, np.ndarray) and data.shape == (2,):
|
|
340
|
+
return {"x": float(data[0]), "y": float(data[1])}
|
|
341
|
+
if isinstance(data, dict) and "x" in data and "y" in data:
|
|
342
|
+
return {"x": float(data["x"]), "y": float(data["y"])}
|
|
343
|
+
return data
|
|
376
344
|
|
|
377
|
-
Serializes as a tuple [x, y, z] for space efficiency.
|
|
378
|
-
Automatically converts from common Python types:
|
|
379
|
-
- Lists: Vector3.from_any([1.0, 2.0, 3.0])
|
|
380
|
-
- Tuples: Vector3.from_any((1.0, 2.0, 3.0))
|
|
381
|
-
- Dicts: Vector3.from_any({"x": 1.0, "y": 2.0, "z": 3.0})
|
|
382
|
-
- Numpy arrays: Vector3.from_any(np.array([1.0, 2.0, 3.0]))
|
|
383
345
|
|
|
384
|
-
|
|
385
|
-
pose = SomeMessage(position=[10.0, 20.0, 30.0]) # List auto-converts!
|
|
346
|
+
class Vector3(Message):
|
|
386
347
|
"""
|
|
348
|
+
A 3D vector (x, y, z).
|
|
387
349
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
def x(self) -> float:
|
|
393
|
-
"""Get the x component.
|
|
394
|
-
|
|
395
|
-
:return: The x component.
|
|
396
|
-
"""
|
|
397
|
-
|
|
398
|
-
return self.data[0]
|
|
350
|
+
Supports multiple construction styles:
|
|
351
|
+
- Vector3(x=1.0, y=2.0, z=3.0) - keyword args
|
|
352
|
+
- Vector3.from_any([1.0, 2.0, 3.0]) - from list
|
|
353
|
+
- Vector3.from_any((1.0, 2.0, 3.0)) - from tuple
|
|
399
354
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
355
|
+
Example:
|
|
356
|
+
```python
|
|
357
|
+
from common.message import Vector3
|
|
403
358
|
|
|
404
|
-
|
|
405
|
-
|
|
359
|
+
# Create a 3D vector
|
|
360
|
+
v = Vector3(x=1.0, y=2.0, z=3.0)
|
|
406
361
|
|
|
407
|
-
|
|
362
|
+
# Vector operations
|
|
363
|
+
magnitude = v.magnitude()
|
|
364
|
+
normalized = v.normalize()
|
|
408
365
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
366
|
+
# Cross and dot products
|
|
367
|
+
v2 = Vector3(x=0.0, y=1.0, z=0.0)
|
|
368
|
+
cross = v.cross(v2)
|
|
369
|
+
dot = v.dot(v2)
|
|
412
370
|
|
|
413
|
-
|
|
414
|
-
|
|
371
|
+
# Convert to numpy
|
|
372
|
+
arr = v.to_numpy()
|
|
373
|
+
```
|
|
374
|
+
"""
|
|
415
375
|
|
|
416
|
-
|
|
376
|
+
_type = "antioch/vector3"
|
|
377
|
+
x: float = Field(default=0.0, description="X component")
|
|
378
|
+
y: float = Field(default=0.0, description="Y component")
|
|
379
|
+
z: float = Field(default=0.0, description="Z component")
|
|
417
380
|
|
|
418
381
|
def __len__(self) -> int:
|
|
419
382
|
"""
|
|
@@ -431,7 +394,7 @@ class Vector3(Message):
|
|
|
431
394
|
:return: Iterator over [x, y, z].
|
|
432
395
|
"""
|
|
433
396
|
|
|
434
|
-
return iter(self.
|
|
397
|
+
return iter((self.x, self.y, self.z))
|
|
435
398
|
|
|
436
399
|
def __getitem__(self, index: int) -> float:
|
|
437
400
|
"""
|
|
@@ -441,7 +404,7 @@ class Vector3(Message):
|
|
|
441
404
|
:return: The component value.
|
|
442
405
|
"""
|
|
443
406
|
|
|
444
|
-
return self.
|
|
407
|
+
return (self.x, self.y, self.z)[index]
|
|
445
408
|
|
|
446
409
|
def __eq__(self, other: object) -> bool:
|
|
447
410
|
"""
|
|
@@ -453,7 +416,7 @@ class Vector3(Message):
|
|
|
453
416
|
|
|
454
417
|
if not isinstance(other, Vector3):
|
|
455
418
|
return False
|
|
456
|
-
return self.
|
|
419
|
+
return self.x == other.x and self.y == other.y and self.z == other.z
|
|
457
420
|
|
|
458
421
|
def __repr__(self) -> str:
|
|
459
422
|
"""
|
|
@@ -462,7 +425,7 @@ class Vector3(Message):
|
|
|
462
425
|
:return: String representation.
|
|
463
426
|
"""
|
|
464
427
|
|
|
465
|
-
return f"Vector3(
|
|
428
|
+
return f"Vector3({self.x}, {self.y}, {self.z})"
|
|
466
429
|
|
|
467
430
|
def __str__(self) -> str:
|
|
468
431
|
"""
|
|
@@ -471,7 +434,7 @@ class Vector3(Message):
|
|
|
471
434
|
:return: String representation.
|
|
472
435
|
"""
|
|
473
436
|
|
|
474
|
-
return f"Vector3(
|
|
437
|
+
return f"Vector3({self.x}, {self.y}, {self.z})"
|
|
475
438
|
|
|
476
439
|
def __add__(self, other: Vector3) -> Vector3:
|
|
477
440
|
"""
|
|
@@ -481,7 +444,7 @@ class Vector3(Message):
|
|
|
481
444
|
:return: The sum vector.
|
|
482
445
|
"""
|
|
483
446
|
|
|
484
|
-
return Vector3(
|
|
447
|
+
return Vector3(x=self.x + other.x, y=self.y + other.y, z=self.z + other.z)
|
|
485
448
|
|
|
486
449
|
def __sub__(self, other: Vector3) -> Vector3:
|
|
487
450
|
"""
|
|
@@ -491,7 +454,7 @@ class Vector3(Message):
|
|
|
491
454
|
:return: The difference vector.
|
|
492
455
|
"""
|
|
493
456
|
|
|
494
|
-
return Vector3(
|
|
457
|
+
return Vector3(x=self.x - other.x, y=self.y - other.y, z=self.z - other.z)
|
|
495
458
|
|
|
496
459
|
def __mul__(self, scalar: float) -> Vector3:
|
|
497
460
|
"""
|
|
@@ -501,7 +464,7 @@ class Vector3(Message):
|
|
|
501
464
|
:return: The scaled vector.
|
|
502
465
|
"""
|
|
503
466
|
|
|
504
|
-
return Vector3(
|
|
467
|
+
return Vector3(x=self.x * scalar, y=self.y * scalar, z=self.z * scalar)
|
|
505
468
|
|
|
506
469
|
def __rmul__(self, scalar: float) -> Vector3:
|
|
507
470
|
"""
|
|
@@ -524,7 +487,7 @@ class Vector3(Message):
|
|
|
524
487
|
|
|
525
488
|
if scalar == 0:
|
|
526
489
|
raise ZeroDivisionError("Cannot divide vector by zero")
|
|
527
|
-
return Vector3(
|
|
490
|
+
return Vector3(x=self.x / scalar, y=self.y / scalar, z=self.z / scalar)
|
|
528
491
|
|
|
529
492
|
def __neg__(self) -> Vector3:
|
|
530
493
|
"""
|
|
@@ -533,59 +496,7 @@ class Vector3(Message):
|
|
|
533
496
|
:return: The negated vector.
|
|
534
497
|
"""
|
|
535
498
|
|
|
536
|
-
return Vector3(
|
|
537
|
-
|
|
538
|
-
@model_validator(mode="before")
|
|
539
|
-
@classmethod
|
|
540
|
-
def convert_iterables(cls, data: Any) -> Any:
|
|
541
|
-
"""
|
|
542
|
-
Automatically convert lists, tuples, dicts, and numpy arrays to Vector3 format.
|
|
543
|
-
"""
|
|
544
|
-
|
|
545
|
-
# Already a Vector3 instance
|
|
546
|
-
if isinstance(data, cls):
|
|
547
|
-
return {"data": data.data}
|
|
548
|
-
|
|
549
|
-
# Tuple format - already correct
|
|
550
|
-
if isinstance(data, tuple) and len(data) == 3:
|
|
551
|
-
return {"data": (float(data[0]), float(data[1]), float(data[2]))}
|
|
552
|
-
|
|
553
|
-
# Dict format with x, y, z - convert to tuple
|
|
554
|
-
if isinstance(data, dict):
|
|
555
|
-
if "data" in data:
|
|
556
|
-
return data
|
|
557
|
-
if "x" in data and "y" in data and "z" in data:
|
|
558
|
-
return {"data": (float(data["x"]), float(data["y"]), float(data["z"]))}
|
|
559
|
-
raise ValueError("Dict must have either 'data' or 'x', 'y', and 'z' fields")
|
|
560
|
-
|
|
561
|
-
# Numpy array - convert
|
|
562
|
-
if isinstance(data, np.ndarray):
|
|
563
|
-
if data.shape != (3,):
|
|
564
|
-
raise ValueError(f"Vector3 array must have shape (3,), got {data.shape}")
|
|
565
|
-
return {"data": (float(data[0]), float(data[1]), float(data[2]))}
|
|
566
|
-
|
|
567
|
-
# List - convert
|
|
568
|
-
if isinstance(data, list):
|
|
569
|
-
if len(data) != 3:
|
|
570
|
-
raise ValueError(f"Vector3 requires 3 values, got {len(data)}")
|
|
571
|
-
if all(item is None for item in data):
|
|
572
|
-
return {"data": (0.0, 0.0, 0.0)}
|
|
573
|
-
return {"data": (float(data[0]), float(data[1]), float(data[2]))}
|
|
574
|
-
|
|
575
|
-
return data
|
|
576
|
-
|
|
577
|
-
@classmethod
|
|
578
|
-
def new(cls, x: float, y: float, z: float) -> Vector3:
|
|
579
|
-
"""
|
|
580
|
-
Create a new 3D vector.
|
|
581
|
-
|
|
582
|
-
:param x: The x component.
|
|
583
|
-
:param y: The y component.
|
|
584
|
-
:param z: The z component.
|
|
585
|
-
:return: A 3D vector.
|
|
586
|
-
"""
|
|
587
|
-
|
|
588
|
-
return cls(data=(x, y, z))
|
|
499
|
+
return Vector3(x=-self.x, y=-self.y, z=-self.z)
|
|
589
500
|
|
|
590
501
|
@classmethod
|
|
591
502
|
def zeros(cls) -> Vector3:
|
|
@@ -595,7 +506,7 @@ class Vector3(Message):
|
|
|
595
506
|
:return: A zero vector.
|
|
596
507
|
"""
|
|
597
508
|
|
|
598
|
-
return cls(
|
|
509
|
+
return cls(x=0.0, y=0.0, z=0.0)
|
|
599
510
|
|
|
600
511
|
@classmethod
|
|
601
512
|
def ones(cls) -> Vector3:
|
|
@@ -605,27 +516,29 @@ class Vector3(Message):
|
|
|
605
516
|
:return: A ones vector.
|
|
606
517
|
"""
|
|
607
518
|
|
|
608
|
-
return cls(
|
|
519
|
+
return cls(x=1.0, y=1.0, z=1.0)
|
|
609
520
|
|
|
610
521
|
@classmethod
|
|
611
|
-
def from_any(cls,
|
|
522
|
+
def from_any(cls, value: Vector3 | tuple | list | dict | np.ndarray | None) -> Vector3:
|
|
612
523
|
"""
|
|
613
|
-
Create Vector3 from any
|
|
524
|
+
Create Vector3 from any compatible type.
|
|
525
|
+
|
|
526
|
+
Accepts:
|
|
527
|
+
- Vector3 instance (returned as-is)
|
|
528
|
+
- Tuple/list of 3 floats: (x, y, z)
|
|
529
|
+
- Dict with 'x', 'y', and 'z' keys
|
|
530
|
+
- Numpy array of shape (3,)
|
|
531
|
+
- None (returns zero vector)
|
|
614
532
|
|
|
615
|
-
:param
|
|
533
|
+
:param value: Any compatible input type.
|
|
616
534
|
:return: A Vector3 instance.
|
|
617
|
-
:raises ValueError: If conversion fails.
|
|
618
535
|
"""
|
|
619
536
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
# Will be handled by validator
|
|
626
|
-
return cls.model_validate(data)
|
|
627
|
-
except Exception as e:
|
|
628
|
-
raise ValueError(f"Cannot convert to Vector3: {e}") from None
|
|
537
|
+
if value is None:
|
|
538
|
+
return cls(x=0.0, y=0.0, z=0.0)
|
|
539
|
+
if isinstance(value, cls):
|
|
540
|
+
return value
|
|
541
|
+
return cls.model_validate(value)
|
|
629
542
|
|
|
630
543
|
@classmethod
|
|
631
544
|
def from_numpy(cls, array: np.ndarray) -> Vector3:
|
|
@@ -639,7 +552,7 @@ class Vector3(Message):
|
|
|
639
552
|
|
|
640
553
|
if array.shape != (3,):
|
|
641
554
|
raise ValueError(f"Vector3 array must have shape (3,), got {array.shape}")
|
|
642
|
-
return cls(
|
|
555
|
+
return cls(x=float(array[0]), y=float(array[1]), z=float(array[2]))
|
|
643
556
|
|
|
644
557
|
@classmethod
|
|
645
558
|
def from_list(cls, values: list[float]) -> Vector3:
|
|
@@ -653,7 +566,7 @@ class Vector3(Message):
|
|
|
653
566
|
|
|
654
567
|
if len(values) != 3:
|
|
655
568
|
raise ValueError(f"Vector3 requires 3 values, got {len(values)}")
|
|
656
|
-
return cls(
|
|
569
|
+
return cls(x=values[0], y=values[1], z=values[2])
|
|
657
570
|
|
|
658
571
|
def dot(self, other: Vector3) -> float:
|
|
659
572
|
"""
|
|
@@ -674,11 +587,9 @@ class Vector3(Message):
|
|
|
674
587
|
"""
|
|
675
588
|
|
|
676
589
|
return Vector3(
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
self.x * other.y - self.y * other.x,
|
|
681
|
-
)
|
|
590
|
+
x=self.y * other.z - self.z * other.y,
|
|
591
|
+
y=self.z * other.x - self.x * other.z,
|
|
592
|
+
z=self.x * other.y - self.y * other.x,
|
|
682
593
|
)
|
|
683
594
|
|
|
684
595
|
def magnitude(self) -> float:
|
|
@@ -719,7 +630,7 @@ class Vector3(Message):
|
|
|
719
630
|
:return: The numpy array.
|
|
720
631
|
"""
|
|
721
632
|
|
|
722
|
-
return np.array(self.
|
|
633
|
+
return np.array([self.x, self.y, self.z], dtype=np.float32)
|
|
723
634
|
|
|
724
635
|
def to_list(self) -> list[float]:
|
|
725
636
|
"""
|
|
@@ -728,7 +639,16 @@ class Vector3(Message):
|
|
|
728
639
|
:return: The list of values.
|
|
729
640
|
"""
|
|
730
641
|
|
|
731
|
-
return
|
|
642
|
+
return [self.x, self.y, self.z]
|
|
643
|
+
|
|
644
|
+
def to_tuple(self) -> tuple[float, float, float]:
|
|
645
|
+
"""
|
|
646
|
+
Convert to a tuple.
|
|
647
|
+
|
|
648
|
+
:return: The tuple of values.
|
|
649
|
+
"""
|
|
650
|
+
|
|
651
|
+
return (self.x, self.y, self.z)
|
|
732
652
|
|
|
733
653
|
def to_gf_vec3f(self) -> Gf.Vec3f:
|
|
734
654
|
"""
|
|
@@ -738,8 +658,8 @@ class Vector3(Message):
|
|
|
738
658
|
:raises ImportError: If pxr is not installed.
|
|
739
659
|
"""
|
|
740
660
|
|
|
741
|
-
|
|
742
|
-
|
|
661
|
+
from pxr import Gf
|
|
662
|
+
|
|
743
663
|
return Gf.Vec3f(self.x, self.y, self.z)
|
|
744
664
|
|
|
745
665
|
def to_gf_vec3d(self) -> Gf.Vec3d:
|
|
@@ -750,11 +670,11 @@ class Vector3(Message):
|
|
|
750
670
|
:raises ImportError: If pxr is not installed.
|
|
751
671
|
"""
|
|
752
672
|
|
|
753
|
-
|
|
754
|
-
|
|
673
|
+
from pxr import Gf
|
|
674
|
+
|
|
755
675
|
return Gf.Vec3d(self.x, self.y, self.z)
|
|
756
676
|
|
|
757
|
-
def to_quat(self) ->
|
|
677
|
+
def to_quat(self) -> Quaternion:
|
|
758
678
|
"""
|
|
759
679
|
Convert RPY angles to quaternion.
|
|
760
680
|
|
|
@@ -763,8 +683,6 @@ class Vector3(Message):
|
|
|
763
683
|
:return: Quaternion representation.
|
|
764
684
|
"""
|
|
765
685
|
|
|
766
|
-
from common.message.quaternion import Quaternion
|
|
767
|
-
|
|
768
686
|
return Quaternion.from_rpy(self.x, self.y, self.z)
|
|
769
687
|
|
|
770
688
|
def to_point(self) -> Point3:
|
|
@@ -776,11 +694,28 @@ class Vector3(Message):
|
|
|
776
694
|
|
|
777
695
|
return Point3(x=self.x, y=self.y, z=self.z)
|
|
778
696
|
|
|
779
|
-
def
|
|
697
|
+
def to_foxglove(self) -> FoxgloveVector3:
|
|
780
698
|
"""
|
|
781
|
-
Convert to
|
|
699
|
+
Convert to Foxglove Vector3 for telemetry.
|
|
782
700
|
|
|
783
|
-
:return:
|
|
701
|
+
:return: Foxglove Vector3 schema.
|
|
784
702
|
"""
|
|
785
703
|
|
|
786
|
-
return self.
|
|
704
|
+
return FoxgloveVector3(x=self.x, y=self.y, z=self.z)
|
|
705
|
+
|
|
706
|
+
@model_validator(mode="before")
|
|
707
|
+
@classmethod
|
|
708
|
+
def _convert_input(cls, data: Any) -> Any:
|
|
709
|
+
"""
|
|
710
|
+
Convert various input types to Vector3 format.
|
|
711
|
+
"""
|
|
712
|
+
|
|
713
|
+
if isinstance(data, cls):
|
|
714
|
+
return {"x": data.x, "y": data.y, "z": data.z}
|
|
715
|
+
if isinstance(data, (tuple, list)) and len(data) == 3:
|
|
716
|
+
return {"x": float(data[0]), "y": float(data[1]), "z": float(data[2])}
|
|
717
|
+
if isinstance(data, np.ndarray) and data.shape == (3,):
|
|
718
|
+
return {"x": float(data[0]), "y": float(data[1]), "z": float(data[2])}
|
|
719
|
+
if isinstance(data, dict) and "x" in data and "y" in data and "z" in data:
|
|
720
|
+
return {"x": float(data["x"]), "y": float(data["y"]), "z": float(data["z"])}
|
|
721
|
+
return data
|