Code covered by the BSD License  

Highlights from
surf2solid - make a solid volume from a surface for 3D printing


5.0 | 11 ratings Rate this file 78 Downloads (last 30 days) File Size: 6.08 KB File ID: #42876
image thumbnail

surf2solid - make a solid volume from a surface for 3D printing



29 Jul 2013 (Updated )

Turns thin surfaces into closed solids by adding a flat base or offsetting by a given thickness.

Editor's Notes:

This file was selected as MATLAB Central Pick of the Week

| Watch this File

File Information

  SOLID_FV = SURF2SOLID(FV,...) takes in a triangulated patch defined by
  FV (a structure with fields 'vertices' and 'faces'), and returns a
  solid patch SOLID_FV closed by options (described below).

  SOLID_FV = SURF2SOLID(F, V,...) takes faces and vertices separately.

  [F,V] = SURF2SOLID(...) returns solid faces and vertices separately.

  SURF2SOLID(...) with no output argument plots the 3 components
  (orig-surface, side-walls, under-surface) to a new figure.

  SURF2SOLID(X, Y, Z, ...) reads in surface data in X, Y, and Z matrices,
  and triangulates this gridded data into a surface using triangulation
  options specified below. Z must be a 2D matrix. X and Y can be 2D
  matrices of the same size as Z, or vectors of length equal to SIZE(Z,2)
  and SIZE(Z,1), respectively. If X or Y are scalar values, they are used
  to specify the X and Y spacing between grid points.

  SURF2SOLID(...,'PropertyName',VALUE,...) makes a solid volume from thin
  surface using any of the following property/value options:

  ELEVATION - Extends the surface down to a flat base at the given
                  (Z) elevation value. Useful for turning a thin
                  elevation map into a solid block with a flat base. The
                  ELEVATION value should be below the lowest (or above
                  the highest) data point. If no other options are given,
                  ELEVATION defaults to MIN(Z)-0.1*(MAX(Z)-MIN(Z)).
                  Variable ELEVATION may also be given per-point, via a
                  2D matrix (the same size as Z for X,Y,Z style input) or
                  a 1D array (with length equal to the number of vertices
                  given in face/vertex input).

  THICKNESS - Value to offset the given thin surface to make a
                  thickened solid slab. Each node on the surface will be
                  projected along its normal direction by thickness. When
                  negative thickness is given, offset will be away from
                  face normal direction. Variable thickness can also be
                  specified via a 2D matrix (of same size as Z, for X,Y,Z
                  input) or an N-by-1 array of thicknesses (where N is
                  the number of vertices in the thin surface)

  TRIANGULATION - When used with gridded data, TRIANGULATION is either:
                   'delaunay' - (default) Delaunay triangulation of X, Y
                   'f' - Forward slash division of grid quads
                   'b' - Back slash division of quadrilaterals
                   'x' - Cross division of quadrilaterals
                  Note that 'f', 'b', or 'x' triangulations use an
                  inbuilt version of FEX entry 28327, "mesh2tri". 'x'
                  style triangulation cannot be used with variable
                  ELEVATION or THICKNESS parameters.

  NORMALS - When THICKNESS options is used, the direction to
                  thicken the surface is (by default) determined by the
                  surface (unit vector) normal directions at each vertex.
                  To override these default directions, you may specify
                  NORMALS as an N-by-3 array of normal directions (where
                  N is the number of vertices in the thin surface). This
                  is useful when underlying data gives more precise
                  normal directions than face orienatations (for an
                  example, see the isonormals function).

Note 1: Currently surf2solid will return a closed surface with face
normals pointing "out". With user feedback, I'd be happy to change this
behaviour to either "in" or "unchanged from input direction".
Note 2: If a single ELEVATION value is specified (i.e., flat base), the
resulting patch will have minimal triangles on the flat base to reduce
patch/file size.

  Example (shows both THICKNESS and ELEVATION forms):
    n = 30;
    [X,Y] = meshgrid(linspace(0,1,2*n+1));
    L = (40/51/0.9)*membrane(1,n);
    figure, subplot(2,2,[1 3]), title 'Thin surface'
    surf(X,Y,L,'EdgeColor','none'); colormap pink; axis image; camlight
    subplot(2,2,2), title 'Block elevation'
    surf2solid(X,Y,L,'elevation',min(L(:))-0.05); axis image; camlight; camlight
    subplot(2,2,4), title 'Thickness'
    surf2solid(X,Y,L,'thickness',-0.1); axis image; camlight;

  Original idea adapted from Paul Kassebaum's blog post
  Many thanks to Paul for his further input and improvements.


Mesh2tri inspired this file.

This file inspired Puncture Surface.

Required Products MATLAB
MATLAB release MATLAB 8.1 (R2013a)
Tags for This File   Please login to tag files.
Please login to add a comment or rating.
Comments and Ratings (18)
29 Aug 2014 Nathan Tomlin

Works really great and imports into openscad perfectly!

