How to find 3D points coordinates in a perpendicular plane to a given vector - math

I have two points in a 3d space, one point is (x,0,z) and the other one is the origin (0,0,0), through those points there is a passing line with length L that is starting from the first point and continuing after the origin point, in the end of this line there is a perpendicular (to the line) flat board with dimensions of W x H, the line ends in the middle of this board.
Assume that x,z,L,H,W are given, I need a way to find all the 3D points coordinates where those points forming a pixels image over the board (meaning each point has a distance of 1 from its left, right, top, bottom neighboring points).
Attached a pretty ugly drawing :) I made trying to illustrate the problem (I marked the pixels points with two question marks but I need them all).
Thanks.

It is possible to define that plane. But there is no selected direction to build a grid uniquelly.
Let we choose OY direction as base (because normal has zero Y-component).
So we have:
Normal vector N = (xx, 0, zz) //I renamed values to avoid confusion with coordinate
variables
Unit normal vector n = (nx, 0, nz), where
nx = xx / Sqrt(xx*xx+zz*zz)
nz = zz / Sqrt(xx*xx+zz*zz)
Base point
B = (bx, 0, bz) = (xx - nx * L, 0, zz - nz * L)
Unit base vector in the plane
dy = (0, 1, 0)
Another base vector
dc = dy x n //vector product
= (-bz, 0, bx)
Now it is possible to generate a grid, using integer indexes i, j in ranges (-W/2..W/2) and (-H/2.. H/2). Grid nodes coordinates:
x(i, j) = bx - j * bz
y(i, j) = 0 + i
z(i, j) = bz + j * bx

Related

How to efficiently compute the future position of a point that will move in a box and bounce on its walls (2D)?

I have a simple maths/physics problem here: In a Cartesian coordinate system, I have a point that moves in time with a known velocity. The point is inside a box, and bounces orthognally on its walls.
Here is a quick example I did on paint:
What we know: The red point position, and its velocity which is defined by an angle θ and a speed. Of course we know the dimensions of the green box.
On the example, I've drawn in yellow its approximate trajectory, and let's say that after a determined period of time which is known, the red point is on the blue point. What would be the most efficient way to compute the blue point position?
I've tought about computing every "bounce point" with trigonometry and vector projection, but I feel like it's a waste of resources because trigonometric functions are usually very processor hungry. I'll have more than a thousand points to compute like that so I really need to find a more efficient way to do it.
If anyone has any idea, I'd be very grateful.
Apart from programming considerations, it has an interesting solution from geometric point of view. You can find the position of the point at a specific time T without considering its temporal trajectory during 0<t<T
For one minute, forget the size and the boundaries of the box; and assume that the point can move on a straight line for ever. Then the point has constant velocity components vx = v*cos(θ), vy = v*sin(θ) and at time T its virtual porition will be x' = x0 + vx * T, y' = y0 + vy * T
Now you need to map the virtual position (x',y') into the actual position (x,y). See image below
You can recursively reflect the virtual point w.r.t the borders until the point comes back into the reference (initial) box. And this is the actual point. Now the question is how to do these mathematics? and how to find (x,y) knowing (x',y')?
Denote by a and b the size of the box along x and y respectively. Then nx = floor(x'/a) and ny = floor(y'/b) indicates how far is the point from the reference box in terms of the number of boxes. Also dx = x'-nx*a and dy = y'-ny*b introduces the relative position of the virtual point inside its virtual box.
Now you can find the true position (x,y): if nx is even, then x = dx else x = a-dx; similarly if ny is even, then y = dy else y = b-dy. In other words, even number of reflections in each axis x and y, puts the true point and the virtual point in the same relative positions, while odd number of reflections make them different and complementary.
You don't need to use trigonometric function all the time. Instead get normalized direction vector as (dx, dy) = (cos(θ), sin(θ))
After bouncing from vertical wall x-component changes it's sign dx = -dx, after bouncing from horizontal wall y-component changes it's sign dy = -dy. You can see that calculations are blazingly simple.
If you (by strange reason) prefer to use angles, use angle transformations from here (for ball with non-zero radius)
if ((ball.x + ball.radius) >= window.width || (ball.x - ball.radius) <= 0)
ball.theta = M_PI - ball.theta;
else
if ((ball.y + ball.radius) >= window.height || (ball.y - ball.radius) <= 0)
ball.theta = - ball.theta;
To get point of bouncing:
Starting point (X0, Y0)
Ray angle Theta, c = Cos(Theta), s = Sin(Theta);
Rectangle coordinates: bottom left (X1,Y1), top right (X2,Y2)
if c >= 0 then //up
XX = X2
else
XX = X1
if s >= 0 then //right
YY = Y2
else
YY = Y1
if c = 0 then //vertical ray
return Intersection = (X0, YY)
if s = 0 then //horizontal ray
return Intersection = (XX, Y0)
tx = (XX - X0) / c //parameter when vertical edge is met
ty = (YY - Y0) / s //parameter when horizontal edge is met
if tx <= ty then //vertical first
return Intersection = (XX, Y0 + tx * s)
else //horizontal first
return Intersection = (X0 + ty * c, YY)

