clarity-api-sdk-python 0.4.1__tar.gz → 0.4.2__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.
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/PKG-INFO +2 -1
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/pyproject.toml +2 -1
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/clarity_api_sdk_python.egg-info/PKG-INFO +2 -1
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/clarity_api_sdk_python.egg-info/SOURCES.txt +4 -1
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/clarity_api_sdk_python.egg-info/requires.txt +1 -0
- clarity_api_sdk_python-0.4.2/src/cti/model/target.py +132 -0
- clarity_api_sdk_python-0.4.2/src/cti/positioning/__init__.py +8 -0
- clarity_api_sdk_python-0.4.2/src/cti/positioning/target_geometry.py +159 -0
- clarity_api_sdk_python-0.4.2/tests/test_target_geometry.py +253 -0
- clarity_api_sdk_python-0.4.1/src/cti/model/target.py +0 -63
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/README.md +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/setup.cfg +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/clarity_api_sdk_python.egg-info/dependency_links.txt +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/clarity_api_sdk_python.egg-info/entry_points.txt +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/clarity_api_sdk_python.egg-info/top_level.txt +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/__init__.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/api/__init__.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/api/async_client.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/api/client.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/api/session.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/api/sonar_wiz_api.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/api/sonar_wiz_async_api.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/cli/__init__.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/cli/__main__.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/cli/client.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/cli/main.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/logger/__init__.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/logger/logger.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/main.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/main_api.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/__init__.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/altitude_source.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/attitude_source.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/deferred_object_deletion.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/depth_source.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/device.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/device_type.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/final_product.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/hierarchy.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/layback_algorithm.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/layback_source.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/layback_type.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/organization.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/platform.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/platform_type.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/position_source.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/processing_job.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/processing_log.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/project.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/projection_option.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/raw_file.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/raw_file_configuration.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/raw_file_device_mapping.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/raw_file_state.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/s3.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/sidescan_ping_source.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/source.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/survey.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/tow_system.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/user_layer.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/tests/test_cli.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/tests/test_raw_file_device_mapping_model.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/tests/test_sdk_async_methods.py +0 -0
- {clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/tests/test_sdk_methods.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clarity-api-sdk-python
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A Python SDK to connect to the CTI Clarity API server.
|
|
5
5
|
Author-email: "Chesapeake Technology Inc." <support@chesapeaketech.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/chesapeake-tech/clarity-api-sdk-python
|
|
@@ -15,6 +15,7 @@ Requires-Dist: h2
|
|
|
15
15
|
Requires-Dist: httpx_auth>=0.23.1
|
|
16
16
|
Requires-Dist: httpx-retries>=0.4.5
|
|
17
17
|
Requires-Dist: pydantic==2.12.3
|
|
18
|
+
Requires-Dist: pyproj==3.7.2
|
|
18
19
|
Requires-Dist: structlog==25.4.0
|
|
19
20
|
Requires-Dist: typer>=0.15
|
|
20
21
|
Provides-Extra: dev
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "clarity-api-sdk-python"
|
|
8
|
-
version = "0.4.
|
|
8
|
+
version = "0.4.2"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name="Chesapeake Technology Inc.", email="support@chesapeaketech.com" },
|
|
11
11
|
]
|
|
@@ -24,6 +24,7 @@ dependencies = [
|
|
|
24
24
|
"httpx_auth>=0.23.1",
|
|
25
25
|
"httpx-retries>=0.4.5",
|
|
26
26
|
"pydantic==2.12.3",
|
|
27
|
+
"pyproj==3.7.2",
|
|
27
28
|
"structlog==25.4.0",
|
|
28
29
|
"typer>=0.15",
|
|
29
30
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clarity-api-sdk-python
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A Python SDK to connect to the CTI Clarity API server.
|
|
5
5
|
Author-email: "Chesapeake Technology Inc." <support@chesapeaketech.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/chesapeake-tech/clarity-api-sdk-python
|
|
@@ -15,6 +15,7 @@ Requires-Dist: h2
|
|
|
15
15
|
Requires-Dist: httpx_auth>=0.23.1
|
|
16
16
|
Requires-Dist: httpx-retries>=0.4.5
|
|
17
17
|
Requires-Dist: pydantic==2.12.3
|
|
18
|
+
Requires-Dist: pyproj==3.7.2
|
|
18
19
|
Requires-Dist: structlog==25.4.0
|
|
19
20
|
Requires-Dist: typer>=0.15
|
|
20
21
|
Provides-Extra: dev
|
|
@@ -52,7 +52,10 @@ src/cti/model/survey.py
|
|
|
52
52
|
src/cti/model/target.py
|
|
53
53
|
src/cti/model/tow_system.py
|
|
54
54
|
src/cti/model/user_layer.py
|
|
55
|
+
src/cti/positioning/__init__.py
|
|
56
|
+
src/cti/positioning/target_geometry.py
|
|
55
57
|
tests/test_cli.py
|
|
56
58
|
tests/test_raw_file_device_mapping_model.py
|
|
57
59
|
tests/test_sdk_async_methods.py
|
|
58
|
-
tests/test_sdk_methods.py
|
|
60
|
+
tests/test_sdk_methods.py
|
|
61
|
+
tests/test_target_geometry.py
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Pydantic models for target data.
|
|
2
|
+
|
|
3
|
+
Mirrors the sample-address shape introduced by clarity-server #119
|
|
4
|
+
(see ``clarity-server/src/model/target.py``). The ``derived`` block
|
|
5
|
+
required by the Targets MVP spec on every read response is computed by
|
|
6
|
+
``cti.positioning.target_geometry.derive`` and surfaced as
|
|
7
|
+
``Target.derived``; populating it server-side is clarity-server #120's
|
|
8
|
+
job.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from uuid import UUID
|
|
13
|
+
|
|
14
|
+
from pydantic import BaseModel, ConfigDict
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
_DEFAULT_NAME = "[unreviewed] [Unknown Object]"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TargetBase(BaseModel):
|
|
21
|
+
"""Sample-address fields shared across create/update/read models.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
channel: Sonar channel index (port/starboard/…).
|
|
25
|
+
ping: Ping address (along-track).
|
|
26
|
+
sample: Sample address within the ping (across-track, non-negative).
|
|
27
|
+
name: Operator-supplied name.
|
|
28
|
+
description: Optional free-form notes.
|
|
29
|
+
width_samples: Optional bounding-box width in sample addresses.
|
|
30
|
+
height_pings: Optional bounding-box height in ping addresses.
|
|
31
|
+
shadow_samples: Optional acoustic-shadow length in sample addresses.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
channel: int
|
|
35
|
+
ping: int
|
|
36
|
+
sample: int
|
|
37
|
+
name: str = _DEFAULT_NAME
|
|
38
|
+
description: str = ""
|
|
39
|
+
width_samples: int | None = None
|
|
40
|
+
height_pings: int | None = None
|
|
41
|
+
shadow_samples: int | None = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TargetCreate(TargetBase):
|
|
45
|
+
"""POST body shape — sample-address fields plus the parent FK.
|
|
46
|
+
|
|
47
|
+
Attributes:
|
|
48
|
+
sidescan_ping_source_id: FK reference to SidescanPingSource.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
sidescan_ping_source_id: UUID
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class TargetUpdate(BaseModel):
|
|
55
|
+
"""Partial update body — every field optional.
|
|
56
|
+
|
|
57
|
+
Attributes:
|
|
58
|
+
channel: Sonar channel index.
|
|
59
|
+
ping: Ping address.
|
|
60
|
+
sample: Sample address.
|
|
61
|
+
name: Operator-supplied name.
|
|
62
|
+
description: Free-form notes.
|
|
63
|
+
width_samples: Bounding-box width in sample addresses.
|
|
64
|
+
height_pings: Bounding-box height in ping addresses.
|
|
65
|
+
shadow_samples: Acoustic-shadow length in sample addresses.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
channel: int | None = None
|
|
69
|
+
ping: int | None = None
|
|
70
|
+
sample: int | None = None
|
|
71
|
+
name: str | None = None
|
|
72
|
+
description: str | None = None
|
|
73
|
+
width_samples: int | None = None
|
|
74
|
+
height_pings: int | None = None
|
|
75
|
+
shadow_samples: int | None = None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class TargetDerived(BaseModel):
|
|
79
|
+
"""Read-only derived block — lat/lon, projected XY, SRID-unit dimensions.
|
|
80
|
+
|
|
81
|
+
Computed by :func:`cti.positioning.target_geometry.derive` from a
|
|
82
|
+
target's sample-address fields plus the parent line's current nav,
|
|
83
|
+
bottom track, and sample/ping spacing. Always populated on read
|
|
84
|
+
responses (no opt-in flag) per the Targets MVP spec.
|
|
85
|
+
|
|
86
|
+
Attributes:
|
|
87
|
+
longitude: Geodetic longitude (EPSG:4326), decimal degrees.
|
|
88
|
+
latitude: Geodetic latitude (EPSG:4326), decimal degrees.
|
|
89
|
+
projected_x: Easting in the project SRID's linear unit.
|
|
90
|
+
projected_y: Northing in the project SRID's linear unit.
|
|
91
|
+
srid: Project SRID (e.g. ``"EPSG:32618"``).
|
|
92
|
+
width: Bounding-box width in SRID linear units, if width_samples set.
|
|
93
|
+
height: Bounding-box height in SRID linear units, if height_pings set.
|
|
94
|
+
shadow: Acoustic-shadow length in SRID linear units, if shadow_samples set.
|
|
95
|
+
linear_unit: SRID's linear unit name (typically ``"meter"``).
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
longitude: float
|
|
99
|
+
latitude: float
|
|
100
|
+
projected_x: float
|
|
101
|
+
projected_y: float
|
|
102
|
+
srid: str
|
|
103
|
+
width: float | None = None
|
|
104
|
+
height: float | None = None
|
|
105
|
+
shadow: float | None = None
|
|
106
|
+
linear_unit: str
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class Target(TargetBase):
|
|
110
|
+
"""Full read shape with database-managed fields and derived block.
|
|
111
|
+
|
|
112
|
+
Attributes:
|
|
113
|
+
target_id: Unique identifier for the target.
|
|
114
|
+
sidescan_ping_source_id: FK reference to SidescanPingSource.
|
|
115
|
+
derived: Derived geographic position and SRID-unit dimensions
|
|
116
|
+
(populated server-side; ``None`` only when the line lacks the
|
|
117
|
+
nav/bottom-track state required to compute it).
|
|
118
|
+
created_by_user_id: Authoring user (nullable until auth wiring lands).
|
|
119
|
+
last_modified_by_user_id: Last-editing user (nullable until auth wiring lands).
|
|
120
|
+
created_at: Row creation timestamp (UTC).
|
|
121
|
+
updated_at: Row last-modification timestamp (UTC).
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
target_id: UUID
|
|
125
|
+
sidescan_ping_source_id: UUID
|
|
126
|
+
derived: TargetDerived | None = None
|
|
127
|
+
created_by_user_id: UUID | None = None
|
|
128
|
+
last_modified_by_user_id: UUID | None = None
|
|
129
|
+
created_at: datetime
|
|
130
|
+
updated_at: datetime
|
|
131
|
+
|
|
132
|
+
model_config = ConfigDict(from_attributes=True)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Shared positioning math used by clarity-server and clarity-engine.
|
|
2
|
+
|
|
3
|
+
The Targets MVP spec requires that geographic position and SRID-unit
|
|
4
|
+
dimensions for a target be derived (not stored) from the parent line's
|
|
5
|
+
current nav, bottom track, and sample spacing — and that the engine and
|
|
6
|
+
server share one source of truth for that math. This package is that
|
|
7
|
+
source of truth.
|
|
8
|
+
"""
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Sample-address → geographic-position math for a single Target.
|
|
2
|
+
|
|
3
|
+
Given a target's ``(channel, ping, sample)`` address and the parent
|
|
4
|
+
line's per-ping nav state at that ping, produce the spec's ``derived``
|
|
5
|
+
block: geodetic lat/lon, projected XY in the project SRID, and the
|
|
6
|
+
optional SRID-unit width/height/shadow dimensions.
|
|
7
|
+
|
|
8
|
+
This module is the canonical implementation. Both ``clarity-server``
|
|
9
|
+
(read path: GET /targets/{id} populates ``Target.derived``) and
|
|
10
|
+
``clarity-engine`` (any internal use that needs target geometry) MUST
|
|
11
|
+
import :func:`derive` rather than re-implement it. See
|
|
12
|
+
``clarity-docs/designs/spec-targets-mvp.md`` §"Conversion responsibility
|
|
13
|
+
split".
|
|
14
|
+
|
|
15
|
+
Conventions
|
|
16
|
+
-----------
|
|
17
|
+
- ``channel == 0`` is port (left of vessel track).
|
|
18
|
+
- Any other ``channel`` is starboard (right of vessel track).
|
|
19
|
+
- Headings are compass bearings: 0° = north, increasing clockwise.
|
|
20
|
+
- Vessel position in :class:`LineState` is **projected** in the same
|
|
21
|
+
``target_srid`` passed to :func:`derive`. Both consumers (server and
|
|
22
|
+
engine) hold per-ping nav in projected coordinates after the
|
|
23
|
+
navigation phase (e.g. clarity-engine writes ``inner_x``/``inner_y``
|
|
24
|
+
in the project SRID), so taking projected input here avoids a
|
|
25
|
+
redundant geodetic round-trip.
|
|
26
|
+
- Slant range is corrected to ground range using the bottom-tracked
|
|
27
|
+
altitude when available; without altitude, slant range is used
|
|
28
|
+
directly (acceptable when the seafloor is shallow relative to range).
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import math
|
|
34
|
+
from dataclasses import dataclass
|
|
35
|
+
from functools import lru_cache
|
|
36
|
+
|
|
37
|
+
import pyproj
|
|
38
|
+
|
|
39
|
+
from cti.model.target import Target, TargetDerived
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
_GEODETIC_CRS = "EPSG:4326"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class LineState:
|
|
47
|
+
"""Per-ping line state at a target's ping index.
|
|
48
|
+
|
|
49
|
+
Callers (typically the server's derive layer) extract these scalars
|
|
50
|
+
from the parent SidescanPingSource's nav/bottom-track Zarr arrays
|
|
51
|
+
and the sample-spacing computed from sound velocity and sample rate.
|
|
52
|
+
|
|
53
|
+
Attributes:
|
|
54
|
+
projected_x: Vessel easting at the target's ping, in the project
|
|
55
|
+
SRID's linear unit (must match ``target_srid`` passed to
|
|
56
|
+
:func:`derive`).
|
|
57
|
+
projected_y: Vessel northing at the target's ping, same SRID.
|
|
58
|
+
heading_deg: Vessel compass heading at the target's ping
|
|
59
|
+
(0 = north, increasing clockwise).
|
|
60
|
+
sample_spacing_units: Across-track distance per sample, in the
|
|
61
|
+
project SRID's linear unit. Caller is responsible for the
|
|
62
|
+
metres-to-SRID-unit conversion before constructing the
|
|
63
|
+
LineState.
|
|
64
|
+
ping_spacing_units: Local along-track distance per ping, in the
|
|
65
|
+
project SRID's linear unit (typically metres for projected
|
|
66
|
+
SRIDs but feet for some state-plane SRIDs). Caller computes
|
|
67
|
+
this from consecutive vessel positions, which are themselves
|
|
68
|
+
already in SRID-projected coordinates, so the result inherits
|
|
69
|
+
the SRID's linear unit rather than being forced to metres.
|
|
70
|
+
altitude_units: Bottom-tracked altitude at the target's ping, in
|
|
71
|
+
SRID linear units, or ``None`` if no bottom track is
|
|
72
|
+
available (slant-to-ground correction is then skipped).
|
|
73
|
+
Caller converts from metres before constructing the LineState.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
projected_x: float
|
|
77
|
+
projected_y: float
|
|
78
|
+
heading_deg: float
|
|
79
|
+
sample_spacing_units: float
|
|
80
|
+
ping_spacing_units: float
|
|
81
|
+
altitude_units: float | None = None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@lru_cache(maxsize=64)
|
|
85
|
+
def _transformer_from(target_srid: str) -> pyproj.Transformer:
|
|
86
|
+
"""Cached inverse transformer from ``target_srid`` to EPSG:4326."""
|
|
87
|
+
return pyproj.Transformer.from_crs(target_srid, _GEODETIC_CRS, always_xy=True)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@lru_cache(maxsize=64)
|
|
91
|
+
def _linear_unit(target_srid: str) -> str:
|
|
92
|
+
"""Linear unit name for ``target_srid`` (e.g. ``"metre"`` / ``"meter"``)."""
|
|
93
|
+
crs = pyproj.CRS.from_user_input(target_srid)
|
|
94
|
+
axis = crs.axis_info[0] if crs.axis_info else None
|
|
95
|
+
return axis.unit_name if axis is not None else "meter"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def derive( # pylint: disable=too-many-locals
|
|
99
|
+
target: Target, line_state: LineState, target_srid: str
|
|
100
|
+
) -> TargetDerived:
|
|
101
|
+
"""Derive a target's geographic position and SRID-unit dimensions.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
target: The target to position. Only ``channel``, ``sample``,
|
|
105
|
+
``width_samples``, ``height_pings``, and ``shadow_samples``
|
|
106
|
+
are read; ``ping`` is consumed by the caller when
|
|
107
|
+
constructing ``line_state``.
|
|
108
|
+
line_state: Per-ping nav + spacing at ``target.ping``.
|
|
109
|
+
target_srid: Project SRID to project into (e.g. ``"EPSG:32618"``).
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
The derived block: geodetic lat/lon, projected XY in
|
|
113
|
+
``target_srid``, optional SRID-unit width/height/shadow, and the
|
|
114
|
+
SRID's linear-unit name.
|
|
115
|
+
"""
|
|
116
|
+
side = -1.0 if target.channel == 0 else 1.0
|
|
117
|
+
slant_range_units = target.sample * line_state.sample_spacing_units
|
|
118
|
+
ground_range_units = (
|
|
119
|
+
math.sqrt(slant_range_units**2 - line_state.altitude_units**2)
|
|
120
|
+
if line_state.altitude_units is not None
|
|
121
|
+
and slant_range_units > line_state.altitude_units
|
|
122
|
+
else slant_range_units
|
|
123
|
+
)
|
|
124
|
+
across_track_units = side * ground_range_units
|
|
125
|
+
|
|
126
|
+
perp_rad = math.radians(line_state.heading_deg) + math.pi / 2.0
|
|
127
|
+
target_x = line_state.projected_x + across_track_units * math.sin(perp_rad)
|
|
128
|
+
target_y = line_state.projected_y + across_track_units * math.cos(perp_rad)
|
|
129
|
+
|
|
130
|
+
inverse = _transformer_from(target_srid)
|
|
131
|
+
target_lon, target_lat = inverse.transform(target_x, target_y)
|
|
132
|
+
|
|
133
|
+
width = (
|
|
134
|
+
target.width_samples * line_state.sample_spacing_units
|
|
135
|
+
if target.width_samples is not None
|
|
136
|
+
else None
|
|
137
|
+
)
|
|
138
|
+
height = (
|
|
139
|
+
target.height_pings * line_state.ping_spacing_units
|
|
140
|
+
if target.height_pings is not None
|
|
141
|
+
else None
|
|
142
|
+
)
|
|
143
|
+
shadow = (
|
|
144
|
+
target.shadow_samples * line_state.sample_spacing_units
|
|
145
|
+
if target.shadow_samples is not None
|
|
146
|
+
else None
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return TargetDerived(
|
|
150
|
+
longitude=target_lon,
|
|
151
|
+
latitude=target_lat,
|
|
152
|
+
projected_x=target_x,
|
|
153
|
+
projected_y=target_y,
|
|
154
|
+
srid=target_srid,
|
|
155
|
+
width=width,
|
|
156
|
+
height=height,
|
|
157
|
+
shadow=shadow,
|
|
158
|
+
linear_unit=_linear_unit(target_srid),
|
|
159
|
+
)
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""Unit tests for cti.positioning.target_geometry.derive.
|
|
2
|
+
|
|
3
|
+
Covers the math contract that clarity-server #120 will rely on:
|
|
4
|
+
slant-to-ground range correction, port/starboard side convention,
|
|
5
|
+
heading-rotated displacement, sample-domain dimension conversion,
|
|
6
|
+
and lat/lon roundtripping through the project SRID.
|
|
7
|
+
|
|
8
|
+
Also pins the Pydantic shape for ``TargetDerived`` and the
|
|
9
|
+
``Target.derived`` field so a regression that drops the derived block
|
|
10
|
+
fails loudly here.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import math
|
|
16
|
+
from datetime import datetime, timezone
|
|
17
|
+
from uuid import uuid4
|
|
18
|
+
|
|
19
|
+
import pyproj
|
|
20
|
+
import pytest
|
|
21
|
+
|
|
22
|
+
from cti.model.target import Target, TargetDerived
|
|
23
|
+
from cti.positioning.target_geometry import LineState, derive
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
_NOW = datetime(2026, 5, 5, tzinfo=timezone.utc)
|
|
27
|
+
_SRID = "EPSG:32618" # UTM zone 18N — covers Chesapeake Bay area
|
|
28
|
+
# Approximate UTM 18N projection of (-76.40, 38.95) — round numbers used so the
|
|
29
|
+
# math in assertions is easy to follow; tests don't depend on exact projection.
|
|
30
|
+
_VESSEL_X = 378_700.0
|
|
31
|
+
_VESSEL_Y = 4_312_160.0
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _make_target(
|
|
35
|
+
*,
|
|
36
|
+
channel: int = 1,
|
|
37
|
+
sample: int = 0,
|
|
38
|
+
width_samples: int | None = None,
|
|
39
|
+
height_pings: int | None = None,
|
|
40
|
+
shadow_samples: int | None = None,
|
|
41
|
+
) -> Target:
|
|
42
|
+
"""Build a Target with sane defaults for tests that vary one field."""
|
|
43
|
+
return Target(
|
|
44
|
+
target_id=uuid4(),
|
|
45
|
+
sidescan_ping_source_id=uuid4(),
|
|
46
|
+
channel=channel,
|
|
47
|
+
ping=1000,
|
|
48
|
+
sample=sample,
|
|
49
|
+
width_samples=width_samples,
|
|
50
|
+
height_pings=height_pings,
|
|
51
|
+
shadow_samples=shadow_samples,
|
|
52
|
+
created_at=_NOW,
|
|
53
|
+
updated_at=_NOW,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _make_line_state(
|
|
58
|
+
*,
|
|
59
|
+
projected_x: float = _VESSEL_X,
|
|
60
|
+
projected_y: float = _VESSEL_Y,
|
|
61
|
+
heading_deg: float = 0.0,
|
|
62
|
+
sample_spacing_units: float = 0.075,
|
|
63
|
+
ping_spacing_units: float = 0.30,
|
|
64
|
+
altitude_units: float | None = None,
|
|
65
|
+
) -> LineState:
|
|
66
|
+
"""Build a LineState with sane defaults for tests that vary one field."""
|
|
67
|
+
return LineState(
|
|
68
|
+
projected_x=projected_x,
|
|
69
|
+
projected_y=projected_y,
|
|
70
|
+
heading_deg=heading_deg,
|
|
71
|
+
sample_spacing_units=sample_spacing_units,
|
|
72
|
+
ping_spacing_units=ping_spacing_units,
|
|
73
|
+
altitude_units=altitude_units,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# ──────────────────────────────────────────────────────────────────────────
|
|
78
|
+
# Position math
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_zero_sample_yields_vessel_position() -> None:
|
|
82
|
+
"""A target at sample=0 sits at the vessel's projected position exactly."""
|
|
83
|
+
ls = _make_line_state()
|
|
84
|
+
derived = derive(_make_target(sample=0), ls, _SRID)
|
|
85
|
+
|
|
86
|
+
assert derived.projected_x == pytest.approx(ls.projected_x, abs=1e-9)
|
|
87
|
+
assert derived.projected_y == pytest.approx(ls.projected_y, abs=1e-9)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_port_and_starboard_are_mirror_images() -> None:
|
|
91
|
+
"""channel=0 and channel=1 at the same sample land equidistant from vessel,
|
|
92
|
+
on opposite sides."""
|
|
93
|
+
ls = _make_line_state()
|
|
94
|
+
port = derive(_make_target(channel=0, sample=200), ls, _SRID)
|
|
95
|
+
starboard = derive(_make_target(channel=1, sample=200), ls, _SRID)
|
|
96
|
+
vessel_x = (port.projected_x + starboard.projected_x) / 2.0
|
|
97
|
+
vessel_y = (port.projected_y + starboard.projected_y) / 2.0
|
|
98
|
+
|
|
99
|
+
# Vessel sits exactly between port and starboard targets
|
|
100
|
+
nadir = derive(_make_target(sample=0), ls, _SRID)
|
|
101
|
+
assert vessel_x == pytest.approx(nadir.projected_x, abs=1e-6)
|
|
102
|
+
assert vessel_y == pytest.approx(nadir.projected_y, abs=1e-6)
|
|
103
|
+
|
|
104
|
+
# Port is the negative side of the perpendicular axis
|
|
105
|
+
assert port.projected_x < starboard.projected_x
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_no_altitude_uses_slant_range_directly() -> None:
|
|
109
|
+
"""Without altitude_units, ground_range == slant_range = sample × sample_spacing."""
|
|
110
|
+
ls = _make_line_state(heading_deg=0.0, altitude_units=None)
|
|
111
|
+
derived = derive(_make_target(channel=1, sample=200), ls, _SRID)
|
|
112
|
+
nadir = derive(_make_target(sample=0), ls, _SRID)
|
|
113
|
+
|
|
114
|
+
# Heading = 0 (north) → starboard is east → +x displacement
|
|
115
|
+
expected_dx = 200 * 0.075 # 15.0 m
|
|
116
|
+
assert derived.projected_x - nadir.projected_x == pytest.approx(
|
|
117
|
+
expected_dx, abs=1e-6
|
|
118
|
+
)
|
|
119
|
+
assert derived.projected_y == pytest.approx(nadir.projected_y, abs=1e-6)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_slant_range_corrected_when_altitude_set() -> None:
|
|
123
|
+
"""ground_range = sqrt(slant² - altitude²) when altitude < slant."""
|
|
124
|
+
ls = _make_line_state(heading_deg=0.0, altitude_units=10.0)
|
|
125
|
+
derived = derive(_make_target(channel=1, sample=200), ls, _SRID)
|
|
126
|
+
nadir = derive(_make_target(sample=0), ls, _SRID)
|
|
127
|
+
|
|
128
|
+
slant = 200 * 0.075 # 15 m
|
|
129
|
+
expected_ground = math.sqrt(slant**2 - 10.0**2) # √125 ≈ 11.180
|
|
130
|
+
assert derived.projected_x - nadir.projected_x == pytest.approx(
|
|
131
|
+
expected_ground, abs=1e-6
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_slant_range_used_when_altitude_exceeds_slant() -> None:
|
|
136
|
+
"""If altitude > slant range, the math would go imaginary — fall back to slant."""
|
|
137
|
+
ls = _make_line_state(heading_deg=0.0, altitude_units=50.0)
|
|
138
|
+
derived = derive(_make_target(channel=1, sample=200), ls, _SRID)
|
|
139
|
+
nadir = derive(_make_target(sample=0), ls, _SRID)
|
|
140
|
+
|
|
141
|
+
expected_dx = 200 * 0.075 # uncorrected
|
|
142
|
+
assert derived.projected_x - nadir.projected_x == pytest.approx(
|
|
143
|
+
expected_dx, abs=1e-6
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_heading_east_displaces_starboard_target_southward() -> None:
|
|
148
|
+
"""Heading 90° (east) → starboard is south → negative y displacement."""
|
|
149
|
+
ls = _make_line_state(heading_deg=90.0)
|
|
150
|
+
derived = derive(_make_target(channel=1, sample=200), ls, _SRID)
|
|
151
|
+
nadir = derive(_make_target(sample=0), ls, _SRID)
|
|
152
|
+
|
|
153
|
+
expected_dy = -200 * 0.075 # 15 m south
|
|
154
|
+
assert derived.projected_y - nadir.projected_y == pytest.approx(
|
|
155
|
+
expected_dy, abs=1e-6
|
|
156
|
+
)
|
|
157
|
+
assert derived.projected_x == pytest.approx(nadir.projected_x, abs=1e-6)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# ──────────────────────────────────────────────────────────────────────────
|
|
161
|
+
# Sample-domain → linear-unit dimension conversion
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def test_width_height_shadow_convert_using_their_respective_spacings() -> None:
|
|
165
|
+
"""width_samples × sample_spacing_units, height_pings × ping_spacing_units,
|
|
166
|
+
shadow_samples × sample_spacing_units."""
|
|
167
|
+
ls = _make_line_state(sample_spacing_units=0.075, ping_spacing_units=0.30)
|
|
168
|
+
target = _make_target(width_samples=10, height_pings=8, shadow_samples=15)
|
|
169
|
+
derived = derive(target, ls, _SRID)
|
|
170
|
+
|
|
171
|
+
assert derived.width == pytest.approx(10 * 0.075)
|
|
172
|
+
assert derived.height == pytest.approx(8 * 0.30)
|
|
173
|
+
assert derived.shadow == pytest.approx(15 * 0.075)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def test_unset_dimensions_pass_through_as_none() -> None:
|
|
177
|
+
"""If width_samples / height_pings / shadow_samples are None, derived
|
|
178
|
+
width / height / shadow are None — not zero."""
|
|
179
|
+
derived = derive(_make_target(), _make_line_state(), _SRID)
|
|
180
|
+
|
|
181
|
+
assert derived.width is None
|
|
182
|
+
assert derived.height is None
|
|
183
|
+
assert derived.shadow is None
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# ──────────────────────────────────────────────────────────────────────────
|
|
187
|
+
# SRID handling
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_linear_unit_comes_from_srid_metadata() -> None:
|
|
191
|
+
"""EPSG:32618 reports its linear unit as 'metre' (UK English per EPSG)."""
|
|
192
|
+
derived = derive(_make_target(), _make_line_state(), "EPSG:32618")
|
|
193
|
+
assert derived.linear_unit == "metre"
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def test_srid_string_round_trips_into_derived_block() -> None:
|
|
197
|
+
"""The SRID the caller passed is the SRID the derived block reports."""
|
|
198
|
+
derived = derive(_make_target(), _make_line_state(), "EPSG:32619")
|
|
199
|
+
assert derived.srid == "EPSG:32619"
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def test_projected_to_geodetic_inverse_is_consistent() -> None:
|
|
203
|
+
"""Projecting vessel position back to geodetic and forward again
|
|
204
|
+
recovers the same projected XY to centimeter precision."""
|
|
205
|
+
ls = _make_line_state()
|
|
206
|
+
derived = derive(_make_target(sample=0), ls, _SRID)
|
|
207
|
+
|
|
208
|
+
forward = pyproj.Transformer.from_crs("EPSG:4326", _SRID, always_xy=True)
|
|
209
|
+
rx, ry = forward.transform(derived.longitude, derived.latitude)
|
|
210
|
+
assert rx == pytest.approx(ls.projected_x, abs=1e-2)
|
|
211
|
+
assert ry == pytest.approx(ls.projected_y, abs=1e-2)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
# ──────────────────────────────────────────────────────────────────────────
|
|
215
|
+
# Pydantic shape pinning
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def test_target_derived_round_trips_through_json() -> None:
|
|
219
|
+
"""TargetDerived serializes and deserializes losslessly."""
|
|
220
|
+
derived = TargetDerived(
|
|
221
|
+
longitude=-76.123,
|
|
222
|
+
latitude=38.456,
|
|
223
|
+
projected_x=412345.67,
|
|
224
|
+
projected_y=4256789.01,
|
|
225
|
+
srid="EPSG:32618",
|
|
226
|
+
width=4.8,
|
|
227
|
+
height=6.0,
|
|
228
|
+
shadow=3.6,
|
|
229
|
+
linear_unit="metre",
|
|
230
|
+
)
|
|
231
|
+
parsed = TargetDerived.model_validate_json(derived.model_dump_json())
|
|
232
|
+
assert parsed == derived
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def test_target_carries_optional_derived_block() -> None:
|
|
236
|
+
"""Target.derived is a TargetDerived | None field, defaulting to None."""
|
|
237
|
+
target = _make_target()
|
|
238
|
+
assert target.derived is None
|
|
239
|
+
|
|
240
|
+
target_with_derived = target.model_copy(
|
|
241
|
+
update={
|
|
242
|
+
"derived": TargetDerived(
|
|
243
|
+
longitude=0.0,
|
|
244
|
+
latitude=0.0,
|
|
245
|
+
projected_x=0.0,
|
|
246
|
+
projected_y=0.0,
|
|
247
|
+
srid="EPSG:4326",
|
|
248
|
+
linear_unit="degree",
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
)
|
|
252
|
+
assert target_with_derived.derived is not None
|
|
253
|
+
assert target_with_derived.derived.srid == "EPSG:4326"
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
"""Pydantic models for target data."""
|
|
2
|
-
|
|
3
|
-
from uuid import UUID
|
|
4
|
-
|
|
5
|
-
from pydantic import BaseModel, ConfigDict
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class TargetBase(BaseModel):
|
|
9
|
-
"""Base model for target data.
|
|
10
|
-
|
|
11
|
-
Attributes:
|
|
12
|
-
name: Target name.
|
|
13
|
-
description: Target description.
|
|
14
|
-
target_x: X coordinate of the target.
|
|
15
|
-
target_y: Y coordinate of the target.
|
|
16
|
-
width: Target width.
|
|
17
|
-
height: Target height.
|
|
18
|
-
shadow: Target shadow.
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
name: str
|
|
22
|
-
description: str
|
|
23
|
-
target_x: float
|
|
24
|
-
target_y: float
|
|
25
|
-
width: float | None = None
|
|
26
|
-
height: float | None = None
|
|
27
|
-
shadow: float | None = None
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class TargetCreate(TargetBase):
|
|
31
|
-
"""Model for creating target data.
|
|
32
|
-
|
|
33
|
-
Attributes:
|
|
34
|
-
sidescan_ping_source_id: FK reference to SidescanPingSource.
|
|
35
|
-
channel: Channel index (0=port, 1=starboard).
|
|
36
|
-
row: Ping row index.
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
sidescan_ping_source_id: UUID
|
|
40
|
-
channel: int
|
|
41
|
-
row: int
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class TargetUpdate(TargetBase):
|
|
45
|
-
"""Model for updating target data."""
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class Target(TargetBase):
|
|
49
|
-
"""Model for target data with database fields.
|
|
50
|
-
|
|
51
|
-
Attributes:
|
|
52
|
-
target_id: Unique identifier for the target.
|
|
53
|
-
sidescan_ping_source_id: FK reference to SidescanPingSource.
|
|
54
|
-
channel: Channel index (0=port, 1=starboard).
|
|
55
|
-
row: Ping row index.
|
|
56
|
-
"""
|
|
57
|
-
|
|
58
|
-
target_id: UUID
|
|
59
|
-
sidescan_ping_source_id: UUID
|
|
60
|
-
channel: int
|
|
61
|
-
row: int
|
|
62
|
-
|
|
63
|
-
model_config = ConfigDict(from_attributes=True)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/api/sonar_wiz_async_api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/altitude_source.py
RENAMED
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/attitude_source.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/final_product.py
RENAMED
|
File without changes
|
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/layback_algorithm.py
RENAMED
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/layback_source.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/platform_type.py
RENAMED
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/position_source.py
RENAMED
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/processing_job.py
RENAMED
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/processing_log.py
RENAMED
|
File without changes
|
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/projection_option.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/raw_file_state.py
RENAMED
|
File without changes
|
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/src/cti/model/sidescan_ping_source.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clarity_api_sdk_python-0.4.1 → clarity_api_sdk_python-0.4.2}/tests/test_sdk_async_methods.py
RENAMED
|
File without changes
|
|
File without changes
|