Ray - plane intersection - raytracing

I have the following problem that I am unable to solve, even after a long search on the internet.
How calculates the intersection of the plane in ray?
The plane is described by four points:
A (ax, ay, 0)
B (bx, by, 0)
C (cx, cy, 0)
D (dx, dy, 0)
Ray have:
Vector3f origin;
Vector3f direction;
And now, i want write a method for checking HIT.
Could someone show me a solution?
public Boolean checkHit(Ray myRay){
.
.
.
}
Thank you

A plane can be defined by a unit normal vector (nx,ny,nz) and a scalar distance from the origin d such that the equation of the plane is nx*x+ny*y+nz*z=d. You need to get the plane from 3 points to this format in order to proceed. If you don't know how you can look up finding a plane from three points.
Now the line can be specified by a unit direction vector (ex,ey,ez) and some point along the line (rx,ry,rz)
Find the product s=(nx*ex+ny*ey+nz*ez). If it is zero then there is no intersection
Find the distance of the intersection to the point on the line t=(d-(nx*rx+ny*ry+nz*rz))/s
The intersection point is at c=(rx+ex*t, ry+ey*t, rz+ez*t)

Related

How to distinguish internal and external face of polygon

So I have a set of points making up a simple polygon
points = [(x0, y0), (x1, y1), ..., (xn, yn)]
The polygon may be concave or convex, both cases must be handled.
Next I create two arcs for each line by treating the arc between point A-B as different from the arc between point B-A. Next I create paths from these points by always choosing the closest counter-clockwise arc. So one path goes clockwise and one counter-clockwise: [(x0, y0), (x1, y1), ... , (xn, yn)] and [(xn, yn), (xn-1, yn-1), ... , (x0, y0)]
By traversing these arcs how do I know if the arcs are creating an internal face or an external face?
For example, in the two polygons below the same orange line is used on two different polygons. In the first polygon the top orange arc is in the internal face (pointing inwards) while in the other polygon the top orange arc is in the external face (pointing outwards).
My question arose from the answer by #HEKTO in this post: How to find all the polygonal shapes of given the vertices?.
Use Green's theorem. Iterate over the points and compute the integral, then check the sign. Like this:
decimal sum = 0.0;
for(int current = 0; current < points.length; current++)
{
int next = current + 1;
if (next == points.length)
next = 0;
sum += (points[this].y + point[next].y) * (point[next].x - point[this].x);
}
Check the sign of sum to find out whether the winding is clockwise or counter-clockwise. Which is which will depend on which direction the Y axis increases in.
Note that if you were trying to compute the area of the polygon you would multiply the Y part of the equation by 0.5, but since you're only interested in the sign of the result you don't need to.

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.

Normal of a 3D tangent

So I have 3 points in a 3D space with a curve passing through the points. I have found the tangent of the point in the middle by averaging the two points either side of it, but I want to find the Normal at the point in the middle. How would I do this without knowing the equation of the line?
`P(1) = (0,1,0)
P(2) = (2,2,2)
p(3) = (4,4,4)
Tangent at P(2) = (4,3,4)`
Thanks!
A = P2 - P1 ... vector between 2 points on the curve (one is the middle point .. P2)
normal = A x tangent
but as MBo pointed out there are infinite number of normals (all are perpendicular to the curve lying on the same plane)
above equation gives one perpendicular to curve and to that A vector

Smallest sphere to encapsulate a triangle in 3D?

At first I figured you sum the vertices and scale by 1/3 to find the origin then take the largest distance from the vertex to the origin. This results in a sphere that contains the triangle, but it isn't necessarily the smallest.
Is there a known method for determining the smallest sphere to fully encapsulate an arbitrary triangle in 3D?
Used the answers here and wikipedia to come up with something in c++ that works for me, I hope this helps someone!
static Sphere makeMinimumBoundingSphere(const Vec3 &p1, const Vec3 &p2, const Vec3 &p3) {
Sphere s;
// Calculate relative distances
float A = (p1 - p2).distance();
float B = (p2 - p3).distance();
float C = (p3 - p1).distance();
// Re-orient triangle (make A longest side)
const Vec3 *a = &p3, *b = &p1, *c = &p2;
if (B < C) swap(B, C), swap(b, c);
if (A < B) swap(A, B), swap(a, b);
// If obtuse, just use longest diameter, otherwise circumscribe
if ((B*B) + (C*C) <= (A*A)) {
s.radius = A / 2.f;
s.position = (*b + *c) / 2.f;
} else {
// http://en.wikipedia.org/wiki/Circumscribed_circle
precision cos_a = (B*B + C*C - A*A) / (B*C*2);
s.radius = A / (sqrt(1 - cos_a*cos_a)*2.f);
Vec3 alpha = *a - *c, beta = *b - *c;
s.position = (beta * alpha.dot(alpha) - alpha * beta.dot(beta)).cross(alpha.cross(beta)) /
(alpha.cross(beta).dot(alpha.cross(beta)) * 2.f) + *c;
}
return s;
}
The smallest sphere to encapsulate the triangle is just the circumsribed cirlce extended into the third dimension.
Update: Scratch that, of course it isn't. It's the sphere that you get if you rotate the smallest circle around its diameter. The reason being that for any containing sphere that has its origin out of the plane of the triangle there is a smaller one that has its origin on the plane (by projecting the origin orthogonally onto the plane).
You are trying to find the smallest enclosing ball MB(P) of a point set P, so you could use an algorithm as implemented here https://github.com/hbf/miniball. (Note: "ball" and "sphere" are synonyms in this context.)
However, this is overkill in your case, since the point set P at hand contains exactly 3 points (the vertices of the triangle). In this particular case, you can use the fact that the smallest enclosing ball MB(P) of P={p,q,r} equals either:
B(p,q) if r is contained in B(p,q), or
B(p,r) if q is contained in B(p,r), or
B(q,r) if p is contained in B(q,r), or
B(p,q,r) otherwise.
Here, B(x,y) is the smallest ball containing the points x,y and B(x,y,z) is the smallest ball containing the points x,y,z on the boundary. B(x,y) and B(x,y,z) can be computed by solving a linear system of equations.
Note: I am the author of https://github.com/hbf/miniball.
Assuming that the sphere is simply a trivial extension of a circle (2-D) into 3-D (using both the same center point and the same radius), I believe what you are looking for is called circumscribed circle of a triangle.
Apparently I didn't consider the case of an obtuse triangle which if you have the vertices (points) of the triangle on the circle, then the circle is not the smallest bounding circle (and thus smallest bounding sphere).
Now I believe that you are looking for the minimum bounding sphere, which is a known and studied problem in mathematics, and computer graphics. "Smallest Enclosing Circle Problem" is a description of an O( n^{2} ) and a linear O(n) algorithms.
And as far as I know the minimal bounding circle does produce the minimal bounding sphere, using the same parameters (center point and radius) projected into three dimensions.

