Code covered by the BSD License  

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

4.6 | 13 ratings Rate this file 104 Downloads (last 30 days) File Size: 6.08 KB File ID: #42876 Version: 1.5
image thumbnail

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


Sven (view profile)


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 (22)
29 Jun 2015 Meghan Kazanski

Is there any way to combine multiple surfaces (as two sets of X,Y,Z matrices) into one solid?

Thanks in advance!

Comment only
28 May 2015 Sven

Sven (view profile)

@Sarah: You gave a property ('elevation') without a value. You need to specify the actual elevation that you desire. Try this code, which specifies an elevation of "3" such that faces are extruded down to a Z-coordinate of 3:

V = [0 0 10; 1 2 11; 2 4 12; 4 2 11; 5 0 10; 2.5 0 9];
F = [1 2 6; 6 4 5; 2 4 6; 2 3 4];

Does this solve your problem?

Comment only
27 May 2015 Sarah Weissenberger

Hi Sven,

I would like to use your code, giving it faces and vertices.
I tried using: surf2solid (F,V, 'elevation');

But Matlab is throwing an error. Can you imagine what is wrong with that?

Thank you very much.

30 Nov 2014 Evan

Evan (view profile)

Hi, a question when trying to figure out a solid with holes inside. For example, the "meshgrid" creates a 5*5 matrix, but I only need to use the central ring area to create solid ring-cylinder. I tried to set the thickness of those pixels(unwanted) to 0, but it still carried out a flat plan covering the whole 5*5 area (I expect no solid in the center hole). How could I set it? Thanks so much.

29 Aug 2014 Nathan Tomlin

Works really great and imports into openscad perfectly!

29 Aug 2014 Nathan Tomlin  
06 Aug 2014 Sven

Sven (view profile)

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

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

Comment only
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

Sven (view profile)

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])

Comment only
23 Jul 2014 Marios

Marios (view profile)

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).

Comment only
23 Feb 2014 Adam Hart


20 Feb 2014 Adam

Adam (view profile)

Awesome! Thanks!

08 Feb 2014 Daniel

Daniel (view profile)

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

Sven (view profile)

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)

Comment only
19 Nov 2013 Sven

Sven (view profile)

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.

Comment only
18 Nov 2013 Daniel

Daniel (view profile)

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.

Comment only
17 Sep 2013 Sven

Sven (view profile)

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?

Comment only
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 1.1

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

15 Aug 2013 1.2

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

02 Dec 2013 1.3

Added ability to solidify self-enclosing surfaces without boundary edges

10 Feb 2014 1.5

Added optional normal direction input

Contact us