绘制圆弧以适应 html canvas 中的角度,圆缠结已知半径 2D 的点

Drawing arc to fit angle in html canvas by Circle tangles point with known radius 2D

这个问题很难解释。但我会尽力而为。 首先我画了 2 条线,一条线包含一个起点和一个终点,像这样

line = {
   startPoint{x: , y:}
   endPoint{x: , y:}
}

然后我在 canvas 上画两条线,形成像这样的三角形的角。

我现在将线彼此分开,长度为 Radius*2,如下所示

那么我现在如何使用两个端点作为切点来绘制圆弧,如下所示

我需要为此使用 arc 还是可以使用 arcto 来完成?如果它是弧形的;然后我如何给它开始绘图和结束点,以便它像上一张图​​中的图像所示那样绘制它。感谢您的宝贵时间,任何意见都有帮助。再次对问题的错误描述表示抱歉

给定在公共点相交的 2 条线段,您可以使用三次贝塞尔曲线对它们应用圆形交点:

方法如下...

  • 给定点 p1 和从 p1 延伸到 p0 (P10) 和从 p1 延伸到 p2 (P12) 的线段:

    var p0={x:50,y:50};
    var p1={x:100,y:150};
    var p2={x:250,y:100};
    
  • 计算 P10 和 P12 上的点,这些点是从公共点 (p1) 返回到各自起点 (p0 和 p2) 的指定路径百分比:

    var lerp=function(a,b,x){ return(a+x*(b-a)); };
    var dx,dy,length;
    var offsetPct=0.15;
    
    // calc a point on P10 that is 15% of the way from p1 to p0
    dx=p1.x-p0.x;
    dy=p1.y-p0.y;
    p00={ x:lerp(p1.x,p0.x,offsetPct), y:lerp(p1.y,p0.y,offsetPct) }
    
    // calc a point on P12 that is 15% of the way from p1 to p2
    dx=p1.x-p2.x;
    dy=p1.y-p2.y;
    p22={ x:lerp(p1.x,p2.x,offsetPct), y:lerp(p1.y,p2.y,offsetPct) }
    
  • 然后您可以使用缩短的线段和三次贝塞尔曲线绘制圆角交叉点:

示例代码和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

var p0={x:50,y:50};
var p1={x:100,y:150};
var p2={x:150,y:50};


roundedIntersection(p0,p1,p2,0.15);


function roundedIntersection(p0,p1,p2,offsetPct){

  var lerp=function(a,b,x){ return(a+x*(b-a)); };
  var dx,dy,length;
  dx=p1.x-p0.x;
  dy=p1.y-p0.y;
  p00={ x:lerp(p1.x,p0.x,offsetPct), y:lerp(p1.y,p0.y,offsetPct) }
  dx=p1.x-p2.x;
  dy=p1.y-p2.y;
  p22={ x:lerp(p1.x,p2.x,offsetPct), y:lerp(p1.y,p2.y,offsetPct) }

  ctx.beginPath();
  ctx.moveTo(p0.x,p0.y);
  ctx.lineTo(p00.x,p00.y);
  ctx.bezierCurveTo( p1.x,p1.y,  p1.x,p1.y  ,p22.x,p22.y);
  ctx.lineTo(p2.x,p2.y);
  ctx.stroke();

  dot(p0.x,p0.y);
  dot(p1.x,p1.y);
  dot(p2.x,p2.y);
  dot(p00.x,p00.y);
  dot(p22.x,p22.y);

  function dot(x,y){
    ctx.beginPath();
    ctx.arc(x,y,2,0,Math.PI*2);
    ctx.closePath();
    ctx.fill();
  }

}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>

是的,你可以使用 arcTo():

  • 设置你的第一行起点moveTo()
  • 那么两条线之间的交点作为第一对
  • 然后第二行的终点(你说的"startpoint line 2")最后一对。
  • 提供半径
  • 要实际绘制最后一条线(它仅用于arcTo()的计算)为弧中的最后一对点添加一个lineTo(),stroke/fill.

如果您想将线分开但不知道交点,您必须 manually calculate(请参阅该答案中的 getIntersection()),方法是首先对线进行插值以使其超出其原始长度。

var ctx = document.querySelector("canvas").getContext("2d");

ctx.moveTo(0, 0);                 // start point
ctx.arcTo(50, 150, 100, 0, 20);   // intersection, outpoint, radius
ctx.lineTo(100, 0);               // line from arc-end to outpoint

ctx.translate(130, 0);
ctx.moveTo(0, 0);                 // start point
ctx.arcTo(50, 150, 80, 50, 8);   // intersection, outpoint, radius
ctx.lineTo(80, 50);               // line from arc-end to outpoint

ctx.stroke();
<canvas></canvas>

如果您在不知道交点的情况下将线分开,则可以通过以下方式扩展线以找到交点:

function extendLine(line, scale) {
  var sx = line.startPoint.x,
      sy = line.startPoint.y,
      ex = line.endPoint.x,
      ey = line.endPoint.y;

   return {
     startPoint: {x: sx, y: sy},
     endPoint: {
       x: sx + (ex - sx) * scale,
       y: sy + (ey - sy) * scale
     }
   }
}

比例可能是一个荒谬的值,因为我们需要确保在非常陡峭的角度下线条会在某处相交。不影响计算速度。

然后用两条线(确保第二条线从第一条线的终点继续,这意味着你可能必须反转坐标 - 如果你想动态地这样做,你可以测量每条线的距离第二行的点到第一行的终点,距离最短的在前作为startPoint):

执行步骤将是:

var line1 = ...,
    line2 = ...,
    line1tmp = extendLine(line1, 10000),
    line2tmp = extendLine(line2, 10000),
    ipoint = getIntersection(line1, line2); // see link above

// define the line + arcTo
ctx.moveTo(line1.startPoint.x, line1.startPoint.y);
ctx.arcTo(ipoint.x, ipoint.y, 
          line2.endPoint.x, line2.endPoint.y,
          Math.abs(line2.startPoint.x - line1.endPoint.x) / 2);
ctx.lineTo(line2.endPoint.x, line2.endPoint.y);
ctx.stroke();