Geometriefunktionen in Flash geschrieben am 12.03.2009
Hier finden sich gesammelte Funktionen für geometrische Berechnungen:
Folgende Funktionen gelten im zweidimensionales Koordinatensystem. Die Punktekoordinaten werden hier in Arrays übergeben Punkt=[Px,Py]. Alternativ könnte man es auch für Objekte umschreiben (P.x,P.y).
Schnittpunkte zweier Strahlen
ActionScript2
/*
Übergabe der Punktkoordinaten im vierpunkte:Array
Aufbau [[p1x,p1y],[p2x,p2y],[p3x,p3y],[p4x,p4y]]
Rückgabe Array:[spx,spy]
*/
function geradenschnittpunkte(vierpunkte:Array):Array{ //[[P0][P1]x[P2][P3]]
var a,h;
var re:Array=new Array(0,0);
h=((vierpunkte[3][1]-vierpunkte[2][1]) * (vierpunkte[1][0]-vierpunkte[0][0])) - ((vierpunkte[3][0]-vierpunkte[2][0]) * (vierpunkte[1][1]-vierpunkte[0][1]));
if(h==0)h=1;
a = (((vierpunkte[3][0]-vierpunkte[2][0]) * (vierpunkte[0][1] - vierpunkte[2][1])) - ((vierpunkte[3][1]-vierpunkte[2][1]) * (vierpunkte[0][0]-vierpunkte[2][0]))) / h;
re[0]=vierpunkte[0][0] + a * (vierpunkte[1][0] - vierpunkte[0][0]);
re[1]=vierpunkte[0][1] + a * (vierpunkte[1][1] - vierpunkte[0][1]);
return re;
}
Schnittpunkte eines Strahles mit Kreis (Sekantenpunkte)
Der Strahl ist durch zwei Punkte definiert.
ActionScript2
function kreislinieschnittpunkte(kreispos:Array,r:Number, p1:Array,p2:Array ):Array{
var r2:Number = r*r; //r²
var AMY:Number = p1[1]-kreispos[1];//Richtung p1 - Kreismitte
var AMX:Number = p1[0]-kreispos[0];
var AMX2:Number = AMX*AMX;
var AMY2:Number = AMY*AMY;
var BAY:Number = p2[1]-p1[1];//Richtung p1 - p2
var BAX:Number = p2[0]-p1[0];
var BAX2:Number = BAX*BAX;
var BAY2:Number = BAY*BAY;
var BAXY:Number = BAX*BAY;
var AMBAX:Number = AMX*BAX;
var AMBAY:Number = AMY*BAY;
var vroot:Number = Math.sqrt(2*AMBAX*AMBAY + BAX2*(r2 - AMY2) + BAY2*(r2 - AMX2));
var pre:Number = AMBAX + AMBAY;
var divisor:Number = BAX2 + BAY2;
var t1:Number = -(pre - vroot)/divisor;
var t2:Number = -(pre + vroot)/divisor;
var res:Array=[[0,0],[0,0]];
res[0][0]=p1[0]+t1*BAX;
res[0][1]=p1[1]+t1*BAY;
res[1][0]=p1[0]+t2*BAX;
res[1][1]=p1[1]+t2*BAY;
return res;
//NaN,NaN,NaN,NaN=keine SP ->Passante
//res[0]==res[1] ->Tangente
//sonst Sekante
}
Quelle: www.flashforum.deStreckenlänge zwischen 2 Punkten
Die Punkte sind in p1 und p2 Arrays gespeichert [p1x,p1y][p2x,p2y]
ActionScript2
function streckenlaenge2D(p1,p2:Array):Number {
return Math.sqrt( Math.pow(p2[1]-p1[1],2)+Math.pow(p2[0]-p1[0],2));
}
und zwischen 2 Punkten im 3D-Raum
function streckenlaenge3D(p1,p2:Array):Number {
var a=streckenlaenge2D(p1,p2);
var b=streckenlaenge2D([0,p1[2]],[0,p2[2]]);
var re= Math.sqrt( a*a+b*b);
return re;
}
Punkt um einen anderen Punkt relativ drehen
Mit dieser Funktion wird ein Punkt um einen anderen gedreht, Winkelangabe in Grad.
ActionScript2
function drehePunkt(p:Array, dreheumPunkt:Array, Winkel:Number):Array{//Winkel in Grad
var r=Winkel*Math.PI/180;//Winkel in Bogenmaß
var re:Array=new Array(0,0);
var flength = Math.sqrt( Math.pow(dreheumPunkt[1]-p[1],2)+Math.pow(dreheumPunkt[0]-p[0],2));
var angle = r+Math.atan2(p[1]-dreheumPunkt[1],p[0]-dreheumPunkt[0]);
while(angle<0){angle = angle+2*Math.PI;}
while(angle>2*Math.PI){angle = angle-2*Math.PI;}
re[0]= dreheumPunkt[0]+Math.cos(angle)*flength;
re[1]= dreheumPunkt[1]+Math.sin(angle)*flength;
return re;
}
Winkel im Schnittpunkt zweier Strecken
Winkel im Dreieck, daher von 0 bis +180
ActionScript2function getWinkel(p0,p1,p2:Array):Number{
//Winkel Strecke p0-p1 zu p1-p2 in Grad
var re:Number=0;
var a=streckenlaenge2D(p1,p2);
var b=streckenlaenge2D(p0,p2);
var c=streckenlaenge2D(p0,p1);
if(a>0 && b>0 && c>0)
re=Math.acos((a*a+c*c-b*b)/(2*a*c))* 180/Math.PI;
return re;
}
relativer Winkel 0..360
ActionScript2function getWinkelimUZS(p0,p1,p2:Array):Number{
var re:Number=0;
var w1,w2;
if(p0[0]==p1[0] && p0[1]<p1[1]){w1=-90;}
else
if(p0[0]==p1[0] && p0[1]>p1[1]){w1=90;}
else
if(p0[0]<p1[0] && p0[1]==p1[1]){w1=0;}
else
if(p0[0]>p1[0] && p0[1]==p1[1]){w1=180;}
else
{
w1=getWinkel(p0,p1,[p0[0],p1[1]]);
if(p0[0]>p1[0] && p0[1]<p1[1]) w1=w1+180;
if(p0[0]>p1[0] && p0[1]>p1[1]) w1=180-w1;
if(p0[0]<p1[0] && p0[1]<p1[1]) w1=w1*-1;
}
//in stabile Lage bringen, p0 liegt rechts von p1
var p0b=drehePunkt(p0,p1,w1);
var p2b=drehePunkt(p2,p1,w1);
re=getWinkel(p0b,p1,p2b);
//wenn p2b in y Richtung oberhalb liegt, 360-Winkel rechnen
if(p0b[1]<p2b[1])re=360-re;
return re;
}
Punkt auf Gerade
Gibt einen Punkt auf der Geraden zurück.
Ist pos=0 dann ist der Punkt auf p1;
ist pos=100 dann ist der Punkt auf p2;
ist pos<0 dann liegt der Punkt vor p1p2;
ist pos>100 dann liegt der Punkt nach p1p2.
ActionScript2function PunktaufGerade(p1,p2:Array,pos:Number):Array{
var re:Array=new Array(0,0);
re[0]=(p2[0]-p1[0])*pos/100+p1[0];
re[1]=(p2[1]-p1[1])*pos/100+p1[1];
return re;
}
Folgende Funktion verschiebt den Punkt p1 auf der Geraden (die durch p1 und p2 definiert wird) um Weite
ActionScript2function verschiebeP1auf(p1,p2:Array, weite:Number):Array{
var re:Array=new Array(0,0);
var ax=p2[0]-p1[0];//Anstieg X
var ay=p2[1]-p1[1];//Anstieg Y
var p1p2=streckenlaenge2D(p1,p2);
re[0]=ax/p1p2*weite+p1[0];
re[1]=ay/p1p2*weite+p1[1];
return re;
}
Dreieck
Mittelpunkt (=Schwerpunkt) eines Dreieckes:
ActionScript2function mittelpunktDreieck(p1,p2,p3:Array):Array{
var re:Array=new Array(0,0);
var m1:Array=streckenmittelpunkt(p2,p3);
var m2:Array=streckenmittelpunkt(p1,p3);
re=geradenschnittpunkte([p1,m1, p2,m2]);
return re;
}
Bezierkurven
Quadratische Bézierkurven
p1,p2 Anfangs und Endpunkt
p2=Stützpunkt
ActionScript2function PunktaufquadBezier(p1,p2,p3:Array, pos:Number):Array{
var re:Array=new Array(0,0);
var p12=PunktaufGerade(p1,p2,pos);
var p23=PunktaufGerade(p2,p3,pos);
re=PunktaufGerade(p12,p23,pos);
return re;
}
Kubische Bézierkurven
p1,p4 Anfangs und Endpunkt
p2,p3=Stützpunkte
ActionScript2function PunktaufKubiBezier(p1,p2,p3,p4:Array, pos:Number):Array{
var re:Array=new Array(0,0);
var p12=PunktaufGerade(p1,p2,pos);
var p23=PunktaufGerade(p2,p3,pos);
var p34=PunktaufGerade(p3,p4,pos);
var s1=PunktaufGerade(p12,p23,pos);
var s2=PunktaufGerade(p23,p34,pos);
re=PunktaufGerade(s1,s2,pos);
return re;
}
Die folgende Funktion gibt den Punkt auf einer kubischen Bezier-Kurve zurück. Die Bezier-Kurve istdurch mehrere Punkte definiert.
ActionScript2function NBezier(punkte:Array, pos:Number):Array {
//punkte=Array mit Punkten [[p1x,p1y],[p2x,p2y],...]
//pos 0,0..100,0 Punkt an Position
var re:Array=new Array(0,0);
var pa=0;
var t;
var strecke=0;
if (pos>0 && pos<100) {
for (t=0; t<punkte.length-1; t++) {
strecke+=streckenlaenge2D(punkte[t],punkte[t+1]);
}
var streckenpos=(strecke/100*pos);//welcher Position
var pas=streckenpos;
//Streckenabschnitt suchen (Teilstück suchen wo der gesuchte Punkt drinnliegt)
var sa=0;
var svor=0;
while (pas>0) {
pas=pas-streckenlaenge2D(punkte[sa],punkte[sa+1]);
svor+=streckenlaenge2D(punkte[sa],punkte[sa+1]);
sa++;
}
if(sa>0){sa--;}
var posaufteilstrecke=100-100/streckenlaenge2D(punkte[sa],punkte[sa+1])*(svor-streckenpos);
var p1:Array=punkte[sa];
var p2:Array=new Array(0,0);
var p3:Array=new Array(0,0);
var p4:Array=punkte[sa+1];
var temp:Array=new Array(0,0);
var w;
if (sa==0) {
p2=PunktaufGerade(punkte[sa],punkte[sa+1],40);
} else {
w=getWinkelimUZS(punkte[sa],punkte[sa-1],punkte[sa+1]);
p2=PunktaufGerade(punkte[sa],punkte[sa-1],40);
p2=drehePunkt(p2,punkte[sa],w+180);
}
if ((sa+2)==punkte.length) {
p3=PunktaufGerade(punkte[sa+1],punkte[sa],40);
} else {
w=getWinkelimUZS(punkte[sa+1],punkte[sa],punkte[sa+2]);
p3=PunktaufGerade(punkte[sa+1],punkte[sa],40);
p3=drehePunkt(p3,p4,w);
}
re=PunktaufKubiBezier(p1,p2,p3,p4,posaufteilstrecke);
} else {
if (pos==0) {
re=punkte[0];
}
if (pos==100) {
re=punkte[punkte.length-1];
}
}
return re;
}
download
Alle oben genannten Funktionen und das Bezierdemo zum freien download:
beziertest.rar (8.23kb, Flash CS3)