Matlab computing wrong surface normals? - matlab

I have a big FEM model from where I can get the "surface" of the model, say the elements and vertex that define the surface of that FEM model. For plotting purposes (nice plots are always a win!) I want to plot it nicely. My approach is just to use
lungs.Vertex=vtx;
lungs.Faces=fcs;
patch(lungs,'facecolor','r','edgecolor','none')
NOTE: I need edgecolor none, as this is 4D data and different FEM have different triangulation, if edges are plotted user will be dizzy.
However this will output everything in a really plain red color, which is not nice (as it can not show the complexity of the figure, which are lungs, for the attentive to details).
therefore I decided to use ligthing:
camlight; camlight(-80,-10); lighting phong;
But again, this is not entirely correct. Actually it seems that the patch nromals are not computed correctly by Matlab.
My supposition is that maybe the patches are not always defined counter-clockwise and therefore some normals go to the wrong direction. However that is something its not straightforward to check.
Anyone has a similar problem, or ahint of how should I aproach this problem in order to have a nice surface ploted here?
EDIT
Just for the shake of plotting, here is the result obtained with #magnetometer answer:

If your model gives you outward oriented normals, you can re-sort the faces of your model so that Matlab can properly calculate it's own normals. The following function works if you have triangular faces and outward oriented normals:
function [FaceCor,nnew]=SortFaces(Faces,Normals,Vertices)
FaceCor=Faces;
nnew=Normals*0;
for jj=1:size(Faces,1)
v1=Vertices(Faces(jj,3),:)-Vertices(Faces(jj,2),:);
v2=Vertices(Faces(jj,2),:)-Vertices(Faces(jj,1),:);
nvek=cross(v2,v1); %calculate normal vectors
nvek=nvek/norm(nvek);
nnew(jj,:)=nvek;
if dot(nvek,Normals(jj,:))<0
FaceCor(jj,:)=[Faces(jj,3) Faces(jj,2) Faces(jj,1)];
nnew(jj,:)=-nvek;
end
end
If your FEM model doesn't give you outward directed normals, one way could be to reconstruct the surface using e.g. a crust algorithm that gives you outward directed normals or correctly oriented patches.
EDIT:
As you don't have normals, the only solution that comes to my mind is to reconstruct the surface. This implementation of the crust algorithm has worked well for me in the past. All you need to do is:
[FacesNew,NormalsNew]=MyRobustCrust(Vertices);
If I remember correctly, FacesNew are not yet oriented counterclockwise, but you can use the SortFaces algorithm I posted above to correct for this, as you now have correctly oriented face normals, i.e. run:
[FaceCor,~]=SortFaces(FacesNew,NormalsNew,Vertices)
If you use Matlab's reducepatch (e.g. reducedmodel=reducepatch(fullmodel,reduction); ) to reduce the number of vertices, you will have to reconstruct the surface again, as reducepatch doesn't seem to keep the correct orientation of the patches.

Related

Triangulation of 3D objects in Matlab

I need to make a surface triangulation of stones (aggregates) point cloud in Matlab. For this I have x,y,z in Cartesian coordinate system.
For the simplicity I have started with spherical object.
DT = delaunayTriangulation(x,y,z);
figure
trisurf(DT.ConnectivityList,DT.Points(:,1),DT.Points(:,2),DT.Points(:,3), ...
'FaceColor','cyan','FaceAlpha', 0.8);
Run the code and result is:
Triangulation of Spherical Object
It makes triangles inside the sphere too. Connecting one point to another one in opposite or somewhere else.
Also, delaunayTriangulation() function triangulates for idealized surfaces and do not works for sensitive surfaces. Think about the surface of stone, there are a lot of irregularity on it.
Then I have tried DelaunayTri() function. It worked for sphere object, triangulated only surface. But when tried more complex (stone) shape, the function just idealized the shape and not considered all protrusions (irregularity) of stone.
tri = DelaunayTri(x,y,z);
[FBtri,FBpoints] = freeBoundary(tri);
figure
trisurf(FBtri,FBpoints(:,1),FBpoints(:,2),FBpoints(:,3), ...
'FaceColor','cyan','FaceAlpha', 0.8);
When freeBoundary() function removed from above code, result is same (idealized) and triangulation made inside the object, which is not acceptable.
Finally, I have used the delaunay() function. Which is even not correctly triangulated the sphere.
tri = delaunay(x,y,z);
figure
trisurf(tri,x,y,z,'FaceColor','cyan','FaceAlpha', 0.8);
Question: With which function and how (please detailed) can I make the detailed 3D triangulation of any shaped stone surface? What was my mistakes above codes?
None of the pure delaunay-based methods you tried will do what you want -- they all tessellate the full convex-hull of the input, not just the surface.
Reconstructing general surfaces from point-clouds is not a straight-forward task. I don't believe it can be done directly using a built-in MATLAB function.
You may wish to look into other options, such as the surface-reconstruction tools provided by CGAL.

