Hallo wp_xyz,
Danke erst mal! Scheint zu funktionieren,
obwohl ich gegenüber der Originalfunktion aus Windows eine Abweichung habe, die auch auf Rundungsfehlern beruhen kann. Der Winkel der von den beiden Strahlen aufgespannt wird ist in meiner Funktion etwas klaeiner, aber sichtbar kleiner, gefühlte 6 Grad gesamt, 2-3 Grad für jeden der beiden Strahlen.
Hier die Originalfunktion mit den Testparametern:
Windows.Pie(WndDC, 300, 110, 500, 200, 310, 110, 200, 260);Die Abweichung beträgt gefühlte 2-3 Grad am Startwinkel und am Endwinkel.
Hier jetzt mein neuer Code. Winkel mit Deiner Funktion berechnet.
Code: Alles auswählen
//Ein anderer Weg zum Ellipsenradius in einem konkreten Punkt
//Funktionirt leider gar nicht --> Absturz!!!
function EllipseRadius(X,Y,a,b, grad: Extended; out p: TPoint): Extended;
var
sqrsin,sqrcos,radius: Extended;
sqra,sqrb: Extended;
begin
sqrsin := Round(sin(grad * pi/180)) mod 360;
sqrsin := sqr(sqrsin);
sqrcos := Round(cos(grad * pi/180)) mod 360;
sqrcos := sqr(sqrcos);
radius := sqrt(sqrcos+sqrsin);
sqra := sqr(a) * sqr(radius);
sqrb := sqr(a) * sqr(a)*sqrsin;
p.X := Round(abs(sqrt(sqra - sqrb))+X);
sqra := sqr(b) * sqr(radius);
sqrb := sqr(b) * sqr(sqrcos);
p.Y := Round(abs(sqrt(sqra - sqrb))+Y);
Result := radius;
end;
//Meine EllipsenbogenFunktion:
function DrawEllipseSeg(Handle: HDC; X, Y, startgrd, endgrd, Xradius, Yradius: Integer; Color: COLORREF): TRect;
var angle,delta: Integer; ptStart,ptEnd: TPoint;
begin
if startgrd < endgrd then
begin
for angle := startGrd to endGrd do
begin
SetPixel(Handle,
Round(Xradius * cos(angle * pi / 180)) + x,
Round(Yradius * sin(angle * pi / 180)) + y,
Color
);
if Round(angle) = Round(startgrd) then
begin
ptStart.X := Round(Xradius * cos(angle * pi / 180)) + x;
ptStart.Y := Round(Yradius * sin(angle * pi / 180)) + y;
end
else
if Round(angle) = Round(endgrd) then
begin
ptEnd.X := Round(Xradius * cos(angle * pi / 180)) + x;
ptEnd.Y := Round(Yradius * sin(angle * pi / 180)) + y;
end;
end;
end
else
if startgrd > endgrd then
begin
delta := startgrd - endgrd;
startgrd := StartGrd - delta;
endgrd := endgrd + delta;
for angle := startGrd to endgrd do
begin
SetPixel(Handle,
Round(Xradius * cos(angle * pi / 180)) + x,
Round(Yradius * sin(angle * pi / 180)) + y,
Color
);
if Round(angle) = Round(startgrd) then
begin
ptStart.X := Round(Xradius * cos(angle * pi / 180)) + x;
ptStart.Y := Round(Yradius * sin(angle * pi / 180)) + y;
end
else
if Round(angle) = Round(endgrd) then
begin
ptEnd.X := Round(Xradius * cos(angle * pi / 180)) + x;
ptEnd.Y := Round(Yradius * sin(angle * pi / 180)) + y;
end;
end;
end;
Result.Left := ptStart.X; // ist für die Begrenzungslinien des Tortentüxkes gedacht
Result.Top := ptStart.Y;
Result.Right := ptEnd.X;
Result.Bottom:= ptEnd.Y
end;
//Meine aktuelle Pie Funktion --> Prameter wie Original
function Pie(dc: HDC; Left, Top, Right, Bottom, xStart, yStart, xEnd, yEnd: Integer): BOOL;
var
xm, ym, a, b: Integer;
stangle, endangle, delta, radius: Extended;
r: TRect;
begin
xm := Left + Abs(Right - Left) div 2;
ym := Top + Abs(Bottom - Top) div 2;
a := Right - xm;
b := Bottom - ym;
r := DrawEllipseSeg(dc, xm, ym, Round(QuadrantAngle(xStart-Left,yStart-Top,xm-Left,ym-Top)),Round(QuadrantAngle(xEnd-Left,yEnd-Top,xm-Left,ym-Top)), a, b, GetDCPenColor(dc));
//Hier werden die Begrenzungen des Tortenstückes gezeichnet
//Zuerst vom x,y Punkt der Ellipse am Startwinkel
MoveToEx(dc, r.Left, r.Top, nil);
LineTo(dc, xm, ym);
//Danach vom x,y Punkt der Ellipse am Endwinkel
MoveToEx(dc, r.Right, r.Bottom, nil);
LineTo(dc, xm, ym);
//Das funktioniert, unabhängig vom Quadranten
//Ein Floodfill ALgorithmus --> funktioniert noch nicht, kann aber mit falscher ANwendung von Stift und Pinsel zusammenhängen. Teste ich morgen.
fill(dc, xm+20,ym, COLOR_APPWORKSPACE, GetDCBrushColor(dc));
end;
//Hier noch der Floodfill Algo:
von hier direkt nach Pascal portiert:
https://de.wikipedia.org/wiki/Floodfill
//Hier der Fill4 Algorithmus:
function fill(dc: HDC; X,Y: Integer; OldColor, NewColor: Colorref): Boolean;
begin
Result := false;
if GetPixel(dc, X,Y) = OldColor then
begin
SetPixel(dc, X,Y, NewColor);
fill(dc, x, y + 1, OldColor, NewColor); // unten
fill(dc, x, y - 1, OldColor, NewColor); // oben
fill(dc, x - 1, y, OldColor, NewColor); // links
fill(dc, x + 1, y, OldColor, NewColor); // rechts end;
end;
end;
Die Original Pie() Funktion ist mit der aktuellen Pinselfarbe gefüllt.
wp_xyz hat geschrieben:Zur Ellipsengleichung: Da hast du sicher nicht "alle Erklärungen" gefunden, denn Google spuckt folgenden Artikel ziemlich weit oben aus:
http://www.mathe-online.at/materialien/ ... llipse.pdf
Danke, diese Abhandlung kenne ich, die Konstruktion der Ellipse erfolgt da aber mittels der Brennpunkte der Ellipse.
Leider habe ich die folgende Erklärung erst heute gefunden:
und zwar hier:
https://en.wikipedia.org/wiki/EllipseGeneral parametric form[edit]
An ellipse in general position can be expressed parametrically as the path of a point , where
as the parameter t varies from 0 to 2π. Here is the center of the ellipse, and is the angle between the -axis and the major axis of the ellipse.
Parametric form in canonical position[edit]
Parametric equation for the ellipse (red) in canonical position. The eccentric anomaly t is the angle of the blue line with the X-axis.
For an ellipse in canonical position (center at origin, major axis along the X-axis), the equation simplifies to
Note that the parameter t (called the eccentric anomaly in astronomy) is not the angle of with the X-axis.
For a given point on an ellipse, formulae connecting the tangential angle , the polar angle from the ellipse center , and the parametric angle t[26] are:[27][28][29][30]
Da geht man von 2 Kreisen aus, der erste im Radius a, der zweite im Radius b.
Ein Strahl läuft um den Mittelpunkt, wenn der bei 90 oder 270 Grad steht befindet sich der an diesem Strahl befestigte Stift auf dem Radius des inneren Kreises mit dem kürzeren Radius b. Nun ändert sich die Stiftlänge abhängig vom Winkel und hat ihr Maximum (a-b) bei 0- und 180 Grad. Die Gleichung ist im verlinkten Wikipedia Artikel unter
"Parametric form in canonical position" zu finden. Hätte ich gut gebrauchen können.
Bei der Erklärung in der PDF Datei habe ich mich an den Brennpunkten gestört, ich wollte eine Funktion die vom Mittelpunkt der Ellipse ausgeht und den richtigen Radius der Ellipse abhängig vom Winkel korrekt berechnet und dann 360 Grad umläuft. Da wäre wohl die oben beschriebene parametrische Form eher meine Freundin gewesen. Leider erst heute gefunden.
wp_xyz hat geschrieben:Was ist eigentlich genau die Aufgabenstellung? Ein Tortenstück ("pie") zu zeichnen? Was sind die gegebenen Voraussetzungen? (Rechteck, das die Ellipse umschreibt; sowie zwei Punkte für die Definition der Start- und Endwinkel?)
Genau, ein Tortenstück zeichnen unter den gleichen Voraussetzungen, wie das die Windows API Funktion Pie() macht. Ein Rechteck umschließt die Ellipse. Die Koordinaten des Rechteckes werden der Pie Funktion übergeben. Zusätzlich erhält die Funktion die X,Y Koordinaten von Start- und Endpunkt zweier Strahlen, die vom Mittelpunkt der Ellipse ausgehen und den Winkel beschreiben, den das Tortenstück aufklappt.
Zu deinem neuen Code: Warum nimmst du plötzlich Windows-Funktionen?
Nicht jetzt erst, sondern von Beginn an. Im Demoprogramm "tut1" habe ich deshalb für die Originalfunktionen Windows. davor gesetzt, für meine Funktion den Namen meiner Unit "arcs" mit den von mir programmierten Funktionen. So kann ich das Verhalten meiner Funktionen testen, indem ich deren Verhalten mit dem Original vergleiche. Ich baue die Windows Funktionen nach.
wp_xyz hat geschrieben:Der alte Code funktioniert doch auch, wenn die Fehler mit der Winkelberechnung gelöst sind. Und da bist du jetzt ein gutes Stück weiter. Ich frage mich nur, warum du Left und Top in der Kathetenberechnung verwendest. Und der Fall wegen Division durch 0 fehlt noch.
Immer noch!?! Da muß ich unbedingt noch mal schauen.
Left und Top verwende ich, weil der Mittelpunkt xm,ym im die Ellipse umschließenden Rechteck liegt und ich ja den Winkel zwischen Abszisse und dem Start bzw. Endstrahl brauche. Für das Zeichnen der Ellipse an der korrekten Position habe ich deshalb die Offsets Left und Top zu xm,ym hinzu addiert (xm + Left, ym + Top). xm,ym ist der Mittelpunkt der Ellipse, die vom Rechteck umschlossen wird. Jedoch werden die X,Y Koordinaten der Endpunkte der beiden Strahlen in Fensterkoordinaten übergeben, nicht in Koordinaten des Rechteckes. Deshalb subtrahiere ich in der Winkelberechnungsfunktion Left und Top wieder und habe so die echten X,Y Koordinaten bezogen auf den Ellipsenmittelpunkt. Vorher hatte ich falsche Winkel, nicht nur geringfügig kleiner, sondern auch im falschen Quadranten und mit zu großer Abweichung in der Winkelöffnung. Habe faktisch so das die Ellipse umschließende Rechteck mit der linken oberen Ecke zum Punkt (0,0) meines Ausgabefensters verschoben
(rechnerisch).
wp_xyz hat geschrieben:Die Winkelberechnung müsste so richtig sein (nicht getestet):
Scheint Ok zu sein, allerdings habe ich gegenüber der Originalfunktion eine Winkelabweichung, in der Originalfunktion ist der Winkel ein Stück größer.Die besagten gefühlten 3 Grad.
Aber ich kann ja noch mal die neu gefundene Wikipedia Seite zu Rate ziehen.
Da ist wohl die Konstante e der Abstand vom X-Radius zum Brennpunkt F?
Wenn dem so ist, dürfte der Rest Rechenarbeit sein. Kann ja noch ne andere Variante testen.
Schaun wir mal. Vielleicht ist ja die parametrische Form genauer. Ein Weg um in mathematischen Dingen wieder fitter zu werden.