How to find projection of a point on a line - math

How can I find projection of a point p=(x, y, z) on the line l(t)= q + vt?
where v is the unit norm vector, and q is a point on the line

From this sketch, if we define define the vectors q = OQ and p = OP, then the orthogonal projection of p onto v is the component of p that follows the direction of v.
Or more explicitly, it's the vector ((p · v)/v²) · v = (p · v) · v, since v² = 1.

Related

Positioning objects parallel with a mesh

I'm trying to align multiple line objects along a human body circumference depending on the orientation of the triangles from the mesh. I would like to put the lines parallel to the mesh. I correctly assign the position for the lines along the circumference, but I also need to add the rotation of the lines such that to be parallel with the body.
The body is a mesh formed by multiple triangles and every line is "linked" with a triangle.
All I have is:
3 points for the closest triangle from the mesh for every line
The normal of the triangle
The positions for the instantiated lines (2 points, start and end)
I need to calculate the angle for every X, Y, Z axes for the line such that the normal of the triangle is perpendicular with the line mesh. I don't know how to get the desired angle. I really appreciate if someone would like to help me.
input:
FVector TrianglePoints[3];
FVector Triangle_Normal; //Calculated as (B-A)^(C-A), where A,B,C are the points of the triangle
FVector linePosition; //I also have the start line and the endLine position if that helps
ouput:
//FRotator rotation(x,y,z), such that the triangle normal and the line object to be perpendicular.
An overview of the circumference line construction. Now the rotation is calculated using the Start position and End position for each line. When we cross some irregular parts of the mesh we want to rotate the lines correctly. Now the rotation is fixed, depending just on the line start and end position.
If I have understood correctly your goal, here is some related vector geometry:
A,B,C are the vertices of the triangle:
A = [xA, yA, zA],
B = [xB, yB, zB]
C = [xC, yC, zC]
K,L are the endpoints of the line-segment:
K = [xK, yK, zK]
L = [xL, yL, zL]
vectors are interpreted as row-vectors
by . I denote matrix multiplication
by x I denote cross product of 3D vectors
by t() I denote the transpose of a matrix
by | | I denote the norm (magnitude) of a vector
Goal: find the rotation matrix and rotation transformation of segment KL
around its midpoint, so that after rotation KL is parallel to the plane ABC
also, the rotation is the "minimal" angle rotation by witch we need to
rotate KL in order to make it parallel to ABC
AB = B - A
AC = C - A
KL = L - K
n = AB x AC
n = n / |n|
u = KL x n
u = u / |u|
v = n x u
cos = ( KL . t(v) ) / |KL|
sin = ( KL . t(n) ) / |KL|
U = [[ u[0], u[1], u[2] ],
[ v[0], v[1], v[2] ],
[ n[0], n[1], n[2] ],
R = [[1, 0, 0],
[0, cos, sin],
[0, -sin, cos]]
ROT = t(U).R.U
then, one can rotate the segment KL around its midpoint
M = (K + L)/2
Y = M + ROT (X - M)
Here is a python script version
A = np.array([0,0,0])
B = np.array([3,0,0])
C = np.array([2,3,0])
K = np.array([ -1,0,1])
L = np.array([ 2,2,2])
KL = L-K
U = np.empty((3,3), dtype=float)
U[2,:] = np.cross(B-A, C-A)
U[2,:] = U[2,:] / np.linalg.norm(U[2,:])
U[0,:] = np.cross(KL, U[2,:])
U[0,:] = U[0,:] / np.linalg.norm(U[0,:])
U[1,:] = np.cross(U[2,:], U[0,:])
norm_KL = np.linalg.norm(KL)
cos_ = KL.dot(U[1,:]) / norm_KL
sin_ = KL.dot(U[2,:]) / norm_KL
R = np.array([[1, 0, 0],
[0, cos_, sin_],
[0,-sin_, cos_]])
ROT = (U.T).dot(R.dot(U))
M = (K+L) / 2
K_rot = M + ROT.dot( K - M )
L_rot = M + ROT.dot( L - M )
print(L_rot)
print(K_rot)
print(L_rot-K_rot)
print((L_rot-K_rot).dot(U[2,:]))
A more inspired solution was to use a procedural mesh, generated at runtime, that have all the requirements that I need:
Continuously along multiple vertices
Easy to apply a UV map for texture tiling
Can be updated at runtime
Isn't hard to compute/work with it

How to calculate the intersection point between an infinite line and a line segment?

Basically, a function that fulfills this signature:
function getLineIntersection(vec2 p0, vec2 direction, vec2 p2, vec2 p3) {
// return a vec2
}
I have looked around at existing solutions, and they all seem to deal with how to find the intersection between two line segments, or between two infinite lines. Is there a solution for this problem where the line has an initial position, an angle, and needs to determine if it intersects with a line segment? Basically, something like this:
There should be one line segment that starts in a location and has a unit direction, and another line segment that is just a line connected by two points. Is this possible, and if so, is there a good way of calculating the intersection point, if it exists?
If you've a endless line which is defined by a point P and a normalized direction R and a second endless line, which is defined by a point Q and a direction S, then the intersection point of the endless lines X is:
alpha ... angle between Q-P and R
beta ... angle between R and S
gamma = 180° - alpha - beta
h = | Q - P | * sin(alpha)
u = h / sin(beta)
t = | Q - P | * sin(gamma) / sin(beta)
t = dot(Q-P, (S.y, -S.x)) / dot(R, (S.y, -S.x)) = determinant(mat2(Q-P, S)) / determinant(mat2(R, S))
u = dot(Q-P, (R.y, -R.x)) / dot(R, (S.y, -S.x)) = determinant(mat2(Q-P, R)) / determinant(mat2(R, S))
X = P + R * t = Q + S * u
If you want to detect if the intersection is on the lien, you need to compare the distance of the intersection point with the length of the line.
The intersection point (X) is on the line segment if t is in [0.0, 1.0] for X = p2 + (p3 - p2) * t
vec2 getLineIntersection(vec2 p0, vec2 direction, vec2 p2, vec2 p3)
{
vec2 P = p2;
vec2 R = p3 - p2;
vec2 Q = p0;
vec2 S = direction;
vec2 N = vec2(S.y, -S.x);
float t = dot(Q-P, N) / dot(R, N);
if (t >= 0.0 && t <= 1.0)
return P + R * t;
return vec2(-1.0);
}
Start with the intersection of two infinite lines, expressed in parametric form (e.g., A + tp, where A is the "start point", p is the direction vector and t is a scalar parameter). Solve a system of two equations to get the two parameters of the intersection point.
Now if one of your lines is really a segment AB, and B = A + p (i.e., the direction vector goes from A to B), then if the parameter t is between 0 and 1, the intersection lies on the segment.

Find line that is tangent to 2 given circles

I've got a situation in which I have 2 circles (C1 and C2)
and i need to find the line equation for the line that is tangent to both of these circles.
So as far as i'm aware, given a single point (P1) and C2's point and radius it is possible to quite easily get 2 possible points of tangency for C2 and P1 to make 2 line equations. But as i don't have P1, only the knowledge that the point will be one of a possible 2 points on C1, i'm not sure how to calculate this.
I assume it will be something along the lines of getting the 2 tangent line equations of C1 that are equal to the same of C2.
Both circles can have any radius, they could be the same or they could be hugely different. They will also never overlap (they can still touch though). And I'm looking for the 2 possible internal tangents.
Oh, and also, visuals would be very helpful haha :)
Let O be the intersection point between the line through the centers and the tangent.
Let d be the distance between the centers and h1, h2 be the distances between O and the centers. By similarity, these are proportional to the radii.
Hence,
h1 / h2 = r1 / r2 = m,
h1 + h2 = d,
giving
h1 = m d / (1 + m),
h2 = d / (1 + m).
Then the coordinates of O are found by interpolating between the centers
xo = (h2.x1 + h1.x2) / d
yo = (h2.y1 + h1.y2) / d
and the angle of the tangent is that of the line through the centers plus or minus the angle between this line and the tangent,
a = arctan((y2 - y1)/(x2 - x1)) +/- arcsin(r1 / h1).
You can write the implicit equation of the tangent as
cos(a).y - sin(a).x = cos(a).yo - sin(a).xo.
(source: imag.fr)
So we are going to use a homothetic transformation. If the circles C and C' have respectively centres O and O', and radius r and r', then we know there exists a unique homothetic transformation with centre J and ratio a, such that :
a = |JO|/|JO'| = r/r'
Noting AB is the vector from A to B, and |z| the norm of a vector z.
Hence you get J, knowing that it is between O and O' which we both already know.
Then with u the projection of JR on JO', and v the decomposition on its orthogonal, and considering the sine s and cosine c of the angle formed by O'JR, we have
|u| = |JR| * c
|v| = |JR| * s
c^2 + s^2 = 1
And finally because the triangle JRO' is right-angled in R :
s = r' / |JO|'
Putting all of this together, we get :
J = O + OO' / |OO'| * a / (a+1)
if |OJ| == r and |O'J| == r' then
return the orthogonal line to (OO') passing through J
|JR| = √( |JO'|^ - r'^2 )
s = r' / |JO'|
c = √( 1 - s^2 )
u = c * |JR| * OO' / |OO'|
w = (-u.y, u.x) % any orthogonal vector to u
v = s * |JR| * w / |w|
return lines corresponding to parametric equations J+t*(u+v) and J+t*(u-v)

Find point on a path in 3d space, given initial and final position and starting velocity vector

Let's say I have an entity in 3d space and I know its position vector (x, y, z) and its velocity vector (so its orientation in space).
Starting from known point A I want to reach known point B in two steps:
a) turn, following a circular path with a known radius R, until point C
b) go straight from point C to final point B.
Speed (scalar value) is not important. Velocity (vector) is known, so I guess it should define the plane on which the circle resides, being tangent to it, together with the line between A and B...
I want to know how to find coordinates (x, y, z) for C and the velocity vector of the entity being there.
Update: see the working demo!
If I understand correctly, your situation (in the plane containing A, B and v) is as shown in the diagram below. The points A and B are given, as is the vector v and the distance r. You want to find the point C.
Well, let the vector w = (−v̂y, v̂x) be a unit vector perpendicular to v. Then O = A + r w.
Now, |C − O| = r and (C − B)·(C − O) = 0 (where · is the dot product). Combine these to get a quadratic equation, which you can solve to find the two possible positions for C. Then pick the one with the right sign for (C − B)×(C − O).
(There's a second choice for the centre of the circle, O = A − r w, representing turning clockwise instead of anticlockwise. This gives you another possibility for C. I guess you'll have to use some heuristic to decide which one you prefer: maybe the one with smallest ∠AOC.)
St0rM asks for help with doing this in 3D (see comments). That's easy! The plane containing A, B, and v has normal vector n = (A − B) × v. Let u = n × v be a vector perpendicular to both n and v, and let w = û (the unit vector in the direction of u).
You'll also need to take into account the constraint that C lies in the same plane as A: C·n = A.n, and "the right sign for (C − B)×(C − O)" becomes "the right sign for (C − B)×(C − O)·n".
Having trouble solving this system of equations?
Well, if (C − B)·(C − O) = 0, then (C − O + O − B)·(C − O) = 0, therefore (C − O)·(C − O) + (O − B)·(C − O) = 0, therefore C·(O − B) = O·(O − B) − r2.
You'll note that this is the equation for a plane, and so is C·n = A.n. Intersect these two planes (see Wikipedia for details — you can use the simpler solution since the planes are orthogonal and can easily be made orthonormal) to get the equation of a line on which C lies: C = H + λL, say, where L = n×(B − O). Then use (C − O)·(C − O) = r2 to turn this into a quadratic equation in λ. You'll find that the quadratic equation simplifies quite a bit if you rewrite the equation of the line as C = H + λL + O so that occurrences of "− O" disappear.
Here's an implementation in Python using numpy to do the vector algebra. I'm sure you can figure out how to convert this to the language of your choice.
import math
from numpy import cross, dot
from numpy.linalg import norm
def unit(v):
"""Return a unit vector in the same direction as v."""
return v / norm(v)
def turnpoints(A, B, v, r):
"""Generate possible turning instructions for a path from A to B
that starts out in direction v, turns through part of a circle of radius
r until it reaches a point C (to be determined), then heads straight for
B. Return each instruction in the form (sense, C) where sense is -1 for
clockwise and +1 for anticlockwise."""
n = unit(cross(A - B, v)) # Unit normal to plane containing A, B, v.
w = unit(cross(n, v)) # Unit normal to v lying in that plane.
for sense in (-1, +1): # Turn clockwise or anticlockwise?
O = A + sense * r * w # Centre of turning circle.
BB = B - O
m = unit(BB)
# C lies on the line H + l*L + O
H = dot(A, n) * n + (r**2 / norm(BB)) * m
L = cross(n, m)
# |C - O| = r**2 gives quadratic eqn in l with coefficients a=1, b=0, c.
c = dot(H, H) - r**2
disc = - 4 * c # Discriminant of quadratic eqn.
if disc < 0:
continue # No tangents (B inside circle).
elif disc == 0: # One tangent (B on circle).
C = H + O
yield (sense, C)
else: # Two tangents (B outside circle)
for sign in (-1, +1):
l = sign * math.sqrt(disc) / 2
C = H + l * L + O
# Only one choice for C is correct (the other involves
# reversing direction).
if dot(cross(C - B, C - O), n) * sense > 0:
yield (sense, C)
Woo, this is interesting.
Find the plane that points A, B, and the entity's velocity exist on. Everything will happen on this plane, so now you can think of the problem as 2D, though the math will still be 3D.
Find the center point of the circle the entity will be traveling along on the plane. This center point will be perpendicular to the entity's velocity, at a distance of R. There will actually be 2 different places you could place the circle, you'll need to choose based on which is closer to B.
Find the two lines from B that are tangential to the circle. The points where these lines touch the circle are your two possibilities for C. Determine which point will allow your entity to hit B when it reaches it and leaves the circle (the other point will bring the entity in exactly the opposite direction).
From this, you should be able to get the position of C, and I'm fairly certain that, if the entity doesn't change speed, the vector should just be the unit vector from C to B times the magnitude of the original velocity vector.
Any or all of this could be wrong. I'm just figuring this from doodling on a piece of paper.
Perhaps this is a shorter version. You could compute C from:
H = O + (r^2)/|BB|)*m
C = H + l*(sqrt(r^2 - |HO|^2)) //this simply applies Pytagora to find out HC magnitude
as a proof of concept:
cml::vector3f A( 4, 3, 2);
cml::vector3f B( 1, 5, 0);
cml::vector3f v( 1, 0, 0);
float r = 1.4142;
cml::vector3f n = cml::cross((A-B),v);
n.normalize();
cout << "n: " << n << endl;
cml::vector3f w = cml::cross(n,v);
w.normalize();
cout << "w: " << w << endl;
cml::vector3f O = A + r*w;
cout << "O: " << O << endl;
cml::vector3f m = B-O;
m.normalize();
cout << "m: " << m << endl;
cml::vector3f OB = B - O;
cml::vector3f H = O + m * ( pow(r,2) / OB.length() );
cout << "H: " << H << endl;
cml::vector3f l = cml::cross(m,n);;
l.normalize();
cout << "l: " << l << endl;
cml::vector3f OH = H - O;
cml::vector3f C = H + l * ( sqrt( pow(r,2)-pow(OH.length(),2) ) );
cout << "C: " << C << endl;

