Forum: PC-Programmierung SVG-Path zu Koordinaten


von Christian M. (christian_m280)


Angehängte Dateien:

Lesenswert?

Aus einem SVG (mit Inkscape erstellt) soll ein Pfad in Koordinaten von 
gleichmässig verteilten Punkten umgewandelt werden. Das angefügte SVG 
zeigt den Pfad. Keine Angst, ich mache schon einen einzigen Pfad daraus, 
wenn es denn soweit ist! Mit welchem Programm/Script kann ich das 
bewerkstelligen?

Hintergrund: Von der Steuerung meiner Modelleisenbahn kann ich die 
Position eines Zuges erhalten und würde die gerne graphisch anzeigen. 
Also ein roter Kreis oder so der auf der Linie entlangfährt. Wenn ich 
nun eine Tabelle hätte mit einigen hundert Punkten wäre der Rest für 
mich kein Problem. Zwischenwerte kann ich interpolieren! Manuelles 
eintragen von so vielen Punkten würde ich gerne vermeiden...

Vielleicht gibt es ja auch noch andere, einfachere Lösungen! Freue mich 
auf Ideen!

Gruss Chregu

von Christian M. (christian_m280)



Lesenswert?

Ups, sehe gerade, ich habe eine ungültige SVG-Datei hochgeladen. Diese 
Datei habe ich abgespeckt, bis sie gerade noch ladbar ist für: 
https://www.unionbytes.de/downloads/VectorGraphic.pbi

Im Anhang die gültige SVG.

Im Zuge meiner Recherche ziehe ich auch einen Umweg über Gcode in 
Betracht, da habe ich schon mal Koordinaten - aber noch noch keine 
gleichmässigen Wegstücke.

Gruss Chregu

von Walter T. (nicolas)


Lesenswert?

Christian M. schrieb:
> Mit welchem Programm/Script kann ich das
> bewerkstelligen?

Christian M. schrieb:
> da habe ich schon mal Koordinaten - aber noch noch keine
> gleichmässigen Wegstücke.

Was willst Du mit den Punkten am Ende machen? In welcher Form brauchst 
Du die Punkte?

Das ist eine recht einfache Programmieraufgabe, um sich mal ein bischen 
mit diskreter Geometrie zu beschäftigen.

Schritt 1: Parametrische Kurve darstellen
Schritt 2: Linienintegral entlang der Kurve bestimmen.
Schritt 3: Gewünschte Punktabstände bestimmen.
Schritt 4: Linie ein zweites Mal im gewünschten Punktabstand 
abschreiten.

von Christian M. (christian_m280)


Lesenswert?

Walter T. schrieb:
> Christian M. schrieb:
>> da habe ich schon mal Koordinaten - aber noch noch keine
>> gleichmässigen Wegstücke.
>
> Was willst Du mit den Punkten am Ende machen? In welcher Form brauchst
> Du die Punkte?

Korrektur: Ich brauche nicht unbedingt gleichmässige Wegstücke. Ich 
stelle mir eine Tabelle vor etwa so:
1
| Wegstrecke |  X |  Y |
2
+------------+----+----+
3
|          0 | 25 | 10 |
4
|        2.2 | 27 | 10 |
5
usw.

Ich bekomme also von der Steuerung den gefahrenen Weg, z.B. 1.1, und die 
Tabelle gibt mir dann mit Interpolation X=26 und Y=10 zurück. Dort male 
ich dann einen roten Kreis oder so.

Walter T. schrieb:
> Das ist eine recht einfache Programmieraufgabe, um sich mal ein bischen
> mit diskreter Geometrie zu beschäftigen.

:-)) Da muss ich mich einlesen. Juhu, eine neue Herausforderung!

Gruss Chregu

von Walter T. (nicolas)


Lesenswert?

Ich finde diese Art von Grfik-Programmierung auch immer als sehr 
motivierend. Man sieht einfach sofort, was man gemacht hat.

von Yalu X. (yalu) (Moderator)


Angehängte Dateien:

Lesenswert?

Inkscape kann dir dabei helfen, Koordinaten äquidistanter Wegpunkte zu
generieren:

Mit "Extensions/Generate from Path/Distribute Along Path" kannst du ein
Objekt (am besten einen kleinen Kreis) wiederholt als Kopie auf einem
gegebenen Pfad platzieren. Der Abstand zwischen den einzelnen Kopien
entlang des Pfads kann durch den Parameter "Space between copies"
festgelegt werden. Das Kästchen "Follow path orientation" sollte
deaktiviert sein, denn dadurch werden die Kopien nur verschoben und
nicht rotiert was die Ermittlung der absoluten Koordinaten (s.u.)
vereinfacht. Weitere Infors liefert der "Help"-Tab des Dialogs.

