BRL-CAD
test_bottess.c
Go to the documentation of this file.
1 /* T E S T _ B O T T E S S . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2011-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @file libgcv/bottess_tester.c
21  *
22  * Test things in the bottess routines...
23  */
24 
25 #include "common.h"
26 
27 #include "vmath.h"
28 #include "bn.h"
29 #include "raytrace.h"
30 #include "nmg.h"
31 #include "gcv.h"
32 
33 #include "./soup.h"
34 #include "./tri_intersect.h"
35 
36 int
37 test_intersection(int should, point_t *t1, point_t *t2, point_t p1, point_t p2)
38 {
39  int coplanar = 0;
40  point_t i[2] = {VINIT_ZERO, VINIT_ZERO};
41  vect_t tmp[2] = {VINIT_ZERO, VINIT_ZERO};
42  struct face_s f[2];
43  struct bn_tol tol;
44 
45  BN_TOL_INIT(&tol);
46  tol.dist = 0.005;
47  tol.dist_sq = tol.dist*tol.dist;
48 
49  VMOVE(f[0].vert[0], t1[0]);
50  VMOVE(f[0].vert[1], t1[1]);
51  VMOVE(f[0].vert[2], t1[2]);
52  VSUB2(tmp[0], t1[1], t1[0]);
53  VSUB2(tmp[1], t1[2], t1[0]);
54  VCROSS(f[0].plane,tmp[0], tmp[1]);
55  f[0].foo = 0;
56 
57  VMOVE(f[1].vert[0], t2[0]);
58  VMOVE(f[1].vert[1], t2[1]);
59  VMOVE(f[1].vert[2], t2[2]);
60  VSUB2(tmp[0], t2[1], t2[0]);
61  VSUB2(tmp[1], t2[2], t2[0]);
62  VCROSS(f[1].plane,tmp[0], tmp[1]);
63  f[1].foo = 0;
64 
65  if ( gcv_tri_tri_intersect_with_isectline(NULL,NULL, f, f+1, &coplanar, i, &tol) == 0 && should == 0)
66  return 0;
67  return !(VNEAR_EQUAL(i[0], p1, tol.dist) && VNEAR_EQUAL(i[1], p2, tol.dist));
68 }
69 
70 int
72 {
73  int count = 0;
74 #define TRY(suc, t00x,t00y,t00z, t01x,t01y,t01z, t02x,t02y,t02z, t10x,t10y,t10z, t11x,t11y,t11z, t12x,t12y,t12z, p0x,p0y,p0z, p1x,p1y,p1z) { \
75  point_t t0[3], t1[3], p0, p1; \
76  VSET(t0[0],t00x,t00y,t00z); VSET(t0[1],t01x,t01y,t01z); VSET(t0[2],t02x,t02y,t02z); \
77  VSET(t1[0],t10x,t10y,t10z); VSET(t1[1],t11x,t11y,t11z); VSET(t1[2],t12x,t12y,t12z); \
78  VSET(p0,p0x,p0y,p0z); VSET(p1,p1x,p1y,p1z); \
79  count += test_intersection(suc, t0, t1, p0, p1); }
80 
81  TRY(1,0,0,0,0,1,0,0,0,1,-1,0,0.5,0,1,0.5,1,0,0.5,0,0,.5,0,.5,.5); /* ep ef */
82  TRY(0,0,0,0,0,1,0,0,0,1,-1,2,0.5,0,3,0.5,1,2,0.5,0,0,.5,0,.5,.5); /* no intersect */
83 
84 #undef TRY
85  return count;
86 }
87 
88 static int
89 find_tri(struct soup_s *s, struct face_s *f, struct bn_tol *t) {
90  unsigned int i, j, k;
91  for (i=0;i<s->nfaces;i++) {
92  int found[3] = {0,0,0};
93  struct face_s *wf = s->faces+i;
94 
95  for (j=0;j<3;j++) for (k=0;k<3;k++) if (VNEAR_EQUAL( wf->vert[j], f->vert[k], t->dist)) found[j] = 1;
96  if (found[0] == 1 && found[1] == 1 && found[2] == 1) return i;
97  }
98  return -1;
99 }
100 
101 int
103 {
104  unsigned long int i, tcount = 0, count = 0, nsplt;
105  struct soup_s s;
106  struct face_s f;
107  struct bn_tol t;
108 
109  BN_TOL_INIT(&t);
110  t.dist = 0.005;
111  t.dist_sq = t.dist * t.dist;
112 
113  /* evil macros to do a lot of scaffolding, setup, execution, etc... */
114  /* prep take: the triangle to split (9 fastf_t), the intersection line (6
115  * fastf_t), and the number of expected resulting triangles. */
116 
117  /* NOTE THE "PREP" AND "POST" MACROS MUST BE USED IN PAIRS DUE TO THE SPLIT ENCLOSING CURLY BRACES */
118 #define PREP(t00,t01,t02,t10,t11,t12,t20,t21,t22, \
119  ispt00,ispt01,ispt02,ispt10,ispt11,ispt12,_nsplt) \
120  { \
121  point_t isectpt[2]; \
122  int urf[_nsplt+1]; \
123  unsigned long int failure = 0, numsplit = _nsplt; \
124  for (i = 0; i < _nsplt + 1; ++i) urf[i] = 0; \
125  tcount++; \
126  VSET(isectpt[0],ispt00,ispt01,ispt02); \
127  VSET(isectpt[1],ispt10,ispt11,ispt12); \
128  s.magic = SOUP_MAGIC; \
129  s.faces = NULL; \
130  s.maxfaces = 0; \
131  s.nfaces = 0; \
132  VSET(f.vert[0],t00,t01,t02); \
133  VSET(f.vert[1],t10,t11,t12); \
134  VSET(f.vert[2],t20,t21,t22); \
135  soup_add_face(&s,V3ARGS(f.vert),&t); \
136  VSET(f.plane,0,0,1); \
137  nsplt = split_face_single(&s,0,isectpt,&f,&t); \
138  if (nsplt != s.nfaces) { \
139  printf("Error, nsplit %lu != s.nfaces %lu ?\n", numsplit, s.nfaces); \
140  }
141 
142  /* the _splits is an array of expected triangles, as 9 fastf_t tuples */
143  /* fastf_t _splits[nsplt][9] = {{...},{...}} */
144  /* post tests to see if the resulting triangles match and cleans up */
145 #define POST(name) \
146  for (i = 0; i < numsplit; i++) { \
147  VSET(f.vert[0],_splits[i][0],_splits[i][1],_splits[i][2]); \
148  VSET(f.vert[1],_splits[i][3],_splits[i][4],_splits[i][5]); \
149  VSET(f.vert[2],_splits[i][6],_splits[i][7],_splits[i][8]); \
150  urf[i] = find_tri(&s,&f,&t); \
151  if (urf[i] == -1) failure++; \
152  } \
153  if (nsplt != 2 && urf[0] == -1 && urf[1] == -1) { \
154  printf("\033[1;31mFAILURE "name"\033[m\n"); \
155  printf("%lu faces now\n",s.nfaces); \
156  for (i = 0; i < s.nfaces; i++) \
157  printf("%03lu: % 2g,% 2g,% 2g | % 2g,% 2g,% 2g | % 2g,% 2g,% 2g\n", \
158  i, V3ARGS(s.faces[i].vert[0]), V3ARGS(s.faces[i].vert[1]), V3ARGS(s.faces[i].vert[2])); \
159  count++; \
160  } \
161  free(s.faces); \
162 } /* NOTE THIS IS THE CLOSING BRACE FROM THE OPENING BRACE IN THE PREVIOUS MACRO!! */
163 
164 
165  /* VERT/VERT */
166  PREP(0,0,0, 0,1,0, 1,0,0, 0,0,0, 0,1,0, 1); {fastf_t _splits[1][9] = {{0,0,0, 0,1,0, 1,0,0}}; POST("VERT/VERT");}
167 
168  /* VERT/EDGE */
169  PREP(-1,0,0, 0,1,0, 1,0,0, 0,0,0, 0,1,0, 2); {fastf_t _splits[2][9] = {{0,0,0,0,1,0,-1,0,0},{0,0,0,0,1,0,1,0,0}}; POST("VERT/EDGE");}
170 
171 #if 0 /* known to be broken right now. */
172  /* EDGE/EDGE */
173  PREP(-2,0,0, 0,2,0, 2,0,0, 1,1,0, -1,1,0, 3); {fastf_t _splits[3][9] = { { 1,1,0, 0,2,0, -1,1,0}, { 1,1,0, -2,0,0, 2,0,0}, {-1,1,0, 1,1,0, -2,0,0}}; POST("EDGE/EDGE");}
174 #endif
175 
176  /* VERT/FACE */
177  PREP(-2,0,0, 0,2,0, 2,0,0, 0,2,0, 0,1,0, 3); {fastf_t _splits[4][9]={ {-2,0,0,2,0,0,0,1,0}, {-2,0,0,0,2,0,0,1,0}, {2,0,0,0,2,0,0,1,0}}; POST("VERT/FACE");}
178 
179  /* EDGE/FACE */
180  PREP(-2,0,0, 0,2,0, 2,0,0, 0,0,0, 0,1,0, 4); {fastf_t _splits[4][9]={{0,0,0,-2,0,0,0,1,0},{0,0,0,2,0,0,0,1,0},{-2,0,0,0,2,0,0,1,0},{2,0,0,0,2,0,0,1,0}}; POST("EDGE/FACE");}
181 
182 #if 0 /* known to be broken right now */
183  /* FACE/FACE */
184  PREP(-2,0,0, 0,2,0, 2,0,0, 0,0,0, 0,1,0, 4); fastf_t _splits[4][9]={{0,0,0,-2,0,0,0,1,0},{0,0,0,2,0,0,0,1,0},{-2,0,0,0,2,0,0,1,0},{2,0,0,0,2,0,0,1,0}}; POST("EDGE/FACE");
185 #endif
186 
187 #undef PREP
188 #undef POST
189 
190  return count;
191 }
192 
193 int
195 {
196  int count = 0;
197 
198  int rval;
199  struct soup_s l, r;
200  struct bn_tol t;
201  point_t p[3];
202 
203 
204  BN_TOL_INIT(&t);
205  t.dist = 0.005;
206  t.dist_sq = t.dist * t.dist;
207 
208  l.magic = r.magic = SOUP_MAGIC;
209  l.faces = r.faces = NULL;
210  l.maxfaces = l.nfaces = r.maxfaces = r.nfaces = 0;
211  VSET(p[0], -1, 0, 0); VSET(p[1], 0, 1, 0); VSET(p[2], 1, 0, 0); soup_add_face(&l, p[0], p[1], p[2], &t);
212  VSET(p[0], 0, 0, -1); VSET(p[1], 0, 1, 0); VSET(p[2], 0, 0, 1); soup_add_face(&r, p[0], p[1], p[2], &t);
213 
214  rval = split_face(&l, 0, &r, 0, &t);
215  if (rval != 3 || l.nfaces != 2 || r.nfaces != 2) {
216  printf("\033[1;31mFAILURE\033[m\n");
217  count++;
218  }
219  {
220  struct face_s f;
221  int tri;
222 #define ZORF(XVAL,ZVAL,LR,FU) VSET(f.vert[0], 0,0,0); VSET(f.vert[1], 0,1,0); VSET(f.vert[2], XVAL,0,ZVAL); tri = find_tri(&LR, &f, &t); if (tri==-1 || l.faces[tri].foo != FU) { count++; printf("\033[1;31mFAILURE\033[m\n"); }
223  ZORF(1,0,l,INSIDE);
224  ZORF(-1,0,l,OUTSIDE);
225  ZORF(0,-1,r,OUTSIDE);
226  ZORF(0,1,r,INSIDE);
227 #undef ZORF
228  }
229 
230  /* TODO: add more cases */
231 
232  return count;
233 }
234 
236 {
237  return -1;
238 }
239 
241 {
242  int rval = 0;
243  unsigned int i;
244  union tree l, *r;
245  struct soup_s ls, *rs;
246  struct model lm, rm;
247  struct nmgregion lnr, rnr;
248  struct bn_tol t;
249  point_t p[3];
250 
251  BN_TOL_INIT(&t);
252  t.dist = 0.005;
253  t.dist_sq = t.dist * t.dist;
254 
255  /* assembly tree linkages */
256 #define PREP l.magic = RT_TREE_MAGIC; ls.magic = SOUP_MAGIC; lm.magic = NMG_MODEL_MAGIC; lnr.m_p = &lm; ls.faces = NULL; ls.nfaces = ls.maxfaces = 0; l.tr_d.td_r = &lnr; l.tr_d.td_r->m_p = (struct model *)&ls; BU_ALLOC(r, union tree); BU_ALLOC(rs, struct soup_s); r->magic = RT_TREE_MAGIC; rs->magic = SOUP_MAGIC; rm.magic = NMG_MODEL_MAGIC; rnr.m_p = &rm; rs->faces = NULL; rs->nfaces = rs->maxfaces = 0; r->tr_d.td_r = &rnr; r->tr_d.td_r->m_p = (struct model *)rs;
257 
258  /* test empty tree */
259  PREP;
260  compose(&l, r, 0, 0, 0); /* r is destroyed */
261  if (ls.nfaces != 0) { printf("Erm, 0+0=%lu?\n", ls.nfaces); rval++; }
262 
263  /* test no moves, all deleted */
264  PREP;
265  VSET(p[0], 0,0,0); VSET(p[1], 0,1,0); VSET(p[0], 0,0,1); soup_add_face(rs,V3ARGS(p),&t);
266  VSET(p[0], 1,0,0); VSET(p[1], 1,1,0); VSET(p[0], 1,0,1); soup_add_face(rs,V3ARGS(p),&t);
267  VSET(p[0], 2,0,0); VSET(p[1], 2,1,0); VSET(p[0], 2,0,1); soup_add_face(rs,V3ARGS(p),&t);
268  for (i=0;i<rs->nfaces;i++) rs->faces[i].foo = OUTSIDE;
269  compose(&l, r, INSIDE, OUTSIDE, INSIDE);
270  if (ls.nfaces != 0) { rval++; printf("Missing faces\n"); }
271 
272  /* test all moves, all kept */
273  PREP;
274  VSET(p[0], 0,0,0); VSET(p[1], 0,1,0); VSET(p[0], 0,0,1); soup_add_face(rs,V3ARGS(p),&t);
275  VSET(p[0], 1,0,0); VSET(p[1], 1,1,0); VSET(p[0], 1,0,1); soup_add_face(rs,V3ARGS(p),&t);
276  VSET(p[0], 2,0,0); VSET(p[1], 2,1,0); VSET(p[0], 2,0,1); soup_add_face(rs,V3ARGS(p),&t);
277  for (i=0;i<rs->nfaces;i++) rs->faces[i].foo = OUTSIDE;
278  compose(&l, r, INSIDE, OUTSIDE, OUTSIDE);
279  if (ls.nfaces != 3) { rval++; printf("Missing faces\n"); }
280 
281  /* test partial moves */
282  PREP;
283  VSET(p[0], 0,0,0); VSET(p[1], 0,1,0); VSET(p[0], 0,0,1); soup_add_face(rs,V3ARGS(p),&t);
284  VSET(p[0], 1,0,0); VSET(p[1], 1,1,0); VSET(p[0], 1,0,1); soup_add_face(rs,V3ARGS(p),&t);
285  VSET(p[0], 2,0,0); VSET(p[1], 2,1,0); VSET(p[0], 2,0,1); soup_add_face(rs,V3ARGS(p),&t);
286  rs->faces[0].foo = OUTSIDE;
287  rs->faces[1].foo = INSIDE;
288  rs->faces[2].foo = OUTSIDE;
289  compose(&l, r, INSIDE, OUTSIDE, OUTSIDE);
290  if (ls.nfaces != 2) { rval++; printf("Missing faces\n"); }
291 
292  PREP;
293  VSET(p[0], 0,0,0); VSET(p[1], 0,1,0); VSET(p[0], 0,0,1); soup_add_face(rs,V3ARGS(p),&t);
294  VSET(p[0], 1,0,0); VSET(p[1], 1,1,0); VSET(p[0], 1,0,1); soup_add_face(rs,V3ARGS(p),&t);
295  VSET(p[0], 2,0,0); VSET(p[1], 2,1,0); VSET(p[0], 2,0,1); soup_add_face(rs,V3ARGS(p),&t);
296  rs->faces[0].foo = OUTSIDE;
297  rs->faces[1].foo = INSIDE;
298  rs->faces[2].foo = OUTSIDE;
299  compose(&l, r, INSIDE, OUTSIDE, INSIDE);
300  if (ls.nfaces != 1) { rval++; printf("Missing faces\n"); }
301 #undef PREP
302  return rval;
303 }
304 
306 {
307  return -1;
308 }
309 
310 int
311 main(void)
312 {
313 #define TRY(STR,FNC) { int rval = FNC(); printf("RESULT:%18s: \033[1;", STR); if (rval) printf("31m%d\033[m failures\n", rval); else printf("32mOK\033[m\n"); }
314  TRY("tri intersection", test_tri_intersections);
315  TRY("single face split", test_face_split_single);
316  TRY("face splitting", test_face_splits);
317  TRY("invert", test_invert);
318  TRY("compose", test_compose);
319  TRY("evaluate", test_evaluate);
320 #undef TRY
321  return 0;
322 }
323 
324 /*
325  * Local Variables:
326  * tab-width: 8
327  * mode: C
328  * indent-tabs-mode: t
329  * c-file-style: "stroustrup"
330  * End:
331  * ex: shiftwidth=4 tabstop=8
332  */
#define BN_TOL_INIT(_p)
Definition: tol.h:87
int test_evaluate()
Definition: test_bottess.c:305
#define OUTSIDE
Definition: nmg_class.c:59
double dist
>= 0
Definition: tol.h:73
if lu s
Definition: nmg_mod.c:3860
#define VSET(a, b, c, d)
Definition: color.c:53
point_t vert[3]
Definition: soup.h:44
double dist_sq
dist * dist
Definition: tol.h:74
int test_face_split_single()
Definition: test_bottess.c:102
Header file for the BRL-CAD common definitions.
#define POST(name)
#define PREP(t00, t01, t02, t10, t11, t12, t20, t21, t22,ispt00, ispt01, ispt02, ispt10, ispt11, ispt12, _nsplt)
int main(void)
Definition: test_bottess.c:311
Definition: soup.h:43
#define SOUP_MAGIC
Definition: soup.h:40
union tree * compose(union tree *left_tree, union tree *right_tree, unsigned long int face_status1, unsigned long int face_status2, unsigned long int face_status3)
Definition: bottess.c:369
uint32_t magic
Definition: soup.h:50
int split_face(struct soup_s *left, unsigned long int left_face, struct soup_s *right, unsigned long int right_face, const struct bn_tol *tol)
Definition: bottess.c:248
#define V3ARGS(a)
Definition: color.c:56
#define ZORF(XVAL, ZVAL, LR, FU)
Support for uniform tolerances.
Definition: tol.h:71
int test_intersection(int should, point_t *t1, point_t *t2, point_t p1, point_t p2)
Definition: test_bottess.c:37
#define INSIDE
Definition: nmg_class.c:57
int test_invert()
Definition: test_bottess.c:235
uint32_t foo
Definition: soup.h:46
int test_tri_intersections()
Definition: test_bottess.c:71
#define TRY(suc, t00x, t00y, t00z, t01x, t01y, t01z, t02x, t02y, t02z, t10x, t10y, t10z, t11x, t11y, t11z, t12x, t12y, t12z, p0x, p0y, p0z, p1x, p1y, p1z)
int gcv_tri_tri_intersect_with_isectline(struct soup_s *left, struct soup_s *right, struct face_s *lf, struct face_s *rf, int *coplanar, point_t *isectpt, const struct bn_tol *tol)
int test_face_splits()
Definition: test_bottess.c:194
struct face_s * faces
Definition: soup.h:51
double fastf_t
Definition: defines.h:300
unsigned long int maxfaces
Definition: soup.h:52
Definition: soup.h:49
int test_compose()
Definition: test_bottess.c:240
unsigned long int nfaces
Definition: soup.h:52
int soup_add_face(struct soup_s *s, point_t a, point_t b, point_t c, const struct bn_tol *tol)
Definition: bottess.c:101