Как я могу распределить точки равномерно по овалу? - PullRequest
1 голос
/ 24 октября 2019

У меня есть овал (как SVG)

Я хочу распределить n точек вдоль овала:

  • равномерно
  • вставьте точки на x процентов
  • , ограниченных нижним f процентами овала

Как я могу сделать это программно? Мне просто нужен список координат в качестве вывода.

enter image description here

SVG эллипса:

<svg id="svg2" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="297mm" width="210mm" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 744.09448819 1052.3622047">
 <g id="layer1">
  <ellipse id="path8074" rx="78.559" ry="105.84" stroke="#000" cy="489.51" cx="314.29" stroke-width=".38188px" fill="none"/>
 </g>
</svg>

Ответы [ 2 ]

3 голосов
/ 24 октября 2019

Расчет эквидистантной точки по окружности эллипса - довольно сложная математическая задача. Кроме того, параллельная кривая (внутрь) для эллипса не является эллипсом.

Если ваш эллипс не слишком сжат (отношение a / b находится в диапазоне 0.5..2), вы можете использовать простое приближение через равноудаленное расстояние tпараметр эллиптического уравнения. В противном случае дисперсия расстояния будет слишком высокой, и вам потребуется более сложный подход на основе расчета длины дуги / расстояния (требуется числовое интегрирование).

[Редактировать]: я добавил некоторую коррекцию t, чтобы улучшить распределение точек. Идея взята отсюда ,

Используя уравнение параллельной кривой , мы можем рассчитать точки таким образом (код Delphi в качестве ссылки):

var
  i, a, b, cx, cy, x, y, k, N: Integer;
  sq, t: Double;
begin
  N := 30;     // Number of points
  a := 120;  //semiaxes
  b := 200;
  cx := 300;   //center
  cy:= 300;
  k := 30;     //inward distance

  Canvas.Ellipse(cx - a, cy - b, cx + a, cy + b);
  for i := 0 to N - 1 do begin
    t := 2 * Pi * i / N;
    //empirically adopted coefficient 0.3
    t := t + 0.3 * ArcTan((a-b)*tan(t)/(a + b * sqr(tan(t))));
    sq := 1.0 / Hypot(a * sin(t), b * cos(t));
    x := Round(cx + (a - b * k * sq) * Cos(t));
    y := Round(cy + (b - a * k * sq) * Sin(t));
    Canvas.Ellipse(x-2,y-2,x+3,y+3);
  end;

enter image description here

2 голосов
/ 24 октября 2019

Вот как я бы это сделал:

  1. Я изменил имеющийся у вас эллипс, чтобы я центрировал его вокруг 0. Чтобы сохранить положение, я перевожу группу <g id="layer1" transform="translate(314.29,489.51)">.

  2. Я рисую еще один эллипс внутри. Атрибут rx этого эллипса - это rx эллипса path8074, умноженный на коэффициент. Допустим, 8. То же самое для ry. Я называю этот эллипс inner

  3. Я вычисляю общую длину внутреннего эллипса, используя let innerLength = inner.getTotalLength();

  4. let n = 10:это количество точек, которое нужно вставить

  5. Я использую цикл for(let i = 0; i < n; i++){ для вычисления координат точек на внутренней траектории let length = i * innerLength / n; let p = inner.getPointAtLength(length); и для рисования кругаотметить точку: drawCircle({cx:p.x,cy:p.y,r:2}, layer1)

const SVG_NS = 'http://www.w3.org/2000/svg';
let rx = path8074.getAttribute("rx");
let ry = path8074.getAttribute("ry");

let factor = .8;
inner.setAttributeNS(null,"rx",rx*factor);
inner.setAttributeNS(null,"ry",ry*factor);

let innerLength = inner.getTotalLength();
let n = 10;//n points

for(let i = 0; i < n; i++){
  let length = i * innerLength / n;
  let p = inner.getPointAtLength(length);
  drawCircle({cx:p.x,cy:p.y,r:2}, layer1)
}

// a function to draw a circle
function drawCircle(o, parent) {
  var circle = document.createElementNS(SVG_NS, 'circle');
  for (var name in o) {
    if (o.hasOwnProperty(name)) {
      circle.setAttributeNS(null, name, o[name]);
    }
  }
  parent.appendChild(circle);
  return circle;
}
<svg id="svg2" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="297mm" width="210mm" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="200 350 744.09448819 1052.3622047">
 <g id="layer1" transform="translate(314.29,489.51)">
  <ellipse id="path8074" rx="78.559" ry="105.84" stroke="#000" stroke-width=".38188px" fill="none"/>
  <ellipse id="inner" stroke="#000"  stroke-width=".38188px" fill="none"/>
 </g>
</svg>

Надеюсь, это поможет.

НАБЛЮДЕНИЕ: Я изменил viewBox элемента svg, потому что я хотел, чтобы эллипсы были видны. Вы можете изменить его обратно на то, что было.

...