Skip to content

1. A first surface ​

The tutorial puts a body into a simulation grid. The body is dragon.stl, a binary STL of 6588 facets. The first program loads it, reads what FOSSIL computed on loading, and writes it back as ASCII.

f90
use fossil, only : surface_stl_object
use penf,   only : I4P, R8P
use vecfor, only : vector_R8P

implicit none
type(surface_stl_object) :: surface
type(vector_R8P)         :: bmin, bmax

call surface%load_from_file(file_name='dragon.stl', guess_format=.true.) ! analyze runs inside
  • use fossil gives the four public types (surface_stl_object, facet_object, distance_field_object, curve_object) and the named constants. Kinds come from PENF (I4P, R8P), vectors from VecFor (vector_R8P).
  • load_from_file(file_name=, guess_format=.true.) reads an ASCII or a binary STL: with guess_format the format is detected from the file size. Without it the file is read as ASCII unless is_ascii=.false.. The optional status is STATUS_FILE_NOT_FOUND for a missing file and STATUS_INVALID_INPUT for NaN or Inf coordinates.
  • Loading runs analyze: bounding box, volume, centroid, facet connectivity, the AABB tree (a SAH BVH by default) and the pseudo-normals the signed distance needs. Every later query relies on it.

the dragon as loaded, 6588 facets, inside the bounding box analyze computes

f90
bmin = surface%get_bmin() ; bmax = surface%get_bmax()
print '(A,I0)',       'facets      ', surface%get_facets_number()
print '(A,3F10.4)',   'box min     ', bmin%x, bmin%y, bmin%z
print '(A,3F10.4)',   'box max     ', bmax%x, bmax%y, bmax%z
print '(A,F12.4)',    'volume      ', surface%get_volume()
print '(A,L1,A,L1)',  'watertight  ', surface%is_watertight(), '   manifold ', surface%is_manifold()
  • The components of surface_stl_object are private. They are read through accessors: get_facets_number, get_bmin, get_bmax, get_volume, get_centroid, get_non_manifold_edges_number, and facet_at(i) for one facet.
  • is_watertight() is true when every edge has exactly two facets, is_manifold() when the surface is also free of edges with three or more facets. The dragon is neither: as it comes, it is not a closed surface. Chapter 2 repairs what can be repaired.
f90
call surface%save_into_file(file_name='dragon-ascii.stl', is_ascii=.true.)
print '(A)', 'saved dragon-ascii.stl'
  • save_into_file(file_name=, is_ascii=) writes the surface, as ASCII by default (is_ascii=.false. writes binary). status reports STATUS_FILE_OPEN_FAIL when the file cannot be created.

Several solids in one file ​

An ASCII STL can hold several solid <name> … endsolid blocks: exporters write one per boundary condition (wall, inlet, outlet). load_from_file keeps them as named patches (get_patches_number, patch_name, facet_patch), and save_into_file writes them back as blocks; load_from_files reads one file per patch. See the cookbook recipe wall, inlet and outlet from one STL.

Running it ​

$ tut01_first_surface
facets      6588
box min       -10.8287   -4.1883    5.2821
box max         9.6461    4.9512   19.7413
volume          465.9287
watertight  F   manifold F
saved dragon-ascii.stl

What you learned

load_from_file reads an STL and analyzes it; accessors and the validity predicates tell what kind of surface you have. Reference: surface_stl_object.

Next: 2. Repairing the surface.