finding the intersection of a line with an arbitrary surface? - matlab

I am using ray tracing and at the beginning I assumed a plane surface so I used the equation of the plane surface which is :
Ax + BY + CZ +d = 0
while A,B and C are the component of the normal vector of the Plane Normal = [A B C]
and using the Ray equation : Ray = Source + t*Direction
And then solve it for t and I can find the intersection points.
My question now that I have function in matlab to read the surface of the object but the object may not be plane surface and I am getting the data of the surface [X Y Z] of the surface but I don't know which equation should I use to find t and then the intersection point. And I even have a function to give me the normal vector at each point
If you can edit the tags the get the right ones please do it.

It might not be a plane, but you can always calculate a normal vector at each point. You'll just have to work harder to do it. Take two partial derivatives in planar coordinates, cross those vectors, and that's the normal at the point.

If your surface is defined as a height Z on a some X-Y grid, you can solve it easily using fzero. This would exclude some complex shapes, but might work for standard optics problems like a ray hitting a lens. Assume that X, Y and Z are 2-d matrices with the same shape. You can then do a 2d interpolation like
z_interp = interp2(X,Y,Z,x_interp,y_interp)
If this is not the case, you should try to define your own function that can calculate z based on x and y.
For the line, we have
x_ray = x_source + t * x_dir
y_ray = y_source + t * y_dir
z_ray = z_source + t * z_dir
So you can now define a function that calculates the height above the surface as a function of t as
height_above_plane = #(t) z_source + t * z_dir - interp2(X, Y, Z, ...
x_source + t*x_dir, y_source + t*y_dir)
Note that this might not be the shortest distance from the point to the plane, it is just the height measured along the z-direction. The time the ray hits the surface can now be found by searching for the t for which the height is zero. This can be done for arbitrary functions using fzero:
t_intercept = fzero(height_above_plane, 0);
This should work well for simple cases where the function defining the surface is relatively smooth and the ray crosses the surface only once. It might be possible to transform cases with more complex geometry into such a simple case.

If you can get the X Y Z of the surface and you said you can get the normal vector in each point so what is your problem now?
The X Y Z of the surface are the intersection points and if you have the normal vector in each point so you can calculate whatever you want ( the reflected or the refracted rays).
I think you have no troubles at all

Related

Calculate vertex normals for parametrically morphed sphere

