Find common endpoint of two 3d line segments - c++

So i have two 3d line segments A and B the only givens are the origins of both line segments and their lenghts. I need to oriente the two line segments in a way that they end at the same position.
EX:
point3d common_end_position;
bool result= intersect_line_segments(
{0, 0, 0}, // position_0
2.0, // length_0
{2, 0, 0}, // position_1
2.0, // length_1
{0, 0, 1}, // hint_direction
&common_end_position);
The funciton should return true with the common end postion being {1, 0, 1.7321}
If they cannont be oriented so that they end at the same endpoint then the function would return false

Let positions are C1 and C2, difference vector is
D = C2-C1, distance is d = |D|, lengths are r and R.
Common end P does not exist if d > R + r or d < abs(R-r)
Otherwise projection of P onto C1C2 has length
x = (d^2 + R^2 - r^2) / (2d)
(mathworld page)
and distance of P from C1C2 is
y = sqrt(R^2-x^2)
If it is guaranteed that hint vector H is perpendicular to D, then the rest is simple:
1) Get normalized vector ud = D / d
2) Find projection point P' = C1 + ud * x
3) Add perpendicular vector P = P' + H * y (assuming unit H vector)
If H might be not perpendicular (but not parallel to C1C2!) then find
H' = ud x (H x ud)
using two vector multiplications and use H' instead.

Related

"Point-Segment" distance: shouldn't this code use the norm instead of the norm squared?

I am using a piece of code I have found on the internet (here) to compute the distance between a point and a segment. Here is the code:
float
dist_Point_to_Segment( Point P, Segment S)
{
Vector v = S.P1 - S.P0;
Vector w = P - S.P0;
double c1 = dot(w,v);
if ( c1 <= 0 )
return d(P, S.P0);
double c2 = dot(v,v);
if ( c2 <= c1 )
return d(P, S.P1);
double b = c1 / c2;
Point Pb = S.P0 + b * v;
return d(P, Pb);
}
When computing double b = c1 / c2; c2 is dot(v, v) (so, the norm of v squared). Shouldn't we use norm(v)? Isn't that the proper definition of the projection of a vector on another one?
Thanks.
Actually the definition is with norm(v) squared. So dot(v, v) is correct.
Here's a nice and short explanation:
http://math.oregonstate.edu/home/programs/undergrad/CalculusQuestStudyGuides/vcalc/dotprod/dotprod.html
If v is normalized, the length of the projection is w.v, and the projected vector is (w.v) v.
As v appears twice, the formula for an unnormalized vector is
(w.(v/|v|)) v/|v| = (w.v/|v|²) v
This spares a square root.

How do I estimate a cube corner from a projected square?

I've got the coordinates of a square's corners projected onto an image. I want to know where I'd find the corners of a cube if they were projected onto the image.
More specifically, assuming a square with sides of length 1. It's at the origin with coordinates (x, y, z) of (0, 0, 0), (1, 0, 0), (0, 1, 0) and (1, 1, 0). I know the corresponding projected locations (u, v) for those square corners. how do I find the (u, v) for the (x, y, z) point (0, 0, 1) ?
I'm really just looking for an equations that will give u001 and v001 in terms of the scalar values:
u000 v000
u100 v100
u010 v010
u110 v110
I think the transformation matrix in homogenous coordinates from (x, y, z, 1) to (u, v, w) will look like:
a b c d
e f g h
i j k 1
But I can't figure out how to find c, g, or k without a z point.
Doing some algebra:
d = u_00
h = v_00
a = u_10 * (i+1) - u_00
b = u_01 * (j+1) - u_00
e = v_10 * (i+1) - v_00
f = v_01 * (j+1) - v_00

Finding element at x,y in a given matrix after rotation in C/C++?

How can I find the element at index x,y in a given matrix after rotating the total matrix without performing the matrix rotation.
That means I am just interested in that coordinate don't want to perform total operation on total matrix and than simply get the element at any index.
Example:
suppose a matrix is given
1 2 3
4 5 6
7 8 9
and i want to find the element at 1,1 after rotating the matrix by 90 degree.
answer should be "7".
**NOTE**: Without performing the rotation on total matrix.
and if i want the element at 1,2 than the answer should be "4".
I hope I clearly communicated the question please help if you know the solution or algorithm for this question.
Thank you.
Suppose you have a m x n matrix and you are interested in the position of M[i][j] after rotation.
So, after a rotation of 90 degrees clockwise, M[i][j] -> M[j][m+1-i].
As in your example, M[3][1] will be M[1][3+1-3] after rotation.
Hope this solves your problem.
Here's one way to solve the problem (other than using somebody else's solution).
It's fairly clear that the column index of each element is the row index of that element after rotation (at least, I hope that's clear).
So, the problem is the column index of an element after rotation.
The first row will become the last column, the second will be the second last, and so on until the last row which becomes the first column.
One way of viewing this is that we have the sequence (of rows) i = 1, 2, ..., m and want to map that to the sequence (of columns) j = m, m - 1, m - 2, ..., 2, 1.
But m = m + 1 - 1, m - 1 = m + 1 - 2, m - 2 = m + 1 - 3, ..., 1 = m + 1 - m.
So the desired sequence is j = m + 1 - i.
In other words, M[i][j] -> M[j][m + 1 - i].
You want to map:
(x,y) -> (x', y')
Assume following:1
x' = ax + by + c
y' = dx + ey + f
Now, (1, 1) maps to (W, 1)2
w = a + b + c
1 = d + e + f
(1, W) maps to (1, 1)3
1 = a + bw + c
1 = d + ew + f
and (W, H) maps to (1, H)4
1 = aw + bh + c
h = dw = eH + f
Solve 2, 3 and 4 equation and fill in to 1 get the value. (Hint: b = -1, e = 0)
// For 90 degree rotation using correct indexing for x and y (starting at 0 not 1)
// Assuming square matrix
template<class T, int size>
T elemAfter90degRot(int x, int y, T[size][size] mat) {
int j = y;
int i = size - 1 - x;
return mat[i][j];
}
I think that should do the trick for a 90 degree rotation of a square matrix

