Metlivi Blog

So erstellen Sie einen Strich mit Breitkantenfeder, indem Sie eine feste Form entlang eines Pfads führen

Um einen Strich mit Breitkantenfeder zu erstellen, definieren Sie eine schmale rechteckige Feder, halten ihren Winkel konstant und verschieben sie entlang eines Pfads. Der Strich ist die Vereinigung aller Positionen, die dieses Rechteck einnimmt. Seine Stärke verändert sich mit der Bewegungsrichtung, obwohl die Feder selbst ihre Größe nie ändert.

Diese Anleitung zeigt, wie Sie diese Geometrie für eine Vektorzeichnung oder einen Akzent an einer Figur konstruieren. Sie definieren die Feder, führen sie kontinuierlich entlang einer Polylinie und erzeugen SVG mit einem vollständigen Python-Programm. Die zentrale Konstruktion vermeidet Lücken, die entstehen können, wenn ein Pinsel mit einzelnen Stempeln simuliert wird.

29. Oktober 20268 Min. LesezeitVon Metlivi Editorial Team
Abschnitt 1

Was bedeutet es, eine feste Form entlang eines Pfads zu führen?

Teilen Sie die Zeichnung in zwei Eingaben auf: einen Pfad, der beschreibt, wohin sich der Bezugspunkt der Feder bewegt, und eine Kontur, die den von der Feder an einer Position bedeckten Bereich beschreibt. Platzieren Sie den Bezugspunkt der Kontur im Ursprung. Addieren Sie an jeder Position des Pfads diese Position zu jedem Punkt der Kontur.

Mathematisch ist die resultierende Menge S = {p + n | p belongs to P, n belongs to N}, wobei P der Pfad und N die Feder ist. Dies ist eine Minkowski-Summe gemäß der punktweisen Definition im CGAL-Benutzerhandbuch zu 2D-Minkowski-Summen.

Bei dieser Konstruktion bedeutet „fest“, dass sowohl die Kontur als auch ihre Ausrichtung in den Zeichenkoordinaten konstant bleiben. Die Feder wird verschoben, ohne sich entlang des Pfads zu drehen. Wenn Sie den Bezugspunkt in der Mitte des Rechtecks halten, beschreibt der Pfad die Mitte der bewegten Feder.

Abschnitt 2

Wie bestimmen Federwinkel und Bewegungsrichtung die Strichstärke?

Wählen Sie drei Parameter: die lange Seite des Rechtecks w, seine kurze Seite h und den Winkel α seiner langen Kante. Ein kleiner positiver Wert für h verleiht der Feder eine sichtbare Mindeststärke. Eine ideale Feder in Form eines Liniensegments hat dagegen keine Stärke und kann beim Bewegen exakt in ihrer eigenen Richtung eine Markierung mit Fläche null hinterlassen.

Für ein gerades Pfadsegment mit Richtungswinkel θ beträgt die senkrecht zur Bewegungsrichtung gemessene Breite der rechteckigen Feder:

width across the stroke = w × |sin(θ − α)| + h × |cos(θ − α)|

Diese Formel ergibt sich aus der Projektion der beiden senkrechten Rechteckseiten auf die Normale des Pfads. Sie beschreibt ein gerades Segment oder die lokale Projektion der Kontur entlang einer glatten Kurve; überlappende Teile eines gekrümmten Strichs können seine Gesamtsilhouette verbreitern.

Bei einer beispielhaften Feder mit den Maßen 24 Einheiten mal 3 Einheiten ergibt eine Bewegung parallel zur langen Kante einen 3 Einheiten breiten Streifen. Eine Bewegung senkrecht dazu ergibt einen 24 Einheiten breiten Streifen. Bei einem Winkelunterschied von 45° beträgt die Breite ungefähr (24 + 3) / √2 oder 19,09 Einheiten. Dies sind berechnete Maße und keine gemessenen Pinselergebnisse.

Verwenden Sie diese drei Richtungen als Kalibrierungstest, bevor Sie eine komplexe Kurve zeichnen. So erkennen Sie, ob Winkel und Maße wie vorgesehen funktionieren, ohne mehrere überlappende Biegungen deuten zu müssen.

Abschnitt 3

