Arc SVG参数

时间:2017-12-06 22:56:29

标签: javascript python svg plotly trigonometry

我一直在努力理解arc svg,因为我似乎需要它们 - 我的目标是绘制圆形交叉点。

我最初的想法是这样的:

enter image description here

对于每个交叉路口,找到起点和终点坐标以及高度 - 但我不太清楚从哪里开始。看来我缺少旋转和大弧标记/扫描参数,我不知道如何检索它们。如果有人能指出我在这里正确的方向,那将是伟大的!

2 个答案:

答案 0 :(得分:4)

圈子和截取点

不太了解SVG arcTo。 MDN提供"A rx,ry xAxisRotate LargeArcFlag,SweepFlag x,y"。作为路径元素中的弧。什么rx和ry是???我猜半径为x,y。

我猜你会用它作为

// x,y start position
// rx,ry radius x and y
// x1,y1 end position
<path d="M x,y A rx, ry, 0 1 1 x1, y1"/>

以下是javascript解决的问题。我已经评论了SVG所需的部分。两个终点(拦截)

有很多冗余,但不清楚你想要什么,所以代码提供了如何找到两个相交圆的其他部分。

余弦定律

解决问题的数学运算称为law of cosines,用于求解三角形。

在这种情况下,三角形由3个长度组成。圆半径各一个,圆中心之间的距离为1。图像提供了更多细节

enter image description here

使用角度c,您可以找到长度GE,DE和EF。如果你想在f点另一边的角度只是交换B和C.

实施例

移动鼠标以检查拦截。

&#13;
&#13;
const ctx = canvas.getContext("2d");
const m = {
  x: 0,
  y: 0
};
document.addEventListener("mousemove", e => {
  var b = canvas.getBoundingClientRect();
  m.x = e.pageX - b.left - scrollX;
  m.y = e.pageY - b.top - scrollY;
});
const PI = Math.PI;
const PI2 = Math.PI * 2;
const circles = [];

function circle(x, y, r, col, f = 0, t = PI2, w = 2) {
  var c;
  circles.push(c = { x, y,r, col, f, t, w});
  return c;
};

function drawCircle(A) {
  ctx.strokeStyle = A.col;
  ctx.lineWidth = A.w;
  ctx.beginPath();
  ctx.arc(A.x, A.y, A.r, A.f, A.t);
  ctx.stroke();
}

function mark(x, y, r, c) {
  ctx.strokeStyle = c;
  ctx.lineWidth = 2;
  ctx.beginPath();
  ctx.arc(x, y, r, 0, PI2);
  ctx.stroke();
}

function line(A, B, c) {
  ctx.strokeStyle = c;
  ctx.lineWidth = 2;
  ctx.beginPath();
  ctx.lineTo(A.x, A.y);
  ctx.lineTo(B.x, B.y);
  ctx.stroke();
}

// note I am sharing calc results between function  


function circleIntercept(A, B) {
  var vx, vy, dist, c, d, x, y, x1, y1, x2, y2, dir, a1, a2;
  // Vec from A to B
  vx = B.x - A.x;
  vy = B.y - A.y;
  // Distance between
  dist = Math.sqrt(vx * vx + vy * vy);
  // Are the intercepting
  if (dist < A.r + B.r && dist > B.r - A.r) {
    c = (B.r * B.r - (dist * dist + A.r * A.r)) / (-2 * dist);

    // Find mid point on cord
    x = A.x + vx * (c / dist);
    y = A.y + vy * (c / dist);
    mark(x, y, 5, "blue");

    // Find circumference intercepts

    //#################################################################
    //=================================================================
    // SVG path 
    // Use x1,y1 and x2,y2 as the start and end angles of the ArcTo SVG
    d = Math.sqrt(A.r * A.r - c * c);
    x1 = x - vy * (d / dist);
    y1 = y + vx * (d / dist);
    x2 = x + vy * (d / dist);
    y2 = y - vx * (d / dist);
    // SVG path from above coords
    // d = `M ${x1}, ${y1} A ${A.r}, ${A,r1} 0, 1, 1, ${x2}, ${y2}`;
    //=================================================================

    // draw the chord
    line({x: x1,y: y1}, {x: x2,y: y2}, "red");
    
    // mark the intercepts
    mark(x1, y1, 5, "Green");
    mark(x2, y2, 5, "Orange");

    // Get direction from A to B
    dir = Math.atan2(vy, vx);

    // Get half inside sweep
    a1 = Math.acos(c / A.r);

    // Draw arc for A
    A.col = "black";
    A.w = 4;
    A.f = dir - a1;
    A.t = dir + a1;
    drawCircle(A);
    A.col = "#aaa";
    A.w = 2;
    A.f = 0;
    A.t = PI2;

    // inside sweep for B
    a2 = Math.asin(d / B.r);

    // Draw arc for B
    B.col = "black";
    B.w = 4;
    if (dist < c) {
      B.t = dir - a2;
      B.f = dir + a2;
    } else {

      B.f = dir + PI - a2;
      B.t = dir + PI + a2;
    }
    drawCircle(B);
    B.col = "#aaa";
    B.w = 2;
    B.f = 0;
    B.t = PI2;

  }

}

var w = canvas.width;
var h = canvas.height;
var cw = w / 2; // center 
var ch = h / 2;
var C1 = circle(cw, ch, ch * 0.5, "#aaa");
var C2 = circle(cw, ch, ch * 0.8, "#aaa");

function update(timer) {
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.globalAlpha = 1;
  if (w !== innerWidth || h !== innerHeight) {
    cw = (w = canvas.width = innerWidth) / 2;
    ch = (h = canvas.height = innerHeight) / 2;
    C1.x = cw;
    C1.y = ch;
    C1.r = ch * 0.5;
    ctx.lineCap = "round";
  }
  C2.x = m.x;
  C2.y = m.y;
  ctx.clearRect(0, 0, w, h);


  drawCircle(C1);
  drawCircle(C2);
  circleIntercept(C1, C2);






  requestAnimationFrame(update);
}
requestAnimationFrame(update);
&#13;
canvas {
  position: absolute;
  top: 0px;
  left: 0px;
}
&#13;
<canvas id="canvas"></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

让我们从一些术语开始,以清除顺时针方向(记住SVG的y轴向下):第一个圆有半径r1,第二个{{1 }}

  • 如果第一个圆的中心低于第二个圆的中心(r2),则将交叉点命名为较小的x坐标cy1 > cy2,另一个(x1, y1)
  • 如果第一个圆的中心高于第二个圆的中心((x2, y2)),则将交叉点命名为较大的x坐标cy1 < cy2,另一个(x1, y1)
  • 否则,请使用较小的y坐标(x2, y2)和另一个(x1, y1)命名交叉点。

现在我们将从第一个到第二个交叉点绘制一个圆弧,该圆弧的半径为第一个圆。前两个弧参数是水平和垂直半径。由于我们画一个圆圈,两者都是相同的。出于同样的原因,旋转半径没有意义,第三个参数是0。

两个圆的交点总是使用小弧(大弧将用于并集),因此大弧标志为0.我们正在顺时针绘制弧,因此扫描标志为1.

还不清楚? spec使用此图片来解释标志:

enter image description here

第二个弧从第二个圆到第一个交叉点,第二个圆的半径。标志保持不变。

结果如下:

(x2, y2)