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 <math.h>
23 #include "gts.h"
24
prepend_triangle_bbox(GtsTriangle * t,GSList ** bboxes)25 static void prepend_triangle_bbox (GtsTriangle * t, GSList ** bboxes)
26 {
27 *bboxes = g_slist_prepend (*bboxes,
28 gts_bbox_triangle (gts_bbox_class (), t));
29 }
30
check_edge(GtsEdge * e,gpointer * data)31 static void check_edge (GtsEdge * e, gpointer * data)
32 {
33 GtsSurface * s1 = data[0];
34 GtsSurface * s2 = data[1];
35 guint * nf = data[2];
36
37 if (gts_edge_is_boundary (e, s1) &&
38 !gts_edge_is_boundary (e, s2)) {
39 GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (e)->v1);
40 GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (e)->v2);
41
42 printf ("VECT 1 2 0 2 0 %g %g %g %g %g %g\n",
43 p1->x, p1->y, p1->z,
44 p2->x, p2->y, p2->z);
45 (*nf)++;
46 }
47 }
48
main(int argc,char * argv[])49 int main (int argc, char * argv[])
50 {
51 GtsSurface * s1, * s2;
52 GtsSurface * s1out2, * s1in2, * s2out1, * s2in1;
53 GtsSurfaceInter * si;
54 GNode * tree1, * tree2;
55 gboolean is_open1, is_open2;
56 GSList * bboxes;
57 FILE * fptr;
58 GtsFile * fp;
59 guint n;
60 gboolean closed = TRUE;
61
62 if (argc != 3) {
63 fprintf (stderr,
64 "%s: test boolean operations between surfaces\n"
65 "usage: %s FILE1 FILE2\n",
66 argv[0], argv[0]);
67 return 1;
68 }
69
70 /* open first file */
71 if ((fptr = fopen (argv[1], "rt")) == NULL) {
72 fprintf (stderr, "%s: can not open file `%s'\n", argv[0], argv[2]);
73 return 1;
74 }
75 /* reads in first surface file */
76 s1 = gts_surface_new (gts_surface_class (),
77 GTS_FACE_CLASS (gts_nface_class ()),
78 GTS_EDGE_CLASS (gts_nedge_class ()),
79 GTS_VERTEX_CLASS (gts_nvertex_class ()));
80 fp = gts_file_new (fptr);
81 if (gts_surface_read (s1, fp)) {
82 fprintf (stderr, "boole: `%s' is not a valid GTS surface file\n",
83 argv[1]);
84 fprintf (stderr, "%s:%d:%d: %s\n", argv[1], fp->line, fp->pos, fp->error);
85 return 1;
86 }
87 gts_file_destroy (fp);
88 fclose (fptr);
89
90 /* open second file */
91 if ((fptr = fopen (argv[2], "rt")) == NULL) {
92 fprintf (stderr, "%s: can not open file `%s'\n", argv[0], argv[3]);
93 return 1;
94 }
95 /* reads in second surface file */
96 s2 = gts_surface_new (gts_surface_class (),
97 GTS_FACE_CLASS (gts_nface_class ()),
98 GTS_EDGE_CLASS (gts_nedge_class ()),
99 GTS_VERTEX_CLASS (gts_nvertex_class ()));
100 fp = gts_file_new (fptr);
101 if (gts_surface_read (s2, fp)) {
102 fprintf (stderr, "boole: `%s' is not a valid GTS surface file\n",
103 argv[2]);
104 fprintf (stderr, "%s:%d:%d: %s\n", argv[2], fp->line, fp->pos, fp->error);
105 return 1;
106 }
107 gts_file_destroy (fp);
108 fclose (fptr);
109
110 /* display summary information about both surfaces */
111 #if 0
112 gts_surface_print_stats (s1, stderr);
113 gts_surface_print_stats (s2, stderr);
114 #endif
115
116 /* check surfaces */
117 g_assert (gts_surface_is_orientable (s1));
118 g_assert (gts_surface_is_orientable (s2));
119 g_assert (!gts_surface_is_self_intersecting (s1));
120 g_assert (!gts_surface_is_self_intersecting (s2));
121
122 /* build bounding boxes for first surface */
123 bboxes = NULL;
124 gts_surface_foreach_face (s1, (GtsFunc) prepend_triangle_bbox, &bboxes);
125 /* build bounding box tree for first surface */
126 tree1 = gts_bb_tree_new (bboxes);
127 /* free list of bboxes */
128 g_slist_free (bboxes);
129 is_open1 = gts_surface_volume (s1) < 0. ? TRUE : FALSE;
130
131 /* build bounding boxes for second surface */
132 bboxes = NULL;
133 gts_surface_foreach_face (s2, (GtsFunc) prepend_triangle_bbox, &bboxes);
134 /* build bounding box tree for second surface */
135 tree2 = gts_bb_tree_new (bboxes);
136 /* free list of bboxes */
137 g_slist_free (bboxes);
138 is_open2 = gts_surface_volume (s2) < 0. ? TRUE : FALSE;
139
140 si = gts_surface_inter_new (gts_surface_inter_class (),
141 s1, s2, tree1, tree2, is_open1, is_open2);
142 g_assert (gts_surface_inter_check (si, &closed));
143
144 s1out2 = gts_surface_new (gts_surface_class (),
145 gts_face_class (),
146 gts_edge_class (),
147 gts_vertex_class ());
148 s1in2 = gts_surface_new (gts_surface_class (),
149 gts_face_class (),
150 gts_edge_class (),
151 gts_vertex_class ());
152 s2out1 = gts_surface_new (gts_surface_class (),
153 gts_face_class (),
154 gts_edge_class (),
155 gts_vertex_class ());
156 s2in1 = gts_surface_new (gts_surface_class (),
157 gts_face_class (),
158 gts_edge_class (),
159 gts_vertex_class ());
160 if (closed) {
161 GtsSurfaceStats st1out2, st1in2, st2out1, st2in1;
162 gpointer data[3];
163 guint nf = 0;
164 gdouble a, ain, aout;
165
166 gts_surface_inter_boolean (si, s1out2, GTS_1_OUT_2);
167 gts_surface_inter_boolean (si, s1in2, GTS_1_IN_2);
168 gts_surface_inter_boolean (si, s2out1, GTS_2_OUT_1);
169 gts_surface_inter_boolean (si, s2in1, GTS_2_IN_1);
170
171 gts_surface_stats (s1out2, &st1out2);
172 fprintf (stderr, "----------- 1 out 2 -----------\n");
173 gts_surface_print_stats (s1out2, stderr);
174 g_assert (st1out2.n_incompatible_faces == 0 &&
175 st1out2.n_non_manifold_edges == 0);
176
177 gts_surface_stats (s1in2, &st1in2);
178 fprintf (stderr, "----------- 1 in 2 -----------\n");
179 gts_surface_print_stats (s1in2, stderr);
180 g_assert (st1in2.n_incompatible_faces == 0 &&
181 st1in2.n_non_manifold_edges == 0 &&
182 st1in2.n_boundary_edges == st1out2.n_boundary_edges);
183 a = gts_surface_area (s1);
184 aout = gts_surface_area (s1out2);
185 ain = gts_surface_area (s1in2);
186 if (a > 0.) {
187 a = fabs (a - aout - ain)/a;
188 g_assert (a < 1e-9);
189 }
190
191 gts_surface_stats (s2out1, &st2out1);
192 fprintf (stderr, "----------- 2 out 1 -----------\n");
193 gts_surface_print_stats (s2out1, stderr);
194 g_assert (st2out1.n_incompatible_faces == 0 &&
195 st2out1.n_non_manifold_edges == 0);
196
197 gts_surface_stats (s2in1, &st2in1);
198 fprintf (stderr, "----------- 2 in 1 -----------\n");
199 gts_surface_print_stats (s2in1, stderr);
200 g_assert (st2in1.n_incompatible_faces == 0 &&
201 st2in1.n_non_manifold_edges == 0 &&
202 st2in1.n_boundary_edges == st2out1.n_boundary_edges);
203 a = gts_surface_area (s2);
204 aout = gts_surface_area (s2out1);
205 ain = gts_surface_area (s2in1);
206 if (a > 0.) {
207 a = fabs (a - aout - ain)/a;
208 g_assert (a < 1e-9);
209 }
210
211 n = g_slist_length (si->edges);
212 g_assert (n == st1in2.n_boundary_edges &&
213 n == st2in1.n_boundary_edges);
214
215 data[0] = s1out2;
216 data[1] = s1in2;
217 data[2] = &nf;
218 printf ("(geometry \"s1 failed\" = LIST {\n");
219 gts_surface_foreach_edge (s1out2, (GtsFunc) check_edge, data);
220 printf ("})\n");
221
222 data[0] = s2out1;
223 data[1] = s2in1;
224 data[2] = &nf;
225 printf ("(geometry \"s2 failed\" = LIST {\n");
226 gts_surface_foreach_edge (s2out1, (GtsFunc) check_edge, data);
227 printf ("})\n");
228
229 g_assert (nf == 0);
230 }
231 else {
232 fprintf (stderr, "----------- 1 out 2 -----------\n");
233 gts_surface_print_stats (s1out2, stderr);
234
235 fprintf (stderr, "----------- 1 in 2 -----------\n");
236 gts_surface_print_stats (s1in2, stderr);
237
238 fprintf (stderr, "----------- 2 out 1 -----------\n");
239 gts_surface_print_stats (s2out1, stderr);
240
241 fprintf (stderr, "----------- 2 in 1 -----------\n");
242 gts_surface_print_stats (s2in1, stderr);
243 }
244
245 printf ("(geometry \"1out2\" { =\n");
246 gts_surface_write_oogl (s1out2, stdout);
247 printf ("})\n"
248 "(normalization \"1out2\" none)\n");
249
250 printf ("(geometry \"1in2\" { =\n");
251 gts_surface_write_oogl (s1in2, stdout);
252 printf ("})\n"
253 "(normalization \"1in2\" none)\n");
254
255 printf ("(geometry \"2out1\" { =\n");
256 gts_surface_write_oogl (s2out1, stdout);
257 printf ("})\n"
258 "(normalization \"2out1\" none)\n");
259
260 printf ("(geometry \"2in1\" { =\n");
261 gts_surface_write_oogl (s2in1, stdout);
262 printf ("})\n"
263 "(normalization \"2in1\" none)\n");
264
265 /* destroy surfaces and intersection */
266 gts_object_destroy (GTS_OBJECT (s1));
267 gts_object_destroy (GTS_OBJECT (s2));
268 gts_object_destroy (GTS_OBJECT (si));
269
270 /* destroy bounding box trees (including bounding boxes) */
271 gts_bb_tree_destroy (tree1, TRUE);
272 gts_bb_tree_destroy (tree2, TRUE);
273
274 return 0;
275 }
276