Bauklötzchen in Kurven legen/Kringel vermeiden
Verfasst: 23.10.2018 23:10
				
				Hallo,
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?
Edit by NicTheQuick: Zeile gekürzt
			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