[Monkey] [Monkey] SVG interpreter problem

Übersicht Andere Programmiersprachen Allgemein

Neue Antwort erstellen

 

PhillipK

Betreff: [Monkey] SVG interpreter problem

BeitragMi, Jul 10, 2013 14:19
Antworten mit Zitat
Benutzer-Profile anzeigen
Huhu Community mob!

Ich habe gestern spasseshalber angefangen, mir das SVG format (xml baum) unter die Lupe zu nehmen.
Zu diesem zweck habe ich mir erstmal das grundlegendste vorgenommen: Die Bezierkurve (die kubische!)

Das Rendern dieser Kurven habe ich schon gefühlte hundert mal geschrieben und das einzubauen ging recht flott. Das ergebnis passt - habs 1zu1 mit Inkscape verglichen und es passt.

Dann gings weiter: Den part aus der SVG datei rauskopieren und interpretieren. Bei einer einfachen kurve hat dies auch gut geklappt. Der aufbau ist wie folgt:

Code: [AUSKLAPPEN]
d="M x1,y1 C x2,y2 x3,y3, x4,y4"

d= startet die definition. In den anführungszeichen kommen die anweisungen:
M = MoveTo -> ausgangspunkt der Zeichnung.
x1,y1 stellen dementsprechend eine art Origin dar.

C leitet die Kubische bezierkurve ein. Hier finden sich immer 3 päärchen. nach dem schema wie oben.
x4,y4 stellen den "2ten" endpunkt der bezierkurve dar, x2,y2 und x3,y3 die "anfasser" -> bestimmung des kurvenverlaufes. Die anweisungen nach C beziehen sich als offset auf X1 und Y1. Mit diesen angaben lässt sich also die bezierkurve darstellen -> klappt, krieg ich hin.

Nun gehts weiter: Mehrere bezierkurven verbinden. Als beispiel habe ich ein kleines Herz gebastelt.
Der output in der datei sieht wie folgt aus:
Code: [AUSKLAPPEN]
d="M 243.02432,256.4018 C 127.08611,225.18767 75.0629,140.4929 133.77485,89.74063 c 63.73617,-55.095342 99.46845,35.9834 99.46845,35.9834 0,0 26.5589,-62.962455 91.77414,-50.142365 65.21524,12.82009 21.23704,92.147885 -14.99365,125.034205 -36.23069,32.88632 -60.31073,58.15485 -66.99947,55.78593 z"


Okay, das ist schon heftiger. Aber der aufbau bleibt gleich: immer 3 päärchen x2,y2 bis x4,y4
und weiter gehts mit x2,y2... bis zur anweisung Z -> endpunkt und startpunkt verbinden.
Weiterhin, alle päärchen sind offsets zum origin.

Nun das problem: Der kram wird richtig ausgelesen, alles richtig in die variablen eingelesen und passend mit einer funktion aufgerufen. Aber der output ist quatsch oO
Hat jemand eine ahnung ob ich das ganze falsch interpretiert habe?

Habe hier mal ein kleines bild gemacht:
user posted image

Die blauen knoten stellen die "bezierpunkte" dar, die Roten + linien stellen die "modifier" dar, mit einer linie auf ihre punkte.

Einen zusammehang erkenne ich nicht. Es passt nichts zusammen Sad

Hier noch der code, der die zeile interpretiert:

BlitzMax: [AUSKLAPPEN]
	Function DrawBezier:Int(line:String)
'd="m 41.416254,139.18428 c 0,0 16.667517,-74.246211 80.812206,-2.0203"
'd= is the required opener
'm is the "move to" command. it explains the starting point.
'c is the "cubic" modifier. It tells us, that 3 vectors are inside the package.

line = line.Trim()
line = line.ToLower()
line = line.Replace("~q", " ")
line = line.Replace("~t", " ")
Local tmpLen:Int = line.Length()

line = line.Replace(" ", " ")
While (tmpLen <> line.Length())
tmpLen = line.Length()

line = line.Replace(" ", " ")
Wend


Local parts:String[] = line.Split(" ")

Local p0:Vec2
Local p1:Vec2
Local p2:Vec2
Local p3:Vec2

Local beziers:List<Vec2> = New List<Vec2>

Print("ANFANG")
For Local i:Int = 0 Until parts.Length()
Select parts[i]
Case "d="
'opener
Case "m"
'median point
Local tmp:String[] = parts[i + 1].Split(",")

p0 = Vec2.Create(Float(tmp[0]), Float(tmp[1]))
beziers.AddLast(p0)
Print("V0: "+parts[i+1])
i = i + 1
Case "c"
'cubic modifier
'3 following vectors


For Local a:Int = i + 1 Until parts.Length() Step 3
'-> still something to read.
'-> No alphanumeric sign in this part?
If parts[a].Length() > 0 And Not IsAlphaNum(parts[a]) Then

Local v1:String = parts[a + 0]
Local v2:String = parts[a + 1]
Local v3:String = parts[a + 2]

Local tmp:String[] = v1.Split(",")
Print("V1: " + v1)
p1 = Vec2.Create(Float(tmp[0]), Float(tmp[1]))

tmp = v2.Split(",")
Print("V2: " + v2)
p2 = Vec2.Create(Float(tmp[0]), Float(tmp[1]))

tmp = v3.Split(",")
Print("V3: " + v3)
p3 = Vec2.Create(Float(tmp[0]), Float(tmp[1]))

i = i + 3

beziers.AddLast(p1)
beziers.AddLast(p2)
beziers.AddLast(p3)

Else
Exit
EndIf
Next
Case "q"
'Quadratic modifier

'2 following vectors
Local v1:String = parts[i + 1]
Local v2:String = parts[i + 2]

Local tmp:String[] = v1.Split(",")
p2 = Vec2.Create(Float(tmp[0]), Float(tmp[1]))