Best way to find a point on a circle closest to a given point

Given a point (pX, pY) and a circle with a known center (cX,cY) and radius (r), what is the shortest amount of code you can come up with to find the point on the circle closest to (pX, pY) ?
I've got some code kind of working but it involves converting the circle to an equation of the form (x - cX)^2 + (y - cY)^2 = r^2 (where r is radius) and using the equation of the line from point (pX, pY) to (cX, cY) to create a quadratic equation to be solved.
Once I iron out the bugs it'll do, but it seems such an inelegant solution.
where P is the point, C is the center, and R is the radius, in a suitable "mathy" language:
V = (P - C); Answer = C + V / |V| * R;
where |V| is length of V.
OK, OK
double vX = pX - cX;
double vY = pY - cY;
double magV = sqrt(vX*vX + vY*vY);
double aX = cX + vX / magV * R;
double aY = cY + vY / magV * R;
easy to extend to >2 dimensions.
i would make a line from the center to the point, and calc where that graph crosses the circle oO i think not so difficult
Solve it mathematically first, then translate into code. Remember that the shortest line between a point and the edge of a circle will also pass through its center (as stated by #litb).
The shortest distance point lies at the intersection of circumference and line passing through the center and the input point. Also center, input and output points lie on a straight line
let the center be (xc, yc) and shortest point from input (xi, yi) be (x,y) then
sqrt((xc-x)^2 + (yc-y)^2) = r
since center, input and output points lie on a straight line, slope calculated between
any of two of these points should be same.
(yc-yi)/(xc-xi) = (y-yc)/(x-xc)
4.solving equations 2&3 should give us the shortest point.
Trig functions, multiply by r, and add pX or pY as appropriate.
Treat the centre of the circular as your origin, convert the co-ordinates of (pX, pY) to polar co-ordinates, (theta, r') replace r' with the original circle's r and convert back to cartesian co-ordinates (and adjust for the origin).
You asked for the shortest code, so here it is. In four lines it can be done, although there is still a quadratic.
I've considered the point to be outside the circle.
I've not considered what happens if the point is directly above or below the circle center, that is cX=pX.
m=(cY-pY)/(cX-pX); //slope
b=cY-m*cX; //or Py-m*Px. Now you have a line in the form y=m*x+b
X=( (2mcY)*((-2*m*cY)^2-4*(cY^2+cX^2-b^2-2*b*cY-r^2)*(-1-m^2))^(1/2) )/(2*(cY^2+cX^2-b^2-2*bc*Y-r^2));
Y=mX+b;
1] Get an equation for a line connecting the point and the circle center.
2] Move along the line a distance of one radius from the center to find the point on the circle. That is: radius=a^2+b^2 which is: r=((cY-Y)+(cX-X))^(1/2)
3] Solve quadratically. X=quadratic_solver(r=((cY-Y)+(cX-X))^(1/2),X) which if you substitute in Y=m*X+b you get that hell above.
4] X and Y are your results on the circle.
I am rather certain I have made an error somewhere, please leave a comment if anyone finds something. Of course it is degenerate, one answer is furthest from your point and the other is closest.
Easy way to think about it in terms of a picture, and easy to turn into code: Take the vector (pX - cX, pY - cY) from the center to the point. Divide by its length sqrt(blah blah blah), multiply by radius. Add this to (cX, cY).
Here is a simple method I use in unity... for the math kn00bs amongst us.
Its dependent on the transform orientation but it works nicely. I am doing a postion.z = 0 but just fatten the axis of the 2d circle you are not using.
//Find closest point on circle
Vector3 closestPoint = transform.InverseTransformPoint(m_testPosition.position);
closestPoint.z = 0;
closestPoint = closestPoint.normalized * m_radius;
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.TransformPoint(closestPoint), 0.01f);

Resources