Subtract delaunay surfaces from each other

I have a surface by the code below and another surface which is created by the exact same code. I want to see the height differences in another figure. How am I able to do that? Already operated with the Minus-operator but this won't work.
Furthermore the matrices have NOT the same size!
Appreciate your help!
x1 = Cx1;
y1 = Cy1;
z1 = Cz1;
tri1 = delaunay(x1,y1);
fig1 = figure%('units','normalized','outerposition',[0 0 1 1]);
trisurf(tri1,x2,y2,z2)
xlabel('x [mm] ','FontSize',30)
ylabel('y [mm] ','FontSize',30)
zlabel('z [mm] ','FontSize',30)
The simplest way to solve this problem is to interpolate from one mesh onto the other one. Such an approach works well when one is more highly resolved than the other, or when you're not as concerned with results at individual nodes, but rather the overall pattern across elements. If that's not the case, then you have a very complicated problem because you need to create a polygonal surface that fully captures all nodes and edges of both triangulations. Consider the following pair of triangular patterns:
A surface that captured all the variations would need to have all the vertices and edges that make up both of them, which is not a purely triangular surface. So, let us instead assume the easier case. To map results from one triangulation to the other, you simply need to formulate functions that define how the values vary along the triangles, which are more broadly called basis functions. It is often assumed that values betweeen the nodes (i.e. vertices) of the triangles vary linearly along the surfaces of the triangles. You can do it differently if you want, it just requires defining new basis functions. If we go for linear functions, then the equations in 2D are pretty simple. Let's say you make an array trimap that has which triangle each of the vertices of the other triangulation is inside of. This can be accomplished using the info here. Then, we set the coordinates of the vertices of the current triangle to (x1,y1), (x2,y2), and (x3,y3), and then do the math:
for cnt1=1,npoints
x1=x(tri1(trimap(cnt1),1));
x2=x(tri1(trimap(cnt1),2));
x3=x(tri1(trimap(cnt1),3));
y1=y(tri1(trimap(cnt1),1));
y2=y(tri1(trimap(cnt1),2));
y3=y(tri1(trimap(cnt1),3));
delta=x2*y3+x1*y2+x3*y1-x2*y1-x1*y3-x3*y2;
delta1=(x2*y3-x3*y2+xstat(cnt1)*(y2-y3)+ystat(cnt1)*(x3-x2));
delta2=(x3*y1-x1*y3+xstat(cnt1)*(y3-y1)+ystat(cnt1)*(x1-x3));
delta3=(x1*y2-x2*y1+xstat(cnt1)*(y1-y2)+ystat(cnt1)*(x2-x1));
weights(cnt1,1)=delta1/delta;
weights(cnt1,2)=delta2/delta;
weights(cnt1,3)=delta3/delta;
z1=z(tri1(trimap(cnt1),1));
z2=z(tri1(trimap(cnt1),2));
z3=z(tri1(trimap(cnt1),3));
valinterp(cnt1)=sum(weights(cnt1,:).*[z1,z2,z3]);
end
valinterp is the interpolated value for each point. Here and here are some nice slides explaining the mathematics behind all this. Note that I've not tested any of this code. Note also that you will need to do something to assign to values outside of the triangulation. Perhaps a null value, or an inverse-distance weighted value.

Constructing voxels of a 3D cube in MATLAB

