RA in Zehntelminuten mit Beschriftung: "RA 18h36.9m" / "DE +38°47'"
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>
This commit is contained in:
+116
-31
@@ -115,13 +115,51 @@ class Display:
|
||||
self._gezeigt = {}
|
||||
self._zeile_schreiben(index, text)
|
||||
|
||||
def _aufbereiten(self, text):
|
||||
"""Auf Zeilenbreite bringen: abschneiden und auffuellen (ggf. mittig)."""
|
||||
@staticmethod
|
||||
def _breiten(text):
|
||||
"""Breite jeder einzelnen Zelle in Pixeln.
|
||||
|
||||
Zeichen aus config.CELL_NARROW brauchen weniger Platz. Fuer Leerzeichen
|
||||
gilt das aber nur *innerhalb* des Textes -- dort trennen sie Beschriftung
|
||||
und Wert ("RA 18h36.9m"). Die Leerzeichen, mit denen die Zeile rechts
|
||||
aufgefuellt wird, behalten die volle Breite: Sie sollen den Rest der
|
||||
Zeile ueberschreiben, und je schmaler sie waeren, desto mehr Zellen
|
||||
muesste man dafuer schreiben.
|
||||
"""
|
||||
ohne_fuellung = len(text.rstrip())
|
||||
return [config.CELL_NARROW.get(ch, config.CELL_WIDTH)
|
||||
if i < ohne_fuellung else config.CELL_WIDTH
|
||||
for i, ch in enumerate(text)]
|
||||
|
||||
@staticmethod
|
||||
def _breite(text):
|
||||
"""Pixelbreite eines Textes."""
|
||||
return sum(Display._breiten(text))
|
||||
|
||||
@staticmethod
|
||||
def _aufbereiten(text):
|
||||
"""Auf die Zeilenbreite bringen: abschneiden und auffuellen.
|
||||
|
||||
Massgeblich sind die **Pixel**, nicht die Zeichenzahl: Seit schmale
|
||||
Zeichen weniger Platz brauchen (config.CELL_NARROW), passen mal 10 und
|
||||
mal 11 Zeichen in dieselbe Zeile. Ein Text wird deshalb so lange
|
||||
gekuerzt, bis er in DISPLAY_WIDTH passt, und nur so weit aufgefuellt, wie
|
||||
eine weitere Zelle noch hineingeht. Ohne das ragte die letzte Zelle ueber
|
||||
den Rand und die Anzeige quittierte mit Fehlercode 4.
|
||||
"""
|
||||
# Ohne str.ljust/center: die kennt MicroPython nicht (am Geraet aufgefallen).
|
||||
platz = config.DISPLAY_WIDTH - config.LINE_X
|
||||
text = text[:config.CHARS_PER_LINE]
|
||||
rest = config.CHARS_PER_LINE - len(text)
|
||||
links = rest // 2 if config.CENTER_LINES else 0
|
||||
return " " * links + text + " " * (rest - links)
|
||||
while text and Display._breite(text) > platz:
|
||||
text = text[:-1]
|
||||
# Beim Auffuellen bewusst mit der *vollen* Zellenbreite rechnen, obwohl
|
||||
# das Leerzeichen schmal gesetzt wird: Die Anzeige bemalt je Zeichen
|
||||
# GLYPH_WIDTH Pixel, ein Leerzeichen am rechten Rand reichte sonst
|
||||
# darueber hinaus.
|
||||
while (len(text) < config.CHARS_PER_LINE
|
||||
and Display._breite(text) + config.CELL_WIDTH <= platz):
|
||||
text += " "
|
||||
return text
|
||||
|
||||
def _zeile_schreiben(self, index, text, voll=False):
|
||||
"""Eine Zeile nachfuehren. Liefert True, wenn der Zeichensatz gewechselt wurde.
|
||||
@@ -129,19 +167,27 @@ class Display:
|
||||
voll=True schreibt alle Zellen, auch die unveraenderten.
|
||||
"""
|
||||
neu = self._aufbereiten(text)
|
||||
alt = None if voll else self._gezeigt.get(index)
|
||||
if alt == neu:
|
||||
pos = self._positionen(neu)
|
||||
alt, alt_pos = self._gezeigt.get(index, (None, None))
|
||||
if voll:
|
||||
alt = None
|
||||
elif alt_pos != pos:
|
||||
# Die Zeile hat eine andere Form als vorher (z.B. ein Dezimalpunkt
|
||||
# kommt dazu, der weniger Platz braucht). Dann sitzen alle Zellen
|
||||
# woanders und der Vergleich waere sinnlos -- vollstaendig neu.
|
||||
alt = None
|
||||
elif alt == neu:
|
||||
return False # nichts zu tun, kein Telegramm
|
||||
|
||||
du = migra.DataUnit()
|
||||
du.attributes(fg=config.COLOR, bg=config.BACKGROUND, blink=migra.STATIC)
|
||||
if alt is None:
|
||||
# Erste Ausgabe dieser Zeile: Zeichensatz sicherheitshalber setzen.
|
||||
# Danach behaelt die Anzeige ihn, und _emit_degree schaltet nach
|
||||
# jedem Gradzeichen wieder zurueck -- ein Wechsel je Telegramm waere
|
||||
# nur unnoetiger Ballast und wuerde die Home-Zelle beschaedigen.
|
||||
# Danach behaelt die Anzeige ihn, und _emit_fremd schaltet nach
|
||||
# jedem Sonderzeichen wieder zurueck -- ein Wechsel je Telegramm
|
||||
# waere nur Ballast und wuerde die Home-Zelle beschaedigen.
|
||||
du.charset(config.CHARSET, spaced=config.CHARSET_SPACED)
|
||||
wechsel = self._emit_line(du, config.LINE_Y[index], neu, alt)
|
||||
wechsel = self._emit_line(du, config.LINE_Y[index], neu, alt, pos)
|
||||
try:
|
||||
self.send(du)
|
||||
except Exception:
|
||||
@@ -151,23 +197,43 @@ class Display:
|
||||
# faelschlich fuer aktuell hielten.
|
||||
self._gezeigt.pop(index, None)
|
||||
raise
|
||||
self._gezeigt[index] = neu
|
||||
self._gezeigt[index] = (neu, pos)
|
||||
return wechsel or alt is None
|
||||
|
||||
@staticmethod
|
||||
def _zelle_faellig(neu, alt, i):
|
||||
def _positionen(text):
|
||||
"""x-Position jeder Zelle einer Zeile.
|
||||
|
||||
Normalerweise ein festes Raster aus CELL_WIDTH. Zeichen aus
|
||||
config.CELL_NARROW bekommen weniger Platz -- der Dezimalpunkt der
|
||||
Zehntelminuten stuende sonst sehr luftig zwischen den Ziffern.
|
||||
"""
|
||||
breiten = Display._breiten(text)
|
||||
x = config.LINE_X
|
||||
aus = []
|
||||
for b in breiten:
|
||||
aus.append(x)
|
||||
x += b
|
||||
return aus
|
||||
|
||||
@staticmethod
|
||||
def _zelle_faellig(neu, alt, i, pos):
|
||||
"""Muss Zelle i neu geschrieben werden?
|
||||
|
||||
Ja, wenn sie sich selbst geaendert hat -- oder wenn ihr **linker**
|
||||
Nachbar neu geschrieben wird: Der reicht 1 px in diese Zelle hinein und
|
||||
loescht deren erste Pixelspalte (siehe _emit_line).
|
||||
Nachbar neu geschrieben wird und bis in diese Zelle hineinragt: Die
|
||||
Anzeige bemalt je Zeichen GLYPH_WIDTH Pixel, mehr als eine Zelle breit
|
||||
ist, und loescht damit die erste Pixelspalte hier (siehe _emit_line).
|
||||
"""
|
||||
def anders(k):
|
||||
return k >= len(alt) or alt[k] != neu[k]
|
||||
|
||||
return anders(i) or (i > 0 and anders(i - 1))
|
||||
if anders(i):
|
||||
return True
|
||||
return (i > 0 and anders(i - 1)
|
||||
and pos[i] < pos[i - 1] + config.GLYPH_WIDTH)
|
||||
|
||||
def _emit_line(self, du, y, text, alt=None):
|
||||
def _emit_line(self, du, y, text, alt=None, pos=None):
|
||||
"""Zellen einer Zeile ausgeben. Liefert True bei Zeichensatzwechsel.
|
||||
|
||||
Jedes Zeichen wird einzeln auf x = LINE_X + i*CELL_WIDTH gesetzt, statt
|
||||
@@ -189,26 +255,45 @@ class Display:
|
||||
Am Geraet aufgefallen (2026-07-27): Beim Sekundenwechsel fehlten dem "s"
|
||||
die linken Pixel, beim Minutenwechsel dem "m".
|
||||
"""
|
||||
if pos is None:
|
||||
pos = self._positionen(text)
|
||||
wechsel = False
|
||||
for i in range(len(text)):
|
||||
if alt is not None and not self._zelle_faellig(text, alt, i):
|
||||
if alt is not None and not self._zelle_faellig(text, alt, i, pos):
|
||||
continue
|
||||
du.cursor(config.LINE_X + i * config.CELL_WIDTH, y)
|
||||
if text[i] == config.DEGREE_MARKER:
|
||||
self._emit_degree(du)
|
||||
du.cursor(pos[i], y)
|
||||
if self._emit_zeichen(du, text[i]):
|
||||
wechsel = True
|
||||
else:
|
||||
du.text(text[i])
|
||||
return wechsel
|
||||
|
||||
def _emit_degree(self, du):
|
||||
"""Das Gradzeichen einfuegen -- ueber Zeichensatzwechsel oder als Fallback."""
|
||||
if config.DEGREE_CHARSET is None:
|
||||
du.text(config.DEGREE_FALLBACK)
|
||||
return
|
||||
du.charset(config.DEGREE_CHARSET, spaced=config.CHARSET_SPACED)
|
||||
du.text(config.DEGREE_CHAR)
|
||||
du.charset(config.CHARSET, spaced=config.CHARSET_SPACED)
|
||||
def _emit_zeichen(self, du, ch):
|
||||
"""Ein Zeichen ausgeben. Liefert True, wenn der Zeichensatz wechseln musste.
|
||||
|
||||
Nur das Gradzeichen kommt aus einem anderen Zeichensatz -- in
|
||||
Zeichensatz 0 gibt es keines.
|
||||
|
||||
Ein Zeichensatzwechsel beschaedigt die Home-Zelle (0,0), also den Anfang
|
||||
der obersten Zeile. Solange alle Wechsel in der *unteren* Zeile
|
||||
stattfinden, genuegt die Reihenfolge in show_lines (unten vor oben).
|
||||
|
||||
**Ein Wechsel mitten in der obersten Zeile laesst sich dagegen nicht
|
||||
sauber reparieren.** Das erste Zeichen danach noch einmal zu schreiben,
|
||||
wurde am Geraet ausprobiert (2026-07-27) und machte es schlimmer: Das
|
||||
nachgezogene Zeichen bemalt GLYPH_WIDTH Pixel und frisst dabei die linke
|
||||
Spalte seines rechten Nachbarn. Deshalb steht in der obersten Zeile
|
||||
bewusst kein Sonderzeichen -- die Beschriftung nutzt ein schmales
|
||||
Leerzeichen statt eines Doppelpunkts aus Zeichensatz 1.
|
||||
"""
|
||||
if ch == config.DEGREE_MARKER:
|
||||
if config.DEGREE_CHARSET is None:
|
||||
du.text(config.DEGREE_FALLBACK)
|
||||
return False
|
||||
du.charset(config.DEGREE_CHARSET, spaced=config.CHARSET_SPACED)
|
||||
du.text(config.DEGREE_CHAR)
|
||||
du.charset(config.CHARSET, spaced=config.CHARSET_SPACED)
|
||||
return True
|
||||
du.text(ch)
|
||||
return False
|
||||
|
||||
def close(self):
|
||||
self._t.close()
|
||||
|
||||
Reference in New Issue
Block a user