
El punto P se describe como el punto de la línea L que comparte espacio con la curva ABCD. De este modo, despejo los componentes x,y de la línea L y de la curva ABCD para despejar el valor T que es un número entre 0 y 1 que sirve como puntero en la curva.
El uso de la curva bezier se describe en un anterior post http://blog.cincibeles.com/2016/01/curva-bizier-y-ruta-de-curvas.html, además he tomado el algoritmo que permite resolver ecuaciones de tercer grado de la página http://www.gyplan.com/es/eqcubic_es.html para poder resolver la igualdad de las formulas bezier y la línea.
despejando la ecuación bezier obtengo..
x = t³ (Ax - 3Bx + 3Cx - Dx) + t² (3Bx - 6Cx + 3Dx) + t (3Cx - 3Dx) + Dx
y = t³ (Ay - 3By + 3Cy - Dy) + t² (3By - 6Cy + 3Dy) + t (3Cy - 3Dy) + Dy
y la ecuación lineal...
x = (y - b) / m + a
y = m (x - a) + b
entonces...
(y - b) / m + a = t³ (Ax - 3Bx + 3Cx - Dx) + t² (3Bx - 6Cx + 3Dx) + t (3Cx - 3Dx) + Dx
m (x - a) + b = t³ (Ay - 3By + 3Cy - Dy) + t² (3By - 6Cy + 3Dy) + t (3Cy - 3Dy) + Dy
despejando la variable t obtendremos el puntero que nos indicará en que sección de la curva está cortando.
En fin. Acá está la función que recibe siete parámetros: un punto de la linea x,y, su pendiente m, y los cuatro puntos de la curva bezier a,b,c,d.
function BizierLineCollide(x,y,m,A,B,C,D){
var Ax=A[0], Ay=A[1], At, Bx=B[0], By=B[1], Bt, Cx=C[0], Cy=C[1], Ct, Dx=D[0], Dy=D[1], Dt, result=[];
if(Math.abs(m)<=1){
At=(Ay-3*By+3*Cy-Dy)-m*(Ax-3*Bx+3*Cx-Dx);
Bt=3*(By-2*Cy+Dy)-m*3*(Bx-2*Cx+Dx);
Ct=3*(Cy-Dy)-m*3*(Cx-Dx)
Dt=Dy-y+m*(x-Dx);
result= eqCubic(At,Bt,Ct,Dt);
}else{
var w=1/m;
At=(Ax-3*Bx+3*Cx-Dx)-w*(Ay-3*By+3*Cy-Dy);
Bt=3*(Bx-2*Cx+Dx)-w*3*(By-2*Cy+Dy);
Ct=3*(Cx-Dx)-w*3*(Cy-Dy);
Dt=Dx-x+w*(y-Dy);
result= eqCubic(At,Bt,Ct,Dt);
}
var fnB=fnBizier(A,B,C,D), _return=[];
result.forEach(function(v,k){
if(!isNaN(v)){
v=Math.round(v*10000)/10000;
if(v>=0 && v<1){
console.log(v);
_return.push(fnB(v));
}
}
});
return _return;
}
Devuelve el punto de colisión x,y y t, ademas los componentes de la pendiente de la curva en el mismo punto.
Para funcionar requiere dos funciones: La función que permite deducir una ecuación cubica y la función de la curva bezier .
function eqCubic(a,b,c,d){ //http://www.gyplan.com/es/eqcubic_es.html
var x1=x2=x3=0, f,g,h,m,k,m2,n,n2,r,rc,theta;
if(a=="" && b==""&& c=="" && d=="") return 'es vacia';
if(a=="" && b==""&& c=="" ) return d;
if(a=="" && b=="" ){
a=c; b=d;
return -b/a;
}
if(a==0 | a=="") {
a=b; b=c; c=d;
var b24ac2a=Math.sqrt(b*b-4*a*c);
return isNaN(b24ac2a)?[]:[(-b+b24ac2a)/(2*a),(-b-b24ac2a)/(2*a)];
};
f = (((3*c)/a) - (((b*b)/(a*a))))/3
g = ((2*((Math.pow(b,3))/(Math.pow(a,3)))-(9*b*c/(a*a)) + ((27*(d/a)))))/27 // Math.pow(b,3)
h = (((g*g)/4) + ((f*f*f)/27))
var dis = h;
if (h > 0){
m = (-(g/2)+ (Math.sqrt(h)))
k=1
if (m < 0) k=-1; else k=1
m2 = (Math.pow((m*k),(1/3)))
m2 = m2*k
k=1
n = -(g/2)- (Math.sqrt(h))
if (n < 0) k=-1; else k=1
n2 = (Math.pow((n*k),(1/3)))
n2 = n2*k
k=1
x1= (m2 + n2) - b/(3*a);
x2= ((-1*(m2 + n2)/2 - b/(3*a)) + " + i * " + (m2 - n2)*Math.pow(3,.5)/2 );
x3= ((-1*(m2 + n2)/2 - b/(3*a)) + " - i * " + (m2 - n2)*Math.pow(3,.5)/2 );
return [x1,x2,x3];
}
if (h<=0){
r = ((Math.sqrt((g*g/4)-h)));
k=1;
if (r<0) k=-1;
rc = Math.pow((r*k),(1/3))*k;
k=1;
theta =Math.acos((-g/(2*r)));
x1= (2*(rc*Math.cos(theta/3))-(b/(3*a)));
x2a=rc*-1;
x2b= Math.cos(theta/3);
x2c= Math.sqrt(3)*(Math.sin(theta/3));
x2d= (b/3*a)*-1;
x2=(x2a*(x2b + x2c))-(b/(3*a));
x3=(x2a*(x2b - x2c))-(b/(3*a));
return [x1,x2,x3];
}
}
function fnBizier(pA,cA,cB,pB){
var B=[
function(x){ return x*x*x; },
function(x){ return 3*x*x*(1-x); },
function(x){ var x1=(1-x); return 3*x*x1*x1; },
function(x){ var x1=(1-x); return x1*x1*x1; }
],
C=[pA,cA,cB,pB],
Ax=3*(C[0][0] - 3*C[1][0] + 3*C[2][0] - C[3][0]),
Bx=2*(3*C[1][0] - 6*C[2][0] + 3*C[3][0]),
Cx=(3*C[2][0] - 3*C[3][0]),
Ay=3*(C[0][1] - 3*C[1][1] + 3*C[2][1] - C[3][1]),
By=2*(3*C[1][1] - 6*C[2][1] + 3*C[3][1]),
Cy=(3*C[2][1] - 3*C[3][1]),
getPoint=function(t){
var B0=B[0](t),
B1=B[1](t),
B2=B[2](t),
B3=B[3](t),
x = pA[0]*B0 + cA[0]*B1 + cB[0]*B2 + pB[0]*B3,
y = pA[1]*B0 + cA[1]*B1 + cB[1]*B2 + pB[1]*B3,
t2=t*t,
mx= t2*Ax + t*Bx + Cx,
my= t2*Ay + t*By + Cy;
return [x,y,t,mx,my];
};
return getPoint;
}
Ejemplo: https://jsfiddle.net/cincibeles/40s89fwx/
No hay comentarios.:
Publicar un comentario