add support for reading binary STL files

This commit is contained in:
Axel Kohlmeyer
2022-05-13 12:18:22 -04:00
parent 4cc3bdd35f
commit c41ad91a9d
2 changed files with 62 additions and 16 deletions

View File

@ -21,7 +21,7 @@ Syntax
*single* args = x y z
x,y,z = coordinates of a single particle (distance units)
*mesh* args = STL-file
STL-file = file with triangle mesh in ASCII STL format
STL-file = file with triangle mesh in STL format
*random* args = N seed region-ID
N = number of particles to create
seed = random # seed (positive integer)
@ -136,18 +136,20 @@ positions.
:align: right
:target: _images/marble_race.jpg
For the *mesh* style, a file with a triangle mesh in `ASCII STL format
<https://en.wikipedia.org/wiki/STL_(file_format)#ASCII_STL>`_ is read
and one or more particles are placed into the area of each triangle.
Binary STL files (e.g. as frequently offered for 3d-printing) can be
converted to ASCII with the :ref:`stl_bin2txt tool <stlconvert>`. The
use of the *units box* option is required. There are two algorithms for
placing atoms available: *bisect* and *qrand*. They can be selected via
the *meshmode* option; *bisect* is the default. If the atom style allows
to set a per-atom radius this radius is set to the average
distance of the triangle vertices from its center times the value of the
*radscale* keyword (default: 1.0). If the atom style supports it, the
atoms created from the mesh are assigned a new molecule ID.
For the *mesh* style, a file with a triangle mesh in `STL format
<https://en.wikipedia.org/wiki/STL_(file_format)>`_ is read and one or
more particles are placed into the area of each triangle. The reader
supports both ASCII and binary files conforming to the format on the
Wikipedia page. Binary STL files (e.g. as frequently offered for
3d-printing) also be first converted to ASCII for editing with the
:ref:`stl_bin2txt tool <stlconvert>`. The use of the *units box* option
is required. There are two algorithms for placing atoms available:
*bisect* and *qrand*. They can be selected via the *meshmode* option;
*bisect* is the default. If the atom style allows to set a per-atom
radius this radius is set to the average distance of the triangle
vertices from its center times the value of the *radscale* keyword
(default: 1.0). If the atom style supports it, the atoms created from
the mesh are assigned a new molecule ID.
In *bisect* mode a particle is created at the center of each triangle
unless the average distance of the triangle vertices from its center is

View File

@ -1036,9 +1036,11 @@ void CreateAtoms::add_mesh(const char *filename)
molid = maxmol + 1;
}
FILE *fp = fopen(filename, "r");
FILE *fp = fopen(filename, "rb");
if (fp == nullptr) error->one(FLERR, "Cannot open file {}: {}", filename, utils::getsyserror());
// first try reading the file in ASCII format
TextFileReader reader(fp, "STL mesh");
try {
char *line = reader.next_line();
@ -1047,7 +1049,7 @@ void CreateAtoms::add_mesh(const char *filename)
line += 6;
if (comm->me == 0)
utils::logmesg(lmp, "Reading STL object {} from file {}\n", utils::trim(line), filename);
utils::logmesg(lmp, "Reading STL object {} from text file {}\n", utils::trim(line), filename);
while ((line = reader.next_line())) {
@ -1092,8 +1094,50 @@ void CreateAtoms::add_mesh(const char *filename)
}
}
} catch (std::exception &e) {
// if ASCII failed for the first line, try reading as binary
if (utils::strmatch(e.what(), "^Invalid STL mesh file format")) {
char title[80];
float triangle[12];
uint32_t ntri;
uint16_t attr;
size_t count;
rewind(fp);
count = fread(title, sizeof(char), 80, fp);
title[79] = '\0';
count = fread(&ntri, sizeof(ntri), 1, fp);
if (count <= 0) {
error->all(FLERR, "Error reading STL file {}: {}", filename, utils::getsyserror());
} else {
if (comm->me == 0)
utils::logmesg(lmp, "Reading STL object {} from binary file {}\n", utils::trim(title),
filename);
}
for (uint32_t i = 0U; i < ntri; ++i) {
count = fread(triangle, sizeof(float), 12, fp);
if (count != 12)
error->all(FLERR, "Error reading STL file {}: {}", filename, utils::getsyserror());
count = fread(&attr, sizeof(attr), 1, fp);
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 3; ++k) vert[j][k] = triangle[3 * j + 3 + k];
++ntriangle;
if (mesh_style == BISECTION) {
// add in center of triangle or bisecting recursively along longest edge
// as needed to get the desired atom density/radii
atomlocal += add_bisection(vert, molid);
} else if (mesh_style == QUASIRANDOM) {
// add quasi-random distribution of atoms
atomlocal += add_quasirandom(vert, molid);
}
}
} else {
error->all(FLERR, "Error reading triangles from file {}: {}", filename, e.what());
}
}
if (ntriangle > 0) {
MPI_Allreduce(&atomlocal, &atomall, 1, MPI_LMP_BIGINT, MPI_SUM, world);