Scala:点在直线上的正交投影

时间:2019-01-02 16:28:39

标签: scala math geometry

我正在尝试制作一个以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 :(得分:3)

给出以下定义:

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在通过点line1line2的直线上的投影,如下所示:

/** 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(或n-D)中的工作方式完全相同。


其背后的一些数学运算法则(如何从头算起)

(如上所述)

我们有三个点:l1l2代表直线,p代表目标点。 我们想将点p正交投影到经过l1l2的直线上(假设l1 != l2)。

d = l2 - l1为从l1l2的方向。那么线上的每个点都可以表示为

l1 + d * t

具有标量因子t。现在我们要找到一个t,使得连接pl1 + 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添加了派生的初始草图)