Page 1 of 1
Ausgabe Optimierung
Posted: Tue 01 Jan, 2008 6:52 pm
by equal
Hallo Laseristen,
ich beschäftige mich momentan mit der Optimierung von Vektorgrafiken zur Ausgabe mit Easylase. Das Einfügen von zusätzlichen Stützpunkten auf Geraden klappt schon sehr gut. Auch das Wiederholen von Start und Endpunkten funktioniert. Letzteres möchte ich jetzt abhängig von dem Winkelunterschied zwischen zwei aufeinanderfolgenden Geraden gestalten.
stumpfer Winkel -> wenig oder keine Punktwiederholungen
spitzer Winkel -> mehr Punktwiederholungen
Ich habe dazu folgendes Implementiert: Von jeder Gerade wird ein Vektor bestimmt (Differenz der X und Y Anteile des Start und Endpunkt). Mit folgender Formel wird der Winkelunterschied der Vektoren berechnet:
Dabei ist (X1,Y1) der Vektor der vorherigen und (X2,Y2) der Vektor der aktuellen Gerade. Das Ergebnis der Berechnung ist der Winkelunterschied zwischen beiden Geraden.
Das klappt auch ganz gut, ist aber ein ziemlich Performance kostender Ansatz. Ich habe hier im Forum gelesen, das dieses Problem schon einige Male gelöst wurde. Aber leider steht dort nirgendwo wie. Darum meine Frage: Gibt es einen einfacheren (Performance schonenderen) Lösungsweg?
Gruß und frohes neues Jahr ... Erik
Posted: Tue 01 Jan, 2008 6:59 pm
by gento
Code: Select all
function Scannerrichtung(X_Start,Y_Start,X_End,Y_End : SmallInt) : Word; // 12 Uhr = 0 Grad
var
Dif_Y,Dif_X : SmallInt;
Dif_N:Double;
Grad:SmallInt;
begin
Dif_Y:=Y_End-Y_Start;
Dif_X:=X_End-X_Start;
Dif_N:=Sqrt(Dif_Y*Dif_Y+Dif_X*Dif_X);
Grad:=Round(RadToDeg(ArcSin(Dif_Y/Dif_N)));
if X_End < X_Start then Grad:=-Grad+180;
if Y_End < Y_Start then Grad:=Grad+90;
Result:=Grad;
end;
Ich benutze diese Function um Frames auf Wege zu Optimieren.
Allesdings wenn es auf Speed ankommt, rechne ich ArcSin vorher in ein Array ein. Array[0..3600] sollte reichen.
lg Gento
Posted: Tue 01 Jan, 2008 10:00 pm
by equal
Hallo Gento,
Dein Lösungsweg ist performanter. Ich habe ihn mal analysiert: Du berechnest zuerst die Länge der beiden Katheten des Dreiecks dessen Hypotenuse die abzubildende Gerade ist (Dif_X und Dif_Y). Dann die Länge der Hypotenuse (Dif_N). Das Verhältnis zwischen Gegenkathete und Hypotenuse ist dann sin(alpha). Da das Ergebnis nur in einem Quadranten eindeutig ist, muss es für negative Steigungen noch angepasst werden.
Da meine Library eh schon die Hypotenuse berechnet (wichtig für die Interpolation), brauch ich nur noch das Verhältnis zur Gegenkathete zu berechnen und für negative Steigungen anpassen. Die Umrechnung in Rad bzw. Grad lass ich weg. Für den Vergleich zweier Geraden reicht auch ein Vergleich der Quotienten ...
Vielen Dank für den Lösungsweg!
(ich hatte schon vermutet das meine Lösung über die Bildung des Skalarprodukts wie mit Kanonen auf Spatzen schiessen ist ...)
Gruß ... Erik
Posted: Wed 02 Jan, 2008 1:39 pm
by equal
Hallo Gento,
leider kann ich Deine Lösung nicht vollständig nachvollziehen. Hier ein Beispiel für eine Gerade von X1=2048;Y1=2048 nach X2=2048;Y2=2548. Die Gerade geht also senkrecht nach oben in Richtung 12 Uhr.
Dif_X=X2-X1=2048-2048=0
Dif_Y=Y2-Y1=2548-2048=500
Dif_N=SQRT(0*0+500*500)=500
winkel=ArcSin(500/500)*(180/Pi)=90 Grad
Da weder Dif_X noch Dif_Y negativ sind, sind keine Anpassungen vorzunehmen.
Der Kommentar in Deinem Quellcode suggeriert das bei diesem Beispiel das Ergebnis 0 Grad betragen müsste, das Ergebnis beträgt aber 90 Grad.
Verwendest Du ein anderes Koordinatensystem?
Gruß ... Erik
Posted: Wed 02 Jan, 2008 2:32 pm
by tl
Bei mir sieht das so aus:
Code: Select all
function TLaserLine.NormAngle : extended;
begin
result := RadToDeg(ArcTan2(self.EndPoint.y - self.StartPoint.y, self.EndPoint.x - self.StartPoint.x));
if result < 0 then result := result + 360;
end;
0/0 links unten
1/1 oben rechts
Winkel auf 12 Uhr = 0°
Thomas
Posted: Thu 03 Jan, 2008 9:41 am
by equal
Hallo TL,
Deine Lösung mit der Tangens Funktion ist ja - da man die Hypotenuse nicht braucht - noch performanter. Leider habe ich auf Anhieb keine Library mit der arctan2 Funktion gefunden - macht aber nichts. Ich verwende nun diese Lösung (in Pseudocode):
Code: Select all
xdiff=x2-x1;
ydiff=y2-y1;
if xdiff==0 then
if ydiff<0 then winkel=180 else winkel=0;
else
winkel=90-(arctan(ydiff/xdiff)*(180/pi));
if xdiff<0 then winkel=winkel+180;
end if
Gruß ... Erik
Posted: Thu 03 Jan, 2008 10:02 am
by gento
Die ArcTan2 Löung ist schon genial.
Weil Delphi da selbst die Bereichsprüfungen vornimmt.
Gento
Posted: Thu 03 Jan, 2008 11:49 am
by gento
Code: Select all
function ArcTan2(const Y, X: Extended): Extended;
asm
FLD Y
FLD X
FPATAN
FWAIT
end;
Aus der Orginal Delphi Unit.
Der komplette Code der Delphi Unit Math.Pas:
http://www.gento.de/Math.rar
Im Klartextcode war der nur in der Delphi Version 7 vorhanden ,ansonsten fertig 'Kompeliert'.
Gento
Posted: Thu 03 Jan, 2008 1:05 pm
by equal
Da merkt man das ich mir die Opcodes aktueller Prozessoren schon (sehr) lange nicht mehr angeschaut habe. Jaja, immer dieses Hochspracheprogrammieren. Von den Opcodes FTAN und FATAN hatte ich noch Dunkel was in Erinnerung - aber FPTAN und FPATAN sind mir völlig neu.
Offen ist noch - was geschieht wenn X = 0 ist? Müsste eigentlich eine Exception geben. Muss ich mal ausprobieren ...
Danke für den Tipp ...
Gruß ... Erik
Posted: Thu 03 Jan, 2008 3:30 pm
by tl