tmp = v2.Split(",")
p3 = Vec2.Create(Float(tmp[0]), Float(tmp[1]))


p1 = Vec2.Create(0, 0)

i = i + 2
Default
If parts[i].Length() > 0 Then Print("UNKNOWN:: " + i + " - len: " + parts[i].Length() + " ~q" + parts[i] + "~q")
End
Next


If p1 <> Null And p2 <> Null And p3 <> Null And p0 <> Null Then 'At least one full bezier set.
If beziers.Count() > 3 And (beziers.Count() -1) Mod 3 = 0 Then 'Is the list filled correctly?
Return DrawBezier(beziers) '-> render the list
EndIf
Return DrawBezier(p0, p1.Add(p0), p2.Add(p0), p3.Add(p0)) '-> Render the vectors
EndIf
End

(es ist monkey, kein blitzmax, aber die sprachen sind sich ähnlich genug.^^)
Intressant ist der "c" case, da die zeile nur cubic beziers enthält.

Das ganze läuft so ab:
1) Eine schleife liest die gesplitteten parts aus
2) Wenn ein "c" vorkommt, wird das nachfolgende in einer weiteren schleife ausgelesen
-> bis ein Alphanumerisches zeichen entdeckt wurde (a-z und A-Z)
3) Alle parts werden richtig eingelesen und in die liste gesteckt
4) Die liste wird ausgelesen: Code hier:
BlitzMax: [AUSKLAPPEN]
Function DrawBezier:Int(beziers:List<Vec2>)

Local p0:Vec2 = beziers.RemoveFirst()

Local p1:Vec2
Local p2:Vec2
Local p3:Vec2

For Local px:Vec2 = EachIn beziers
If Not p1 Then
p1 = px
ElseIf Not p2 Then
p2 = px
ElseIf Not p3 Then
p3 = px

DrawBezier(p0, p1.Add(p0), p2.Add(p0), p3.Add(p0))
p1 = Null
p2 = Null
p3 = Null
EndIf
Next

End

Anmerkung: Vec2 ist eine eigene miniklasse um 2d Vectoren zu behandeln.
ich adde auf p1 bis p3 immer p0, da ich mit den "totalen" positionen besser arbeiten kann. Aber wie gesagt, das funktioniert Sad
Also irgendwo... wo ist der verdammte fehler? oO

Holzchopf

Meisterpacker

BeitragMi, Jul 10, 2013 17:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Mein erster Gedanke (übrigens bestärkt durch die Tatsache, dass in deinem Code ein line.ToLower() auftaucht): Wahrscheinlich liegt einfach eine Unstimmigkeit bei absoluten und relativen Koordinaten vor. Grossbuchstaben = absolut, Kleinbuchstaben = relativ.

MfG
Holzchopf
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm
 

PhillipK

BeitragMi, Jul 10, 2013 19:57
Antworten mit Zitat
Benutzer-Profile anzeigen
Ah, ah... ah?
Mist verdammter.
Ich hatte mir eine seite durchgelesen, wo der aufbau der parameter beschrieben war. Dort wurden zwar explizit zb "C and c" erwähnt, aber beides zusammen als cubic bezier erklärt. Ein unterschied zwischen groß / klein wurde nicht erwähnt. Grummel ^^

Ich tests mal grade Smile (danke für den hinweis, HC!)

Edit:
Ach wär ja auch zu schön gewesen, wenns so was banales gewesen wäre.
Um das problem zu finden, habe ich mal 2 bezierkurven genommen, statt der 5 für das herz.
Witzig: Ich erkenne alle knoten wieder, so wie sie inkscape darstellt. aber es scheint als wäre die reihenfolge futsch Sad

Immerhin ein punkt zum ansetzen..

Edit2:

Ich habe mir grade nocheinmal andere "defintionen" angeschaut.
Eine davon gibt recht viel informationen, allerdings kapiere ich den text leider nicht ganz >.<
Zitat:
Draws a cubic Bézier curve from the current point to (x,y) using (x1,y1) as the control point at the beginning of the curve and (x2,y2) as the control point at the end of the curve. C (uppercase) indicates that absolute coordinates will follow; c (lowercase) indicates that relative coordinates will follow. Multiple sets of coordinates may be specified to draw a polybézier. At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybézier.

Wobei als parameter folgendes angegeben wird:
Code: [AUSKLAPPEN]
(x1 y1 x2 y2 x y)+


Das + scheint mir als "wiederholzeichen" zu diehnen, bedeutet das mein erster ansatz richtig ist: Mehrere sets von mit je 3 xy päärchen definieren mehrere linien.
Allerdings bin ich davon ausgegangen, das sich alle relativen koordinaten auf die MoveTo anweisung beziehen. Nach diesem text bin ich mir allerdings nichtmehr so sicher, denn hier
Code: [AUSKLAPPEN]
At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybézier.

klingt es so, als würde die MoveTo indirekt erneut verwendet werden: Die 2te bis nte bezier kurve beziehen sich immer auf den letzten punkt aus dem bezier n-1. Kurve eins bezieht sich auf die moveto anweisung, kurve 2 auf den letzten punkt von kurve eins.

Die absoluten koordinaten konnte ich auch nicht darstellen.

Ein rumspielen mit der XML datei hat gezeigt, das selbst "Totale koordinaten" relativ werden, sobald eine 2te bezierkurve ins spiel kommt.
Fragen über fragen und nun gut 20 ideen gesammelt, wie dieses bescheuerte format aufgebaut ist Sad
(und dabei ist die bezierkurve nur die spitze des eisberges ^^)

Anyways, ich knacke das bescheuerte rätsel heute noch D:

Neue Antwort erstellen


Übersicht Andere Programmiersprachen Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group