Kategorien
Allgemein Satori

Bezierkurven in GFA-Basic

Ok, wir haben Ende 2023. Aber immernoch gibt es manchmal Situationen, wo ich weder mit Code noch mit Pseudocode was gut erklären kann. Dann hilft mir oft ein Relikt aus meiner Kindheit namens GFA-Basic. Der Interpreter kümmert sich um die Einrückung und Colorierung während ich tippe. Es gibt kaum Klammern und keine Semicola.
Menschen können das fast vom Blatt lesen, und darum geht es.

Ihr kennt sicher alle diese schönen Kurven, die galant durch eine Reihe von Kontrollpunkten laufen? Nun, gestern hab ich versucht, Emilio zu erklären, wie solche Bezierkurven entstehen:

Durch Interpolation zwischen Punkten, die ihrerseits Interpolationen sind. Vielleicht erkläre ich später noch ein paar Fallstricke zu Anzahl und Reihenfolge dieser Punkte, aber für heute nehmen wir die einfachste Form: Jeder Ankerpunkt, durch den die Kurve läuft, hat zwei spiegelbildliche Kontrollpunkte, durch feine Nadeln zu ihrem Ankerpunkt dargestellt. Deswegen brauchen wir nur einen davon abzuspeichern, der andere leitet sich davon ab.

Der Trick ist nun, dass man die Kurve in Abschnitten zwischen je zwei Ankerpunkten zeichnet. Den ersten Ankerpunkt wird die Kurve in Richtung ausgehender Kontrollpunkt verlassen, den zweiten Ankerpunkt in Richtung eingehender Kontrollpunkt erreichen. Dazu lässt man einen Parameter von 0 nach eins wandern und nutzt ihn insgesamt sechs mal zur Interpolation zwischen je zwei Punkten:

Zunächst errechnet man drei Zwischenpunkte aus vieren, aus denen sich wiederum zwei Zwischenpunkte ergeben, und zwischen diesen liegt der eine gesuchte Punkt, der die eigentliche Kurve zeichnet.

Hier ist der GFA-Basic-Code, um einige zufällige Punkte zu erzeugen und dann eine Bezierkurve durch sie zu zeichnen:


' *** Für Emilio mal eben BezierKurven visualisiert
' *** Remember: We have to calculate 3 levels of interpolation in order to
' ***           get those curves going through control points continuously

' ** INITIALISIERUNG

Type Int2 :
  x As Short
  y As Short
EndType

Local Short maxSegment = 18
Local Short maxContRange = 512
Local Short maxSteps = 120
Global Tang(maxSegment) As Int2
Global Cont(maxSegment) As Int2
Global ext, p As Int2

AutoRedraw = True
OpenW 1, , , 1600, 1280, 0

Global res As Int2 : res.x = _X : res.y = _Y

randomPoints(maxSegment, maxContRange)
DrawBezier(maxSegment, maxSteps)

'Warteschleife
Repeat
  DoEvents
Until ext Or InKey$ = #27
CloseW 1

Sub randomPoints(maxSegment&, maxContRange&)
  ' Generate and draw points
  Local T As Int2, C As Int2, segment
  For segment = 0 To maxSegment - 1

    ' tangent points
    T.x = Rand(res.x * .8) + res.x * .1
    T.y = Rand(res.y * .8) + res.y * .1
    Color RGB(128, 128, 128)
    Box T.x - 2, T.y - 2, T.x + 3, T.y + 3
    ' write to array
    Tang(segment).x = T.x
    Tang(segment).y = T.y

    ' control points
    C.x = Rand(maxContRange) - maxContRange / 2
    C.y = Rand(maxContRange) - maxContRange / 2
    Color RGB(64, 192, 128)
    Box T.x + C.x - 1, T.y + C.y - 1, T.x + C.x + 1, T.y + C.y + 1
    Color RGB(128, 144, 255)
    Box T.x - C.x - 1, T.y - C.y - 1, T.x - C.x + 1, T.y - C.y + 1
    Cont(segment).x = C.x
    Cont(segment).y = C.y

  Next
Return