Die neu generierten Objekte sind in einer Gruppe zusammengefasst und
sehen in der SVG-Datei wie folgt aus:
1
    <g
2
       id="g111">
3
      <circle
4
         style="fill:#ff0000;stroke-width:0.499999;stroke-linejoin:round"
5
         cx="128.06248"
6
         cy="189.31512"
7
         r="0.5"
8
         transform="translate(88.394, -32.963)"
9
         id="circle1" />
10
      <circle
11
         style="fill:#ff0000;stroke-width:0.499999;stroke-linejoin:round"
12
         cx="128.06248"
13
         cy="189.31512"
14
         r="0.5"
15
         transform="translate(82.7215, -31.9805)"
16
         id="circle2" />
17
      ...
18
    </g>

Die Koordinaten cy und cy sind dabei diejenigen des ursprünglichen
Objekts und für alle Kopien gleich. Zu diesen Koordinaten muss die
Verschiebung in "transform" hinzuaddiert werden, um die absoluten
Koordinaten der Punkte zu erhalten.

von Walter T. (nicolas)


Lesenswert?

Moment, vielleicht habe ich die Fragestellung nicht verstanden: Soll das 
laufend gemacht werden, (z.B. um "Knoten" auf der Linie äquidistant 
abzubilden), oder nur einmal (z.B. um Bohrungen für LEDs auf einer 
Anzeigeplatte zu positionieren)?

Meine obige Antwort ging vom ersten Fall aus.

Wenn es nur darum geht, das ein einziges Mal zu machen, sollte das jedes 
CAD können. Bei mir tritt diese Aufgabe z.B. regelmäßig auf, wenn ich 
Schablonen mit Nahtlöchern herstelle. Ich mache das dann mit TurboCAD. 
Daß es dafür ein Inkscape-Plugin gibt, ist natürlich auch klasse!

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Falls das später im Browser läuft, könntest du die Punkte euch einfach 
per CSS & JS auf dem Pfad platzieren. Mit den offset-path und 
offset-distance Eigenschaften kann man einfach einen Pfad, und eine 
Distanz angeben:
https://developer.mozilla.org/en-US/docs/Web/CSS/offset-path#creating_an_offset-path_using_path
Leicht angepasste Version, wo ich das per JS setze: 
https://jsfiddle.net/742d9cqx/ (Den Slider bewegen)

: Bearbeitet durch User
von Christian M. (christian_m280)


Lesenswert?

Yalu X. schrieb:
> Mit "Extensions/Generate from Path/Distribute Along Path"

Das funktioniert hervorragend!

Yalu X. schrieb:
> am besten einen kleinen Kreis

Weiss jetzt auch warum! ;-)

Yalu X. schrieb:
> Inkscape kann dir dabei helfen, Koordinaten äquidistanter Wegpunkte zu
> generieren

Ich dachte schon, dass es einen Hack gibt!

Gruss Chregu

von Christian M. (christian_m280)


Lesenswert?

Daniel A. schrieb:
> Falls das später im Browser läuft, könntest du die Punkte euch einfach
> per CSS & JS auf dem Pfad platzieren.

Ja jetzt bin ich ein bisschen im Dilemma. Das geht im Browser so schön 
einfach! Eigentlich wollte ich ein Windows-Window nehmen und das Ganze 
mit PureBasic umsetzen. Dafür fehlten mir nur die Koordinaten.

Aber im Browser muss ich ja noch die Datenübernahme machen. Sowas mache 
ich normalerweise mit SpiderBasic und Inline-JS, wie: 
Beitrag "Browsercache ausschalten" aber die ganzen Callbacks 
schrecken mich wieder ab...

Gruss Chregu

von Christian M. (christian_m280)


Lesenswert?

Yalu X. schrieb:
> Die neu generierten Objekte sind in einer Gruppe zusammengefasst und
> sehen in der SVG-Datei wie folgt aus:

Hallo Yalu,

geht doch nicht so ganz einfach:

-einen Kreis (circle) kann ich nicht auf den Pfad anwenden, kommt ein 
Python-Error*. Und ein Path hat dann 8 Nodes und gibt viele Daten

-nachher muss ich noch "Zerlegen", damit es einzelne Objekte sind, aber 
das ist kein Problem

*
1
Traceback (most recent call last):
2
  File "pathalongpath.py", line 292, in <module>
3
    e.affect()
4
  File "inkex.py", line 289, in affect
5
    self.effect()
6
  File "pathalongpath.py", line 209, in effect
7
    self.prepareSelectionList()
8
  File "pathalongpath.py", line 145, in prepareSelectionList
9
    self.objectsToPaths(self.patterns)
10
  File "pathmodifier.py", line 241, in objectsToPaths
