Bauklötzchen in Kurven legen/Kringel vermeiden
-
- Beiträge: 107
- Registriert: 08.03.2009 16:08
Re: Bauklötzchen in Kurven legen/Kringel vermeiden
Das sieht doch hervorragend aus! Die Absätze oder Brüche liegen, glaube ich, an den Originaldaten, die nicht so ganz zur obigen vereinfachten Version passen. Die Originallinie ist mehrfach unterbrochen und nochmals unterteilt. Dehalb habe ich die der erste Prozedur makeCoordinatesList(posxystring$) nur alle zweiten Koorinaten eingelesen " for ... Step 2); möglicherweise wird deshalb mitunter an den falschen Punkten angesetzt.
Ich baue das mal in das eigentliche Programm ein und melde mich dann, erst einmal vielen Dank an alle!
Mein Progammierstil scheint ja noch schlechter zu sein als befürchtet.
Ich baue das mal in das eigentliche Programm ein und melde mich dann, erst einmal vielen Dank an alle!
Mein Progammierstil scheint ja noch schlechter zu sein als befürchtet.
- NicTheQuick
- Ein Admin
- Beiträge: 8675
- Registriert: 29.08.2004 20:20
- Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti - Wohnort: Saarbrücken
- Kontaktdaten:
Re: Bauklötzchen in Kurven legen/Kringel vermeiden
Oder man schreibt einfach
Code: Alles auswählen
_diff - 360
Re: Bauklötzchen in Kurven legen/Kringel vermeiden
@nic, das könnte sein
übrigens, je nachdem was dein Code so macht, behalte im Hinterkopf (oder wo auch immer) das z.b. bei +/-abbiration (oder generell beim ändern eines Winkelwertes) ein Wert außerhalb von 0..360 rauskommen könnte. den PB Winkel-Funktionen ist das aber vermutlich egal.
übrigens, je nachdem was dein Code so macht, behalte im Hinterkopf (oder wo auch immer) das z.b. bei +/-abbiration (oder generell beim ändern eines Winkelwertes) ein Wert außerhalb von 0..360 rauskommen könnte. den PB Winkel-Funktionen ist das aber vermutlich egal.
-
- Beiträge: 107
- Registriert: 08.03.2009 16:08
Re: Bauklötzchen in Kurven legen/Kringel vermeiden
Also ich weiß ja nicht, wie groß der Schritt für die Menschheit ist, aber für mich ... Der Einbau hat auf Anhieb geklappt, ich da habe auch noch einmal richtig herumgemalt, nirgendwo ein Kringel oder eine Kurve falschrum. Ein wenigen Fällen wird zwar nur ein einziges gedrehtes Klötzschen gesetzt, so dass die Kurve da reichlich eckig ist, das liegt aber vermutlich an Randbedingungen, die ich noch anpassen muss. Jedenfalls besteht kein Zusammenhang mit den Absätzen oder Brüchen.
Ich hatte da schon einige Zeit ohne Erfolg herumgeknobelt und dachte schon, das wird nix mehr, also nochmals vielen Dank.
Bei den Winkelsummen steht bei mir eigentlich immer so etwas : If degree > 360 : degree = degree - 360 : endif
Aber pure basic scheinen Winkel > 360 oder < 0 in der Tat nicht zu stören.
Ich hatte da schon einige Zeit ohne Erfolg herumgeknobelt und dachte schon, das wird nix mehr, also nochmals vielen Dank.
Bei den Winkelsummen steht bei mir eigentlich immer so etwas : If degree > 360 : degree = degree - 360 : endif
Aber pure basic scheinen Winkel > 360 oder < 0 in der Tat nicht zu stören.
Re: Bauklötzchen in Kurven legen/Kringel vermeiden
Ich denke mal, dass manche Ecken so eckig sind passiert wenn die Winkeländerung über den 0-Punkt geht.
z.b. von 350° nach 10°, dann ist diff = +20, also erster If-Zweig, aber gleich mit dem ersten Schritt ist 358° ja schon größer als 10°, also stop=1.
z.b. von 350° nach 10°, dann ist diff = +20, also erster If-Zweig, aber gleich mit dem ersten Schritt ist 358° ja schon größer als 10°, also stop=1.
-
- Beiträge: 107
- Registriert: 08.03.2009 16:08
Re: Bauklötzchen in Kurven legen/Kringel vermeiden
Ach so. Ich hatte eine Funktion im Verdacht, die den Rotationswinkel ändert.
Ich versuche erst einmal, ob ich die Knicke selbst rundbiegen kann.
Ich versuche erst einmal, ob ich die Knicke selbst rundbiegen kann.
-
- Beiträge: 107
- Registriert: 08.03.2009 16:08
Re: Bauklötzchen in Kurven legen/Kringel vermeiden
Auch das mit dem Durchgang über die 360 Grad kriege ich nicht hin. Die Idee war, die Winkeldifferenz zum nächsten Wegpunkt zu bestimmen, daraus und aus der Winkeländerung jedes Klötzchens (hier 8 Grad pro Klotz) deren nötige Anzahl zu bestimmen und dann einfach diese Anzahl zu legen. Das wäre dann aquivalent zu "until olddegree >= newdegree". Dabei wollte ich dann auch die Info benutzen, ob der Winkel links oder rechts dreht (_diff > oder < 0)
Ich schaffe es aber nicht einmal die Winkeldifferenz zu bestimmtn. Die vom Programm berechneten Winkel (olddegree/newdegree) sind komisch, ich kann sie nicht nachvollziehen. So ganz falsch können sie aber auch nicht sein, das ganze funktioniert ja
Gibt es dafür eine Lösung?
Ich schaffe es aber nicht einmal die Winkeldifferenz zu bestimmtn. Die vom Programm berechneten Winkel (olddegree/newdegree) sind komisch, ich kann sie nicht nachvollziehen. So ganz falsch können sie aber auch nicht sein, das ganze funktioniert ja
Gibt es dafür eine Lösung?
Re: Bauklötzchen in Kurven legen/Kringel vermeiden
folgende Änderungen:
- Procedure.f normalizeAngle(a.f)
- Procedure.f angleDiff(aFrom.f, aTo.f)
--- normalisiert die Eingabewinkel zuerst, damit wird z.b. -2*360 zu 0 wird
--- prüft jetzt auch den Überlauf in die andere Richtung, also wenn diff < -180
- unittest (CompilerIf)
- der Hauptcode prüft jetzt für den stop nach Änderung des Winkels, ob diff sich umgekehrt hat; olddegree wird nach Änderung sicherheitshalber nochmal normalisiert.-
Einmal komplett (die Absätze sind wie gehabt, aber die eckigen Ecken sind jetzt rund):
- Procedure.f normalizeAngle(a.f)
Code: Alles auswählen
Procedure.f normalizeAngle(a.f)
; normalisieren zu 0..360
While a < 0
a + 360
Wend
While a >= 360
a - 360
Wend
ProcedureReturn a
EndProcedure
--- normalisiert die Eingabewinkel zuerst, damit wird z.b. -2*360 zu 0 wird
--- prüft jetzt auch den Überlauf in die andere Richtung, also wenn diff < -180
Code: Alles auswählen
Procedure.f angleDiff(aFrom.f, aTo.f)
Protected aDiff.f
aDiff = normalizeAngle(aTo) - normalizeAngle(aFrom)
; bei mehr als einer halben drehung, die andere richtung nehmen
If aDiff >= 180
aDiff - 360
EndIf
If aDiff <= -180
aDiff + 360
EndIf
ProcedureReturn aDiff
EndProcedure
Code: Alles auswählen
; unittest
CompilerIf 0
Define.f a1, a2
a1 = 0.0 : a2 = 45.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 45
a1 = 90.0 : a2 = 80.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -10
a1 = 170.0 : a2 = 190.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 20
a1 = 100.0 : a2 = 260.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 160
a1 = 90.0 : a2 = 270.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 180
a1 = 80.0 : a2 = 280.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -160
a1 = 10.0 : a2 = 350.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -20
a1 = 10.0 : a2 = 360.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -10
a1 = 10.0 : a2 = 0.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -10
a1 = 360.0 : a2 = 350.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -10
a1 = 0.0 : a2 = 350.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -10
a1 = -45.0 : a2 = 0.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 45
a1 = -45.0 : a2 = -90.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2); -45
; -10 -> 10
a1 = -4*360-10 : a2 = -2*360+10 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 20
; 10 -> -10
a1 = 4*360+10 : a2 = 2*360-10 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -20
End
CompilerEndIf
Code: Alles auswählen
_diff.f = angleDiff(olddegree1, newdegree1)
If _diff >= 0
olddegree + abirration
If angleDiff(olddegree, newdegree) <= 0
stop = 1
EndIf : ;Original
Else
olddegree - abirration
If angleDiff(olddegree, newdegree) >= 0
stop = 1
EndIf
EndIf
olddegree = normalizeAngle(olddegree)
Code: Alles auswählen
Structure coordinates
x.i
y.i
EndStructure
Global NewList coordinates.coordinates()
Procedure makeCoordinatesList(posxystring$)
number = CountString(posxystring$,",")
For loop = 1 To number Step 2 ; Step 2, weil hier die Lücken zwischen den Abschnitten aus dem Original fehlen
AddElement(coordinates())
With coordinates()
\x = Val(StringField(posxystring$,loop,","))
\y = Val(StringField(posxystring$,loop + 1,","))
EndWith
Next
EndProcedure
Procedure.f ATan3(y.i,x.i)
If y > 0 And x < 0 ; links oben
ProcedureReturn ATan(y/x) * 180/#PI +180
ElseIf y < 0 And x < 0 ; links unten
ProcedureReturn ATan(y/x) *180/#PI + 180
ElseIf y < 0 And x > 0 ; rechts unten
ProcedureReturn ATan(y/x) *180/#PI + 360
ElseIf y > 0 And x > 0; rechts oben
ProcedureReturn ATan(y/x) *180/#PI
ElseIf y < 0 And x = 0 ; links (x u. y vertauscht wg. Koordinatensystem! Real also x < 0, y = 0)
ProcedureReturn 270
ElseIf y > 0 And x = 0 ; rechts ( "" )
ProcedureReturn 90
ElseIf y = 0 And x < 0 ; unten ( "" )
ProcedureReturn 180
ElseIf y = 0 And x > 0 ; oben ( "" )
ProcedureReturn 360
EndIf
EndProcedure
Procedure.s plotlineLow(x1,y1,x2,y2,image,colour)
colour = RGB(0,0,255)
dx = x2 - x1
dy = y2 - y1
yi = 1
If dy < 0
yi = -1
dy = -dy
EndIf
D = 2*dy - dx
y = y1
StartDrawing(ImageOutput(image))
For x = x1 To x2
Plot(x,y,colour)
If D > 0
y = y + yi
D = D - 2*dx
EndIf
D = D + 2*dy
Next
StopDrawing()
EndProcedure
Procedure.s plotLineHigh(x1,y1,x2,y2,image,colour)
colour = RGB(0,0,255)
dx = x2 - x1
dy = y2 - y1
xi = 1
If dx < 0
xi = -1
dx = -dx
EndIf
D = 2*dx - dy
x = x1
StartDrawing(ImageOutput(image))
For y = y1 To y2
Plot(x,y,colour)
If D > 0
x = x + xi
D = D - 2*dy
EndIf
D = D + 2*dx
Next
StopDrawing()
EndProcedure
Procedure selectPlotHighLow(x1,y1,x2,y2,image,colour)
If Abs(y2 - y1) < Abs(x2 - x1)
If x1 > x2
plotLineLow(x2, y2, x1, y1,image,colour)
Else
plotLineLow(x1,y1, x2,y2,image,colour)
EndIf
Else
If y1 > y2
plotLinehigh(x2, y2, x1, y1,image,colour)
Else
plotLinehigh(x1, y1, x2, y2,image,colour)
EndIf
EndIf
EndProcedure
Procedure.f getDistance(startX,startY,endX,endY)
xDistanceSquare = (endX - startX) * (endX - startX)
yDistanceSquare = (endY - startY) * (endY - startY)
distance.f = Sqr(xDistanceSquare + yDistanceSquare)
ProcedureReturn distance
EndProcedure
Procedure.f normalizeAngle(a.f)
; normalisieren zu 0..360
While a < 0
a + 360
Wend
While a >= 360
a - 360
Wend
ProcedureReturn a
EndProcedure
Procedure.f angleDiff(aFrom.f, aTo.f)
Protected aDiff.f
aDiff = normalizeAngle(aTo) - normalizeAngle(aFrom)
; bei mehr als einer halben drehung, die andere richtung nehmen
If aDiff >= 180
aDiff - 360
EndIf
If aDiff <= -180
aDiff + 360
EndIf
ProcedureReturn aDiff
EndProcedure
; unittest
CompilerIf 0
Define.f a1, a2
a1 = 0.0 : a2 = 45.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 45
a1 = 90.0 : a2 = 80.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -10
a1 = 170.0 : a2 = 190.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 20
a1 = 100.0 : a2 = 260.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 160
a1 = 90.0 : a2 = 270.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 180
a1 = 80.0 : a2 = 280.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -160
a1 = 10.0 : a2 = 350.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -20
a1 = 10.0 : a2 = 360.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -10
a1 = 10.0 : a2 = 0.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -10
a1 = 360.0 : a2 = 350.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -10
a1 = 0.0 : a2 = 350.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -10
a1 = -45.0 : a2 = 0.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 45
a1 = -45.0 : a2 = -90.0 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2); -45
; -10 -> 10
a1 = -4*360-10 : a2 = -2*360+10 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; 20
; 10 -> -10
a1 = 4*360+10 : a2 = 2*360-10 : Debug "" + a1 + " -> " + a2 + " = " + angleDiff(a1, a2) ; -20
End
CompilerEndIf
Procedure makeLinesWithCurves(image,colour)
length.f = 3; Länge der "Bauklötzchen", hier = 4 pixel
ForEach coordinates()
If run = 0 ; erster Abschnitt noch ohne Kurven
startx = coordinates()\x ; Anfang der Linienabschnitte
starty = coordinates()\y
EndIf
If NextElement(coordinates())
endx = coordinates()\x ; Ende der Linienabschnitte
endy = coordinates()\y
If Not ListIndex(coordinates()) = ListSize(coordinates()) ; letztes Element ist bereits erreicht - nix mehr malen
distance.f = getDistance(startX,startY,endX,endY) ; Entfernung zwischen zwei Punkten
olddegree.f = degree.f ; Letzer Winkel eines Abschnittes
olddegree1.f = degree.f
degree.f = ATan3(endx-startx, endy-starty) ; Winkel zun nächsten Punkt(aktueller Winkel)
Debug StrF(degree,2) ; Im Original ist das Koordinatensystem verdreht (Atan3), deshalb werden die Winkel scheinbar falsch angezeigt, ist aber berücksichtigt
newdegree.f = degree.f ; aktueller Winkel
newdegree1.f = degree.f
abirration = 8 ; Winkeländerung in der Kurve pro Pixel
; Kurven legen .................................
If curve ; 1 Abschnitt keine Kurve
stop = 0
StartDrawing(ImageOutput(image))
; Anfang Kurven legen, Farbe = Rot
Repeat
;-------------------------------
; Hier wird bestimmt, ob der Winkel in der Kurve gegenüber dem Ankunftswinkel (olddegree) vergrößert oder verkleinert wird.
; Und das kriege ich nicht hin - siehe die Kringel beim Kurvenzeichnen!
_diff.f = angleDiff(olddegree1, newdegree1)
If _diff >= 0
olddegree + abirration
If angleDiff(olddegree, newdegree) <= 0
stop = 1
EndIf : ;Original
Else
olddegree - abirration
If angleDiff(olddegree, newdegree) >= 0
stop = 1
EndIf
EndIf
olddegree = normalizeAngle(olddegree)
;----------------------------
sinus.f = Sin(Radian(olddegree.f))
cosinus.f = Cos(Radian(olddegree.f))
slX.f = (sinus.f * length.f); Berechnet Veränderung von x im Winkel auf der Strecke.
slY.f = (cosinus.f * length.f) ; berechnet Veränderung von y im Winkel aif der Strecle
degree.f = ATan3(endx-startx, endy-starty) ; Berechnet den aktuellen Winkel zum Zielpunkt nach Setzen eines Klötzchens
Plot(startx,starty,RGB(255,0,0))
startX = startX + slX ; Veränderung startx/starty = x/y-Koordinaten nach dem Setzen eines Klötchens
startY = startY + slY
Until stop ; Olddegree = ankunftswinkel ist jetzt wegen +/- abirration so ungefähr gleich dem Zielwinkel
StopDrawing()
EndIf
; ;ende Kurven legen .................................
degree.f = ATan3(endx-startx, endy-starty) ; Winkel vom Kurvenende zum nächsten Punkt/Gerade Linie
distance.f = getDistance(startX,startY,endX,endY) ; NeuBerechnung der Entfernung
sinus.f = Sin(Radian(degree))
cosinus.f = Cos(Radian(degree))
slX.f = (sinus * length.f); Berechnet Veränderung von x im Winkel auf der strecke
slY.f = (cosinus * length.f) ; berechnet Veränderung von y im Winkel
;Gerade Linie
StartDrawing(ImageOutput(image))
While distance.f > 0; Abbruch wenn, wenn Entfrnung negativ, Zilpunkt ist mehr oder weniger erreicht
Plot(startX,startY,RGB(234,255,0))
startX = startX + slX ; veränderung startx in der Schleife/Nächste Platte;
startY = startY + slY
distance.f = distance.f - length.f
Wend
StopDrawing()
curve + 1 ; erster Abschnitt ist eine Gerade, ab jetzt Kurven
EndIf
EndIf
Next ;Foreach roads()1
EndProcedure
Procedure makeLines(image,colour)
ForEach coordinates()
With coordinates()
startx = \x
starty = \y
EndWith
If endx ; Daher keine Linie zum ersten Punkt
selectPlotHighLow(startx,starty,endx,endy,image,colour) ; Erstmal gerade Linie zum nächsten Punkt
EndIf
endx = startx
endy = starty
Next
EndProcedure
Global imagewidth = 1400
Global imagehight = 900
window = OpenWindow(#PB_Any,300,50,imagewidth,imagehight,"Bauklötzchen",#PB_Window_MinimizeGadget| #PB_Window_MaximizeGadget|#PB_Window_SizeGadget)
image = CreateImage(#PB_Any,imagewidth,imagehight,24,RGB(110,110,110))
imgad = ImageGadget(#PB_Any,0,0,imagewidth,imageheight,ImageID(image))
;x/y-Koordinaten
posXYstring$ = "228,605,193,496,193,495,225,432,226,430,271,388,272,388,336,409,337,410,371,457,372,458,337,512,335,514,334,549,334,549,384,587,384," +
"587,433,633,435,635,439,672,439,672,508,640,510,638,482,573,481,571,448,525,447,523,507,481,508,480,506,430,506,430,521,384,522,383," +
"677,376,680,376,715,437,715,437,661,497,659,498,596,491,594,490,574,544,574,546,649,599,649,599,708,616,710,616,727,660,727,663,683," +
"693,680,694,770,739,770,739,856,696,856,696,803,618,802,616,798,539,798,538,856,508,856,508,793,451,792,450,819,397,819,397,894,384," +
"897,384,977,334,978,333,958,148,958,147,794,87,793,87,635,120,632,121,600,170,600,170,644,253,645,255,753,275,754,275,833,251,836,250,764,189,"
makeCoordinatesList(posXYstring$)
makeLines(image,3) ; 3 = blau
ResizeGadget(imgad, 0,0,#PB_Ignore,#PB_Ignore)
Repeat
event = WaitWindowEvent()
If message = 0
message = MessageRequester("Test", "Linien mit Kurven auf 'OK' klicken",#PB_MessageRequester_Ok)
makeLinesWithCurves(image,2) ;2 = Grün
ResizeGadget(imgad, 0,0,#PB_Ignore,#PB_Ignore)
EndIf
If event = #PB_Event_CloseWindow
close = 1
EndIf
Until close
Re: Bauklötzchen in Kurven legen/Kringel vermeiden
Noch ein Hinweis..
Winkeldifferenzen darfst du mit der obigen Funktion nicht normalisieren, sondern nur absolute Winkel.
Bei dir sind absolute Winkel ja im Bereich 0..360, und Winkeldifferenzen im Bereich -180..0..180.
Generell ist es vielleicht einfacher, auch alle absoluten Winkel im selben Bereich -180..180 zu speichern, macht aber nicht wirklich einen Unterschied.
Winkeldifferenzen darfst du mit der obigen Funktion nicht normalisieren, sondern nur absolute Winkel.
Bei dir sind absolute Winkel ja im Bereich 0..360, und Winkeldifferenzen im Bereich -180..0..180.
Generell ist es vielleicht einfacher, auch alle absoluten Winkel im selben Bereich -180..180 zu speichern, macht aber nicht wirklich einen Unterschied.
-
- Beiträge: 107
- Registriert: 08.03.2009 16:08
Re: Bauklötzchen in Kurven legen/Kringel vermeiden
Fantastisch. habe ich natürlich gleich eingebaut, scheint prima zu funktionieren. Am Wochenende werde ich dann mal versuchen, das Ganze auch zu verstehen. Nochmals vielen Dank!