SDDSlib
Loading...
Searching...
No Matches
sdds2stl.c
Go to the documentation of this file.
1/**
2 * @file sdds2stl.c
3 * @brief Converts SDDS (Self-Describing Data Set) files into binary STL (stereolithography) files.
4 *
5 * This program reads an SDDS file, extracts normal vectors and vertex coordinates,
6 * and writes them into a binary STL file. It supports optional piped input/output
7 * and adheres to SDDS conventions for data processing.
8 *
9 * Features:
10 * - Handles various SDDS data types.
11 * - Provides big-endian and little-endian support for portability.
12 * - Can process data directly from stdin or output to stdout using pipe options.
13 *
14 * Usage:
15 * ```
16 * sdds2stl [-pipe[=input]] [<inputFile>] [<outputFile>]
17 * ```
18 *
19 * @note Ensure the input SDDS file contains the required columns:
20 * - NormalVectorX, NormalVectorY, NormalVectorZ
21 * - Vertex1X, Vertex1Y, Vertex1Z
22 * - Vertex2X, Vertex2Y, Vertex2Z
23 * - Vertex3X, Vertex3Y, Vertex3Z
24 *
25 * @copyright
26 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
27 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
28 *
29 * @license
30 * This file is distributed under the terms of the Software License Agreement
31 * found in the file LICENSE included with this distribution.
32 *
33 * @author R. Soliday
34 */
35
36#include "mdb.h"
37#include "SDDS.h"
38#include "scan.h"
39#if defined(_WIN32)
40# include <io.h>
41# include <fcntl.h>
42#endif
43
44float float_reverse_bytes(float x);
45
46/* Enumeration for option types */
47enum option_type {
48 SET_PIPE,
49 N_OPTIONS
50};
51
52char *option[N_OPTIONS] =
53 {
54 "pipe"};
55
56char *usage =
57 "sdds2stl [-pipe[=input]] [<inputFile>] [<outputFile>]\n"
58 "Converts an SDDS file to a binary STL file.\n"
59 "Program by Robert Soliday. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
60
61int main(int argc, char **argv) {
62 char *input = NULL, *output = NULL;
63 SDDS_DATASET SDDS_dataset;
64 SCANNED_ARG *scanned;
65 long i_arg;
66 unsigned long pipe_flags = 0;
67
68 int i;
69 int64_t rows = 0;
70 int32_t row, bsrows;
71 float *normal_vector[3];
72 float *vertex1[3];
73 float *vertex2[3];
74 float *vertex3[3];
75 short attribute = 0;
76 FILE *fd;
77 int32_t big_endian_machine = 0;
78 float temp;
79
81 argc = scanargs(&scanned, argc, argv);
82 if (argc < 2) {
83 fprintf(stderr, "%s", usage);
84 return 1;
85 }
86
87 for (i_arg = 1; i_arg < argc; i_arg++) {
88 if (scanned[i_arg].arg_type == OPTION) {
89 switch (match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
90 case SET_PIPE:
91 if (!processPipeOption(scanned[i_arg].list + 1, scanned[i_arg].n_items - 1, &pipe_flags)) {
92 fprintf(stderr, "sdds2stl: invalid -pipe syntax\n");
93 return 1;
94 }
95 break;
96 default:
97 fprintf(stderr, "sdds2stl: invalid option seen\n%s", usage);
98 return 1;
99 }
100 } else {
101 if (!input)
102 SDDS_CopyString(&input, scanned[i_arg].list[0]);
103 else if (!output)
104 SDDS_CopyString(&output, scanned[i_arg].list[0]);
105 else {
106 fprintf(stderr, "sdds2stl: too many filenames\n%s", usage);
107 return 1;
108 }
109 }
110 }
111
112 if (pipe_flags & USE_STDIN)
113 processFilenames("sdds2tiff", &input, &output, USE_STDIN, 1, NULL);
114
115 if (!SDDS_InitializeInput(&SDDS_dataset, input))
116 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
117
118 if ((SDDS_CheckColumn(&SDDS_dataset, "NormalVectorX", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
119 fprintf(stderr, "sdds2stl: NormalVectorX column not found.\n");
120 return 1;
121 }
122
123 if ((SDDS_CheckColumn(&SDDS_dataset, "NormalVectorY", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
124 fprintf(stderr, "sdds2stl: NormalVectorX column not found.\n");
125 return 1;
126 }
127
128 if ((SDDS_CheckColumn(&SDDS_dataset, "NormalVectorZ", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
129 fprintf(stderr, "sdds2stl: NormalVectorX column not found.\n");
130 return 1;
131 }
132
133 if ((SDDS_CheckColumn(&SDDS_dataset, "Vertex1X", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
134 fprintf(stderr, "sdds2stl: Vertex1X column not found.\n");
135 return 1;
136 }
137
138 if ((SDDS_CheckColumn(&SDDS_dataset, "Vertex1Y", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
139 fprintf(stderr, "sdds2stl: Vertex1Y column not found.\n");
140 return 1;
141 }
142
143 if ((SDDS_CheckColumn(&SDDS_dataset, "Vertex1Z", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
144 fprintf(stderr, "sdds2stl: Vertex1Z column not found.\n");
145 return 1;
146 }
147
148 if ((SDDS_CheckColumn(&SDDS_dataset, "Vertex2X", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
149 fprintf(stderr, "sdds2stl: Vertex2X column not found.\n");
150 return 1;
151 }
152
153 if ((SDDS_CheckColumn(&SDDS_dataset, "Vertex2Y", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
154 fprintf(stderr, "sdds2stl: Vertex2Y column not found.\n");
155 return 1;
156 }
157
158 if ((SDDS_CheckColumn(&SDDS_dataset, "Vertex2Z", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
159 fprintf(stderr, "sdds2stl: Vertex2Z column not found.\n");
160 return 1;
161 }
162
163 if ((SDDS_CheckColumn(&SDDS_dataset, "Vertex3X", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
164 fprintf(stderr, "sdds2stl: Vertex3X column not found.\n");
165 return 1;
166 }
167
168 if ((SDDS_CheckColumn(&SDDS_dataset, "Vertex3Y", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
169 fprintf(stderr, "sdds2stl: Vertex3Y column not found.\n");
170 return 1;
171 }
172
173 if ((SDDS_CheckColumn(&SDDS_dataset, "Vertex3Z", NULL, SDDS_ANY_NUMERIC_TYPE, NULL)) != SDDS_CHECK_OKAY) {
174 fprintf(stderr, "sdds2stl: Vertex3Z column not found.\n");
175 return 1;
176 }
177
178 if (SDDS_ReadTable(&SDDS_dataset) <= 0) {
179 fprintf(stderr, "sdds2stl: Unable to read SDDS page.\n");
180 return 1;
181 }
182
183 rows = SDDS_RowCount(&SDDS_dataset);
184 if (rows > INT32_MAX) {
185 fprintf(stderr, "sdds2stl: Too many rows input file for conversion to STL format\n");
186 return 1;
187 }
188
189 for (i = 0; i < 3; i++) {
190 normal_vector[i] = malloc(sizeof(*(normal_vector[i])) * rows);
191 vertex1[i] = malloc(sizeof(*(vertex1[i])) * rows);
192 vertex2[i] = malloc(sizeof(*(vertex2[i])) * rows);
193 vertex3[i] = malloc(sizeof(*(vertex3[i])) * rows);
194 }
195
196 normal_vector[0] = SDDS_GetColumnInFloats(&SDDS_dataset, "NormalVectorX");
197 normal_vector[1] = SDDS_GetColumnInFloats(&SDDS_dataset, "NormalVectorY");
198 normal_vector[2] = SDDS_GetColumnInFloats(&SDDS_dataset, "NormalVectorZ");
199 vertex1[0] = SDDS_GetColumnInFloats(&SDDS_dataset, "Vertex1X");
200 vertex1[1] = SDDS_GetColumnInFloats(&SDDS_dataset, "Vertex1Y");
201 vertex1[2] = SDDS_GetColumnInFloats(&SDDS_dataset, "Vertex1Z");
202 vertex2[0] = SDDS_GetColumnInFloats(&SDDS_dataset, "Vertex2X");
203 vertex2[1] = SDDS_GetColumnInFloats(&SDDS_dataset, "Vertex2Y");
204 vertex2[2] = SDDS_GetColumnInFloats(&SDDS_dataset, "Vertex2Z");
205 vertex3[0] = SDDS_GetColumnInFloats(&SDDS_dataset, "Vertex3X");
206 vertex3[1] = SDDS_GetColumnInFloats(&SDDS_dataset, "Vertex3Y");
207 vertex3[2] = SDDS_GetColumnInFloats(&SDDS_dataset, "Vertex3Z");
208
209 if (!SDDS_Terminate(&SDDS_dataset))
210 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
211
212 if (!output) {
213#if defined(_WIN32)
214 if (_setmode(_fileno(stdout), _O_BINARY) == -1) {
215 fprintf(stderr, "error: unable to set stdout to binary mode\n");
216 exit(1);
217 }
218#endif
219 fd = stdout;
220 } else
221 fd = fopen(output, "wb");
222
223 big_endian_machine = SDDS_IsBigEndianMachine();
224
225 fprintf(fd, "STL BINARY FILE CREATED BY SDDS2STL --------------------------------------------");
226 if (big_endian_machine) {
227 bsrows = rows;
228 SDDS_SwapLong((int32_t *)&bsrows);
229 fwrite(&bsrows, sizeof(int32_t), 1, fd);
230 for (row = 0; row < rows; row++) {
231 for (i = 0; i < 3; i++) {
232 temp = float_reverse_bytes(normal_vector[i][row]);
233 fwrite(&temp, sizeof(float), 1, fd);
234 }
235 for (i = 0; i < 3; i++) {
236 temp = float_reverse_bytes(vertex1[i][row]);
237 fwrite(&temp, sizeof(float), 1, fd);
238 }
239 for (i = 0; i < 3; i++) {
240 temp = float_reverse_bytes(vertex2[i][row]);
241 fwrite(&temp, sizeof(float), 1, fd);
242 }
243 for (i = 0; i < 3; i++) {
244 temp = float_reverse_bytes(vertex3[i][row]);
245 fwrite(&temp, sizeof(float), 1, fd);
246 }
247 fwrite(&attribute, sizeof(short), 1, fd);
248 }
249 } else {
250 fwrite(&rows, sizeof(int32_t), 1, fd);
251 for (row = 0; row < rows; row++) {
252 for (i = 0; i < 3; i++)
253 fwrite(&(normal_vector[i][row]), sizeof(float), 1, fd);
254 for (i = 0; i < 3; i++)
255 fwrite(&(vertex1[i][row]), sizeof(float), 1, fd);
256 for (i = 0; i < 3; i++)
257 fwrite(&(vertex2[i][row]), sizeof(float), 1, fd);
258 for (i = 0; i < 3; i++)
259 fwrite(&(vertex3[i][row]), sizeof(float), 1, fd);
260 fwrite(&attribute, sizeof(short), 1, fd);
261 }
262 }
263
264 fclose(fd);
265
266 return 1;
267}
268
269float float_reverse_bytes(float x) {
270 char c;
271 union {
272 float yfloat;
273 char ychar[4];
274 } y;
275
276 y.yfloat = x;
277
278 c = y.ychar[0];
279 y.ychar[0] = y.ychar[3];
280 y.ychar[3] = c;
281
282 c = y.ychar[1];
283 y.ychar[1] = y.ychar[2];
284 y.ychar[2] = c;
285
286 return y.yfloat;
287}
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.
float * SDDS_GetColumnInFloats(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of floats, considering only rows marke...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a column exists in the SDDS dataset with the specified name, units, and type.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:856
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
#define SDDS_ANY_NUMERIC_TYPE
Special identifier used by SDDS_Check*() routines to accept any numeric type.
Definition SDDStypes.h:157
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)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390