Параметры Arc SVG

1

Я пытался понять arc svg, так как кажется, что я нуждаюсь в них в замысле - моя цель - построить пересечение круга.

Моя оригинальная идея была примерно такой:

Изображение 174551

для каждого пересечения, чтобы найти начальную и конечную координаты, а также высоту - но я не очень уверен, куда идти отсюда. Кажется, мне не хватает параметров вращения и большого дугового флага /Sweep, и я не уверен, как я собираюсь их восстановить. Если бы кто-нибудь мог указать мне в правильном направлении здесь, это было бы здорово!

Теги:
svg
plotly
trigonometry

2 ответа

3
Лучший ответ

Круги и точки перехвата

Не знаю много о 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. Две конечные точки (перехваты)

Существует много избыточности, но неясно, чего вы хотите, поэтому код обеспечивает, как найти другие части двух пересекающихся кругов.

Закон Косинеса

Математика для решения проблемы называется законом косинусов, который используется для решения треугольников.

В этом случае треугольник создается из 3-х длин. Каждый из радиуса окружности и один - это расстояние между центрами окружности. Изображение дает более подробную информацию

Изображение 174551

С углом c вы можете найти длины GE, DE и EF. Если вам нужен угол для другой стороны в точке f, просто замените B и C.

пример

Переместите мышь, чтобы проверить перехват.

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);
canvas {
  position: absolute;
  top: 0px;
  left: 0px;
}
<canvas id="canvas"></canvas>
  • 0
    Мне потребовалось некоторое время, чтобы проработать это :) Я хотел бы дать вам больше голосов за это! Вероятно, я должен учиться и делать свой проект в JS, а не преобразовывать свои результаты в SVG из Python. Спасибо!!
  • 1
    @erocoar Во время набора текста я забыл добавить самую важную часть. Вся математика основана на законе косинусов en.wikipedia.org/wiki/Trigonometric_functions#Law_of_cosines, которые обеспечивают простой способ решения любого треугольника, если у вас есть 3 из 3 треугольников, 6 свойств (3 длины сторон и 3 угла). Перехватывает круг является решением треугольника со сторонами A, B, C, где A - это расстояние между центрами окружностей, а B и C - это радиус двух окружностей. Угол acos((C*C-(A*A+B*B))/(-2*A*B)) - угол от линии соединения до точки пересечения.
Показать ещё 1 комментарий
1

Начнем с некоторой терминологии, чтобы прояснить, что такое по часовой стрелке (помните, что ось y SVG идет вниз): первый круг имеет радиус r1, второй r2.

  • Если центр первого круга меньше, чем центр второго (cy1 > cy2), то укажите точку пересечения с меньшей координатой x (x1, y1), а другую (x2, y2).
  • Если центр первого круга больше, чем центр второго (cy1 < cy2), то укажите точку пересечения с большей координатой x (x1, y1), а другая (x2, y2).
  • Иначе, назовите точку пересечения с меньшей координатой y (x1, y1), а другую (x2, y2).

Теперь мы проведем дугу от первой до второй точки пересечения с радиусом первого круга. Первыми двумя параметрами дуги являются горизонтальный и вертикальный радиус. Поскольку мы рисуем круг, оба они одинаковы. По этой же причине вращение радиусов не имеет смысла, а третий параметр равен 0.

Пересечение двух окружностей всегда использует малую дугу (большая дуга будет использоваться для объединения), поэтому большой флаг дуги равен 0. Мы рисуем дугу по часовой стрелке, поэтому флаг развертки равен 1.

Все еще неясно? Спектр использует это изображение для объяснения флагов:

Изображение 174551

Вторая дуга идет от второй к первой точке пересечения с радиусом второго круга. Флаги остаются неизменными.

Результат выглядит следующим образом:

M x1, y1 A r1 r1 0 0 1 x2, y2 A r2 r2 0 0 1 x1, y1 Z
  • 0
    Спасибо! Это действительно полезно - я думаю, что ошибся, рассматривая пересечение как часть нового эллипса. :) Для определения, какой круг слева / справа, я бы сделал это по углу?
  • 0
    Это больше вопрос о том, как вы заказываете точки пересечения. Вы также можете сказать: нарисуйте стрелку от круга 1 до круга 2 и перейдите от точки пересечения слева от стрелки к точке справа с радиусом 1 и обратно с радиусом 2. Все зависит от вашего кода.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню