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