I want to morph sphere, using the following equation:
R=1+k*(cos(4*elev)+sin(4*az)),
Spherical coordinates elev and az are transferred as gl_Vertex. The problem is to calculate normals for such morphing. I may calculate them, just shifting az and elev a bit, the obtain 2 more "virtual" vertices and use standard approach with cross-product, but it looks rather ugly and expensive approach.
Is their are any way to calculate normals also parametrically for such kind of morphing?
UPDATE:
Thanks to #meowgoesthedog, but I still have problems. My implementation of this formula (code below) did not work:
Am i correct and it should be:
cos(theta)*(k*(cos(4*theta)+sin(4*phi))+1) or cos(theta*(k*(cos(4*theta)+sin(4*phi))+1))?
Are normals calculated in cartesian coordinate system?
My code in Matlab:
close all
clear all
N=100;
phi_range=linspace(-pi,pi,N+2);
theta_range=linspace(-pi/2,pi/2,N);
phi_range([1,end])=[];
k=6;
% generate morphed sphere
PHI=repmat(phi_range,N,1);
THETA=repmat(theta_range',1,N);
R=1+k*cos(4*THETA)+k*sin(4*PHI);
% convert to cartesian coordinates
[X,Y,Z]=sph2cart(PHI,THETA,R);
%% meowgoesthedog formula
S=k.*(cos(4.*THETA)+sin(4.*PHI))+1;
V1_x = cos(PHI).*(cos(THETA).*S-4.*k.*sin(THETA).*sin(4.*THETA));
V1_y = sin(PHI).*(cos(THETA).*S-4.*k.*sin(THETA).*sin(4.*THETA));
V1_z = -sin(THETA).*S-4.*k.*sin(4.*THETA).*cos(THETA);
V2_x = sin(THETA).*(4.*k.*cos(PHI).*cos(4.*PHI)-sin(PHI).*S);
V2_y = sin(THETA).*(4.*k.*sin(PHI).*cos(4.*PHI)+cos(PHI).*S);
V2_z = 4.*k.*cos(THETA).*cos(4.*THETA);
V1=cat(3,V1_x,V1_y,V1_z);
V2=cat(3,V2_x,V2_y,V2_z);
Normals=cross(V1,V2);
% normalize
Normals=Normals./sqrt(sum(Normals.^2,3));
%% plot and compare results:
hold all
surfnorm(X,Y,Z,'EdgeAlpha',0.5)
quiver3(X,Y,Z,Normals(:,:,1),Normals(:,:,2),Normals(:,:,3),'m')
On figures below red - correct normals, magenta which I calculate.
We can compute an analytical expression for the normal using differential geometry. Let's first state the form of the Cartesian parametric coordinate:
Locally at any point on the surface, there is a 2D coordinate system spanned by the unit vectors in the directions of increasing θ and φ.
These vectors are given by:
The normal is simply given by the cross-product of these two vectors (un-normalized):
After some very tedious algebra we obtain:
(The formula becomes too long to legibly display past this point, and probably not as efficient to evaluate either.)
EDIT
It appears that I have used the conventional definition of θ (angle from the +Z axis) instead of Matlab's elev. Redefining the equations this would give:
Where ψ = ½π - θ is the elevation.

find area of 3D polygon

Given a matrix nx3 that represents n points in 3D space. All points lie on a plane. The plane is given by its normal and a point lying on it. Is there a Matlab function or any Matlabby way to find the area directly from the matrix?
What i was trying to do is write a function that first computes the centroid,c, of the n-gon. Then form triangles : (1,2,c),(2,3,c),...,(n,1,c). Compute their area and sum up. But then i had to organise the polygon points in a cyclic order as they were unordered which i figured was hard. Is there a easy way to do so?
Is there a easier way in Matlab to just call some function on the matrix?
Here is perhaps an easier method.
First suppose that your plane is not parallel to the z-axis.
Then project the polygon down to the xy-plane simply by removing the 3rd coordinate.
Now compute the area A' in the xy-plane by the usual techniques.
If your plane makes an angle θ with the xy-plane, then your 3D
area A = A' / cos θ.
If your plane is parallel to the z-axis, do the same computation
w.r.t. the y-axis instead, projecting to the xz-plane.
To project from 3D to the plane normal to N, take some non-parallel vector A and compute the cross products U = N x A and V = N x U. After normalizing U and V, the dot products P.U and P.V give you 2D coordinates in the plane.
Joseph's solution is even easier (I'd recommend to drop the coordinate with the smallest absolute cosine).
You said the points all lie on a plane and you have the normal. You should then be able to reproject the 3-D points into 2-D coordinates in a new 2-D basis. I am not aware of a canned function in Matlab to do this , but coding it should not be difficult, this answer from Math.SE and this Matlab Central post should help you.
If you already solved the problem of finding the coordinates of the points in the 2-D plane they are in, you could use the Matlab boundary or convex hull function to compute the area of the boundary or convex hull enclosing the points.
[k,v]= boundary(x,y)
or
[k,v] =convhull(x,y)
where k is the vector of indices into points x,y, that define the boundary or convex hull, v is the area enclosed, and x, y are vectors of the x and y coordinates of your points.
What you were describing with trying to find triangles with the points sounds like a first attempt toward Delaunay triangulation. I think more recent versions of Matlab have functions to do Delaunay triangulation as well.

Matlab's curl function and its limitation?

Iam beginner to matlab. Still learning it.Recently i have been asked to compute curl of three velocity components and plot its contour w.r.t circumferential angle along x-axis and radius along y-axis. The data u,v and w is pre-calculated by me as follows
u = V * Cos(beta) * cos(alpha); % V is velocity in m/s and alpha,beta are angles in radians
similarly
v = V * cos(beta) * sin(alpha);
w = V * sin(alpha)
Someone recently commented out saying that to enable mat lab's curl functionality my u,v and w data should be in Cartesian coordinate. I relied saying that though my initial data is in spherical coordinates(V,alpha,beta) but iam using coordinate conversion on u,v and w and transforming my data to Cartesian coordinate.
He further replied saying that "not only u,v,w should be Cartesian but its relative data x,y,z should also need to be Cartesian coordinate"
I dint get it. Can anyone say what he was trying to say or if i can use the curl functionality in matlab
I shall be gretful for your help and answer
I have not tried the function, but as far as it concerns the coordinates u, v, w defines the force for each gridspace from x, y, z. However, the help on mathworks homepage says that x, y, z
must be monotonic, but do not need to be uniformly spaced.
This may be a trouble for spherical coordinates, when transformed to cartesians. I assume that weakly monotonic for any coordinate (but not all of them) would work, but spherical coordinates does not apply for that. What you could try is to transform the coordinates but make sure that the grid is monotonic. I mean, you make sure the grid in Cartesian coordinates is kept monotonic instead of the spherical.
So the answer is then more explicitly x, y, z, need to be non decreasing with at least 1 coordinate at the time which is increasing, but the force of each point can have the value of spherical coordinate transformed to its corresponding Cartesian value.
Except for this I would like to advise you to use the formal definition of spherical coordinates, which defines alpha as the angle from z to the xy-plane (alpha = 0 is the z-axis). I would also recommend you to use the more common coordinate names. r, phi and theta.