Wie führen Sie die Form kontinuierlich entlang des Pfads, ohne Stempellücken zu hinterlassen?

Bewegen Sie eine konvexe Feder entlang eines geraden Segments: Erstellen Sie an jedem Endpunkt eine Kopie der Feder und berechnen Sie die konvexe Hülle der zusammengefassten Eckpunkte. Diese Hülle entspricht genau dem Bereich, der beim Verschieben entlang des Segments überstrichen wird.

Der Grund ist einfach: Jede Zwischenposition ist eine lineare Interpolation zwischen den Federpositionen an den Endpunkten. Da die Feder konvex ist, enthält die Hülle genau diese interpolierten Positionen. Diese Segmentkonstruktion ergibt sich direkt aus der Definition der Minkowski-Summe und ist kein separates Pinselnmerkmal.

Bei einem Rechteck liefert jedes Segment lediglich acht mögliche Punkte: vier Ecken am Anfang und vier am Ende. Berechnen Sie ihre Hülle, wiederholen Sie das für jedes aufeinanderfolgende Paar von Pfadpunkten und vereinigen Sie die resultierenden Polygone. Benachbarte Überstreichungen teilen sich die vollständige Federposition am gemeinsamen Endpunkt, sodass die Geometrie lückenlos abgedeckt ist.

Berechnen Sie nicht eine einzige konvexe Hülle um den gesamten Pfad. Dadurch würden Sie Bereiche zwischen den Biegungen ausfüllen und gewollte Einbuchtungen beseitigen. Die Hülle gehört zu jedem einzelnen Segment; der vollständige Strich ist ihre Vereinigung.

Eine konkave Feder erfordert eine andere Behandlung. Ihre Hülle würde die Einbuchtungen ausfüllen. Zerlegen Sie sie in konvexe Teile, führen Sie jeden Teil entlang des Pfads und vereinigen Sie die Ergebnisse. CGAL beschreibt den verwandten Ansatz aus Zerlegung und Vereinigung für Minkowski-Summen nichtkonvexer Polygone.

Abschnitt 4

Wie implementieren Sie das Entlangführen der Feder in Python?

Das folgende vollständige Programm benötigt Python 3 und dessen Standardbibliothek. Es definiert einen Beispielpfad mit fünf Punkten, konstruiert eine rechteckige Feder und gibt ein SVG-Dokument mit vier gefüllten Überstreichungspolygonen aus. Speichern Sie es als broad_edge.py und führen Sie dann python broad_edge.py > stroke.svg aus, um die Zeichnung zu erstellen.

Die Koordinaten folgen hier der SVG-Konvention: x nimmt nach rechts und y nach unten zu. Daher neigt ein positiver Winkel in diesem Programm die Feder auf dem Bildschirm im Uhrzeigersinn. In anderen Zeichenprogrammen kann eine andere Winkelkonvention gelten.

from math import cos, sin, radians


def hull(points):
    pts = sorted(set(points))
    if len(pts) <= 1:
        return pts

    def cross(o, a, b):
        return ((a[0] - o[0]) * (b[1] - o[1])
                - (a[1] - o[1]) * (b[0] - o[0]))

    def half(sequence):
        out = []
        for p in sequence:
            while len(out) >= 2 and cross(out[-2], out[-1], p) <= 0:
                out.pop()
            out.append(p)
        return out

    return half(pts)[:-1] + half(reversed(pts))[:-1]


def sweep(path, width=24, thickness=3, angle=30):
    if not path or width <= 0 or thickness <= 0:
        raise ValueError(
            'Provide a nonempty path and positive nib dimensions'
        )

    a = radians(angle)
    u = (cos(a), sin(a))
    v = (-sin(a), cos(a))
    nib = [
        (s * width * u[0] / 2 + t * thickness * v[0] / 2,
         s * width * u[1] / 2 + t * thickness * v[1] / 2)
        for s, t in [(-1, -1), (1, -1), (1, 1), (-1, 1)]
    ]
    pairs = list(zip(path, path[1:])) or [(path[0], path[0])]
    return [
        hull([(p[0] + q[0], p[1] + q[1])
              for p in (start, end) for q in nib])
        for start, end in pairs
    ]


