Skip to content

Commit 5182e7b

Browse files
committed
[stn] added resection calc and station upload commands
1 parent 25d8f24 commit 5182e7b

File tree

6 files changed

+250
-4
lines changed

6 files changed

+250
-4
lines changed

src/instrumentman/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from . import terminal
1010
from . import setup
1111
from . import setmeasurement
12+
from . import resection
1213
from . import protocoltest
1314
from . import inclination
1415
from . import filetransfer
@@ -77,6 +78,7 @@ def cli_upload() -> None:
7778
cli_measure.add_command(inclination.cli_measure)
7879
cli_calc.add_command(setmeasurement.cli_calc)
7980
cli_calc.add_command(inclination.cli_calc)
81+
cli_calc.add_command(resection.cli_calc)
8082
cli_test.add_command(protocoltest.cli_geocom)
8183
cli_test.add_command(protocoltest.cli_gsidna)
8284
cli_merge.add_command(setmeasurement.cli_merge)
@@ -91,3 +93,4 @@ def cli_upload() -> None:
9193
cli_download.add_command(settings.cli_download)
9294
cli_upload.add_command(datatransfer.cli_upload)
9395
cli_upload.add_command(settings.cli_upload)
96+
cli_upload.add_command(resection.cli_upload)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from typing import Any
2+
3+
from click_extra import (
4+
extra_command,
5+
argument,
6+
option,
7+
file_path
8+
)
9+
10+
from ..utils import (
11+
com_port_argument,
12+
com_option_group,
13+
Angle
14+
)
15+
16+
17+
@extra_command(
18+
"station",
19+
params=None,
20+
context_settings={"auto_envvar_prefix": None}
21+
) # type: ignore[misc]
22+
@argument(
23+
"measurements",
24+
help="input session file to process",
25+
type=file_path(exists=True)
26+
)
27+
@argument(
28+
"targets",
29+
type=file_path(exists=True),
30+
help="JSON file containing target definitions"
31+
)
32+
@argument(
33+
"output",
34+
help="output JSON file",
35+
type=file_path(readable=False)
36+
)
37+
@option(
38+
"--points",
39+
help="target points to use as references",
40+
type=str
41+
)
42+
@option(
43+
"--height",
44+
help="instrument height",
45+
type=float,
46+
default=0
47+
)
48+
def cli_calc(**kwargs: Any) -> None:
49+
"""Calculate station coordinates from set measurements by resection."""
50+
from .calculate import main
51+
52+
main(**kwargs)
53+
54+
55+
@extra_command(
56+
"station",
57+
params=None,
58+
context_settings={"auto_envvar_prefix": None}
59+
) # type: ignore[misc]
60+
@com_port_argument()
61+
@com_option_group()
62+
@option(
63+
"--coordinates",
64+
help="station coordinates",
65+
type=(float, float, float),
66+
default=(0, 0, 0)
67+
)
68+
@option(
69+
"--instrumentheight",
70+
"--iheight",
71+
help="instrument height",
72+
type=float,
73+
default=0
74+
)
75+
@option(
76+
"--orientation",
77+
help="instrument orientation correction",
78+
type=Angle(),
79+
default="0-00-00"
80+
)
81+
def cli_upload(**kwargs: Any) -> None:
82+
"""Upload station setup to instrument."""
83+
from .upload import main
84+
85+
main(**kwargs)
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
from pathlib import Path
2+
import json
3+
4+
from jsonschema import ValidationError
5+
from geocompy.data import Angle, Coordinate
6+
7+
from ..targets import load_targets_from_json
8+
from ..setmeasurement.sessions import SessionDict
9+
from ..setmeasurement.process import (
10+
SessionValidator,
11+
calc_angles
12+
)
13+
from ..utils import echo_red
14+
from ..calculations import resection_2d_1d, preliminary_resection
15+
16+
17+
def main(
18+
measurements: Path,
19+
targets: Path,
20+
output: Path,
21+
points: str | None = None,
22+
height: float = 0
23+
) -> None:
24+
with measurements.open("rt", encoding="utf8") as file:
25+
data: SessionDict = json.load(file)
26+
27+
validator = SessionValidator(False)
28+
try:
29+
validator.validate(data)
30+
except ValidationError as ve:
31+
echo_red("Measurement data does not follow the required schema")
32+
echo_red(ve)
33+
exit(4)
34+
except ValueError as e:
35+
echo_red("The Measurement data did not pass validation")
36+
echo_red(e)
37+
exit(4)
38+
39+
try:
40+
targetlist = load_targets_from_json(str(targets))
41+
except ValidationError:
42+
echo_red("Target data does not follow the required schema")
43+
exit(4)
44+
45+
target_names = targetlist.get_target_names()
46+
if points is not None:
47+
target_names = list(set(target_names).intersection(points.split(",")))
48+
49+
actual_targets: list[str] = []
50+
references: list[Coordinate] = []
51+
obs: list[tuple[Angle, Angle, float]] = []
52+
for cycle in data["cycles"]:
53+
for p in cycle["points"]:
54+
name = p["name"]
55+
if name not in target_names:
56+
continue
57+
58+
actual_targets.append(name)
59+
60+
t = targetlist.get_target(name)
61+
coord = t.coords
62+
coord.z += t.height
63+
references.append(coord)
64+
hz = Angle(p["face1"][0])
65+
v = Angle(p["face1"][1])
66+
d = p["face1"][2]
67+
if p.get("face2") is not None:
68+
hz, v, _, _ = calc_angles(
69+
hz,
70+
v,
71+
Angle(p["face2"][0]),
72+
Angle(p["face2"][1])
73+
)
74+
d = (d + p["face2"][2]) / 2
75+
76+
obs.append(
77+
(hz, v, d)
78+
)
79+
80+
if len(set(actual_targets)) < 2:
81+
echo_red("Cannot calculate resection from less than 2 targets")
82+
exit(1)
83+
84+
(
85+
converged,
86+
orientation,
87+
stdev_orientation,
88+
station,
89+
stdev_station
90+
) = resection_2d_1d(
91+
obs,
92+
references,
93+
preliminary_resection(
94+
obs,
95+
references
96+
)
97+
)
98+
99+
if not converged:
100+
echo_red("Resection calculation failed")
101+
exit(1)
102+
103+
results = {
104+
"station": list(station - Coordinate(0, 0, height)),
105+
"stddev_station": list(stdev_station),
106+
"instrumentheight": height,
107+
"orientation": orientation.to_dms(4),
108+
"stddev_orientation": stdev_orientation.to_dms(4)
109+
}
110+
with output.open("wt", encoding="utf8") as file:
111+
json.dump(results, file, indent=4)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from geocompy.data import Angle, Coordinate
2+
from geocompy.communication import open_serial
3+
from geocompy.geo import GeoCom
4+
from geocompy.geo.gctypes import GeoComCode
5+
6+
from ..utils import echo_red, echo_green
7+
8+
9+
def main(
10+
port: str,
11+
baud: int = 9600,
12+
timeout: int = 15,
13+
retry: int = 1,
14+
sync_after_timeout: bool = False,
15+
coordinates: tuple[float, float, float] = (0, 0, 0),
16+
instrumentheight: float = 0,
17+
orientation: str = "0-00-00"
18+
) -> None:
19+
station = Coordinate(*coordinates)
20+
ori = Angle.from_dms(orientation)
21+
with open_serial(
22+
port=port,
23+
speed=baud,
24+
timeout=timeout,
25+
retry=retry,
26+
sync_after_timeout=sync_after_timeout
27+
) as com:
28+
tps = GeoCom(com)
29+
resp_stn = tps.tmc.set_station(station, instrumentheight)
30+
if resp_stn.error != GeoComCode.OK:
31+
echo_red("Cannot set station")
32+
exit(1)
33+
34+
resp_angle = tps.tmc.get_angle()
35+
if resp_angle.error != GeoComCode.OK or resp_angle.params is None:
36+
echo_red("Cannot set orientation")
37+
exit(1)
38+
39+
resp_ori = tps.tmc.set_azimuth(
40+
(resp_angle.params[0] + ori).normalized()
41+
)
42+
if resp_ori.error != GeoComCode.OK:
43+
echo_red("Cannot set orientation")
44+
exit(1)
45+
46+
echo_green("Station and orientation set")

