compass-lib 0.0.8__tar.gz → 0.0.9__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.
Files changed (41) hide show
  1. compass_lib-0.0.9/PKG-INFO +107 -0
  2. compass_lib-0.0.9/README.md +59 -0
  3. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/__init__.py +1 -1
  4. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/constants.py +19 -0
  5. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/geojson.py +17 -12
  6. compass_lib-0.0.9/compass_lib/section_colors.py +104 -0
  7. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/survey/models.py +2 -0
  8. compass_lib-0.0.8/PKG-INFO +0 -63
  9. compass_lib-0.0.8/README.md +0 -15
  10. {compass_lib-0.0.8 → compass_lib-0.0.9}/LICENSE +0 -0
  11. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/commands/__init__.py +0 -0
  12. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/commands/convert.py +0 -0
  13. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/commands/encrypt.py +0 -0
  14. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/commands/geojson.py +0 -0
  15. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/commands/main.py +0 -0
  16. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/enums.py +0 -0
  17. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/errors.py +0 -0
  18. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/geo_utils.py +0 -0
  19. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/interface.py +0 -0
  20. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/io.py +0 -0
  21. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/models.py +0 -0
  22. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/plot/__init__.py +0 -0
  23. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/plot/models.py +0 -0
  24. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/plot/parser.py +0 -0
  25. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/project/__init__.py +0 -0
  26. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/project/format.py +0 -0
  27. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/project/models.py +0 -0
  28. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/project/parser.py +0 -0
  29. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/solver/__init__.py +0 -0
  30. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/solver/ariane.py +0 -0
  31. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/solver/base.py +0 -0
  32. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/solver/lse.py +0 -0
  33. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/solver/models.py +0 -0
  34. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/solver/noop.py +0 -0
  35. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/solver/proportional.py +0 -0
  36. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/solver/sparse.py +0 -0
  37. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/survey/__init__.py +0 -0
  38. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/survey/format.py +0 -0
  39. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/survey/parser.py +0 -0
  40. {compass_lib-0.0.8 → compass_lib-0.0.9}/compass_lib/validation.py +0 -0
  41. {compass_lib-0.0.8 → compass_lib-0.0.9}/pyproject.toml +0 -0
