Calculate volume of hollow tilted cylinder inside cube, without a grid - matlab

I have a hollow cylinder with inner radius r1 and outer radius r2. This cylinder is tilted from the Z axis towards the X axis, then rotated around the Z axis and then translated along X and along Y. I also have a cube between a range of X and Y values. I then want to calculate how large a volume of the hollow cylinder is inside the cube.
%set variables
r1 = 0.9; r2 = 1.0;
z1 =-1.0; z2 = 1.0;
beta = pi/4; gamma = pi/8;
%create inner surface
[X,Y,Z] = cylinder(r1, 100);
%outer surface
[Xx,Yy,Zz] = cylinder(r2, 100);
%fix coordinates
X = [X,Xx]; Y = [Y,Yy]; Z = [Z,Zz];
Z(1,:) = z1; Z(2,:) = z2;
%elongate in first rotation direction
X = X/cos(beta);
%shift top and bottom accordingly
X(1,:) = X(1,:) + z2/tan(beta);
X(2,:) = X(2,:) + z1/tan(beta);
%also perform another rotation in XY plane
Xnu = X*cos(gamma) + -Y*sin(gamma);
Y = X*sin(gamma) + Y*cos(gamma);
X = Xnu;
%translation not included for this example
surf(X,Y,Z); axis equal
%try to make a cube from its nodes/corners
ix=-1;iy=-1;dx=0.5;dy=dx;
[X,Y,Z] = ndgrid( ix*dx+[-dx/2, dx/2] , iy*dy+[-dy/2, dy/2] , [z1, z2] );
X = reshape(X, 2, []);Y = reshape(Y, 2, []);Z = reshape(Z, 2, []);
%failed
surf(X,Y,Z); axis equal
The hollow cylinder seems OK. Just no 'cap' on the top of the edge.
The cube looks nothing like a cube, but at least the volume between the corners should be correct.
My question is, how do I get the intersection of these two shapes and then calculate the volume?
I actually need to iterate over many of these tubes and cubes, but once I have this single case fixed then it should be easy. Each cube represents a measured pixel from an experiment and each hollow cylinder a physical object that was in the experiment. When simulating this on a meshgrid itself I encounter memory issues very fast.

Related

Adding mesh to enclosed semicircle MATLAB

I am currently trying to produce a 2D heat transfer analysis on an alloy which has a shape of a semicircle, (and then introduce a heat source on this shape). I found myself unable to produce a mesh for that specific shape, the code below shows what I have done up until now, if anyone could possibly point me in the right direction it would be greatly appreciated!
initially I set up the grid parameters as follows:
%-------------------GRID SETTINGS----------------------%
Sx = 10; %physical width
Sy = 10; %physical height
Nx = 100; %number of points x-axis
Ny = round(Nx*Sy/Sx); %number of points y-axis
Nt = 500;
%-------------------GRID RESOLUTION---------------------%
dx = Sx/(Nx);
dy = Sy/(Ny);
and worked on creating the shape of an enclosed semicircle as below:
%---------------------SHAPE CREATION--------------------%
r1 = 0.07; %radius 1, m
r2 = 5; %radius 2, m
phi = 0:0.01:pi;
x = r2*cos(phi); x = [x,x(1)]; %x coordinates
y = r1*sin(phi); y = [y,y(1)]; %y coordinates
[X, Y] = meshgrid(x,y);
I'd use polar coordinates for your mesh and then visualize the results in cartesian coordinates. Check out the example below, hope this gives you a starting point (not really sure why you applied two different radius (r1, r2) to your x,y coordinates - so I assumed you have a minimal and maximal radius).
Nx = 100;
r1 = 1; %radius 1, m
r2 = 5; %radius 2, m
phi = 0:0.01:pi;
% generate mesh grid in polar coordinates
radius = linspace(r1, r2, Nx/2);
[Radius, Phi] = meshgrid(radius, phi);
heat = Radius.^2; % some "fake" heat data
% plot results (in cartesian coordinates)
mesh(Radius.*cos(Phi), Radius.*sin(Phi), heat)
axis equal
% top view
view([-0.2 90.0])

Graphing a Line given x,y, and z angle

I have this piece of MATLAB code that outputs x,y, and z angles and I would like draw a line using them. Can someone point me in the right direction on how to do this?
C = pi;
A = pi;
B = pi;
Z = [cos(C),-sin(C),0; sin(C),cos(C),0; 0,0,1];
X = [1,0,0;0,cos(A),-sin(A);0,sin(A),cos(A)];
Y = [cos(B),0,sin(B);0,1,0;-sin(B),0,cos(B)];
R =(X*Y)*Z;
yaw=atan2(R(2,1),R(1,1))
pitch=atan2(-R(3,1),sqrt(R(3,2)^2+R(3,3)^2))
roll=atan2(R(3,2),R(3,3))
X, Y, and Z are not angles, they are rotation matrices defined by the angles A, B, and C.
it's not clear what's the meaning of "draw a line using them", they are just used to rotate vectors in the 3D space.
here is an example of drawing a rotated vector with them:
% define rotation angles (around the axes)
C = pi/2;
A = pi/4;
B = pi/4;
% generate rotation matrices
Z = [cos(C),-sin(C),0; sin(C),cos(C),0; 0,0,1];
X = [1,0,0;0,cos(A),-sin(A);0,sin(A),cos(A)];
Y = [cos(B),0,sin(B);0,1,0;-sin(B),0,cos(B)];
R =(X*Y)*Z;
% generate a vector and rotate it
v = [1;1;1];
u = R*v;
% plot
quiver3(0,0,0,v(1),v(2),v(3));
hold on
quiver3(0,0,0,u(1),u(2),u(3));
xlim([-1 1]); ylim([-1 1]); zlim([-1 1])
axis square
legend('original','rotated')

