javascript – 计算二次贝塞尔曲线的交点

前端之家收集整理的这篇文章主要介绍了javascript – 计算二次贝塞尔曲线的交点前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这肯定会推动我对我的知识的限制.

是否有计算二次贝塞尔曲线和直线之间交点的公式?

例:

在下图中,我有P1,P2,C(它是控制点)和X1,X2(我的特定计算只是X轴上的一条直线.)

我想知道的是T的X,Y位置以及红色曲线和黑色线交叉点处T处的切线角度.

在做了一点研究并找到this问题后,我知道我可以使用:

  1. t = 0.5; // given example value
  2. x = (1 - t) * (1 - t) * p[0].x + 2 * (1 - t) * t * p[1].x + t * t * p[2].x;
  3. y = (1 - t) * (1 - t) * p[0].y + 2 * (1 - t) * t * p[1].y + t * t * p[2].y;

计算沿曲线任意给定点的X,Y位置.因此,使用它我可以沿着曲线循环遍历一堆点,检查是否有任何在我的交叉X轴上.并从那里尝试计算我的切线角度.但这似乎并不是最好的方法.任何数学大师都知道最好的方法是什么?

我想也许它比我想要的要复杂得多.

解决方法

二次曲线公式:
  1. y=ax^2+bx+c // where a,b,c are known

线公式:

  1. // note: this `B` is not the same as the `b` in the quadratic formula ;-)
  2.  
  3. y=m*x+B // where m,B are known.

曲线&线相交,其中两个方程对于相同的[x,y]都为真:

这是带注释的代码和演示:

  1. // canvas vars
  2. var canvas=document.getElementById("canvas");
  3. var ctx=canvas.getContext("2d");
  4. var cw=canvas.width;
  5. var ch=canvas.height;
  6.  
  7. // linear interpolation utility
  8. var lerp=function(a,x){ return(a+x*(b-a)); };
  9.  
  10. // qCurve & line defs
  11. var p1={x:125,y:200};
  12. var p2={x:250,y:225};
  13. var p3={x:275,y:100};
  14. var a1={x:30,y:125};
  15. var a2={x:300,y:175};
  16.  
  17. // calc the intersections
  18. var points=calcQLintersects(p1,p2,p3,a1,a2);
  19.  
  20. // plot the curve,line & solution(s)
  21. var textPoints='Intersections: ';
  22. ctx.beginPath();
  23. ctx.moveTo(p1.x,p1.y);
  24. ctx.quadraticCurveTo(p2.x,p2.y,p3.x,p3.y);
  25. ctx.moveTo(a1.x,a1.y);
  26. ctx.lineTo(a2.x,a2.y);
  27. ctx.stroke();
  28. ctx.beginPath();
  29. for(var i=0;i<points.length;i++){
  30. var p=points[i];
  31. ctx.moveTo(p.x,p.y);
  32. ctx.arc(p.x,p.y,4,Math.PI*2);
  33. ctx.closePath();
  34. textPoints+=' ['+parseInt(p.x)+','+parseInt(p.y)+']';
  35. }
  36. ctx.font='14px verdana';
  37. ctx.fillText(textPoints,10,20);
  38. ctx.fillStyle='red';
  39. ctx.fill();
  40.  
  41. ///////////////////////////////////////////////////
  42.  
  43. function calcQLintersects(p1,a2) {
  44. var intersections=[];
  45.  
  46. // inverse line normal
  47. var normal={
  48. x: a1.y-a2.y,y: a2.x-a1.x,}
  49.  
  50. // Q-coefficients
  51. var c2={
  52. x: p1.x + p2.x*-2 + p3.x,y: p1.y + p2.y*-2 + p3.y
  53. }
  54.  
  55. var c1={
  56. x: p1.x*-2 + p2.x*2,y: p1.y*-2 + p2.y*2,}
  57.  
  58. var c0={
  59. x: p1.x,y: p1.y
  60. }
  61.  
  62. // Transform to line
  63. var coefficient=a1.x*a2.y-a2.x*a1.y;
  64. var a=normal.x*c2.x + normal.y*c2.y;
  65. var b=(normal.x*c1.x + normal.y*c1.y)/a;
  66. var c=(normal.x*c0.x + normal.y*c0.y + coefficient)/a;
  67.  
  68. // solve the roots
  69. var roots=[];
  70. d=b*b-4*c;
  71. if(d>0){
  72. var e=Math.sqrt(d);
  73. roots.push((-b+Math.sqrt(d))/2);
  74. roots.push((-b-Math.sqrt(d))/2);
  75. }else if(d==0){
  76. roots.push(-b/2);
  77. }
  78.  
  79. // calc the solution points
  80. for(var i=0;i<roots.length;i++){
  81. var minX=Math.min(a1.x,a2.x);
  82. var minY=Math.min(a1.y,a2.y);
  83. var maxX=Math.max(a1.x,a2.x);
  84. var maxY=Math.max(a1.y,a2.y);
  85. var t = roots[i];
  86. if (t>=0 && t<=1) {
  87. // possible point -- pending bounds check
  88. var point={
  89. x:lerp(lerp(p1.x,p2.x,t),lerp(p2.x,y:lerp(lerp(p1.y,lerp(p2.y,p3.y,t)
  90. }
  91. var x=point.x;
  92. var y=point.y;
  93. // bounds checks
  94. if(a1.x==a2.x && y>=minY && y<=maxY){
  95. // vertical line
  96. intersections.push(point);
  97. }else if(a1.y==a2.y && x>=minX && x<=maxX){
  98. // horizontal line
  99. intersections.push(point);
  100. }else if(x>=minX && y>=minY && x<=maxX && y<=maxY){
  101. // line passed bounds check
  102. intersections.push(point);
  103. }
  104. }
  105. }
  106. return intersections;
  107. }
  1. body{ background-color: ivory; padding:10px; }
  2. #canvas{border:1px solid red;}
  1. <h4>Calculate intersections of QBez-Curve and Line</h4>
  2. <canvas id="canvas" width=350 height=350></canvas>

猜你在找的JavaScript相关文章