- Extract predicates declarations into predicates.h - Extract I/O functions from tetgen.cxx into io.cxx - Remove duplicate helper functions from tetgen.cxx
2900 lines
99 KiB
C++
2900 lines
99 KiB
C++
//============================================================================//
|
|
// //
|
|
// TetGen //
|
|
// //
|
|
// A Quality Tetrahedral Mesh Generator and A 3D Delaunay Triangulator //
|
|
// //
|
|
// I/O Functions //
|
|
// //
|
|
//============================================================================//
|
|
|
|
#include "tetgen.h"
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_node_call() Read a list of points from a file. //
|
|
// //
|
|
// 'infile' is the file handle contains the node list. It may point to a //
|
|
// .node, or .poly or .smesh file. 'markers' indicates each node contains an //
|
|
// additional marker (integer) or not. 'uvflag' indicates each node contains //
|
|
// u,v coordinates or not. It is reuqired by a PSC. 'infilename' is the name //
|
|
// of the file being read, it is only used in error messages. //
|
|
// //
|
|
// The 'firstnumber' (0 or 1) is automatically determined by the number of //
|
|
// the first index of the first point. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_node_call(FILE* infile, int markers, int uvflag,
|
|
char* infilename)
|
|
{
|
|
char inputline[INPUTLINESIZE];
|
|
char *stringptr;
|
|
REAL x, y, z, attrib;
|
|
int firstnode, currentmarker;
|
|
int index, attribindex;
|
|
int i, j;
|
|
|
|
// Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
|
|
pointlist = new REAL[numberofpoints * 3];
|
|
if (pointlist == (REAL *) NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
if (numberofpointattributes > 0) {
|
|
pointattributelist = new REAL[numberofpoints * numberofpointattributes];
|
|
if (pointattributelist == (REAL *) NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
}
|
|
if (markers) {
|
|
pointmarkerlist = new int[numberofpoints];
|
|
if (pointmarkerlist == (int *) NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
}
|
|
if (uvflag) {
|
|
pointparamlist = new pointparam[numberofpoints];
|
|
if (pointparamlist == NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
}
|
|
|
|
// Read the point section.
|
|
index = 0;
|
|
attribindex = 0;
|
|
for (i = 0; i < numberofpoints; i++) {
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
if (useindex) {
|
|
if (i == 0) {
|
|
firstnode = (int) strtol (stringptr, &stringptr, 0);
|
|
if ((firstnode == 0) || (firstnode == 1)) {
|
|
firstnumber = firstnode;
|
|
}
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
} // if (useindex)
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
|
|
break;
|
|
}
|
|
x = (REAL) strtod(stringptr, &stringptr);
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
|
|
break;
|
|
}
|
|
y = (REAL) strtod(stringptr, &stringptr);
|
|
if (mesh_dim == 3) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
|
|
break;
|
|
}
|
|
z = (REAL) strtod(stringptr, &stringptr);
|
|
} else {
|
|
z = 0.0; // mesh_dim == 2;
|
|
}
|
|
pointlist[index++] = x;
|
|
pointlist[index++] = y;
|
|
pointlist[index++] = z;
|
|
// Read the point attributes.
|
|
for (j = 0; j < numberofpointattributes; j++) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
attrib = 0.0;
|
|
} else {
|
|
attrib = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
pointattributelist[attribindex++] = attrib;
|
|
}
|
|
if (markers) {
|
|
// Read a point marker.
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
currentmarker = 0;
|
|
} else {
|
|
currentmarker = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
pointmarkerlist[i] = currentmarker;
|
|
}
|
|
}
|
|
if (i < numberofpoints) {
|
|
// Failed to read points due to some error.
|
|
delete [] pointlist;
|
|
pointlist = (REAL *) NULL;
|
|
if (markers) {
|
|
delete [] pointmarkerlist;
|
|
pointmarkerlist = (int *) NULL;
|
|
}
|
|
if (numberofpointattributes > 0) {
|
|
delete [] pointattributelist;
|
|
pointattributelist = (REAL *) NULL;
|
|
}
|
|
if (uvflag) {
|
|
delete [] pointparamlist;
|
|
pointparamlist = NULL;
|
|
}
|
|
numberofpoints = 0;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_node() Load a list of points from a .node file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_node(char* filebasename)
|
|
{
|
|
FILE *infile;
|
|
char innodefilename[FILENAMESIZE];
|
|
char inputline[INPUTLINESIZE];
|
|
char *stringptr;
|
|
bool okflag;
|
|
int markers;
|
|
int uvflag; // for psc input.
|
|
|
|
// Assembling the actual file names we want to open.
|
|
strcpy(innodefilename, filebasename);
|
|
strcat(innodefilename, ".node");
|
|
|
|
// Try to open a .node file.
|
|
infile = fopen(innodefilename, "r");
|
|
if (infile == (FILE *) NULL) {
|
|
printf(" Cannot access file %s.\n", innodefilename);
|
|
return false;
|
|
}
|
|
printf("Opening %s.\n", innodefilename);
|
|
|
|
// Set initial flags.
|
|
mesh_dim = 3;
|
|
numberofpointattributes = 0; // no point attribute.
|
|
markers = 0; // no boundary marker.
|
|
uvflag = 0; // no uv parameters (required by a PSC).
|
|
|
|
// Read the first line of the file.
|
|
stringptr = readnumberline(inputline, infile, innodefilename);
|
|
// Does this file contain an index column?
|
|
stringptr = strstr(inputline, "rbox");
|
|
if (stringptr == NULL) {
|
|
// Read number of points, number of dimensions, number of point
|
|
// attributes, and number of boundary markers.
|
|
stringptr = inputline;
|
|
numberofpoints = (int) strtol (stringptr, &stringptr, 0);
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr != '\0') {
|
|
mesh_dim = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr != '\0') {
|
|
numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr != '\0') {
|
|
markers = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr != '\0') {
|
|
uvflag = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
} else {
|
|
// It is a rbox (qhull) input file.
|
|
stringptr = inputline;
|
|
// Get the dimension.
|
|
mesh_dim = (int) strtol (stringptr, &stringptr, 0);
|
|
// Get the number of points.
|
|
stringptr = readnumberline(inputline, infile, innodefilename);
|
|
numberofpoints = (int) strtol (stringptr, &stringptr, 0);
|
|
// There is no index column.
|
|
useindex = 0;
|
|
}
|
|
|
|
// Load the list of nodes.
|
|
okflag = load_node_call(infile, markers, uvflag, innodefilename);
|
|
|
|
fclose(infile);
|
|
return okflag;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_edge() Load a list of edges from a .edge file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_edge(char* filebasename)
|
|
{
|
|
FILE *infile;
|
|
char inedgefilename[FILENAMESIZE];
|
|
char inputline[INPUTLINESIZE];
|
|
char *stringptr;
|
|
int markers, corner;
|
|
int index;
|
|
int i, j;
|
|
|
|
strcpy(inedgefilename, filebasename);
|
|
strcat(inedgefilename, ".edge");
|
|
|
|
infile = fopen(inedgefilename, "r");
|
|
if (infile != (FILE *) NULL) {
|
|
printf("Opening %s.\n", inedgefilename);
|
|
} else {
|
|
//printf(" Cannot access file %s.\n", inedgefilename);
|
|
return false;
|
|
}
|
|
|
|
// Read number of boundary edges.
|
|
stringptr = readnumberline(inputline, infile, inedgefilename);
|
|
numberofedges = (int) strtol (stringptr, &stringptr, 0);
|
|
if (numberofedges > 0) {
|
|
edgelist = new int[numberofedges * 2];
|
|
if (edgelist == (int *) NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
markers = 0; // Default value.
|
|
} else {
|
|
markers = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
if (markers > 0) {
|
|
edgemarkerlist = new int[numberofedges];
|
|
}
|
|
}
|
|
|
|
// Read the list of edges.
|
|
index = 0;
|
|
for (i = 0; i < numberofedges; i++) {
|
|
// Read edge index and the edge's two endpoints.
|
|
stringptr = readnumberline(inputline, infile, inedgefilename);
|
|
for (j = 0; j < 2; j++) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Edge %d is missing vertex %d in %s.\n",
|
|
i + firstnumber, j + 1, inedgefilename);
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
corner = (int) strtol(stringptr, &stringptr, 0);
|
|
if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
|
|
printf("Error: Edge %d has an invalid vertex index.\n",
|
|
i + firstnumber);
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
edgelist[index++] = corner;
|
|
}
|
|
if (numberofcorners == 10) {
|
|
// Skip an extra vertex (generated by a previous -o2 option).
|
|
stringptr = findnextnumber(stringptr);
|
|
}
|
|
// Read the edge marker if it has.
|
|
if (markers) {
|
|
stringptr = findnextnumber(stringptr);
|
|
edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0);
|
|
}
|
|
}
|
|
|
|
fclose(infile);
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_face() Load a list of faces (triangles) from a .face file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_face(char* filebasename)
|
|
{
|
|
FILE *infile;
|
|
char infilename[FILENAMESIZE];
|
|
char inputline[INPUTLINESIZE];
|
|
char *stringptr;
|
|
REAL attrib;
|
|
int markers, corner;
|
|
int index;
|
|
int i, j;
|
|
|
|
strcpy(infilename, filebasename);
|
|
strcat(infilename, ".face");
|
|
|
|
infile = fopen(infilename, "r");
|
|
if (infile != (FILE *) NULL) {
|
|
printf("Opening %s.\n", infilename);
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
// Read number of faces, boundary markers.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
|
|
stringptr = findnextnumber(stringptr);
|
|
if (mesh_dim == 2) {
|
|
// Skip a number.
|
|
stringptr = findnextnumber(stringptr);
|
|
}
|
|
if (*stringptr == '\0') {
|
|
markers = 0; // Default there is no marker per face.
|
|
} else {
|
|
markers = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
if (numberoftrifaces > 0) {
|
|
trifacelist = new int[numberoftrifaces * 3];
|
|
if (trifacelist == (int *) NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
if (markers) {
|
|
trifacemarkerlist = new int[numberoftrifaces];
|
|
if (trifacemarkerlist == (int *) NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read the list of faces.
|
|
index = 0;
|
|
for (i = 0; i < numberoftrifaces; i++) {
|
|
// Read face index and the face's three corners.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
for (j = 0; j < 3; j++) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Face %d is missing vertex %d in %s.\n",
|
|
i + firstnumber, j + 1, infilename);
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
corner = (int) strtol(stringptr, &stringptr, 0);
|
|
if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
|
|
printf("Error: Face %d has an invalid vertex index.\n",
|
|
i + firstnumber);
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
trifacelist[index++] = corner;
|
|
}
|
|
if (numberofcorners == 10) {
|
|
// Skip 3 extra vertices (generated by a previous -o2 option).
|
|
for (j = 0; j < 3; j++) {
|
|
stringptr = findnextnumber(stringptr);
|
|
}
|
|
}
|
|
// Read the boundary marker if it exists.
|
|
if (markers) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
attrib = 0.0;
|
|
} else {
|
|
attrib = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
trifacemarkerlist[i] = (int) attrib;
|
|
}
|
|
}
|
|
|
|
fclose(infile);
|
|
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_tet() Load a list of tetrahedra from a .ele file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_tet(char* filebasename)
|
|
{
|
|
FILE *infile;
|
|
char infilename[FILENAMESIZE];
|
|
char inputline[INPUTLINESIZE];
|
|
char *stringptr;
|
|
REAL attrib;
|
|
int corner;
|
|
int index, attribindex;
|
|
int i, j;
|
|
|
|
strcpy(infilename, filebasename);
|
|
strcat(infilename, ".ele");
|
|
|
|
infile = fopen(infilename, "r");
|
|
if (infile != (FILE *) NULL) {
|
|
printf("Opening %s.\n", infilename);
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
// Read number of elements, number of corners (4 or 10), number of
|
|
// element attributes.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
|
|
if (numberoftetrahedra <= 0) {
|
|
printf("Error: Invalid number of tetrahedra.\n");
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
numberofcorners = 4; // Default read 4 nodes per element.
|
|
} else {
|
|
numberofcorners = (int) strtol(stringptr, &stringptr, 0);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
numberoftetrahedronattributes = 0; // Default no attribute.
|
|
} else {
|
|
numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
|
|
}
|
|
if (numberofcorners != 4 && numberofcorners != 10) {
|
|
printf("Error: Wrong number of corners %d (should be 4 or 10).\n",
|
|
numberofcorners);
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
|
|
// Allocate memory for tetrahedra.
|
|
tetrahedronlist = new int[numberoftetrahedra * numberofcorners];
|
|
if (tetrahedronlist == (int *) NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
// Allocate memory for output tetrahedron attributes if necessary.
|
|
if (numberoftetrahedronattributes > 0) {
|
|
tetrahedronattributelist = new REAL[numberoftetrahedra *
|
|
numberoftetrahedronattributes];
|
|
if (tetrahedronattributelist == (REAL *) NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
}
|
|
|
|
// Read the list of tetrahedra.
|
|
index = 0;
|
|
attribindex = 0;
|
|
for (i = 0; i < numberoftetrahedra; i++) {
|
|
// Read tetrahedron index and the tetrahedron's corners.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
for (j = 0; j < numberofcorners; j++) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Tetrahedron %d is missing vertex %d in %s.\n",
|
|
i + firstnumber, j + 1, infilename);
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
corner = (int) strtol(stringptr, &stringptr, 0);
|
|
if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
|
|
printf("Error: Tetrahedron %d has an invalid vertex index.\n",
|
|
i + firstnumber);
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
tetrahedronlist[index++] = corner;
|
|
}
|
|
// Read the tetrahedron's attributes.
|
|
for (j = 0; j < numberoftetrahedronattributes; j++) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
attrib = 0.0;
|
|
} else {
|
|
attrib = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
tetrahedronattributelist[attribindex++] = attrib;
|
|
}
|
|
}
|
|
|
|
fclose(infile);
|
|
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_vol() Load a list of volume constraints from a .vol file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_vol(char* filebasename)
|
|
{
|
|
FILE *infile;
|
|
char inelefilename[FILENAMESIZE];
|
|
char infilename[FILENAMESIZE];
|
|
char inputline[INPUTLINESIZE];
|
|
char *stringptr;
|
|
REAL volume;
|
|
int volelements;
|
|
int i;
|
|
|
|
strcpy(infilename, filebasename);
|
|
strcat(infilename, ".vol");
|
|
|
|
infile = fopen(infilename, "r");
|
|
if (infile != (FILE *) NULL) {
|
|
printf("Opening %s.\n", infilename);
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
// Read number of tetrahedra.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
volelements = (int) strtol (stringptr, &stringptr, 0);
|
|
if (volelements != numberoftetrahedra) {
|
|
strcpy(inelefilename, filebasename);
|
|
strcat(infilename, ".ele");
|
|
printf("Warning: %s and %s disagree on number of tetrahedra.\n",
|
|
inelefilename, infilename);
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
|
|
tetrahedronvolumelist = new REAL[volelements];
|
|
if (tetrahedronvolumelist == (REAL *) NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
|
|
// Read the list of volume constraints.
|
|
for (i = 0; i < volelements; i++) {
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
volume = -1.0; // No constraint on this tetrahedron.
|
|
} else {
|
|
volume = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
tetrahedronvolumelist[i] = volume;
|
|
}
|
|
|
|
fclose(infile);
|
|
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_var() Load constraints applied on facets, segments, and nodes //
|
|
// from a .var file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_var(char* filebasename)
|
|
{
|
|
FILE *infile;
|
|
char varfilename[FILENAMESIZE];
|
|
char inputline[INPUTLINESIZE];
|
|
char *stringptr;
|
|
int index;
|
|
int i;
|
|
|
|
// Variant constraints are saved in file "filename.var".
|
|
strcpy(varfilename, filebasename);
|
|
strcat(varfilename, ".var");
|
|
infile = fopen(varfilename, "r");
|
|
if (infile != (FILE *) NULL) {
|
|
printf("Opening %s.\n", varfilename);
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
// Read the facet constraint section.
|
|
stringptr = readnumberline(inputline, infile, varfilename);
|
|
if (stringptr == NULL) {
|
|
// No region list, return.
|
|
fclose(infile);
|
|
return true;
|
|
}
|
|
if (*stringptr != '\0') {
|
|
numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0);
|
|
} else {
|
|
numberoffacetconstraints = 0;
|
|
}
|
|
if (numberoffacetconstraints > 0) {
|
|
// Initialize 'facetconstraintlist'.
|
|
facetconstraintlist = new REAL[numberoffacetconstraints * 2];
|
|
index = 0;
|
|
for (i = 0; i < numberoffacetconstraints; i++) {
|
|
stringptr = readnumberline(inputline, infile, varfilename);
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: facet constraint %d has no facet marker.\n",
|
|
firstnumber + i);
|
|
break;
|
|
} else {
|
|
facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: facet constraint %d has no maximum area bound.\n",
|
|
firstnumber + i);
|
|
break;
|
|
} else {
|
|
facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
}
|
|
if (i < numberoffacetconstraints) {
|
|
// This must be caused by an error.
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Read the segment constraint section.
|
|
stringptr = readnumberline(inputline, infile, varfilename);
|
|
if (stringptr == NULL) {
|
|
// No segment list, return.
|
|
fclose(infile);
|
|
return true;
|
|
}
|
|
if (*stringptr != '\0') {
|
|
numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0);
|
|
} else {
|
|
numberofsegmentconstraints = 0;
|
|
}
|
|
if (numberofsegmentconstraints > 0) {
|
|
// Initialize 'segmentconstraintlist'.
|
|
segmentconstraintlist = new REAL[numberofsegmentconstraints * 3];
|
|
index = 0;
|
|
for (i = 0; i < numberofsegmentconstraints; i++) {
|
|
stringptr = readnumberline(inputline, infile, varfilename);
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: segment constraint %d has no frist endpoint.\n",
|
|
firstnumber + i);
|
|
break;
|
|
} else {
|
|
segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: segment constraint %d has no second endpoint.\n",
|
|
firstnumber + i);
|
|
break;
|
|
} else {
|
|
segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: segment constraint %d has no maximum length bound.\n",
|
|
firstnumber + i);
|
|
break;
|
|
} else {
|
|
segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
}
|
|
if (i < numberofsegmentconstraints) {
|
|
// This must be caused by an error.
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
fclose(infile);
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_mtr() Load a size specification map from a .mtr file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_mtr(char* filebasename)
|
|
{
|
|
FILE *infile;
|
|
char mtrfilename[FILENAMESIZE];
|
|
char inputline[INPUTLINESIZE];
|
|
char *stringptr;
|
|
REAL mtr;
|
|
int ptnum;
|
|
int mtrindex;
|
|
int i, j;
|
|
|
|
strcpy(mtrfilename, filebasename);
|
|
strcat(mtrfilename, ".mtr");
|
|
infile = fopen(mtrfilename, "r");
|
|
if (infile != (FILE *) NULL) {
|
|
printf("Opening %s.\n", mtrfilename);
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
// Read the number of points.
|
|
stringptr = readnumberline(inputline, infile, mtrfilename);
|
|
ptnum = (int) strtol (stringptr, &stringptr, 0);
|
|
if (ptnum != numberofpoints) {
|
|
printf(" !! Point numbers are not equal. Ignored.\n");
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
// Read the number of columns (1, 3, or 6).
|
|
stringptr = findnextnumber(stringptr); // Skip number of points.
|
|
if (*stringptr != '\0') {
|
|
numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
if ((numberofpointmtrs != 1) && (numberofpointmtrs != 3) &&
|
|
(numberofpointmtrs != 6)) {
|
|
// Column number doesn't match.
|
|
numberofpointmtrs = 0;
|
|
printf(" !! Metric size does not match (1, 3, or 6). Ignored.\n");
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
|
|
// Allocate space for pointmtrlist.
|
|
pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
|
|
if (pointmtrlist == (REAL *) NULL) {
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
mtrindex = 0;
|
|
for (i = 0; i < numberofpoints; i++) {
|
|
// Read metrics.
|
|
stringptr = readnumberline(inputline, infile, mtrfilename);
|
|
for (j = 0; j < numberofpointmtrs; j++) {
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Metric %d is missing value #%d in %s.\n",
|
|
i + firstnumber, j + 1, mtrfilename);
|
|
terminatetetgen(NULL, 1);
|
|
}
|
|
mtr = (REAL) strtod(stringptr, &stringptr);
|
|
pointmtrlist[mtrindex++] = mtr;
|
|
stringptr = findnextnumber(stringptr);
|
|
}
|
|
}
|
|
|
|
fclose(infile);
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_elem() Load a list of refine elements from an .elem file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_elem(char* filebasename)
|
|
{
|
|
FILE *infile;
|
|
char inelemfilename[FILENAMESIZE];
|
|
char line[1024];
|
|
|
|
strcpy(inelemfilename, filebasename);
|
|
strcat(inelemfilename, ".elem");
|
|
|
|
// Try to open a .elem file.
|
|
infile = fopen(inelemfilename, "r");
|
|
if (infile != (FILE *) NULL) {
|
|
printf("Opening %s.\n", inelemfilename);
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
int elenum = 0;
|
|
float growth_ratio = 0.;
|
|
fgets(line, 1023, infile);
|
|
sscanf(line, "%d %f", &elenum, &growth_ratio);
|
|
|
|
if (elenum == 0) {
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
|
|
refine_elem_list = new int[elenum * 4];
|
|
numberofrefineelems = elenum;
|
|
|
|
int *idx, i;
|
|
for (i = 0; i < elenum; i++) {
|
|
fgets(line, 1023, infile);
|
|
idx = &(refine_elem_list[i*4]);
|
|
sscanf(line, "%d %d %d %d", &(idx[0]), &(idx[1]), &(idx[2]), &(idx[3]));
|
|
}
|
|
|
|
fclose(infile);
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_poly() Load a PL complex from a .poly or a .smesh file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_poly(char* filebasename)
|
|
{
|
|
FILE *infile;
|
|
char inpolyfilename[FILENAMESIZE];
|
|
char insmeshfilename[FILENAMESIZE];
|
|
char inputline[INPUTLINESIZE];
|
|
char *stringptr, *infilename;
|
|
int smesh, markers, uvflag, currentmarker;
|
|
int index;
|
|
int i, j, k;
|
|
|
|
// Assembling the actual file names we want to open.
|
|
strcpy(inpolyfilename, filebasename);
|
|
strcpy(insmeshfilename, filebasename);
|
|
strcat(inpolyfilename, ".poly");
|
|
strcat(insmeshfilename, ".smesh");
|
|
|
|
// First assume it is a .poly file.
|
|
smesh = 0;
|
|
// Try to open a .poly file.
|
|
infile = fopen(inpolyfilename, "r");
|
|
if (infile == (FILE *) NULL) {
|
|
// .poly doesn't exist! Try to open a .smesh file.
|
|
infile = fopen(insmeshfilename, "r");
|
|
if (infile == (FILE *) NULL) {
|
|
printf(" Cannot access file %s and %s.\n",
|
|
inpolyfilename, insmeshfilename);
|
|
return false;
|
|
} else {
|
|
printf("Opening %s.\n", insmeshfilename);
|
|
infilename = insmeshfilename;
|
|
}
|
|
smesh = 1;
|
|
} else {
|
|
printf("Opening %s.\n", inpolyfilename);
|
|
infilename = inpolyfilename;
|
|
}
|
|
|
|
// Initialize the default values.
|
|
mesh_dim = 3; // Three-dimensional coordinates.
|
|
numberofpointattributes = 0; // no point attribute.
|
|
markers = 0; // no boundary marker.
|
|
uvflag = 0; // no uv parameters (required by a PSC).
|
|
|
|
// Read number of points, number of dimensions, number of point
|
|
// attributes, and number of boundary markers.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
numberofpoints = (int) strtol (stringptr, &stringptr, 0);
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr != '\0') {
|
|
mesh_dim = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr != '\0') {
|
|
numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr != '\0') {
|
|
markers = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
if (*stringptr != '\0') {
|
|
uvflag = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
|
|
if (numberofpoints > 0) {
|
|
// Load the list of nodes.
|
|
if (!load_node_call(infile, markers, uvflag, infilename)) {
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
} else {
|
|
// If the .poly or .smesh file claims there are zero points, that
|
|
// means the points should be read from a separate .node file.
|
|
if (!load_node(filebasename)) {
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if ((mesh_dim != 3) && (mesh_dim != 2)) {
|
|
printf("Input error: TetGen only works for 2D & 3D point sets.\n");
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
if (numberofpoints < (mesh_dim + 1)) {
|
|
printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1);
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
|
|
facet *f;
|
|
polygon *p;
|
|
|
|
if (mesh_dim == 3) {
|
|
|
|
// Read number of facets and number of boundary markers.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
if (stringptr == NULL) {
|
|
// No facet list, return.
|
|
fclose(infile);
|
|
return true;
|
|
}
|
|
numberoffacets = (int) strtol (stringptr, &stringptr, 0);
|
|
if (numberoffacets <= 0) {
|
|
// No facet list, return.
|
|
fclose(infile);
|
|
return true;
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
markers = 0; // no boundary marker.
|
|
} else {
|
|
markers = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
|
|
// Initialize the 'facetlist', 'facetmarkerlist'.
|
|
facetlist = new facet[numberoffacets];
|
|
if (markers == 1) {
|
|
facetmarkerlist = new int[numberoffacets];
|
|
}
|
|
|
|
// Read data into 'facetlist', 'facetmarkerlist'.
|
|
if (smesh == 0) {
|
|
// Facets are in .poly file format.
|
|
for (i = 1; i <= numberoffacets; i++) {
|
|
f = &(facetlist[i - 1]);
|
|
init(f);
|
|
f->numberofholes = 0;
|
|
currentmarker = 0;
|
|
// Read number of polygons, number of holes, and a boundary marker.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr != '\0') {
|
|
f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
|
|
if (markers == 1) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr != '\0') {
|
|
currentmarker = (int) strtol(stringptr, &stringptr, 0);
|
|
}
|
|
}
|
|
}
|
|
// Initialize facetmarker if it needs.
|
|
if (markers == 1) {
|
|
facetmarkerlist[i - 1] = currentmarker;
|
|
}
|
|
// Each facet should has at least one polygon.
|
|
if (f->numberofpolygons <= 0) {
|
|
printf("Error: Wrong number of polygon in %d facet.\n", i);
|
|
break;
|
|
}
|
|
// Initialize the 'f->polygonlist'.
|
|
f->polygonlist = new polygon[f->numberofpolygons];
|
|
// Go through all polygons, read in their vertices.
|
|
for (j = 1; j <= f->numberofpolygons; j++) {
|
|
p = &(f->polygonlist[j - 1]);
|
|
init(p);
|
|
// Read number of vertices of this polygon.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
|
|
if (p->numberofvertices < 1) {
|
|
printf("Error: Wrong polygon %d in facet %d\n", j, i);
|
|
break;
|
|
}
|
|
// Initialize 'p->vertexlist'.
|
|
p->vertexlist = new int[p->numberofvertices];
|
|
// Read all vertices of this polygon.
|
|
for (k = 1; k <= p->numberofvertices; k++) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
// Try to load another non-empty line and continue to read the
|
|
// rest of vertices.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Missing %d endpoints of polygon %d in facet %d",
|
|
p->numberofvertices - k, j, i);
|
|
break;
|
|
}
|
|
}
|
|
p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
}
|
|
if (j <= f->numberofpolygons) {
|
|
// This must be caused by an error. However, there're j - 1
|
|
// polygons have been read. Reset the 'f->numberofpolygon'.
|
|
if (j == 1) {
|
|
// This is the first polygon.
|
|
delete [] f->polygonlist;
|
|
}
|
|
f->numberofpolygons = j - 1;
|
|
// No hole will be read even it exists.
|
|
f->numberofholes = 0;
|
|
break;
|
|
}
|
|
// If this facet has hole pints defined, read them.
|
|
if (f->numberofholes > 0) {
|
|
// Initialize 'f->holelist'.
|
|
f->holelist = new REAL[f->numberofholes * 3];
|
|
// Read the holes' coordinates.
|
|
index = 0;
|
|
for (j = 1; j <= f->numberofholes; j++) {
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
for (k = 1; k <= 3; k++) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Hole %d in facet %d has no coordinates", j, i);
|
|
break;
|
|
}
|
|
f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
|
|
}
|
|
if (k <= 3) {
|
|
// This must be caused by an error.
|
|
break;
|
|
}
|
|
}
|
|
if (j <= f->numberofholes) {
|
|
// This must be caused by an error.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (i <= numberoffacets) {
|
|
// This must be caused by an error.
|
|
numberoffacets = i - 1;
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
} else { // poly == 0
|
|
// Read the facets from a .smesh file.
|
|
for (i = 1; i <= numberoffacets; i++) {
|
|
f = &(facetlist[i - 1]);
|
|
init(f);
|
|
// Initialize 'f->facetlist'. In a .smesh file, each facetlist only
|
|
// contains exactly one polygon, no hole.
|
|
f->numberofpolygons = 1;
|
|
f->polygonlist = new polygon[f->numberofpolygons];
|
|
p = &(f->polygonlist[0]);
|
|
init(p);
|
|
// Read number of vertices of this polygon.
|
|
stringptr = readnumberline(inputline, infile, insmeshfilename);
|
|
p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
|
|
if (p->numberofvertices < 1) {
|
|
printf("Error: Wrong number of vertex in facet %d\n", i);
|
|
break;
|
|
}
|
|
// Initialize 'p->vertexlist'.
|
|
p->vertexlist = new int[p->numberofvertices];
|
|
for (k = 1; k <= p->numberofvertices; k++) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
// Try to load another non-empty line and continue to read the
|
|
// rest of vertices.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Missing %d endpoints in facet %d",
|
|
p->numberofvertices - k, i);
|
|
break;
|
|
}
|
|
}
|
|
p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
|
|
}
|
|
if (k <= p->numberofvertices) {
|
|
// This must be caused by an error.
|
|
break;
|
|
}
|
|
// Read facet's boundary marker at last.
|
|
if (markers == 1) {
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
currentmarker = 0;
|
|
} else {
|
|
currentmarker = (int) strtol(stringptr, &stringptr, 0);
|
|
}
|
|
facetmarkerlist[i - 1] = currentmarker;
|
|
}
|
|
}
|
|
if (i <= numberoffacets) {
|
|
// This must be caused by an error.
|
|
numberoffacets = i - 1;
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Read the hole section.
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
if (stringptr == NULL) {
|
|
// No hole list, return.
|
|
fclose(infile);
|
|
return true;
|
|
}
|
|
if (*stringptr != '\0') {
|
|
numberofholes = (int) strtol (stringptr, &stringptr, 0);
|
|
} else {
|
|
numberofholes = 0;
|
|
}
|
|
if (numberofholes > 0) {
|
|
// Initialize 'holelist'.
|
|
holelist = new REAL[numberofholes * 3];
|
|
for (i = 0; i < 3 * numberofholes; i += 3) {
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Hole %d has no x coord.\n", firstnumber + (i / 3));
|
|
break;
|
|
} else {
|
|
holelist[i] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Hole %d has no y coord.\n", firstnumber + (i / 3));
|
|
break;
|
|
} else {
|
|
holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Hole %d has no z coord.\n", firstnumber + (i / 3));
|
|
break;
|
|
} else {
|
|
holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
}
|
|
if (i < 3 * numberofholes) {
|
|
// This must be caused by an error.
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Read the region section. The 'region' section is optional, if we
|
|
// don't reach the end-of-file, try read it in.
|
|
stringptr = readnumberline(inputline, infile, NULL);
|
|
if (stringptr != (char *) NULL && *stringptr != '\0') {
|
|
numberofregions = (int) strtol (stringptr, &stringptr, 0);
|
|
} else {
|
|
numberofregions = 0;
|
|
}
|
|
if (numberofregions > 0) {
|
|
// Initialize 'regionlist'.
|
|
regionlist = new REAL[numberofregions * 5];
|
|
index = 0;
|
|
for (i = 0; i < numberofregions; i++) {
|
|
stringptr = readnumberline(inputline, infile, infilename);
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Region %d has no x coordinate.\n", firstnumber + i);
|
|
break;
|
|
} else {
|
|
regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Region %d has no y coordinate.\n", firstnumber + i);
|
|
break;
|
|
} else {
|
|
regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Region %d has no z coordinate.\n", firstnumber + i);
|
|
break;
|
|
} else {
|
|
regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
printf("Error: Region %d has no region attrib.\n", firstnumber + i);
|
|
break;
|
|
} else {
|
|
regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
stringptr = findnextnumber(stringptr);
|
|
if (*stringptr == '\0') {
|
|
regionlist[index] = regionlist[index - 1];
|
|
} else {
|
|
regionlist[index] = (REAL) strtod(stringptr, &stringptr);
|
|
}
|
|
index++;
|
|
}
|
|
if (i < numberofregions) {
|
|
// This must be caused by an error.
|
|
fclose(infile);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// End of reading poly/smesh file.
|
|
fclose(infile);
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_off() Load a polyhedron from a .off file. //
|
|
// //
|
|
// The .off format is one of file formats of the Geomview, an interactive //
|
|
// program for viewing and manipulating geometric objects. More information //
|
|
// is available form: http://www.geomview.org. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_off(char* filebasename)
|
|
{
|
|
FILE *fp;
|
|
tetgenio::facet *f;
|
|
tetgenio::polygon *p;
|
|
char infilename[FILENAMESIZE];
|
|
char buffer[INPUTLINESIZE];
|
|
char *bufferp;
|
|
double *coord;
|
|
int nverts = 0, iverts = 0;
|
|
int nfaces = 0, ifaces = 0;
|
|
int nedges = 0;
|
|
int line_count = 0, i;
|
|
|
|
// Default, the off file's index is from '0'. We check it by remembering the
|
|
// smallest index we found in the file. It should be either 0 or 1.
|
|
int smallestidx = 0;
|
|
|
|
strncpy(infilename, filebasename, 1024 - 1);
|
|
infilename[FILENAMESIZE - 1] = '\0';
|
|
if (infilename[0] == '\0') {
|
|
printf("Error: No filename.\n");
|
|
return false;
|
|
}
|
|
if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
|
|
strcat(infilename, ".off");
|
|
}
|
|
|
|
if (!(fp = fopen(infilename, "r"))) {
|
|
printf(" Unable to open file %s\n", infilename);
|
|
return false;
|
|
}
|
|
printf("Opening %s.\n", infilename);
|
|
|
|
while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
|
|
// Check section
|
|
if (nverts == 0) {
|
|
// Read header
|
|
bufferp = strstr(bufferp, "OFF");
|
|
if (bufferp != NULL) {
|
|
// Read mesh counts
|
|
bufferp = findnextnumber(bufferp); // Skip field "OFF".
|
|
if (*bufferp == '\0') {
|
|
// Read a non-empty line.
|
|
bufferp = readline(buffer, fp, &line_count);
|
|
}
|
|
if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3)
|
|
|| (nverts == 0)) {
|
|
printf("Syntax error reading header on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
// Allocate memory for 'tetgenio'
|
|
if (nverts > 0) {
|
|
numberofpoints = nverts;
|
|
pointlist = new REAL[nverts * 3];
|
|
smallestidx = nverts + 1; // A bigger enough number.
|
|
}
|
|
if (nfaces > 0) {
|
|
numberoffacets = nfaces;
|
|
facetlist = new tetgenio::facet[nfaces];
|
|
}
|
|
}
|
|
} else if (iverts < nverts) {
|
|
// Read vertex coordinates
|
|
coord = &pointlist[iverts * 3];
|
|
for (i = 0; i < 3; i++) {
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading vertex coords on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
coord[i] = (REAL) strtod(bufferp, &bufferp);
|
|
bufferp = findnextnumber(bufferp);
|
|
}
|
|
iverts++;
|
|
} else if (ifaces < nfaces) {
|
|
// Get next face
|
|
f = &facetlist[ifaces];
|
|
init(f);
|
|
// In .off format, each facet has one polygon, no hole.
|
|
f->numberofpolygons = 1;
|
|
f->polygonlist = new tetgenio::polygon[1];
|
|
p = &f->polygonlist[0];
|
|
init(p);
|
|
// Read the number of vertices, it should be greater than 0.
|
|
p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
|
|
if (p->numberofvertices == 0) {
|
|
printf("Syntax error reading polygon on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
// Allocate memory for face vertices
|
|
p->vertexlist = new int[p->numberofvertices];
|
|
for (i = 0; i < p->numberofvertices; i++) {
|
|
bufferp = findnextnumber(bufferp);
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading polygon on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
|
|
// Detect the smallest index.
|
|
if (p->vertexlist[i] < smallestidx) {
|
|
smallestidx = p->vertexlist[i];
|
|
}
|
|
}
|
|
ifaces++;
|
|
} else {
|
|
// Should never get here
|
|
printf("Found extra text starting at line %d in file %s\n", line_count,
|
|
infilename);
|
|
break;
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
// Decide the firstnumber of the index.
|
|
if (smallestidx == 0) {
|
|
firstnumber = 0;
|
|
} else if (smallestidx == 1) {
|
|
firstnumber = 1;
|
|
} else {
|
|
printf("A wrong smallest index (%d) was detected in file %s\n",
|
|
smallestidx, infilename);
|
|
return false;
|
|
}
|
|
|
|
if (iverts != nverts) {
|
|
printf("Expected %d vertices, but read only %d vertices in file %s\n",
|
|
nverts, iverts, infilename);
|
|
return false;
|
|
}
|
|
if (ifaces != nfaces) {
|
|
printf("Expected %d faces, but read only %d faces in file %s\n",
|
|
nfaces, ifaces, infilename);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_ply() Load a polyhedron from a .ply file. //
|
|
// //
|
|
// This is a simplified version of reading .ply files, which only reads the //
|
|
// set of vertices and the set of faces. Other informations (such as color, //
|
|
// material, texture, etc) in .ply file are ignored. Complete routines for //
|
|
// reading and writing ,ply files are available from: http://www.cc.gatech. //
|
|
// edu/projects/large_models/ply.html. Except the header section, ply file //
|
|
// format has exactly the same format for listing vertices and polygons as //
|
|
// off file format. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_ply(char* filebasename)
|
|
{
|
|
FILE *fp;
|
|
tetgenio::facet *f;
|
|
tetgenio::polygon *p;
|
|
char infilename[FILENAMESIZE];
|
|
char buffer[INPUTLINESIZE];
|
|
char *bufferp, *str;
|
|
double *coord;
|
|
int endheader = 0, format = 0;
|
|
int nverts = 0, iverts = 0;
|
|
int nfaces = 0, ifaces = 0;
|
|
int line_count = 0, i;
|
|
|
|
// Default, the ply file's index is from '0'. We check it by remembering the
|
|
// smallest index we found in the file. It should be either 0 or 1.
|
|
int smallestidx = 0;
|
|
|
|
strncpy(infilename, filebasename, FILENAMESIZE - 1);
|
|
infilename[FILENAMESIZE - 1] = '\0';
|
|
if (infilename[0] == '\0') {
|
|
printf("Error: No filename.\n");
|
|
return false;
|
|
}
|
|
if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
|
|
strcat(infilename, ".ply");
|
|
}
|
|
|
|
if (!(fp = fopen(infilename, "r"))) {
|
|
printf("Error: Unable to open file %s\n", infilename);
|
|
return false;
|
|
}
|
|
printf("Opening %s.\n", infilename);
|
|
|
|
while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
|
|
if (!endheader) {
|
|
// Find if it is the keyword "end_header".
|
|
str = strstr(bufferp, "end_header");
|
|
// strstr() is case sensitive.
|
|
if (!str) str = strstr(bufferp, "End_header");
|
|
if (!str) str = strstr(bufferp, "End_Header");
|
|
if (str) {
|
|
// This is the end of the header section.
|
|
endheader = 1;
|
|
continue;
|
|
}
|
|
// Parse the number of vertices and the number of faces.
|
|
if (nverts == 0 || nfaces == 0) {
|
|
// Find if it si the keyword "element".
|
|
str = strstr(bufferp, "element");
|
|
if (!str) str = strstr(bufferp, "Element");
|
|
if (str) {
|
|
bufferp = findnextfield(str);
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading element type on line%d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
if (nverts == 0) {
|
|
// Find if it is the keyword "vertex".
|
|
str = strstr(bufferp, "vertex");
|
|
if (!str) str = strstr(bufferp, "Vertex");
|
|
if (str) {
|
|
bufferp = findnextnumber(str);
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading vertex number on line");
|
|
printf(" %d in file %s\n", line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
nverts = (int) strtol(bufferp, &bufferp, 0);
|
|
// Allocate memory for 'tetgenio'
|
|
if (nverts > 0) {
|
|
numberofpoints = nverts;
|
|
pointlist = new REAL[nverts * 3];
|
|
smallestidx = nverts + 1; // A big enough index.
|
|
}
|
|
}
|
|
}
|
|
if (nfaces == 0) {
|
|
// Find if it is the keyword "face".
|
|
str = strstr(bufferp, "face");
|
|
if (!str) str = strstr(bufferp, "Face");
|
|
if (str) {
|
|
bufferp = findnextnumber(str);
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading face number on line");
|
|
printf(" %d in file %s\n", line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
nfaces = (int) strtol(bufferp, &bufferp, 0);
|
|
// Allocate memory for 'tetgenio'
|
|
if (nfaces > 0) {
|
|
numberoffacets = nfaces;
|
|
facetlist = new tetgenio::facet[nfaces];
|
|
}
|
|
}
|
|
}
|
|
} // It is not the string "element".
|
|
}
|
|
if (format == 0) {
|
|
// Find the keyword "format".
|
|
str = strstr(bufferp, "format");
|
|
if (!str) str = strstr(bufferp, "Format");
|
|
if (str) {
|
|
format = 1;
|
|
bufferp = findnextfield(str);
|
|
// Find if it is the string "ascii".
|
|
str = strstr(bufferp, "ascii");
|
|
if (!str) str = strstr(bufferp, "ASCII");
|
|
if (!str) {
|
|
printf("This routine only reads ascii format of ply files.\n");
|
|
printf("Hint: You can convert the binary to ascii format by\n");
|
|
printf(" using the provided ply tools:\n");
|
|
printf(" ply2ascii < %s > ascii_%s\n", infilename, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
} else if (iverts < nverts) {
|
|
// Read vertex coordinates
|
|
coord = &pointlist[iverts * 3];
|
|
for (i = 0; i < 3; i++) {
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading vertex coords on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
coord[i] = (REAL) strtod(bufferp, &bufferp);
|
|
bufferp = findnextnumber(bufferp);
|
|
}
|
|
iverts++;
|
|
} else if (ifaces < nfaces) {
|
|
// Get next face
|
|
f = &facetlist[ifaces];
|
|
init(f);
|
|
// In .off format, each facet has one polygon, no hole.
|
|
f->numberofpolygons = 1;
|
|
f->polygonlist = new tetgenio::polygon[1];
|
|
p = &f->polygonlist[0];
|
|
init(p);
|
|
// Read the number of vertices, it should be greater than 0.
|
|
p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
|
|
if (p->numberofvertices == 0) {
|
|
printf("Syntax error reading polygon on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
// Allocate memory for face vertices
|
|
p->vertexlist = new int[p->numberofvertices];
|
|
for (i = 0; i < p->numberofvertices; i++) {
|
|
bufferp = findnextnumber(bufferp);
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading polygon on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
|
|
if (p->vertexlist[i] < smallestidx) {
|
|
smallestidx = p->vertexlist[i];
|
|
}
|
|
}
|
|
ifaces++;
|
|
} else {
|
|
// Should never get here
|
|
printf("Found extra text starting at line %d in file %s\n", line_count,
|
|
infilename);
|
|
break;
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
// Decide the firstnumber of the index.
|
|
if (smallestidx == 0) {
|
|
firstnumber = 0;
|
|
} else if (smallestidx == 1) {
|
|
firstnumber = 1;
|
|
} else {
|
|
printf("A wrong smallest index (%d) was detected in file %s\n",
|
|
smallestidx, infilename);
|
|
return false;
|
|
}
|
|
|
|
if (iverts != nverts) {
|
|
printf("Expected %d vertices, but read only %d vertices in file %s\n",
|
|
nverts, iverts, infilename);
|
|
return false;
|
|
}
|
|
if (ifaces != nfaces) {
|
|
printf("Expected %d faces, but read only %d faces in file %s\n",
|
|
nfaces, ifaces, infilename);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_stl() Load a surface mesh from a .stl file. //
|
|
// //
|
|
// The .stl or stereolithography format is an ASCII or binary file used in //
|
|
// manufacturing. It is a list of the triangular surfaces that describe a //
|
|
// computer generated solid model. This is the standard input for most rapid //
|
|
// prototyping machines. //
|
|
// //
|
|
// Comment: A .stl file many contain many duplicated points. They will be //
|
|
// unified during the Delaunay tetrahedralization process. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
static void SwapBytes(char *array, int size, int n)
|
|
{
|
|
char *x = new char[size];
|
|
for(int i = 0; i < n; i++) {
|
|
char *a = &array[i * size];
|
|
memcpy(x, a, size);
|
|
for(int c = 0; c < size; c++)
|
|
a[size - 1 - c] = x[c];
|
|
}
|
|
delete [] x;
|
|
}
|
|
|
|
bool tetgenio::load_stl(char* filebasename)
|
|
{
|
|
FILE *fp;
|
|
tetgenmesh::arraypool *plist;
|
|
tetgenio::facet *f;
|
|
tetgenio::polygon *p;
|
|
char infilename[FILENAMESIZE];
|
|
char buffer[INPUTLINESIZE];
|
|
char *bufferp, *str;
|
|
double *coord;
|
|
int solid = 0;
|
|
int nverts = 0, iverts = 0;
|
|
int nfaces = 0;
|
|
int line_count = 0, i;
|
|
|
|
strncpy(infilename, filebasename, FILENAMESIZE - 1);
|
|
infilename[FILENAMESIZE - 1] = '\0';
|
|
if (infilename[0] == '\0') {
|
|
printf("Error: No filename.\n");
|
|
return false;
|
|
}
|
|
if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
|
|
strcat(infilename, ".stl");
|
|
}
|
|
|
|
if (!(fp = fopen(infilename, "rb"))) {
|
|
printf("Error: Unable to open file %s\n", infilename);
|
|
return false;
|
|
}
|
|
printf("Opening %s.\n", infilename);
|
|
|
|
// "solid", or binary data header
|
|
if(!fgets(buffer, sizeof(buffer), fp)){ fclose(fp); return 0; }
|
|
bool binary = strncmp(buffer, "solid", 5) && strncmp(buffer, "SOLID", 5);
|
|
|
|
// STL file has no number of points available. Use a list to read points.
|
|
plist = new tetgenmesh::arraypool(sizeof(double) * 3, 10);
|
|
|
|
if(!binary){
|
|
solid = 1;
|
|
while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
|
|
// The ASCII .stl file must start with the lower case keyword solid and
|
|
// end with endsolid.
|
|
if (solid == 0) {
|
|
// Read header
|
|
bufferp = strstr(bufferp, "solid");
|
|
if (bufferp != NULL) {
|
|
solid = 1;
|
|
}
|
|
} else {
|
|
// We're inside the block of the solid.
|
|
str = bufferp;
|
|
// Is this the end of the solid.
|
|
bufferp = strstr(bufferp, "endsolid");
|
|
if (bufferp != NULL) {
|
|
solid = 0;
|
|
} else {
|
|
// Read the XYZ coordinates if it is a vertex.
|
|
bufferp = str;
|
|
bufferp = strstr(bufferp, "vertex");
|
|
if (bufferp != NULL) {
|
|
plist->newindex((void **) &coord);
|
|
for (i = 0; i < 3; i++) {
|
|
bufferp = findnextnumber(bufferp);
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading vertex coords on line %d\n",
|
|
line_count);
|
|
delete plist;
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
coord[i] = (REAL) strtod(bufferp, &bufferp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // if(!binary)
|
|
|
|
else {
|
|
rewind(fp);
|
|
while(!feof(fp)) {
|
|
char header[80];
|
|
if(!fread(header, sizeof(char), 80, fp)) break;
|
|
unsigned int nfacets = 0;
|
|
size_t ret = fread(&nfacets, sizeof(unsigned int), 1, fp);
|
|
bool swap = false;
|
|
if(nfacets > 100000000){
|
|
//Msg::Info("Swapping bytes from binary file");
|
|
swap = true;
|
|
SwapBytes((char*)&nfacets, sizeof(unsigned int), 1);
|
|
}
|
|
if(ret && nfacets){
|
|
//points.resize(points.size() + 1);
|
|
char *data = new char[nfacets * 50 * sizeof(char)];
|
|
ret = fread(data, sizeof(char), nfacets * 50, fp);
|
|
if(ret == nfacets * 50){
|
|
for(unsigned int i = 0; i < nfacets; i++) {
|
|
float *xyz = (float *)&data[i * 50 * sizeof(char)];
|
|
if(swap) SwapBytes((char*)xyz, sizeof(float), 12);
|
|
for(int j = 0; j < 3; j++){
|
|
//SPoint3 p(xyz[3 + 3 * j], xyz[3 + 3 * j + 1], xyz[3 + 3 * j + 2]);
|
|
//points.back().push_back(p);
|
|
//bbox += p;
|
|
plist->newindex((void **) &coord);
|
|
coord[0] = xyz[3 + 3 * j];
|
|
coord[1] = xyz[3 + 3 * j + 1];
|
|
coord[2] = xyz[3 + 3 * j + 2];
|
|
}
|
|
}
|
|
}
|
|
delete [] data;
|
|
}
|
|
} // while (!feof(fp))
|
|
} // binary
|
|
|
|
fclose(fp);
|
|
|
|
nverts = (int) plist->objects;
|
|
// nverts should be an integer times 3 (every 3 vertices denote a face).
|
|
if (nverts == 0 || (nverts % 3 != 0)) {
|
|
printf("Error: Wrong number of vertices in file %s.\n", infilename);
|
|
delete plist;
|
|
return false;
|
|
}
|
|
numberofpoints = nverts;
|
|
pointlist = new REAL[nverts * 3];
|
|
for (i = 0; i < nverts; i++) {
|
|
coord = (double *) fastlookup(plist, i);
|
|
iverts = i * 3;
|
|
pointlist[iverts] = (REAL) coord[0];
|
|
pointlist[iverts + 1] = (REAL) coord[1];
|
|
pointlist[iverts + 2] = (REAL) coord[2];
|
|
}
|
|
|
|
nfaces = (int) (nverts / 3);
|
|
numberoffacets = nfaces;
|
|
facetlist = new tetgenio::facet[nfaces];
|
|
|
|
// Default use '1' as the array starting index.
|
|
firstnumber = 1;
|
|
iverts = firstnumber;
|
|
for (i = 0; i < nfaces; i++) {
|
|
f = &facetlist[i];
|
|
init(f);
|
|
// In .stl format, each facet has one polygon, no hole.
|
|
f->numberofpolygons = 1;
|
|
f->polygonlist = new tetgenio::polygon[1];
|
|
p = &f->polygonlist[0];
|
|
init(p);
|
|
// Each polygon has three vertices.
|
|
p->numberofvertices = 3;
|
|
p->vertexlist = new int[p->numberofvertices];
|
|
p->vertexlist[0] = iverts;
|
|
p->vertexlist[1] = iverts + 1;
|
|
p->vertexlist[2] = iverts + 2;
|
|
iverts += 3;
|
|
}
|
|
|
|
delete plist;
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_medit() Load a surface mesh from a .mesh file. //
|
|
// //
|
|
// The .mesh format is the file format of Medit, a user-friendly interactive //
|
|
// mesh viewer program. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_medit(char* filebasename, int istetmesh)
|
|
{
|
|
FILE *fp;
|
|
tetgenio::facet *tmpflist, *f;
|
|
tetgenio::polygon *p;
|
|
char infilename[FILENAMESIZE];
|
|
char buffer[INPUTLINESIZE];
|
|
char *bufferp, *str;
|
|
double *coord;
|
|
int *tmpfmlist;
|
|
int dimension = 0;
|
|
int nverts = 0;
|
|
int nfaces = 0;
|
|
int ntets = 0;
|
|
int line_count = 0;
|
|
int corners = 0; // 3 (triangle) or 4 (quad).
|
|
int *plist;
|
|
int i, j;
|
|
|
|
int smallestidx = 0;
|
|
|
|
strncpy(infilename, filebasename, FILENAMESIZE - 1);
|
|
infilename[FILENAMESIZE - 1] = '\0';
|
|
if (infilename[0] == '\0') {
|
|
//printf("Error: No filename.\n");
|
|
return false;
|
|
}
|
|
if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
|
|
strcat(infilename, ".mesh");
|
|
}
|
|
|
|
if (!(fp = fopen(infilename, "r"))) {
|
|
//printf("Error: Unable to open file %s\n", infilename);
|
|
return false;
|
|
}
|
|
printf("Opening %s.\n", infilename);
|
|
|
|
while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
|
|
if (*bufferp == '#') continue; // A comment line is skipped.
|
|
if (dimension == 0) {
|
|
// Find if it is the keyword "Dimension".
|
|
str = strstr(bufferp, "Dimension");
|
|
if (!str) str = strstr(bufferp, "dimension");
|
|
if (!str) str = strstr(bufferp, "DIMENSION");
|
|
if (str) {
|
|
// Read the dimensions
|
|
bufferp = findnextnumber(str); // Skip field "Dimension".
|
|
if (*bufferp == '\0') {
|
|
// Read a non-empty line.
|
|
bufferp = readline(buffer, fp, &line_count);
|
|
}
|
|
dimension = (int) strtol(bufferp, &bufferp, 0);
|
|
if (dimension != 2 && dimension != 3) {
|
|
printf("Unknown dimension in file on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
mesh_dim = dimension;
|
|
}
|
|
}
|
|
if (nverts == 0) {
|
|
// Find if it is the keyword "Vertices".
|
|
str = strstr(bufferp, "Vertices");
|
|
if (!str) str = strstr(bufferp, "vertices");
|
|
if (!str) str = strstr(bufferp, "VERTICES");
|
|
if (str) {
|
|
// Read the number of vertices.
|
|
bufferp = findnextnumber(str); // Skip field "Vertices".
|
|
if (*bufferp == '\0') {
|
|
// Read a non-empty line.
|
|
bufferp = readline(buffer, fp, &line_count);
|
|
}
|
|
nverts = (int) strtol(bufferp, &bufferp, 0);
|
|
// Initialize the smallest index.
|
|
smallestidx = nverts + 1;
|
|
// Allocate memory for 'tetgenio'
|
|
if (nverts > 0) {
|
|
numberofpoints = nverts;
|
|
pointlist = new REAL[nverts * 3];
|
|
}
|
|
// Read the follwoing node list.
|
|
for (i = 0; i < nverts; i++) {
|
|
bufferp = readline(buffer, fp, &line_count);
|
|
if (bufferp == NULL) {
|
|
printf("Unexpected end of file on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
// Read vertex coordinates
|
|
coord = &pointlist[i * 3];
|
|
for (j = 0; j < 3; j++) {
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading vertex coords on line");
|
|
printf(" %d in file %s\n", line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
if ((j < 2) || (dimension == 3)) {
|
|
coord[j] = (REAL) strtod(bufferp, &bufferp);
|
|
} else {
|
|
coord[j] = 0.0;
|
|
}
|
|
bufferp = findnextnumber(bufferp);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
if ((ntets == 0) && istetmesh) { // Only read tetrahedra if 'istetmesh = 1'.
|
|
// Find if it is the keyword "Tetrahedra"
|
|
corners = 0;
|
|
str = strstr(bufferp, "Tetrahedra");
|
|
if (!str) str = strstr(bufferp, "tetrahedra");
|
|
if (!str) str = strstr(bufferp, "TETRAHEDRA");
|
|
if (str) {
|
|
corners = 4;
|
|
}
|
|
if (corners == 4) {
|
|
// Read the number of tetrahedra
|
|
bufferp = findnextnumber(str); // Skip field "Tetrahedra".
|
|
if (*bufferp == '\0') {
|
|
// Read a non-empty line.
|
|
bufferp = readline(buffer, fp, &line_count);
|
|
}
|
|
ntets = strtol(bufferp, &bufferp, 0);
|
|
if (ntets > 0) {
|
|
// It is a tetrahedral mesh.
|
|
numberoftetrahedra = ntets;
|
|
numberofcorners = 4;
|
|
numberoftetrahedronattributes = 1;
|
|
tetrahedronlist = new int[ntets * 4];
|
|
tetrahedronattributelist = new REAL[ntets];
|
|
}
|
|
} // if (corners == 4)
|
|
// Read the list of tetrahedra.
|
|
for (i = 0; i < numberoftetrahedra; i++) {
|
|
plist = &(tetrahedronlist[i * 4]);
|
|
bufferp = readline(buffer, fp, &line_count);
|
|
if (bufferp == NULL) {
|
|
printf("Unexpected end of file on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
// Read the vertices of the tet.
|
|
for (j = 0; j < corners; j++) {
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading face on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
plist[j] = (int) strtol(bufferp, &bufferp, 0);
|
|
// Remember the smallest index.
|
|
if (plist[j] < smallestidx) smallestidx = plist[j];
|
|
bufferp = findnextnumber(bufferp);
|
|
}
|
|
// Read the attribute of the tet if it exists.
|
|
tetrahedronattributelist[i] = 0;
|
|
if (*bufferp != '\0') {
|
|
tetrahedronattributelist[i] = (REAL) strtol(bufferp, &bufferp, 0);
|
|
}
|
|
} // i
|
|
} // Tetrahedra
|
|
if (nfaces == 0) {
|
|
// Find if it is the keyword "Triangles" or "Quadrilaterals".
|
|
corners = 0;
|
|
str = strstr(bufferp, "Triangles");
|
|
if (!str) str = strstr(bufferp, "triangles");
|
|
if (!str) str = strstr(bufferp, "TRIANGLES");
|
|
if (str) {
|
|
corners = 3;
|
|
} else {
|
|
str = strstr(bufferp, "Quadrilaterals");
|
|
if (!str) str = strstr(bufferp, "quadrilaterals");
|
|
if (!str) str = strstr(bufferp, "QUADRILATERALS");
|
|
if (str) {
|
|
corners = 4;
|
|
}
|
|
}
|
|
if (corners == 3 || corners == 4) {
|
|
// Read the number of triangles (or quadrilaterals).
|
|
bufferp = findnextnumber(str); // Skip field "Triangles".
|
|
if (*bufferp == '\0') {
|
|
// Read a non-empty line.
|
|
bufferp = readline(buffer, fp, &line_count);
|
|
}
|
|
nfaces = strtol(bufferp, &bufferp, 0);
|
|
// Allocate memory for 'tetgenio'
|
|
if (nfaces > 0) {
|
|
if (!istetmesh) {
|
|
// It is a PLC surface mesh.
|
|
if (numberoffacets > 0) {
|
|
// facetlist has already been allocated. Enlarge arrays.
|
|
// This happens when the surface mesh contains mixed cells.
|
|
tmpflist = new tetgenio::facet[numberoffacets + nfaces];
|
|
tmpfmlist = new int[numberoffacets + nfaces];
|
|
// Copy the data of old arrays into new arrays.
|
|
for (i = 0; i < numberoffacets; i++) {
|
|
f = &(tmpflist[i]);
|
|
tetgenio::init(f);
|
|
*f = facetlist[i];
|
|
tmpfmlist[i] = facetmarkerlist[i];
|
|
}
|
|
// Release old arrays.
|
|
delete [] facetlist;
|
|
delete [] facetmarkerlist;
|
|
// Remember the new arrays.
|
|
facetlist = tmpflist;
|
|
facetmarkerlist = tmpfmlist;
|
|
} else {
|
|
// This is the first time to allocate facetlist.
|
|
facetlist = new tetgenio::facet[nfaces];
|
|
facetmarkerlist = new int[nfaces];
|
|
}
|
|
} else {
|
|
if (corners == 3) {
|
|
// It is a surface mesh of a tetrahedral mesh.
|
|
numberoftrifaces = nfaces;
|
|
trifacelist = new int[nfaces * 3];
|
|
trifacemarkerlist = new int[nfaces];
|
|
}
|
|
}
|
|
} // if (nfaces > 0)
|
|
// Read the following list of faces.
|
|
if (!istetmesh) {
|
|
for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
|
|
bufferp = readline(buffer, fp, &line_count);
|
|
if (bufferp == NULL) {
|
|
printf("Unexpected end of file on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
f = &facetlist[i];
|
|
tetgenio::init(f);
|
|
// In .mesh format, each facet has one polygon, no hole.
|
|
f->numberofpolygons = 1;
|
|
f->polygonlist = new tetgenio::polygon[1];
|
|
p = &f->polygonlist[0];
|
|
tetgenio::init(p);
|
|
p->numberofvertices = corners;
|
|
// Allocate memory for face vertices
|
|
p->vertexlist = new int[p->numberofvertices];
|
|
// Read the vertices of the face.
|
|
for (j = 0; j < corners; j++) {
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading face on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0);
|
|
// Remember the smallest index.
|
|
if (p->vertexlist[j] < smallestidx) {
|
|
smallestidx = p->vertexlist[j];
|
|
}
|
|
bufferp = findnextnumber(bufferp);
|
|
}
|
|
// Read the marker of the face if it exists.
|
|
facetmarkerlist[i] = 0;
|
|
if (*bufferp != '\0') {
|
|
facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
|
|
}
|
|
}
|
|
// Have read in a list of triangles/quads.
|
|
numberoffacets += nfaces;
|
|
nfaces = 0;
|
|
} else {
|
|
// It is a surface mesh of a tetrahedral mesh.
|
|
if (corners == 3) {
|
|
for (i = 0; i < numberoftrifaces; i++) {
|
|
plist = &(trifacelist[i * 3]);
|
|
bufferp = readline(buffer, fp, &line_count);
|
|
if (bufferp == NULL) {
|
|
printf("Unexpected end of file on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
// Read the vertices of the face.
|
|
for (j = 0; j < corners; j++) {
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading face on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
plist[j] = (int) strtol(bufferp, &bufferp, 0);
|
|
// Remember the smallest index.
|
|
if (plist[j] < smallestidx) {
|
|
smallestidx = plist[j];
|
|
}
|
|
bufferp = findnextnumber(bufferp);
|
|
}
|
|
// Read the marker of the face if it exists.
|
|
trifacemarkerlist[i] = 0;
|
|
if (*bufferp != '\0') {
|
|
trifacemarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
|
|
}
|
|
} // i
|
|
} // if (corners == 3)
|
|
} // if (b->refine)
|
|
} // if (corners == 3 || corners == 4)
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
// Decide the firstnumber of the index.
|
|
if (smallestidx == 0) {
|
|
firstnumber = 0;
|
|
} else if (smallestidx == 1) {
|
|
firstnumber = 1;
|
|
} else {
|
|
printf("A wrong smallest index (%d) was detected in file %s\n",
|
|
smallestidx, infilename);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_vtk() Load VTK surface mesh from file (.vtk ascii or binary). //
|
|
// //
|
|
// This function is contributed by: Bryn Lloyd, Computer Vision Laboratory, //
|
|
// ETH, Zuerich. May 7, 2007. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
// Two inline functions used in read/write VTK files.
|
|
|
|
void swapBytes(unsigned char* var, int size)
|
|
{
|
|
int i = 0;
|
|
int j = size - 1;
|
|
char c;
|
|
|
|
while (i < j) {
|
|
c = var[i]; var[i] = var[j]; var[j] = c;
|
|
i++, j--;
|
|
}
|
|
}
|
|
|
|
bool testIsBigEndian()
|
|
{
|
|
short word = 0x4321;
|
|
if((*(char *)& word) != 0x21)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
bool tetgenio::load_vtk(char* filebasename)
|
|
{
|
|
FILE *fp;
|
|
tetgenio::facet *f;
|
|
tetgenio::polygon *p;
|
|
char infilename[FILENAMESIZE];
|
|
char line[INPUTLINESIZE];
|
|
char mode[128], id[256], fmt[64];
|
|
char *bufferp;
|
|
double *coord;
|
|
float _x, _y, _z;
|
|
int nverts = 0;
|
|
int nfaces = 0;
|
|
int line_count = 0;
|
|
int dummy;
|
|
int id1, id2, id3;
|
|
int nn = -1;
|
|
int nn_old = -1;
|
|
int i, j;
|
|
bool ImALittleEndian = !testIsBigEndian();
|
|
|
|
int smallestidx = 0;
|
|
|
|
strncpy(infilename, filebasename, FILENAMESIZE - 1);
|
|
infilename[FILENAMESIZE - 1] = '\0';
|
|
if (infilename[0] == '\0') {
|
|
printf("Error: No filename.\n");
|
|
return false;
|
|
}
|
|
if (strcmp(&infilename[strlen(infilename) - 4], ".vtk") != 0) {
|
|
strcat(infilename, ".vtk");
|
|
}
|
|
if (!(fp = fopen(infilename, "r"))) {
|
|
printf("Error: Unable to open file %s\n", infilename);
|
|
return false;
|
|
}
|
|
printf("Opening %s.\n", infilename);
|
|
|
|
// Default uses the index starts from '0'.
|
|
firstnumber = 0;
|
|
strcpy(mode, "BINARY");
|
|
|
|
while((bufferp = readline(line, fp, &line_count)) != NULL) {
|
|
if(strlen(line) == 0) continue;
|
|
//swallow lines beginning with a comment sign or white space
|
|
if(line[0] == '#' || line[0]=='\n' || line[0] == 10 || line[0] == 13 ||
|
|
line[0] == 32) continue;
|
|
|
|
sscanf(line, "%s", id);
|
|
if(!strcmp(id, "ASCII")) {
|
|
strcpy(mode, "ASCII");
|
|
}
|
|
|
|
if(!strcmp(id, "POINTS")) {
|
|
sscanf(line, "%s %d %s", id, &nverts, fmt);
|
|
if (nverts > 0) {
|
|
numberofpoints = nverts;
|
|
pointlist = new REAL[nverts * 3];
|
|
smallestidx = nverts + 1;
|
|
}
|
|
|
|
if(!strcmp(mode, "BINARY")) {
|
|
for(i = 0; i < nverts; i++) {
|
|
coord = &pointlist[i * 3];
|
|
if(!strcmp(fmt, "double")) {
|
|
fread((char*)(&(coord[0])), sizeof(double), 1, fp);
|
|
fread((char*)(&(coord[1])), sizeof(double), 1, fp);
|
|
fread((char*)(&(coord[2])), sizeof(double), 1, fp);
|
|
if(ImALittleEndian){
|
|
swapBytes((unsigned char *) &(coord[0]), sizeof(coord[0]));
|
|
swapBytes((unsigned char *) &(coord[1]), sizeof(coord[1]));
|
|
swapBytes((unsigned char *) &(coord[2]), sizeof(coord[2]));
|
|
}
|
|
} else if(!strcmp(fmt, "float")) {
|
|
fread((char*)(&_x), sizeof(float), 1, fp);
|
|
fread((char*)(&_y), sizeof(float), 1, fp);
|
|
fread((char*)(&_z), sizeof(float), 1, fp);
|
|
if(ImALittleEndian){
|
|
swapBytes((unsigned char *) &_x, sizeof(_x));
|
|
swapBytes((unsigned char *) &_y, sizeof(_y));
|
|
swapBytes((unsigned char *) &_z, sizeof(_z));
|
|
}
|
|
coord[0] = double(_x);
|
|
coord[1] = double(_y);
|
|
coord[2] = double(_z);
|
|
} else {
|
|
printf("Error: Only float or double formats are supported!\n");
|
|
return false;
|
|
}
|
|
}
|
|
} else if(!strcmp(mode, "ASCII")) {
|
|
for(i = 0; i < nverts; i++){
|
|
bufferp = readline(line, fp, &line_count);
|
|
if (bufferp == NULL) {
|
|
printf("Unexpected end of file on line %d in file %s\n",
|
|
line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
// Read vertex coordinates
|
|
coord = &pointlist[i * 3];
|
|
for (j = 0; j < 3; j++) {
|
|
if (*bufferp == '\0') {
|
|
printf("Syntax error reading vertex coords on line");
|
|
printf(" %d in file %s\n", line_count, infilename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
coord[j] = (REAL) strtod(bufferp, &bufferp);
|
|
bufferp = findnextnumber(bufferp);
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if(!strcmp(id, "POLYGONS")) {
|
|
sscanf(line, "%s %d %d", id, &nfaces, &dummy);
|
|
if (nfaces > 0) {
|
|
numberoffacets = nfaces;
|
|
facetlist = new tetgenio::facet[nfaces];
|
|
}
|
|
|
|
if(!strcmp(mode, "BINARY")) {
|
|
for(i = 0; i < nfaces; i++){
|
|
fread((char*)(&nn), sizeof(int), 1, fp);
|
|
if(ImALittleEndian){
|
|
swapBytes((unsigned char *) &nn, sizeof(nn));
|
|
}
|
|
if (i == 0)
|
|
nn_old = nn;
|
|
if (nn != nn_old) {
|
|
printf("Error: No mixed cells are allowed.\n");
|
|
return false;
|
|
}
|
|
|
|
if(nn == 3){
|
|
fread((char*)(&id1), sizeof(int), 1, fp);
|
|
fread((char*)(&id2), sizeof(int), 1, fp);
|
|
fread((char*)(&id3), sizeof(int), 1, fp);
|
|
if(ImALittleEndian){
|
|
swapBytes((unsigned char *) &id1, sizeof(id1));
|
|
swapBytes((unsigned char *) &id2, sizeof(id2));
|
|
swapBytes((unsigned char *) &id3, sizeof(id3));
|
|
}
|
|
f = &facetlist[i];
|
|
init(f);
|
|
// In .off format, each facet has one polygon, no hole.
|
|
f->numberofpolygons = 1;
|
|
f->polygonlist = new tetgenio::polygon[1];
|
|
p = &f->polygonlist[0];
|
|
init(p);
|
|
// Set number of vertices
|
|
p->numberofvertices = 3;
|
|
// Allocate memory for face vertices
|
|
p->vertexlist = new int[p->numberofvertices];
|
|
p->vertexlist[0] = id1;
|
|
p->vertexlist[1] = id2;
|
|
p->vertexlist[2] = id3;
|
|
// Detect the smallest index.
|
|
for (j = 0; j < 3; j++) {
|
|
if (p->vertexlist[j] < smallestidx) {
|
|
smallestidx = p->vertexlist[j];
|
|
}
|
|
}
|
|
} else {
|
|
printf("Error: Only triangles are supported\n");
|
|
return false;
|
|
}
|
|
}
|
|
} else if(!strcmp(mode, "ASCII")) {
|
|
for(i = 0; i < nfaces; i++) {
|
|
bufferp = readline(line, fp, &line_count);
|
|
nn = (int) strtol(bufferp, &bufferp, 0);
|
|
if (i == 0)
|
|
nn_old = nn;
|
|
if (nn != nn_old) {
|
|
printf("Error: No mixed cells are allowed.\n");
|
|
return false;
|
|
}
|
|
|
|
if (nn == 3) {
|
|
bufferp = findnextnumber(bufferp); // Skip the first field.
|
|
id1 = (int) strtol(bufferp, &bufferp, 0);
|
|
bufferp = findnextnumber(bufferp);
|
|
id2 = (int) strtol(bufferp, &bufferp, 0);
|
|
bufferp = findnextnumber(bufferp);
|
|
id3 = (int) strtol(bufferp, &bufferp, 0);
|
|
f = &facetlist[i];
|
|
init(f);
|
|
// In .off format, each facet has one polygon, no hole.
|
|
f->numberofpolygons = 1;
|
|
f->polygonlist = new tetgenio::polygon[1];
|
|
p = &f->polygonlist[0];
|
|
init(p);
|
|
// Set number of vertices
|
|
p->numberofvertices = 3;
|
|
// Allocate memory for face vertices
|
|
p->vertexlist = new int[p->numberofvertices];
|
|
p->vertexlist[0] = id1;
|
|
p->vertexlist[1] = id2;
|
|
p->vertexlist[2] = id3;
|
|
// Detect the smallest index.
|
|
for (j = 0; j < 3; j++) {
|
|
if (p->vertexlist[j] < smallestidx) {
|
|
smallestidx = p->vertexlist[j];
|
|
}
|
|
}
|
|
} else {
|
|
printf("Error: Only triangles are supported.\n");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
// Decide the firstnumber of the index.
|
|
if (smallestidx == 0) {
|
|
firstnumber = 0;
|
|
} else if (smallestidx == 1) {
|
|
firstnumber = 1;
|
|
} else {
|
|
printf("A wrong smallest index (%d) was detected in file %s\n",
|
|
smallestidx, infilename);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if(!strcmp(id,"LINES") || !strcmp(id,"CELLS")){
|
|
printf("Warning: load_vtk(): cannot read formats LINES, CELLS.\n");
|
|
}
|
|
} // while ()
|
|
|
|
return true;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_plc() Load a piecewise linear complex from file(s). //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_plc(char* filebasename, int object)
|
|
{
|
|
bool success;
|
|
|
|
if (object == (int) tetgenbehavior::NODES) {
|
|
success = load_node(filebasename);
|
|
} else if (object == (int) tetgenbehavior::POLY) {
|
|
success = load_poly(filebasename);
|
|
} else if (object == (int) tetgenbehavior::OFF) {
|
|
success = load_off(filebasename);
|
|
} else if (object == (int) tetgenbehavior::PLY) {
|
|
success = load_ply(filebasename);
|
|
} else if (object == (int) tetgenbehavior::STL) {
|
|
success = load_stl(filebasename);
|
|
} else if (object == (int) tetgenbehavior::MEDIT) {
|
|
success = load_medit(filebasename, 0);
|
|
} else if (object == (int) tetgenbehavior::VTK) {
|
|
success = load_vtk(filebasename);
|
|
} else {
|
|
success = load_poly(filebasename);
|
|
}
|
|
|
|
if (success) {
|
|
// Try to load the following files (.edge, .var, .mtr).
|
|
load_edge(filebasename);
|
|
load_var(filebasename);
|
|
load_mtr(filebasename);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// load_mesh() Load a tetrahedral mesh from file(s). //
|
|
// //
|
|
//============================================================================//
|
|
|
|
bool tetgenio::load_tetmesh(char* filebasename, int object)
|
|
{
|
|
bool success = false;
|
|
|
|
if (object == (int) tetgenbehavior::MEDIT) {
|
|
success = load_medit(filebasename, 1);
|
|
} else if (object == (int) tetgenbehavior::NEU_MESH) {
|
|
//success = load_neumesh(filebasename, 1);
|
|
} else {
|
|
success = load_node(filebasename);
|
|
if (success) {
|
|
success = load_tet(filebasename);
|
|
}
|
|
if (success) {
|
|
// Try to load the following files (.face, .edge, .vol).
|
|
load_face(filebasename);
|
|
load_edge(filebasename);
|
|
load_vol(filebasename);
|
|
}
|
|
}
|
|
|
|
if (success) {
|
|
// Try to load the following files (.var, .mtr).
|
|
load_var(filebasename);
|
|
load_mtr(filebasename);
|
|
load_elem(filebasename);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// save_nodes() Save points to a .node file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
void tetgenio::save_nodes(const char *filebasename)
|
|
{
|
|
FILE *fout;
|
|
char outnodefilename[FILENAMESIZE];
|
|
char outmtrfilename[FILENAMESIZE];
|
|
int i, j;
|
|
|
|
sprintf(outnodefilename, "%s.node", filebasename);
|
|
printf("Saving nodes to %s\n", outnodefilename);
|
|
fout = fopen(outnodefilename, "w");
|
|
fprintf(fout, "%d %d %d %d\n", numberofpoints, mesh_dim,
|
|
numberofpointattributes, pointmarkerlist != NULL ? 1 : 0);
|
|
for (i = 0; i < numberofpoints; i++) {
|
|
if (mesh_dim == 2) {
|
|
fprintf(fout, "%d %.16g %.16g", i + firstnumber, pointlist[i * 3],
|
|
pointlist[i * 3 + 1]);
|
|
} else {
|
|
fprintf(fout, "%d %.16g %.16g %.16g", i + firstnumber,
|
|
pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
|
|
}
|
|
for (j = 0; j < numberofpointattributes; j++) {
|
|
fprintf(fout, " %.16g",
|
|
pointattributelist[i * numberofpointattributes + j]);
|
|
}
|
|
if (pointmarkerlist != NULL) {
|
|
fprintf(fout, " %d", pointmarkerlist[i]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
fclose(fout);
|
|
|
|
// If the point metrics exist, output them to a .mtr file.
|
|
if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) {
|
|
sprintf(outmtrfilename, "%s.mtr", filebasename);
|
|
printf("Saving metrics to %s\n", outmtrfilename);
|
|
fout = fopen(outmtrfilename, "w");
|
|
fprintf(fout, "%d %d\n", numberofpoints, numberofpointmtrs);
|
|
for (i = 0; i < numberofpoints; i++) {
|
|
for (j = 0; j < numberofpointmtrs; j++) {
|
|
fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
fclose(fout);
|
|
}
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// save_elements() Save elements to a .ele file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
void tetgenio::save_elements(const char* filebasename)
|
|
{
|
|
FILE *fout;
|
|
char outelefilename[FILENAMESIZE];
|
|
int i, j;
|
|
|
|
sprintf(outelefilename, "%s.ele", filebasename);
|
|
printf("Saving elements to %s\n", outelefilename);
|
|
fout = fopen(outelefilename, "w");
|
|
if (mesh_dim == 3) {
|
|
fprintf(fout, "%d %d %d\n", numberoftetrahedra, numberofcorners,
|
|
numberoftetrahedronattributes);
|
|
for (i = 0; i < numberoftetrahedra; i++) {
|
|
fprintf(fout, "%d", i + firstnumber);
|
|
for (j = 0; j < numberofcorners; j++) {
|
|
fprintf(fout, " %5d", tetrahedronlist[i * numberofcorners + j]);
|
|
}
|
|
for (j = 0; j < numberoftetrahedronattributes; j++) {
|
|
fprintf(fout, " %g",
|
|
tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
} else {
|
|
// Save a two-dimensional mesh.
|
|
fprintf(fout, "%d %d %d\n",numberoftrifaces,3,trifacemarkerlist ? 1 : 0);
|
|
for (i = 0; i < numberoftrifaces; i++) {
|
|
fprintf(fout, "%d", i + firstnumber);
|
|
for (j = 0; j < 3; j++) {
|
|
fprintf(fout, " %5d", trifacelist[i * 3 + j]);
|
|
}
|
|
if (trifacemarkerlist != NULL) {
|
|
fprintf(fout, " %d", trifacemarkerlist[i]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
}
|
|
|
|
fclose(fout);
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// save_faces() Save faces to a .face file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
void tetgenio::save_faces(const char* filebasename)
|
|
{
|
|
FILE *fout;
|
|
char outfacefilename[FILENAMESIZE];
|
|
int i;
|
|
|
|
sprintf(outfacefilename, "%s.face", filebasename);
|
|
printf("Saving faces to %s\n", outfacefilename);
|
|
fout = fopen(outfacefilename, "w");
|
|
fprintf(fout, "%d %d\n", numberoftrifaces,
|
|
trifacemarkerlist != NULL ? 1 : 0);
|
|
for (i = 0; i < numberoftrifaces; i++) {
|
|
fprintf(fout, "%d %5d %5d %5d", i + firstnumber, trifacelist[i * 3],
|
|
trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
|
|
if (trifacemarkerlist != NULL) {
|
|
fprintf(fout, " %d", trifacemarkerlist[i]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
|
|
fclose(fout);
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// save_edges() Save egdes to a .edge file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
void tetgenio::save_edges(char* filebasename)
|
|
{
|
|
FILE *fout;
|
|
char outedgefilename[FILENAMESIZE];
|
|
int i;
|
|
|
|
sprintf(outedgefilename, "%s.edge", filebasename);
|
|
printf("Saving edges to %s\n", outedgefilename);
|
|
fout = fopen(outedgefilename, "w");
|
|
fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
|
|
for (i = 0; i < numberofedges; i++) {
|
|
fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
|
|
edgelist[i * 2 + 1]);
|
|
if (edgemarkerlist != NULL) {
|
|
fprintf(fout, " %d", edgemarkerlist[i]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
|
|
fclose(fout);
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// save_neighbors() Save egdes to a .neigh file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
void tetgenio::save_neighbors(char* filebasename)
|
|
{
|
|
FILE *fout;
|
|
char outneighborfilename[FILENAMESIZE];
|
|
int i;
|
|
|
|
sprintf(outneighborfilename, "%s.neigh", filebasename);
|
|
printf("Saving neighbors to %s\n", outneighborfilename);
|
|
fout = fopen(outneighborfilename, "w");
|
|
fprintf(fout, "%d %d\n", numberoftetrahedra, mesh_dim + 1);
|
|
for (i = 0; i < numberoftetrahedra; i++) {
|
|
if (mesh_dim == 2) {
|
|
fprintf(fout, "%d %5d %5d %5d", i + firstnumber, neighborlist[i * 3],
|
|
neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
|
|
} else {
|
|
fprintf(fout, "%d %5d %5d %5d %5d", i + firstnumber,
|
|
neighborlist[i * 4], neighborlist[i * 4 + 1],
|
|
neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
|
|
fclose(fout);
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// save_poly() Save segments or facets to a .poly file. //
|
|
// //
|
|
// It only save the facets, holes and regions. No .node file is saved. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
void tetgenio::save_poly(const char *filebasename)
|
|
{
|
|
FILE *fout;
|
|
facet *f;
|
|
polygon *p;
|
|
char outpolyfilename[FILENAMESIZE];
|
|
int i, j, k;
|
|
|
|
sprintf(outpolyfilename, "%s.poly", filebasename);
|
|
printf("Saving poly to %s\n", outpolyfilename);
|
|
fout = fopen(outpolyfilename, "w");
|
|
|
|
// The zero indicates that the vertices are in a separate .node file.
|
|
// Followed by number of dimensions, number of vertex attributes,
|
|
// and number of boundary markers (zero or one).
|
|
fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
|
|
pointmarkerlist != NULL ? 1 : 0);
|
|
|
|
// Save segments or facets.
|
|
if (mesh_dim == 2) {
|
|
// Number of segments, number of boundary markers (zero or one).
|
|
fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
|
|
for (i = 0; i < numberofedges; i++) {
|
|
fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
|
|
edgelist[i * 2 + 1]);
|
|
if (edgemarkerlist != NULL) {
|
|
fprintf(fout, " %d", edgemarkerlist[i]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
} else {
|
|
// Number of facets, number of boundary markers (zero or one).
|
|
fprintf(fout, "%d %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0);
|
|
for (i = 0; i < numberoffacets; i++) {
|
|
f = &(facetlist[i]);
|
|
fprintf(fout, "%d %d %d # %d\n", f->numberofpolygons,f->numberofholes,
|
|
facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber);
|
|
// Output polygons of this facet.
|
|
for (j = 0; j < f->numberofpolygons; j++) {
|
|
p = &(f->polygonlist[j]);
|
|
fprintf(fout, "%d ", p->numberofvertices);
|
|
for (k = 0; k < p->numberofvertices; k++) {
|
|
if (((k + 1) % 10) == 0) {
|
|
fprintf(fout, "\n ");
|
|
}
|
|
fprintf(fout, " %d", p->vertexlist[k]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
// Output holes of this facet.
|
|
for (j = 0; j < f->numberofholes; j++) {
|
|
fprintf(fout, "%d %.12g %.12g %.12g\n", j + firstnumber,
|
|
f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save holes.
|
|
fprintf(fout, "%d\n", numberofholes);
|
|
for (i = 0; i < numberofholes; i++) {
|
|
// Output x, y coordinates.
|
|
fprintf(fout, "%d %.12g %.12g", i + firstnumber, holelist[i * mesh_dim],
|
|
holelist[i * mesh_dim + 1]);
|
|
if (mesh_dim == 3) {
|
|
// Output z coordinate.
|
|
fprintf(fout, " %.12g", holelist[i * mesh_dim + 2]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
|
|
// Save regions.
|
|
fprintf(fout, "%d\n", numberofregions);
|
|
for (i = 0; i < numberofregions; i++) {
|
|
if (mesh_dim == 2) {
|
|
// Output the index, x, y coordinates, attribute (region number)
|
|
// and maximum area constraint (maybe -1).
|
|
fprintf(fout, "%d %.12g %.12g %.12g %.12g\n", i + firstnumber,
|
|
regionlist[i * 4], regionlist[i * 4 + 1],
|
|
regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
|
|
} else {
|
|
// Output the index, x, y, z coordinates, attribute (region number)
|
|
// and maximum volume constraint (maybe -1).
|
|
fprintf(fout, "%d %.12g %.12g %.12g %.12g %.12g\n", i + firstnumber,
|
|
regionlist[i * 5], regionlist[i * 5 + 1],
|
|
regionlist[i * 5 + 2], regionlist[i * 5 + 3],
|
|
regionlist[i * 5 + 4]);
|
|
}
|
|
}
|
|
|
|
fclose(fout);
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// save_faces2smesh() Save triangular faces to a .smesh file. //
|
|
// //
|
|
// It only save the facets. No holes and regions. No .node file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
void tetgenio::save_faces2smesh(char* filebasename)
|
|
{
|
|
FILE *fout;
|
|
char outsmeshfilename[FILENAMESIZE];
|
|
int i, j;
|
|
|
|
sprintf(outsmeshfilename, "%s.smesh", filebasename);
|
|
printf("Saving faces to %s\n", outsmeshfilename);
|
|
fout = fopen(outsmeshfilename, "w");
|
|
|
|
// The zero indicates that the vertices are in a separate .node file.
|
|
// Followed by number of dimensions, number of vertex attributes,
|
|
// and number of boundary markers (zero or one).
|
|
fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
|
|
pointmarkerlist != NULL ? 1 : 0);
|
|
|
|
// Number of facets, number of boundary markers (zero or one).
|
|
fprintf(fout, "%d %d\n", numberoftrifaces,
|
|
trifacemarkerlist != NULL ? 1 : 0);
|
|
|
|
// Output triangular facets.
|
|
for (i = 0; i < numberoftrifaces; i++) {
|
|
j = i * 3;
|
|
fprintf(fout, "3 %d %d %d", trifacelist[j], trifacelist[j + 1],
|
|
trifacelist[j + 2]);
|
|
if (trifacemarkerlist != NULL) {
|
|
fprintf(fout, " %d", trifacemarkerlist[i]);
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
|
|
// No holes and regions.
|
|
fprintf(fout, "0\n");
|
|
fprintf(fout, "0\n");
|
|
|
|
fclose(fout);
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// readline() Read a nonempty line from a file. //
|
|
// //
|
|
// A line is considered "nonempty" if it contains something more than white //
|
|
// spaces. If a line is considered empty, it will be dropped and the next //
|
|
// line will be read, this process ends until reaching the end-of-file or a //
|
|
// non-empty line. Return NULL if it is the end-of-file, otherwise, return //
|
|
// a pointer to the first non-whitespace character of the line. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
|
|
{
|
|
char *result;
|
|
|
|
// Search for a non-empty line.
|
|
do {
|
|
result = fgets(string, INPUTLINESIZE - 1, infile);
|
|
if (linenumber) (*linenumber)++;
|
|
if (result == (char *) NULL) {
|
|
return (char *) NULL;
|
|
}
|
|
// Skip white spaces.
|
|
while ((*result == ' ') || (*result == '\t')) result++;
|
|
// If it's end of line, read another line and try again.
|
|
} while ((*result == '\0') || (*result == '\r') || (*result == '\n'));
|
|
return result;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// findnextfield() Find the next field of a string. //
|
|
// //
|
|
// Jumps past the current field by searching for whitespace or a comma, then //
|
|
// jumps past the whitespace or the comma to find the next field. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
char* tetgenio::findnextfield(char *string)
|
|
{
|
|
char *result;
|
|
|
|
result = string;
|
|
// Skip the current field. Stop upon reaching whitespace or a comma.
|
|
while ((*result != '\0') && (*result != ' ') && (*result != '\t') &&
|
|
(*result != ',') && (*result != ';')) {
|
|
result++;
|
|
}
|
|
// Now skip the whitespace or the comma, stop at anything else that looks
|
|
// like a character, or the end of a line.
|
|
while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
|
|
(*result == ';')) {
|
|
result++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// readnumberline() Read a nonempty number line from a file. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
|
|
{
|
|
char *result;
|
|
|
|
// Search for a non-empty line.
|
|
result = readline(string, infile, (int *) NULL);
|
|
if (result == (char *) NULL) {
|
|
return (char *) NULL;
|
|
}
|
|
// Check for a comment.
|
|
result = strchr(result, '#');
|
|
if (result != (char *) NULL) {
|
|
*result = '\0';
|
|
}
|
|
return string;
|
|
}
|
|
|
|
//============================================================================//
|
|
// //
|
|
// findnextnumber() Find the next number of a string. //
|
|
// //
|
|
// Jumps past the current field by searching for whitespace or a comma, then //
|
|
// jumps past the whitespace and anything else that doesn't look like a //
|
|
// number. //
|
|
// //
|
|
//============================================================================//
|
|
|
|
char* tetgenio::findnextnumber(char *string)
|
|
{
|
|
char *result;
|
|
|
|
result = string;
|
|
// Skip the current field. Stop upon reaching whitespace or a comma.
|
|
while ((*result != '\0') && (*result != '#') && (*result != ' ') &&
|
|
(*result != '\t') && (*result != ',')) {
|
|
result++;
|
|
}
|
|
// Now skip the whitespace and anything else that doesn't look like a
|
|
// number, a comment, or the end of a line.
|
|
while ((*result != '\0') && (*result != '#')
|
|
&& (*result != '.') && (*result != '+') && (*result != '-')
|
|
&& ((*result < '0') || (*result > '9'))) {
|
|
result++;
|
|
}
|
|
// Check for a comment (prefixed with `#').
|
|
if (*result == '#') {
|
|
*result = '\0';
|
|
}
|
|
return result;
|
|
}
|