Orienting 2D shape face with normal to 3D trajectory

I have line, or trajectory in 3D space. I also have a 2D shape. I want to take this shape and move it along the curve keeping the surface normal parallel to the tangent of the curve. Based on a post here I have successfully done this that produces something which 'looks right' for shapes with rotational symmetry like a circle. See the code and figure below for the example.
% create data
npts = 30;
tend = 8*pi;
t = linspace(0,tend,npts)';
z = linspace(-1,1,npts)';
omz = sqrt(1-z.^2);
x = cos(t).*omz;
y = sin(t).*omz;
scatter3 (x,y,z, 'x');
hold on
% fit 3 slms to data in each direction
xslm = slmengine (t, x, 'knots', ceil(npts/1.5));
yslm = slmengine (t, y, 'knots', ceil(npts/1.5));
zslm = slmengine (t, z, 'knots', ceil(npts/1.5));
% test points
tq = linspace(0,tend,200 * npts)';
dx = slmeval (t, xslm, 1, false);
dy = slmeval (t, yslm, 1, false);
dz = slmeval (t, zslm, 1, false);
quiver3(x,y,z,dx,dy,dz);
plot3 (slmeval(tq, xslm, 0, false), slmeval(tq, yslm, 0, false), slmeval(tq, zslm, 0, false));
hold off
axis equal
% The following taken from post on matlab central
%
% http://uk.mathworks.com/matlabcentral/newsreader/view_thread/159522
%
% P10 = P1-P0;
%
% P20 = P2-P0;
% N = dot(P10,P10)*P20-dot(P20,P20)*P10; % <-- Approx. tangent direction
R = 0.05;
P0 = [x,y,z];
N = [dx, dy, dz];
% circle points
% theta = linspace(0,2*pi).';
box_x = [ -R; R; R; -R; -R ];
box_y = [ -R/2; -R; R; R/2; -R/2 ];
for ind = 1:size(P0,1)
T = null(N(ind,:)).'; % Get two orthogonal unit vectors which are orthog. to N
% V = bsxfun ( #plus, ...
% R * ( cos(theta) * T(1,:) + sin(theta) * T(2,:) ), ...
% P0(ind,:) );
V = bsxfun ( #plus, ...
box_x * T(1,:) + box_y * T(2,:), ...
P0(ind,:) );
hold on
quiver3(P0(ind,1),P0(ind,2),P0(ind,3),T(1,1),T(1,2),T(1,3), 0.5, 'b');
quiver3(P0(ind,1),P0(ind,2),P0(ind,3),T(2,1),T(2,2),T(2,3), 0.5, 'b');
plot3(V(:,1),V(:,2),V(:,3));
hold off
end
Note that this code makes use of the Shape Language Modelling functions from the Matlab file exchange to make the curve and get it's tangent at various points, but this isn't crucial to the problem.
However, as you can see, the rotation of the shape flips as you move around the curve with this method. I need to keep the rotation of the shape consistent as I actually wish to sample values from scattered 3D data on the shape surface which represents the inside of a 'tube' or whatever the shape is.
So how can I control the orientation of my shape as I move along the curve?
You need 2 vectors and position! The tangent (you have it) and one vector to align to like up which must be not parallel to tangent. Then just construct 3D transform matrix use tangent as Z-axis and exploit the cross product to get the other two for example:
Up = (0,1,0)
Z = tangent/|tangent|
X = cross(Z,Up)
Y = cross(X,Z)
O = position
Position is just the actual position at the trajectory +/- shape offset. You can adjust the sign of the X,Y,Z axises by negating them or by changing the cross product operand order to obtain the mirroring of shape you want. Now to construct the transform matrix see:
Understanding 4x4 homogenous transform matrices
Now just transform/render your shape with this matrix.

Matlab - Subtracting two 3D figures with surf and min function

