3D Line - Plane intersection? - math

I am having two Vectors (X,Y,Z), one above Y=0 and one below Y=0.
I want to find the Vector (X,Y,Z) where the line between the two original vectors intersects with the Y=0 level.
How do I do that?
Example Point A:
X = -43.54235
Y = 95.2679138
Z = -98.2120361
Example Point B:
X = -43.54235
Y = 97.23531
Z = -96.24464
These points read from two UnProjections from a users click and I'm trying to target the unprojection to Y=0.
(I found 3D line plane intersection, with simple plane but didn't understand the accepted answer as it's for 2D)

I suspect that by two vectors, you really mean two points, and want to intersect the line connecting those two points with the plane defined by Y=0.
If that's the case, then you could use the definition of a line between two points:
<A + (D - A)*u, B + (E - B)*u, C + (F - C)*u>
Where <A,B,C> is one of your points and <D,E,F> is the other point. u is an undefined scalar that is used to calculate the points along this line.
Since you're intersecting this line with the plane Y=0, you simply need to find the point on the line where the "Y" segment is 0.
Specifically, solve for u in B + (E - B)*u = 0, and then feed that back into the original line equation to find the X and Z components.

The equation for the line is
(x–x1)/(x2–x1) = (y–y1)/(y2–y1) = (z–z1)/(z2–z1)
So making y=0 yields your coordinates for the intersection.
x = -y1 * (x2-x1)/(y2-y1) + x1
and
z = -y1 * (z2-z1) /(y2-y1) + z1

Related

How can I find where a point will touch a line given a vector?

Here, line segment ab is cast upward on arbitrary vector n where I do somethings to find the black point on the line segment cd. My question is, how do I find the point on ab that intersects with the inverted n vector coming down from the new point?
Looks like it will have the same x-coordinate as the black point (call this x). The slope of ab is m = (by - ay) / (bx - ax), so the y coordinate is mx + ay.
If the projection is parallel, by the Thales theorem the ratios are preserved.
|ae| / |ab| = |cf| / |cd| = r
which is known.
The searched point is, vectorially
e = a + r.ab = a + |cf|/|cd|.ab

Connecting two points with a 3D logarithmic spiral (Julia)

