compass-lib 0.0.3__tar.gz → 0.0.4__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.
- {compass_lib-0.0.3 → compass_lib-0.0.4}/PKG-INFO +5 -2
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/__init__.py +8 -8
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/commands/convert.py +8 -6
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/commands/geojson.py +43 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/constants.py +14 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/enums.py +53 -15
- compass_lib-0.0.4/compass_lib/geojson.py +2141 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/interface.py +4 -4
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/io.py +7 -7
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/project/models.py +6 -4
- compass_lib-0.0.4/compass_lib/solver/__init__.py +43 -0
- compass_lib-0.0.4/compass_lib/solver/ariane.py +488 -0
- compass_lib-0.0.4/compass_lib/solver/base.py +54 -0
- compass_lib-0.0.4/compass_lib/solver/lse.py +304 -0
- compass_lib-0.0.4/compass_lib/solver/models.py +229 -0
- compass_lib-0.0.4/compass_lib/solver/noop.py +28 -0
- compass_lib-0.0.4/compass_lib/solver/proportional.py +201 -0
- compass_lib-0.0.4/compass_lib/solver/sparse.py +249 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/survey/__init__.py +8 -8
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/survey/format.py +58 -51
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/survey/models.py +33 -67
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/survey/parser.py +94 -235
- compass_lib-0.0.4/compass_lib/validation.py +241 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/pyproject.toml +4 -1
- compass_lib-0.0.3/compass_lib/geojson.py +0 -1024
- compass_lib-0.0.3/compass_lib/validation.py +0 -74
- {compass_lib-0.0.3 → compass_lib-0.0.4}/LICENSE +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/README.md +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/commands/__init__.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/commands/encrypt.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/commands/main.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/errors.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/geo_utils.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/models.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/plot/__init__.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/plot/models.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/plot/parser.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/project/__init__.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/project/format.py +0 -0
- {compass_lib-0.0.3 → compass_lib-0.0.4}/compass_lib/project/parser.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: compass_lib
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Compass Parser Library.
|
|
5
5
|
Keywords: cave,survey,karst
|
|
6
6
|
Author-email: Jonathan Dekhtiar <jonathan@dekhtiar.com>
|
|
7
7
|
Maintainer-email: Jonathan Dekhtiar <jonathan@dekhtiar.com>
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
Classifier: Development Status :: 3 - Alpha
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
@@ -21,11 +21,14 @@ Classifier: Programming Language :: Python :: 3
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
22
|
License-File: LICENSE
|
|
23
23
|
Requires-Dist: geojson>=3.2,<4
|
|
24
|
+
Requires-Dist: numpy>=1.26,<3
|
|
25
|
+
Requires-Dist: scipy>=1.12,<2
|
|
24
26
|
Requires-Dist: orjson>=3.10,<3.12
|
|
25
27
|
Requires-Dist: pydantic>=2.12,<2.13
|
|
26
28
|
Requires-Dist: pydantic-extra-types>=2.11,<3.0
|
|
27
29
|
Requires-Dist: pyIGRF14==1.0.4
|
|
28
30
|
Requires-Dist: pyproj>=3.7.1,<3.8
|
|
31
|
+
Requires-Dist: shapely>=2.0,<3
|
|
29
32
|
Requires-Dist: utm>=0.8.1,<0.9
|
|
30
33
|
Requires-Dist: cryptography>=44.0.0,<47.0.0 ; extra == "test"
|
|
31
34
|
Requires-Dist: python-dotenv>=1.0.0,<2.0.0 ; extra == "test"
|
|
@@ -12,16 +12,16 @@ Usage:
|
|
|
12
12
|
for file_dir in project.file_directives:
|
|
13
13
|
print(f"File: {file_dir.file}")
|
|
14
14
|
if file_dir.data:
|
|
15
|
-
for
|
|
16
|
-
print(f" Survey: {
|
|
15
|
+
for survey in file_dir.data.surveys:
|
|
16
|
+
print(f" Survey: {survey.header.survey_name}")
|
|
17
17
|
|
|
18
18
|
# Or load individual files
|
|
19
19
|
from compass_lib import read_dat_file, read_mak_file
|
|
20
|
-
|
|
20
|
+
surveys = read_dat_file(Path("survey.DAT"))
|
|
21
21
|
directives = read_mak_file(Path("project.MAK"))
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
__version__ = "0.0.
|
|
24
|
+
__version__ = "0.0.4"
|
|
25
25
|
|
|
26
26
|
# Constants
|
|
27
27
|
from compass_lib.constants import COMPASS_ENCODING
|
|
@@ -60,8 +60,8 @@ from compass_lib.project.models import FileDirective
|
|
|
60
60
|
from compass_lib.project.models import LinkStation
|
|
61
61
|
from compass_lib.survey.models import CompassDatFile
|
|
62
62
|
from compass_lib.survey.models import CompassShot
|
|
63
|
-
from compass_lib.survey.models import
|
|
64
|
-
from compass_lib.survey.models import
|
|
63
|
+
from compass_lib.survey.models import CompassSurvey
|
|
64
|
+
from compass_lib.survey.models import CompassSurveyHeader
|
|
65
65
|
from compass_lib.validation import days_in_month
|
|
66
66
|
from compass_lib.validation import is_valid_station_name
|
|
67
67
|
from compass_lib.validation import validate_station_name
|
|
@@ -88,8 +88,8 @@ __all__ = [
|
|
|
88
88
|
"CompassParseError",
|
|
89
89
|
"CompassParseException",
|
|
90
90
|
"CompassShot",
|
|
91
|
-
"
|
|
92
|
-
"
|
|
91
|
+
"CompassSurvey",
|
|
92
|
+
"CompassSurveyHeader",
|
|
93
93
|
"DrawOperation",
|
|
94
94
|
"FileDirective",
|
|
95
95
|
"FileFormat",
|
|
@@ -120,13 +120,15 @@ def _convert(
|
|
|
120
120
|
if source_format == FileFormat.COMPASS and target_format == FileFormat.JSON:
|
|
121
121
|
# Compass -> JSON using Pydantic
|
|
122
122
|
if file_type == CompassFileType.DAT:
|
|
123
|
-
|
|
124
|
-
dat_file = CompassDatFile(
|
|
123
|
+
surveys = read_dat_file(input_path)
|
|
124
|
+
dat_file = CompassDatFile(surveys=surveys)
|
|
125
125
|
# Wrap in format envelope for DAT files
|
|
126
126
|
envelope = {
|
|
127
127
|
"version": "1.0",
|
|
128
128
|
"format": FormatIdentifier.COMPASS_DAT.value,
|
|
129
|
-
"
|
|
129
|
+
"surveys": json.loads(dat_file.model_dump_json(by_alias=True))[
|
|
130
|
+
"surveys"
|
|
131
|
+
],
|
|
130
132
|
}
|
|
131
133
|
result = json.dumps(envelope, indent=2, sort_keys=True)
|
|
132
134
|
else: # mak
|
|
@@ -139,9 +141,9 @@ def _convert(
|
|
|
139
141
|
if file_type == CompassFileType.DAT:
|
|
140
142
|
data = json.loads(json_str)
|
|
141
143
|
# Handle both envelope format and raw format
|
|
142
|
-
|
|
143
|
-
dat_file = CompassDatFile.model_validate({"
|
|
144
|
-
result = format_dat_file(dat_file.
|
|
144
|
+
surveys_data = data.get("surveys", [])
|
|
145
|
+
dat_file = CompassDatFile.model_validate({"surveys": surveys_data})
|
|
146
|
+
result = format_dat_file(dat_file.surveys) or ""
|
|
145
147
|
else: # mak
|
|
146
148
|
project = CompassMakFile.model_validate_json(json_str)
|
|
147
149
|
result = format_mak_file(project.directives) or ""
|
|
@@ -11,6 +11,10 @@ from pathlib import Path
|
|
|
11
11
|
|
|
12
12
|
from compass_lib.enums import FileExtension
|
|
13
13
|
from compass_lib.geojson import convert_mak_to_geojson
|
|
14
|
+
from compass_lib.solver.ariane import ArianeSolver
|
|
15
|
+
from compass_lib.solver.lse import LSESolver
|
|
16
|
+
from compass_lib.solver.proportional import ProportionalSolver
|
|
17
|
+
from compass_lib.solver.sparse import SparseSolver
|
|
14
18
|
|
|
15
19
|
logger = logging.getLogger(__name__)
|
|
16
20
|
|
|
@@ -74,6 +78,32 @@ Notes:
|
|
|
74
78
|
action="store_true",
|
|
75
79
|
help="Include passage polygon features (from LRUD data)",
|
|
76
80
|
)
|
|
81
|
+
parser.add_argument(
|
|
82
|
+
"--anchors",
|
|
83
|
+
action="store_true",
|
|
84
|
+
help="Include anchor point features (fixed reference stations)",
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
"--no-colors",
|
|
88
|
+
action="store_true",
|
|
89
|
+
help="Disable origin-based coloring of stations and legs",
|
|
90
|
+
)
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--solver",
|
|
93
|
+
choices=["proportional", "sparse", "lse", "ariane", "none"],
|
|
94
|
+
default="proportional",
|
|
95
|
+
help="Survey adjustment solver: "
|
|
96
|
+
"proportional (L2, spreads error evenly), "
|
|
97
|
+
"sparse (L1, fewest/smallest changes), "
|
|
98
|
+
"lse (blunder-aware, protects good data), "
|
|
99
|
+
"ariane (sparse CG + blunder-aware, scales to large caves), "
|
|
100
|
+
"none (raw BFS, shows misclosure gaps)",
|
|
101
|
+
)
|
|
102
|
+
parser.add_argument(
|
|
103
|
+
"--minify",
|
|
104
|
+
action="store_true",
|
|
105
|
+
help="Compact output without indentation (smaller file size)",
|
|
106
|
+
)
|
|
77
107
|
|
|
78
108
|
parsed_args = parser.parse_args(args)
|
|
79
109
|
|
|
@@ -89,12 +119,25 @@ Notes:
|
|
|
89
119
|
return 1
|
|
90
120
|
|
|
91
121
|
try:
|
|
122
|
+
solvers = {
|
|
123
|
+
"proportional": ProportionalSolver,
|
|
124
|
+
"sparse": SparseSolver,
|
|
125
|
+
"lse": LSESolver,
|
|
126
|
+
"ariane": ArianeSolver,
|
|
127
|
+
"none": lambda: None,
|
|
128
|
+
}
|
|
129
|
+
solver = solvers[parsed_args.solver]()
|
|
130
|
+
|
|
92
131
|
result = convert_mak_to_geojson(
|
|
93
132
|
parsed_args.input_file,
|
|
94
133
|
output_path=parsed_args.output_file,
|
|
95
134
|
include_stations=not parsed_args.no_stations,
|
|
96
135
|
include_legs=not parsed_args.no_legs,
|
|
97
136
|
include_passages=parsed_args.passages,
|
|
137
|
+
include_anchors=parsed_args.anchors,
|
|
138
|
+
color_by_origin=not parsed_args.no_colors,
|
|
139
|
+
solver=solver,
|
|
140
|
+
minify=parsed_args.minify,
|
|
98
141
|
)
|
|
99
142
|
|
|
100
143
|
if parsed_args.output_file is None:
|
|
@@ -82,3 +82,17 @@ FLAG_CHARS: dict[str, str] = {
|
|
|
82
82
|
#: (positive = north, negative = south), NOT by comparing northing to this threshold.
|
|
83
83
|
#: This constant is kept for reference and potential future use.
|
|
84
84
|
UTM_SOUTHERN_HEMISPHERE_OFFSET: float = 10_000_000.0
|
|
85
|
+
|
|
86
|
+
# -----------------------------------------------------------------------------
|
|
87
|
+
# Solver Constraints
|
|
88
|
+
# -----------------------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
#: Maximum relative change to a shot's tape length during traverse adjustment
|
|
91
|
+
#: (0.05 = 5 %). The solver will never stretch or shrink a shot by more than
|
|
92
|
+
#: this fraction of the original survey measurement.
|
|
93
|
+
SOLVER_MAX_LENGTH_CHANGE: float = 0.15
|
|
94
|
+
|
|
95
|
+
#: Maximum relative change to a shot's compass heading during traverse
|
|
96
|
+
#: adjustment (0.15 = 15 %). The solver will never rotate a shot's bearing
|
|
97
|
+
#: or inclination by more than this fraction of the original survey reading.
|
|
98
|
+
SOLVER_MAX_HEADING_CHANGE: float = 0.15
|
|
@@ -5,14 +5,14 @@ This module contains all enumerations used in Compass survey data formats,
|
|
|
5
5
|
including units for measurements, file types, and various classification types.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from enum import
|
|
8
|
+
from enum import StrEnum
|
|
9
9
|
from math import radians
|
|
10
10
|
from math import tan
|
|
11
11
|
|
|
12
12
|
from compass_lib.constants import FEET_TO_METERS
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
class FileFormat(
|
|
15
|
+
class FileFormat(StrEnum):
|
|
16
16
|
"""File format types for conversion operations.
|
|
17
17
|
|
|
18
18
|
Attributes:
|
|
@@ -26,7 +26,7 @@ class FileFormat(str, Enum):
|
|
|
26
26
|
GEOJSON = "geojson"
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
class CompassFileType(
|
|
29
|
+
class CompassFileType(StrEnum):
|
|
30
30
|
"""Types of Compass files.
|
|
31
31
|
|
|
32
32
|
Attributes:
|
|
@@ -67,7 +67,7 @@ class CompassFileType(str, Enum):
|
|
|
67
67
|
return mapping.get(ext_lower)
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
class FileExtension(
|
|
70
|
+
class FileExtension(StrEnum):
|
|
71
71
|
"""File extensions for various file formats (with dot).
|
|
72
72
|
|
|
73
73
|
Attributes:
|
|
@@ -85,7 +85,7 @@ class FileExtension(str, Enum):
|
|
|
85
85
|
GEOJSON = ".geojson"
|
|
86
86
|
|
|
87
87
|
|
|
88
|
-
class FormatIdentifier(
|
|
88
|
+
class FormatIdentifier(StrEnum):
|
|
89
89
|
"""Format identifiers used in JSON files.
|
|
90
90
|
|
|
91
91
|
Attributes:
|
|
@@ -97,7 +97,7 @@ class FormatIdentifier(str, Enum):
|
|
|
97
97
|
COMPASS_MAK = "compass_mak"
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
class AzimuthUnit(
|
|
100
|
+
class AzimuthUnit(StrEnum):
|
|
101
101
|
"""Unit for compass azimuth (bearing) measurements.
|
|
102
102
|
|
|
103
103
|
Attributes:
|
|
@@ -128,7 +128,7 @@ class AzimuthUnit(str, Enum):
|
|
|
128
128
|
return degrees
|
|
129
129
|
|
|
130
130
|
|
|
131
|
-
class InclinationUnit(
|
|
131
|
+
class InclinationUnit(StrEnum):
|
|
132
132
|
"""Unit for vertical angle (inclination) measurements.
|
|
133
133
|
|
|
134
134
|
Attributes:
|
|
@@ -136,7 +136,9 @@ class InclinationUnit(str, Enum):
|
|
|
136
136
|
PERCENT_GRADE: Percentage gradient (tan(angle) * 100)
|
|
137
137
|
DEGREES_AND_MINUTES: Degrees with minutes notation
|
|
138
138
|
GRADS: Gradians
|
|
139
|
-
DEPTH_GAUGE:
|
|
139
|
+
DEPTH_GAUGE: Delta depth (From_depth - To_depth) for underwater surveys.
|
|
140
|
+
Negative = descending (going deeper), positive = ascending.
|
|
141
|
+
Uses the same units as length measurements.
|
|
140
142
|
"""
|
|
141
143
|
|
|
142
144
|
DEGREES = "D"
|
|
@@ -165,7 +167,7 @@ class InclinationUnit(str, Enum):
|
|
|
165
167
|
return value
|
|
166
168
|
|
|
167
169
|
|
|
168
|
-
class LengthUnit(
|
|
170
|
+
class LengthUnit(StrEnum):
|
|
169
171
|
"""Unit for distance measurements.
|
|
170
172
|
|
|
171
173
|
Attributes:
|
|
@@ -196,7 +198,7 @@ class LengthUnit(str, Enum):
|
|
|
196
198
|
return feet
|
|
197
199
|
|
|
198
200
|
|
|
199
|
-
class LrudAssociation(
|
|
201
|
+
class LrudAssociation(StrEnum):
|
|
200
202
|
"""Indicates which station LRUD measurements are associated with.
|
|
201
203
|
|
|
202
204
|
Attributes:
|
|
@@ -208,7 +210,7 @@ class LrudAssociation(str, Enum):
|
|
|
208
210
|
TO = "T"
|
|
209
211
|
|
|
210
212
|
|
|
211
|
-
class LrudItem(
|
|
213
|
+
class LrudItem(StrEnum):
|
|
212
214
|
"""Individual LRUD dimension identifiers.
|
|
213
215
|
|
|
214
216
|
Attributes:
|
|
@@ -224,7 +226,7 @@ class LrudItem(str, Enum):
|
|
|
224
226
|
DOWN = "D"
|
|
225
227
|
|
|
226
228
|
|
|
227
|
-
class ShotItem(
|
|
229
|
+
class ShotItem(StrEnum):
|
|
228
230
|
"""Components of a shot measurement for format ordering.
|
|
229
231
|
|
|
230
232
|
Attributes:
|
|
@@ -242,7 +244,7 @@ class ShotItem(str, Enum):
|
|
|
242
244
|
BACKSIGHT_INCLINATION = "d"
|
|
243
245
|
|
|
244
246
|
|
|
245
|
-
class Severity(
|
|
247
|
+
class Severity(StrEnum):
|
|
246
248
|
"""Severity level for parse errors.
|
|
247
249
|
|
|
248
250
|
Attributes:
|
|
@@ -254,7 +256,7 @@ class Severity(str, Enum):
|
|
|
254
256
|
WARNING = "warning"
|
|
255
257
|
|
|
256
258
|
|
|
257
|
-
class DrawOperation(
|
|
259
|
+
class DrawOperation(StrEnum):
|
|
258
260
|
"""Drawing operations for plot commands.
|
|
259
261
|
|
|
260
262
|
Attributes:
|
|
@@ -266,7 +268,7 @@ class DrawOperation(str, Enum):
|
|
|
266
268
|
LINE_TO = "D"
|
|
267
269
|
|
|
268
270
|
|
|
269
|
-
class Datum(
|
|
271
|
+
class Datum(StrEnum):
|
|
270
272
|
"""Geodetic datum values supported by Compass.
|
|
271
273
|
|
|
272
274
|
These are the standard datum values that can be used in MAK project files.
|
|
@@ -322,6 +324,42 @@ class Datum(str, Enum):
|
|
|
322
324
|
WGS_1972 = "WGS 1972"
|
|
323
325
|
WGS_1984 = "WGS 1984"
|
|
324
326
|
|
|
327
|
+
def get_utm_epsg(self, zone: int, northern: bool) -> str:
|
|
328
|
+
"""Get the EPSG code for a UTM zone with this datum.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
zone: UTM zone number (1-60)
|
|
332
|
+
northern: True for northern hemisphere
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
EPSG code string (e.g., "EPSG:26717" for NAD27 UTM Zone 17N)
|
|
336
|
+
"""
|
|
337
|
+
zone = abs(zone)
|
|
338
|
+
|
|
339
|
+
match self:
|
|
340
|
+
case Datum.NORTH_AMERICAN_1927:
|
|
341
|
+
# NAD27 / UTM: EPSG:26701-26722 (zones 1-22 north)
|
|
342
|
+
return f"EPSG:{26700 + zone}"
|
|
343
|
+
|
|
344
|
+
case Datum.NORTH_AMERICAN_1983:
|
|
345
|
+
# NAD83 / UTM: EPSG:26901-26923 (zones 1-23 north)
|
|
346
|
+
return f"EPSG:{26900 + zone}"
|
|
347
|
+
|
|
348
|
+
case Datum.WGS_1972:
|
|
349
|
+
# WGS72 / UTM: EPSG:32201-32260 (north), EPSG:32301-32360 (south)
|
|
350
|
+
if northern:
|
|
351
|
+
return f"EPSG:{32200 + zone}"
|
|
352
|
+
return f"EPSG:{32300 + zone}"
|
|
353
|
+
|
|
354
|
+
case Datum.WGS_1984:
|
|
355
|
+
# WGS84 / UTM: EPSG:32601-32660 (north), EPSG:32701-32760 (south)
|
|
356
|
+
if northern:
|
|
357
|
+
return f"EPSG:{32600 + zone}"
|
|
358
|
+
return f"EPSG:{32700 + zone}"
|
|
359
|
+
|
|
360
|
+
case _:
|
|
361
|
+
raise NotImplementedError(f"This DATUM: `{self}` is not supported")
|
|
362
|
+
|
|
325
363
|
@classmethod
|
|
326
364
|
def normalize(cls, value: str | None) -> "Datum | None":
|
|
327
365
|
"""Normalize and validate a datum string to a Datum enum value.
|