path = [(40, 45), (85, 125), (140, 150), (195, 110), (245, 45)]
polygons = sweep(path)
all_points = [p for polygon in polygons for p in polygon]
x0, y0 = (min(p[i] for p in all_points) - 5 for i in (0, 1))
x1, y1 = (max(p[i] for p in all_points) + 5 for i in (0, 1))

svg = [
    '<svg xmlns="http://www.w3.org/2000/svg" '
    f'viewBox="{x0} {y0} {x1 - x0} {y1 - y0}">',
    '<g fill="#23364d" stroke="none">'
]
for polygon in polygons:
    coordinates = ' '.join(f'{x:.6f},{y:.6f}' for x, y in polygon)
    svg.append(f'<polygon points="{coordinates}"/>')
svg.extend(['</g>', '</svg>'])
print('\n'.join(svg))

Wenn der Pfad nur aus einem Punkt besteht, zeichnet das Programm eine einzelne Federkontur. Auch wiederholte aufeinanderfolgende Punkte ergeben eine Kontur, sodass keine Richtungsberechnung erforderlich ist. Leere Pfade und nichtpositive Federmaße lösen einen Fehler aus. Geben Sie endliche numerische Koordinatenpaare an; dieses kompakte Beispiel prüft keine importierten Pfaddaten.

Das Programm wurde mit den Beispielkoordinaten ausgeführt: Es erzeugte vier Überstreichungspolygone mit jeweils sechs Ecken, und das generierte SVG ließ sich erfolgreich als XML parsen. Auch Fälle mit einzelnen und wiederholten Punkten wurden geprüft. Diese Prüfungen bestätigen die Konstruktion und Dokumentstruktur, stellen aber keinen visuellen Renderingtest dar.

Abschnitt 5

Wie behandeln Sie Kurven, Ecken und Endpunkte?

Das Beispiel ist für seine Polylinie exakt, abgesehen von Gleitkommaarithmetik und Koordinatenrundung. Um eine Bézier-Kurve zu verwenden, nähern Sie sie zunächst durch gerade Segmente an und wenden dann dieselbe Überstreichung an. Fügen Sie dort mehr Segmente hinzu, wo sich die Kurve stark biegt, statt alle Abtastpunkte gleichmäßig über den Kurvenparameter zu verteilen.

Wählen Sie die Näherungstoleranz passend zur vorgesehenen Ausgabegröße. Eine Abweichung von einem Viertel Pixel kann zum Beispiel ein erstes Ziel für die Bildschirmdarstellung sein; prüfen Sie das Ergebnis anschließend in der größten geplanten Skalierung. Das ist eine beispielhafte technische Entscheidung und kein universeller Qualitätsmaßstab. Wichtig ist: Zusätzliche Unterteilungen eines bereits geraden Segments verändern den überstrichenen Bereich nicht.

Halten Sie getrennte Pfade mit aufgesetzter Feder getrennt. Wenn Sie Punkte aus zwei nicht verbundenen Strichen an einen einzigen Aufruf übergeben, entsteht eine unerwünschte verbindende Überstreichung. Erzeugen Sie jeden Strich separat und sammeln Sie die Polygone in der Ausgabe.

An einem Endpunkt behält die Feder ihre vollständige Kontur. An einer Ecke überlappen sich die beiden benachbarten Überstreichungen. In diesem Modell gibt es weder eine zusätzliche Gehrungs- noch eine runde Kappe. Die üblichen Stricheigenschaften von SVG definieren eigene Konstruktionen für Kappen und Verbindungen; ihre Ergänzung würde also Geometrie hinzufügen, die über die Überstreichung mit fester Feder hinausgeht. Siehe die SVG-2-Definitionen von Strichkappen und -verbindungen.

Abschnitt 6

Wann müssen Sie die Polygone vereinigen?

Das Programm exportiert gefüllte, überlappende Polygone. Für eine Vorschau in Vollfarbe stellen diese die überstrichene Fläche dar, ohne dass eine Polygonvereinigungsbibliothek erforderlich ist. Sie bleiben jedoch separate, bearbeitbare Objekte; das Programm berechnet keine einzige zusammenhängende Umrandung.