I am calculating points along a three-dimensional logarithmic spiral between two points. I seem to be close, but I think I'm missing a conditional sign flip somewhere.
This code works relatively well:
using PlotlyJS
using LinearAlgebra
# Points to connect (`p2` spirals into `p1`)
p1 = [1,1,1]
p2 = [3,10,2]
# Number of curve revolutions
rev = 3
# Number of points defining the curve
rez = 500 # Number of points defining the line
r = norm(p1-p2)
t = range(0,r,rez)
theta_offset = atan((p1[2]-p2[2])/(p1[1]-p2[1]))
theta = range(0, 2*pi*rev, rez) .+ theta_offset
x = cos.(theta).*exp.(-t).*r.+p1[1];
y = sin.(theta).*exp.(-t).*r.+p1[2];
z = exp.(-t).*log.(r).+p1[3]
# Plot curve points
plot(scatter(x=x, y=y, z=z, marker=attr(size=2,color="red"),type="scatter3d"))
and produces the following plot. Values of the endpoints are shown on the plot, with an arrow from the coordinate to its respective marker. The first point is off, but it's close enough for my liking.
The problem comes when I flip p2 and p1 such that
p1 = [3,10,2]
p2 = [1,1,1]
In this case, I still get a spiral from p2 to p1, and the end point (p1) is highly accurate. However, the other endpoint (p2) is wildly off:
I think this is due to me changing the relative Z position of the two points, but I'm not sure, and I haven't been able to solve this riddle. Any help would be greatly appreciated. (Bonus points if you can help figure out why the Z value on p2 is off in the first example!)
Assuming this is a follow-up of your other question: Drawing an equiangular spiral between two known points in Julia
I assume you just want to add a third dimension to your previous 2D problem using cylindric coordinate system. This means that you need to separate the treatment of x and y coordinate on one side, and the z coordinate on the other side.
First you need to calculate your r on the first two coordinate:
r = norm(p1[1:2]-p2[1:2])
Then, when calculating z, you need to take only the third dimension in your formula (not sure why you used a log function there in the first place):
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
That will fix your z-axis.
Finally for your x and y coordinate, use the two argument atan function:
julia>?atan
help?> atan
atan(y)
atan(y, x)
Compute the inverse tangent of y or y/x, respectively.
For one argument, this is the angle in radians between the positive x-axis and the point (1, y), returning a value in the interval [-\pi/2, \pi/2].
For two arguments, this is the angle in radians between the positive x-axis and the point (x, y), returning a value in the interval [-\pi, \pi]. This corresponds to a standard atan2
(https://en.wikipedia.org/wiki/Atan2) function. Note that by convention atan(0.0,x) is defined as \pi and atan(-0.0,x) is defined as -\pi when x < 0.
like this:
theta_offset = atan( p1[2]-p2[2], p1[1]-p2[1] )
And finally, like in your previous question, add the p2 point instead of the p1 point at the end of x, y, and z:
x = cos.(theta).*exp.(-t).*r.+p2[1];
y = sin.(theta).*exp.(-t).*r.+p2[2];
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
In the end, I have this:
using PlotlyJS
using LinearAlgebra
# Points to connect (`p2` spirals into `p1`)
p2 = [1,1,1]
p1 = [3,10,2]
# Number of curve revolutions
rev = 3
# Number of points defining the curve
rez = 500 # Number of points defining the line
r = norm(p1[1:2]-p2[1:2])
t = range(0.,norm(p1-p2), length=rez)
theta_offset = atan( p1[2]-p2[2], p1[1]-p2[1] )
theta = range(0., 2*pi*rev, length=rez) .+ theta_offset
x = cos.(theta).*exp.(-t).*r.+p2[1];
y = sin.(theta).*exp.(-t).*r.+p2[2];
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
#show (x[begin], y[begin], z[begin])
#show (x[end], y[end], z[end]);
# Plot curve points
plot(scatter(x=x, y=y, z=z, marker=attr(size=2,color="red"),type="scatter3d"))
Which give the expected results:
p2 = [1,1,1]
p1 = [3,10,2]
(x[begin], y[begin], z[begin]) = (3.0, 10.0, 2.0)
(x[end], y[end], z[end]) = (1.0001877364735474, 1.0008448141309634, 1.0000938682367737)
and:
p1 = [1,1,1]
p2 = [3,10,2]
(x[begin], y[begin], z[begin]) = (0.9999999999999987, 1.0, 1.0)
(x[end], y[end], z[end]) = (2.9998122635264526, 9.999155185869036, 1.9999061317632263)
In 2D, let us assume the pole at the point C, and the spiral from P to Q, corresponding to a variation of the parameter in the interval [0, 1].
We have
X = Cx + cos(at+b).e^(ct+d)
Y = Cy + sin(at+b).e^(ct+d)
Using the known points,
Px - Cx = cos(b).e^d
Py - Cy = sin(b).e^d
Qx - Cx = cos(a+b).e^(c+d)
Qy - Cy = sin(a+b).e^(c+d)
From the first two, by a Cartesian to polar transformation (and logarithm), you can obtain b and d. From the last two, you similarly obtain a+b and c+d, and the spiral is now defined.
For the Z coordinate, I cannot answer precisely as you don't describe how you generalize the spiral to 3D. Anyway, we can assume a certain function Z(t), that you can map to [Pz, Qz] by the linear transformation
(Qz - Pz) . (Z(t) - Z(0)) / (Z(1) - Z(0)) + Pz.

Calculate point on a circle in 3D space

i am scratching my head for some time now how to do this.
I have two defined vectors in 3d space. Say vector X at (0,0,0) and vector Y at (3,3,3). I will get a random point on a line between those two vectors. And around this point i want to form a circle ( some amount of points ) perpendicular to the line between the X and Y at given radius.
Hopefuly its clear what i am looking for. I have looked through many similar questions, but just cant figure it out based on those. Thanks for any help.
Edit:
(Couldnt put everything into comment so adding it here)
#WillyWonka
Hi, thanks for your reply, i had some moderate success with implementing your solution, but has some trouble with it. It works most of the time, except for specific scenarios when Y point would be at positions like (20,20,20). If it sits directly on any axis its fine.
But as soon as it gets into diagonal the distance between perpendicular point and origin gets smaller for some reason and at very specific diagonal positions it kinda flips the perpendicular points.
IMAGE
Here is the code for you to look at
public Vector3 X = new Vector3(0,0,0);
public Vector3 Y = new Vector3(0,0,20);
Vector3 A;
Vector3 B;
List<Vector3> points = new List<Vector3>();
void FindPerpendicular(Vector3 x, Vector3 y)
{
Vector3 direction = (x-y);
Vector3 normalized = (x-y).normalized;
float dotProduct1 = Vector3.Dot(normalized, Vector3.left);
float dotProduct2 = Vector3.Dot(normalized, Vector3.forward);
float dotProduct3 = Vector3.Dot(normalized, Vector3.up);
Vector3 dotVector = ((1.0f - Mathf.Abs(dotProduct1)) * Vector3.right) +
((1.0f - Mathf.Abs(dotProduct2)) * Vector3.forward) +
((1.0f - Mathf.Abs(dotProduct3)) * Vector3.up);
A = Vector3.Cross(normalized, dotVector.normalized);
B = Vector3.Cross(A, normalized);
}
What you want to do first is to find the two orthogonal basis vectors of the plane perpendicular to the line XY, passing through the point you choose.
You first need to find a vector which is perpendicular to XY. To do this:
Normalize the vector XY first
Dot XY with the X-axis
If this is very small (for numerical stability let's say < 0.1) then it must be parallel/anti-parallel to the X-axis. We choose the Y axis.
If not then we choose the X-axis
For whichever chosen axis, cross it with XY to get one of the basis vectors; cross this with XY again to get the second vector.
Normalize them (not strictly necessary but very useful)
You now have two basis vectors to calculate your circle coordinates, call them A and B. Call the point you chose P.
Then any point on the circle can be parametrically calculated by
Q(r, t) = P + r * (A * cos(t) + B * sin(t))
where t is an angle (between 0 and 2π), and r is the circle's radius.

Given vector of one axis, how do I find vectors of other two axes?

This is a maths problem I am not exactly sure how to do. The vector is not aligned to an axis, so just rotating 90 degrees around x, y or z won't necessarily give me the other axes.
I can think of a couple of different scenarios you might be asking about.
Given: A pre-existing coordinate system
In a 2D system, your axes/basis are always [1,0] and [0,1] -- x and y axes.
In a 3D system, your axes/basis are always [1,0,0], [0,1,0], and [0,0,1] -- x, y, and z.
Given: One axis in an arbitrary-basis 2D coordinate system
If you have one axis in an arbitrary-basis 2D coordinate system, the other axis is the orthogonal vector.
To rotate a vector orthogonally counter-clockwise:
[x_new, y_new] = [ -y_old, x_old]
To rotate a vector orthogonally clockwise:
[x_new, y_new] = [ y_old, -x_old]
To summarize:
Given: x-axis = [ a, b]
Then: y-axis = [-b, a]
Given: y-axis = [ c, d]
Then: x-axis = [ d, -c]
Given: Two axes in an arbitrary-basis 3D coordinate system
To do this, find the cross product.
[a,b,c] x [d,e,f] = [ b*f - c*e, c*d - a*f, a*e - b*d ]
Following these three guidelines:
(x axis) x (y axis) = (z axis)
(y axis) x (z axis) = (x axis)
(z axis) x (x axis) = (y axis)
Given: One axis in an arbitrary-basis 3D coordinate system
There is not enough information to find the unique solution this problem. This is because, if you look at the second case (One axis in an arbitrary-basis 2D coordinate system), you first need to find an orthogonal vector. However, there are an infinite amount of possible orthogonal vectors to a single axis in 3D space!
You can, however, find one of the possible solutions.
One way to find an arbitrary one of these orthogonal vectors by finding any vector [d,e,f] where:
[a,b,c] = original axis
[d,e,f] = arbitrary orthogonal axis (cannot be [0,0,0])
a*d + b*e + c*f = 0
For example, if your original axis is [2,3,4], you'd solve:
2 * d + 3 * e + 4 * f = 0
That is, any value of [d,e,f] that satisfies this is a satisfactory orthogonal vector (as long as it's not [0,0,0]). One could pick, for example, [3,-2,0]:
2 * 3 + 3 *-2 + 4 * 0 = 0
6 + -6 + 0 = 0
As you can see, one "formula" that works to is [d,e,f] = [b,-a,0]...but there are many other ones that can work as well; there are, in fact, an infinite!
Once you find your two axes [a,b,c] and [d,e,f], you can reduce this back to the previous case (case 3), using [a,b,c] and [d,e,f] as your x and y axes (or whatever axes you need them to be, for your specific problem).
Normalization
Note that, as you continually do dot products and cross products, your vectors will begin to grow larger and larger. Depending on what you want, this might not be desired. For example, you might want your basis vectors (your coordinate axes) to all be the same size/length.
To turn any vector (except for [0,0,0]) into a unit vector (a vector with a length of 1, in the same direction as the original vector):
r = [a,b,c]
v = Sqrt(a^2 + b^2 + c^2) <-- this is the length of the original vector
r' = [ a/v , b/v , c/v ]
Where r' represents the unit vector of r -- a vector with length of 1 that points in the same direction as r does. An example:
r = [1,2,3]
v = Sqrt(1^2 + 2^2 + 3^2) = Sqrt(13) = 3.60555 <-- this is the length of the original vector
r' = [0.27735, 0.55470, 0.83205]
Now, if I wanted, for example, a vector in the same direction of r with a length of 5, I'd simply multiply out r' * 5, which is [a' * 5, b' * 5, c' * 5].
Having only one axis isn't enough, since there are still an infinite number of axes that can be in the perpendicular plane.
If you manage to get another axis though, you can use the cross product to find the third.
If you have one vector (x,y,z) you can get one perpendicular vector to it as (y,-x,0) (dot-product is xy-yx+0*z = 0)
Then you take the cross-product of both to get the remaining perpendicular vector:
(x,y,z) × (y,-x,0) = (0y+zx, yz-0x, -x²-y²) = (zx, yz, -x²-y²)
Are you talking about a typical 3coordinate system like the one used in a 3D engine?
With just a vector you can't find the other two, the only information you will have it the plane on which they lay.. but they can be at any angle also if they're perpendicular with the only one vector you have.

How can I turn a ray-plane intersection point into barycentric coordinates?

My problem:
How can I take two 3D points and lock them to a single axis? For instance, so that both their z-axes are 0.
What I'm trying to do:
I have a set of 3D coordinates in a scene, representing a a box with a pyramid on it. I also have a camera, represented by another 3D coordinate. I subtract the camera coordinate from the scene coordinate and normalize it, returning a vector that points to the camera. I then do ray-plane intersection with a plane that is behind the camera point.
O + tD
Where O (origin) is the camera position, D is the direction from the scene point to the camera and t is time it takes for the ray to intersect the plane from the camera point.
If that doesn't make sense, here's a crude drawing:
I've searched far and wide, and as far as I can tell, this is called using a "pinhole camera".
The problem is not my camera rotation, I've eliminated that. The trouble is in translating the intersection point to barycentric (uv) coordinates.
The translation on the x-axis looks like this:
uaxis.x = -a_PlaneNormal.y;
uaxis.y = a_PlaneNormal.x;
uaxis.z = a_PlaneNormal.z;
point vaxis = uaxis.CopyCrossProduct(a_PlaneNormal);
point2d.x = intersection.DotProduct(uaxis);
point2d.y = intersection.DotProduct(vaxis);
return point2d;
While the translation on the z-axis looks like this:
uaxis.x = -a_PlaneNormal.z;
uaxis.y = a_PlaneNormal.y;
uaxis.z = a_PlaneNormal.x;
point vaxis = uaxis.CopyCrossProduct(a_PlaneNormal);
point2d.x = intersection.DotProduct(uaxis);
point2d.y = intersection.DotProduct(vaxis);
return point2d;
My question is: how can I turn a ray plane intersection point to barycentric coordinates on both the x and the z axis?
The usual formula for points (p) on a line, starting at (p0) with vector direction (v) is:
p = p0 + t*v
The criterion for a point (p) on a plane containing (p1) and with normal (n) is:
(p - p1).n = 0
So, plug&chug:
(p0 + t*v - p1).n = (p0-p1).n + t*(v.n) = 0
-> t = (p1-p0).n / v.n
-> p = p0 + ((p1-p0).n / v.n)*v
To check:
(p - p1).n = (p0-p1).n + ((p1-p0).n / v.n)*(v.n)
= (p0-p1).n + (p1-p0).n
= 0
If you want to fix the Z coordinate at a particular value, you need to choose a normal along the Z axis (which will define a plane parallel to XY plane).
Then, you have:
n = (0,0,1)
-> p = p0 + ((p1.z-p0.z)/v.z) * v
-> x and y offsets from p0 = ((p1.z-p0.z)/v.z) * (v.x,v.y)
Finally, if you're trying to build a virtual "camera" for 3D computer graphics, the standard way to do this kind of thing is homogeneous coordinates. Ultimately, working with homogeneous coordinates is simpler (and usually faster) than the kind of ad hoc 3D vector algebra I have written above.

Resources