Scala: Orthogonal projection of a point onto a line - scala

I'm trying to make a function that takes 3 points as arguments. The first two of which represent two points on a line. The third one represents another point, outside of that line. Suppose a perpendicular through the third point on the line defined by the first two points. Now what I want to do, is calculate that intersection. I've come up with this procedure so far, but somehow it works only like 50% of the time. Could somebody figure out what I'm doing wrong here?
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
}

Given the following definitions:
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
}
meaning that
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
you obtain the projection of a point p on line going through points line1 and line2 as follows:
/** 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)
}
Example:
println(projectPointOnLine((-1.0, 10.0), (7.0, 4.0), (6.0, 11.0)))
gives
(3.0, 7.0)
This works in 3D (or n-D) in exactly the same way.
Some math behind that (How to derive it from scratch)
(notation as above)
We have three points: l1 and l2 for the line and p for the target point.
We want to project the point p orthogonally onto the line that goes through l1 and l2 (assuming l1 != l2).
Let d = l2 - l1 be the direction from l1 to l2. Then every point on the line can be represented as
l1 + d * t
with some scalar factor t. Now we want to find a t such that the vector connecting p and l1 + d * t is orthogonal to d, that is:
(p - (l1 + d * t)) dot d == 0
Recall that
(v1 + v2) dot v3 = (v1 dot v3) + (v2 dot v3)
for all vectors v1, v2, v3, and that
(v1 * s) dot v2 = (v1 dot v2) * s
for scalar factors s. Using this and the definition v.normSquared = v dot v, we obtain:
(p - l1 - d * t) dot d
= (p - l1) dot d - (d dot d) * t
= (p - l1) dot d - d.normSquare * t
and this should become 0. Resolving for t gives:
t = ((p - l1) dot d) / d.normSquare
and this is exactly the formula that is used in the code.
(Thanks at SergGr for adding an initial sketch of the derivation)

Related

Conversion of Looping to Recursive Solution

I have written a method pythagoreanTriplets in scala using nested loops. As a newbie in scala, I am struggling with how can we do the same thing using recursion and use Lazy Evaluation for the returning list(List of tuples). Any help will be highly appreciated.
P.S: The following method is working perfectly fine.
// This method returns the list of all pythagorean triples whose components are
// at most a given limit. Formula a^2 + b^2 = c^2
def pythagoreanTriplets(limit: Int): List[(Int, Int, Int)] = {
// triplet: a^2 + b^2 = c^2
var (a,b,c,m) = (0,0,0,2)
var triplets:List[(Int, Int, Int)] = List()
while (c < limit) {
breakable {
for (n <- 1 until m) {
a = m * m - n * n
b = 2 * m * n
c = m * m + n * n
if (c > limit)
break
triplets = triplets :+ (a, b, c)
}
m += 1
}
}// end of while
triplets
}
I don't see where recursion would offer significant advantages.
def pythagoreanTriplets(limit: Int): List[(Int, Int, Int)] =
for {
m <- (2 to limit/2).toList
n <- 1 until m
c = m*m + n*n if c <= limit
} yield (m*m - n*n, 2*m*n, c)

Find 3d coordinates of a point on a line projected from another point in 3d space

Working in Swift, ARTKit / SceneKit
I have a line AB in 3d and I have xyz coordinates of both points A and B.
I also have a point C and I know its xyz coordinates too.
Now, I want to find out the xyz coordinates of point D on line AB; given that CD is perpendicular to AB.
What would be a simple way to do it in Swift.
Parameterize the line AB with a scalar t:
P(t) = A + (B - A) * t`
The point D = P(t) is such that CD is perpendicular to AB, i.e. their dot product is zero:
dot(C - D, B - A) = 0
dot(C - A - (B - A) * t, B - A) = 0
dot(C - A, B - A) = t * dot(B - A, B - A)
// Substitute value of t
--> D = A + (B - A) * dot(C - A, B - A) / dot(B - A, B - A)
Swift code:
var BmA = B - A
var CmA = C - A
var t = dot(CmA, BmA) / dot(BmA, BmA)
var D = A + BmA * t;

Scala for the Impatient, chapter 2, exercise on recursive pow function

I am reading Scala for the Impatient, Chapter 2 and there is an exercise question I don't understanding what exactly does it want:
Write a function that computes x^n, where n is an integer. Use the
following recursive definition:
X^n = y * y if n is even and positive, where y = x^(n/2)
X^n = x * x^(n-1) if n is odd and positive
x^0 = 1
x^n = 1 / x^-n if n is negative
If the question want x^n, I could just use the pow method defined in scala.math:
def pow(x: Double, y: Double): Double
The question is asking to (re)implement a recursive pow function on integers:
def pow(x: Int, y: Int): Int = ...
You need write a smarter implementation than the naive O(n) algorithm:
def slowPow(x: Int, y: Int): Int =
if (y == 0) 1 else x * slowPow(x, y - 1)
Try to use the given recursive definition instead...
To answer your question directly, I don't think you can dodge the question using the one from scala.math. As you noted it only works on Doubles. Also is neither recursive nor implemented in Scala.
def pow(x: Double, n: Int): Double = {
if (n == 0) 1
else if (n < 0) 1 / (x - n)
else if (n % 2 == 1) x * pow(x, n - 1)
else {
val y = pow(x, n / 2)
y * y
}
}
pow(2, 0) == 1
pow(2, -2) == 0.25
pow(2, 4) == 16
pow(2, 5) == 32

Drag on a line segment control - calculate point on line

I have a line segment defined by P1 und P2 and a knob on that line which can be dragged. The drag should also work if the drag location L is away from the line segment.
One idea was to find the perpendicular line and then find the intersection. But that won`t work if the drag location L is extacly on the line segment or on the (infinite) line going through P1 and P2.
Infact at the end of the day this should be a simple slider-control with the only difference that the control is not always a horizontal or vertical line segment (where you can drag on) but can be of any angle.
Let's define V as the vector P2 - P1. So there is a line defined by P1 + t V (for all real t), and your line segment (call it S) is the subset of that line where 0 ≤ t ≤ 1.
You want to find the point in S that is closest to your drag point L. For any t, the distance from L to the t point on the line is
sqrt((P1x + t Vx - Lx)^2 + (P1y + t Vy - Ly)^2)).
To find the closest point to L, we want to find the t that minimizes this distance. In fact it suffices to minimize the square of the distance
(P1x + t Vx - Lx)^2 + (P1y + t Vy - Ly)^2
which is sometimes called the quadrance. To find the t that minimizes the quadrance, we take the derivative of the quadrance with respect to t, set it equal to zero, and solve for t:
Solve[D[(P1x + t Vx - Lx)^2 + (P1y + t Vy - Ly)^2, t] == 0, t]
If you type that into Mathematica, you'll get the answer
{{t->(Lx Vx - P1x Vx + Ly Vy - P1y Vy) / (Vx^2 + Vy^2)}}
But that t could be any real number. You'll need to clamp it to the range 0 ... 1 to guarantee that you get a point in your line segment.
In Swift:
extension CGPoint {
func closestPointOnLineSegment(start p1: CGPoint, end p2: CGPoint) -> CGPoint {
let v = CGPointMake(p2.x - p1.x, p2.y - p1.y)
var t: CGFloat = (self.x * v.x - p1.x * v.x + self.y * v.y - p1.y * v.y) / (v.x * v.x + v.y * v.y)
if t < 0 { t = 0 }
else if t > 1 { t = 1 }
return CGPointMake(p1.x + t * v.x, p1.y + t * v.y)
}
}
Example use:
let knobPoint = dragPoint.closestPointOnLineSegment(start: p1, end: p2)
You need to find projection of point L onto line P1P2.
If denote vector P=P1P2, and vector M = P1L, then needed projection
L' = P * DotProduct(M, P) / DotProduct(P, P)
Probably you really need to find a ratio of P1L' and P1P2, then
t = DotProduct(M, P) / DotProduct(P, P)

little mathematical thing : squares and roundings

in scala, given the integers d & x, I would have a boolean expression which should be true if and only if y = (x^2 - 1) / d^2 is a square.
I tried this:
(Math.sqrt((x * x - 1) / (d * d)).toInt * Math.sqrt((x * x - 1) / (d * d)).toInt == ((x * x - 1) / (d * d)))
but the 3-tuple (x = 2, d = <all values tested>, y = 0.0) seems to be always an answer of my problem, which is obviously wrong.
I think my error comes from the rounding made: if x=2, d=4 (for example) then x * x - 1 == 3 and d * d == 16 so the division leads to 0.
do you know what is the good expression?
if n is a round square, then Math.sqrt(n).toInt == Math.sqrt(n). In your case:
(Math.sqrt((x * x - 1) / (d * d)).toInt == Math.sqrt((x * x - 1) / (d * d)))
But before doing that, you need to make sure that x and d are doubles.
Try in REPL:
scala> val x = 1
scala> val d = 3
scala> x/d
A Int divided by an Int will result the rounded Int, so you are applying sqrt to zero.
Also due to float point arithmetic, you may want to compare like this instead:
(Math.sqrt((x * x - 1) / (d * d)).toInt - Math.sqrt((x * x - 1) / (d * d))) <= ZERO
where ZERO is replaced by a really small number like 0.00001
Because this is integer division, you are checking whether ((x*x-1)/(d*d)).toInt is a perfect square. You can convert everything to doubles first, but if you want to stay in the realm of integers, check that the division should result in an integer:
( x*x-1 % d*d == 0 ) && Math.sqrt(y).toInt == Math.sqrt(y)