Sub DrawBezier(maxSegment&, maxSteps&)
  Local Int segment, step, j
  Local Float s
  Local T0 As Int2,  T1 As Int2, C0 As Int2, C1 As Int2
  Local  R As Int2,   G As Int2,  B As Int2
  Local GR As Int2,  RB As Int2
  Local  Z As Int2, old As Int2

  For j = 0 To maxSegment - 1
    T0 = Tang(j)
    C0 = Cont(j)
    ' make control point absolute:
    C0.x += T0.x : C0.y += T0.y

    T1 = Tang((j + 1) % maxSegment)
    C1 = Cont((j + 1) % maxSegment)
    ' mirror control point 1 and make absolute:
    C1.x = T1.x - C1.x : C1.y = T1.y - C1.y

    For step = 0 To maxSteps
      s = step / maxSteps

      ' Interpolation Level 1:
      ' grüne Punkte = Tangentialpunkt 0 bis Kontrollpunkt 0
      interpol(T0, C0, s, G)
      Color RGB(64, 192, 128)
      Pset G.x, G.y

      ' blaue Punkte = Spiegelung von Kontrollpunkt 1 bis Tangentialpunkt 1
      interpol(C1, T1, s, B)
      Color RGB(128, 144, 255)
      Pset B.x, B.y

      ' rote Punkte = Interpolation zwischen Kontrollpunkten
      interpol(C0, C1, s, R)
      Color RGB(255, 192, 184)
      Pset R.x, R.y

      ' Interpolation Level 2:
      ' grün-rote Interpolation
      interpol(G, R, s, GR)
      ' rot-blaue Interpolation
      interpol(R, B, s, RB)

      ' Interpolation Level 3:
      ' schwarZe Punkte = BeZierkurve
      old = Z
      interpol(GR, RB, s, Z)       ' in Z wird das Ergebnis geschrieben

      If step > 0
        Color RGB(0, 0, 0)
        Line old.x, old.y, Z.x, Z.y
      EndIf

    Next
  Next
Return

Sub interpol(ByRef start As Int2, ByRef end As Int2, s, ByRef p As Int2)
  p.x = start.x * (1 - s) + end.x * s
  p.y = start.y * (1 - s) + end.y * s
Return

Sub Win_1_MouseWheel(Buttons&, Delta%, MseX%, MseY%)
  ext = Buttons && 1
Return

Sub Win_1_ReSize
  res.x = _X : res.y = _Y
  Win_1.BorderStyle = 0
Return
Kategorien
Satori

易经 – Das Buch der Wandlungen

Was mag das bedeuten, dass ich so gar nichts über das I Ging erinnere? Hatte ich dieses Kulturgut wegen bool isEsoteric = true nach /dev/null gepiped?

Jetzt bin ich jedenfalls zum ersten Mal über die binäre Codierung seiner 64 Zeichen, genannt Hexagramme, darauf gekommen. Diese sind allerdings keine digitale Früherscheinung in der Geschichte der Zahlenschrift, wie Leibniz nach seiner Erfindung des Binärcodes irrtümlicherweise annahm. Skeptisch eingeordnet sind sie schon eher ein Zeichensatz für eine altertümliche Methode zur Erforschung des Unbewussten, wie C.G. Jung sie aufgefasst hat.

Darüber hinaus aber vor allem eine unwahrscheinlich passende ästhetische Inspiration während meiner aktuellen Arbeit mit geometrischen Generatoren. Kein Wunder, dass mir am Tollsten daran gefällt, dass sowohl die Trigramme als auch die Hexagramme im UTF-Zeichensatz standardisiert sind.

Zum Nachtisch gönne ich mir aber auch ein kleines Bedeutungszitat, gewissermaßen als Orakelersatz:

Kraft
(乾, qián)
Himmel
(天, tiān)
Vater
(父, )
Beben
(震, zhèn)
Donner
(雷, léi)
Ältester Sohn
(長男, chǎngnán)
„Meine“ Trigramme mit Ihren (Haupt-)Bedeutungen.
Pakua
Kategorien
Allgemein Satori

Die sozialen Netze und ich – Ein Status-Update.

Der Platz zwischen den Goldenen Käfigen

