这肯定会推动我对我的知识的限制.
是否有计算二次贝塞尔曲线和直线之间交点的公式?
例:
在下图中,我有P1,P2,C(它是控制点)和X1,X2(我的特定计算只是X轴上的一条直线.)
我想知道的是T的X,Y位置以及红色曲线和黑色线交叉点处T处的切线角度.
在做了一点研究并找到this问题后,我知道我可以使用:
t = 0.5; // given example value x = (1 - t) * (1 - t) * p[0].x + 2 * (1 - t) * t * p[1].x + t * t * p[2].x; y = (1 - t) * (1 - t) * p[0].y + 2 * (1 - t) * t * p[1].y + t * t * p[2].y;
计算沿曲线任意给定点的X,Y位置.因此,使用它我可以沿着曲线循环遍历一堆点,检查是否有任何在我的交叉X轴上.并从那里尝试计算我的切线角度.但这似乎并不是最好的方法.任何数学大师都知道最好的方法是什么?
我想也许它比我想要的要复杂得多.
解决方法
二次曲线公式:
y=ax^2+bx+c // where a,b,c are known
线公式:
// note: this `B` is not the same as the `b` in the quadratic formula ;-) y=m*x+B // where m,B are known.
曲线&线相交,其中两个方程对于相同的[x,y]都为真:
这是带注释的代码和演示:
// canvas vars var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); var cw=canvas.width; var ch=canvas.height; // linear interpolation utility var lerp=function(a,x){ return(a+x*(b-a)); }; // qCurve & line defs var p1={x:125,y:200}; var p2={x:250,y:225}; var p3={x:275,y:100}; var a1={x:30,y:125}; var a2={x:300,y:175}; // calc the intersections var points=calcQLintersects(p1,p2,p3,a1,a2); // plot the curve,line & solution(s) var textPoints='Intersections: '; ctx.beginPath(); ctx.moveTo(p1.x,p1.y); ctx.quadraticCurveTo(p2.x,p2.y,p3.x,p3.y); ctx.moveTo(a1.x,a1.y); ctx.lineTo(a2.x,a2.y); ctx.stroke(); ctx.beginPath(); for(var i=0;i<points.length;i++){ var p=points[i]; ctx.moveTo(p.x,p.y); ctx.arc(p.x,p.y,4,Math.PI*2); ctx.closePath(); textPoints+=' ['+parseInt(p.x)+','+parseInt(p.y)+']'; } ctx.font='14px verdana'; ctx.fillText(textPoints,10,20); ctx.fillStyle='red'; ctx.fill(); /////////////////////////////////////////////////// function calcQLintersects(p1,a2) { var intersections=[]; // inverse line normal var normal={ x: a1.y-a2.y,y: a2.x-a1.x,} // Q-coefficients var c2={ x: p1.x + p2.x*-2 + p3.x,y: p1.y + p2.y*-2 + p3.y } var c1={ x: p1.x*-2 + p2.x*2,y: p1.y*-2 + p2.y*2,} var c0={ x: p1.x,y: p1.y } // Transform to line var coefficient=a1.x*a2.y-a2.x*a1.y; var a=normal.x*c2.x + normal.y*c2.y; var b=(normal.x*c1.x + normal.y*c1.y)/a; var c=(normal.x*c0.x + normal.y*c0.y + coefficient)/a; // solve the roots var roots=[]; d=b*b-4*c; if(d>0){ var e=Math.sqrt(d); roots.push((-b+Math.sqrt(d))/2); roots.push((-b-Math.sqrt(d))/2); }else if(d==0){ roots.push(-b/2); } // calc the solution points for(var i=0;i<roots.length;i++){ var minX=Math.min(a1.x,a2.x); var minY=Math.min(a1.y,a2.y); var maxX=Math.max(a1.x,a2.x); var maxY=Math.max(a1.y,a2.y); var t = roots[i]; if (t>=0 && t<=1) { // possible point -- pending bounds check var point={ x:lerp(lerp(p1.x,p2.x,t),lerp(p2.x,y:lerp(lerp(p1.y,lerp(p2.y,p3.y,t) } var x=point.x; var y=point.y; // bounds checks if(a1.x==a2.x && y>=minY && y<=maxY){ // vertical line intersections.push(point); }else if(a1.y==a2.y && x>=minX && x<=maxX){ // horizontal line intersections.push(point); }else if(x>=minX && y>=minY && x<=maxX && y<=maxY){ // line passed bounds check intersections.push(point); } } } return intersections; }
body{ background-color: ivory; padding:10px; } #canvas{border:1px solid red;}
<h4>Calculate intersections of QBez-Curve and Line</h4> <canvas id="canvas" width=350 height=350></canvas>