К написанию этой публикации меня побудила следующая статья на Хабре: «Математика провисающих проводов и цепей в играх», хоть я и совершенно не занимаюсь играми.
Статья заинтересовала меня потому, что давала повод для применения моего собственного приложения для визуализации графических объектов. Первоначальное предназначение этого приложения — исследование динамических систем, которые можно представить в виде системы дифференциальных уравнений. Одним из компонентов этого приложения является вьюер (просмотрщик) трехмерных проволочных моделей. Вьюер нужен для просмотра и анализа трехмерных траекторий динамической системы, но его можно использовать и для просмотра вообще любых проволочных моделей. Недавно я добавил в свое приложение возможность генерации проволочных моделей для заданных параметрически поверхностей. Статья о цепных линиях натолкнула меня на мысль: можно ли для данной трехмерной кривой сгенерировать (и исследовать с помощью вьюера) поверхность в виде трубки, окружающей данную кривую? Такая поверхность может представлять собою модель кабеля, шланга или реального провода ненулевой толщины. Сначала это показалось мне несложной задачей, но выяснилось, что даже для такой относительно простой кривой, как цепная линия, создать трубку не так-то просто.
Приложение для анализа динамических систем позволяет легко строить трехмерные параметрические кривые и рассматривать их с разных сторон. Вот пример нескольких цепных линий, отличающихся значением параметра
Хорошо бы придать этим цепным линиям объем!
Простые трубчатые поверхности
Существует очень небольшое количество кривых, для которых можно сразу выписать параметрическое уравнение поверхности-трубки. Прежде всего это цилиндр
Несложно также написать уравнение поверхности-трубки для окружности, это будет тор, получаемый как поверхность вращения окружности — сечения трубки вокруг не пересекающей его оси ( — расстояние от центра образующей окружности до оси вращения, — радиус образующей окружности)
Для трубки вокруг винтовой линии
(где — радиус, — шаг витков) уже пришлось заглянуть в Гугл, догадаться, как устроено параметрическое уравнение такой поверхности было бы нелегко ( — радиус трубки)
Попытка написать уравнение для трубки вокруг цепной линии по аналогии с винтовой линией, закончилась для меня неудачно, ибо я запутался в получающихся при этом производных и обратных функциях.
Общая схема построения трубки
Тем не менее, применяя общий подход, описанный в книге: Alfred Gray, «Modern Differential Geometry of Curves and Surfaces with Mathematica», у меня получилось реализовать (и запрограммировать) алгоритм построения трубки для произвольной кривой. Скажу сразу, я не претендовал на создание реалистичных трубок с текстурами, тенями и прочим, пришлось ограничиться простыми проволочными моделями.
Проволочную (каркасную) модель трубчатой поверхности можно представлять себе как совокупность образующих, т.е. кривых, находящихся на одном и том же заданном расстоянии от исходной кривой, а также сечений, расположенных перпендикулярно образующим кривым. Для круглой трубки сечения — это окружности, но можно рассматривать также треугольную, квадратную трубки или трубку, имеющую в сечении любой другой правильный многоугольник (на самом деле, сечения-окружности также можно приблизить правильными многоугольниками, имеющими достаточное количество сторон). В целом модель трубки представляет собой пространственный многогранник, при достаточном количестве образующих кривых и сечений выглядящий как настоящая трубка из проволоки. Проворачивая трубку, приближая и удаляя отдельные её части с помощью вьюера проволочных моделей, можно легко проанализировать её устройство.
Построение трубок требует некоторых знаний из дифференциальной геометрии. Для генерации трубки удобно использовать базис Френе. Это подвижная тройка взаимно ортогональных единичных векторов, в каждой точке кривой состоящая из вектора касательной , вектора главной нормали , который перпендикулярен касательному и лежит в соприкасающейся плоскости кривой, и, наконец, вектора бинормали , который определяется как векторное произведение векторов касательной и главной нормали.
Если кривая задана параметрически, то есть в виде зависимости , где — вектор-функция, определяющая координаты каждой точки кривой как — параметр, то формулы для векторов касательной и главной нормали можно выписать, определив первую и вторую производные функции . Особенно просто формулы для касательной и главной нормали выглядят в случае, когда используется естественная параметризация кривой, т.е. параметром является длина кривой от начала до текущей точки . В этом случае
где — производная функции по естественному параметру , — норма (длина) вектора, — векторное произведение.
Если компоненты базиса Френе для данной кривой известны, можно сразу записать параметрическое уравнение трубчатой поверхности в векторной форме:
где — исходная кривая, — главная нормаль, — бинормаль, — радиус трубки,
(понятно, что при фиксированном это уравнение будет определять образующую кривую трубки, а при фиксированном — окружность сечения трубки, лежащую в плоскости, определяемой главной нормалью и бинормалью кривой, эта плоскость перпендикулярна исходной кривой).
Алгоритм построения трубки
В приложении для исследования динамических систем имеется возможность построения
параметрических кривых, заданных аналитически, но мне хотелось уметь строить трубки не только для них, но и для любых траекторий динамических систем, для которых не всегда (а точнее, очень редко) можно выписать аналитическую зависимость траектории от параметра. Поэтому я сформулировал для себя задачу следующим образом: построить трубку для любой дискретной кривой, состоящей из упорядоченного набора точек (фактически это будет ломанная в пространстве). Для этой ломанной, тем не менее, нужно уметь определять первую и вторую производную. Это удобно делать при помощи интерполяционных кубических сплайнов.
Сплайн — это кусочно-полиномиальная функция, которая строится на основании дискретной кривой. В узловых точках сплайн совпадает с дискретной кривой, а в промежутках представляет собой полином третьей степени. Для разных интервалов полиномы различны, но их коэффициенты подбираются так, чтобы сам сплайн, а также его первая и вторая производные были непрерывны на заданном интервале изменения параметра (то есть полиномы на соседних отрезках как бы «сшиваются»).
План построения трубки теперь выглядит так:
- построим естественную параметризацию кривой. Для этого разобьем интервал изменения исходного параметра на равные промежутки, построим сплайны для каждой из координат исходной дискретной кривой. Для вычисления длины кривой воспользуемся равенством для длины участка параметрической кривой, лежащего между значениями параметра и :
соответствующие производные найдем дифференцированием сплайнов, а интегралы определим численно, пользуясь квадратурной формулой Гаусса с пятью узлами - перестроим сплайны для отдельных координат с учетом естественного параметра
- сформируем массив единичных касательных векторов, для этого нужно просто найти производные от сплайнов для отдельных координат по естественному параметру
- сформируем массив единичных векторов главной нормали, это будут вторые производные от сплайнов для отдельных координат, кроме того, их нужно будет отнормировать, поделив на длины векторов
- сформируем массив векторов бинормали, вычислив векторное произведение соответствующих касательных векторов и векторов главной нормали (здесь нормировка уже не нужна, результирующие векторы автоматически будут иметь единичную длину)
- наконец, пользуясь вышеперечисленными компонентами базиса Френе, сгенерируем образующие кривые и сечения
Параметры для построения трубки
Для построения трубки в приложении для анализа динамических систем нужно задать (кроме собственно кривой, по которой строится трубка) небольшое число параметров, определяющих трубку. Параметры задаются в следующей форме:
Фактически в этой форме нужно указать количество точек в образующих кривых (то же, что количество сечений), количество образующих кривых, количество точек в сечении, радиус трубки, а также цвета для образующих кривых и сечений.
Примеры трубок для параметрических кривых
Кривая Вивиани, образуется при пересечение кругового цилиндра со сферой с центром на поверхности цилиндра и радиусом, равным диаметру цилиндра
Линия шва на теннисном мяче — гладкая кривая на поверхности сферы, имеющая четыре точки перегиба
Примеры трубок для фазовых траекторий динамических систем
Переходы Джозефсона (теория сверхпроводимости) — динамическая система для описания явления протекания сверхпроводящего тока через тонкий слой диэлектрика, разделяющий два сверхпроводника
Взаимодействие фотон-экситон в оптическом полупроводнике
Другие трубки для фазовых траекторий динамических систем
Упрощенное уравнение Курамото-Цузуки для процессов, происходящих в нелинейных диссипативных средах диффузионного типа
Одна из систем Спротта-искусственно сконструированных моделей нелинейной динамики (случай F)
Одна из систем Спротта-искусственно сконструированных моделей нелинейной динамики (случай F)
Поучительные ошибки, встретившиеся при отладке и исправленные
Когда генерация трубок только-только заработала (я использовал для отладки трубку для винтовой линии), первые варианты сгенерированной поверхности вместо аккуратного среза на краях трубки имели какой-то «клюв»
Оказалось, что я использовал неподходящие сплайны. Для однозначного определения сплайна нужно задавать для него краевые условия. Наиболее часто встречаются условия вида , которые соответствуют тому, что сплайн на концах интервала определения становится просто прямой. Для трубок же этот вариант неприменим, для них нужно использовать другие условия, задающие положения касательной на концах, т.е. значения производной . Когда я воспользовался сплайнами нужного типа — «клювы» исчезли.
Другая проблема возникла с трубками для динамических систем. Я тренировался на «дверной ручке» — решении краевой задачи для системы
Здесь трубка содержала близко к концам участки с «осиной талией»
В этом случае выяснилось, что кривая, являющаяся решением системы, имеет на соответствующих интервалах точки перегиба, в которых вторая производная, т.е. главная нормаль меняет свой знак (оставаясь при этом главной нормалью). Пришлось такие точки отслеживать и разворачивать в них главную нормаль. После этого «дверные ручки» стали нормальными, пригодными для установки на любую дверь.
Поучительные ошибки
Когда генерация трубок только-только заработала (я использовал для отладки трубку для винтовой линии), первые варианты сгенерированной поверхности вместо аккуратного среза на краях трубки имели какой-то «клюв»
Оказалось, что я использовал неподходящие сплайны. Для однозначного определения сплайна нужно задавать для него краевые условия. Наиболее часто встречаются условия вида , которые соответствуют тому, что сплайн на концах интервала определения становится просто прямой. Для трубок же этот вариант неприменим, для них нужно использовать другие условия, задающие положения касательной на концах, т.е. значения производной . Когда я воспользовался сплайнами нужного типа — «клювы» исчезли.
Другая проблема возникла с трубками для динамических систем. Я тренировался на «дверной ручке» — решении краевой задачи для системы
Здесь трубка содержала близко к концам участки с «осиной талией»
В этом случае выяснилось, что кривая, являющаяся решением системы, имеет на соответствующих интервалах точки перегиба, в которых вторая производная, т.е. главная нормаль меняет свой знак (оставаясь при этом главной нормалью). Пришлось такие точки отслеживать и разворачивать в них главную нормаль. После этого «дверные ручки» стали нормальными, пригодными для установки на любую дверь.
Заключение
Я не уверен, что описанная схема содержит что-либо новое в визуализации трубок, и не знаю, какие методы для их построения используются в настоящих «взрослых» графических системах — возможно, подобные, а возможно — в корне отличающиеся. Тем не менее, мне было интересно разобраться в проблеме и создать работающую систему для построения трубок, шлангов, кабелей и проводов.
А получилось ли сформировать трубки для цепных линий, упомянутых в начале публикации?
Конечно, для цепных линий трубки генерировать очень легко и приятно
Ссылки
- «Равномерное перемещение объекта вдоль кривой» (статья на Хабре)
- Wink — приложение для создания презентаций и Flash-роликов
- GifMaker — средство для создания GIF-анимаций онлайн
- Сайт приложения для исследования динамических систем
Фотография шланга для полива в начале статьи сделана в «Concordia Celes Hotel», Окурджалар, Аланья, Турция, в июне 2021 года.
avdx
Делал такое для ломаных линий. Там нельзя посчитать нормаль по понятным причинам, поэтому просто в первой точке выбирал произвольное направление нормали, перпендикулярное направлению. А потом просто в каждой новой точке поворачивал координатную систему на угол поворота вектора направления (т.е. осью вращения было векторное произведение векторов предыдущего направления и нового).
Странно, кстати, что в статье нет упоминания про проблему пересечения сечений. Для заданных значения кривизны кривой и радиуса сечения всегда существует минимальный шаг между сечениями при котором сечения начнут пересекаться, в результате чего модель получается некорректной.
belch84 Автор
Подход с ломаными и поворотами координатной системы используется в этой книге:
Я тоже работаю с фактически ломаной, но сплайн превращает её в гладкую кривую с непрерывной второй производной, т.е. непрерывно меняющейся главной нормалью (нужно помнить, что сплайны нелокальны, т.е. изменение положения одной из точек кривой изменяет коэффициенты полиномов на всех отрезках, это затратно в смысле вычислений, но волшебным образом преображает ломаную). Что касается пересечения сечений — в большинстве случев можно подобрать такое их количество, чтобы они не пересекались. Реальные кривые являются гладкими не во всех точках, там, где касательная обращается в 0, все равно будут проблемы. Кроме того, именно проволочная модель с очень большим кол-вом сечений вообще будет выглядеть непонятно
avdx
Интерполяцию сплайнами тоже делал. Только использовал эрмитов сплайн, потому что он ведет себя более предсказуемо. Обычный кубический сплайн часто начинает осцилировать, особенно если в интерполируемых данных присутствует шум. Ну и при изменении одной точки эрмитов сплайн меняется только локально. Но зато вторая производная у него не непрерывна.
Поэтому делал так: интерполировал ломаную сплайном, а потом уже делал тесселяцию сплайна ломаной, но уже с более мелким шагом, и для нее уже использовал метод с поворотом координатной системы.