Skip to content

Commit

Permalink
topreader: round trip
Browse files Browse the repository at this point in the history
  • Loading branch information
speleo3 committed May 10, 2024
1 parent d610679 commit 9d7b643
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 23 deletions.
79 changes: 59 additions & 20 deletions extensions/topreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import sys
import struct
import time
import calendar
import collections
import math
from html import escape
Expand Down Expand Up @@ -69,7 +70,7 @@ def adegrees(angle: int, divisor=0xFFFF) -> float:

def adegrees_inv(degrees: float, divisor=0xFFFF) -> int:
'''convert angle from degrees to internal units'''
return int((degrees * divisor) / 360.0)
return round((degrees * divisor) / 360.0)


def posdeg(deg):
Expand Down Expand Up @@ -168,11 +169,11 @@ def is_consecutive_number(from_: str, to: str) -> bool:
return p_from[0] == p_to[0] and abs(int(p_from[2]) - int(p_to[2])) == 1


def _make_Point(x: int, y: int) -> tuple:
def _make_Point(x: int, y: int) -> tuple[float, float]:
return distmm(x), distmm(y)


def _make_Point_inv(x: float, y: float) -> tuple:
def _make_Point_inv(x: float, y: float) -> tuple[int, int]:
return distmm_inv(x), distmm_inv(y)


Expand All @@ -190,7 +191,7 @@ def _read_date(F: BinaryIO) -> time.struct_time:


def _write_date(tripdate: time.struct_time) -> Iterable[bytes]:
ticks = int((time.mktime(tripdate) + PTICKS) * NANOSEC)
ticks = int((calendar.timegm(tripdate) + PTICKS) * NANOSEC)
yield struct.pack('<Q', ticks)


Expand All @@ -205,10 +206,17 @@ def _read_comments(F: BinaryIO) -> str:
return C.decode('utf-8')


def _write_comment(comment) -> Iterable[bytes]:
# TODO
commentlength = 0
yield struct.pack('<B', commentlength)
def _write_comment(comment: str) -> Iterable[bytes]:
bc = comment.encode("utf-8")
commentlength = len(bc)
if commentlength >= 0x80:
commentlength2 = commentlength // 0x80
commentlength -= 0x80 * (commentlength2 - 1)
assert commentlength2 < 0x100
yield struct.pack('<BB', commentlength, commentlength2)
else:
yield struct.pack('<B', commentlength)
yield bc


def _read_trip(F: BinaryIO):
Expand Down Expand Up @@ -264,8 +272,8 @@ def _read_shot(F: BinaryIO):


def _write_shot(shot: dict) -> Iterable[bytes]:
yield _write_station(shot["from"])
yield _write_station(shot["to"])
yield from _write_station(shot["from"])
yield from _write_station(shot["to"])

Dist = distmm_inv(shot[KEY_TAPE])
yield struct.pack('<L', Dist)
Expand All @@ -283,9 +291,7 @@ def _write_shot(shot: dict) -> Iterable[bytes]:

comment = shot.get('comment', '')
if comment:
# TODO
# flags |= 0b00000010
pass
flags |= 0b00000010

yield struct.pack('<B', flags)

Expand All @@ -296,9 +302,7 @@ def _write_shot(shot: dict) -> Iterable[bytes]:
yield struct.pack('<h', tripindex)

if comment:
# TODO
# yield from _write_comments(comment)
pass
yield from _write_comment(comment)


def _read_reference(F: BinaryIO) -> list:
Expand All @@ -316,14 +320,25 @@ def _read_reference(F: BinaryIO) -> list:


def _write_reference(ref: list) -> Iterable[bytes]:
raise NotImplementedError
yield from _write_station(ref[0])
yield struct.pack(
'<QQL',
distmm_inv(ref[1]),
distmm_inv(ref[2]),
distmm_inv(ref[3]),
)
yield from _write_comment(ref[4])


def _read_Point(F: BinaryIO):
x, y = struct.unpack('<ll', F.read(8))
return _make_Point(x, y)


def _write_Point(point: tuple[float, float]) -> Iterable[bytes]:
yield struct.pack('<ll', *_make_Point_inv(*point))