Wie alle wissen, verfolge ich die Entwicklung unserer Werkzeuge zur Vernetzung mit regem Interesse und habe daher gegenüber den Untauglichen eine sattsame Kritizität entwickelt.

In letzter Zeit gingen mir einige erweiterte Modelle durch den Kopf, wie ich die Ungesunden, aber Populären unter den Diensten vielleicht wenigstens effizient einsetzen könnte, um innerhalb ihrer Nutzerschaft mehr Licht auf die systemischen Probleme und Alternativen zu werfen. Das will ich dort und hier – also mittelbar 🙂 – ab heute regelmäßig tun.

Etliche Versuche, sich doch auf die datenhungrigen Übergrifflichkeiten verschiedenster Diensteanbieter und ihrer Wegelagerer einzulassen, auf denen freilich beider Geschäftsmodelle gründen, scheiterten in den letzten Jahren schlicht beim erneuten Anlesen der AGB oder der technischen Selbstauskunft, manchmal auch erst bei den ersten mandatorischen Schritten zum Anlegen eines Nutzerprofils.

Richtig viel Arbeit machen aber die wenigen Alternativen, die mit gutem Beispiel vorangehen, neue Anforderungen erfüllen, nicht nur an neue Smilies, sondern z.B. auch an Quelloffenheit und verlässliche Ende-zu-Ende-Verschlüsselung. Die nämlich muss man probieren, gegeneinander abwägen, parallel zu den alten Lösungen betreiben, und vor allem: Für die muss man werben – denn ein Wiederhör’n mit Freunden und Bekannten ist darüber erstmal nicht zu erwarten.

Beispiel Telegram

Im Zuge eines Updates von Lineage 14.1 auf Lineage 15.1 bin ich heute in F-Droid, dem obligatorischen App Store für quelloffene Android-Apps, über den -Client des Kurznachrichtendienstes Telegram gestolpert und hab‘ ihn kurzerhand installiert. Wie umfassend Telegram sich technisch selbst disqualifiziert, hatte ich zwischenzeitlich leider vergessen, und mit der Quelloffenheit seines Clients hatte sich Telegram ja einige Vorschusslorbeeren erworben.
Leider kam die Wikipedia-Seite zu langsam, um mich am Schlimmsten zu hindern: Telegram hat sich beim Start die Erlaubnis geholt, meine Kontakte dauerhaft abzugreifen und seinen Servern die gleich mal gepflegt einverleibt. Und zwar nicht – wie es eben Signal macht – nur die Telefonnummern in einer lokal versalzenen und verhashten Form, nein, nein: großzügig mit allen Namen dabei.
Angesichts meiner Einstellung zu Kontaktdatenweitergabe durch private Nutzung solcher Dienste, und welche Einverständnismechanismen ich in diesen Fällen für angemessen halte, bin ich schockiert.

Wie ich dann sah, würden auch sämtliche normale – und Gruppenchats für den Anbieter lesbar auf deren Servern liegen, wo sie schön brav von Regierungen und anderen Angreifern wie aus Zahnpastatuben herausgedrückt werden können. Immerhin verschanzen sich die Macher irgendwo zwischen Dubai, den Seychellen und den Jungferninseln. Achja, es sind aber Russen. Oder so…
Die für geheime Chats extra angebotene Verschlüsselung ist zudem laut Fachkritik irgendwas zwischen unorthodox und kaputt.
Zwar ist es möglich, sich ohne Preisgabe der Kontakte an den Server untereinander zu verbinden, doch wenn dies erst nach Inbetriebnahme klar wird, ist das Kind doch schon in den Brunnen gefallen.
Beide Features sind optional; allein deshalb schon wird der Löwenanteil des KI-Futters von morgen so schürfbereit in irgendwelchen Rechenzentren landen.

Also ehrlich… das wollt ihr jetzt nehmen, weil Wh’App zu F’ook gehört?

Ich dachte mal, ich tipp‘ das am Rechner ins WordPress und schick‘ meinen vier Telegram-Leuten einen Link hierhin, so nach dem Motto: „Ihr könnt jetzt rüberkommen, bei Signal sind immerhin schon 64 meiner Kontakte :)“