I'm trying to make a surf plot that looks like:
So far I have:
x = [-1:1/100:1];
y = [-1:1/100:1];
[X,Y] = meshgrid(x,y);
Triangle1 = -abs(X) + 1.5;
Triangle2 = -abs(Y) + 1.5;
Z = min(Triangle1, Triangle2);
surf(X,Y,Z);
shading flat
colormap winter;
hold on;
[X,Y,Z] = sphere();
Sphere = surf(X, Y, Z + 1.5 );% sphere with radius 1 centred at (0,0,1.5)
hold off;
This code produces a graph that looks like :
A pyramid with square base ([-1,1]x[-1,1]) and vertex at height c = 1.5 above the origin (0,0) is erected.
The top of the pyramid is hollowed out by removing the portion of it that falls within a sphere of radius r=1 centered at the vertex.
So I need to keep the part of the surface of the sphere that is inside the pyramid and delete the rest. Note that the y axis in each plot is different, that's why the second plot looks condensed a bit. Yes there is a pyramid going into the sphere which is hard to see from that angle.
I will use viewing angles of 70 (azimuth) and 35 (elevation). And make sure the axes are properly scaled (as shown). I will use the AXIS TIGHT option to get the proper dimensions after the removal of the appropriate surface of the sphere.
Here is my humble suggestion:
N = 400; % resolution
x = linspace(-1,1,N);
y = linspace(-1,1,N);
[X,Y] = meshgrid(x,y);
Triangle1 = -abs(X)+1.5 ;
Triangle2 = -abs(Y)+1.5 ;
Z = min(Triangle1, Triangle2);
Trig = alphaShape(X(:),Y(:),Z(:),2);
[Xs,Ys,Zs] = sphere(N-1);
Sphere = alphaShape(Xs(:),Ys(:),Zs(:)+2,2);
% get all the points from the pyramid that are within the sphere:
inSphere = inShape(Sphere,X(:),Y(:),Z(:));
Zt = Z;
Zt(inSphere) = nan; % remove the points in the sphere
surf(X,Y,Zt)
shading interp
view(70,35)
axis tight
I use alphaShape object to remove all unwanted points from the pyramid and then plot it without them:
I know, it's not perfect, as you don't see the bottom of the circle within the pyramid, but all my tries to achieve this have failed. My basic idea was plotting them together like this:
hold on;
Zc = Zs;
inTrig = inShape(Trig,Xs(:),Ys(:),Zs(:)+1.5);
Zc(~inTrig) = nan;
surf(Xs,Ys,Zc+1.5)
hold off
But the result is not so good, as you can't really see the circle within the pyramid.
Anyway, I post this here as it might give you a direction to work on.
An alternative to EBH's method.
A general algorithm from subtracting two shapes in 3d is difficult in MATLAB. If instead you remember that the equation for a sphere with radius r centered at (x0,y0,z0) is
r^2 = (x-x0)^2 + (y-y0)^2 + (z-z0)^2
Then solving for z gives z = z0 +/- sqrt(r^2-(x-x0)^2-(y-y0)^2) where using + in front of the square root gives the top of the sphere and - gives the bottom. In this case we are only interested in the bottom of the sphere. To get the final surface we simply take the minimum z between the pyramid and the half-sphere.
Note that the domain of the half-sphere is defined by the filled circle r^2-(x-x0)^2-(y-y0)^2 >= 0. We define any terms outside the domain as infinity so that they are ignored when the minimum is taken.
N = 400; % resolution
z0 = 1.5; % sphere z offset
r = 1; % sphere radius
x = linspace(-1,1,N);
y = linspace(-1,1,N);
[X,Y] = meshgrid(x,y);
% pyramid
Triangle1 = -abs(X)+1.5 ;
Triangle2 = -abs(Y)+1.5 ;
Pyramid = min(Triangle1, Triangle2);
% half-sphere (hemisphere)
sqrt_term = r^2 - X.^2 - Y.^2;
HalfSphere = -sqrt(sqrt_term) + z0;
HalfSphere(sqrt_term < 0) = inf;
Z = min(HalfSphere, Pyramid);
surf(X,Y,Z)
shading interp
view(70,35)
axis tight

MATLAB Surface Plotting

I want to plot the region (of integration) in 3d-space given by the conditions -1<=x<=1, 0<=y<=1, 0<=z<=1-x^2 with translucent single-coloured faces in essentially 'wireframe'.
My solution basically draws the four bounding surfaces of the region separately. I used surf() for the bottom face that lies on the x-y plane and the top face; however surf() doesn't seem to work with the two vertical faces. Hence I guess that there has to be an easier way to draw this...
Cludgiest code ever:
figure
hold on
x = linspace(-1,1,30);
y = linspace(0,1,30);
[X,Y] = meshgrid(x,y);
Z = 1-X.^2;
h = surf(X,Y,Z);
set(h,'edgecolor','none','FaceColor','r','FaceAlpha',0.5);
Z = zeros(30);
h = surf(X,Y,Z);
set(h,'edgecolor','none','FaceColor','r','FaceAlpha',0.5);
Y = ones(30);
z = 1-x.^2;
y = x.*0;
h = fill3(x,y,z,'r');
alpha(h,0.5);
y = y+1;
h = fill3(x,y,z,'r');
alpha(h,0.5);
y = linspace(0,1,30);
x = y.*0+1;
z = y.*0
plot3(x,y,z,'k')