46#define LINE_MAX_LEN 256
50float float_reverse_bytes(
float x);
52int leqi(
char *string1,
char *string2);
62char *option[N_OPTIONS] = {
63 "ascii",
"binary",
"pipe"};
67 "Usage: stl2sdds [<inputFile>] [<outputFile>] [-pipe[=in][,out]]\n"
68 " [-ascii | -binary]\n\n"
70 " -pipe[=in][,out] Enable piping for input and/or output using SDDS toolkit.\n"
71 " -ascii Output SDDS in ASCII format. Default is binary.\n"
72 " -binary Output SDDS in binary format.\n\n"
73 "Converts STL files to SDDS format.\n"
74 "Author: Robert Soliday.\n"
75 "Compiled on " __DATE__
" at " __TIME__
", SVN revision: " SVN_VERSION
"\n";
77int main(
int argc,
char **argv) {
78 char *inputFile = NULL, *outputFile = NULL;
83 unsigned long pipeFlags = 0;
85 int i, n = 0, solid = 0;
88 int32_t face_num = 0, iface;
89 int32_t bigEndianMachine = 0;
90 int64_t bytes_num = 0, text_num = 0;
91 float *normalVector[3];
96 char input[LINE_MAX_LEN];
98 char token[LINE_MAX_LEN];
102 argc =
scanargs(&scanned, argc, argv);
104 fprintf(stderr,
"%s", USAGE);
108 for (iArg = 1; iArg < argc; iArg++) {
109 if (scanned[iArg].arg_type == OPTION) {
110 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
118 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags)) {
119 fprintf(stderr,
"Error: Invalid -pipe syntax.\n");
120 fprintf(stderr,
"%s", USAGE);
125 fprintf(stderr,
"Error: Invalid option detected.\n%s", USAGE);
131 else if (!outputFile)
134 fprintf(stderr,
"Error: Too many filenames provided.\n%s", USAGE);
144 fprintf(stderr,
"Error: Input file '%s' not found.\n", inputFile);
147 if (!(fd = fopen(inputFile,
"rb"))) {
148 fprintf(stderr,
"Error: Unable to open input file '%s'.\n", inputFile);
153 if (_setmode(_fileno(stdin), _O_BINARY) == -1) {
154 fprintf(stderr,
"Error: Unable to set stdin to binary mode.\n");
164 bytes_num += fread(&init, 1, 6, fd);
166 int stlascii = (strcasecmp(
"solid ", init) == 0) ? TRUE : FALSE;
170 for (i = 0; i < 74; i++) {
171 if (fgetc(fd) == EOF)
177 bytes_num += fread(&face_num, 1,
sizeof(int32_t), fd);
178 if (bigEndianMachine) {
182 for (i = 0; i < 3; i++) {
183 normalVector[i] = malloc(
sizeof(*(normalVector[i])) * face_num);
184 vertex1[i] = malloc(
sizeof(*(vertex1[i])) * face_num);
185 vertex2[i] = malloc(
sizeof(*(vertex2[i])) * face_num);
186 vertex3[i] = malloc(
sizeof(*(vertex3[i])) * face_num);
187 if (!normalVector[i] || !vertex1[i] || !vertex2[i] || !vertex3[i]) {
188 fprintf(stderr,
"Error: Memory allocation failed.\n");
194 for (iface = 0; iface < face_num; iface++) {
195 for (i = 0; i < 3; i++) {
196 if (fread(&(normalVector[i][iface]), 1,
sizeof(
float), fd) !=
sizeof(
float)) {
197 fprintf(stderr,
"Error: Unexpected end of file while reading normals.\n");
200 bytes_num +=
sizeof(float);
201 if (bigEndianMachine) {
202 normalVector[i][iface] = float_reverse_bytes(normalVector[i][iface]);
205 for (i = 0; i < 3; i++) {
206 if (fread(&(vertex1[i][iface]), 1,
sizeof(
float), fd) !=
sizeof(
float)) {
207 fprintf(stderr,
"Error: Unexpected end of file while reading vertex1.\n");
210 bytes_num +=
sizeof(float);
211 if (bigEndianMachine) {
212 vertex1[i][iface] = float_reverse_bytes(vertex1[i][iface]);
215 for (i = 0; i < 3; i++) {
216 if (fread(&(vertex2[i][iface]), 1,
sizeof(
float), fd) !=
sizeof(
float)) {
217 fprintf(stderr,
"Error: Unexpected end of file while reading vertex2.\n");
220 bytes_num +=
sizeof(float);
221 if (bigEndianMachine) {
222 vertex2[i][iface] = float_reverse_bytes(vertex2[i][iface]);
225 for (i = 0; i < 3; i++) {
226 if (fread(&(vertex3[i][iface]), 1,
sizeof(
float), fd) !=
sizeof(
float)) {
227 fprintf(stderr,
"Error: Unexpected end of file while reading vertex3.\n");
230 bytes_num +=
sizeof(float);
231 if (bigEndianMachine) {
232 vertex3[i][iface] = float_reverse_bytes(vertex3[i][iface]);
235 if (fread(&(attribute), 1,
sizeof(
short int), fd) !=
sizeof(
short int)) {
236 fprintf(stderr,
"Error: Unexpected end of file while reading attribute.\n");
239 bytes_num +=
sizeof(
short int);
242 for (i = 0; i < 3; i++) {
243 normalVector[i] = NULL;
248 fseek(fd, 0, SEEK_SET);
249 while (fgets(input, LINE_MAX_LEN, fd) != NULL) {
251 for (next = input; *next !=
'\0' && isspace((
unsigned char)*next); next++) {
253 if (*next ==
'\0' || *next ==
'#' || *next ==
'!' || *next ==
'$') {
256 sscanf(next,
"%s%n", token, &width);
259 if (leqi(token,
"facet")) {
262 for (i = 0; i < 3; i++) {
263 normalVector[i] = malloc(
sizeof(*(normalVector[i])) * n);
264 vertex1[i] = malloc(
sizeof(*(vertex1[i])) * n);
265 vertex2[i] = malloc(
sizeof(*(vertex2[i])) * n);
266 vertex3[i] = malloc(
sizeof(*(vertex3[i])) * n);
267 if (!normalVector[i] || !vertex1[i] || !vertex2[i] || !vertex3[i]) {
268 fprintf(stderr,
"Error: Memory allocation failed.\n");
274 for (i = 0; i < 3; i++) {
275 normalVector[i] = realloc(normalVector[i],
sizeof(*(normalVector[i])) * n);
276 vertex1[i] = realloc(vertex1[i],
sizeof(*(vertex1[i])) * n);
277 vertex2[i] = realloc(vertex2[i],
sizeof(*(vertex2[i])) * n);
278 vertex3[i] = realloc(vertex3[i],
sizeof(*(vertex3[i])) * n);
279 if (!normalVector[i] || !vertex1[i] || !vertex2[i] || !vertex3[i]) {
280 fprintf(stderr,
"Error: Memory allocation failed.\n");
287 sscanf(next,
"%*s %e %e %e",
288 &(normalVector[0][n - 1]),
289 &(normalVector[1][n - 1]),
290 &(normalVector[2][n - 1]));
293 if (!fgets(input, LINE_MAX_LEN, fd) || !fgets(input, LINE_MAX_LEN, fd)) {
294 fprintf(stderr,
"Error: Unexpected end of file while reading outer loop.\n");
300 sscanf(next,
"%*s %e %e %e",
301 &(vertex1[0][n - 1]),
302 &(vertex1[1][n - 1]),
303 &(vertex1[2][n - 1]));
306 if (!fgets(input, LINE_MAX_LEN, fd)) {
307 fprintf(stderr,
"Error: Unexpected end of file while reading vertex2.\n");
313 sscanf(next,
"%*s %e %e %e",
314 &(vertex2[0][n - 1]),
315 &(vertex2[1][n - 1]),
316 &(vertex2[2][n - 1]));
319 if (!fgets(input, LINE_MAX_LEN, fd)) {
320 fprintf(stderr,
"Error: Unexpected end of file while reading vertex3.\n");
326 sscanf(next,
"%*s %e %e %e",
327 &(vertex3[0][n - 1]),
328 &(vertex3[1][n - 1]),
329 &(vertex3[2][n - 1]));
332 if (!fgets(input, LINE_MAX_LEN, fd) || !fgets(input, LINE_MAX_LEN, fd)) {
333 fprintf(stderr,
"Error: Unexpected end of file while reading endloop/endfacet.\n");
337 }
else if (leqi(token,
"color")) {
338 fprintf(stderr,
"Warning: Color field seen in STL file ignored.\n");
339 }
else if (leqi(token,
"solid")) {
342 fprintf(stderr,
"Error: More than one solid field seen in STL file.\n");
345 }
else if (leqi(token,
"endsolid")) {
348 fprintf(stderr,
"Error: Unrecognized keyword '%s' in STL file.\n", token);
362 SDDSout.layout.data_mode.column_major = 1;
366 const char *columns[] = {
367 "NormalVectorX",
"NormalVectorY",
"NormalVectorZ",
368 "Vertex1X",
"Vertex1Y",
"Vertex1Z",
369 "Vertex2X",
"Vertex2Y",
"Vertex2Z",
370 "Vertex3X",
"Vertex3Y",
"Vertex3Z"};
371 for (i = 0; i < 12; i++) {
385 if (!SDDS_StartTable(&SDDSout, face_num)) {
391 const char *column_names[] = {
392 "NormalVectorX",
"NormalVectorY",
"NormalVectorZ",
393 "Vertex1X",
"Vertex1Y",
"Vertex1Z",
394 "Vertex2X",
"Vertex2Y",
"Vertex2Z",
395 "Vertex3X",
"Vertex3Y",
"Vertex3Z"};
396 float *data_columns[12] = {
397 normalVector[0], normalVector[1], normalVector[2],
398 vertex1[0], vertex1[1], vertex1[2],
399 vertex2[0], vertex2[1], vertex2[2],
400 vertex3[0], vertex3[1], vertex3[2]};
402 for (i = 0; i < 12; i++) {
410 if (!SDDS_WriteTable(&SDDSout)) {
424 for (i = 0; i < 3; i++) {
425 free(normalVector[i]);
434float float_reverse_bytes(
float x) {
445 y.ychar[0] = y.ychar[3];
450 y.ychar[1] = y.ychar[2];
456int leqi(
char *string1,
char *string2) {
459 int nchar1 = strlen(string1);
460 int nchar2 = strlen(string2);
462 nchar = (nchar1 < nchar2) ? nchar1 : nchar2;
465 for (i = 0; i < nchar; i++) {
466 if (toupper((
unsigned char)string1[i]) != toupper((
unsigned char)string2[i])) {
472 if (nchar1 > nchar) {
473 for (i = nchar; i < nchar1; i++) {
474 if (string1[i] !=
' ') {
478 }
else if (nchar2 > nchar) {
479 for (i = nchar; i < nchar2; i++) {
480 if (string2[i] !=
' ') {
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
void SDDS_SwapLong(int32_t *data)
Swaps the endianness of a 32-bit integer.
int32_t SDDS_SetColumnFromFloats(SDDS_DATASET *SDDS_dataset, int32_t mode, float *data, int64_t rows,...)
Sets the values for a single data column using single-precision floating-point numbers.
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_DefineSimpleColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type)
Defines a simple data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
#define SDDS_FLOAT
Identifier for the float data type.
long fexists(const char *filename)
Checks if a file exists.
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
long processPipeOption(char **item, long items, unsigned long *flags)
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
void free_scanargs(SCANNED_ARG **scanned, int argc)