Рассмотрение различных способов улучшить рисование

На прошлой неделе я опубликовал статью, в которой рассказывалось о создании пользовательского кругового жеста. Статья, которая по сути является обновлением этого прекрасного туториала на сайте https://www.raywenderlich.com. Хотя было слишком много, чтобы сказать это по-настоящему. Ключевой фразой в этой статье был метод подгонки Таубина, упомянутый ближе к концу. Один из полудюжины алгоритмов, пытающихся подогнать точки к кругу.



Теперь, предположив, что вы читали ее и/или лучше попробовали — моя статья, а не статья Рэя :), вы бы поняли, что сопоставление нарисованных от руки кругов с геометрическими — настоящая проблема. Задача, над которой математики работали веками. Проблема, для которой в сети можно найти еще несколько готовых решений/альтернативных алгоритмов. Решения в таких местах, как сайт Николай Чернов, которые вы найдете здесь.

Но подождите — прежде чем вы уйдете — здесь есть вариант, которого у математиков до недавнего времени не было. Шанс вмешаться в рисунок круга, прежде чем мы попытаемся его подогнать. Присоединяйтесь ко мне в этом путешествии, чтобы исследовать некоторые альтернативы, чтобы сделать все правильно, прежде чем что-то пойдет не так.

Предварительная фиксация

Как это работает? Ну, в основном я останавливаю рисование пользователем напрямую и использую перетаскивание как подсказку для создания круга.

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

Перерисовка

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

Решение, которое хорошо работает, особенно с младшими возрастными группами, которым вообще сложно нарисовать круг. Это отличное решение, если ваш клиент доволен тем, как оно работает.

Примечание. Я продолжил работу над этим решением, переработал DrawPoly и использовал AnimatableData для создания изображения, которое вы видите в заголовке этой статьи. На данный момент это мое любимое решение.

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

Код, который я вызываю, собрав все точки с этим вызовом в модификаторе просмотра .end моего перетаскивания.

.onEnded({ (_) in
  touchedPoints.locals[indexed] = newPath(pointsArray:   touchedPoints.locals[indexed])
...
})

Ограничить направление

Это похоже на последнюю попытку, за исключением того, что я просматриваю координаты в реальном времени и решаю, основываясь на их направлении, добавлять их к линии рисования или нет. Короче говоря, если вы не меняете X и Y одновременно, вы не рисуете круг.

Это работает лучше, чем предыдущее решение, поскольку кажется чище. Но, возможно, это возвращает слишком много контроля пользователю. Я думаю, мы можем обнаружить, что это будет продолжать возвращать ложные отрицательные значения слишком часто.

Кодировать.

Ограничить скорость

Если у вас есть дети, вы наверняка пробовали эту технику с ними. Вспомните, как вы учили их писать, и они хотят вернуться к игровой приставке. Они торопили события, и казалось, что по странице прополз паук. Вы просите их сделать это снова, но на этот раз медленнее. Это подход, который мы можем использовать с нашим сопротивлением, поскольку оно записывает скорость, с которой оно движется. Мы можем использовать скорость, чтобы определить, нужно ли нам добавлять координаты или нет.

Этот метод работает, и все же показывает пол в том, как мы рисуем здесь. Вы видите, когда я двигаюсь медленно, я получаю разумный круг, но если я двигаюсь быстро, это беспорядок. Чтобы это действительно работало, вам также нужно переосмыслить DrawPolygon.

Кодировать.

Регистрация точек каждые X долей секунды

Оглядываясь назад на самые уродливые нарисованные круги, почти всегда те, которые выглядят как спущенная шина и / или кривые шестиугольники, не могут быть распознаны как круги. Ограничение расстояния, на которое мы путешествуем, поможет сгладить подобные проблемы. Это в некотором смысле другой подход к ограничению скорости. Это заставит пользователя рисовать круг медленнее.

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

Направление управления II

Наконец, возвращаясь к предложенному методу управления направлением, мне пришло в голову, что мы можем сделать больше по этому поводу. Ведь круг — это набор путей с заранее заданным маршрутом. Мы могли бы использовать наборы предопределенных путей, чтобы принимать более обоснованные решения относительно того, движется ли пользователь в правильном или неправильном направлении.

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

Чтобы закодировать…

Это тоже работает довольно хорошо, хотя, если вы просмотрите код, вы найдете некоторые глобальные переменные, также известные как ошибка в процессе создания. Вы все еще можете сделать закорючку, если постараетесь, но это немного сложнее.

Динамическая посадка

На данный момент я превысил 1024 слова, и, боюсь, мне нужно довести эту статью до конца. Но прежде чем я пойду, объяснение. Это еще одно расширение предыдущего метода, только область рисования будет контролироваться еще более жестко. Ограничение не только направления, в котором вы идете, но и пикселей, которые вы можете активировать. Я могу изучить это и, возможно, опубликовать третью часть, напишите мне, если хотите ее увидеть.

Машинное обучение

Извините, я тоже не буду здесь это рассматривать. Я думаю, ему нужна своя газета. Но давайте поговорим об этом на мгновение. В конце концов, это звучит как одна из тех нечетких задач машинного обучения. Представьте себе — вы могли бы отметить в своей игре, какие кружки обводят рисунки пользователя, проходящие подгонку Таубина, и каким-то образом внести смещение в рисунок, чтобы пользователю было предложено рисовать именно таким образом. Стоит ли рассматривать эту идею? Оставьте комментарий, если вы думаете, что я должен исследовать это дальше.

Возможно, вы придумаете другой способ. Не стесняйтесь предлагать это в комментариях, и я постараюсь воплотить вашу идею в код. Спасибо, что нашли время, чтобы прочитать это — я надеюсь, что вам было так же интересно читать, как и мне писать. Следуйте за мной на medium.com, чтобы получать больше исследований, советов и методов решения реальных проблем кодирования.

Наконец, извините, но у меня не хватило места, чтобы показать, как мне удалось создать изображение заголовка с анимацией, хотя будьте уверены, что это не так уж отличается. Я думаю, что в ближайшем будущем я сделаю одну или две части анимации в SwiftUI.

Сохраняйте спокойствие, продолжайте кодировать.