Partitioning of an AABB

I have a problem where I need to divide an AABB into a number of small AABBs. I need to find the minimum and maximum points in each of the smaller AABB.
If we take this cuboid as an example, we can see that is divided into 64 smaller cuboids. I need to calculate the minimum and maximum points of all of these smaller cuboids, where the number of cuboids (64) can be specified by the end user.
I have made a basic attempt with the following code:
// Half the length of each side of the AABB.
float h = side * 0.5f;
// The length of each side of the inner AABBs.
float l = side / NUMBER_OF_PARTITIONS;
// Calculate the minimum point on the parent AABB.
Vector3 minPointAABB(
origin.getX() - h,
origin.getY() - h,
origin.getZ() - h
);
// Calculate all inner AABBs which completely fill the parent AABB.
for (int i = 0; i < NUMBER_OF_PARTITIONS; i++)
{
// This is not correct! Given a parent AABB of min (-10, 0, 0) and max (0, 10, 10) I need to
// calculate the following positions as minimum points of InnerAABB (with 8 inner AABBs).
// (-10, 0, 0), (-5, 0, 0), (-10, 5, 0), (-5, 5, 0), (-10, 0, 5), (-5, 0, 5),
// (-10, 5, 5), (-5, 5, 5)
Vector3 minInnerAABB(
minPointAABB.getX() + i * l,
minPointAABB.getY() + i * l,
minPointAABB.getZ() + i * l
);
// We can calculate the maximum point of the AABB from the minimum point
// by the summuation of each coordinate in the minimum point with the length of each side.
Vector3 maxInnerAABB(
minInnerAABB.getX() + l,
minInnerAABB.getY() + l,
minInnerAABB.getZ() + l
);
// Add the inner AABB points to a container for later use.
}
Many thanks!
I assume that your problem is that you don't get enough sub-boxes. The number of partitions refers to partitions per dimension, right? So 2 partitions yield 8 sub-boxes, 3 partitions yield 27 sub-boxes and so on.
Then you must have three nested loops, one for each dimension:
for (int k = 0; k < NUMBER_OF_PARTITIONS; k++)
for (int j = 0; j < NUMBER_OF_PARTITIONS; j++)
for (int i = 0; i < NUMBER_OF_PARTITIONS; i++)
{
Vector3 minInnerAABB(
minPointAABB.getX() + i * l,
minPointAABB.getY() + j * l,
minPointAABB.getZ() + k * l
);
Vector3 maxInnerAABB(
minInnerAABB.getX() + l,
minInnerAABB.getY() + l,
minInnerAABB.getZ() + l
);
// Add the inner AABB points to a container for later use.
}
}
}
Alternatively, you can have one huge loop over the cube of your partitios and sort out the indices by division and remainder operations inside the loop, which is a bit messy for three dimensions.
It might also be a good idea to make the code more general by calculating three independent sub-box lengths for each dimension based on the side lengths of the original box.

How do I get three non-colinear points on a plane? - C++