@@ -0,0 +1,107 @@
1
+ Metadata-Version: 2.5
2
+ Name: compass_lib
3
+ Version: 0.0.9
4
+ Summary: Compass Parser Library.
5
+ Keywords: cave,survey,karst
6
+ Author-email: Jonathan Dekhtiar <jonathan@dekhtiar.com>
7
+ Maintainer-email: Jonathan Dekhtiar <jonathan@dekhtiar.com>
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Intended Audience :: Information Technology
14
+ Classifier: Topic :: Software Development :: Build Tools
15
+ Classifier: Topic :: Scientific/Engineering
16
+ Classifier: Topic :: Software Development :: Libraries
17
+ Classifier: Topic :: Utilities
18
+ Classifier: License :: OSI Approved :: Apache Software License
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3 :: Only
22
+ License-File: LICENSE
23
+ Requires-Dist: geojson>=3.2,<4
24
+ Requires-Dist: numpy>=2.4.4,<3
25
+ Requires-Dist: scipy>=1.17.1,<2
26
+ Requires-Dist: orjson>=3.12,<4
27
+ Requires-Dist: pydantic>=2.13,<3
28
+ Requires-Dist: pydantic-extra-types>=2.11.1,<3
29
+ Requires-Dist: pyIGRF14>=1.0.4,<2
30
+ Requires-Dist: pyproj>=3.7.2,<4
31
+ Requires-Dist: shapely>=2.1.2,<3
32
+ Requires-Dist: utm>=0.8.1,<1
33
+ Requires-Dist: cryptography>=50.0.0,<51 ; extra == "test"
34
+ Requires-Dist: python-dotenv>=1.2.2,<2 ; extra == "test"
35
+ Requires-Dist: deepdiff>=7.0,<10 ; extra == "test"
36
+ Requires-Dist: pytest>=9.0.3,<10 ; extra == "test"
37
+ Requires-Dist: pytest-cov>=7.1.0,<8 ; extra == "test"
38
+ Requires-Dist: pytest-env>=1.6.0,<2 ; extra == "test"
39
+ Requires-Dist: pytest-runner>=6.0.1,<7 ; extra == "test"
40
+ Requires-Dist: pytest-ordering>=0.6,<1 ; extra == "test"
41
+ Requires-Dist: parameterized>=0.9.0,<1 ; extra == "test"
42
+ Project-URL: Bug Reports, https://github.com/OpenSpeleo/pytool_compass_lib/issues
43
+ Project-URL: Homepage, https://pypi.org/project/compass-lib/
44
+ Project-URL: Source, https://github.com/OpenSpeleo/pytool_compass_lib
45
+ Provides-Extra: test
46
+ Import-Name: compass_lib
47
+
48
+ # Compass Python Lib
49
+
50
+ ## Conversion commands:
51
+
52
+ ```bash
53
+ # Install in dev mod
54
+ pip install -e ".[dev,test]"
55
+
56
+ # Install latest stable version
57
+ pip install compass_lib
58
+
59
+ # run some commands
60
+ compass convert --input_file=./tests/artifacts/fulford.dat --output_file=fulford.json --format=json --overwrite
61
+ compass convert --input_file=./tests/artifacts/random.dat --output_file=random.json --format=json --overwrite
62
+ ```
63
+
64
+ ## GeoJSON section colors
65
+
66
+ GeoJSON survey legs include `properties.color`, an opaque CSS `#rrggbb` color.
67
+ Every shot in a DAT survey block receives the same generated section color.
68
+ Sections sharing a station have different colors, including across MAK-linked
69
+ DAT files. Names alone do not identify sections or station connections: the
70
+ existing MAK station-scoping rules remain authoritative. Geometric crossings
71
+ without a shared station do not create a color constraint.
72
+
73
+ The palette lives in `compass_lib/constants.py` as `SURVEY_COLORS`: vivid red,
74
+ orange, yellow, lime, green, mint, cyan, blue, purple, and hot pink. Both
75
+ palette colors and generated overflow colors have HSV saturation of at least 80%
76
+ and value of at least 90%, excluding black, white, gray, and muted shades.
77
+
78
+ Assignment uses ordinary random choices in at most 16 iterative passes, without
79
+ hashing, a fixed seed, or algorithm versioning. It stops on completion or no
80
+ improvement. Remaining sections receive distinct vibrant colors using a finite
81
+ fallback budget sized to the input, so reaching the pass limit does not leave
82
+ touching sections with the same viewer fallback color. Colors can change when
83
+ GeoJSON is regenerated and remain fixed in each stored artifact.
84
+
85
+ See [GeoJSON section coloring](docs/geojson-section-colors.md) for pass
86
+ semantics, fallback bounds, the color-space limit, export behavior, and test
87
+ coverage.
88
+
89
+ `CompassSurvey.color` is derived metadata assigned during coordinate
90
+ computation; it is excluded from source JSON and DAT/MAK serialization.
91
+ `SurveyLeg.color` carries it through coordinate propagation and adjustment.
92
+ Passage polygons and clipped passage fragments inherit their leg's color.
93
+ Station/anchor and misclosure styling retain their existing semantics.
94
+
95
+ The `color` property is independent of `color_by_origin` and CLI `--no-colors`,
96
+ which still control origin-based simplestyle `stroke`/`marker-color` styling.
97
+ Clients can use `color` for shot rendering and fall back to the survey color for
98
+ legacy data without it. Existing saved GeoJSON must be regenerated to gain these
99
+ properties; no source files are rewritten. Palette changes also require
100
+ regenerating stored GeoJSON; existing artifacts retain the colors recorded when
101
+ they were exported.
102
+
103
+ Portable regression coverage lives in `tests/test_section_colors.py`, including
104
+ duplicate names, linked/scoped stations, crowded junctions, solver paths, round
105
+ trips, CLI/API exports, vibrant colors, and safe budget exhaustion. Private
106
+ fixtures remain additional coverage and are never required for these guarantees.
107
+
@@ -0,0 +1,59 @@
1
+ # Compass Python Lib
2
+
3
+ ## Conversion commands:
4
+
5
+ ```bash
6
+ # Install in dev mod
7
+ pip install -e ".[dev,test]"
8
+
9
+ # Install latest stable version
10
+ pip install compass_lib
11
+
12
+ # run some commands
13
+ compass convert --input_file=./tests/artifacts/fulford.dat --output_file=fulford.json --format=json --overwrite
14
+ compass convert --input_file=./tests/artifacts/random.dat --output_file=random.json --format=json --overwrite
15
+ ```
16
+
17
+ ## GeoJSON section colors
18
+
19
+ GeoJSON survey legs include `properties.color`, an opaque CSS `#rrggbb` color.
20
+ Every shot in a DAT survey block receives the same generated section color.
21
+ Sections sharing a station have different colors, including across MAK-linked
22
+ DAT files. Names alone do not identify sections or station connections: the
23
+ existing MAK station-scoping rules remain authoritative. Geometric crossings
24
+ without a shared station do not create a color constraint.
25
+
26
+ The palette lives in `compass_lib/constants.py` as `SURVEY_COLORS`: vivid red,
27
+ orange, yellow, lime, green, mint, cyan, blue, purple, and hot pink. Both
28
+ palette colors and generated overflow colors have HSV saturation of at least 80%
29
+ and value of at least 90%, excluding black, white, gray, and muted shades.
30
+
31
+ Assignment uses ordinary random choices in at most 16 iterative passes, without
32
+ hashing, a fixed seed, or algorithm versioning. It stops on completion or no
33
+ improvement. Remaining sections receive distinct vibrant colors using a finite
34
+ fallback budget sized to the input, so reaching the pass limit does not leave
35
+ touching sections with the same viewer fallback color. Colors can change when
36
+ GeoJSON is regenerated and remain fixed in each stored artifact.
37
+
38
+ See [GeoJSON section coloring](docs/geojson-section-colors.md) for pass
39
+ semantics, fallback bounds, the color-space limit, export behavior, and test
40
+ coverage.
41
+
42
+ `CompassSurvey.color` is derived metadata assigned during coordinate
43
+ computation; it is excluded from source JSON and DAT/MAK serialization.
44
+ `SurveyLeg.color` carries it through coordinate propagation and adjustment.
45
+ Passage polygons and clipped passage fragments inherit their leg's color.
46
+ Station/anchor and misclosure styling retain their existing semantics.
47
+
48
+ The `color` property is independent of `color_by_origin` and CLI `--no-colors`,
49
+ which still control origin-based simplestyle `stroke`/`marker-color` styling.
50
+ Clients can use `color` for shot rendering and fall back to the survey color for
51
+ legacy data without it. Existing saved GeoJSON must be regenerated to gain these
52
+ properties; no source files are rewritten. Palette changes also require
53
+ regenerating stored GeoJSON; existing artifacts retain the colors recorded when
54
+ they were exported.
55
+
56
+ Portable regression coverage lives in `tests/test_section_colors.py`, including
57
+ duplicate names, linked/scoped stations, crowded junctions, solver paths, round
58
+ trips, CLI/API exports, vibrant colors, and safe budget exhaustion. Private
59
+ fixtures remain additional coverage and are never required for these guarantees.
@@ -21,7 +21,7 @@ Usage:
21
21
  directives = read_mak_file(Path("project.MAK"))
