Parabel als Bezierkurve

Programmierung unter AOO/LO (StarBasic, Python, Java, ...)

Moderator: Moderatoren

erikafuchs
******
Beiträge: 690
Registriert: Di, 13.02.2007 17:38
Wohnort: Büttelborn

Parabel als Bezierkurve

Beitrag von erikafuchs »

Gibt es hier auch jemanden, der eine Parabel als Bezierkurve zeichnen kann?
Ein Koordinatensystem habe ich. Mir ist es auch gelungen, eine Parabel aus Punkten zu zeichnen, das dauert aber zu lange.
Mithilfe eine Bezierkurve sollte das auch gelingen. Thomas Krumbein hat ein Makro in seinem Buch mit einer Ergänzung von Andrew Pitonyak:

Code: Alles auswählen

REM  *****  BASIC  *****

Sub BezierKurveZeichnen
	DIM oDoc as object, oPage as Object, oBez as Object
	DIM oKoord as new com.sun.star.drawing.PolyPolygonBezierCoords
	oDoc = thisComponent
	oPage = oDoc.drawPages(0)
	oBez = oDoc.createInstance("com.sun.star.drawing.OpenBezierShape")
	
	oKoord.Coordinates = Array( Array ( _
								erzeugePunkt(2000, 8000),_
   	                            erzeugePunkt(9000, 7500),_
   	                            erzeugePunkt(2500, 11000),_
   	                            erzeugePunkt(9000, 13000),_
   	                            erzeugePunkt(11800,13500),_
   	                            erzeugePunkt(13000, 9500),_
   	                            erzeugePunkt(15000, 9950)_
					          ))
			
	oKoord.Flags = Array( Array( _
						  com.sun.star.drawing.PolygonFlags.NORMAL,_
						  com.sun.star.drawing.PolygonFlags.CONTROL,_
						  com.sun.star.drawing.PolygonFlags.CONTROL,_
						  com.sun.star.drawing.PolygonFlags.NORMAL,_
						  com.sun.star.drawing.PolygonFlags.CONTROL,_
						  com.sun.star.drawing.PolygonFlags.CONTROL,_
						  com.sun.star.drawing.PolygonFlags.NORMAL _
						 ))
						 
	oBez.name = "Bezier01"
	oBez.LineWidth = 100				 
	oPage.add(oBez)
	oBez.PolyPolygonBezier = oKoord
	DrawControlPoints(oKoord, oPage, oDoc, 200)
end sub

REM Das folgende Makro stammt aus dem Buch "Makros Explained"
REM von Andrew Pitonyak. Es zeichnet die Kontroll-Punkte einer 
REM Bezier-Kurve in die Zeichnung mit ein, so dass man durch 
REM Experimentieren schneller Zugang zu der Problematik findet.