Defining plane induced homography for image manipulation

I am trying to artificially manipulate a 2D image using a rigid 3D transformation (T). Specifically, I have an image and I want to transform using T it to determine the image if captured from a different location.
Here's what I have so far:
The problem reduces to determining the plane-induced homography (Hartley and Zisserman Chapter 13) - without camera calibration matrices this is H = R-t*n'/d.
I am unsure, however, how to define n and d. I know that they help to define the world plane, but I'm not sure how to define them in relation to the first image plane (e.g. the camera plane of the original image).
Please advise! Thanks! K
Not sure what you mean by "first image plane": the camera's?
The vector n and the scalar d define the equation of the plane defining the homography:
n X + d = 0, or, in coordinates, n_x * x + n_y * y + n_z * z + d = 0, for every point X = (x, y, z) belonging to the plane.
There are various ways to estimate the homography. For example, you can map a quadrangle on the plane to a rectangle of known aspect ratio.
Or you can estimate the locations of vanishing points (this comes handy when you have, say, an image of a skyscraper, with nice rows of windows). In this case, if p and q are the homogeneous coordinates of the vanishing points of two orthogonal lines on a plane in the scene, then normal to the plane in camera coordinates is simply given by (p X q) / (|p| |q|)

Plotting characteristics of antenna radiation in matlab

I need to plot this function
theta = (-pi:0.01:pi);
f = 3*10^9;
c = 299792458;
da = 2;
Here's my code, but I'm not sure it's correct. I dont know where exactly dot mark should be. How to set X-Axis in degress?
beta = (2*pi*f)/c;
const= (da*beta)/2;
j= (cos(theta)+1).*(besselj(1,const*sin(theta))./(const*sin(theta)));
My another question is how to plot this function in polar coordinates.
I made something like this.
polar(theta,j);
Is it possible to rotate that function(by y-axis) to get 3D plot?
Things are quite right to me, although I wouldn't use the symbol j as a variable because (as i does) it is the symbol for the imaginary unit (sqrt(-1)). Doing so you are overriding it, thus things will work until you don't need complex numbers.
You should use element-wise operations such as (.*) when you aim at combining arrays entries element by element, as you correctly did to obtain F(\theta). In fact, cos(theta) is the array of the cosines of the angles contained in theta and so on.
Finally, you can rotate the plot using the command Rotate 3D in the plot window. Nonetheless, you have a 2D curve (F(\theta)) therefore, you will keep on rotating a 2D graph obtaining some kind of perspective view of it, nothing more. To obtain genuine information you need an additional dependent variable (Or I misunderstood your question?).
EDIT: Now I see your point, you want the Surface of revolution around some axis, which I suppose by virtue of the symmetry therein to be theta=0. Well, revolution surfaces can be obtained by a bit of analytic geometry and plotted e.g. by using mesh. Check this out:
% // 2D polar coordinate radius (your j)
Rad= (cos(theta)+1).*(besselj(1,const*sin(theta))./(const*sin(theta)));
Rad = abs(Rad); % // We need its absolute value for sake of clarity
xv = Rad .* cos(theta); % // 2D Cartesian coordinates
yv = Rad .* sin(theta); % // 2D Cartesian coordinates
phi = -pi:.01:pi; % // 3D revolution angle around theta = 0
% // 3D points of the surface
xf = repmat(xv',size(phi));
yf = yv' * cos(phi);
zf = yv' * sin(phi);
mesh(xf,yf,zf)
You can also add graphics effects
this is done via
mesh(xf,yf,zf,'FaceColor','interp','FaceLighting','phong')
camlight right
and a finer angular discretization (1e-3).