Hey everybody :)
I'm slowly losing my mind trying to create a surface from curves plotted in 3D. I've already tried:
  • 2D Delaunay
  • Alpha‐Shape masking
  • Lofting between constant curves
  • 2D grid interpolation + “fillmissing”
  • Thin‐plate spline / RBF interpolation
  • Edge‐length filtering on 2D Delaunay
  • 3D Delaunay + FreeBoundary
  • Constant‐x / constant‐y triangle removal
but I can't quite get it working. The last two points combined result in a decent surface (see code and picture below).
DT3 = delaunayTriangulation(X_all, Y_all, Z_all);
% Only outer triangles (FreeBoundary)
[FV, Pts] = freeBoundary(DT3);
% Coordinates of edges
I1 = FV(:,1); I2 = FV(:,2); I3 = FV(:,3);
x1 = Pts(I1,1); y1 = Pts(I1,2);
x2 = Pts(I2,1); y2 = Pts(I2,2);
x3 = Pts(I3,1); y3 = Pts(I3,2);
tol = 1e-6;
% Mask if triangle is in x-z or y-z-plane
allSameX = (abs(x1 - x2) < tol) & (abs(x2 - x3) < tol);
allSameY = (abs(y1 - y2) < tol) & (abs(y2 - y3) < tol);
keepTri = ~(allSameX | allSameY);
FV = FV(keepTri, :);
% Plot
hold on;
trisurf(FV, Pts(:,1), Pts(:,2), Pts(:,3), Pts(:,3), ...
'EdgeColor','none', ...
'FaceColor','interp', ...
'FaceAlpha',0.6);
The problems are the loops and leaning of the curves. No matter what I do, I either get surfaces in all of the loops and overhangs as well or like in this case a surface, which isn't fitting the curves. Below you can see the 2D delaunay, which is really good, but somehow the part of the code, that is supposed to delete triangles in the x-z or y-z-plane isn't working.
% 2D Delaunay triangulation
tri = delaunay(X_all, Y_all);
% 2) Compute corner indices and coordinates for each triangle
I1 = tri(:,1); I2 = tri(:,2); I3 = tri(:,3);
x1 = X_all(I1); y1 = Y_all(I1);
x2 = X_all(I2); y2 = Y_all(I2);
x3 = X_all(I3); y3 = Y_all(I3);
% 3) Mark any triangle whose three values are (almost) identical
tol = 1e-6;
allSameX = (abs(x1 - x2) < tol) & (abs(x2 - x3) < tol);
allSameY = (abs(y1 - y2) < tol) & (abs(y2 - y3) < tol);
% Keep only those triangles that are neither “allSameX” nor “allSameY”
keepTri = ~(allSameX | allSameY);
tri = tri(keepTri, :);
% 5) Plot the filtered surface (trisurf)
trisurf(tri, X_all, Y_all, Z_all, Z_all, ...
'EdgeColor', 'none', ...
'FaceColor', 'interp', ...
'FaceAlpha', 0.6);
I would really appreciate your tips and help on how to get a good surface fitting to those curves. If you need any further info, please just let me know. Thank you so much in advance!
Edit: Added data files.

5 Comments

@Daniel Martin, post the data please...
@William Rose, sorry added the X_all, Y_all, Z_all files now.
hello
tried also a few things but it failed to get the expected results
(still I need to test it for a complex shape that intersect or fold on itself)
anyway , like other approaches based on Delaunay triangulation, the result will be best if your data is more uniformly distributed like a cloud (as in the demo files).
unfortunately, your data looks like a skeleton with a lot of empty areas . I wished there would be more dots between the lines
do you have control over that generation of data ? maybe you can reduce the point density in each "line" (we can probably get a good result with 10 times less points) and increase the number of lines ...
thank you for your answer!
I'll have a look into the fex submission, thanks.
Yes, that is a problem I realised as well, so actually I already added more curves to get the data shared with you. I could theoretically generate more lines and to a certain point influence the density in each curve, but that would take quite a while and would maybe be a solution for the long run if there's no other suitable option.
if that is too complicated , we can also manage the density from within matlab (we can downsample your data by picking only every k samples)
more lines would be beneficial for sure !

Sign in to comment.

 Accepted Answer

well , maybe with boundary (shrink factor = 1) and trisurf we have a simple solution - maybe not perfect but visually quite close to what we want (or am I wrong ? )
my result :
load('X_all.mat')
load('Y_all.mat')
load('Z_all.mat')
figure
plot3(X_all,Y_all,Z_all,'b.')
hold on
k = boundary(X_all,Y_all,Z_all,1);
trisurf(k,X_all,Y_all,Z_all,'FaceAlpha',0.2,'EdgeColor','none');
view([45 25])
hold off

4 Comments

Daniel Martin
Daniel Martin on 5 Jun 2025
Edited: Daniel Martin on 5 Jun 2025
@Mathieu NOE, the best solutions are always the simplest, ey? That's actually exactly what we want. It's not perfect as you're saying, with some small artefacts going on in the top region, but it is really really good and I'm quite happy with it. Do you think I could try to perfect it in some way using this approach? Thank you so much, you've already helped me a ton!
hello again
glab it works for you
as I said above I would try this code with more lines (a denser skeletton) , each line probably not more than 100 / 200 dots.
all the best
@Mathieu NOE, I finally found some time to generate more data. With that and by tweaking the shrink factor a bit (to 0.85) plus some other minor adaptations like excluding the bottom surface, I got the surface I was looking for in the end, see the pic below. Thank you so much again!
hello again
glad I could be of some help here !
have a good day

Sign in to comment.

More Answers (0)

Products

Release

R2024a

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!