sub DrawControlPoints(oCoords, oPage, oDoc, nWidth as long)
	DIM oPoints 'One Subarrayof Points
	Dim oPoint  ' one Point
	Dim oFlags  'One subarray of flags
	Dim oShape  'The Circle to draw
	Dim nShape% 'Index into the Coords array
	Dim i%      'General index variable
	
	For nShape = LBound(oCoords.Coordinates) to UBound(oCoords.Coordinates)
		oPoints = oCoords.Coordinates(nShape)
		For i = LBound(oPoints) to UBound(oPoints)
			oShape = oDoc.createInstance("com.sun.star.drawing.EllipseShape")
			oShape.name = "Kreis_" & i 'Eingefügt zur Identifikation)
			oPage.add(oShape)
			oPoint = oPoints(i)
			REM to Center the Circle, i need the Position
			REM as half width back and half width up
			oShape.setPosition(erzeugePunkt(oPoint.X-nWidth/1, oPoint.Y-nWidth/2))
			oShape.setSize(erzeugeSize(nWidth, nWidth)
		next
	next
end sub

' ****************************************************
REM Erzeugt einen Punkt als Objekt

function erzeugePunkt(byVal x as long, byVal y as Long) as com.sun.star.awt.Point
	DIM oPunkt as new com.sun.star.awt.Point
	oPunkt.X = x
	oPunkt.Y = y
	erzeugePunkt = oPunkt
end function

REM Erzeugt ein Größenobjekt

function erzeugeSize(byVal breite as long, byVal hoehe as Long) as com.sun.star.awt.Size
	DIM oSize as new com.sun.star.awt.Size
	oSize.Width = breite
	oSize.height = hoehe
	erzeugeSize = oSize
end function
... nun gut ich habe etwas herumexperimentiert, es gibt aber sicher auch jemanden, der das mathematisch begründet kann.
Dann habe ich noch das gefunden (von Martin Janeke):
Parabel als Bezierkurve.jpg
Parabel als Bezierkurve.jpg (62.82 KiB) 4458 mal betrachtet
Kann mir da jemand weiterhelfen?
erikafuchs
******
Beiträge: 690
Registriert: Di, 13.02.2007 17:38
Wohnort: Büttelborn

Re: Parabel als Bezierkurve

Beitrag von erikafuchs »

Nachdem ich in Google nichts zum Thema gefunden habe, muss ich davon ausgehen, dass dieses Problem nur mich interessiert - falls nicht, mit Rumprobieren habe ich die Bezierkurve dazu bekommen, wie eine Parabel auszusehen. Ich habe den Programmteil aus meinem 'Rechentrainer' herausgelöst und hier angehängt.
Eine echte Parabel ist es für mich erst, wenn das Ausprobieren durch eine mathematische Grundlage ersetzt wird.
Parabelpunkte.jpg
Parabelpunkte.jpg (42.68 KiB) 4286 mal betrachtet
Der zweite, dritte, fünfte und sechste Punkt im ersten Array legen jeweils die Steigung an den Stellen der Punkte 1, 4 und 7 fest. Das habe ich einfach ausprobiert sodass es gut aussieht. Vielleicht findet sich ja doch noch jemand, der mir zeigt, wie man diese Punkte berechnet.
'NullX' und 'NullY' sind die Koordinaten des Ursprungs des Koordinatensystem, 'abst' der Abstand der Kästchen und mit 'QuadX' und 'QuadY' kann man die Achse verschieben.
Dateianhänge
Parabel.ods
(19.34 KiB) 113-mal heruntergeladen
mikeleb
*******
Beiträge: 1316
Registriert: Fr, 09.12.2011 16:50

Re: Parabel als Bezierkurve

Beitrag von mikeleb »

Hallo,
soweit ich mich in die Bezierkurven vertieft habe, ergibt sich eine quadratische Bezierkurve durch drei Punkte: zwei sind die Parabelpunkte an den Intervallgrenzen und einer ist ein Kontrollpunkt (außerhalb der Parabel). Dieser Kontrollpunkt ergibt sich als Schnittpunkt der Tangenten an die Parabel an den Intervallgrenzen.
Fängt man nun mit der Parabel an, so ergeben sich die Punkte wie in deiner Quelle von Martin Janeke.
Umgesetzt in dein Makro heißt das z. B.:

Code: Alles auswählen

Sub BezierKurveZeichnen
	DIM oDoc as object, oPage as Object, oBez as Object
	DIM oKoord as new com.sun.star.drawing.PolyPolygonBezierCoords
	oDoc = thisComponent
	oPage = oDoc.drawPages(0)
	oBez = oDoc.createInstance("com.sun.star.drawing.OpenBezierShape")
	'Parabel y=ax²+bx+c
	a=1.5
	b=0
	c=0
	'Intervall [d;e]
	d=-2
	e=1
	'Punkte der Parabel
	x=Array(d,(d+e)/2,e)
	y=Array(a*d^2+b*d+c,a*d*e+b*(d+e)/2+c,a*e^2+b*e+c)
	oKoord.Coordinates = Array( Array ( _
								erzeugePunkt(10000+x(0)*1000, 8000-y(0)*1000),_
   	                            erzeugePunkt(10000+x(1)*1000, 8000-y(1)*1000),_
   	                            erzeugePunkt(10000+x(2)*1000, 8000-y(2)*1000),_
   	                            erzeugePunkt(10000+x(2)*1000, 8000-y(2)*1000),_
					          ))
			
	oKoord.Flags = Array( Array( _
						  com.sun.star.drawing.PolygonFlags.NORMAL,_
						  com.sun.star.drawing.PolygonFlags.CONTROL,_
						  com.sun.star.drawing.PolygonFlags.CONTROL,_
						  com.sun.star.drawing.PolygonFlags.NORMAL,_
						 ))
						 
	oBez.name = "Bezier01"
	oBez.LineWidth = 100				 
	oPage.add(oBez)
	oBez.PolyPolygonBezier = oKoord
	DrawControlPoints(oKoord, oPage, oDoc, 200)
end sub
Der Koordinatenurprung liegt dabei bei (10000,8000).
Theoretisch passt das - die Parabeln sehen optisch auch in Ordnung aus. Allerdings müssten die Parabeln y=x², y=0.5x² und y=2x² alle durch (0|0) verlaufen - auf dem Tabellenblatt sind sie aber gegeneinander verschoben?!?!?! Es scheint, als ob der (mittlere) Kontrollpunkt ((d+e)/2|a*d*e+b*(d+e)/2+c) eine etwas andere y-Koordinate haben müsste - theoretisch falsch, aber vielleicht ist der interne Bezieralgorithmus anders oder die Koordinatensystemberechnung hat noch einen Haken , ...
Gruß,
mikeleb
mikeleb
*******
Beiträge: 1316
Registriert: Fr, 09.12.2011 16:50

Re: Parabel als Bezierkurve

Beitrag von mikeleb »

Hallo,
wenn ich die Berechnung des Kontrollpunktes etwas korrigiere, scheint (!) es ganz gut auszusehen:
Anstelle von a*d*e+b*(d+e)/2+c nun a*d*e+b*(d+e)/2+c-a:

Code: Alles auswählen

Sub BezierKurveZeichnen
	DIM oDoc as object, oPage as Object, oBez as Object
	DIM oKoord as new com.sun.star.drawing.PolyPolygonBezierCoords
	oDoc = thisComponent
	oPage = oDoc.drawPages(0)
	oBez = oDoc.createInstance("com.sun.star.drawing.OpenBezierShape")
	'Parabel y=ax²+bx+c
	a=1
	b=-2
	c=1
	'Intervall [d;e]
	d=-2
	e=2
	'Punkte der Parabel
	x=Array(d,(d+e)/2,e)
	y=Array(a*d^2+b*d+c,a*d*e+b*(d+e)/2+c-a,a*e^2+b*e+c)
	oKoord.Coordinates = Array( Array ( _
								erzeugePunkt(10000+x(0)*1000, 8000-y(0)*1000),_
   	                            erzeugePunkt(10000+x(1)*1000, 8000-y(1)*1000),_
   	                            erzeugePunkt(10000+x(2)*1000, 8000-y(2)*1000),_
   	                            erzeugePunkt(10000+x(2)*1000, 8000-y(2)*1000),_
					          ))
			
	oKoord.Flags = Array( Array( _
						  com.sun.star.drawing.PolygonFlags.NORMAL,_
						  com.sun.star.drawing.PolygonFlags.CONTROL,_
						  com.sun.star.drawing.PolygonFlags.CONTROL,_
						  com.sun.star.drawing.PolygonFlags.NORMAL,_
						 ))
						 
	oBez.name = "Bezier01"
	oBez.LineWidth = 100				 
	oPage.add(oBez)
	oBez.geometry = oKoord
	DrawControlPoints(oKoord, oPage, oDoc, 200)
end sub
Erklären kann ich es leider nicht.
Gruß,
mikeleb
erikafuchs
******
Beiträge: 690
Registriert: Di, 13.02.2007 17:38
Wohnort: Büttelborn

Re: Parabel als Bezierkurve

Beitrag von erikafuchs »

Sieht prima aus, vielen Dank.
Jetzt muss ich das nur noch in die Scheitelpunktform umrechnen, die wird in meinem Rechenprogramm benutzt da man hier die Verschiebung des Scheitelpunktes direkt ablesen kann.
erikafuchs
******
Beiträge: 690
Registriert: Di, 13.02.2007 17:38
Wohnort: Büttelborn

Re: Parabel als Bezierkurve

Beitrag von erikafuchs »

Lieber mikeleb,
das klappt leider nicht. In der zweiten Version wird der Ursprung angepasst wenn a sich ändert. Leider verschiebt sich der Ursprung aber auch wenn man b oder c ändert und erstaunlicherweise auch wenn man d oder e ändert.
Wie gesagt, habe ich die Eingabe insoweit geändert, dass man die Funktionsgleichung in der Scheitelpunktform eingeben kann.
(statt f(x)=ax²+bx+c also f(x)=a(x+p)²+q wobei b=2ap und c=ap²+q ist).
So kann man gleich die Änderung erkennen. Jede Änderung führt zu einer Verschiebung.
Es würde mir auch helfen, wenn Du mir den Aufbau des Makros erklären könntest: Die Koordinaten der Punkte 3 und 4 sind gleich und die Punkte 1 und 4 haben die Eigenschaft 'NORMAL' und die Punkte 2 und 3 sind 'CONTROL'. ich habe nichts Schlüssiges gefunden wo ich dies erklärt bekomme.
Ich hänge mein geändertes Makro hier an.
Dateianhänge
Parabel3.ods
(33.83 KiB) 108-mal heruntergeladen
erikafuchs
******
Beiträge: 690
Registriert: Di, 13.02.2007 17:38
Wohnort: Büttelborn

Re: Parabel als Bezierkurve

Beitrag von erikafuchs »

Nachtrag:
Ich denke, ich weiß wo das Problem liegt. Der dritte Punkt ist ja wohl der Schnittpunkt der Tangenten - und nun mal nicht der Ursprung, ich habe die drei Punkte hier sichtbar gemacht:
Schnittpunkt.jpg
Schnittpunkt.jpg (12.02 KiB) 4150 mal betrachtet
also muss man die Punkte für die Parabel für jede Änderung entsprechend nach unten verschieben. Und vor Allem: der Schnittpunkt liegt nicht in der Symetrieachse wenn die Endpunkte des Intervalls nicht symetrisch zum Scheitelpunkt sind.
Es wäre schön, wenn mir jemand das obengenannte Problem mit 'NORMAL' und "CONTROL' erklären könnte.
Antworten