433c53aabd
Die GM4000 liefert im Auslieferzustand keine Sekunden, sondern Zehntelminuten.
Bisher wurde daraus eine Sekundenanzeige gerechnet -- die sprang in
6-Sekunden-Schritten, weil die Rohdaten sie gar nicht hergeben. Die Zehntelform
ist ehrlicher und kuerzer, und der gewonnene Platz traegt die Beschriftung:
RA 18h36.9m
DE +38°47'
Bei Hochpraezision entfaellt die Beschriftung, dort braucht die Deklination mit
+38°47'01" alle Zellen.
Der Mock konnte das gar nicht nachstellen -- er sendete immer das
Hochpraezisionsformat. Neu: "mount_mock.py --low" bildet den Auslieferzustand ab
(RA als HH:MM.T, DEC ohne Bogensekunden). Vorgabe bleibt hoch, damit die
bestehenden Tests mit ihren festen Erwartungen unveraendert durchlaufen.
Zur Darstellung, alles am Geraet ausprobiert:
- **Schmale Zeichen** (config.CELL_NARROW): Dezimalpunkt und der Abstand
zwischen Beschriftung und Wert bekommen 3 statt 6 px -- in der Sperrschrift
standen sie sonst sehr luftig. Fuer die Leerzeichen am Zeilenende gilt das
nicht, die sollen den Rest der Zeile ueberschreiben.
- Damit entscheidet die **Pixelbreite** ueber das Abschneiden, nicht mehr die
Zeichenzahl: "RA 18h36.9m" sind 11 Zeichen und trotzdem nur 60 px.
- **Linksbuendig ab LINE_X = 0**, der Schalter zum Zentrieren ist entfallen.
Zentriert standen die Zeilen um wenige Pixel gegeneinander versetzt, weil die
RA-Zeile mit ihrem schmalen Punkt kuerzer ist als die DEC-Zeile.
Ein Zwischenschritt, der wieder verworfen wurde und als Warnung im Code steht:
Ein Doppelpunkt als Trenner ("RA:18h36.9m") sah in Zeichensatz 0 zu wuchtig aus;
der aus Zeichensatz 1 ist schlanker, steht aber mitten in der obersten Zeile --
und jeder Zeichensatzwechsel zerstoert die Home-Zelle. Das erste Zeichen danach
noch einmal zu schreiben machte es schlimmer: Das nachgezogene Zeichen bemalt
GLYPH_WIDTH Pixel und frisst die linke Spalte seines rechten Nachbarn. Deshalb
steht in der obersten Zeile jetzt bewusst kein Sonderzeichen.
161 Tests gruen, am Geraet bestaetigt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
147 lines
5.3 KiB
Python
147 lines
5.3 KiB
Python
"""Rektaszension und Deklination einlesen und fuer die Anzeige formatieren.
|
|
|
|
Die Eingabe ist bewusst tolerant, damit man beim Testen nicht auf ein Format
|
|
festgelegt ist: 12h34m56s | 12:34:56 | "12 34 56" | 12.5824 (Stunden dezimal)
|
|
Bei der Deklination entsprechend mit Vorzeichen und Grad/Bogenminuten.
|
|
|
|
Ausgegeben wird die breiteste Schreibweise, die noch in die Zeile passt --
|
|
die tatsaechliche Zeichenbreite der Anzeige kennen wir erst nach dem Livetest.
|
|
"""
|
|
|
|
import config
|
|
|
|
_SEPARATORS = "hHmMsSdD°'\"::,"
|
|
|
|
|
|
def _split(value):
|
|
"""Zahlenfelder aus einer Koordinatenangabe holen, Trennzeichen egal."""
|
|
out, cur = [], ""
|
|
for ch in str(value).strip():
|
|
if ch.isdigit() or ch == ".":
|
|
cur += ch
|
|
elif ch in "+-" and not cur and not out:
|
|
cur += ch
|
|
else:
|
|
if cur:
|
|
out.append(cur)
|
|
cur = ""
|
|
if cur:
|
|
out.append(cur)
|
|
if not out:
|
|
raise ValueError("keine Zahlen in %r gefunden" % (value,))
|
|
return out
|
|
|
|
|
|
def _to_sexagesimal(value, unit_max, name):
|
|
"""Eingabe in (Vorzeichen, Ganzteil, Minuten, Sekunden) zerlegen."""
|
|
fields = _split(value)
|
|
negative = fields[0].startswith("-")
|
|
fields[0] = fields[0].lstrip("+-")
|
|
|
|
if len(fields) == 1: # dezimal, z.B. 12.5824
|
|
total = float(fields[0]) * 3600.0
|
|
else:
|
|
parts = [float(f) for f in fields[:3]] + [0.0] * (3 - len(fields[:3]))
|
|
total = parts[0] * 3600.0 + parts[1] * 60.0 + parts[2]
|
|
|
|
total = int(round(total))
|
|
big, rest = divmod(total, 3600)
|
|
minutes, seconds = divmod(rest, 60)
|
|
|
|
if big >= unit_max:
|
|
raise ValueError("%s: %s ausserhalb des gueltigen Bereichs" % (name, value))
|
|
return negative, big, minutes, seconds
|
|
|
|
|
|
def parse_ra(value):
|
|
"""Rektaszension -> (Stunden, Minuten, Sekunden)."""
|
|
_, h, m, s = _to_sexagesimal(value, 24, "Rektaszension")
|
|
return h, m, s
|
|
|
|
|
|
def parse_dec(value):
|
|
"""Deklination -> (Vorzeichen als '+'/'-', Grad, Bogenminuten, Bogensekunden)."""
|
|
neg, d, m, s = _to_sexagesimal(value, 91, "Deklination")
|
|
if d > 90 or (d == 90 and (m or s)):
|
|
raise ValueError("Deklination %s liegt ausserhalb +/-90 Grad" % (value,))
|
|
return ("-" if neg else "+"), d, m, s
|
|
|
|
|
|
def _fit(candidates, width):
|
|
"""Erste Schreibweise nehmen, die in die Zeile passt; sonst die kuerzeste."""
|
|
for text in candidates:
|
|
if len(text) <= width:
|
|
return text
|
|
return candidates[-1][:width]
|
|
|
|
|
|
def _to_tenths(h, m, s):
|
|
"""(h, m, s) in (Stunden, Minuten, Zehntelminuten) umrechnen.
|
|
|
|
Ganzzahlig gerechnet, damit es unter MicroPython keine Float-Ueberraschungen
|
|
gibt. Der Uebertrag ist wichtig: 18:36:57 sind 36,95 Minuten und werden zu
|
|
18:37.0, nicht zu 18:36.10.
|
|
"""
|
|
zehntel = ((h * 3600 + m * 60 + s) * 10 + 30) // 60 # kaufmaennisch runden
|
|
minuten, t = divmod(zehntel, 10)
|
|
h, m = divmod(minuten, 60)
|
|
return h % 24, m, t
|
|
|
|
|
|
def format_ra(value, width=None, high_precision=None):
|
|
"""Rektaszension formatieren.
|
|
|
|
Die Darstellung folgt dem, was die Montierung wirklich liefert:
|
|
|
|
Niedrigpraezision (Vorgabe): **HHhMM.T** mit Zehntelminuten -- genau die
|
|
Aufloesung, die die GM4000 in diesem Modus sendet. Sieben Zeichen, das laesst
|
|
Platz fuer die Beschriftung "RA:" auf der Anzeige (siehe
|
|
displayloop.format_coordinates). Das "h" statt eines Doppelpunkts ist
|
|
Nutzerwunsch -- der Doppelpunkt wirkt in der Sperrschrift zu wuchtig.
|
|
|
|
Hochpraezision: HHhMMmSSs mit echten Sekunden.
|
|
|
|
Bis 2026-07-27 wurde auch bei Niedrigpraezision mit Sekunden angezeigt. Die
|
|
sprangen dort in 6-Sekunden-Schritten, weil die Rohdaten sie gar nicht
|
|
hergeben -- die Zehntelform ist ehrlicher und kuerzer.
|
|
"""
|
|
width = config.CHARS_PER_LINE if width is None else width
|
|
high = config.HIGH_PRECISION if high_precision is None else high_precision
|
|
h, m, s = parse_ra(value)
|
|
if high:
|
|
candidates = [
|
|
"%02dh%02dm%02ds" % (h, m, s),
|
|
"%02d:%02d:%02d" % (h, m, s),
|
|
"%02dh%02dm" % (h, m),
|
|
]
|
|
else:
|
|
h, m, t = _to_tenths(h, m, s)
|
|
candidates = [
|
|
"%02dh%02d.%dm" % (h, m, t), # 8: 18h36.9m
|
|
"%02dh%02d.%d" % (h, m, t), # 7: ohne Minutenzeichen
|
|
"%02dh%02dm" % (h, m), # 6: ohne Zehntel
|
|
]
|
|
return _fit(candidates, width)
|
|
|
|
|
|
def format_dec(value, width=None, high_precision=None):
|
|
width = config.CHARS_PER_LINE if width is None else width
|
|
high = config.HIGH_PRECISION if high_precision is None else high_precision
|
|
sign, d, m, s = parse_dec(value)
|
|
deg = config.DEGREE_MARKER
|
|
if high:
|
|
candidates = [
|
|
"%s%02d%s%02d'%02d\"" % (sign, d, deg, m, s), # 10: mit Bogensekundenzeichen
|
|
"%s%02d%s%02d'%02d" % (sign, d, deg, m, s), # 9: Gradzeichen, ohne " am Ende
|
|
"%s%02d:%02d:%02d" % (sign, d, m, s), # 9: Doppelpunkte
|
|
"%s%02d%s%02d'" % (sign, d, deg, m), # 7: ohne Bogensekunden
|
|
"%s%02d:%02d" % (sign, d, m), # 6
|
|
]
|
|
else:
|
|
# Niedrigpraezision: ohne Sekunden (die Montierung liefert nur sDD MM).
|
|
candidates = [
|
|
"%s%02d%s%02d'" % (sign, d, deg, m), # 7: -00°55'
|
|
"%s%02d:%02d" % (sign, d, m), # 6: -00:55
|
|
]
|
|
return _fit(candidates, width)
|