Привет. Мой старый графический фреймворк (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 дуги. Я нарисовал в редакторе решение для примера, как на ваших рисунках. Решение не учитывает ваше условие про пересечение на перпендикуляре: Если я продолжу увеличивать радиус большей окружности, и подбирать радиус меньшей что бы они пересекались в одной точке, эта точка никогда не будет на перпендикуляре. Даже если мы увеличим радиус второй окружности до бесконечности (она станет прямой), пересечение все еще не достигнет перпендикуляра: Решение без вложенных окружностей не подходит, потому что дуги не с правильной стороны выходят: Тоже самое и с решением, когда вторая окружность внутри первой:
вторник, 26 ноября 2019 г.
Примерная замена кубического Безье на две дуги
Подписаться на:
Комментарии к сообщению (Atom)
Комментариев нет:
Отправить комментарий