Как создать кривые Безье из B-сплайнов в Sympy? - PullRequest
0 голосов
/ 02 июля 2019

Мне нужно нарисовать плавную кривую через некоторые точки, которые я затем хочу показать как путь SVG.Поэтому я создаю B-Spline с scipy.interpolate и могу получить доступ к некоторым массивам, которые, я полагаю, полностью его определяют.Кто-нибудь знает достаточно простой способ создания кривых Безье из этих массивов?

import numpy as np
from scipy import interpolate

x = np.array([-1, 0, 2])
y = np.array([ 0, 2, 0])

x = np.r_[x, x[0]]
y = np.r_[y, y[0]]

tck, u = interpolate.splprep([x, y], s=0, per=True)

cx = tck[1][0]
cy = tck[1][1]

print(          'knots: ', list(tck[0]) )
print( 'coefficients x: ', list(cx)     )
print( 'coefficients y: ', list(cy)     )
print(         'degree: ', tck[2]       )
print(      'parameter: ', list(u)      )

enter image description here

Красные точки - это 3 начальные точки в x и y.Зеленые точки - это 6 коэффициентов в cx и cy.(Их значения повторяются после 3-й, поэтому каждая зеленая точка имеет два зеленых номера индекса.)

Возвращаемые значения tck и u описаны scipy.interpolate.splprep документация

knots:  [-1.0, -0.722, -0.372, 0.0, 0.277, 0.627, 1.0, 1.277, 1.627, 2.0]

#                   0       1       2       3       4       5
coefficients x:  [ 3.719, -2.137, -0.053,  3.719, -2.137, -0.053]
coefficients y:  [-0.752, -0.930,  3.336, -0.752, -0.930,  3.336]

degree:  3

parameter:  [0.0, 0.277, 0.627, 1.0]

Ответы [ 2 ]

2 голосов
/ 03 июля 2019

Не уверен, что начинать с B-сплайна имеет смысл: сформировать кривую ромбовидного романа через точки (с виртуальными «до первого» и «после последнего», наложенными на реальные точки), а затем преобразовать это в кривую Безье, используя относительно тривиальное преобразование ?Например, учитывая ваши точки p0, p1 и p2, первый сегмент будет кривой скручивания {p2, p0, p1, p2} для сегмента p1 - p2, {p0, p1, p2, p0} даст p2--p0, и {p1, p2, p0, p1} приведут к p0 - p1.Затем вы тривиально конвертируете их, и теперь у вас есть SVG-путь.

В качестве демонстратора нажмите https://editor.p5js.org/ и вставьте следующий код:

var points = [{x:150, y:100 },{x:50, y:300 },{x:300, y:300 }];

// add virtual points:
points = points.concat(points);

function setup() {
  createCanvas(400, 400);
  tension = createSlider(1, 200, 100);
}

function draw() {
  background(220);
  points.forEach(p => ellipse(p.x, p.y, 4));

  for (let n=0; n<3; n++) {
    let [c1, c2, c3, c4] = points.slice(n,n+4);
    let t = 0.06 * tension.value();

    bezier(
      // on-curve start point
      c2.x, c2.y,
      // control point 1
      c2.x + (c3.x - c1.x)/t,
      c2.y + (c3.y - c1.y)/t,
      // control point 2
      c3.x - (c4.x - c2.x)/t,
      c3.y - (c4.y - c2.y)/t,
      // on-curve end point
      c3.x, c3.y
    );
  }
}

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

Преобразование этого в код Python должно быть почти легким упражнением: для нас почти нет кода для написания =)

И, конечно,Теперь вы можете создать путь SVG, но это вряд ли проблема: теперь вы знаете все точки Безье, поэтому просто начните строить строку <path d=...>, пока вы выполняете итерацию.

0 голосов
/ 09 июля 2019

Кривая B-сплайна - это просто набор кривых Безье, соединенных вместе. Поэтому, безусловно, можно преобразовать его обратно в несколько кривых Безье без потери точности формы. Используемый алгоритм называется «вставка узла», и существуют разные способы сделать это с помощью двух самых известных алгоритмов - алгоритма Бёма и алгоритма Осло. Вы можете отослать эту ссылку для более подробной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...