29 Aug 2014 Nathan Tomlin  
06 Aug 2014 Sven

Hi Mona, the output from surf2solid (a faces/vertices structure) can be given directly to stlwrite:

FV = surf2solid(...)
stlwrite('yourfile.stl', FV)

06 Aug 2014 Mona MK

Hi Sven,

Could you give me a clue on how to convert this generated solid topography into STL format? For instance using your older 'stlwrite - Write binary or ascii STL file' code.

Thanks for the awesome work in advance! :)

23 Jul 2014 Sven

Hi Marios:

1) Use the triangulated faces/vertices input (SURF2SOLID(F, V,...)) instead of the gridded input (SURF2SOLID(X, Y, Z, ...)) and you can make arbitrary shaped surfaces instead of a grid. I would simply put 0 thickness at the nodes you don't want solid instead of NaN thickness.

2) This is possible, you just need to calculate the distance you want each node to be offset and use that 'thickness'. Basically, give the thickness as the difference between the original surface and your desired surface.

Here's a small example that uses most of those options:

v = [2 4 0; 2 6 0; 8 4 1; 8 0 0; 0 4 0]
f = [1 2 3; 1 3 4; 5 2 1]
figure, surf2solid(f,v,'thickness',[0 0 3 2 0])

23 Jul 2014 Marios

Hi Sven,

Very good work. Two questions.

1) Can I change the rectangular mesh to an irregular (curved) one. I have NaN to areas I don't want to create a solid, but it says that it is not supported.

2) Is it possible that user provide a different bottom surface (assuming that up and down surface have the same x,y coordinates).

23 Feb 2014 Adam Hart


20 Feb 2014 Adam

Awesome! Thanks!

08 Feb 2014 Daniel

Thanks for the update Sven! After removing degenerate faces from my surfaces, I feel like this works very well. I've even fed the result through stlwrite, and successfully printed one.


30 Nov 2013 Sven

Hi Daniel, I've had time to make this fix - it was simply a case of adding an if-isempty clause to line 100 to detect surfaces without any boundary. It's in submission now, and here's a working example of a torus that had the error you described but now works fine:

% Make a torus
% Get quad faces
figure, t = surf(x,y,z); p = surf2patch(t); close(gcf)
% Triangulate faces (removing coincident vertices)
tri = cat(1, p.faces(:, [1 2 3]), p.faces(:, [1 3 4]));
[unqV, ~, unqI] = unique(p.vertices,'rows');
pTri = struct('vertices',unqV,'faces',unqI(tri));
% Solidify thin surface
pSol = surf2solid(pTri,'Thickness',1)
% Show the result
figure, patch(pSol,'FaceColor','g','FaceAlpha',0.2)

19 Nov 2013 Sven

Hi Daniel,
That sounds like the type of thing that surf2solid should handle but I never used it as a test case. I think it should be manageable to work out what to do when "edge" faces are empty. I'll try to put something in, but it will be a week or so... I'm travelling right now.

18 Nov 2013 Daniel

Thanks for the m-file! I am generally pleased with what I see.

I would like to use this file to thicken surfaces generated from implicit equations. Such an example is a torus. I have a coarse set of faces which describe the surface, and want to pass it through the thickener for printing, but I am getting an error at and beyond line 99 (getting boundVerts), because there are no bounding vertices (the surface is closed!)... Do you have a workaround? It is not immediately clear to me how to correct for this.
Thanks again!

05 Oct 2013 Elad

Awesome work!
here is a link to an excellent blog post (written by Sven) with examples of how to use surf2solid function:

17 Sep 2013 Phalgun Lolur

What I meant to say was, I use the hold on command to add new objects to my axis. But how do I create an stl file from that? My objective is to print a multi-layered 3D file. But I'm not quite sure how to do that.

17 Sep 2013 Sven

Hi Phalgun,
I don't quite know what you mean by "multi-layered data". As far as I can tell, the "hold on" command will simply let you add new objects to your current plot axes... nothing about multi-layers and nothing about printing there. What is the "multi-layered 3d image file" type that your 3d printer accepts, and how do you create one of these files normally?

16 Sep 2013 Phalgun Lolur

Dear Sven,

The file worked wonderfully well. But if I needed to use it for printing multi-layered data, how would I do it? I usually use the "hold on" command to generate these multi layered 3d image files in matlab. But I was wondering how to create an stl file from it.

30 Jul 2013 Paul Kassebaum

Love it!

30 Jul 2013 mathgirl

The function is amazing. It works fast and efficiently, and is very easy to use. The resulting stl has high resolution and reasonable size.

Thank you Sven!
Really appreciate your work.

31 Jul 2013

Set other-faces as opposite norm direction to input faces
Ensured optional per-node thickness input is accepted

15 Aug 2013

Added per-node elevation and thickness, minimal-flat-base file size, and default face orientation "out".

02 Dec 2013

Added ability to solidify self-enclosing surfaces without boundary edges

10 Feb 2014

Added optional normal direction input

Contact us