How to find a point in 3-D at an arbitrary perpendicular line given distance to the point

I have a line AB. I would like to draw a line BC, perpendicular to AB. I know xyz of the points A and B, I also know the distance N between B and C. How can I find an arbitrary point C which fits into the given parameters? The calculations should be done in 3-D. Any point, perpendicular to AB can be the point C, if its distance to B equals N.
An almost identical question is given here, but I would like to know how the same thing is done in 3-D: How do you find a point at a given perpendicular distance from a line?
The calculation that works for me in 2-D was given in the link above:
dx = A.x-B.x
dy = A.y-B.y
dist = sqrt(dx*dx + dy*dy)
dx /= dist
dy /= dist
C.x = B.x + N*dy
C.y = B.y - N*dx
I tried adding Z axis to it like this:
dz = A.z - B.z
dist = sqrt(dx*dx + dy*dy + dz*dz)
dz /=dist
C.z = .... at this point it becomes a mystery to me
If I put something like "C.z - N*dz" into C.z, the distance is accurate only in some rotation angles, I would like to know the correct solution. I can imagine that in 3-D it is calculated in a completely different manner.
Clarification
Point C is not unique. It can be any point on a circle with its
centre at B and radius N. The circle is perpendicular to AB
If the desired point C can be any of the infinitely-many points fitting your requirements, here is one method.
Choose any vector that is not parallel or anti-parallel to vector AB. You could try the vector (1, 0, 0), and if that is parallel you could use (0, 1, 0) instead. Then take the cross-product of vector AB and the chosen vector. That cross-product is perpendicular to vector AB. Divide that cross-product by its length then multiply by the desired length N. Finally extend that vector from point B to find your desired point C.
Here is code in Python 3 that follows that algorithm. This code is somewhat non-pythonic to make it easier to convert to other languages. (If I really did this for myself I would use the numpy module to avoid coordinates completely and shorten this code.) But it does treat the points as tuples of 3 values: many languages will require you to handle each coordinate separately. Any real-life code would need to check for "near zero" rather than "zero" and to check that the sqrt calculation does not result in zero. I'll leave those additional steps to you. Ask if you have more questions.
from math import sqrt
def pt_at_given_distance_from_line_segment_and_endpoint(a, b, dist):
"""Return a point c such that line segment bc is perpendicular to
line segment ab and segment bc has length dist.
a and b are tuples of length 3, dist is a positive float.
"""
vec_ab = (b[0]-a[0], b[1]-a[1], b[2]-a[2])
# Find a vector not parallel or antiparallel to vector ab
if vec_ab[1] != 0 or vec_ab[2] != 0:
vec = (1, 0, 0)
else:
vec = (0, 1, 0)
# Find the cross product of the vectors
cross = (vec_ab[1] * vec[2] - vec_ab[2] * vec[1],
vec_ab[2] * vec[0] - vec_ab[0] * vec[2],
vec_ab[0] * vec[1] - vec_ab[1] * vec[0])
# Find the vector in the same direction with length dist
factor = dist / sqrt(cross[0]**2 + cross[1]**2 + cross[2]**2)
newvec = (factor * cross[0], factor * cross[1], factor * cross[2])
# Find point c such that vector bc is that vector
c = (b[0] + newvec[0], b[1] + newvec[1], b[2] + newvec[2])
# Done!
return c
The resulting output from the command
print(pt_at_given_distance_from_line_segment_and_endpoint((1, 2, 3), (4, 5, 6), 2))
is
(4.0, 6.414213562373095, 4.585786437626905)

Sliding Two Points Along Perpendicular Slope By Distance

