Я работаю над игрой, которая требует, чтобы игроки рисовали линию от точки A (x1, y1) до другой точки B (x2, y2) на экране устройства Android.
Я хочу выяснить, насколько хорошо этот рисунок подходит к прямой линии. Например, результат 90% будет означать, что рисунок почти идеально соответствует линии. Если игроки проводят изогнутую линию от А до В, она должна получить низкую оценку.
Конечные точки заранее неизвестны. Как я могу это сделать?
j=1
так что вы можете сравнитьtouchList[j]
сtouchList[j-1]
, но когдаtouch.phase == TouchPhase.Began
илиtouch.phase == TouchPhase.Ended
позиции не добавляютсяtouchList
и впоследствии не включены вsumLength
. Эта ошибка будет присутствовать во всех случаях, но будет более очевидной, когда линия имеет несколько сегментов.Ответы:
Совершенно прямая линия также будет самой короткой из возможных линий общей длиной
sqrt((x1-x2)² + (y1-y2)²)
. Более набросанная линия будет менее идеальной связью и, следовательно, будет неизбежно более длинной.Когда вы берете все отдельные точки пути, который нарисовал пользователь, и суммируете расстояния между ними, вы можете сравнить общую длину с идеальной длиной. Чем меньше общая длина, деленная на идеальную длину, тем лучше линия.
Вот визуализация. Когда черные точки являются конечными точками жеста, а синие точки - это точки, которые вы измерили во время жеста, вы должны рассчитать и сложить длины зеленых линий и разделить их на длину красной линии:
Счет или индекс извилистости 1 был бы идеальным, все, что выше, было бы менее совершенным, что-либо ниже 1 было бы ошибкой. Когда вы предпочитаете иметь счет в процентах, разделите 100% на это число.
источник
Это также может быть не лучшим способом реализации этого, но я предлагаю RMSD (среднеквадратичное отклонение) может быть лучше, чем просто метод расстояния, в случаях, упомянутых Dancrumb (см. Первые две строки ниже).
RMSD = sqrt(mean(deviation^2))
Заметка:
=sum(abs(deviation))
)(Прошу прощения за низкое качество моего рисунка)
Как видите, вы должны
Если ваша линия указывает на
(1, 3)
то, что вы хотите(3, -1)
(через начало координат)h
от идеальной линии до пользовательской, параллельной этому вектору.источник
Существующие ответы не учитывают, что конечные точки являются произвольными (а не заданными). Таким образом, при измерении прямолинейности кривой не имеет смысла использовать конечные точки (например, для вычисления ожидаемой длины, угла, положения). Простым примером будет прямая линия с обоими концами. Если мы измеряем с использованием расстояния от кривой и прямой линии между конечными точками, это будет довольно большим, поскольку нарисованная нами прямая линия смещена от прямой линии между конечными точками.
Как мы скажем, насколько прямая кривая? Предполагая, что кривая достаточно гладкая, мы хотим знать, насколько в среднем изменяется касательная к кривой. Для линии это будет ноль (поскольку касательная постоянна).
Если мы примем положение в момент времени t (x (t), y (t)), то касательная будет (Dx (t), Dy (t)), где Dx (t) - производная от x в момент времени t (на этом сайте отсутствует поддержка TeX). Если кривая не параметризована длиной дуги, мы нормализуем ее делением на || (Dx (t), Dy (t)) ||. Таким образом, у нас есть единичный вектор (или угол) касательной к кривой в момент времени t. Таким образом, угол a (t) = (Dx (t), Dy (t)) / || (Dx (t), Dy (t)) ||
Затем нас интересует || Da (t) || ^ 2, интегрированное вдоль кривой.
Учитывая, что у нас, скорее всего, есть дискретные точки данных, а не кривая, мы должны использовать конечные разности для аппроксимации производных. Итак, Да (т) становится
(a(t+h)-a(t))/h
. И, (т) становится((x(t+h)-x(t))/h,(y(t+h)-y(t))/h)/||((x(t+h)-x(t))/h,(y(t+h)-y(t))/h)||
. Затем мы получаем S путем суммированияh||Da(t)||^2
для всех точек данных и, возможно, нормализации по длине кривой. Скорее всего, мы используемh=1
, но это действительно просто произвольный масштабный коэффициент.Повторим, S будет нулем для линии и чем больше, тем больше она отклоняется от линии. Для преобразования в нужный формат используйте
1/(1+S)
. Учитывая, что масштаб является несколько произвольным, можно умножить S на некоторое положительное число (или преобразовать его другим способом, например, использовать bS ^ c вместо S), чтобы отрегулировать, насколько прямолинейны определенные кривые.источник
Это система на основе сетки, верно? Найдите свои собственные точки для линии и рассчитайте наклон линии. Теперь, используя это вычисление, определите действительные точки, через которые должна пройти линия, учитывая некоторую погрешность от точного значения.
С помощью небольшого количества тестов методом проб и ошибок определите, какое будет хорошее и плохое количество совпадающих точек, и настройте свою игру, используя шкалу для тех же результатов вашего тестирования.
т. е. короткая линия с почти горизонтальным уклоном может иметь 7 точек, через которые вы можете провести. Если вы можете последовательно соответствовать 6 или более из 7, которые были определены как часть прямой линии, то это будет самый высокий балл. Оценка по длине и точности должна быть частью оценки.
источник
Очень простой и интуитивно понятный способ измерения - это область между наиболее подходящей прямой линией и реальной кривой. Определить это довольно просто:
источник
Идея состоит в том, чтобы сохранить все точки, к которым пользователь прикоснулся, а затем оценить и суммировать расстояние между каждой из этих точек до линии, образованной, когда пользователь отпускает экран.
Вот кое-что, с чего можно начать в псевдокоде:
Что
cumulativeDistance
может дать вам представление о примерке. Расстояние 0 означало бы, что пользователь все время был на линии. Теперь вам нужно сделать несколько тестов, чтобы увидеть, как он ведет себя в вашем контексте. И вы можете усилить возвращаемое значениеdistanceOfPointToLine
, возведя его в квадрат, чтобы наказать больше на больших расстояниях от линии.Я не знаком с единством, но код
update
здесь может идти вonDrag
функции.И вы можете захотеть добавить где-то там некоторый код, чтобы предотвратить регистрацию точки, если она совпадает с последней зарегистрированной точкой. Вы не хотите регистрировать вещи, когда пользователь не двигается.
источник
Один из методов, который вы можете использовать, состоит в том, чтобы разделить линию на сегменты и сделать произведение векторной точки между каждым вектором, представляющим сегмент, и вектором, представляющим прямую линию между первой и последней точкой. Преимущество этого состоит в том, что вы можете легко находить чрезвычайно «колючие» сегменты.
Редактировать:
Кроме того, я хотел бы рассмотреть возможность использования длины сегмента в дополнение к точечному произведению. Очень короткий, но ортогональный вектор должен считать меньше длинного с меньшим отклонением.
источник
Самым простым и быстрым может быть просто выяснить, насколько толстой должна быть линия, чтобы покрыть все точки нарисованной пользователем линии.
Чем толще должна быть линия, тем хуже пользователь рисовал ее.
источник
Как-то со ссылкой на MSalters Answer, здесь есть более конкретная информация.
Используйте метод наименьших квадратов, чтобы подогнать линию под ваши точки. Вы в основном ищете функцию y = f (x), которая подходит лучше всего. Получив его, вы можете использовать действительные значения y, чтобы сложить квадрат разностей:
s = сумма за ((yf (x)) ^ 2)
Чем меньше сумма, тем прямее линия.
Как получить наилучшее приближение, объясняется здесь: http://math.mit.edu/~gs/linearalgebra/ila0403.pdf
Просто прочитайте из "Установка прямой линии". Обратите внимание, что t используется вместо x и b вместо y. C и D должны быть определены как приближение, тогда у вас есть f (x) = C + Dx
Дополнительное примечание: Очевидно, что вы также должны принять во внимание длину линии. Каждая линия, состоящая из 2 очков, будет идеальной. Я не знаю точного контекста, но, думаю, я бы использовал сумму квадратов, деленную на количество очков, в качестве рейтинга. Также я бы добавил требование минимальной длины, минимального количества баллов. (Может быть, около 75% от максимальной длины)
источник