Reading data

Routines for parsing surface grids from files into EBGeometry’s DCEL grids (see Half-edge meshes (DCEL) for the concept, DCEL for the concrete API) – or directly into BVH-accelerated signed distance functions, including the triangle-mesh representation described conceptually in Triangle meshes – are given in the namespace EBGeometry::Parser. The source code is implemented in Source/EBGeometry_Parser.hpp.

Important

EBGeometry is currently limited to reading STL, PLY, OBJ, and VTK (legacy or XML polydata) files, and then reconstructing DCEL grids from those. PLY and VTK files can contain associated data on the nodes and faces, but this is not automatically populated when constructing the DCEL grids. It is also possible to build DCEL grids from polygon soups read using third-party codes (see Using third-party sources).

Quickstart

Every reader function in EBGeometry::Parser comes in two overloads: one that takes a single file name, and one that takes a std::vector<std::string> of file names and returns a vector of results, one per file. If you have one or multiple mesh files, the quickest way to turn them into BVH-accelerated signed distance fields is

std::vector<std::string> files; // <---- List of file names.

const auto distanceFields = EBGeometry::Parser::readIntoPackedBVH<float>(files);

This will build a DCEL mesh for each input file and wrap it in a MeshSDF, backed by a SIMD-accelerated PackedBVH over the mesh’s faces. See DCEL mesh SDF with PackedBVH for further details.

Tip

If the input files consist only of triangles, use the version

std::vector<std::string> files; // <---- List of file names.

const auto distanceFields = EBGeometry::Parser::readIntoTriangleBVH<float>(files);

This version will convert all DCEL polygons to triangles, pack them into SIMD-width groups, and usually provides a nice code speedup over readIntoPackedBVH.

Reading raw file data

At the lowest level, readPLY<T>, readSTL<T>, readOBJ<T>, and readVTK<T> (each with a single-filename and a std::vector<std::string> overload) parse a file into a raw, format-specific data structure (PLY<T>, STL<T>, OBJ<T>, or VTK<T>) holding nothing more than the vertex coordinates and face index lists as they appear in the file – no DCEL topology, no signed distance functionality. Two small helpers support this layer: getFileType inspects a file’s extension to determine which of the four formats it is (or FileType::Unsupported), and getFileEncoding inspects the file header to determine whether it is Encoding::ASCII or Encoding::Binary. Most users will not call these raw readers directly – they exist mainly as the common first step every readInto* function below builds on – but they are useful if you need the raw vertex/face data without paying for DCEL construction at all.

Note

If an STL file contains multiple solids (uncommon, but technically valid STL), readSTL only reads the first one.

For the raw readers’ exact signatures, see the Doxygen entries for readPLY, readSTL, readOBJ, and readVTK.

Reading mesh files

Above the raw per-format readers, EBGeometry offers five ways to turn a file directly into a higher-level representation, each doing progressively more work:

  1. Into a DCEL mesh, with no signed-distance functionality – readIntoDCEL, see DCEL.

  2. Into a bare DCEL signed distance function (FlatMeshSDF, \(O(N)\) scan, no BVH) – readIntoMesh.

  3. Into a signed distance function representation of a DCEL mesh, using a PackedBVH over DCEL faces (any polygon) – MeshSDF, via readIntoPackedBVH.

  4. Into a signed distance function representation of a triangle mesh, using a PackedBVH over SoA triangle groups – TriMeshSDF, via readIntoTriangleBVH.

  5. Into a flat, unconnected list of Triangle objects (each with precomputed vertex positions, normals, and edge normals, but no half-edge topology linking them) – via readIntoTriangles. Internally this still parses through a DCEL mesh first and then extracts each face as an independent Triangle; use it when you need per-triangle data as plain values (e.g. to feed your own acceleration structure) rather than any of EBGeometry’s own SDF wrappers.

See Mesh Signed Distance Function Classes for how the three SDF classes (options 2-4 above) compare.

Important

The EBGeometry parser will read input files into internal objects that represent each file type. Conversion of these objects into DCEL meshes is not required, and it is possible to create bounding volume hierarchies directly from the facets. This is useful when only an acceleration structure is needed for looking up facets or triangles, but no signed distance function is otherwise required.

DCEL representation

To read one or multiple files and turn it into DCEL meshes, use readIntoDCEL<T, Meta>(filename) (or the std::vector<std::string> overload for multiple files at once), returning a shared_ptr<DCEL::MeshT<T, Meta>> (or a vector thereof). Note that this will only expose the DCEL mesh, but not include any signed distance functionality.