Code or formula for intersection of two parabolas in any rotation

I am working on a geometry problem that requires finding the intersection of two parabolic arcs in any rotation. I was able to intesect a line and a parabolic arc by rotating the plane to align the arc with an axis, but two parabolas cannot both align with an axis. I am working on deriving the formulas, but I would like to know if there is a resource already available for this.
I'd first define the equation for the parabolic arc in 2D without rotations:
x(t) = ax² + bx + c
y(t) = t;
You can now apply the rotation by building a rotation matrix:
s = sin(angle)
c = cos(angle)
matrix = | c -s |
| s c |
Apply that matrix and you'll get the rotated parametric equation:
x' (t) = x(t) * c - s*t;
y' (t) = x(t) * s + c*t;
This will give you two equations (for x and y) of your parabolic arcs.
Do that for both of your rotated arcs and subtract them. This gives you an equation like this:
xa'(t) = rotated equation of arc1 in x
ya'(t) = rotated equation of arc1 in y.
xb'(t) = rotated equation of arc2 in x
yb'(t) = rotated equation of arc2 in y.
t1 = parametric value of arc1
t2 = parametric value of arc2
0 = xa'(t1) - xb'(t2)
0 = ya'(t1) - yb'(t2)
Each of these equation is just a order 2 polynomial. These are easy to solve.
To find the intersection points you solve the above equation (e.g. find the roots).
You'll get up to two roots for each axis. Any root that is equal on x and y is an intersection point between the curves.
Getting the position is easy now: Just plug the root into your parametric equation and you can directly get x and y.
Unfortunately, the general answer requires solution of a fourth-order polynomial. If we transform coordinates so one of the two parabolas is in the standard form y=x^2, then the second parabola satisfies (ax+by)^2+cx+dy+e==0. To find the intersection, solve both simultaneously. Substituting in y=x^2 we see that the result is a fourth-order polynomial: (ax+bx^2)^2+cx+dx^2+e==0. Nils solution therefore won't work (his mistake: each one is a 2nd order polynomial in each variable separately, but together they're not).
It's easy if you have a CAS at hand.
See the solution in Mathematica.
Choose one parabola and change coordinates so its equation becomes y(x)=a x^2 (Normal form).
The other parabola will have the general form:
A x^2 + B x y + CC y^2 + DD x + EE y + F == 0
where B^2-4 A C ==0 (so it's a parabola)
Let's solve a numeric case:
p = {a -> 1, A -> 1, B -> 2, CC -> 1, DD -> 1, EE -> -1, F -> 1};
p1 = {ToRules#N#Reduce[
(A x^2 + B x y + CC y^2 + DD x + EE y +F /. {y -> a x^2 } /. p) == 0, x]}
{{x -> -2.11769}, {x -> -0.641445},
{x -> 0.379567- 0.76948 I},
{x -> 0.379567+ 0.76948 I}}
Let's plot it:
Show[{
Plot[a x^2 /. p, {x, -10, 10}, PlotRange -> {{-10, 10}, {-5, 5}}],
ContourPlot[(A x^2 + B x y + CC y^2 + DD x + EE y + F /. p) ==
0, {x, -10, 10}, {y, -10, 10}],
Graphics[{
PointSize[Large], Pink, Point[{x, x^2} /. p /. p1[[1]]],
PointSize[Large], Pink, Point[{x, x^2} /. p /. p1[[2]]]
}]}]
The general solution involves calculating the roots of:
4 A F + 4 A DD x + (4 A^2 + 4 a A EE) x^2 + 4 a A B x^3 + a^2 B^2 x^4 == 0
Which is done easily in any CAS.

Resources