11
    newnode=self.objectToPath(node,doReplace)
12
  File "pathmodifier.py", line 235, in objectToPath
13
    inkex.errormsg(_("Please first convert objects to paths!  (Got [%s].)") % node.tag)
14
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 9: ordinal not in range(128)

Gruss Chregu

von Yalu X. (yalu) (Moderator)


Lesenswert?

Christian M. schrieb:
> Yalu X. schrieb:
>> Mit "Extensions/Generate from Path/Distribute Along Path"
>
> Das funktioniert hervorragend!

Christian M. schrieb:
> geht doch nicht so ganz einfach:

Was ist passiert? Ist zwischenzeitlich ein Meteorit eingeschlagen? ;-)

> Please first convert objects to paths!

Vermutlich hast du eine andere Inkscape-Version (ich habe 1.3.2), bei
der das zu verteilende Objekt zwingend ein Path sein muss (ein Kreis ist
keiner). Mit "Path/Object to Path" kannst du den Kreis in einen Path
konvertieren, dann sollte es funktionieren.

Bei mir werden nach der Konvertierung die Kreise durch vier
90°-Kreisbögen dargestellt:
1
      <path
2
         style="display:inline;fill:#ff0000;stroke-width:0.499999;stroke-linejoin:round"
3
         d="m 126.94166,196.50833 a 0.5,0.5 0 0 1 -0.5,0.5 0.5,0.5 0 0 1 -0.5,-0.5 0.5,0.5 0 0 1 0.5,-0.5 0.5,0.5 0 0 1 0.5,0.5 z"
4
         transform="translate(90.014, -40.156)"
5
         id="path2" />

Der Bezugspunkt liegt nun aber nicht mehr im Mittelpunkt des Kreises,
sondern an seinem rechten Rand. Das muss bei der Umrechnung in absolute
Koordinaten berücksichtigt werden, indem von der x-Koordinate noch der
Kreisradius (hier 0.5) subtrahiert wird.

von Christian M. (christian_m280)


Lesenswert?

Yalu X. schrieb:
> Vermutlich hast du eine andere Inkscape-Version (ich habe 1.3.2)

Habe 0.92, Windows. Habe mal eine neuere Version installiert gehabt, 
aber wieder gewechselt, bin nicht damit zurechtgekommen...

Habe unterdessen einen kurzen Strich genommen, der wird auch schön um 
die Kurven gelegt. Bekomme dann einen Datensatz wie:
1
    <path
2
       style="fill:none;stroke:#ff0000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
3
       d="m 175.32852,253.84516 c 0,0 -0.99999,0.005 -0.99999,0.005"
4
       id="path2380" />
und muss nur noch die zwei Zahlen nach d="m extrahieren. Das PureBasic 
Programm sieht so aus:
1
;Datei einlesen und Wegpunkte extrahieren
2
3
;Typische Zeile (nach Trim()):
4
;<path
5
;style="fill:none;stroke:#ff0000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
6
;d="m 175.32852,253.84516 c 0,0 -0.99999,0.005 -0.99999,0.005"
7
;id="path2380" />
8
9
text.s = ""
10
anzahlPunkte.u = 0
11
12
If ReadFile(0, "Layout_GB-Wegpunkte.svg")
13
  If OpenFile(1, "Tabelle-Wegpunkte.txt")
14
    While Eof(0) = 0
15
      text.s = ReadString(0, #PB_Ascii)
16
      text.s = Trim(text.s)
17
      If Mid(text.s, 1, 2) = "d="
18
        anzahlPunkte.u + 1
19
        text.s = StringField(text.s, 2, " ")
20
        WriteStringN(1, text.s)
21
      EndIf
22
    Wend
23
    Debug anzahlPunkte.u
24
    CloseFile(1)
25
  Else
26
    MessageRequester("Information", "Konnte Datei nicht öffnen zum Schreiben!")
27
  EndIf
28
  CloseFile(0)
29
Else
30
  MessageRequester("Information", "Konnte Datei nicht öffnen zum Lesen!")
31
EndIf
und in der Datei steht schön:
1
167.02807,253.86809
2
166.02808,253.87309
3
165.02809,253.87809
4
164.0281,253.88309
5
163.02811,253.88809
6
162.02813,253.89309
7
161.02814,253.89809
8
160.02815,253.90309
9
usw.

Jetzt noch Offset und Skallierung. Vielen Dank für die Hilfe!

Gruss Chregu

von Yalu X. (yalu) (Moderator)


Lesenswert?

Christian M. schrieb:
> Habe unterdessen einen kurzen Strich genommen

Ja, das geht natürlich auch. Der Strich ist wahrscheinlich das
einfachste Objekt, dass als Path durchgeht.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.