0
votes

I want to show, with Matlab, a temperature distribution on an object surface.

I've got a 3D data in the form of (x, y, z, V) vectors. I would like to show this object in Matlab, with the colour representing the local total "value".

I can export the object as an STL file. It can be shown easily using the STL plotting (see stldemo):

fv = stlread('file.stl');
patch(fv, 'EdgeColor', 'none', 'FaceLighting', 'gouraud', 'AmbientStrength', 0.15, 'FaceColor', [0.8 0.8 1.0]);
camlight('headlight');
material('dull');

To colour it according to (x,y,z,V), I need to attach each (x, y, z) point to a vertex in the patch (the nearest one would work). If there are many (x,y,z) points for which a single STL vertex is the nearest, I add up the corresponding V values for that vertex.

The number of vertices is thousands. The number of (x, y, z) points is also large. So doing a loop through (x, y, z) points and then an internal loop over vertices to find the nearest one (which involves calculating distances between points) is out of question. Is there any smart way to do it quickly?

Note: I cannot control the location of the data points, they are defined by an external program. The STL points are controlled by another external program. So I have to marry two different point sets.

Here is the code illustrating what I want to achieve, with 4 vertices and 3 data points:

% Create patch
figure;
p = patch;
colorbar

p.Vertices = [...
    0, 0, 0; ...
    1, 0, 0; ...
    1, 1, 0;
    0, 1, 0];
p.Faces = [ ...
    1, 2, 3; ...
    1, 3, 4];

% Data points
x = [0.1, 0.1, 0.25];
y = [0.01, 0.02, 0.75];
z = [0.01, 0.2, -0.01];
v = [1, 1, 1];

p.FaceVertexCData = zeros(size(p.Vertices, 1), 1);
% Point 1 (0.1, 0.01, 0.01) is closest to vertex 1 (0, 0, 0). Its value
% goes to vertex 1.
p.FaceVertexCData(1) = p.FaceVertexCData(1) + v(1);
% Point 2 (0.1, 0.02, 0.2) is also closest to vertex 1 (0, 0, 0). Its
% value also goes to vertex 1
p.FaceVertexCData(1) = p.FaceVertexCData(1) + v(2);
% Point 3 (0.25, 0.75, -0.01) is closest to vertex 4 (0, 1, 0). Its power
% goes to vertex 4.
p.FaceVertexCData(4) = p.FaceVertexCData(4) + v(3);
% Other vertices are left with 0.

p.FaceColor = 'interp';
1
This is really the kind of case where an mvce would greatly help. Try to supply a minimal subset of data that people can work with, otherwise they would have to generate sample data and not everyone will do that ... - Hoki
Also, how are the temperature data calculated ? Could you feed the patch points to the function which calculate the temperature distribution ? That would make the whole exercise a lot simpler (just a couple of settings on CData and colormap) - Hoki
@Hoki, I added an example which hopefully explains what I am trying to achieve. And I cannot calculate the temperature and the predefined points, the (x, y, z) points are defined by an external modelling software in its own way. - texnic

1 Answers

2
votes

Attaching a volume scalar value (of Temperature in your case) of a point to a neighbouring point is a tricky exercise, requires complex for loops and defining special case rules (in your case you wanted to attach the value of 2 different points to the same patch vertex, what if the 2 values to attach are different? Do you average? discard ?).

A safer approach is to re-interpolate your temperature field over your object surface. the function griddata can do that for you.

First I had to define a scalar field. Since I do not have your temperature data, I use the flow function from Matlab. I generated a scalar field the same ways than in this article: flow data.
This gave me a scalar field v (flow value but let's say it's your temperature) at for every coordinates x, y, z.

flow

Then I created and introduced a 3D patch which will be your object. I chose a sphere but any 3D patch will work the same way. The code to get the sphere as a patch is borrowed from surf2patch
you will have to offset and inflate the sphere to get it exactly as in the figure below

simplesphere

Now is the interesting bit. In the following code, v is the value of the scalar field (temperature for you) at the coordinates x, y, z.

%% // Extract patch vertices coordinates in separate variables
xp = fv.vertices(:,1) ;
yp = fv.vertices(:,2) ;
zp = fv.vertices(:,3) ;

%% // interpolate the temperature field over the patch coordinates
Tpv = griddata(x,y,z,v,xp,yp,zp) ;

%% // Set the patch color data to the new interpolated temperature
set(hp,'FaceVertexCData',Tpv) ;

And your object surface is now at the right interpolated temperature:
you can delete the slice plane if you want to observe the patch alone

obectfinal