1 /* GTS - Library for the manipulation of triangulated surfaces
2 * Copyright (C) 1999 St�phane Popinet
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include "config.h"
23 #ifdef HAVE_GETOPT_H
24 # include <getopt.h>
25 #endif /* HAVE_GETOPT_H */
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif /* HAVE_UNISTD_H */
29 #include "gts.h"
30
write_edge(GtsSegment * s,FILE * fp)31 static void write_edge (GtsSegment * s, FILE * fp)
32 {
33 fprintf (fp, "VECT 1 2 0 2 0 %g %g %g %g %g %g\n",
34 GTS_POINT (s->v1)->x,
35 GTS_POINT (s->v1)->y,
36 GTS_POINT (s->v1)->z,
37 GTS_POINT (s->v2)->x,
38 GTS_POINT (s->v2)->y,
39 GTS_POINT (s->v2)->z);
40 }
41
42 /* set - compute set operations between surfaces */
main(int argc,char * argv[])43 int main (int argc, char * argv[])
44 {
45 GtsSurface * s1, * s2, * s3;
46 GtsSurfaceInter * si;
47 GNode * tree1, * tree2;
48 FILE * fptr;
49 GtsFile * fp;
50 int c = 0;
51 gboolean verbose = TRUE;
52 gboolean inter = FALSE;
53 gboolean check_self_intersection = FALSE;
54 gchar * operation, * file1, * file2;
55 gboolean closed = TRUE, is_open1, is_open2;
56
57 /* parse options using getopt */
58 while (c != EOF) {
59 #ifdef HAVE_GETOPT_LONG
60 static struct option long_options[] = {
61 {"inter", no_argument, NULL, 'i'},
62 {"self", no_argument, NULL, 's'},
63 {"help", no_argument, NULL, 'h'},
64 {"verbose", no_argument, NULL, 'v'}
65 };
66 int option_index = 0;
67 switch ((c = getopt_long (argc, argv, "hvis",
68 long_options, &option_index))) {
69 #else /* not HAVE_GETOPT_LONG */
70 switch ((c = getopt (argc, argv, "hvis"))) {
71 #endif /* not HAVE_GETOPT_LONG */
72 case 's': /* self */
73 check_self_intersection = TRUE;
74 break;
75 case 'i': /* inter */
76 inter = TRUE;
77 break;
78 case 'v': /* verbose */
79 verbose = FALSE;
80 break;
81 case 'h': /* help */
82 fprintf (stderr,
83 "Usage: set [OPTION] OPERATION FILE1 FILE2\n"
84 "Compute set operations between surfaces, where OPERATION is either.\n"
85 "union, inter, diff.\n"
86 "\n"
87 " -i --inter output an OOGL (Geomview) representation of the curve\n"
88 " intersection of the surfaces\n"
89 " -s --self checks that the surfaces are not self-intersecting\n"
90 " if one of them is, the set of self-intersecting faces\n"
91 " is written (as a GtsSurface) on standard output\n"
92 " -v --verbose do not print statistics about the surface\n"
93 " -h --help display this help and exit\n"
94 "\n"
95 "Reports bugs to %s\n",
96 GTS_MAINTAINER);
97 return 0; /* success */
98 break;
99 case '?': /* wrong options */
100 fprintf (stderr, "Try `set --help' for more information.\n");
101 return 1; /* failure */
102 }
103 }
104
105 if (optind >= argc) { /* missing OPERATION */
106 fprintf (stderr,
107 "set: missing OPERATION\n"
108 "Try `set --help' for more information.\n");
109 return 1; /* failure */
110 }
111 operation = argv[optind++];
112
113 if (optind >= argc) { /* missing FILE1 */
114 fprintf (stderr,
115 "set: missing FILE1\n"
116 "Try `set --help' for more information.\n");
117 return 1; /* failure */
118 }
119 file1 = argv[optind++];
120
121 if (optind >= argc) { /* missing FILE2 */
122 fprintf (stderr,
123 "set: missing FILE2\n"
124 "Try `set --help' for more information.\n");
125 return 1; /* failure */
126 }
127 file2 = argv[optind++];
128
129 /* open first file */
130 if ((fptr = fopen (file1, "rt")) == NULL) {
131 fprintf (stderr, "set: can not open file `%s'\n", file1);
132 return 1;
133 }
134 /* reads in first surface file */
135 s1 = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (gts_surface_class ())));
136 fp = gts_file_new (fptr);
137 if (gts_surface_read (s1, fp)) {
138 fprintf (stderr, "set: `%s' is not a valid GTS surface file\n",
139 file1);
140 fprintf (stderr, "%s:%d:%d: %s\n", file1, fp->line, fp->pos, fp->error);
141 return 1;
142 }
143 gts_file_destroy (fp);
144 fclose (fptr);
145
146 /* open second file */
147 if ((fptr = fopen (file2, "rt")) == NULL) {
148 fprintf (stderr, "set: can not open file `%s'\n", file2);
149 return 1;
150 }
151 /* reads in second surface file */
152 s2 = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (gts_surface_class ())));
153 fp = gts_file_new (fptr);
154 if (gts_surface_read (s2, fp)) {
155 fprintf (stderr, "set: `%s' is not a valid GTS surface file\n",
156 file2);
157 fprintf (stderr, "%s:%d:%d: %s\n", file2, fp->line, fp->pos, fp->error);
158 return 1;
159 }
160 gts_file_destroy (fp);
161 fclose (fptr);
162
163 /* display summary information about both surfaces */
164 if (verbose) {
165 gts_surface_print_stats (s1, stderr);
166 gts_surface_print_stats (s2, stderr);
167 }
168
169 /* check that the surfaces are orientable manifolds */
170 if (!gts_surface_is_orientable (s1)) {
171 fprintf (stderr, "set: surface `%s' is not an orientable manifold\n",
172 file1);
173 return 1;
174 }
175 if (!gts_surface_is_orientable (s2)) {
176 fprintf (stderr, "set: surface `%s' is not an orientable manifold\n",
177 file2);
178 return 1;
179 }
180
181 /* check that the surfaces are not self-intersecting */
182 if (check_self_intersection) {
183 GtsSurface * self_intersects;
184
185 self_intersects = gts_surface_is_self_intersecting (s1);
186 if (self_intersects != NULL) {
187 fprintf (stderr, "set: surface `%s' is self-intersecting\n", file1);
188 if (verbose)
189 gts_surface_print_stats (self_intersects, stderr);
190 gts_surface_write (self_intersects, stdout);
191 gts_object_destroy (GTS_OBJECT (self_intersects));
192 return 1;
193 }
194 self_intersects = gts_surface_is_self_intersecting (s2);
195 if (self_intersects != NULL) {
196 fprintf (stderr, "set: surface `%s' is self-intersecting\n", file2);
197 if (verbose)
198 gts_surface_print_stats (self_intersects, stderr);
199 gts_surface_write (self_intersects, stdout);
200 gts_object_destroy (GTS_OBJECT (self_intersects));
201 return 1;
202 }
203 }
204
205 /* build bounding box tree for first surface */
206 tree1 = gts_bb_tree_surface (s1);
207 is_open1 = gts_surface_volume (s1) < 0. ? TRUE : FALSE;
208
209 /* build bounding box tree for second surface */
210 tree2 = gts_bb_tree_surface (s2);
211 is_open2 = gts_surface_volume (s2) < 0. ? TRUE : FALSE;
212
213 si = gts_surface_inter_new (gts_surface_inter_class (),
214 s1, s2, tree1, tree2, is_open1, is_open2);
215 g_assert (gts_surface_inter_check (si, &closed));
216 if (!closed) {
217 fprintf (stderr,
218 "set: the intersection of `%s' and `%s' is not a closed curve\n",
219 file1, file2);
220 return 1;
221 }
222
223 s3 = gts_surface_new (gts_surface_class (),
224 gts_face_class (),
225 gts_edge_class (),
226 gts_vertex_class ());
227 if (!strcmp (operation, "union")) {
228 gts_surface_inter_boolean (si, s3, GTS_1_OUT_2);
229 gts_surface_inter_boolean (si, s3, GTS_2_OUT_1);
230 }
231 else if (!strcmp (operation, "inter")) {
232 gts_surface_inter_boolean (si, s3, GTS_1_IN_2);
233 gts_surface_inter_boolean (si, s3, GTS_2_IN_1);
234 }
235 else if (!strcmp (operation, "diff")) {
236 gts_surface_inter_boolean (si, s3, GTS_1_OUT_2);
237 gts_surface_inter_boolean (si, s3, GTS_2_IN_1);
238 gts_surface_foreach_face (si->s2, (GtsFunc) gts_triangle_revert, NULL);
239 gts_surface_foreach_face (s2, (GtsFunc) gts_triangle_revert, NULL);
240 }
241 else {
242 fprintf (stderr,
243 "set: operation `%s' unknown\n"
244 "Try `set --help' for more information.\n",
245 operation);
246 return 1;
247 }
248
249 /* check that the resulting surface is not self-intersecting */
250 if (check_self_intersection) {
251 GtsSurface * self_intersects;
252
253 self_intersects = gts_surface_is_self_intersecting (s3);
254 if (self_intersects != NULL) {
255 fprintf (stderr, "set: the resulting surface is self-intersecting\n");
256 if (verbose)
257 gts_surface_print_stats (self_intersects, stderr);
258 gts_surface_write (self_intersects, stdout);
259 gts_object_destroy (GTS_OBJECT (self_intersects));
260 return 1;
261 }
262 }
263 /* display summary information about the resulting surface */
264 if (verbose)
265 gts_surface_print_stats (s3, stderr);
266 /* write resulting surface to standard output */
267 if (inter) {
268 printf ("LIST {\n");
269 g_slist_foreach (si->edges, (GFunc) write_edge, stdout);
270 printf ("}\n");
271 }
272 else {
273 GTS_POINT_CLASS (gts_vertex_class ())->binary = TRUE;
274 gts_surface_write (s3, stdout);
275 }
276
277 /* destroy surfaces */
278 gts_object_destroy (GTS_OBJECT (s1));
279 gts_object_destroy (GTS_OBJECT (s2));
280 gts_object_destroy (GTS_OBJECT (s3));
281 gts_object_destroy (GTS_OBJECT (si));
282
283 /* destroy bounding box trees (including bounding boxes) */
284 gts_bb_tree_destroy (tree1, TRUE);
285 gts_bb_tree_destroy (tree2, TRUE);
286
287 return 0;
288 }
289