DCEL mesh SDF

To read one or multiple files and also turn it into a bare (BVH-free) signed distance representation, use readIntoMesh<T, Meta>(filename), returning a shared_ptr<FlatMeshSDF<T, Meta>> (or a vector thereof for the multi-file overload).

DCEL mesh SDF with PackedBVH

readIntoPackedBVH<T, Meta, K>(filename, build) wraps a DCEL mesh in a PackedBVH (depth-first flat layout) with SIMD traversal, returning a shared_ptr<MeshSDF<T, Meta, K>> (or a vector thereof). It supports any polygon, not just triangles; the BVH branching factor K defaults to 4 and the build strategy a_build defaults to BVH::Build::SAH. For maximum throughput on triangle-only meshes, prefer readIntoTriangleBVH below.

Triangle meshes with PackedBVH

readIntoTriangleBVH<T, Meta, K, W>(filename, maxLeafGroups, build) converts all DCEL polygons to triangles, packs them into SoA groups of W, and builds a PackedBVH, returning a shared_ptr<TriMeshSDF<T, Meta, K, W>> (or a vector thereof). SIMD intrinsics evaluate up to W triangles per leaf visit. K and W default to the SIMD-optimal values for T on the current ISA (BVH::DefaultBranchingRatio<T>() and TriangleSoA::DefaultWidth<T>(), see Mesh Signed Distance Function Classes); maxLeafGroups (default 2) bounds the number of full W-sized SoA groups per BVH leaf. The code will raise an error if any face is not a triangle.

Flat triangle list

readIntoTriangles<T, Meta>(filename) returns a flat std::vector<shared_ptr<Triangle<T, Meta>>> (or, for the multi-file overload, one such vector per file) – every face of the parsed mesh as an independent, self-contained Triangle value, with no DCEL/half-edge topology connecting them. Use this when some other part of your code wants raw triangle values (for example, to build a custom acceleration structure) rather than any of EBGeometry’s own SDF wrappers.

Note

readIntoDCEL, readIntoMesh, readIntoPackedBVH, readIntoTriangleBVH, and readIntoTriangles are declared inline static in the header, so this project’s current Doxygen configuration (EXTRACT_STATIC = NO) does not extract them into the generated API reference individually – their exact signatures are documented via the Doxygen comment on each function directly in Source/EBGeometry_Parser.hpp. The raw per-format readers above (readPLY/readSTL/readOBJ/readVTK, declared without static) do not have this limitation and are linked individually.

From soups to DCEL

EBGeometry also supports the creation of DCEL grids from polygon soups, which can then later be turned into an SDF representation. A triangle soup is represented as

std::vector<Vec3T<T>> vertices;
std::vector<std::vector<size_t>> faces;

Here, vertices contains the \(x,y,z\) coordinates of each vertex, while each entry faces contains a list of vertices for the face.

Turning a soup into a DCEL mesh is a two- (optionally three-) step process, using the functions in namespace EBGeometry::Soup:

  • containsDegeneratePolygons(vertices, facets) is an optional up-front check: it returns true if any face has fewer than three vertices, or two or more vertices that coincide after lexicographic sorting. Useful for validating a soup produced by an external tool before spending time compressing/converting it.

  • compress(vertices, facets) discards duplicate vertices from the soup in place, updating facets to reference the compressed vertex list.

  • soupToDCEL(mesh, vertices, facets, id) builds the vertices, half-edges, and faces of the (already-compressed) soup into the output DCEL mesh, reconciles pair edges (internally, via reconcilePairEdgesDCEL, which links each half-edge \(u \to v\) to its reverse \(v \to u\)), and runs a mesh sanity check. This also computes the vertex and edge normal vectors.

Note

Every function in EBGeometry::Soup is also declared inline static, so – for the same reason noted above for the readInto* family – none of them currently appear individually in the generated Doxygen API reference; the namespace page exists but is effectively empty. Their exact signatures and contracts are documented via the Doxygen comment on each function directly in Source/EBGeometry_Soup.hpp.

Warning

soupToDCEL will issue plenty of warnings if the polygon soup is not watertight and orientable.

Using third-party sources

By design, EBGeometry does not include much functionality for parsing files into polygon soups. There are many open source third-party codes for achieving this (and we have tested several of them):

  1. happly or miniply for Stanford PLY files.

  2. stl_reader for STL files.

  3. tinyobjloader for OBJ files.

In almost every case, the above codes can be read into polygon soups, and one can then turn the soup into a DCEL mesh as described in From soups to DCEL.