src/instrumentman/setmeasurement/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ def cli_validate(**kwargs: Any) -> None:
202202
type=(float, float, float)
203203
)
204204
@option(
205+
"--instrumentheight",
205206
"--iheight",
206207
help="override instrument height",
207208
type=float
@@ -213,7 +214,7 @@ def cli_validate(**kwargs: Any) -> None:
213214
)
214215
@constraint(
215216
all_or_none,
216-
["station", "iheight"]
217+
["station", "instrumentheight"]
217218
)
218219
def cli_calc(**kwargs: Any) -> None:
219220
"""Calculate results from set measurements.

src/instrumentman/setmeasurement/process.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def main_calc(
201201
precision: int = 4,
202202
allow_oneface: bool = False,
203203
station: tuple[float, float, float] | None = None,
204-
iheight: float | None = None,
204+
instrumentheight: float | None = None,
205205
orientation: str | None = None
206206
) -> None:
207207
with input.open("rt", encoding="utf8") as file:
@@ -222,7 +222,7 @@ def main_calc(
222222
points = {"points": search("cycles[].points[]", data)}
223223
ptids = list(set(search("points[].name", points)))
224224

225-
if station is None or iheight is None:
225+
if station is None or instrumentheight is None:
226226
stn = Coordinate(
227227
*data["station"]
228228
) + Coordinate(
@@ -234,7 +234,7 @@ def main_calc(
234234
stn = Coordinate(
235235
station[0],
236236
station[1],
237-
station[2] + iheight
237+
station[2] + instrumentheight
238238
)
239239

240240
if orientation is None:

0 commit comments

Comments
 (0)