I want to construct a 3D cube in MATLAB. I know that the units of any 3D shape are voxels not pixels. Here is what I want to do,
First, I want to construct a cube with some given dimensions x, y, and z.
Second, according to what I understand from different image processing tutorials, this cube must consists of voxels (3D pixels). I want to give every voxel an initial color value, say gray.
Third, I want to access every voxel and change its color, but I want to distinguish the voxels that represent the faces of the cube from those that represent the internal region. I want to axis every voxel by its position x,y, z. At the end, we will end up with a cube that have different colors regions.
I've searched a lot but couldn't find a good way to implement that, but the code given here seems very close in regard to constructing the internal region of the cube,
http://www.mathworks.com/matlabcentral/fileexchange/3280-voxel
But it's not clear to me how it performs the process.
Can anyone tell me how to build such a cube in MATLAB?
Thanks.
You want to plot voxels! Good! Lets see how we can do this stuff.
First of all: yeah, the unit of 3D shapes may be voxels, but they don't need to be. You can plot an sphere in 3D without it being "blocky", thus you dont need to describe it in term of voxels, the same way you don't need to describe a sinusoidal wave in term of pixels to be able to plot it on screen. Look at the figure below. (same happens for cubes)
If you are interested in drawing voxels, I generally would recommend you to use vol3D v2 from Matlab's FEX. Why that instead of your own?
Because the best (only?) way of plotting voxels is actually plotting flat square surfaces, 6 for each cube (see answer here for function that does that). This flat surfaces will also create some artifacts for something called z-fighting in computer graphics. vol3D actually only plots 3 surfaces, the ones looking at you, saving half of the computational time, and avoiding ugly plotting artifacts. It is easy to use, you can define colors per voxel and also the alpha (transparency) of each of them, allowing you to see inside.
Example of use:
% numbers are arbitrary
cube=zeros(11,11,11);
cube(3:9,3:9,3:9)=5; % Create a cube inside the region
% Boring: faces of the cube are a different color.
cube(3:9,3:9,3)=2;
cube(3:9,3:9,9)=2;
cube(3:9,3,3:9)=2;
cube(3:9,9,3:9)=2;
cube(3,3:9,3:9)=2;
cube(9,3:9,3:9)=2;
vold3d('Cdata',cube,'alpha',cube/5)
But yeah, that still looks bad. Because if you want to see the inside, voxel plotting is not the best option. Alphas of different faces stack one on top of the other and the only way of solving this is writing advanced computer graphics ray tracing algorithms, and trust me, that's a long and tough road to take.
Very often one has 4D data, thus data that contains 3D location and a single data for each of the locations. One may think that in this case, you really want voxels, as each of them have a 3D +color, 4D data. Indeed! you can do it with voxels, but sometimes its better to describe it in some other ways. As an example, lets see this person who wanted to highlight a region in his/hers 4D space (link). To see a bigger list I suggest you look at my answer in here about 4D visualization techniques.
Lets try wits a different approach than the voxel one. Lets use the previous cube and create isosurfaces whenever the 4D data changes of value.
iso1=isosurface(cube,1);
iso2=isosurface(cube,4);
p1=patch(iso1,'facecolor','r','facealpha',0.3,'linestyle','none');
p2=patch(iso2,'facecolor','g','facealpha',1,'linestyle','none');
% below here is code for it to look "fancy"
isonormals(cube,p1)
view(3);
axis tight
axis equal
axis off
camlight
lighting gouraud
And this one looks way better, in my opinion.
Choose freely and good plotting!

Interpolating CFD data in 2D using griddata MATLAB

I would like to find residuals of my solutions. However, each solution uses a different grid, thus I would like to interpolate the solutions in 2D to a mesh grid for each solution such that I can easily find the residuals.
I used griddata which seems to work, but it doesn't work very well in regions of discontinuities and near edges. I would like to interpolate data of flow over a sphere for example. The area of the sphere should be confined to zero since that is outside of the grid boundaries; however, after using griddata, there's some non zero values in the sphere region. I also get a warning saying there were duplicate x and y points.
Does anyone know how to preserve the integrity of the sphere after using griddata? I've double checked the original x,y data, and the area of the sphere all have values of 0.
Thank you. I hope that made sense.
Best,
Yuki

[MATLAB]: How would I mathematically and visually reproduce the 3D surface of the new King's Cross 'Western Concourse'?

Anyone have any starting tips for me? I want to learn from this (ie Don't want to be lazy and have someone answer this for me).
I would like to develop my understanding of mathematical 3D surfaces. My own personal project is to produce a 3D surface/graph of the concourse structure in MATLAB.
I found a link with good pictures of its geometry here. I am not expecting to get it 100% perfectly but I'd like to come close!
At the end of this exercise I would like to have a mathematical definition of the geometry as well as a visual representation of the surface. This can involve cartesian equations, parametric equations, matrices, etc.
Any help would be very much appreciated!
To give some specific advice for MATLAB:
I would load in the 'section' image from the web page you have linked, and display this in a MATLAB figure window. You can then try plotting lines over the top until you find one that fits nicely. So you might do something like:
A = imread('~/Desktop/1314019872-1244-n364-1000x707.jpg');
imshow(A)
hold on
axis on
%# my guess at the function - obviously not a good fit
x = [550:900];
plot(x, 0.0001*x.^2 + 300)
Of course, you might want to move the position of the origin or crop the picture and so on.
As an arguably better alternative to this trial-and-error method, you could trace the outline of the section (e.g by clicking points with something like ginput), and then use one of MATLAB's curve-fitting tools (e.g. fit) to fit a function to the data.
The final 3D shape looks to me (at a casual glance) to be a 3D revolution of the section shape around a central axis. Use of a cylindrical coordinate system could therefore be a good idea.
The final plotting of your 3D shape could be done with a function such as surf or mesh.
I would start by defining a function that defines for each x, y coordinate whether there is a point z, and if so with which altitude.
The shape reminds me a bit of a log or a square root.