space-dementia
space-dementia

Reputation: 307

Interpolate surface of 3D cylinder in Matlab

I have a dataset that describes a point cloud of a 3D cylinder (xx,yy,zz,C): 3D point cloud

and I would like to make a surface plot from this dataset, similar to this enter image description here

In order to do this I thought I could interpolate my scattered data using TriScatteredInterp onto a regular grid and then plot it using surf:

F = TriScatteredInterp(xx,yy,zz);
max_x = max(xx); min_x = min(xx);
max_y = max(yy); min_y = min(yy);
max_z = max(zz); min_z = min(zz);
xi = min_x:abs(stepSize):max_x;
yi = min_y:abs(stepSize):max_y;
zi = min_z:abs(stepSize):max_z;
[qx,qy] = meshgrid(xi,yi);
qz = F(qx,qy);
F = TriScatteredInterp(xx,yy,C);
qc = F(qx,qy);

figure
surf(qx,qy,qz,qc);
axis image

This works really well for convex and concave objects but ends in this for the cylinder: enter image description here

Can anybody help me as to how to achieve a nicer plot?

Upvotes: 10

Views: 6067

Answers (4)

SamuelNLP
SamuelNLP

Reputation: 4136

I think what you are loking for is the Convex hull function. See its documentation.

K = convhull(X,Y,Z) returns the 3-D convex hull of the points (X,Y,Z), where X, Y, and Z are column vectors. K is a triangulation representing the boundary of the convex hull. K is of size mtri-by-3, where mtri is the number of triangular facets. That is, each row of K is a triangle defined in terms of the point indices.

Example in 2D

xx = -1:.05:1; yy = abs(sqrt(xx));
[x,y] = pol2cart(xx,yy);
k = convhull(x,y);
plot(x(k),y(k),'r-',x,y,'b+')

enter image description here

Use plot to plot the output of convhull in 2-D. Use trisurf or trimesh to plot the output of convhull in 3-D.

Upvotes: 1

ccook
ccook

Reputation: 5959

Have you tried Delaunay triangulation?

http://www.mathworks.com/help/matlab/ref/delaunay.html

load seamount
tri = delaunay(x,y);
trisurf(tri,x,y,z);

plot

There is also TriScatteredInterp

http://www.mathworks.com/help/matlab/ref/triscatteredinterp.html

ti = -2:.25:2;
[qx,qy] = meshgrid(ti,ti);
qz = F(qx,qy);
mesh(qx,qy,qz);
hold on;
plot3(x,y,z,'o');

enter image description here

Upvotes: 1

snooze_bear
snooze_bear

Reputation: 599

TriScatteredInterp is good for fitting 2D surfaces of the form z = f(x,y), where f is a single-valued function. It won't work to fit a point cloud like you have.

Since you're dealing with a cylinder, which is, in essence, a 2D surface, you can still use TriScatterdInterp if you convert to polar coordinates, and, say, fit radius as a function of angle and height--something like:

% convert to polar coordinates:
theta = atan2(yy,xx);
h = zz;
r = sqrt(xx.^2+yy.^2);

% fit radius as a function of theta and h
RFit = TriScatteredInterp(theta(:),h(:),r(:));

% define interpolation points
stepSize = 0.1;
ti = min(theta):abs(stepSize):max(theta);
hi = min(h):abs(stepSize):max(h);
[qx,qy] = meshgrid(ti,hi);
% find r values at points:
rfit = reshape(RFit(qx(:),qy(:)),size(qx));
% plot
surf(rfit.*cos(qx),rfit.*sin(qx),qy)

Upvotes: 0

Rody Oldenhuis
Rody Oldenhuis

Reputation: 38032

A cylinder is the collection of all points equidistant to a line. So you know that your xx, yy and zz data have one thing in common, and that is that they all should lie at an equal distance to the line of symmetry. You can use that to generate a new cylinder (line of symmetry taken to be z-axis in this example):

% best-fitting radius 
% NOTE: only works if z-axis is cylinder's line of symmetry
R = mean( sqrt(xx.^2+yy.^2) );

% generate some cylinder
[x y z] = cylinder(ones(numel(xx),1));

% adjust z-range and set best-fitting radius
z = z * (max(zz(:))-min(zz(:))) + min(zz(:));
x=x*R;
y=y*R;

% plot cylinder
surf(x,y,z)

Upvotes: 0

Related Questions