22
22
  """
23
23
 
24
- __version__ = "0.0.8"
24
+ __version__ = "0.0.9"
25
25
 
26
26
  # Constants
27
27
  from compass_lib.constants import COMPASS_ENCODING
@@ -15,6 +15,25 @@ COMPASS_ENCODING = "cp1252"
15
15
  #: Encoding used for JSON files
16
16
  JSON_ENCODING = "utf-8"
17
17
 
18
+ #: Bright, saturated palette shared by section colors and origin debug styling.
19
+ #: No black, white, gray, brown, or muted shades.
20
+ SURVEY_COLORS: tuple[str, ...] = (
21
+ "#ff1744", # vivid red
22
+ "#ff6d00", # bright orange
23
+ "#ffea00", # electric yellow
24
+ "#aaff00", # lime
25
+ "#00e676", # spring green
26
+ "#00ffb3", # bright mint
27
+ "#00e5ff", # cyan
28
+ "#2979ff", # electric blue
29
+ "#d500f9", # purple
30
+ "#ff00a8", # hot pink
31
+ )
32
+
33
+ #: HSV bounds also enforced when crowded junctions require additional colors.
34
+ SURVEY_COLOR_MIN_SATURATION: float = 0.8
35
+ SURVEY_COLOR_MIN_VALUE: float = 0.9
36
+
18
37
  #: Encoding used when reading raw Compass files (ASCII with replacements)
19
38
  ASCII_ENCODING = "ascii"
20
39
 
@@ -55,10 +55,12 @@ from compass_lib.constants import FEET_TO_METERS
55
55
  from compass_lib.constants import GEOJSON_COORDINATE_PRECISION
56
56
  from compass_lib.constants import JSON_ENCODING
57
57
  from compass_lib.constants import METERS_TO_FEET
58
+ from compass_lib.constants import SURVEY_COLORS
58
59
  from compass_lib.enums import Datum
59
60
  from compass_lib.geo_utils import GeoLocation
60
61
  from compass_lib.geo_utils import get_declination
61
62
  from compass_lib.io import load_project
63
+ from compass_lib.section_colors import assign_section_colors
62
64
  from compass_lib.solver.models import SurveyNetwork
63
65
 
64
66
  if TYPE_CHECKING:
@@ -139,6 +141,9 @@ class SurveyLeg:
139
141
  but measurement deltas do not).
140
142
  """
