восстановление окружностей из кривых Безье

Я пытаюсь восстановить исходные графические примитивы из путей Postscript / SVG. Таким образом, исходный круг отображается (в разметке SVG) как:

   <path stroke-width="0.5" d="M159.679 141.309 
        C159.679 141.793 159.286 142.186 158.801 142.186 
        C158.318 142.186 157.925 141.793 157.925 141.309 
        C157.925 140.825 158.318 140.432 158.801 140.432 
        C159.286 140.432 159.679 140.825 159.679 141.309" />

Это приближение с использованием 4 кривых Безье для создания круга. В других местах дуги окружности аппроксимируются связанными кривыми Безье.

Мой вопрос в том, есть ли алгоритм, который я могу использовать, чтобы распознать эту конструкцию и восстановить «лучший» круг. Я не против мелких ошибок - в худшем случае они будут второстепенными.

ОБНОВЛЕНИЕ: обратите внимание, что я априори не знаю, что это круг или дуга - это может быть что угодно. И на кривой может быть 2, 3, 4 или, возможно, даже больше точек. Так что мне действительно нужна такая функция:

error = getCircleFromPath(path)

где error даст раннее указание на то, вероятно ли это круг.

[Я согласен с тем, что если я знаю, что это круг, это более легкая проблема.]

ОБНОВЛЕНИЕ: @george каким-то образом решает мою проблему, но я не думаю, что это вся история.

После перевода в начало координат и нормализации у меня появились следующие четыре точки на кривой:

point [0, 1] with control point at [+-d,1] // horizontal tangent
point [1, 0] with control point at [1,+-d] // vertical tangent
point [0, -1] with control point at [+-d,-1] // horizontal tangent
point [-1, 0] with control point at [-1,+-d] // vertical tangent

