ich scheitere wieder einmal an der Geometrie.
Mein Program legt Bauklötzen (Länge = 3) entlang einer Linie. Also nicht wirklich Bauklötzchen,
nur so zur Veranschaulichung.
Dazu erhält es Kooridinaten von Punkten, durch die die Linie läuft.
Im Programm wird diese Linie durch die anfängliche blaue Linie angezeigt.
Das geht nun so:
Zuerst werden Klötzchen vom ersten Punkt zum zweiten Punkt in gerader Linie gelegt.
Dann wird die Entfernung zum nächsten Punkt und die Winkeldifferenz zu ihm berechnet.
Das Programm schwenkt nämlich nicht gleich auf den neuen Winkel ein, sondern
legt erst eine Kurve in Richtung auf den neuen Punkt. Dazu dreht es die nächsten
Klötzchen um jeweils einen bestimmten Winkelbetrag (Hier: 8 Grad) und legt sie aneinander,
bis ein Klötzchen so ungefähr in Richtung des neuen Punktes zeigt. Dann legte es weiter
Klötzchen in gerader Linie, bis es so etwa den neuen Punkt erreicht hat und peilt
dann den nächsten Punkt an und so weiter.
Das funktioniert auch ganz gut, aber: Unter bestimmten Bedingungen, ich weiß nicht welche,
dreht das Programm die Klötchen in die falsche Richtung und produziert so Kringel bis fast
zu Vollkreisen, bis es wieder in die richtige Richtung zeigt.
Das Problem liegt sicherlich darin, dem Programm zu sagen, wann es den Drehwinkel zum
Ankunftswinkel addieren und wann es ihn substrahieren muss. Ich kriege nur nicht heraus,
wie das richtig funktiniert.
Die geraden Linen werden bei "mit Kurven" gelb angezeigt, die Kurven selbst rot. Die gelben
Linien zeigen wegen der Kurven natürlich eine erhebliche Abweichung von der "Ideallinie",
macht aber nichts.
Das ganze ist nur ein sehr reduzierter Auszug aus dem Originalprogramm, das deutlich
komplexer ist. Insoweit wundere ich mich, dass ich das überhaupt hingekriegt habe
Um so doofer wäre es natürlich, wenn ich an den Kringeln scheitern würde.
Irgendeine Idee, wie ich für jeden Fall bestimme, ob das Programm beim
Drehen der Klötzchen den Drehwinkel addieren oder substrahiern muss?
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 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!
If newdegree1 - olddegree1 >= 0 : olddegree + abirration : If olddegree > newdegree : stop = 1 : EndIf : ;Original
Else : olddegree - abirration :If olddegree < newdegree : stop = 1 : EndIf
EndIf
;----------------------------
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