141
143
 
144
+ color: str | None = None
145
+ """Derived source-section color, independent of propagation origin."""
146
+
142
147
 
143
148
  @dataclass
144
149
  class MisclosureLeg:
@@ -185,18 +190,7 @@ class ComputedSurvey:
185
190
  #: stations can be visually distinguished by their propagation source.
186
191
  #: Viewers that support the simplestyle spec (geojson.io, GitHub, QGIS,
187
192
  #: Mapbox, …) will render these automatically.
188
- ORIGIN_COLORS: list[str] = [
189
- "#1f77b4", # blue
190
- "#ff7f0e", # orange
191
- "#2ca02c", # green
192
- "#d62728", # red
193
- "#9467bd", # purple
194
- "#8c564b", # brown
195
- "#e377c2", # pink
196
- "#7f7f7f", # grey
197
- "#bcbd22", # olive
198
- "#17becf", # cyan
199
- ]
193
+ ORIGIN_COLORS: list[str] = list(SURVEY_COLORS)
200
194
 
201
195
 
202
196
  # -----------------------------------------------------------------------------
@@ -757,6 +751,9 @@ def propagate_coordinates(
757
751
  Returns:
758
752
  ComputedSurvey with all computed stations and legs
759
753
  """
754
+ assign_section_colors(
755
+ project, ([edge[3] for edge in edges] for edges in adjacency.values())
756
+ )
760
757
  result = ComputedSurvey()
761
758
 
762
759
  # Set metadata
@@ -957,6 +954,7 @@ def propagate_coordinates(
957
954
  inclination=shot.frontsight_inclination,
958
955
  file=file_name,
959
956
  survey=survey_name,
957
+ color=survey.color,
960
958
  left=shot.left,
961
959
  right=shot.right,
962
960
  up=shot.up,
@@ -997,6 +995,7 @@ def propagate_coordinates(
997
995
  inclination=shot.frontsight_inclination,
998
996
  file=file_name,
999
997
  survey=survey_name,
998
+ color=survey.color,
1000
999
  left=shot.left,
1001
1000
  right=shot.right,
1002
1001
  up=shot.up,
@@ -1027,6 +1026,7 @@ def propagate_coordinates(
1027
1026
  inclination=shot.frontsight_inclination,
1028
1027
  file=file_name,
1029
1028
  survey=survey_name,
1029
+ color=survey.color,
1030
1030
  left=shot.left,
1031
1031
  right=shot.right,
1032
1032
  up=shot.up,
@@ -1240,6 +1240,7 @@ def propagate_coordinates(
1240
1240
  inclination=shot.frontsight_inclination,
1241
1241
  file=file_name,
1242
1242
  survey=survey_name,
1243
+ color=survey.color,
1243
1244
  left=shot.left,
1244
1245
  right=shot.right,
1245
1246
  up=shot.up,
@@ -1259,6 +1260,7 @@ def propagate_coordinates(
1259
1260
  inclination=shot.frontsight_inclination,
1260
1261
  file=file_name,
1261
1262
  survey=survey_name,
1263
+ color=survey.color,
1262
1264
  left=shot.left,
1263
1265
  right=shot.right,
1264
1266
  up=shot.up,
@@ -1415,6 +1417,7 @@ def propagate_coordinates(
1415
1417
  inclination=shot.frontsight_inclination,
1416
1418
  file=file_name,
1417
1419
  survey=survey_name,
1420
+ color=survey.color,
1418
1421
  left=shot.left,
1419
1422
  right=shot.right,
1420
1423
  up=shot.up,
@@ -1676,6 +1679,7 @@ def leg_to_feature(
1676
1679
  "id": str(uuid.uuid5(uuid.NAMESPACE_OID, leg.to_station.name)),
1677
1680
  "depth": abs(depth_ft), # Compass depth is < 0
1678
1681
  "name": leg.survey,
1682
+ **({"color": leg.color} if leg.color is not None else {}),
1679
1683
  },
1680
1684
  )
1681
1685
 
@@ -1886,6 +1890,7 @@ def passage_to_feature(
1886
1890
  ),
1887
1891
  properties={
1888
1892
  "type": "passage",
1893
+ **({"color": leg.color} if leg.color is not None else {}),
1889
1894
  "from": leg.from_station.name,
1890
1895
  "to": leg.to_station.name,
1891
1896
  "left_ft": leg.left,
@@ -0,0 +1,104 @@
1
+ """Bounded coloring passes respecting the computed station topology."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import random
7
+ from itertools import islice
8
+ from typing import TYPE_CHECKING
9
+
10
+ from compass_lib.constants import SURVEY_COLOR_MIN_SATURATION
11
+ from compass_lib.constants import SURVEY_COLOR_MIN_VALUE
12
+ from compass_lib.constants import SURVEY_COLORS
13
+
14
+ if TYPE_CHECKING:
15
+ from collections.abc import Iterable
16
+ from collections.abc import Iterator
17
+
18
+ from compass_lib.project.models import CompassMakFile
19
+ from compass_lib.survey.models import CompassSurvey
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+ MAX_COLORING_PASSES = 16
24
+ RGB_COLOR_COUNT = 1 << 24
25
+
26
+
27
+ def _additional_colors() -> Iterator[str]:
28
+ """Visit distinct RGB values, accepting only bright, saturated colors."""
29
+ for index in range(RGB_COLOR_COUNT):
30
+ # The odd multiplier visits every RGB value once without a growing set.
31
+ rgb = (0x68BDEB + index * 0x9E3779) % RGB_COLOR_COUNT
32
+ channels = ((rgb >> 16) & 255, (rgb >> 8) & 255, rgb & 255)
33
+ peak = max(channels)
34
+ if peak / 255 < SURVEY_COLOR_MIN_VALUE:
35
+ continue
36
+ saturation = (peak - min(channels)) / peak
37
+ if saturation >= SURVEY_COLOR_MIN_SATURATION:
38
+ yield f"#{rgb:06x}"
39
+
40
+
41
+ def assign_section_colors(
42
+ project: CompassMakFile,
43
+ station_sections: Iterable[Iterable[CompassSurvey]],
44
+ ) -> None:
45
+ """Try random palette assignments in bounded passes, then use vivid extras.
46
+
47
+ Each DAT survey block is a separate section, even when names repeat. The
48
+ existing station graph supplies connectivity, including MAK station scopes.
49
+ Only conflict-free candidates coloring more sections improve the assignment;
50
+ no-progress and pass-budget exhaustion lead to a bounded fallback.
51
+ """
52
+ sections = [
53
+ section
54
+ for directive in project.file_directives
55
+ if directive.data is not None
56
+ for section in directive.data.surveys
57
+ ]
58
+ section_indices = {id(section): index for index, section in enumerate(sections)}
59
+ neighbors: list[set[int]] = [set() for _ in sections]
60
+ for owners in station_sections:
61
+ indices = {section_indices[id(section)] for section in owners}
62
+ for index in indices:
63
+ neighbors[index].update(indices - {index})
64
+
65
+ order = sorted(range(len(sections)), key=lambda index: -len(neighbors[index]))
66
+ colors: dict[int, str] = {}
67
+ for _ in range(MAX_COLORING_PASSES):
68
+ candidate: dict[int, str] = {}
69
+ for index in order:
70
+ forbidden = {
71
+ candidate[other] for other in neighbors[index] if other in candidate
72
+ }
73
+ available = [color for color in SURVEY_COLORS if color not in forbidden]
74
+ if available:
75
+ candidate[index] = random.choice(available)
76
+ if len(candidate) <= len(colors):
77
+ break
78
+ colors = candidate
79
+ if len(colors) == len(sections):
80
+ break
81
+
82
+ # Finish unresolved sections with distinct bright colors. The generator is
83
+ # unique, so at most len(used) candidates can collide with assigned colors.
84
+ # This input-sized bound completes the fallback without an arbitrary cap
85
+ # leaving touching sections to render the same survey fallback color.
86
+ used = set(colors.values())
87
+ candidate_budget = len(sections) - len(colors) + len(used)
88
+ extras = iter(islice(_additional_colors(), candidate_budget))
89
+ for index in order:
90
+ if index in colors:
91
+ continue
92
+ color = next((value for value in extras if value not in used), None)
93
+ if color is None:
94
+ logger.warning(
95
+ "Vibrant RGB color space exhausted; %s sections use viewer fallback",
96
+ len(sections) - len(colors),
97
+ )
98
+ break
99
+ colors[index] = color
100
+ used.add(color)
101
+
102
+ for index, section in enumerate(sections):
103
+ # Omit unassigned colors instead of exporting a conflicting color.
104
+ section.color = colors.get(index)
@@ -100,6 +100,8 @@ class CompassSurvey(BaseModel):
100
100
 
101
101
  header: CompassSurveyHeader
102
102
  shots: list[CompassShot] = Field(default_factory=list)
103
+ # Derived project-wide display metadata, never written into source files.
104
+ color: str | None = Field(default=None, exclude=True)
103
105
 
104
106
 
105
107
  class CompassDatFile(BaseModel):
@@ -1,63 +0,0 @@
1
- Metadata-Version: 2.5
2
- Name: compass_lib
3
- Version: 0.0.8
4
- Summary: Compass Parser Library.
5
- Keywords: cave,survey,karst
6
- Author-email: Jonathan Dekhtiar <jonathan@dekhtiar.com>
7
- Maintainer-email: Jonathan Dekhtiar <jonathan@dekhtiar.com>
8
- Requires-Python: >=3.11
9
- Description-Content-Type: text/markdown
10
- Classifier: Development Status :: 3 - Alpha
11
- Classifier: Intended Audience :: Developers
12
- Classifier: Intended Audience :: Science/Research
13
- Classifier: Intended Audience :: Information Technology
14
- Classifier: Topic :: Software Development :: Build Tools
15
- Classifier: Topic :: Scientific/Engineering
16
- Classifier: Topic :: Software Development :: Libraries
17
- Classifier: Topic :: Utilities
18
- Classifier: License :: OSI Approved :: Apache Software License
19
- Classifier: Operating System :: OS Independent
20
- Classifier: Programming Language :: Python :: 3
21
- Classifier: Programming Language :: Python :: 3 :: Only
22
- License-File: LICENSE
23
- Requires-Dist: geojson>=3.2,<4
24
- Requires-Dist: numpy>=2.4.4,<3
25
- Requires-Dist: scipy>=1.17.1,<2
26
- Requires-Dist: orjson>=3.12,<4
27
- Requires-Dist: pydantic>=2.13,<3
28
- Requires-Dist: pydantic-extra-types>=2.11.1,<3
29
- Requires-Dist: pyIGRF14>=1.0.4,<2
30
- Requires-Dist: pyproj>=3.7.2,<4
31
- Requires-Dist: shapely>=2.1.2,<3
32
- Requires-Dist: utm>=0.8.1,<1
33
- Requires-Dist: cryptography>=50.0.0,<51 ; extra == "test"
34
- Requires-Dist: python-dotenv>=1.2.2,<2 ; extra == "test"
35
- Requires-Dist: deepdiff>=7.0,<10 ; extra == "test"
36
- Requires-Dist: pytest>=9.0.3,<10 ; extra == "test"
37
- Requires-Dist: pytest-cov>=7.1.0,<8 ; extra == "test"
38
- Requires-Dist: pytest-env>=1.6.0,<2 ; extra == "test"
39
- Requires-Dist: pytest-runner>=6.0.1,<7 ; extra == "test"
40
- Requires-Dist: pytest-ordering>=0.6,<1 ; extra == "test"
41
- Requires-Dist: parameterized>=0.9.0,<1 ; extra == "test"
42
- Project-URL: Bug Reports, https://github.com/OpenSpeleo/pytool_compass_lib/issues
43
- Project-URL: Homepage, https://pypi.org/project/compass-lib/
44
- Project-URL: Source, https://github.com/OpenSpeleo/pytool_compass_lib
45
- Provides-Extra: test
46
- Import-Name: compass_lib
47
-
48
- # Compass Python Lib
49
-
50
- ## Conversion commands:
51
-
52
- ```bash
53
- # Install in dev mod
54
- pip install -e ".[dev,test]"
55
-
56
- # Install latest stable version
57
- pip install compass_lib
58
-
59
- # run some commands
60
- compass convert --input_file=./tests/artifacts/fulford.dat --output_file=fulford.json --format=json --overwrite
61
- compass convert --input_file=./tests/artifacts/random.dat --output_file=random.json --format=json --overwrite
62
- ```
63
-
@@ -1,15 +0,0 @@
1
- # Compass Python Lib
2
-
3
- ## Conversion commands:
4
-
5
- ```bash
6
- # Install in dev mod
7
- pip install -e ".[dev,test]"
8
-
9
- # Install latest stable version
10
- pip install compass_lib
11
-
12
- # run some commands
13
- compass convert --input_file=./tests/artifacts/fulford.dat --output_file=fulford.json --format=json --overwrite
14
- compass convert --input_file=./tests/artifacts/random.dat --output_file=random.json --format=json --overwrite
15
- ```
File without changes
File without changes