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:

Image

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