compass-lib 0.0.2__py3-none-any.whl → 0.0.3__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.
- compass_lib/__init__.py +113 -3
- compass_lib/commands/__init__.py +2 -0
- compass_lib/commands/convert.py +223 -36
- compass_lib/commands/encrypt.py +33 -7
- compass_lib/commands/geojson.py +118 -0
- compass_lib/commands/main.py +1 -1
- compass_lib/constants.py +84 -36
- compass_lib/enums.py +292 -84
- compass_lib/errors.py +86 -0
- compass_lib/geo_utils.py +47 -0
- compass_lib/geojson.py +1024 -0
- compass_lib/interface.py +332 -0
- compass_lib/io.py +246 -0
- compass_lib/models.py +217 -95
- compass_lib/plot/__init__.py +28 -0
- compass_lib/plot/models.py +265 -0
- compass_lib/plot/parser.py +610 -0
- compass_lib/project/__init__.py +36 -0
- compass_lib/project/format.py +158 -0
- compass_lib/project/models.py +494 -0
- compass_lib/project/parser.py +638 -0
- compass_lib/survey/__init__.py +24 -0
- compass_lib/survey/format.py +284 -0
- compass_lib/survey/models.py +160 -0
- compass_lib/survey/parser.py +842 -0
- compass_lib/validation.py +74 -0
- {compass_lib-0.0.2.dist-info → compass_lib-0.0.3.dist-info}/METADATA +8 -11
- compass_lib-0.0.3.dist-info/RECORD +31 -0
- {compass_lib-0.0.2.dist-info → compass_lib-0.0.3.dist-info}/entry_points.txt +2 -1
- compass_lib/encoding.py +0 -27
- compass_lib/parser.py +0 -435
- compass_lib/utils.py +0 -15
- compass_lib-0.0.2.dist-info/RECORD +0 -16
- {compass_lib-0.0.2.dist-info → compass_lib-0.0.3.dist-info}/WHEEL +0 -0
- {compass_lib-0.0.2.dist-info → compass_lib-0.0.3.dist-info}/licenses/LICENSE +0 -0
compass_lib/constants.py
CHANGED
|
@@ -1,36 +1,84 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Constants used throughout the compass_lib library.
|
|
3
|
+
|
|
4
|
+
This module centralizes all constant values to ensure consistency
|
|
5
|
+
and avoid magic numbers/strings scattered across the codebase.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# -----------------------------------------------------------------------------
|
|
9
|
+
# File Encodings
|
|
10
|
+
# -----------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
#: Default encoding for Compass files (Windows-1252 / CP1252)
|
|
13
|
+
COMPASS_ENCODING = "cp1252"
|
|
14
|
+
|
|
15
|
+
#: Encoding used for JSON files
|
|
16
|
+
JSON_ENCODING = "utf-8"
|
|
17
|
+
|
|
18
|
+
#: Encoding used when reading raw Compass files (ASCII with replacements)
|
|
19
|
+
ASCII_ENCODING = "ascii"
|
|
20
|
+
|
|
21
|
+
# -----------------------------------------------------------------------------
|
|
22
|
+
# Unit Conversions
|
|
23
|
+
# -----------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
#: Conversion factor from feet to meters
|
|
26
|
+
FEET_TO_METERS: float = 0.3048
|
|
27
|
+
|
|
28
|
+
#: Conversion factor from meters to feet
|
|
29
|
+
METERS_TO_FEET: float = 1.0 / FEET_TO_METERS
|
|
30
|
+
|
|
31
|
+
# -----------------------------------------------------------------------------
|
|
32
|
+
# Missing Data Indicators
|
|
33
|
+
# -----------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
#: Values >= this threshold indicate missing data for distances/measurements
|
|
36
|
+
MISSING_VALUE_THRESHOLD: float = 990.0
|
|
37
|
+
|
|
38
|
+
#: Values <= this threshold indicate missing data for angles
|
|
39
|
+
MISSING_ANGLE_THRESHOLD: float = -900.0
|
|
40
|
+
|
|
41
|
+
#: String representation of missing value in formatted output
|
|
42
|
+
MISSING_VALUE_STRING: str = "-999.00"
|
|
43
|
+
|
|
44
|
+
#: Null LRUD values used in PLT files (either 999.0 or 999.9 indicates missing)
|
|
45
|
+
NULL_LRUD_VALUES: tuple[float, float] = (999.0, 999.9)
|
|
46
|
+
|
|
47
|
+
# -----------------------------------------------------------------------------
|
|
48
|
+
# Formatting Constants
|
|
49
|
+
# -----------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
#: Width of station name column in DAT files
|
|
52
|
+
STATION_NAME_WIDTH: int = 13
|
|
53
|
+
|
|
54
|
+
#: Width of numeric columns in DAT files
|
|
55
|
+
NUMBER_WIDTH: int = 8
|
|
56
|
+
|
|
57
|
+
#: Decimal precision for GeoJSON coordinates (WGS84)
|
|
58
|
+
GEOJSON_COORDINATE_PRECISION: int = 7
|
|
59
|
+
|
|
60
|
+
#: Decimal precision for elevation values in GeoJSON
|
|
61
|
+
GEOJSON_ELEVATION_PRECISION: int = 2
|
|
62
|
+
|
|
63
|
+
# -----------------------------------------------------------------------------
|
|
64
|
+
# Shot Flag Characters
|
|
65
|
+
# -----------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
#: Mapping of shot flags to their character representations
|
|
68
|
+
FLAG_CHARS: dict[str, str] = {
|
|
69
|
+
"exclude_distance": "L",
|
|
70
|
+
"exclude_from_plotting": "P",
|
|
71
|
+
"exclude_from_all_processing": "X",
|
|
72
|
+
"do_not_adjust": "C",
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# -----------------------------------------------------------------------------
|
|
76
|
+
# UTM Constants
|
|
77
|
+
# -----------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
#: Southern hemisphere UTM northing offset (10 million meters)
|
|
80
|
+
#: Note: This constant represents the false northing added to southern hemisphere
|
|
81
|
+
#: UTM coordinates. However, in Compass, hemisphere is determined by the ZONE SIGN
|
|
82
|
+
#: (positive = north, negative = south), NOT by comparing northing to this threshold.
|
|
83
|
+
#: This constant is kept for reference and potential future use.
|
|
84
|
+
UTM_SOUTHERN_HEMISPHERE_OFFSET: float = 10_000_000.0
|
compass_lib/enums.py
CHANGED
|
@@ -1,119 +1,240 @@
|
|
|
1
|
-
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Enumerations for Compass file formats.
|
|
3
|
+
|
|
4
|
+
This module contains all enumerations used in Compass survey data formats,
|
|
5
|
+
including units for measurements, file types, and various classification types.
|
|
6
|
+
"""
|
|
2
7
|
|
|
3
8
|
from enum import Enum
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from typing import TYPE_CHECKING
|
|
9
|
+
from math import radians
|
|
10
|
+
from math import tan
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
from typing_extensions import Self
|
|
12
|
+
from compass_lib.constants import FEET_TO_METERS
|
|
10
13
|
|
|
11
14
|
|
|
12
|
-
class
|
|
13
|
-
|
|
14
|
-
def reverse(cls, name):
|
|
15
|
-
return cls._value2member_map_[name]
|
|
15
|
+
class FileFormat(str, Enum):
|
|
16
|
+
"""File format types for conversion operations.
|
|
16
17
|
|
|
18
|
+
Attributes:
|
|
19
|
+
COMPASS: Native Compass binary/text format (.dat, .mak, .plt)
|
|
20
|
+
JSON: JSON serialization format
|
|
21
|
+
GEOJSON: GeoJSON geographic format
|
|
22
|
+
"""
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
PLT = 2
|
|
24
|
+
COMPASS = "compass"
|
|
25
|
+
JSON = "json"
|
|
26
|
+
GEOJSON = "geojson"
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
class CompassFileType(str, Enum):
|
|
30
|
+
"""Types of Compass files.
|
|
31
|
+
|
|
32
|
+
Attributes:
|
|
33
|
+
DAT: Survey data file containing shots
|
|
34
|
+
MAK: Project/make file linking DAT files
|
|
35
|
+
PLT: Plot file with processed survey data
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
DAT = "dat"
|
|
39
|
+
MAK = "mak"
|
|
40
|
+
PLT = "plt"
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def extension(self) -> str:
|
|
44
|
+
"""Get the file extension for this type (with dot)."""
|
|
45
|
+
return {
|
|
46
|
+
CompassFileType.DAT: FileExtension.DAT.value,
|
|
47
|
+
CompassFileType.MAK: FileExtension.MAK.value,
|
|
48
|
+
CompassFileType.PLT: FileExtension.PLT.value,
|
|
49
|
+
}[self]
|
|
29
50
|
|
|
30
51
|
@classmethod
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
52
|
+
def from_extension(cls, ext: str) -> "CompassFileType | None":
|
|
53
|
+
"""Get file type from extension.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
ext: File extension (with or without dot, case-insensitive)
|
|
34
57
|
|
|
35
|
-
|
|
58
|
+
Returns:
|
|
59
|
+
CompassFileType or None if not recognized
|
|
60
|
+
"""
|
|
61
|
+
ext_lower = ext.lower().lstrip(".")
|
|
62
|
+
mapping = {
|
|
63
|
+
"dat": cls.DAT,
|
|
64
|
+
"mak": cls.MAK,
|
|
65
|
+
"plt": cls.PLT,
|
|
66
|
+
}
|
|
67
|
+
return mapping.get(ext_lower)
|
|
36
68
|
|
|
37
69
|
|
|
38
|
-
|
|
70
|
+
class FileExtension(str, Enum):
|
|
71
|
+
"""File extensions for various file formats (with dot).
|
|
39
72
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
73
|
+
Attributes:
|
|
74
|
+
DAT: Compass survey data file extension
|
|
75
|
+
MAK: Compass project/make file extension
|
|
76
|
+
PLT: Compass plot file extension
|
|
77
|
+
JSON: JSON file extension
|
|
78
|
+
GEOJSON: GeoJSON file extension
|
|
79
|
+
"""
|
|
45
80
|
|
|
81
|
+
DAT = ".dat"
|
|
82
|
+
MAK = ".mak"
|
|
83
|
+
PLT = ".plt"
|
|
84
|
+
JSON = ".json"
|
|
85
|
+
GEOJSON = ".geojson"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class FormatIdentifier(str, Enum):
|
|
89
|
+
"""Format identifiers used in JSON files.
|
|
90
|
+
|
|
91
|
+
Attributes:
|
|
92
|
+
COMPASS_DAT: Format identifier for DAT files in JSON
|
|
93
|
+
COMPASS_MAK: Format identifier for MAK/project files in JSON
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
COMPASS_DAT = "compass_dat"
|
|
97
|
+
COMPASS_MAK = "compass_mak"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class AzimuthUnit(str, Enum):
|
|
101
|
+
"""Unit for compass azimuth (bearing) measurements.
|
|
102
|
+
|
|
103
|
+
Attributes:
|
|
104
|
+
DEGREES: Standard degrees (0-360)
|
|
105
|
+
QUADS: Quadrant notation
|
|
106
|
+
GRADS: Gradians (400 per circle)
|
|
107
|
+
"""
|
|
46
108
|
|
|
47
|
-
class AzimuthUnits(CustomEnum):
|
|
48
109
|
DEGREES = "D"
|
|
49
110
|
QUADS = "Q"
|
|
50
|
-
|
|
111
|
+
GRADS = "R"
|
|
112
|
+
|
|
113
|
+
@staticmethod
|
|
114
|
+
def convert(degrees: float | None, to_unit: "AzimuthUnit") -> float | None:
|
|
115
|
+
"""Convert degrees to the target unit.
|
|
51
116
|
|
|
117
|
+
Args:
|
|
118
|
+
degrees: Value in degrees (or None)
|
|
119
|
+
to_unit: Target unit to convert to
|
|
52
120
|
|
|
53
|
-
|
|
121
|
+
Returns:
|
|
122
|
+
Converted value or None if input is None
|
|
123
|
+
"""
|
|
124
|
+
if degrees is None:
|
|
125
|
+
return None
|
|
126
|
+
if to_unit == AzimuthUnit.GRADS:
|
|
127
|
+
return degrees * 400 / 360
|
|
128
|
+
return degrees
|
|
54
129
|
|
|
55
|
-
# export const inclinationUnits: { [string]: DisplayInclinationUnit } = {
|
|
56
|
-
# D: 'degrees',
|
|
57
|
-
# G: 'percentGrade',
|
|
58
|
-
# M: 'degreesAndMinutes',
|
|
59
|
-
# R: 'gradians',
|
|
60
|
-
# W: 'depthGauge',
|
|
61
|
-
# }
|
|
62
130
|
|
|
131
|
+
class InclinationUnit(str, Enum):
|
|
132
|
+
"""Unit for vertical angle (inclination) measurements.
|
|
133
|
+
|
|
134
|
+
Attributes:
|
|
135
|
+
DEGREES: Standard degrees (-90 to +90)
|
|
136
|
+
PERCENT_GRADE: Percentage gradient (tan(angle) * 100)
|
|
137
|
+
DEGREES_AND_MINUTES: Degrees with minutes notation
|
|
138
|
+
GRADS: Gradians
|
|
139
|
+
DEPTH_GAUGE: Depth gauge reading
|
|
140
|
+
"""
|
|
63
141
|
|
|
64
|
-
class InclinationUnits(CustomEnum):
|
|
65
142
|
DEGREES = "D"
|
|
66
143
|
PERCENT_GRADE = "G"
|
|
67
144
|
DEGREES_AND_MINUTES = "M"
|
|
68
|
-
|
|
145
|
+
GRADS = "R"
|
|
69
146
|
DEPTH_GAUGE = "W"
|
|
70
147
|
|
|
148
|
+
@staticmethod
|
|
149
|
+
def convert(value: float | None, to_unit: "InclinationUnit") -> float | None:
|
|
150
|
+
"""Convert degrees to the target unit.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
value: Value in degrees (or None)
|
|
154
|
+
to_unit: Target unit to convert to
|
|
71
155
|
|
|
72
|
-
|
|
156
|
+
Returns:
|
|
157
|
+
Converted value or None if input is None
|
|
158
|
+
"""
|
|
159
|
+
if value is None:
|
|
160
|
+
return None
|
|
161
|
+
if to_unit == InclinationUnit.PERCENT_GRADE:
|
|
162
|
+
return tan(radians(value)) * 100
|
|
163
|
+
if to_unit == InclinationUnit.GRADS:
|
|
164
|
+
return value * 200 / 180
|
|
165
|
+
return value
|
|
73
166
|
|
|
74
167
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# I: 'feetAndInches',
|
|
78
|
-
# M: 'meters',
|
|
79
|
-
# }
|
|
168
|
+
class LengthUnit(str, Enum):
|
|
169
|
+
"""Unit for distance measurements.
|
|
80
170
|
|
|
171
|
+
Attributes:
|
|
172
|
+
DECIMAL_FEET: Standard feet with decimals
|
|
173
|
+
FEET_AND_INCHES: Feet and inches notation
|
|
174
|
+
METERS: Metric meters
|
|
175
|
+
"""
|
|
81
176
|
|
|
82
|
-
class LengthUnits(CustomEnum):
|
|
83
177
|
DECIMAL_FEET = "D"
|
|
84
178
|
FEET_AND_INCHES = "I"
|
|
85
179
|
METERS = "M"
|
|
86
180
|
|
|
181
|
+
@staticmethod
|
|
182
|
+
def convert(feet: float | None, to_unit: "LengthUnit") -> float | None:
|
|
183
|
+
"""Convert feet to the target unit.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
feet: Value in feet (or None)
|
|
187
|
+
to_unit: Target unit to convert to
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
Converted value or None if input is None
|
|
191
|
+
"""
|
|
192
|
+
if feet is None:
|
|
193
|
+
return None
|
|
194
|
+
if to_unit == LengthUnit.METERS:
|
|
195
|
+
return feet * FEET_TO_METERS
|
|
196
|
+
return feet
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class LrudAssociation(str, Enum):
|
|
200
|
+
"""Indicates which station LRUD measurements are associated with.
|
|
201
|
+
|
|
202
|
+
Attributes:
|
|
203
|
+
FROM: LRUD measured at the FROM station
|
|
204
|
+
TO: LRUD measured at the TO station
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
FROM = "F"
|
|
208
|
+
TO = "T"
|
|
87
209
|
|
|
88
|
-
# ============================== LRUD ============================== #
|
|
89
210
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# R: 'right',
|
|
93
|
-
# U: 'up',
|
|
94
|
-
# D: 'down',
|
|
95
|
-
# }
|
|
211
|
+
class LrudItem(str, Enum):
|
|
212
|
+
"""Individual LRUD dimension identifiers.
|
|
96
213
|
|
|
214
|
+
Attributes:
|
|
215
|
+
LEFT: Distance to left wall
|
|
216
|
+
RIGHT: Distance to right wall
|
|
217
|
+
UP: Distance to ceiling
|
|
218
|
+
DOWN: Distance to floor
|
|
219
|
+
"""
|
|
97
220
|
|
|
98
|
-
class LRUD(CustomEnum):
|
|
99
221
|
LEFT = "L"
|
|
100
222
|
RIGHT = "R"
|
|
101
223
|
UP = "U"
|
|
102
224
|
DOWN = "D"
|
|
103
225
|
|
|
104
226
|
|
|
105
|
-
|
|
227
|
+
class ShotItem(str, Enum):
|
|
228
|
+
"""Components of a shot measurement for format ordering.
|
|
106
229
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
230
|
+
Attributes:
|
|
231
|
+
LENGTH: Distance between stations
|
|
232
|
+
FRONTSIGHT_AZIMUTH: Compass bearing forward
|
|
233
|
+
FRONTSIGHT_INCLINATION: Vertical angle forward
|
|
234
|
+
BACKSIGHT_AZIMUTH: Compass bearing backward
|
|
235
|
+
BACKSIGHT_INCLINATION: Vertical angle backward
|
|
236
|
+
"""
|
|
114
237
|
|
|
115
|
-
|
|
116
|
-
class ShotItem(CustomEnum):
|
|
117
238
|
LENGTH = "L"
|
|
118
239
|
FRONTSIGHT_AZIMUTH = "A"
|
|
119
240
|
FRONTSIGHT_INCLINATION = "D"
|
|
@@ -121,28 +242,115 @@ class ShotItem(CustomEnum):
|
|
|
121
242
|
BACKSIGHT_INCLINATION = "d"
|
|
122
243
|
|
|
123
244
|
|
|
124
|
-
|
|
245
|
+
class Severity(str, Enum):
|
|
246
|
+
"""Severity level for parse errors.
|
|
247
|
+
|
|
248
|
+
Attributes:
|
|
249
|
+
ERROR: Critical parsing error
|
|
250
|
+
WARNING: Non-fatal warning
|
|
251
|
+
"""
|
|
252
|
+
|
|
253
|
+
ERROR = "error"
|
|
254
|
+
WARNING = "warning"
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class DrawOperation(str, Enum):
|
|
258
|
+
"""Drawing operations for plot commands.
|
|
259
|
+
|
|
260
|
+
Attributes:
|
|
261
|
+
MOVE_TO: Move to location without drawing
|
|
262
|
+
LINE_TO: Draw line to location
|
|
263
|
+
"""
|
|
264
|
+
|
|
265
|
+
MOVE_TO = "M"
|
|
266
|
+
LINE_TO = "D"
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class Datum(str, Enum):
|
|
270
|
+
"""Geodetic datum values supported by Compass.
|
|
271
|
+
|
|
272
|
+
These are the standard datum values that can be used in MAK project files.
|
|
273
|
+
The enum values match the exact strings used in Compass MAK files.
|
|
274
|
+
|
|
275
|
+
Attributes:
|
|
276
|
+
ADINDAN: Adindan datum
|
|
277
|
+
ARC_1950: Arc 1950 datum
|
|
278
|
+
ARC_1960: Arc 1960 datum
|
|
279
|
+
AUSTRALIAN_1966: Australian 1966 datum
|
|
280
|
+
AUSTRALIAN_1984: Australian 1984 datum
|
|
281
|
+
CAMP_AREA_ASTRO: Camp Area Astro datum
|
|
282
|
+
CAPE: Cape datum
|
|
283
|
+
EUROPEAN_1950: European 1950 datum
|
|
284
|
+
EUROPEAN_1979: European 1979 datum
|
|
285
|
+
GEODETIC_1949: Geodetic 1949 datum
|
|
286
|
+
HONG_KONG_1963: Hong Kong 1963 datum
|
|
287
|
+
HU_TZU_SHAN: Hu Tzu Shan datum
|
|
288
|
+
INDIAN: Indian datum
|
|
289
|
+
NORTH_AMERICAN_1927: North American 1927 datum (NAD27)
|
|
290
|
+
NORTH_AMERICAN_1983: North American 1983 datum (NAD83)
|
|
291
|
+
OMAN: Oman datum
|
|
292
|
+
ORDNANCE_SURVEY_1936: Ordnance Survey 1936 datum
|
|
293
|
+
PULKOVO_1942: Pulkovo 1942 datum
|
|
294
|
+
SOUTH_AMERICAN_1956: South American 1956 datum
|
|
295
|
+
SOUTH_AMERICAN_1969: South American 1969 datum
|
|
296
|
+
TOKYO: Tokyo datum
|
|
297
|
+
WGS_1972: WGS 1972 datum
|
|
298
|
+
WGS_1984: WGS 1984 datum
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
ADINDAN = "Adindan"
|
|
302
|
+
ARC_1950 = "Arc 1950"
|
|
303
|
+
ARC_1960 = "Arc 1960"
|
|
304
|
+
AUSTRALIAN_1966 = "Australian 1966"
|
|
305
|
+
AUSTRALIAN_1984 = "Australian 1984"
|
|
306
|
+
CAMP_AREA_ASTRO = "Camp Area Astro"
|
|
307
|
+
CAPE = "Cape"
|
|
308
|
+
EUROPEAN_1950 = "European 1950"
|
|
309
|
+
EUROPEAN_1979 = "European 1979"
|
|
310
|
+
GEODETIC_1949 = "Geodetic 1949"
|
|
311
|
+
HONG_KONG_1963 = "Hong Kong 1963"
|
|
312
|
+
HU_TZU_SHAN = "Hu Tzu Shan"
|
|
313
|
+
INDIAN = "Indian"
|
|
314
|
+
NORTH_AMERICAN_1927 = "North American 1927"
|
|
315
|
+
NORTH_AMERICAN_1983 = "North American 1983"
|
|
316
|
+
OMAN = "Oman"
|
|
317
|
+
ORDNANCE_SURVEY_1936 = "Ordnance Survey 1936"
|
|
318
|
+
PULKOVO_1942 = "Pulkovo 1942"
|
|
319
|
+
SOUTH_AMERICAN_1956 = "South American 1956"
|
|
320
|
+
SOUTH_AMERICAN_1969 = "South American 1969"
|
|
321
|
+
TOKYO = "Tokyo"
|
|
322
|
+
WGS_1972 = "WGS 1972"
|
|
323
|
+
WGS_1984 = "WGS 1984"
|
|
324
|
+
|
|
325
|
+
@classmethod
|
|
326
|
+
def normalize(cls, value: str | None) -> "Datum | None":
|
|
327
|
+
"""Normalize and validate a datum string to a Datum enum value.
|
|
125
328
|
|
|
126
|
-
|
|
127
|
-
# F: 'from',
|
|
128
|
-
# T: 'to',
|
|
129
|
-
# }
|
|
329
|
+
Performs case-insensitive matching with whitespace normalization.
|
|
130
330
|
|
|
331
|
+
Args:
|
|
332
|
+
value: The datum string to normalize (case-insensitive)
|
|
131
333
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
TO = "T"
|
|
334
|
+
Returns:
|
|
335
|
+
The corresponding Datum enum value, or None if value is None
|
|
135
336
|
|
|
337
|
+
Raises:
|
|
338
|
+
ValueError: If the datum string is not recognized
|
|
339
|
+
"""
|
|
340
|
+
if value is None:
|
|
341
|
+
return None
|
|
136
342
|
|
|
137
|
-
#
|
|
343
|
+
# Normalize: lowercase, strip whitespace, collapse multiple spaces
|
|
344
|
+
normalized = " ".join(value.strip().lower().split())
|
|
138
345
|
|
|
346
|
+
# Match against enum values (case-insensitive)
|
|
347
|
+
for datum in cls:
|
|
348
|
+
if datum.value.lower() == normalized:
|
|
349
|
+
return datum
|
|
139
350
|
|
|
140
|
-
|
|
141
|
-
EXCLUDE_PLOTING = "P"
|
|
142
|
-
EXCLUDE_CLOSURE = "C"
|
|
143
|
-
EXCLUDE_LENGTH = "L"
|
|
144
|
-
TOTAL_EXCLUSION = "X"
|
|
145
|
-
SPLAY = "S"
|
|
351
|
+
raise ValueError(f"Unknown datum: {value!r}")
|
|
146
352
|
|
|
147
|
-
|
|
148
|
-
|
|
353
|
+
@classmethod
|
|
354
|
+
def from_string(cls, value: str | None) -> "Datum | None":
|
|
355
|
+
"""Alias for normalize() for backwards compatibility."""
|
|
356
|
+
return cls.normalize(value)
|
compass_lib/errors.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Error handling for Compass file parsing.
|
|
3
|
+
|
|
4
|
+
This module provides error classes for tracking parsing errors with
|
|
5
|
+
source location information for helpful error messages.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
from compass_lib.enums import Severity
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class SourceLocation:
|
|
15
|
+
"""Tracks the source location of text for error reporting.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
source: The source file name or identifier
|
|
19
|
+
line: Line number (0-based)
|
|
20
|
+
column: Column number (0-based)
|
|
21
|
+
text: The text at this location
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
source: str
|
|
25
|
+
line: int
|
|
26
|
+
column: int
|
|
27
|
+
text: str
|
|
28
|
+
|
|
29
|
+
def __str__(self) -> str:
|
|
30
|
+
"""Format as human-readable location string."""
|
|
31
|
+
return f"(in {self.source}, line {self.line + 1}, column {self.column + 1})"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True)
|
|
35
|
+
class CompassParseError:
|
|
36
|
+
"""Represents a parsing error or warning with source location.
|
|
37
|
+
|
|
38
|
+
This is a data record for storing error information, not an exception.
|
|
39
|
+
Use CompassParseException for raising errors.
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
severity: ERROR or WARNING
|
|
43
|
+
message: Human-readable error message
|
|
44
|
+
location: Source location where error occurred (optional)
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
severity: Severity
|
|
48
|
+
message: str
|
|
49
|
+
location: SourceLocation | None = None
|
|
50
|
+
|
|
51
|
+
def __str__(self) -> str:
|
|
52
|
+
"""Format as human-readable error string."""
|
|
53
|
+
base = f"{self.severity.value}: {self.message}"
|
|
54
|
+
if self.location:
|
|
55
|
+
base += f" {self.location}"
|
|
56
|
+
if self.location.text:
|
|
57
|
+
base += f"\n {self.location.text}"
|
|
58
|
+
return base
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class CompassParseException(Exception): # noqa: N818
|
|
62
|
+
"""Exception raised for critical parsing errors.
|
|
63
|
+
|
|
64
|
+
Attributes:
|
|
65
|
+
message: Error message
|
|
66
|
+
location: Source location where error occurred
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(self, message: str, location: SourceLocation | None = None):
|
|
70
|
+
self.message = message
|
|
71
|
+
self.location = location
|
|
72
|
+
super().__init__(str(self))
|
|
73
|
+
|
|
74
|
+
def __str__(self) -> str:
|
|
75
|
+
"""Format as human-readable exception string."""
|
|
76
|
+
if self.location:
|
|
77
|
+
return f"{self.message} {self.location}"
|
|
78
|
+
return self.message
|
|
79
|
+
|
|
80
|
+
def to_error(self) -> CompassParseError:
|
|
81
|
+
"""Convert exception to CompassParseError record."""
|
|
82
|
+
return CompassParseError(
|
|
83
|
+
severity=Severity.ERROR,
|
|
84
|
+
message=self.message,
|
|
85
|
+
location=self.location,
|
|
86
|
+
)
|