For my current project, a user taps 2 locations on the X,Y plane. Once the two points are tapped, the user should then click and drag to extend 2 new points starting at the original 2 locations into a perfect rectangle (90 degree corners).
The math seems super simple, I just can't seem to get the right configuration to slide these two points along the perpendicular slope (by a certain distance).
My current attempt is to find the perpendicular slope and slide it by X distance (the distance the user has dragged), but I'm stuck on translating the perp. slope by distance.
You have points A and B. Difference vector
D = (Dx, Dy) = (Bx - Ax, By - Ay)
Normalized (unit) vector
Len = Sqrt(Dx*Dx + Dy*Dy)
(dx, dy) = (Dx / Len, Dy / Len)
Perpendicular unit vector
(px, py) = (-dy, dx)
Shift by distance L
pL = (px * L, py * L)
So shifted A will have coordinates
(a'x, a'y) = (Ax +/- px * L, Bx +/- py * L)
+ or - for two possible shift directions

How to find points along arc if given initial point, ending point, random point + precision?

the precision is the number of points I want for my vector, from 0, the initial point of my arc, to the precision I want minus 1.
Code example in c++:
int precision = 20;
double pointInit[3] = {2,5,2};
double pointRandom[3] = {3,7,1};
double pointInit[3] = {0,-3,1};
std::vector<std::array<double,3>> pointArc;
std::array<double, 3> currentPoint;
// Fill the pointArc vector, from 0 (initial point) to precision -1 (ending point)
for (int i = 0 ; i < precision; i++)
{
// Find the value of the current point
// currentPoint[0] = ????;
// currentPoint[1] = ????;
// currentPoint[2] = ????;
pointArc.push_back(currentPoint);
}
EDIT : The arc I'm looking for is a circular arc
Use atan2() to find the angles of the endpoints with respect to the center, subtend the angle between them precision - 1 times, and convert the polar coordinates (use one of the endpoints to get the distance from the center) to rectangular form.
1) translate the three points so that P0 comes to the origin
2) consider the vectors P0P1 and P0P2 and form an orthonormal basis by the Gram-Schmidt process (this is easy)
3) in this new basis, the coordinates of the three points are (0, 0, 0), (X1, 0, 0), (X2, Y2, 0), and you have turned the 3D problem to 2D. (Actually X1=d(P0,P1) and X2, Y2 are obtained from the dot and cross products of P0P2 with P0P1 / X1)
The equation of a 2D circle through the origin is
x² + y² = 2Xc.x + 2Yc.y
Plugging the above coordinates, you easily solve the 2x2 system for Xc and Yc.
X1² = 2Xc.X1
X2² + Y2² = 2Xc.X2 + 2Yc.Y2
4) The parametric equation of the circle is
x = Xc + R cos(t)
y = Yc + R sin(t)
where R²=Xc²+Yc².
You can find the angles t0 and t2 corresponding to the endpoints with tan(t) = (y - Yc) / (x - Xc).
5) interpolate on the angle t0.(1-i/n) + t2.i/n, compute the reduced coordinates x, y from the parametric equation and apply the inverse transforms of 2) and 1).

Drawing a plane