Wenn Sie für die weitere Konturbearbeitung eine saubere Silhouette benötigen, berechnen Sie die boolesche Vereinigung aller Segmentpolygone. Erhalten Sie dabei alle Löcher, die im Ergebnis verbleiben. Ein Schleifenpfad kann einen unbemalten Bereich umschließen; wenn Sie jede geschlossene Kontur füllen, verändert das den Strich.

Auch Transparenz muss bewusst behandelt werden. Wird fill-opacity mit Teiltransparenz auf überlappende Polygone einzeln angewendet, können Überlappungsbereiche dunkler erscheinen. Für gleichmäßige Transparenz wenden Sie die Deckkraft auf die umschließende Gruppe an oder vereinigen Sie die Geometrie, bevor Sie die Füllungsdeckkraft anwenden. SVG unterscheidet in seiner Spezifikation zum Malen zwischen der Deckkraft der Objektfüllung und der Gruppen-Deckkraft.

Gewünschtes Ergebnis Geeigneter nächster Schritt
Vorschau in Vollfarbe Gefüllte Überstreichungspolygone beibehalten
Gleichmäßig transparente Vorschau Deckkraft auf die umschließende Gruppe anwenden
Eine bearbeitbare Silhouette Überstreichungspolygone boolesch vereinigen
Benutzerdefinierte konkave Feder Feder vor dem Entlangführen zerlegen
Glatter gekrümmter Strich Kurve annähern und dann ihre Segmente überstreichen
Abschnitt 7

Wie diagnostizieren Sie einen unerwarteten Strich?

Beginnen Sie mit den Kalibrierungsrichtungen und untersuchen Sie anschließend den Pfad und die Ausgabekonstruktion. Ändern Sie jeweils nur eine Eingabe, damit die Ursache einer sichtbaren Veränderung klar bleibt.

  • Die Stärke bleibt nahezu konstant: Prüfen Sie, ob sich die Feder mit dem Pfad dreht. Ihr Winkel muss in den Zeichenkoordinaten fest bleiben.
  • Zwischen den Markierungen sind sichtbare Lücken: Ersetzen Sie einzelne Stempel durch die Segmenthüllenkonstruktion.
  • Eine breite Keilform füllt das Innere einer Biegung: Prüfen Sie, ob Sie versehentlich eine Hülle über mehrere Pfadsegmente auf einmal berechnet haben.
  • Die Enden sehen abgerundet aus: Prüfen Sie, ob ein gewöhnlicher Strich oder eine andere Federkontur hinzugefügt wurde.
  • Eine glatte Ausgangskurve wirkt kantig: Verfeinern Sie ihre Polylinienannäherung an den Biegungen.
  • Es erscheinen unerwartete Verbindungen: Halten Sie getrennte Pfade in separaten Aufrufen zum Entlangführen.

Wenn Sie das Ergebnis mit dem Kalligrafiewerkzeug von Inkscape vergleichen, bietet dessen Dokumentation nützliche Parameterprüfungen: „Fixierung“ auf 100 hält den Winkel fest, „Dünnung“ auf 0 entfernt die geschwindigkeitsabhängige Variation der Breite, und Druck- sowie Neigungssteuerungen können Breite und Winkel verändern. Deaktivieren Sie diese variablen Eingaben, wenn Sie das Verhalten einer festen Feder untersuchen. Diese Einstellungen beschreiben die Steuerungsmöglichkeiten des Werkzeugs; sie belegen nicht, dass dessen Ausgabe mit dieser rechteckigen Konstruktion identisch ist. Siehe die Dokumentation zur Kalligrafie-Werkzeugleiste von Inkscape.

Ein zuverlässiger Strich mit Breitkantenfeder beginnt mit einem einfachen Kalibrierungspfad und einer klar definierten Kontur. Sobald die Tests für parallele, senkrechte und diagonale Bewegungen korrekt funktionieren, wenden Sie dieselbe Segmentüberstreichung auf den gewünschten Pfad an, verfeinern Sie gekrümmte Abschnitte passend zur Ausgabegröße und vereinigen Sie die Polygone, wenn Sie für den nächsten Bearbeitungsschritt eine einzelne Silhouette benötigen.

Abschnitt 8

Quellen

Weitere Artikel

Dieses Thema weiter erkunden