"""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 format_ra(value, width=None, high_precision=None): """Rektaszension formatieren, immer mit Sekunden (HHhMMmSSs). Bei Niedrigpraezision liefert die Montierung nur Zehntel-Minuten; die Sekunden kommen dann in 6-Sekunden-Schritten. Das Format ist dasselbe wie bei Hochpraezision -- der Unterschied steckt allein in der Aufloesung der Rohdaten, nicht in der Darstellung. high_precision wird daher fuer RA nicht ausgewertet (nur bei DEC relevant, siehe format_dec). """ width = config.CHARS_PER_LINE if width is None else width h, m, s = parse_ra(value) return _fit([ "%02dh%02dm%02ds" % (h, m, s), "%02d:%02d:%02d" % (h, m, s), "%02dh%02dm" % (h, m), ], 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)