I want to draw a plane which is given by the equation: Ax+By+Cz+D=0.
I first tried to draw him by setting x,y and then get z from the equation. this did not work fine because there are some planes like 0x+0y+z + 0 = 0 and etc...
my current solution is this:
- draw the plane on ZY plane by giving 4 coordinates which goes to infinity.
- find out to rotation that should be done in order to bring the normal of the given plane(a,b,c) to lay
on z axis.
- find the translation that should be done in order for that plane be on x axis.
- make the exactly opposite transformation to those rotation and to this translation hence i will get the
plane in his place.
ok
this is a great thing but I can make the proper math calculations(tried a lot of times...) with the dot product and etc....
can someone help me in understanding the exact way it should be done OR give me some formula in which I will put ABCD and get the right transformation?
You will want the following transformation matrix:
[ x0_x y0_x z0_x o_x ]
M = [ x0_y y0_y z0_y o_y ]
[ x0_z y0_z z0_z o_z ]
[ 0 0 0 1 ]
Here, z0 is the normal of your plane, and o is the origin of your plane, and x0 and y0 are two vectors within your plane orthogonal to z0 that define the rotation and skew of your projection.
Then any point (x,y) on your XY plane can be projected to a point (p_x, p_y, p_z) your new plane with the following:
(p_x, p_y, p_z, w) = M * (x, y, 0, 1)
now, z0 in your transformation matrix is easy, that's the normal of your plane and that is simply n = normalize(a,b,c).
In choosing the rest however you have distinctly more freedom. For the origin you could take the point that the plane intersects the Z axis, unless of course the plane is parallel to the Z axis, in which case you need something else.
So e.g.
if (c != 0) { //plane intersects Z axis
o_x = 0;
o_y = 0;
o_z = -d/c;
}
else if (b != 0) { // plane intersects Y axis
o_x = 0;
o_y = -d/b;
o_z = 0;
}
else { // plane must intersect the X axis
o_x = -d/a;
o_y = 0;
o_z = 0;
}
In practice you may want to prefer a different test than (c != 0), because with that test it will succeed even is c is very very small but just different from zero, leading your origin to be at say, x=0, y=0, z=10e100 which would probably not be desirable. So some test like (abs(c) > threshold) is probably preferable. However you could of course take an entirely different point in the plane to put the origin, perhaps the point closest to the origin of your original coordinate system, which would be:
o = n * (d / sqrt(a^2 + b^2 + c^2))
Then finally we need to figure out an x0 and y0. Which could be any two linearly independent vectors that are orthogonal to z0.
So first, let's choose a vector in the XY plane for our x0 vector:
x0 = normalize(z0_y, -z0_x, 0)
Now, this fails if your z0 happens to be of the form (0, 0, z0_z) so we need a special case for that:
if (z0_x == 0 && z0_y == 0) {
x0 = (1, 0, 0)
}
else {
x0 = normalize(z0_y, -z0_x, 0)
}
Finally let's say we do not want skew and choose y0 to be orthogonal to both x0, and y0, then, using the crossproduct
y0 = normalize(x0_y*y0_z-x0_z*y0_y, x0_z*y0_x-x0_z*y0_z, x0_x*y0_y-x0_y*y0_x)
Now you have all to fill your transformation matrix.
Disclaimer: Appropriate care should be taken when using floating point representations for your numbers, simple (foo == 0) tests are not sufficient in those cases. Read up on floating point math before you start implementing stuff.
Edit: renamed some variables for clarity
Is this what you're asking?
Transforming a simple plane like the xy plane to your plane is fairly simple:
your plane is Ax+By+Cz+D=0
the xy plane is simply z=0. i.e. A=B=D=0, while C=whatever you want. We'll say 1 for simplicity's sake.
When you have a plane in this form, the normal of the plane is defined by the vector (A,B,C)
so you want a rotation that will take you from (0,0,1) to (A,B,C)*
*Note that this will only work if {A,B,C} is unitary. so you may have to divide A B and C each by sqrt(A^2+B^2+C^2).
rotating around just two of the axes can get your from any direction to any other direction, so we'll pick x and y;
here are the rotation matrices for rotations by a about the x axis, and b about the y axis.
Rx := {{1, 0, 0}, {0, Cos[a], Sin[a]}, {0, -Sin[a], Cos[a]}}
Ry := {{Cos[b], 0, -Sin[b]}, {0, 1, 0}, {Sin[b], 0, Cos[b]}}
if we do a rotation about x, followed by a rotation about y, of the vector normal to the xy plane, (0,0,1), we get:
Ry.Rx.{0,0,1} = {-Cos[a] Sin[b], Sin[a], Cos[a] Cos[b]}
which are your A B C values.
i.e.
A = -Cos[a]Sin[b]
B = Sin[a]
C = Cos[a]Cos[b]
From here, it's simple.
a = aSin[B]
so now A = -Cos[aSin[B]]Sin[b]
Cos[aSin[x]] = sqrt(1-x^2)
so:
A = -Sqrt[1-B^2] * Sin[b]
b = aSin[-A/sqrt[1-B^2]]
a = aSin[B] (rotation about x axis)
b = aSin[-A/sqrt[1-B^2]] (rotation about y axis)
So we now have the angles about the x and y axes we need to rotate by.
After this, you just need to shift your plane up or down until it matches the one you already have.
The plane you have at the moment, (after those two rotations) is going to be Ax+By+Cz=0.
the plane you want is Ax+Bx+Cz+D=0. To find out d, we will see where the z axis crosses your plane.
i.e. Cz+D=0 -> z = -D/C
So we transform your z in Ax+By+Cz=0 by -D/C to give:
Ax+By+C(z+D/C) = Ax+By+Cz+D=0. Oh would you look at that!
It turns out you don't have to do any extra maths once you have the angles to rotate by!
The two angles will give you A,B, and C. To get D you just copy it from what you had.
Hope that's of some help, I'm not entirely sure how you plan on actually drawing the plane though...
Edited to fix some horrible formatting. hopefully it's better now.

Resources