Here are the calculations
L1 = Line joining points A(x1,y1) and B(x2,y2)
L2 = Line joining points c(x3,y3) and D(x4,y4)
For Line L1
Line Equation : y = m1*x + c1
slope m1 : (y2-y1)/(x2-x1)
Y intercept : c1 = (y1 - m1*x1)
For Line L2
Line Equation : y = m2*x + c2
slope m2 : (y4-y3)/(x4-x3)
Y intercept : c2 = (y3 - m2*x3)
For Point of Intersection
Solving the above equations we get
x = (c2 -c1)/(m1-m2)
y = (c1*m2 - c2*m1)/(m2-m1)
These above calculations are used to calculate the intersection points in my java program.
The Problem
The problem occurs when the two lines are parallel to x-axis and y-axis respectively. For example if the connecting points are as follows
L1 = A(34,112) B(34,180) ...(x-coordinate value remains constant)
L2 = C(72,100) D(88,100) ...(y-coordinate value remains constant)
now m1 will become Infinity and m2 will become 0 accordingly c1 will become Infinity and c2=y3 as a result the computation of the intersection points using below given formula gives strange (NaN) result although the lines L1 and L2 must meet at (34,100).
x = (c2 -c1)/(m1-m2)
y = (c1*m2 - c2*m1)/(m2-m1)
Why such a problem ? How is this problem handled using math so that it can be implemented in the program.
A line which is parallel to the y-axis cannot be expressed as y = ax + b. You need to use the general equation of a line ax + by + c = 0. Determine the coefficients of the equations of your two lines and solve the linear system of their intersection. Make sure the determinant of the system is different from 0, otherwise there is no solution, or an infinity (which you can consider being another case of no solution).
You can obtain a and b coefficients quite easily considering the normal vector of your segment (if vect(AB) = (x,y) then normal(AB) = (-y,x) = (a,b). You then determine c by introducing the coordinates of A in the equation : c = -a*x_A - b*y_A.
You now have a linear system to solve :
(S) : { a1*x + b1*y + c1 = 0
{ a2*x + b2*y + c2 = 0
If det = a1*b2 - a2*b1 = 0 (be careful with loss of precision, make your comparison epsilon-wise), then the system has no unic solution. Otherwise, you can find the inverse of the matrix of the system :
M = (a1 b1), M^(-1) = 1/det * ( b2 -b1)
(a2 b2) (-a2 a1)
Now you just need to compute
M^(-1) * (-c1) = 1/det * (-b2*c1 + b1*c2)
(-c2) ( a2*c1 - a1*c2)
And that's it, you have your solution !
Related
Im trying to work out how to calculate where a 3D line(Two 3D points) and a Axis meets.
In my case im trying to calculate the intersection of a 3D Point to the Z Axis.
Lets say i give the line the coords of
Point1.X = 0
Point1.Y = 0
Point1.Z = 0
Point2.X = 50
Point2.Y = 50
Point2.Z = 50
And i want to calculate the intersect at Z 15, how would i accomplish this?
I've thought about using interpolation, but it seems really inefficient here, i've looked at another posts and mathematical equations, but i dont really understand them enough to implement them into usable code.
Suppose you have vector A (like your point1) and B, then a straight line L through both points can be defined by
L(k) = A + k(B - A)
such that L(0) = A and L(1) = B. Suppose you want to find where
L(k).z = z_0
then you need to solve
A.z + k(B.z - A.z) = z_0
so the line L intersects the plane z = z_0 at
k = (z_0 - A.z) / (B.z - A.z)
If (B.z - A.z) is zero, either it does not intersect the plane z = z_0 anywhere, or it is in the plane everywhere.
lambda = ( Point1.Z - Z ) / ( Point1.Z - Point2.Z )
Point3.X = Point1.X + lambda * (Point2.X - Point1.X)
Point3.Y = Point1.Y + lambda * (Point2.Y - Point1.Y)
Point3.Z = Z
I have a question that I would like to share with you in case you could help me. I am working on 3D lines and I need to obtain the exact points at which the minimum distance of two intersecting lines is located. Why do I need these points?
Of each one of the infinite lines, I would only be interested in knowing if this minimum distance is in a certain range from that of points on the same line. For example, I have the points P (0,0,0) and Q (10,10,10) of a line r and I would only be interested to know if said minimum distance is in that coordinate interval or not.
To obtain the distance, I use the formula:
But once said I do not know how to ensure if such a minimum distance is reached within the range of values of P and Q that I comment above.
If anyone has any better ideas on how to check this or knows how to get such points, I would really appreciate it.
Usually, lines in 3D are specified by the coordinates of one point on the line and the coordinates of one vector aligned (or parallel) to the line. So I am going to assume that what you have as input data is:
1) line s with point S = [xS, yS, zS] on l and a vector u = [u1, u2, u3] aligned with s
2) line r defined by the pair of points P = [xP, yP, zP] and Q = [xQ, yQ, zQ]
Your goal is to check whether the point on r that is closest to line s
is inside the line segment PQ on r or not.
Algorithm.
n = u x (Q - P)
SP = P - S
SQ = Q - S
proj_SP = SP - ( (n . SP) / (n . n) ) n
proj_SQ = SQ - ( (n . SQ) / (n . n) ) n
w = n x u
if (proj_SP . w) * (proj_SQ . w) < 0
then the point on r that is closest to line s
is inside the line segment PQ
else
the point on r that is closest to line s
is outside the line segment PQ
If I understand your question right:
for point P get orthogonal projections onto both lines (denominator is not needed if v and w are normalized)
PAproj = A - P + dot(AP, v) / dot(v,v) * v
PBproj = B - P + dot(BP, w) / dot(w,w) * w
Then check that these vectors are anticollinear
cross(PAproj, PBproj) == 0
and
dot(PAproj, PBproj) has negative sign
Given a distance d (going from 0 to d) and 2 points s and e in between which no points can be placed (placing points on s and e is fine, it's not allowed to place points between them).
Place n points such that the distance between each point is as large as possible (distribute them as evenly as possible).
Output the minimal distance between 2 points.
Graphic representation, place n points on the black line (it's a 1-dimensional line) so that the smallest distance between each 2 points is as large as possible (an absolute error of up to 10^(-4) is allowed).
Examples:
d=7, n=2, s=6, e=7, Output is: 7.0000000000
d=5, n=3, s=5, e=5, Output is: 2.5000000006
d=3, n=3, s=0, e=1, Output is: 1.5000000007
d=9, n=10, s=5, e=6, Output is: 1.0000000001
d=6, n=2, s=1, e=6, Output is: 6.0000000000
d=5, n=3, s=4, e=5, Output is: 2.5000000006
My approach:
I tried looking at the intervals separately, distributing points (ideal distribution, lengthOfInterval/n) on the first and second interval (0 to s and e to d) and inspecting all distributions whose number of points sum up to n, I would store a (distribution, largest minimal distance) pair and pick the pair with the largest minimal distance. I don't know how to work with the 10^(-4) tolerance (how does this part even look in code?) and am not sure if my approach is correct. Every suggestion is welcome.
I'm stuck on this question :/
You can use binary search over the possible sizes of gaps between points (from 0 to d) to converge to the largest minimum gap size.
To determine the viability of any given gap size, you basically try to place points from the left and from the right and see whether the gap in the middle is big enough:
Determine how many points can be placed left of s (which is s/gapSize + 1).
Determine how many points will then be required to be placed to the right of e
(which is n - points on left).
Determine how far inwards each side will go.
Check whether the points on the right fits in the gap [e, d] and whether there's at least gap size difference between each side.
Code for this: (note that I worked with number of gaps instead of points, which is just 1 less than the number of points, since it leads to simpler code)
double high = d, low = 0, epsilon = 0.000001;
while (low + epsilon < high)
{
double mid = (low + high)/2;
int gapsOnLeft = (int)(s/mid); // gaps = points - 1
if (gapsOnLeft + 1 > n)
gapsOnLeft = n - 1;
int gapsOnRight = n - gapsOnLeft - 2; // will be -1 when there's no point on the right
double leftOffset = mid*gapsOnLeft;
// can be > d with no point on the right, which makes the below check work correctly
double rightOffset = d - mid*gapsOnRight;
if (leftOffset + mid <= rightOffset && rightOffset >= e)
low = mid;
else
high = mid;
}
System.out.println(low);
Live demo.
The time complexity is O(log d).
The problem with your approach is that it's hard to figure out how big the gaps between points are supposed to be, so you won't know how many points are supposed to go on either side of (s, e) as to end up with an optimal solution and to correctly deal with both cases when s and e are really close together and when they're far apart.
Binary search
Its very easy to find the number of points you can place if the minimum separation distance b/w any pair l is given.
If l=d, then at the most only 2 points can be placed.
..
...
....
so just do a binary search on l.
A crude implementation goes like this.
low,high=0.00001,d
while(high-low>eps):
m = (low+high)/2
if((no. of points placed s.t any pair is at most m units away) >=n):
low=mid
else:
high=mid
TL;DR: Your approach does not always work (and you're not doing it as fast as you could) see the 3rd bullet point for one that works (and uses the given 10^(-4)).
If [s, e] is small and well-placed, then the optimum is just distributing evenly on the whole segment, best value is now d/(n-1). But you'll have to check that none of your elements is between s and e.
Your approach works if s and e are "far enough".
You can do it faster than what you seem to suggest though, by lookign for the best splitting between the two segments in time O(1): if you put n1 (1<=n1<=n-1) elements on the left, you want to maximize min(s/(n1-1), (d-e)/(n-n1-1)) (one of these quantities being possibly +infinity, but then the other is not). The maximum of that function is obtained for s/(x-1) = (d-e)/(n-x-1), just compute the corresponding value for x, and either its floor or ceiling is the best value for n1. The distance obtained is best = min(s/(n1-1), (d-e)/(n-n1-1)) Then you put n1 points on the left, starting at 0, separated by distance best, and n-n1 on the right, starting at d, going left, separated by best.
If the distance between the last point on the left and the first on the right is smaller than best, then you have a problem, this approach does not work.
The complicated case is when the two previous approaches failed: the hole is small and not well placed. Then there are probably many ways to solve the problem. One is to use binary search to find the optimal space between two consecutive points. Given a candidate space sp, try distributing points on the line starting at 0, spaced by sp, as many as you can while remaining below s. Do the same on the right while staying above e and above (last on the left + sp). If you have successfully placed at least n points in total, then sp is too small. Otherwise, it is too big.
Thus, you can use binary search to find the optimal spas follows: start at sp possibly in [max(s, d-e)/(n-1), d/(n-1)]. At each step, take the middle mid of your possible segment [x, y]. Check if the real optimum is above or below mid. According to your case, look for the optimum in [mid, y] or [x, mid]. Stop iff y-x < 10^(-4).
The two previous cases will actually also be found by this method, so you don't need to implement them, except if you want the exact optimal value when possible (i.e. in the first two cases).
It's pretty tricky, except for the simple case (no point lands in the gap):
double dMin = d / (n - 1.0);
if (Math.ceil(e / dMin - 1) * dMin <= s)
return dMin;
Let's continue with the edge cases, placing one point on one side and the rest of the points on the other one:
dMin = Math.min((d - e) / (n - 2.0), e); // one point at 0
double dm = Math.min(s / (n - 2.0), d - s); // one point at d
if (dm > dMin) // 2nd configuration was better
dMin = dm;
And finally for two or more points on both sides:
// left : right = (x - 1) : (n - x - 1)
// left * n - left * x - left = right * x - right
// x * (left + right) = left * n - left + right
// x = (left * n - left + right) / (left + right) = (left * n) / (left + right) - 1
int x = s * n / (d - e + s) - 1;
if (x < 2)
x = 2;
for (int y = x; y <= x + 2 && y < n - 1; y++) {
double dLeft = s / (y - 1.0);
double dRight = (d - e) / (n - y - 1.0);
dm = Math.min(dLeft, dRight);
if (dm > e - s) { // dm bigger than gap
if (dLeft > dRight)
dLeft = e / ((double) y);
else
dRight = (d - s) / ((double) n - y);
dm = Math.min(dLeft, dRight);
}
if (dm > dMin)
dMin = dm;
}
This would be O(1) space and time, but I'm not 100% positive if all cases are checked. Please let me know if it worked. Tested against all the test cases. The above works for n >= 2, if n equals 2 it will be caught by the first check.
I translated this spline interpolation algorithm from apache.commons.math from Java into Scala in the most straightforward way I could think of (see below). The function I ended up with runs 2 to 3 times slower than the original Java code. My guess is that the problem stems from the extra loops coming from the calls to Array.fill, but I can't think of a straightforward way to get rid of them. Any suggestions on how to make this code perform better? (It would also be nice to write it in a more concise and/or functional way -- suggestions on that front would be appreciated as well.)
type Real = Double
def mySplineInterpolate(x: Array[Real], y: Array[Real]) = {
if (x.length != y.length)
throw new DimensionMismatchException(x.length, y.length)
if (x.length < 3)
throw new NumberIsTooSmallException(x.length, 3, true)
// Number of intervals. The number of data points is n + 1.
val n = x.length - 1
// Differences between knot points
val h = Array.tabulate(n)(i => x(i+1) - x(i))
var mu: Array[Real] = Array.fill(n)(0)
var z: Array[Real] = Array.fill(n+1)(0)
var i = 1
while (i < n) {
val g = 2.0 * (x(i+1) - x(i-1)) - h(i-1) * mu(i-1)
mu(i) = h(i) / g
z(i) = (3.0 * (y(i+1) * h(i-1) - y(i) * (x(i+1) - x(i-1))+ y(i-1) * h(i)) /
(h(i-1) * h(i)) - h(i-1) * z(i-1)) / g
i += 1
}
// cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants)
var b: Array[Real] = Array.fill(n)(0)
var c: Array[Real] = Array.fill(n+1)(0)
var d: Array[Real] = Array.fill(n)(0)
var j = n-1
while (j >= 0) {
c(j) = z(j) - mu(j) * c(j + 1)
b(j) = (y(j+1) - y(j)) / h(j) - h(j) * (c(j+1) + 2.0 * c(j)) / 3.0
d(j) = (c(j+1) - c(j)) / (3.0 * h(j))
j -= 1
}
Array.tabulate(n)(i => Polynomial(Array(y(i), b(i), c(i), d(i))))
}
You can get rid of all the Array.fill since a new array is always initialized with 0 or null, depending on whether it is a value or a reference (booleans are initialized with false, and characters with \0).
You might be able to simplify the loops by zipping arrays, but you'll only make it slower. The only way functional programming (on the JVM anyway) is going to help you make this faster is if you make it non-strict, such as with a Stream or a view, and then you go ahead and not use all of it.
I have one line segment formed by two vectors, let's say v1 and v2, a vector v3 and an angle a. How do I write a method in Java (I'm also using Apache Commons Math to represent a vector) which gives me a vector v4, so that the line segments v1-v2 and v3-v4 are at angle a? There are infinite v4 elements, it would even be better if I could give a size to that method so that the line segment v3-v4 has that size. (all in 2d space, angle can be radians or degrees, doesn't matter)
Edit: as promised I have included an image of the problem I'm trying to solve. I have a line segment defined by 2 vectors (the line is a bit longer but that doesn't matter), an angle, and a third point. I need to draw the second line which intersects the first one at angle a. Since all lines in Javafx (which I'm using here) are drawn by defining two points, I needed to find the red point (or any of the possible ones).
Edit: Using Ali's answer I got the following method which does what I need:
public Pair<Vector2D, Vector2D> calculateFourthPoint(Vector2D v1, Vector2D v2, Vector2D v3, double angleInDegrees) {
Vector2D r = v1.subtract(v2);
double rx = r.getX();
double ry = r.getY();
double angle = toRadians(angleInDegrees);
double a = pow(rx, 2) + pow(ry, 2);
double b = 2 * sqrt(pow(rx, 2) + pow(ry, 2)) * cos(angle) * rx;
double c = pow(rx, 2) * pow(cos(angle), 2) + pow(ry, 2) * pow(cos(angle), 2) - pow(ry, 2);
double discriminant = sqrt(pow(b, 2) - (4 * a * c));
double sx1 = (-b + discriminant) / (2 * a);
double sx2 = (-b - discriminant) / (2 * a);
double sy1 = sqrt(1 - pow(sx1, 2));
double sy2 = sqrt(1 - pow(sx2, 2));
Vector2D s1 = new Vector2D(sx1, sy1);
Vector2D s2 = new Vector2D(sx2, sy2);
Vector2D v4_1 = v3.subtract(s1);
Vector2D v4_2 = v3.subtract(s2);
return new Pair<Vector2D, Vector2D>(v4_1, v4_2);
}
I don't know Apache Commons Math so I am writing in pseudo code. Let vx and vy denote the x and y components of vector v, respectively.
Let r=v1-v2 and s=v3-v4. You have 2 unknowns (namely sx and sy; and v4=v3-s) so you need 2 equations. These should be:
dot_product(r,s)=length(r)*cos a // forces the desired angle
dot_product(s,s)=1 // just sets the length of s to 1
To spell it out, the above equations are:
(1) rx*sx + ry*sy = sqrt(rx^2+ry^2)*cos a
(2) sx^2 + sy^2 = 1
The first equation is linear in both sx and sy. Let's eliminate sy from the first equation (assuming that ry is not zero)
sy = (1/ry)*(sqrt(rx^2+ry^2)*cos a - rx*sx)
and substitute this sy into the second equation. You get a quadratic equation in sy (I don't want to write it here because it is complicated) and that has 2 solutions. You get the corresponding sx by substituting the sy values into (assuming rx is not zero):
sx = (1/rx)*(sqrt(rx^2+ry^2)*cos a - ry*sy).
Finally, v4=v3-s. You get 2 solutions for v4, one for each of the solutions to the quadratic equation. (Degenerate cases, such as r being a null vector, are ignored in my answer.)
Shame we can't do LaTeX-style equations here (or can we? I dunno, never done it here...), but here goes:
v1-v2 · v3-v4 = |v1-v2| * |v3-v4| * cos(a) (by definition)
define |v3-v4| to be a unit vector, so that
v1-v2 · v3-v4 = |v1-v2|*1*cos(a) = |v1-v2|*cos(a)
working the left hand side out gives
v1·v4 + v2·v4 = |v1-v2|*cos(a) - v1·v3 + v2·v3
or
(v1+v2)·v4 = |v1-v2|*cos(a) - (v1-v2)·v3
while
|v3-v4| = (v3-v4)·(v3-v4) = 1
So, there are 2 equations in 2 unknowns. Now, for brevity,
aa = (v1+v2|x
bb = (v1+v2|y
x1 = v4|x
x2 = v4|y
A = |v1-v2|*cos(a) - (v1-v2)·v3
where |x means x-component, etc. With this, trivial substitution gives us
( (A-aa*x1)/bb )^2 + (aa*x1)^2 = 1 (-> 2 solutions)
( (A-bb*x2)/aa )^2 + (bb*x2)^2 = 1 (-> another 2 solutions)
The solutions are a bit too messy to write down here, but they are plain quadratic equations that can be easily solved.
You then have 4 unique vectors which lie on a unit circle around v3 (see picture). These 4 vectors result in only 2 distinct lines, but it is still a good idea to find all 4 vectors (as a self-check, and to improve robustness -- there can be some fringe cases where one of the vectors is such that something like catastrophic cancellation occurs).
Which line is best suited for you, depends of course on your use case.
Whatever the solution you pick, you should of course always verify whether
arccos(((v1-v2)·(v3-v4))/|v1-v2|) = a
as it should be.