Страницы

Поиск по вопросам

вторник, 26 ноября 2019 г.

Примерная замена кубического Безье на две дуги


Привет. Мой старый графический фреймворк (GD) не умеет рисовать кубические кривы
Безье (вообще никакие не умеет). С целью отрисовки символов из TTF шрифтов (напряму
задача не позволяет), хочу как-то частично неадекватно заменить кривые Безье на дуги. Но как? Мне не нужны готовые научные работы (я знаю, они есть и имеют промышленный смысл), которые позволяют набором дуг приблизить результат к кривой Безье максимально точно. Мне достаточно двух дуг.

Вот что у меня есть:


Координаты точек P₁ и P₂ известны. Координаты контрольных точек C₁ и C₂ тоже. И
точек P₁ и P₂ я провел прямые перпендикулярно отрезкам P₁C₁ и P₂C₂ красного цвета. Центры искомых дуг будут лежать на этих прямых, иначе касательные в точках P₁ и P₂ не совпадут, и нарушается условие задачи.

Дальше я решил действовать так. Через среднюю точку P₀ между точками P₁ и P₂ я прове
перпендикулярную отрезку между ними прямую (серый цвет), далее "серый перпендикуляр". Потом добавляю первую окружность (зеленый цвет):



Видно, что в зависимости от ее радиуса R₁ ее центр просто "ездит" по красной прямой, при этом изменяется точка пересечения с серым перпендикуляром и угол пересечения.

Аналогично все и с второй окружностью радиуса R₂ (синий цвет):

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

То есть, исходные данные это P₁, P₂, C₁, C₂, координаты которых (x, y) известны
А найти надо R₁ и R₂ (радиусы окружностей, скалярные числа).

Я уже не в силах решать уравнения с X и Y по-отдельности, с кучей тригонометрии
Может, с помощью векторной алгебры это как-то попроще-изящнее решается?

К вопросу, а что я уже сделал сам. Я решил немного другую задачу, когда заранее известен радиус первой дуги.


Ответы

Ответ 1



В качестве простой альтернативы предлагаю растеризацию. Промежуточные точки высчитываются очень легко: Point GetMiddlePoint(double alpha) { Point Q0 = Middle(P1, C1, alpha); Point Q1 = Middle(C1, C2, alpha); Point Q2 = Middle(C2, P2, alpha); Point R0 = Middle(Q0, Q1, alpha); Point R1 = Middle(Q1, Q2, alpha); return Middle(R0, R1, alpha); } Point Middle(Point X, Point Y, double alpha) => X + (Y - X) * alpha; Соединив промежуточные точки линиями, уже на 8 точках получаем не такой уж плохой результат:

Ответ 2



Вы сформулировали задачу так, что она не имеет решения в общем случае. Так вот, мне нужно найти такие значения радиусов R₁ и R₂, чтобы обе окружности пересекались с серым перпендикуляром в одной точке, кроме того, имели в этой точке одинаковый угол касательной. Если 2 окружности пересекаются, то в точке пересечения они имеют одинаковый уго касательной тогда и только тогда, когда точка пересечения одна: В примере выше, в первых 2 случаях угол касательной одинаковый, в 3 случае, никак нельзя совместить 2 дуги. Я нарисовал в редакторе решение для примера, как на ваших рисунках. Решение не учитывает ваше условие про пересечение на перпендикуляре: Если я продолжу увеличивать радиус большей окружности, и подбирать радиус меньшей что бы они пересекались в одной точке, эта точка никогда не будет на перпендикуляре. Даже если мы увеличим радиус второй окружности до бесконечности (она станет прямой), пересечение все еще не достигнет перпендикуляра: Решение без вложенных окружностей не подходит, потому что дуги не с правильной стороны выходят: Тоже самое и с решением, когда вторая окружность внутри первой:

Комментариев нет:

Отправить комментарий