def _read_Polygon(F: BinaryIO):
numpoints = struct.unpack('<L', F.read(4))[0]
poly = [_read_Point(F) for _ in range(numpoints)]
Expand All @@ -334,6 +349,13 @@ def _read_Polygon(F: BinaryIO):
}


def _write_Polygon(poly: dict) -> Iterable[bytes]:
yield struct.pack('<L', len(poly["coord"]))
for point in poly["coord"]:
yield from _write_Point(point)
yield struct.pack('<B', COLOURS.index(poly[KEY_COLOR]) + 1)


def _read_station(F: BinaryIO) -> str:
# id's split into major.decimal(minor)
idd, idm = struct.unpack('<HH', F.read(4))
Expand All @@ -349,7 +371,7 @@ def _read_station(F: BinaryIO) -> str:
return ""


def _write_station(shot: str) -> bytes:
def _write_station(shot: str) -> Iterable[bytes]:
idm, dot, idd = shot.rpartition(".")
if dot:
iidd, iidm = int(idd), int(idm)
Expand All @@ -358,7 +380,7 @@ def _write_station(shot: str) -> bytes:
else:
assert not (idd or idm)
iidd, iidm = 0, 0x8000
return struct.pack('<HH', iidd, iidm)
yield struct.pack('<HH', iidd, iidm)


def _read_xsection(F: BinaryIO) -> list:
Expand All @@ -377,6 +399,15 @@ def _read_xsection(F: BinaryIO) -> list:
]


def _write_xsection(xsec: list) -> Iterable[bytes]:
x, y, stn, direction = xsec
yield from _write_Point((x, y))
yield from _write_station(stn)
if direction != -1:
direction = adegrees_inv(direction)
yield struct.pack('<l', direction)


def _read_mapping(F: BinaryIO) -> dict:
x, y, scale = struct.unpack('<iii', F.read(12))
return {
Expand Down Expand Up @@ -417,7 +448,15 @@ def _read_drawing(F: BinaryIO) -> dict:

def _write_drawing(drawing: dict) -> Iterable[bytes]:
yield from _write_mapping(drawing["transform"])
# TODO

for poly in drawing["polys"]:
yield struct.pack('<B', 1)
yield from _write_Polygon(poly)

for xsec_ in drawing["xsec"]:
yield struct.pack('<B', 3)
yield from _write_xsection(xsec_)

yield struct.pack('<B', 0)


Expand Down
Binary file modified tests/data/test1.top
Binary file not shown.
16 changes: 13 additions & 3 deletions tests/test_topreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pathlib import Path
from pytest import approx
import pytest

TESTS_DATA = Path(__file__).resolve().parent / "data"

Expand All @@ -13,8 +14,8 @@ def test_distmm():
assert m.distmm_inv(meter) == approx(mm)


def test_adegrees():
angle = 1234
@pytest.mark.parametrize("angle", [1234, 1])
def test_adegrees(angle: int):
angle_deg = m.adegrees(angle)
assert m.adegrees_inv(angle_deg) == angle

Expand All @@ -37,7 +38,13 @@ def test_make_Point():
def _assert_top_test1(top: dict):
assert top["version"] == 3
assert top["trips"][0]["date"][:3] == (2020, 1, 30)
assert top["trips"][0]["comment"] == "Trip comment\r\nTC Line two"
assert top["trips"][0]["comment"] == "\r\n".join([
"A123456789012345678901234567", "B123456789012345678901234567",
"C123456789012345678901234567", "D123456789012345678901234567",
"E123456789012345678901234567", "F123456789012345678901234567",
"G123456789012345678901234567", "H123456789012345678901234567",
"I123456789012345678901234567", "J123456789012345678901234567", ""
])
assert top["trips"][0]["dec"] == approx(1.23, abs=1e-3)
assert top["shots"][2] == {
"from": "16.29",
Expand All @@ -64,3 +71,6 @@ def test_load():
with open(TESTS_DATA / "test1.top", "rb") as handle:
top = m.load(handle)
_assert_top_test1(top)
content = m.dumps(top)
top = m.loads(content)
_assert_top_test1(top)

0 comments on commit 9d7b643

Please sign in to comment.