Scala: ортогональная проекция точки на линию - PullRequest
0 голосов
/ 02 января 2019

Я пытаюсь сделать функцию, которая принимает 3 пункта в качестве аргументов.Первые две из которых представляют две точки на линии.Третий представляет другую точку за пределами этой линии.Предположим, что перпендикуляр через третью точку на линии, определенной первыми двумя точками.Теперь я хочу вычислить это пересечение.До сих пор я придумал эту процедуру, но почему-то она работает только в 50% случаев.Может кто-нибудь выяснить, что я делаю здесь не так?

def calculateIntersection(p1: (Double, Double), p2: (Double, Double), c: (Double, Double)): (Double, Double) = {
    var intersection: (Double, Double) = null
    // CASE 1: line is vertical
    if(p1._1 == p2._1) {
      intersection = (p1._1, c._2)
    }
    // CASE 2: line is horizontal
    else if(p1._2 == p2._2) {
      intersection = (c._1, p1._2)
    }
    // CASE 3: line is neither vertical, nor horizontal
    else {
      val slope1: Double = (p2._2 - p1._2) / (p2._1 - p1._1) // slope of the line
      val slope2: Double = pow(slope1, -1) * -1 // slope of the perpendicular
      val intercept1: Double = p1._2 - (slope1 * p1._1) // y-intercept of the line
      val intercept2: Double = c._2 - (slope2 * c._1) // y-intercept of the perpendicular
      intersection = ((intercept2 - intercept1) / (slope1 - slope2), 
                     slope1 * ((intercept2 - intercept1) / (slope1 - slope2)) + intercept1)
    }
    intersection
}

1 Ответ

0 голосов
/ 02 января 2019

Учитывая следующие определения:

type Point = (Double, Double)

implicit class PointOps(p: Point) {
  def +(other: Point) = (p._1 + other._1, p._2 + other._2)
  def -(other: Point) = (p._1 - other._1, p._2 - other._2)
  def dot(other: Point) = p._1 * other._1 + p._2 * other._2
  def *(scalar: Double) = (p._1 * scalar, p._2 * scalar)
  def normSquare: Double = p._1 * p._1 + p._2 * p._2
}

, означая, что

a + b        // is vector addition
a - b        // is vector subtraction
a dot b      // is the dot product (scalar product)
a * f        // is multiplication of a vector `a` with a scalar factor `f`
a.normSquare // is the squared length of a vector

вы получаете проекцию точки p на линии, проходящей через точки line1 и line2следующим образом:

/** Projects point `p` on line going through two points `line1` and `line2`. */
def projectPointOnLine(line1: Point, line2: Point, p: Point): Point = {
  val v = p - line1
  val d = line2 - line1
  line1 + d * ((v dot d) / d.normSquare)
}

Пример:

println(projectPointOnLine((-1.0, 10.0), (7.0, 4.0), (6.0, 11.0)))

дает

(3.0, 7.0)

Это работает в 3D (или nD) точно так же.


За этим стоит некоторая математика (Как вывести ее с нуля)

(обозначения, как указано выше)

У нас есть триточки: l1 и l2 для линии и p для целевой точки.Мы хотим проецировать точку p ортогонально на линию, проходящую через l1 и l2 (при условии l1 != l2).

Пусть d = l2 - l1 будет направлением от l1 до l2.Тогда каждая точка на линии может быть представлена ​​как

l1 + d * t

с некоторым скалярным коэффициентом t.Теперь мы хотим найти t такой, чтобы вектор, соединяющий p и l1 + d * t, был ортогонален d, то есть:

(p - (l1 + d * t)) dot d == 0

Напомним, что

(v1 + v2) dot v3 = (v1 dot v3) + (v2 dot v3)

для всех векторов v1, v2, v3, а для

(v1 * s) dot v2 = (v1 dot v2) * s

для скалярных факторов s.Используя это и определение v.normSquared = v dot v, мы получаем:

(p - l1 - d * t) dot d 
= (p - l1) dot d - (d dot d) * t
= (p - l1) dot d - d.normSquare * t

, и это должно стать 0.Разрешение для t дает:

t = ((p - l1) dot d) / d.normSquare

, и именно эта формула используется в коде.

(Спасибо SergGr за добавление начального эскиза деривации)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...