Это гарантирует, что касательная в каждой точке "параллельна" направлению траектории в этой точке. Он также гарантирует симметрию (4-кратная ось с отражением. Но это не гарантирует круг. Например, большое значение d даст закругленную рамку, а маленькое значение - закругленный ромб.

Мое значение d составляет около 0,57. Это может быть 1 / sqrt (3.) Или что-то еще. Я прошу именно такого рода отношений.

@george дает середину дуги как;

{p1,(p1 + 3 (p2 + p3) + p4)/8,p4}

поэтому в моем примере (от 1,0 до 0,1) это будет: [[1,0]+3[1,d]+3[d,1]+[0,1]] / 8, т.е.

[0.5+3d/8, 3d/8+0.5]

и если d = 0,57, это дает 0,71, поэтому, возможно, d равно

(sqrt(0.5)-0.5)*8./3.

Это справедливо для квадратного ромба, но для дуг окружности формула должна быть более общей, и я был бы признателен, если она у кого-нибудь есть. Например, я не знаком с математикой Безье, поэтому формула @ george была для меня новой.

enter code here

person peter.murray.rust    schedule 16.10.2012    source источник


Ответы (4)


Не делая за вас всех математических расчетов ... это может помочь:

На безье всегда есть 4 контрольные точки. Ваша кривая состоит из 4 точек Безье, связанных вместе с точками 1-4, 4-7, 7-10 и 10-13 - контрольными точками для каждой части. Точки 1, 4, 7 и 10 (& 13 == 1) лежат точно на кривой. Чтобы узнать, получился ли у вас красивый круг, рассчитайте:

center =   ( p1+p7 )/2  =(  {159.679, 141.309} +  {157.925, 141.309} ) / 2
       = {158.802, 141.309}

убедитесь, что вы получили тот же результат, используя пункты 4 + 10 -> {158.801, 141.309}

Как только вы узнаете центр, вы можете выбрать точки вдоль кривой и посмотреть, есть ли у вас постоянное расстояние.

Если у вас есть только одна дуга Безье с 4 точками, полезная формула состоит в том, что средняя точка находится в (p1 + 3 (p2 + p3) + p4) / 8. Итак, вы можете найти круг, проходящий через три точки:

{p1,(p1 + 3 (p2 + p3) + p4)/8,p4}

и снова выберите другие точки на кривой, чтобы решить, действительно ли у вас есть почти дуга окружности.

Отредактируйте формулу Безье так:

x=(1-t)^3 p1 + 3 (1-t)^2 t p2 + 3 (1-t) t^2 p3 + t^3 p4    with  parameter 0 < t < 1

так, например, при t = 1/4 у вас есть

x=( 27 p1 + 27 p2 + 9 p3 + 1 p4 ) / 64

поэтому, как только вы найдете центр, вы можете легко проверить несколько точек и рассчитать расстояние до них.

Я подозреваю, что если вы хотите только обнаружить почти точные дуги окружности, тогда проверка двух дополнительных точек с жестким допуском поможет. Если вы хотите обнаружить объекты примерно круглой формы, я бы вычислил кучу точек и использовал среднюю ошибку в качестве критерия.

person agentp    schedule 16.10.2012
comment
Первый расчет показывает только то, что у вас есть симметричный объект - это может быть округлый прямоугольник, а не круг. Второе соотношение (+1) ценно - необходимо, но все же недостаточно. Если бы вы могли сказать мне, как выбрать точки, отличные от средней, чтобы решить проблему. - person peter.murray.rust; 17.10.2012
comment
Спасибо - я только что увидел ваше обновление, и это то, что я хочу - person peter.murray.rust; 21.10.2012

Если все ваши элементы имеют форму круга, вы можете просто получить размеры через path.getBBox() и создать круг оттуда. В данном случае я рассматриваю эллипсы, но вы можете легко преобразовать их в реальные circle элементы:

var path = document.getElementById("circle_path");
var bbox = path.getBBox();

var rx = bbox.width/2;
var ry = bbox.height/2;
var cx = bbox.x + rx;
var cy = bbox.y + ry;

var ellipse = document.createElementNS(xmlns, "ellipse");
ellipse.setAttribute("fill", "none");
ellipse.setAttribute("stroke", "red");
ellipse.setAttribute("stroke-width", 0.1);
ellipse.setAttribute("cx", cx);
ellipse.setAttribute("cy", cy);
ellipse.setAttribute("rx", rx);
ellipse.setAttribute("ry", ry);

svg.appendChild(ellipse);

Вы можете увидеть демо здесь:

http://jsfiddle.net/nwHm6/

person methodofaction    schedule 16.10.2012
comment
+1 за усилия по созданию jsfiddle. Я обновил свой вопрос, чтобы пояснить, что я не знаю, что ищу круг - person peter.murray.rust; 16.10.2012
comment
Но вы просто хотите преобразовать круги, подобные контурам, в circle, или вы хотите также преобразовать дуги, такие как кривые Безье, в синтаксис дуговых путей? - person methodofaction; 16.10.2012
comment
Оба. И я хочу признать, что это круги и дуги. В моих приложениях будет много дуг - person peter.murray.rust; 16.10.2012
comment
Но поскольку в SVG нет элемента arc, зачем вам переводить из одного синтаксиса пути в другой? это все равно будет <path d="M 0 0 A 100 49 ..." /> - person methodofaction; 16.10.2012
comment
Я хочу распознать это как дугу и аннотировать SVG. Да, явного синтаксиса SVG может и не быть, но я все же могу добавить комментарий, что это дуга с радиусом R от начала до конца. Путь мне об этом не говорит. (Аналогичным образом я реконструирую прямоугольники и многоугольники из путей). Я хочу проанализировать и классифицировать результаты (например, содержит ли эта страница дуги окружности с радиусом ‹10 пикселей - person peter.murray.rust; 16.10.2012

Концы кривых Безье, вероятно, находятся на окружности. Если это так, то легко восстановить исходный круг.

Другая возможность - принять центр масс контрольных точек за центр круга, потому что контрольные точки, вероятно, расположены симметрично относительно центра. Радиус из центра определяется как среднее расстояние от четырех ближайших к центру контрольных точек.

person lhf    schedule 16.10.2012
comment
Но может не быть ровно четырех точек и не может быть полного круга. - person peter.murray.rust; 16.10.2012

Можно определить эллипс как единичный круг с центром в точке (0,0), сдвинутый (2 параметра), масштабированный (2 параметра) и повернутый (1 параметр). Итак, на каждой дуге возьмите пять точек (t = 0 ¼ ½ ¾ 1) и решите эти пять параметров. Затем возьмите промежуточные четыре точки (t = ⅛ ⅜ ⅝ ⅞) и проверьте, лежат ли они на одной и той же преобразованной окружности. Если да, то блин !, это (часть) преобразованного круга.

Непосредственно перед и после может быть другой arc или arcn. Это одинаковые эллипсы? Если да, и обозначенные углы соприкасаются, тогда объедините свои описания частей.

person jdaw1    schedule 01.04.2013