How to check a point is inside an ellipsoid with orientation? - algorithm

For an ellipsoid of the form
with orientation vector and centre at point , how to find whether a point is inside the ellipsoid or not?
An additional note that the geometry actually is with a=b (spheroid) and therefore one axis is sufficient to define orientation
Note: I see a similar question asked in the forum. But, it is about an ellipsoid at origin and without any arbitrary orientation and here both arbitrary position and orientation are considered.

Find affine transform M that translates this ellipse in axis-oriented one (translation by -p and rotation to align orientation vector r and proper coordinate axis).
Then apply this transform to point p and check that p' lies inside axis-oriented ellipsoid, i.e.
x^2/a^2+ y^2/b^2+z^2/c^2 <= 1

Create a coordinate system E with the center at p and with the long axis of the ellipse aligned with r. Create a matrix that can transform global coordinates to the coordinate system E. Then put the transformed coordinates into the ellipse equation.

A center point p and an "orientation vector" r do not suffice to completely specify the position of the ellipsoid, there is one degree of freedom left. Your problem is indeterminate.

If your vector r is a unit vector from the origin to the pole, then the test for whether a point q is in (or on) the ellipse is:
v = q-p; // 3d vector difference
dot = v.r; // 3d dot product
f = dot*dot;
g = v.v - f; // 3d dot product and scalar subtraction
return f/(b*b) + g/(a*a) <= 1
Note that if the ellipse was aligned so that r was the z unit vector, then the test above translates into the usual test for inclusion of a point in an ellipse.

Related

Point in Polygon 3d (same plane) algorithm

