Во многих инструментах рисования (Adobe Photoshop, Sketch ​​и т. Д.), Если мы удерживаем кнопку SHIFT при рисовании линии, мы можем создавать идеально прямые линии по горизонтали или вертикали.

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

Демо: чтобы лучше понять идею, вы можете проверить демо-версию на демонстрационной странице.

Требования

Ввод

  • Базовая точка (B)
  • Текущая позиция мыши (M)

Вывод

  • Проекция текущего положения мыши на ось x или ось y (P)

Для удобства на всех графиках мы обозначим базовую точку красным кружком, а текущую точку мыши - зеленым кружком.

Простое решение

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

Расчет довольно простой - вот код Javascript:

Расширенная проблема

Как насчет того, чтобы проецировать на биссектрисе линию между горизонтальной линией и вертикальной линией (аналогично Sketch)? Это означает, что пользователи могут проецировать положение мыши на горизонтальную линию, вертикальную линию, линию под углом 45 градусов или линию под углом 135 градусов.

Подход похожий. На этот раз нам нужно рассчитать расстояние между положением мыши и четырьмя линиями: горизонтальной линией, вертикальной линией и двумя биссектрисами (линия под углом 45 градусов и линия под углом 135 градусов). Но расчет сложнее.

Мы все еще можем разделить его на 2 этапа:

  1. Определите ближайшую линию с помощью мыши
  2. Рассчитать проекцию положения мыши на ближайшую линию

Шаг 1. Определите ближайшую линию с помощью мыши

Во-первых, нам нужно определить формулировку 4 строк выше. Поскольку мы уже знаем базовую точку (x0, y0) и угол линии, легко определить формулировку каждой линии.

Пример: чтобы вычислить формулу биссектрисы под углом 45 градусов, мы уже знаем, что прямая будет проходить через базовую точку (x0, y0) и (x0 + 1, y0 + 1). Используя метод Найти-уравнение-линии, мы можем вычислить формулу линии.

В итоге у нас будут 4 строчные формулы:

Чтобы рассчитать расстояние от базовой позиции мыши до каждой линии, мы можем использовать популярную математическую формулу:

Шаг 2: Рассчитайте ортогональную проекцию положения мыши на ближайшую линию

Теперь проблема заключается в вычислении ортогональной проекции положения мыши (M) на ближайшую линию по формуле: ax + by + c = 0 (L)

Есть несколько способов решить эту проблему. Я выбрал простой способ: сначала вычислите формулу линии, которая содержит позицию мыши M и перпендикулярна линии L, называемой L '. Затем решите систему уравнений, чтобы получить точку пересечения между прямой L и L ', которая является точкой проекции, которую мы находим.

После некоторых вычислений я выяснил формулу L ’, которая проходит через M (x0, y0) и перпендикулярна L (ax + by + c = 0):

Теперь, чтобы найти пересечение, нам нужно решить систему уравнений:

Используя правило Крамера и определитель матрицы, мы можем легко решить это уравнение:

Граница

Бывает ситуация, когда мы хотим ограничить границу проекции.

Пример:

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

В этой ситуации мы можем просто получить точку пересечения линии L ’с границей (называемой P’).

Полный исходный код

Вы можете ознакомиться с демо-версией и исходным кодом на Github.

Удачного кодирования!