I'm trying to implement at line-plane intersection algorithm. According to Wikipedia I need three non-colinear points on the plane to do that.
I therefore tried implementing this algorithm in C++, however. Something is definitely wrong, cause it makes no sense that I can choose whatever x and y coordinates and they'll fit in the plane. What if the plane is vertical and along the x-axis? No point with y=1 would then be in the plane.
I realize that this problem has been posted a lot on StackOverflow, and I see lots of solutions where the plane is defined by 3 points. But I only have a normal and a position. And I can't test my line-plane intersection algorithm before I sort out my non-colinear point finder.
The problem right now, is that I'm dividing by normal.z, and that obviously won't work when normal.z is 0.
I'm testing with this plane: Plane* p = new Plane(Color(), Vec3d(0.0,0.0,0.0), Vec3d(0.0,1.0,0.0)); // second parameter : position, third parameter : normal
The current code gives this incorrect answer:
{0 , 0 , 0} // alright, this is the original
{12.8377 , 17.2728 , -inf} // obviously this is not a non-colinear point on the given plane
Here's my code:
std::vector<Vec3d>* Plane::getThreeNonColinearPoints() {
std::vector<Vec3d>* v = new std::vector<Vec3d>();
v->push_back(Vec3d(position.x, position.y, position.z)); // original position can serve as one of the three non-colinear points.
srandom(time(NULL));
double rx, ry, rz, start;
rx = Plane::fRand(10.0, 20.0);
ry = Plane::fRand(10.0, 20.0);
// Formula from here: http://en.wikipedia.org/wiki/Plane_(geometry)#Definition_with_a_point_and_a_normal_vector
// nx(x-x0) + ny(y-y0) + nz(z-z0) = 0
// |-----------------| <- this is "start"
//I'll try to insert position as x0,y0,z0 and normal as nx,ny,nz, and solve the equation
start = normal.x * (rx - position.x) + normal.y * (ry - position.y);
// nz(z-z0) = -start
start = -start;
// (z-z0) = start/nz
start /= normal.z; // division by zero
// z = start+z0
start += position.z;
rz = start;
v->push_back(Vec3d(rx, ry, rz));
// TODO one more point
return v;
}
I realize that I might be trying to solve this totally wrong. If so, please link a concrete implementation of this. I'm sure it must exist, when I see so many line-plane intersection implementations.
Thanks in advance.
A plane can be defined with several ways. Typically a point on the plane and a normal vector is used. To get the normal vector from three points (P1, P2, P3 ) take the cross product of the side of the triangle
P1 = {x1, y1, z1};
P2 = {x2, y2, z2};
P3 = {x3, y3, z3};
N = UNIT( CROSS( P2-P1, P3-P1 ) );
Plane P = { P1, N }
The reverse, to go from a point P1 and normal N to three points, you start from any direction G not along the normal N such that DOT(G,N)!=0. The two orthogonal directions along the plane are then
//try G={0,0,1} or {0,1,0} or {1,0,0}
G = {0,0,1};
if( MAG(CROSS(G,N))<TINY ) { G = {0,1,0}; }
if( MAG(CROSS(G,N))<TINY ) { G = {1,0,0}; }
U = UNIT( CROSS(N, G) );
V = CROSS(U,N);
P2 = P1 + U;
P3 = P1 + V;
A line is defined by a point and a direction. Typically two points (Q1, Q2) define the line
Q1 = {x1, y1, z1};
Q2 = {x2, y2, z2};
E = UNIT( Q2-Q1 );
Line L = { Q1, E }
The intersection of the line and plane are defined by the point on the line r=Q1+t*E that intersects the plane such that DOT(r-P1,N)=0. This is solved for the scalar distance t along the line as
t = DOT(P1-Q1,N)/DOT(E,N);
and the location as
r = Q1+(t*E);
NOTE: The DOT() returns the dot-product of two vector, CROSS() the cross-product, and UNIT() the unit vector (with magnitude=1).
DOT(P,Q) = P[0]*Q[0]+P[1]*Q[1]+P[2]*Q[2];
CROSS(P,Q) = { P[1]*Q[2]-P[2]*Q[1], P[2]*Q[0]-P[0]*Q[2], P[0]*Q[1]-P[1]*Q[0] };
UNIT(P) = {P[0]/sqrt(DOT(P,P)), P[1]/sqrt(DOT(P,P)), P[2]/sqrt(DOT(P,P))};
t*P = { t*P[0], t*P[1], t*P[2] };
MAG(P) = sqrt(P[0]*P[0]+P[1]*P[1]+P[2]*P[2]);
One approach you may find easy to implement is to see where the plane intersects the coordinate axes. For the plane given by the equationaX + bY + cZ - d = 0 hold two variables at 0 and solve for the third. So the solutions would be (assuming a, b, c, and d are all non-zero):
(d/a, 0, 0)
(0, d/b, 0)
(0, 0, d/c)
You will need to consider the cases where one or more of the coefficients are 0 so you don't get a degenerate or colinear solutions. As an example if exactly one of the coefficients is 0 (say a=0) you instead use
(1, d/b, 0)
(0, d/b, 0)
(0, 0, d/c)
If exactly two of the coefficients are 0 (say a=0 and b=0) you can use:
(1, 0, d/c)
(0, 1, d/c)
(0, 0, d/c)
If d=0, the plane intersects the three axes at the origin, and so you can use:
(1, 0, -a/c)
(0, -c/b, 1)
(-b/a, 1, 0)
You will need to work out simular cases for d and exactly one other coefficient being 0, as well as d and two others being 0. There should be a total of 16 cases, but there are a few things that come to mind which should make that somewhat more manageable.
Where N=(Nx,Ny,Nz) is the normal, you could project the points N, (Ny,Nz,Nx), (Nz,Nx,Ny) onto the plane: they're guaranteed to be distinct.
Alternatively, if P and Q are on the plane, P+t(Q-P)xN is also on the plane for any t!=0 where x is the cross product.
Alternatively if M!=N is an arbitrary vector, K=MxN and L=KxN are colinear with the plane and any point p on the plane can be written as p=Origin+sK+tL for some s,t.