I have a point and a polygon in the same plane in 3d space and now I want to check whether or not the point is in the polygon or not.
Is there an easy way to change the algorithm from this thread Point in Polygon Algorithm to work for 3d space?
Or are there other algorithms that can solve this problem easily?
If there are not, would the following idea work:
Check if the plane is the XZ-plane or the YZ-plane, if yes, ignore the other axis (i.e. for the XZ-plane ignore the y values) and use the pip algorithm from the before mentioned thread. And if no, just ignore the z values of the point and the polygon and use the pip algorithm.
there are 2 "basic" ways of testing planar concave polygon:
convert to set of convex ones and test direction of cross product between point and all faces
the conversion to convex polygon is not as easy but its doable either by triangulation or clipping ear or what ever method... After that just check the cross products... so if your convex polygon has vertexes p0,p1,p2,...,p(n-1) and testing point p then
d0 = cross( p-p0 , p0-p(n-1) );
for (i=1;i<n;i++)
{
di = cross( p-p(i), p(i)-p(i-1) );
if ( dot ( d0 , di ) <=0.0 ) return false;
}
return true;
so just check all the polygons and return OR of the subresults
use hit test
You cast ray from your point in any direction parallel to your plane and count the number of hits you ray has done with the edges of polygon. If its even point is outside if its odd point is inside. The link in your question uses this algo. However in 3D you need to change the direction so it still is inside plane... for example by using single edge of polygon dir=p1-p0 as your direction. You also have to code some rules for cases when your ray hits Vertex directly so its counted just once instead of multiple times. Also the hit must be computed in 3D so you need axis/line intersection. It can be found here:
Cone to box collision
just look for line closest(axis a0,line l1) function. It returns line that is the closest connection between line and axis. Then just simply check if the two points are the same or not (length of the line is zero).
Now to simplify this you might port your 3D data into 2D
That can get rid of some accuracy problems related to rounding to the plane...
You are doing this by just ignoring one coordinate. That is simple but it might bring some rounding problems also the result has different shape (scaled differently in each axis) so the metrics is not the same anymore which might bring other problems latter if this is used for other purposes or any kind of thresholding is used.
There is a better method. We need any 2 basis vectors u,v that are perpendicular to each and are inside your plane and one point o inside the plane. That is easy just:
o = p0; // any point from the polygon
u = p1-p0; // any edge of polygon
u /= |u|; // normalize
v = p2-p1; // any other edge of polygon
v /= |v|; // normalize
for (;fabs(dot(u,v)>0.75;) // if too parallel
{
v=(p(1+rand(n-1))-p0); // chose random "edge"
v /= |v|; // normalize
}
v=cross(u,v); // make u,v perpendicular
v=cross(v,u); // and inside the plane
v /= |v|; // normalize just in case because of rounding the size might not be unit anymore
Now to convert point p(x,y,z) from 3D to 2D (x,y) just do:
x = dot(p-o,u);
y = dot(p-o,v);
to convert back to 3D:
p = o + x*u + y*v;
With this way of conversion the metrics is the same so the length of polygon edges and size of polygon will not change ...

Inverse Camera Intrinsic Matrix for Image Plane at Z = -1

A similar question was asked before, unfortunately I cannot comment Samgaks answer so I open up a new post with this one. Here is the link to the old question:
How to calculate ray in real-world coordinate system from image using projection matrix?
My goal is to map from image coordinates to world coordinates. In fact I am trying to do this with the Camera Intrinsics Parameters of the HoloLens Camera.
Of course this mapping will only give me a ray connecting the Camera Optical Centre and all points, which can lie on that ray. For the mapping from image coordinates to world coordinates we can use the inverse camera matrix which is:
K^-1 = [1/fx 0 -cx/fx; 0 1/fy -cy/fy; 0 0 1]
Pcam = K^-1 * Ppix;
Pcam_x = P_pix_x/fx - cx/fx;
Pcam_y = P_pix_y/fy - cy/fy;
Pcam_z = 1
Orientation of Camera Coordinate System and Image Plane
In this specific case the image plane is probably at Z = -1 (However, I am a bit uncertain about this). The Section Pixel to Application-specified Coordinate System on page HoloLens CameraProjectionTransform describes how to go form pixel coordinates to world coordinates. To what I understand two signs in the K^-1 are flipped s.t. we calculate the coordinates as follows:
Pcam_x = (Ppix_x/fx) - (cx*(-1)/fx) = P_pix_x/fx + cx/fx;
Pcam_y = (Ppix_y/fy) - (cy*(-1)/fy) = P_pix_y/fy + cy/fy;
Pcam_z = -1
Pcam = (Pcam_x, Pcam_y, -1)
CameraOpticalCentre = (0,0,0)
Ray = Pcam - CameraOpticalCentre
I do not understand how to create the Camera Intrinsics for the case of the image plane being at a negative Z-coordinate. And I would like to have a mathematical explanation or intuitive understanding of why we have the sign flip (P_pix_x/fx + cx/fx instead of P_pix_x/fx - cx/fx).
Edit: I read in another post that the thirst column of the camera matrix has to be negated for the case that the camera is facing down the negative z-direction. This would explain the sign flip. However, why do we need to change the sign of the third column. I would like to have a intuitive understanding of this.
Here the link to the post Negation of third column
Thanks a lot in advance,
Lisa
why do we need to change the sign of the third column
To understand why we need to negate the third column of K (i.e. negate the principal points of the intrinsic matrix) let's first understand how to get the pixel coordinates of a 3D point already in the camera coordinates frame. After that, it is easier to understand why -z requires negating things.
let's imagine a Camera c, and one point B in the space (w.r.t. the camera coordinate frame), let's put the camera sensor (i.e. image) at E' as in the image below. Therefore f (in red) will be the focal length and ? (in blue) will be the x coordinate in pixels of B (from the center of the image). To simplify things let's place B at the corner of the field of view (i.e. in the corner of the image)
We need to calculate the coordinates of B projected into the sensor d (which is the same as the 2d image). Because the triangles AEB and AE'B' are similar triangles then ?/f = X/Z therefore ? = X*f/Z. X*f is the first operation of the K matrix is. We can multiply K*B (with B as a column vector) to check.
This will give us coordinates in pixels w.r.t. the center of the image. Let's imagine the image is size 480x480. Therefore B' will look like this in the image below. Keep in mind that in image coordinates, the y-axis increases going down and the x-axis increases going right.
In images, the pixel at coordinates 0,0 is in the top left corner, therefore we need to add half of the width of the image to the point we have. then px = X*f/Z + cx. Where cx is the principal point in the x-axis, usually W/2. px = X*f/Z + cx is exactly as doing K * B / Z. So X*f/Z was -240, if we add cx (W/2 = 480/2 = 240) and therefore X*f/Z + cx = 0, same with the Y. The final pixel coordinates in the image are 0,0 (i.e. top left corner)
Now in the case where we use z as negative, when we divide X and Y by Z, because Z is negative, it will change the sign of X and Y, therefore it will be projected to B'' at the opposite quadrant as in the image below.
Now the second image will instead be:
Because of this, instead of adding the principal point, we need to subtract it. That is the same as negating the last column of K.
So we have 240 - 240 = 0 (where the second 240 is the principal point in x, cx) and the same for Y. The pixel coordinates are 0,0 as in the example when z was positive. If we do not negate the last column we will end up with 480,480 instead of 0,0.
Hope this helped a little bit

How to find the pixel location of a GPS point in an orthoimage with known orientation and GPS location

I have a problem where I need to determine whether a given latitude, longitude GPS-point is in a given orthoimage (approx. 1 hectare area) with known real-world orientation and GPS-location (corresponding to the center of image).
That is, given a GPS-point P, I need to determine:
Is point P located in the orthoimage, and if yes,
What is the pixel location of point P in the orthoimage.
My question is summarized in the following image:
As you can see in the image, I know the GPS-coordinates of the image (center) and where North is located with respect to the image. Also, I know how many centimeters in the ground each pixel corresponds to.
My question is: What would be an efficient and smart way to achieve the goals in my problem?
One approach I had in mind was to solve a linear mapping between the GPS- and pixel-points and then use this mapping to answer both problems 1-2. I thought this could be a reasonable approach, even though the earth has curvature and the GPS-coordinates are (I'd say) more like a parabolic function of the pixel coordinates, since the distances are very small (one image is an approximately 1 hectare area) I could assume without significant loss in accuracy that the GPS-coordinates change locally linearly w.r.t pixel coordinates.
What do you think? Thank you.
Update:
The orthophotos have been taken with a Phantom 4 Pro drone with gimbal camera system.
I thought about one possibility myself, not perfect but it's a start:
The following information is given:
a rectangular orthoimage Img, Yaw of the image (that is, how many degrees the image is facing away from north), pix_size pixel size in the ground (centimeters/pixel).
The problem is: Given an arbitrary GPS-point p = (lat, long), determine the pixel location of p in Img.
Denote c = (latc, longc) and cp = (x,y) as the GPS- and pixel-coordinates of the center point of Img.
Determine how much we must move along North-South and West-East axes to get from c to p. Let lat_delta = latc-lat and long_delta = longc-long. If lat_delta < 0 -> p is more in north than c, otherwise p is more in south than c. The same goes analoguously for long_delta.
> if lat_delta < 0:
> pN = [latc + abs(lat_delta), longc]
> else:
> pN = [latc - abs(lat_delta), longc]
>
> if lat_long < 0:
> pE = [latc, longc + abs(long_delta)]
> else:
> pE = [latc, longc - abs(long_delta)]
Now the points c, p, pN and pE form a "spherical" right triangle (I think I could safely assume it to be planar because the orthophoto describes max 1 hectare area). So the Pythagorean theorem applies sufficiently enough for my purposes.
Next, I calculate the ground distances dN = Haversine(c,pN) and dE = Haversine(c, pE), which tell me how much in ground distance I must move in North-South and West-East axes in order to get from c to p.
Now I will apply a rotation matrix R(-Yaw) to vectors n = [0,1] and e = [1,0], which represent the upwards and right vectors in my pixel coordinate system. So I get nr = R(-Yaw)*n and er = R(-Yaw)*e where nr is a unit pixel vector pointing towards North in the image and er is similarly a unit pixel vector pointing towards East in the image.
Next, I calculate the ratios mN = dN/pix_size and mE = dE/pix_size (the factors also need to take into account the +- direction). Now I calculate the pixel location of p by:
pp = cp + mN*nr + mE*er,
where I can now easily check if the pixel values pp are within the bounds of the image Img.
Of course this method does not work in a general large area case and needs to be refined for this purpose.

Determine whether the direction of a line segment is clockwise or anti clockwise

I have a list of 2D points (x1,y1),(x2,y2)......(Xn,Yn) representing a curved segment, is there any formula to determine whether the direction of drawing that segment is clockwise or anti clockwise ?
any help is appreciated
Alternately, you can use a bit of linear algebra. If you have three points a, b, and c, in that order, then do the following:
1) create the vectors u = (b-a) = (b.x-a.x,b.y-a.y) and v = (c-b) ...
2) calculate the cross product uxv = u.x*v.y-u.y*v.x
3) if uxv is -ve then a-b-c is curving in clockwise direction (and vice-versa).
by following a longer curve along in the same manner, you can even detect when as 's'-shaped curve changes from clockwise to anticlockwise, if that is useful.
One possible approach. It should work reasonably well if the sampling of the line represented by your list of points is uniform and smooth enough, and if the line is sufficiently simple.
Subtract the mean to "center" the line.
Convert to polar coordinates to get the angle.
Unwrap the angle, to make sure its increments are meaningful.
Check if total increment is possitive or negative.
I'm assuming you have the data in x and y vectors.
theta = cart2pol(x-mean(x), y-mean(y)); %// steps 1 and 2
theta = unwrap(theta); %// step 3
clockwise = theta(end)<theta(1); %// step 4. Gives 1 if CW, 0 if ACW
This only considers the integrated effect of all points. It doesn't tell you if there are "kinks" or sections with different directions of turn along the way.
A possible improvement would be to replace the average of x and y by some kind of integral. The reason is: if sampling is denser in a region the average will be biased towards that, whereas the integral wouldn't.
Now this is my approach, as mentioned in a comment to the question -
Another approach: draw a line from starting point to ending point. This line is indeed a vector. A CW curve has most of its part on RHS of this line. For CCW, left.
I wrote a sample code to elaborate this idea. Most of the explanation can be found in comments in the code.
clear;clc;close all
%% draw a spiral curve
N = 30;
theta = linspace(0,pi/2,N); % a CCW curve
rho = linspace(1,.5,N);
[x,y] = pol2cart(theta,rho);
clearvars theta rho N
plot(x,y);
hold on
%% find "the vector"
vec(:,:,1) = [x(1), y(1); x(end), y(end)]; % "the vector"
scatter(x(1),y(1), 200,'s','r','fill') % square is the starting point
scatter(x(end),y(end), 200,'^','r','fill') % triangle is the ending point
line(vec(:,1,1), vec(:,2,1), 'LineStyle', '-', 'Color', 'r')
%% find center of mass
com = [mean(x), mean(y)]; % center of mass
vec(:,:,2) = [x(1), y(1); com]; % secondary vector (start -> com)
scatter(com(1), com(2), 200,'d','k','fill') % diamond is the com
line(vec(:,1,2), vec(:,2,2), 'LineStyle', '-', 'Color', 'k')
%% find rotation angle
dif = diff(vec,1,1);
[ang, ~] = cart2pol(reshape(dif(1,1,:),1,[]), reshape(dif(1,2,:),1,[]));
clearvars dif
% now you can tell the answer by the rotation angle
if ( diff(ang)>0 )
disp('CW!')
else
disp('CCW!')
end
One can always tell on which side of the directed line (the vector) a point is, by comparing two vectors, namely, rotating vector [starting point -> center of mass] to the vector [starting point -> ending point], and then comparing the rotation angle to 0. A few seconds of mind-animating can help understand.

How to scale a torus and keep the radius of tube unchanged?

If I have a torus defined like this.
u,v are in the interval [0, 2π),
R is the distance from the center of the tube to the center of the torus,
r is the radius of the tube.
I want to enlarge the R and keep r unchanged, how to use transformation matrix to do it, or is it possible?
The transformation you're looking for is not linear, so it can't be represented by a matrix.
To tell that it's not linear, imagine the torus centered at the origin laid out parallel to the xy-plane. The positive x-axis intersects the torus at two points; let's call the one closer to the origin a and the farther one b.
After you apply your transformation, we expect that a and b both moved away from the origin by the same amount. But since b is a multiple of a, this is impossible:
b = c*a
f(b) - b = f(c*a) - c*a
= c*f(a) - c*a
= c*( f(a) - a )
The same multiple that relates a and b also relates how far a moved compared to b.
You will have the same problem even if you project the torus onto a plane.

Resources