1 /* ----------------------------------------------------------------------
2 SPARTA - Stochastic PArallel Rarefied-gas Time-accurate Analyzer
3 http://sparta.sandia.gov
4 Steve Plimpton, sjplimp@sandia.gov, Michael Gallis, magalli@sandia.gov
5 Sandia National Laboratories
6
7 Copyright (2014) Sandia Corporation. Under the terms of Contract
8 DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
9 certain rights in this software. This software is distributed under
10 the GNU General Public License.
11
12 See the README file in the top-level SPARTA directory.
13 ------------------------------------------------------------------------- */
14
15 #include "math.h"
16 #include "string.h"
17 #include "cut3d.h"
18 #include "cut2d.h"
19 #include "surf.h"
20 #include "domain.h"
21 #include "grid.h"
22 #include "comm.h"
23 #include "math_extra.h"
24 #include "memory.h"
25 #include "error.h"
26
27 using namespace SPARTA_NS;
28
29 enum{UNKNOWN,OUTSIDE,INSIDE,OVERLAP}; // several files
30 enum{CTRI,CTRIFACE,FACEPGON,FACE};
31 enum{EXTERIOR,INTERIOR,BORDER};
32 enum{ENTRY,EXIT,TWO,CORNER}; // same as Cut2d
33
34 #define EPSEDGE 1.0e-9 // minimum edge length (fraction of cell size)
35 #define SHRINK 1.0e-8 // shrink grid cell by this fraction when split fails
36
37 // cell ID for 2d or 3d cell
38
39 //#define VERBOSE
40 //#define VERBOSE_ID 61275
41
42 /* ---------------------------------------------------------------------- */
43
Cut3d(SPARTA * sparta)44 Cut3d::Cut3d(SPARTA *sparta) : Pointers(sparta)
45 {
46 implicit = surf->implicit;
47
48 ntiny = 0;
49 nshrink = 0;
50
51 cut2d = new Cut2d(sparta,0);
52 memory->create(path1,12,3,"cut3d:path1");
53 memory->create(path2,12,3,"cut3d:path2");
54 }
55
56 /* ---------------------------------------------------------------------- */
57
~Cut3d()58 Cut3d::~Cut3d()
59 {
60 delete cut2d;
61 memory->destroy(path1);
62 memory->destroy(path2);
63 }
64
65 /* ----------------------------------------------------------------------
66 compute intersections of a grid cell with all surfs
67 csurfs = indices into global surf list
68 return nsurf = # of surfs
69 return -1 if nsurf > max
70 ------------------------------------------------------------------------- */
71
surf2grid(cellint id_caller,double * lo_caller,double * hi_caller,surfint * surfs_caller,int max)72 int Cut3d::surf2grid(cellint id_caller, double *lo_caller, double *hi_caller,
73 surfint *surfs_caller, int max)
74 {
75 id = id_caller;
76 lo[0] = lo_caller[0]; lo[1] = lo_caller[1]; lo[2] = lo_caller[2];
77 hi[0] = hi_caller[0]; hi[1] = hi_caller[1]; hi[2] = hi_caller[2];
78 surfs = surfs_caller;
79
80 Surf::Tri *tris = surf->tris;
81 int ntotal = surf->nsurf;
82
83 double value;
84 double *x1,*x2,*x3;
85
86 nsurf = 0;
87 for (int m = 0; m < ntotal; m++) {
88 x1 = tris[m].p1;
89 x2 = tris[m].p2;
90 x3 = tris[m].p3;
91
92 value = MAX(x1[0],x2[0]);
93 if (MAX(value,x3[0]) < lo[0]) continue;
94 value = MIN(x1[0],x2[0]);
95 if (MIN(value,x3[0]) > hi[0]) continue;
96
97 value = MAX(x1[1],x2[1]);
98 if (MAX(value,x3[1]) < lo[1]) continue;
99 value = MIN(x1[1],x2[1]);
100 if (MIN(value,x3[1]) > hi[1]) continue;
101
102 value = MAX(x1[2],x2[2]);
103 if (MAX(value,x3[2]) < lo[2]) continue;
104 value = MIN(x1[2],x2[2]);
105 if (MIN(value,x3[2]) > hi[2]) continue;
106
107 // 3 versions of this:
108 // 1 = tri_hex_intersect with geometric line_tri_intersect,
109 // devel/cut3d.old1.py
110 // 2 = tri_hex_intersect with tetvol line_tri_intersect, here
111 // 3 = Sutherland-Hodgman clip algorithm, here and in devel/cut3d.py
112
113 //if (tri_hex_intersect(x1,x2,x3,tris[m].norm)) {
114 // if (nsurf == max) return -1;
115 // surfs[nsurf++] = m;
116 // }
117
118 if (clip(x1,x2,x3)) {
119 if (nsurf < max) surfs[nsurf] = m;
120 nsurf++;
121 }
122 }
123
124 return nsurf;
125 }
126
127 /* ----------------------------------------------------------------------
128 compute intersections of a grid cell with a provided list of surfs
129 csurfs = indices into global surf list
130 nlist, list = vector of surf indices of length nlist
131 return nsurf = # of surfs
132 return -1 if nsurf > max
133 called by AdaptGrid via Grid::surf2grid_one
134 ------------------------------------------------------------------------- */
135
surf2grid_list(cellint id_caller,double * lo_caller,double * hi_caller,int nlist,surfint * list,surfint * surfs_caller,int max)136 int Cut3d::surf2grid_list(cellint id_caller,
137 double *lo_caller, double *hi_caller,
138 int nlist, surfint *list,
139 surfint *surfs_caller, int max)
140 {
141 id = id_caller;
142 lo[0] = lo_caller[0]; lo[1] = lo_caller[1]; lo[2] = lo_caller[2];
143 hi[0] = hi_caller[0]; hi[1] = hi_caller[1]; hi[2] = hi_caller[2];
144 surfs = surfs_caller;
145
146 Surf::Tri *tris = surf->tris;
147
148 int m;
149 double value;
150 double *x1,*x2,*x3;
151
152 nsurf = 0;
153 for (int i = 0; i < nlist; i++) {
154 m = list[i];
155 x1 = tris[m].p1;
156 x2 = tris[m].p2;
157 x3 = tris[m].p3;
158
159 value = MAX(x1[0],x2[0]);
160 if (MAX(value,x3[0]) < lo[0]) continue;
161 value = MIN(x1[0],x2[0]);
162 if (MIN(value,x3[0]) > hi[0]) continue;
163
164 value = MAX(x1[1],x2[1]);
165 if (MAX(value,x3[1]) < lo[1]) continue;
166 value = MIN(x1[1],x2[1]);
167 if (MIN(value,x3[1]) > hi[1]) continue;
168
169 value = MAX(x1[2],x2[2]);
170 if (MAX(value,x3[2]) < lo[2]) continue;
171 value = MIN(x1[2],x2[2]);
172 if (MIN(value,x3[2]) > hi[2]) continue;
173
174 // 3 versions of this:
175 // 1 = tri_hex_intersect with geometric line_tri_intersect,
176 // devel/cut3d.old1.py
177 // 2 = tri_hex_intersect with tetvol line_tri_intersect, here
178 // 3 = Sutherland-Hodgman clip algorithm, here and in devel/cut3d.py
179
180 //if (tri_hex_intersect(x1,x2,x3,tris[m].norm)) {
181 // if (nsurf == max) return -1;
182 // surfs[nsurf++] = m;
183 // }
184
185 if (clip(x1,x2,x3)) {
186 if (nsurf < max) surfs[nsurf] = m;
187 nsurf++;
188 }
189 }
190
191 return nsurf;
192 }
193
194 /* ----------------------------------------------------------------------
195 compute intersections of a grid cell with a single surf
196 p012 = corner pts of surf
197 lo,hi = grid cell corner points
198 return 1 if intersects, 0 if not
199 called by Grid::surf2grid2
200 ------------------------------------------------------------------------- */
201
surf2grid_one(double * p0,double * p1,double * p2,double * lo_caller,double * hi_caller)202 int Cut3d::surf2grid_one(double *p0, double *p1, double *p2,
203 double *lo_caller, double *hi_caller)
204 {
205 lo[0] = lo_caller[0]; lo[1] = lo_caller[1]; lo[2] = lo_caller[2];
206 hi[0] = hi_caller[0]; hi[1] = hi_caller[1]; hi[2] = hi_caller[2];
207 return clip(p0,p1,p2);
208 }
209
210 /* ----------------------------------------------------------------------
211 Sutherland-Hodgman clipping algorithm
212 don't need to delete duplicate points since touching counts as intersection
213 ------------------------------------------------------------------------- */
214
clip(double * p0,double * p1,double * p2)215 int Cut3d::clip(double *p0, double *p1, double *p2)
216 {
217 int i,npath,nnew;
218 double value;
219 double *s,*e;
220 double **path,**newpath;
221
222 // initial path = tri vertices
223
224 nnew = 3;
225 memcpy(path1[0],p0,3*sizeof(double));
226 memcpy(path1[1],p1,3*sizeof(double));
227 memcpy(path1[2],p2,3*sizeof(double));
228
229 // intersect if any of tri vertices is within grid cell
230
231 if (p0[0] >= lo[0] && p0[0] <= hi[0] &&
232 p0[1] >= lo[1] && p0[1] <= hi[1] &&
233 p0[2] >= lo[2] && p0[2] <= hi[2] &&
234 p1[0] >= lo[0] && p1[0] <= hi[0] &&
235 p1[1] >= lo[1] && p1[1] <= hi[1] &&
236 p1[2] >= lo[2] && p1[2] <= hi[2] &&
237 p2[0] >= lo[0] && p2[0] <= hi[0] &&
238 p2[1] >= lo[1] && p2[1] <= hi[1] &&
239 p2[2] >= lo[2] && p2[2] <= hi[2]) return 1;
240
241 // clip tri against each of 6 grid face planes
242
243 for (int dim = 0; dim < 3; dim++) {
244 path = path1;
245 newpath = path2;
246 npath = nnew;
247 nnew = 0;
248
249 value = lo[dim];
250 s = path[npath-1];
251 for (i = 0; i < npath; i++) {
252 e = path[i];
253 if (e[dim] >= value) {
254 if (s[dim] < value) between(s,e,dim,value,newpath[nnew++]);
255 memcpy(newpath[nnew++],e,3*sizeof(double));
256 } else if (s[dim] >= value) between(e,s,dim,value,newpath[nnew++]);
257 s = e;
258 }
259 if (!nnew) return 0;
260
261 path = path2;
262 newpath = path1;
263 npath = nnew;
264 nnew = 0;
265
266 value = hi[dim];
267 s = path[npath-1];
268 for (i = 0; i < npath; i++) {
269 e = path[i];
270 if (e[dim] <= value) {
271 if (s[dim] > value) between(s,e,dim,value,newpath[nnew++]);
272 memcpy(newpath[nnew++],e,3*sizeof(double));
273 } else if (s[dim] <= value) between(e,s,dim,value,newpath[nnew++]);
274 s = e;
275 }
276 if (!nnew) return 0;
277 }
278
279 return nnew;
280 }
281
282 /* ----------------------------------------------------------------------
283 clip triangle P0 P1 P2 against cell with corners CLO,CHI
284 tri may or may not intersect cell (due to rounding)
285 return # of clipped points, can be 0,1,2,3 up to 8 (I think)
286 return clipped points in cpath as series of x,y,z triplets
287 called externally, depends on no class variables
288 duplicate points in cpath are deleted
289 uses Sutherland-Hodgman clipping algorithm
290 ------------------------------------------------------------------------- */
291
clip_external(double * p0,double * p1,double * p2,double * clo,double * chi,double * cpath)292 int Cut3d::clip_external(double *p0, double *p1, double *p2,
293 double *clo, double *chi, double *cpath)
294 {
295 int i,npath,nnew;
296 double value;
297 double *s,*e;
298 double **path,**newpath;
299
300 // initial path = tri vertices
301
302 nnew = 3;
303 memcpy(path1[0],p0,3*sizeof(double));
304 memcpy(path1[1],p1,3*sizeof(double));
305 memcpy(path1[2],p2,3*sizeof(double));
306
307 // clip tri against each of 6 grid face planes
308
309 for (int dim = 0; dim < 3; dim++) {
310 path = path1;
311 newpath = path2;
312 npath = nnew;
313 nnew = 0;
314
315 value = clo[dim];
316 s = path[npath-1];
317 for (i = 0; i < npath; i++) {
318 e = path[i];
319 if (e[dim] >= value) {
320 if (s[dim] < value) between(s,e,dim,value,newpath[nnew++]);
321 memcpy(newpath[nnew++],e,3*sizeof(double));
322 } else if (s[dim] >= value) between(e,s,dim,value,newpath[nnew++]);
323 s = e;
324 }
325 if (!nnew) return 0;
326
327 path = path2;
328 newpath = path1;
329 npath = nnew;
330 nnew = 0;
331
332 value = chi[dim];
333 s = path[npath-1];
334 for (i = 0; i < npath; i++) {
335 e = path[i];
336 if (e[dim] <= value) {
337 if (s[dim] > value) between(s,e,dim,value,newpath[nnew++]);
338 memcpy(newpath[nnew++],e,3*sizeof(double));
339 } else if (s[dim] <= value) between(e,s,dim,value,newpath[nnew++]);
340 s = e;
341 }
342 if (!nnew) return 0;
343 }
344
345 // copy path points to cpath
346 // delete any duplicate points while copying
347 // inner-loop check is to not add a point that duplicates previous point
348 // post-loop check is for duplicate due to 1st point = last point
349
350 int m = 0;
351 int n = nnew;
352 nnew = 0;
353 for (i = 0; i < n; i++) {
354 if (m) {
355 if (path1[i][0] == cpath[m-3] && path1[i][1] == cpath[m-2] &&
356 path1[i][2] == cpath[m-1]) continue;
357 }
358 cpath[m++] = path1[i][0];
359 cpath[m++] = path1[i][1];
360 cpath[m++] = path1[i][2];
361 nnew++;
362 }
363 if (nnew > 1)
364 if (cpath[0] == cpath[m-3] && cpath[1] == cpath[m-2] &&
365 cpath[2] == cpath[m-1]) nnew--;
366
367 return nnew;
368 }
369
370 /* ----------------------------------------------------------------------
371 calculate cut volume of a grid cell that contains nsurf tris
372 also calculate if cell is split into distinct sub-volumes by tris
373 return nsplit = # of splits, 1 for no split
374 return vols = ptr to vector of vols = one vol per split
375 if nsplit = 1, cut vol
376 if nsplit > 1, one vol per split cell
377 return corners = UNKNOWN/INSIDE/OUTSIDE for each of 8 corner pts
378 if nsplit > 1, also return:
379 surfmap = which sub-cell (0 to Nsurfs-1) each surf is in
380 = -1 if not in any sub-cell, discarded by add_tris
381 xsplit = coords of a point in one of the split cells
382 xsub = which sub-cell (0 to Nsplit-1) xsplit is in
383 work is done by split_try()
384 call it once more with shrunk grid cell if first attempt fails
385 ------------------------------------------------------------------------- */
386
split(cellint id_caller,double * lo_caller,double * hi_caller,int nsurf_caller,surfint * surfs_caller,double * & vols_caller,int * surfmap,int * corners,int & xsub,double * xsplit)387 int Cut3d::split(cellint id_caller, double *lo_caller, double *hi_caller,
388 int nsurf_caller, surfint *surfs_caller,
389 double *&vols_caller, int *surfmap,
390 int *corners, int &xsub, double *xsplit)
391 {
392 lo[0] = lo_caller[0]; lo[1] = lo_caller[1]; lo[2] = lo_caller[2];
393 hi[0] = hi_caller[0]; hi[1] = hi_caller[1]; hi[2] = hi_caller[2];
394
395 // perform split with full-size grid cell
396
397 int nsplit;
398 int errflag =
399 split_try(id_caller,nsurf_caller,surfs_caller,vols_caller,surfmap,
400 corners,xsub,xsplit,nsplit);
401
402 // error return
403 // try again after shrinking grid cell by SHRINK factor
404 // this gets rid of pesky errors due to tri pts/edges on cell faces
405
406 if (errflag) {
407 nshrink++;
408
409 double newlo = lo[0] + SHRINK*(hi[0]-lo[0]);
410 double newhi = hi[0] - SHRINK*(hi[0]-lo[0]);
411 lo[0] = newlo;
412 hi[0] = newhi;
413
414 newlo = lo[1] + SHRINK*(hi[1]-lo[1]);
415 newhi = hi[1] - SHRINK*(hi[1]-lo[1]);
416 lo[1] = newlo;
417 hi[1] = newhi;
418
419 newlo = lo[2] + SHRINK*(hi[2]-lo[2]);
420 newhi = hi[2] - SHRINK*(hi[2]-lo[2]);
421 lo[2] = newlo;
422 hi[2] = newhi;
423
424 errflag =
425 split_try(id_caller,nsurf_caller,surfs_caller,vols_caller,surfmap,
426 corners,xsub,xsplit,nsplit);
427 }
428
429 // could not perform cut/split -> fatal error
430 // print info about cell and final error message
431 // NOTE: could unshrink cell first
432
433 if (errflag) {
434 failed_cell();
435 split_error(errflag);
436 }
437
438 return nsplit;
439 }
440
441 /* ----------------------------------------------------------------------
442 attempt to split cell
443 return 0 if successful, otherwise return an error flag
444 called multiple times by split() with slightly different grid cell sizes
445 ------------------------------------------------------------------------- */
446
split_try(cellint id_caller,int nsurf_caller,surfint * surfs_caller,double * & vols_caller,int * surfmap,int * corners,int & xsub,double * xsplit,int & nsplit)447 int Cut3d::split_try(cellint id_caller,
448 int nsurf_caller, surfint *surfs_caller,
449 double *&vols_caller, int *surfmap,
450 int *corners, int &xsub, double *xsplit, int &nsplit)
451 {
452 id = id_caller;
453 nsurf = nsurf_caller;
454 surfs = surfs_caller;
455
456 int errflag = add_tris();
457 if (errflag) return errflag;
458
459 #ifdef VERBOSE
460 if (id == VERBOSE_ID) print_bpg("BPG after added tris");
461 #endif
462
463 clip_tris();
464 clip_adjust();
465
466 #ifdef VERBOSE
467 if (id == VERBOSE_ID) print_bpg("BPG after clipped tris");
468 #endif
469
470 // all triangles just touched cell surface
471 // mark corner points based on grazecount or touchmark value
472 // return vol = 0.0 for UNKNOWN/INSIDE, full cell vol for OUTSIDE
473 // vol is changed in Grid::set_inout() if OVERLAP cell corners are marked
474
475 if (empty) {
476 int mark = UNKNOWN;
477 if (grazecount || touchmark == INSIDE) mark = INSIDE;
478 else if (touchmark == OUTSIDE) mark = OUTSIDE;
479 corners[0] = corners[1] = corners[2] = corners[3] =
480 corners[4] = corners[5] = corners[6] = corners[7] = mark;
481
482 double vol = 0.0;
483 if (mark == OUTSIDE) vol = (hi[0]-lo[0]) * (hi[1]-lo[1]) * (hi[2]-lo[2]);
484
485 vols.grow(1);
486 vols[0] = vol;
487 vols_caller = &vols[0];
488 nsplit = 1;
489 return 0;
490 }
491
492 ctri_volume();
493 errflag = edge2face();
494 if (errflag) return errflag;
495
496 double lo2d[2],hi2d[2];
497
498 for (int iface = 0; iface < 6; iface++) {
499 if (facelist[iface].n) {
500 face_from_cell(iface,lo2d,hi2d);
501 edge2clines(iface);
502 errflag = cut2d->split_face(id,iface,lo2d,hi2d);
503 if (errflag) return errflag;
504 errflag = add_face_pgons(iface);
505 if (errflag) return errflag;
506 } else {
507 face_from_cell(iface,lo2d,hi2d);
508 errflag = add_face(iface,lo2d,hi2d);
509 if (errflag) return errflag;
510 }
511 }
512
513 remove_faces();
514
515 #ifdef VERBOSE
516 if (id == VERBOSE_ID) print_bpg("BPG after faces");
517 #endif
518
519 errflag = check();
520 if (errflag) return errflag;
521
522 walk();
523
524 #ifdef VERBOSE
525 if (id == VERBOSE_ID) print_loops();
526 #endif
527
528 errflag = loop2ph();
529
530 // loop2ph detected no positive-volume loops, cell is inside the surf
531
532 if (errflag == 4) {
533 corners[0] = corners[1] = corners[2] = corners[3] =
534 corners[4] = corners[5] = corners[6] = corners[7] = INSIDE;
535 double volume = 0.0;
536 vols.grow(1);
537 vols[0] = volume;
538 vols_caller = &vols[0];
539 nsplit = 1;
540 return 0;
541 }
542
543 // other error returns from loop2ph
544
545 if (errflag) return errflag;
546
547 // if multiple splits, find a split point
548
549 nsplit = phs.n;
550 if (nsplit > 1) {
551 create_surfmap(surfmap);
552 if (implicit) errflag = split_point_implicit(surfmap,xsplit,xsub);
553 else errflag = split_point_explicit(surfmap,xsplit,xsub);
554 }
555 if (errflag) return errflag;
556
557 // successful cut/split
558 // set corners = OUTSIDE if corner pt is in list of edge points
559 // else set corners = INSIDE
560
561 int icorner;
562 double *p1,*p2;
563
564 corners[0] = corners[1] = corners[2] = corners[3] =
565 corners[4] = corners[5] = corners[6] = corners[7] = INSIDE;
566
567 int nedge = edges.n;
568 for (int iedge = 0; iedge < nedge; iedge++) {
569 if (!edges[iedge].active) continue;
570 p1 = edges[iedge].p1;
571 p2 = edges[iedge].p2;
572 icorner = corner(p1);
573 if (icorner >= 0) corners[icorner] = OUTSIDE;
574 icorner = corner(p2);
575 if (icorner >= 0) corners[icorner] = OUTSIDE;
576 }
577
578 // store volumes in vector so can return ptr to it
579
580 vols.grow(nsplit);
581 for (int i = 0; i < nsplit; i++) vols[i] = phs[i].volume;
582 vols_caller = &vols[0];
583
584 // successful exit
585
586 return 0;
587 }
588
589 /* ----------------------------------------------------------------------
590 2-letter prefix is which method encountered error
591 ------------------------------------------------------------------------- */
592
split_error(int errflag)593 void Cut3d::split_error(int errflag)
594 {
595 if (errflag == 1)
596 error->one(FLERR,"FE: Found edge in same direction");
597 if (errflag == 2)
598 error->one(FLERR,"EF: Singlet BPG edge not on cell face");
599 if (errflag == 3)
600 error->one(FLERR,"EF: BPG edge on more than 2 faces");
601 if (errflag == 4)
602 error->one(FLERR,"LP: No positive volumes in cell");
603 if (errflag == 5)
604 error->one(FLERR,"LP: More than one positive volume with "
605 "a negative volume");
606 if (errflag == 6)
607 error->one(FLERR,"LP: Single volume is negative, inverse donut");
608 if (errflag == 7)
609 error->one(FLERR,"SP: Could not find split point in split cell");
610
611 if (errflag == 11)
612 error->one(FLERR,"CH: Vertex has less than 3 edges");
613 if (errflag == 12)
614 error->one(FLERR,"CH: Vertex contains invalid edge");
615 if (errflag == 13)
616 error->one(FLERR,"CH: Vertex contains edge that doesn't point to it");
617 if (errflag == 14)
618 error->one(FLERR,"CH: Vertex contains duplicate edge");
619 if (errflag == 15)
620 error->one(FLERR,"CH: Vertex pointers to last edge are invalid");
621 if (errflag == 16)
622 error->one(FLERR,"CH: Edge not part of 2 vertices");
623 if (errflag == 17)
624 error->one(FLERR,"CH: Edge part of same vertex twice");
625 if (errflag == 18)
626 error->one(FLERR,"CH: Edge part of invalid vertex");
627 if (errflag == 19)
628 error->one(FLERR,"CH: Edge part of invalid vertex");
629
630 if (errflag == 21)
631 error->one(FLERR,"WB: Point appears first in more than one CLINE");
632 if (errflag == 22)
633 error->one(FLERR,"WB: Point appears last in more than one CLINE");
634 if (errflag == 23)
635 error->one(FLERR,"WB: Singlet CLINES point not on cell border");
636 if (errflag == 24)
637 error->one(FLERR,"LP: No positive areas in cell");
638 if (errflag == 25)
639 error->one(FLERR,"LP: More than one positive area with a negative area");
640 if (errflag == 26)
641 error->one(FLERR,"LP: Single area is negative, inverse donut");
642 }
643
644 /* ----------------------------------------------------------------------
645 add each triangle as vertex and edges to BPG
646 add full edge even if outside cell, clipping comes later
647 skip transparent surfs
648 ------------------------------------------------------------------------- */
649
add_tris()650 int Cut3d::add_tris()
651 {
652 int i,m;
653 int e1,e2,e3,dir1,dir2,dir3;
654 double p1[3],p2[3],p3[3];
655 Surf::Tri *tri;
656 Vertex *vert;
657 Edge *edge;
658
659 Surf::Tri *tris = surf->tris;
660
661 verts.grow(nsurf);
662 edges.grow(3*nsurf);
663 verts.n = 0;
664 edges.n = 0;
665
666 int nvert = 0;
667 for (i = 0; i < nsurf; i++) {
668 m = surfs[i];
669 tri = &tris[m];
670 if (tri->transparent) continue;
671
672 memcpy(p1,tri->p1,3*sizeof(double));
673 memcpy(p2,tri->p2,3*sizeof(double));
674 memcpy(p3,tri->p3,3*sizeof(double));
675
676 vert = &verts[nvert];
677 vert->active = 1;
678 vert->style = CTRI;
679 vert->label = i;
680 vert->nedge = 0;
681 vert->volume = 0.0;
682 vert->norm = tri->norm;
683
684 // look for each edge of tri
685 // add to edges in forward dir if doesn't yet exist
686 // add to edges in reverse dir if already exists
687
688 e1 = findedge(p1,p2,0,dir1);
689 if (e1 == -2) return 1;
690
691 if (e1 < 0) {
692 e1 = edges.n++;
693 dir1 = 0;
694 edge = &edges[e1];
695 edge->style = CTRI;
696 edge->nvert = 0;
697 edge->verts[0] = edge->verts[1] = -1;
698 memcpy(edge->p1,p1,3*sizeof(double));
699 memcpy(edge->p2,p2,3*sizeof(double));
700 }
701 edge_insert(e1,dir1,nvert,-1,-1,-1,-1);
702
703 e2 = findedge(p2,p3,0,dir2);
704 if (e2 == -2) return 1;
705
706 if (e2 < 0) {
707 e2 = edges.n++;
708 dir2 = 0;
709 edge = &edges[e2];
710 edge->style = CTRI;
711 edge->nvert = 0;
712 edge->verts[0] = edge->verts[1] = -1;
713 memcpy(edge->p1,p2,3*sizeof(double));
714 memcpy(edge->p2,p3,3*sizeof(double));
715 }
716 edge_insert(e2,dir2,nvert,e1,dir1,-1,-1);
717
718 e3 = findedge(p3,p1,0,dir3);
719 if (e3 == -2) return 1;
720
721 if (e3 < 0) {
722 e3 = edges.n++;
723 dir3 = 0;
724 edge = &edges[e3];
725 edge->style = CTRI;
726 edge->nvert = 0;
727 edge->verts[0] = edge->verts[1] = -1;
728 memcpy(edge->p1,p3,3*sizeof(double));
729 memcpy(edge->p2,p1,3*sizeof(double));
730 }
731 edge_insert(e3,dir3,nvert,e2,dir2,-1,-1);
732
733 nvert++;
734 }
735
736 verts.n = nvert;
737 return 0;
738 }
739
740 /* ----------------------------------------------------------------------
741 clip collection of tris that overlap cell by 6 faces of cell
742 loop over faces, loop over tris, loop over edges in tri
743 edges fully outside the cell are removed
744 shared edges that intersect the cell are clipped consistently
745 ------------------------------------------------------------------------- */
746
clip_tris()747 void Cut3d::clip_tris()
748 {
749 int i,n,dim,lohi,ivert,iedge,jedge,idir,jdir,nedge;
750 int p1flag,p2flag;
751 double value;
752 double *p1,*p2,*p3;
753 Edge *edge,*newedge;
754
755 // loop over all 6 faces of cell
756
757 int nvert = verts.n;
758
759 for (int iface = 0; iface < 6; iface++) {
760 dim = iface / 2;
761 lohi = iface % 2;
762 if (lohi == 0) value = lo[dim];
763 else value = hi[dim];
764
765 // mark all edges as unclipped
766 // some may have been clipped and not cleared on previous face
767
768 nedge = edges.n;
769 for (iedge = 0; iedge < nedge; iedge++)
770 if (edges[iedge].active) edges[iedge].clipped = 0;
771
772 // loop over vertices, clip each of its edges to face
773 // if edge already clipped, unset clip flag and keep edge as-is
774
775 for (ivert = 0; ivert < nvert; ivert++) {
776 iedge = verts[ivert].first;
777 idir = verts[ivert].dirfirst;
778 nedge = verts[ivert].nedge;
779
780 for (i = 0; i < nedge; i++) {
781 edge = &edges[iedge];
782
783 if (edge->clipped) {
784 edge->clipped = 0;
785 iedge = edge->next[idir];
786 idir = edge->dirnext[idir];
787 continue;
788 }
789
790 // p1/p2 are pts in order of traversal
791
792 if (idir == 0) {
793 p1 = edge->p1;
794 p2 = edge->p2;
795 } else {
796 p1 = edge->p2;
797 p2 = edge->p1;
798 }
799
800 // p1/p2 flag = OUTSIDE/ON/INSIDE for edge pts
801
802 if (lohi == 0) {
803 if (p1[dim] < value) p1flag = OUTSIDE;
804 else if (p1[dim] > value) p1flag = INSIDE;
805 else p1flag = OVERLAP;
806 if (p2[dim] < value) p2flag = OUTSIDE;
807 else if (p2[dim] > value) p2flag = INSIDE;
808 else p2flag = OVERLAP;
809 } else {
810 if (p1[dim] < value) p1flag = INSIDE;
811 else if (p1[dim] > value) p1flag = OUTSIDE;
812 else p1flag = OVERLAP;
813 if (p2[dim] < value) p2flag = INSIDE;
814 else if (p2[dim] > value) p2flag = OUTSIDE;
815 else p2flag = OVERLAP;
816 }
817
818 // if both OUTSIDE or one OUTSIDE and other ON, delete edge
819 // if both INSIDE or one INSIDE and other ON or both ON, keep as-is
820 // if one INSIDE and one OUTSIDE, replace OUTSIDE pt with clip pt
821
822 #ifdef VERBOSE
823 /*
824 if (id == VERBOSE_ID && ivert == 1) {
825 printf("EDGE %d %d: %d %d: %d %d: %d\n",iedge,idir,p1flag,p2flag,
826 edge->verts[0],edge->verts[1],edge->prev[0]);
827 }
828 */
829 #endif
830
831 if (p1flag == OUTSIDE) {
832 if (p2flag == OUTSIDE || p2flag == OVERLAP) edge_remove(edge,idir);
833 else {
834 if (idir == 0) between(p1,p2,dim,value,edge->p1);
835 else between(p1,p2,dim,value,edge->p2);
836 edge->clipped = 1;
837 }
838 } else if (p1flag == INSIDE) {
839 if (p2flag == OUTSIDE) {
840 if (idir == 0) between(p1,p2,dim,value,edge->p2);
841 else between(p1,p2,dim,value,edge->p1);
842 edge->clipped = 1;
843 }
844 } else {
845 if (p2flag == OUTSIDE) edge_remove(edge,idir);
846 }
847
848 iedge = edge->next[idir];
849 idir = edge->dirnext[idir];
850 }
851
852 #ifdef VERBOSE
853 /*
854 if (id == VERBOSE_ID) {
855 char str[24];
856 sprintf(str,"Partial FACE %d %d\n",iface,ivert);
857 print_bpg(str);
858 }
859 */
860 #endif
861
862 // loop over edges in vertex again
863 // iedge = this edge, jedge = next edge
864 // p1 = last pt in iedge, pt = first pt in jedge
865 // if p1 != p2, add edge between them
866
867 edges.grow(edges.n + verts[ivert].nedge);
868 iedge = verts[ivert].first;
869 idir = verts[ivert].dirfirst;
870
871 for (i = 0; i < verts[ivert].nedge; i++) {
872 edge = &edges[iedge];
873 jedge = edge->next[idir];
874 jdir = edge->dirnext[idir];
875 if (jedge < 0) {
876 jedge = verts[ivert].first;
877 jdir = verts[ivert].dirfirst;
878 }
879
880 if (idir == 0) p1 = edge->p2;
881 else p1 = edge->p1;
882 if (jdir == 0) p2 = edges[jedge].p1;
883 else p2 = edges[jedge].p2;
884
885 if (!samepoint(p1,p2)) {
886 n = edges.n++;
887 newedge = &edges[n];
888 newedge->style = CTRI;
889 newedge->nvert = 0;
890 newedge->verts[0] = newedge->verts[1] = -1;
891 memcpy(newedge->p1,p1,3*sizeof(double));
892 memcpy(newedge->p2,p2,3*sizeof(double));
893 // convert jedge back to -1 for last vertex
894 if (jedge == verts[ivert].first) jedge = -1;
895 edge_insert(n,0,ivert,iedge,idir,jedge,jdir);
896 i++;
897 }
898
899 iedge = jedge;
900 idir = jdir;
901 }
902 }
903
904 #ifdef VERBOSE
905 /*
906 if (id == VERBOSE_ID) {
907 char str[24];
908 sprintf(str,"After FACE %d\n",iface);
909 print_bpg(str);
910 }
911 */
912 #endif
913 }
914 }
915
916 /* ----------------------------------------------------------------------
917 adjust the collection of clipped triangles (vertices)
918 discard if clipped tri is a single point, increment touchcount
919 touchmark = corner point marking inferred from touching tri orientations
920 discard if grazes cell with outward normal, increment grazecount
921 if all clipped tris are discarded
922 set and return empty, touchcount, grazecount, touchmark
923 ------------------------------------------------------------------------- */
924
clip_adjust()925 void Cut3d::clip_adjust()
926 {
927 int nvert,nedge,nface1,nface2;
928 int faces1[6],faces2[6];
929 double pboth[3],move1[3],move2[3];
930 double *p1,*p2,*p3;
931 Edge *edge;
932
933 #ifdef VERBOSE
934 if (id == VERBOSE_ID) print_bpg("BPG after initial clipping");
935 #endif
936
937 // epsilon = EPSEDGE fraction of largest cell dimension
938
939 epsilon = EPSEDGE*(hi[0]-lo[0]);
940 epsilon = MAX(epsilon,EPSEDGE*(hi[1]-lo[1]));
941 epsilon = MAX(epsilon,EPSEDGE*(hi[2]-lo[2]));
942
943 // collapse edges shorter than epsilon to a single point (so will be removed)
944 // one or both of the points should be on cell faces
945 // tiny edges can occur for several reasons:
946 // (1) pre-clip end point is within epsilon of face
947 // (2) a tri barely grazes cell edge or corner
948 // (3) clipping round-off produces tiny edges near cell faces
949
950 nedge = edges.n;
951
952 for (int iedge = 0; iedge < nedge; iedge++) {
953 if (!edges[iedge].active) continue;
954
955 edge = &edges[iedge];
956 p1 = edge->p1;
957 p2 = edge->p2;
958 double dx = p1[0]-p2[0];
959 double dy = p1[1]-p2[1];
960 double dz = p1[2]-p2[2];
961 double edgelen = sqrt(dx*dx+dy*dy+dz*dz);
962
963 if (edgelen < epsilon) {
964 //printf("TINY EDGE id %ld nsurf %d i/nedge %d %d len %g eps %g\n",
965 // id,nsurf,iedge,nedge,edgelen,epsilon);
966 ntiny++;
967
968 nface1 = on_faces(p1,faces1);
969 nface2 = on_faces(p2,faces2);
970
971 // set both p1 and p2 to same pboth
972 // if both pts are interior (should not happen), pboth = p1
973 // if only one pt X is on a face, pboth = X
974 // if both pts are on one or more faces:
975 // push both to face(s), recalculate on_faces()
976 // if pt X is on more faces, pboth = X, else pboth = p1
977
978 if (!nface1 && !nface2) {
979 memcpy(pboth,p1,3*sizeof(double));
980 //printf("INTERIOR EDGE %ld %d %d %g %g\n",
981 // id,iedge,nedge,edgelen,epsilon);
982 } else if (nface1 && !nface2) {
983 memcpy(pboth,p1,3*sizeof(double));
984 } else if (nface2 && !nface1) {
985 memcpy(pboth,p2,3*sizeof(double));
986 } else {
987 memcpy(move1,p1,3*sizeof(double));
988 memcpy(move2,p2,3*sizeof(double));
989 move_to_faces(move1);
990 move_to_faces(move2);
991 nface1 = on_faces(move1,faces1);
992 nface2 = on_faces(move2,faces2);
993 if (nface2 > nface1) memcpy(pboth,move2,3*sizeof(double));
994 else memcpy(pboth,move1,3*sizeof(double));
995 }
996
997 // set all points that are same as old p1 or p2 to pboth
998 // reset first for all jedge != iedge, then reset iedge
999
1000 for (int jedge = 0; jedge < nedge; jedge++) {
1001 if (!edges[jedge].active) continue;
1002 if (jedge == iedge) continue;
1003
1004 if (samepoint(edges[jedge].p1,p1))
1005 memcpy(edges[jedge].p1,pboth,3*sizeof(double));
1006 if (samepoint(edges[jedge].p2,p1))
1007 memcpy(edges[jedge].p2,pboth,3*sizeof(double));
1008
1009 if (samepoint(edges[jedge].p1,p2))
1010 memcpy(edges[jedge].p1,pboth,3*sizeof(double));
1011 if (samepoint(edges[jedge].p2,p2))
1012 memcpy(edges[jedge].p2,pboth,3*sizeof(double));
1013 }
1014
1015 memcpy(edges[iedge].p1,pboth,3*sizeof(double));
1016 memcpy(edges[iedge].p2,pboth,3*sizeof(double));
1017 }
1018 }
1019
1020 #ifdef VERBOSE
1021 if (id == VERBOSE_ID) print_bpg("BPG after tiny edge collapse");
1022 #endif
1023
1024 // remove zero-length edges
1025
1026 nedge = edges.n;
1027
1028 for (int iedge = 0; iedge < nedge; iedge++) {
1029 if (!edges[iedge].active) continue;
1030 edge = &edges[iedge];
1031 if (samepoint(edge->p1,edge->p2)) edge_remove(edge);
1032 }
1033
1034 #ifdef VERBOSE
1035 if (id == VERBOSE_ID) print_bpg("BPG after remove zero-length edges");
1036 #endif
1037
1038 // remove vertices (triangles) which now have less than 3 edges
1039 // do this after deleting zero-length edges so vertices are updated
1040 // removals should have 2 or 0 edges, no verts should have 1 edge
1041 // if all triangles are removed, BPG will be empty,
1042 // which will result in cell corner pts being left UNKNOWN in split()
1043 // to try and avoid this, tally inside/outside for all removed tris
1044 // tri is "outside" if it implies cell is outside the surf (in the flow)
1045 // tri is "inside" if it implies cell is inside the surf (not in the flow)
1046 // some tris may not follow this rule, but most should
1047 // outside = tri norm from tri ctr points towards cell ctr
1048 // inside = tri norm from tri ctr points away from cell ctr
1049 // cbox = cell center pt, ctri = triangle center pt, t2b = cbox-ctri
1050
1051 touchcount = 0;
1052 grazecount = 0;
1053
1054 int noutside = 0;
1055 int ninside = 0;
1056
1057 double cbox[3],ctri[3],t2b[3];
1058
1059 nvert = verts.n;
1060
1061 for (int ivert = 0; ivert < nvert; ivert++)
1062 if (verts[ivert].nedge <= 2) {
1063 touchcount++;
1064 cbox[0] = 0.5*(lo[0]+hi[0]);
1065 cbox[1] = 0.5*(lo[1]+hi[1]);
1066 cbox[2] = 0.5*(lo[2]+hi[2]);
1067 int itri = surfs[verts[ivert].label];
1068 p1 = surf->tris[itri].p1;
1069 p2 = surf->tris[itri].p2;
1070 p3 = surf->tris[itri].p3;
1071 ctri[0] = (p1[0]+p2[0]+p3[0])/3.0;
1072 ctri[1] = (p1[1]+p2[1]+p3[1])/3.0;
1073 ctri[2] = (p1[2]+p2[2]+p3[2])/3.0;
1074 MathExtra::sub3(cbox,ctri,t2b);
1075 double dot = MathExtra::dot3(verts[ivert].norm,t2b);
1076 if (dot > 0.0) noutside++;
1077 if (dot < 0.0) ninside++;
1078 vertex_remove(&verts[ivert]);
1079 }
1080
1081 // discard clipped tri if lies on a cell face w/ normal out of cell
1082 // increment grazecount in this case
1083
1084 for (int ivert = 0; ivert < nvert; ivert++) {
1085 if (!verts[ivert].active) continue;
1086 if (grazing(&verts[ivert])) {
1087 vertex_remove(&verts[ivert]);
1088 grazecount++;
1089 }
1090 }
1091
1092 // remove edges which now have no vertices
1093
1094 for (int iedge = 0; iedge < nedge; iedge++) {
1095 if (!edges[iedge].active) continue;
1096 if (edges[iedge].nvert == 0) edges[iedge].active = 0;
1097 }
1098
1099 // set BPG empty flag if no active vertices
1100
1101 empty = 1;
1102 for (int ivert = 0; ivert < nvert; ivert++)
1103 if (verts[ivert].active) {
1104 empty = 0;
1105 break;
1106 }
1107
1108 // if no lines, set touchmark which will be used to mark corner points
1109 // only set touchmark if all deleted tris had same orientation
1110 // NOTE: setting touchmark based on orientation of just majority
1111 // triggered later corner marking error for cone_test/in.cone problem
1112
1113 touchmark = UNKNOWN;
1114 if (empty) {
1115 if (ninside && noutside == 0) touchmark = INSIDE;
1116 else if (noutside && ninside == 0) touchmark = OUTSIDE;
1117 }
1118 }
1119
1120 /* ----------------------------------------------------------------------
1121 compute volume of vertices
1122 when called, only clipped triangles exist
1123 ------------------------------------------------------------------------- */
1124
ctri_volume()1125 void Cut3d::ctri_volume()
1126 {
1127 int i,iedge,idir,nedge;
1128 double zarea,volume;
1129 double *p0,*p1,*p2;
1130 Edge *edge;
1131
1132 int nvert = verts.n;
1133 for (int ivert = 0; ivert < nvert; ivert++) {
1134 if (!verts[ivert].active) continue;
1135 iedge = verts[ivert].first;
1136 idir = verts[ivert].dirfirst;
1137 nedge = verts[ivert].nedge;
1138
1139 if (idir == 0) p0 = edges[iedge].p1;
1140 else p0 = edges[iedge].p2;
1141
1142 volume = 0.0;
1143
1144 for (i = 0; i < nedge; i++) {
1145 edge = &edges[iedge];
1146
1147 // compute projected volume of a convex polygon to zlo face
1148 // split polygon into triangles
1149 // each tri makes a tri-capped volume with zlo face
1150 // zarea = area of oriented tri projected into z plane
1151 // volume based on height of z midpt of tri above zlo face
1152
1153 if (idir == 0) {
1154 p1 = edge->p1;
1155 p2 = edge->p2;
1156 } else {
1157 p1 = edge->p2;
1158 p2 = edge->p1;
1159 }
1160 zarea = 0.5 * ((p1[0]-p0[0])*(p2[1]-p0[1]) - (p1[1]-p0[1])*(p2[0]-p0[0]));
1161 volume -= zarea * ((p0[2]+p1[2]+p2[2])/3.0 - lo[2]);
1162
1163 iedge = edge->next[idir];
1164 idir = edge->dirnext[idir];
1165 }
1166
1167 verts[ivert].volume = volume;
1168 }
1169 }
1170
1171 /* ----------------------------------------------------------------------
1172 assign all singlet edges to faces (0-5)
1173 singlet edge must be on one or two faces, two if on cell edge
1174 if along cell edge, assign to one of two faces based on
1175 which has larger dot product of its inward face norm
1176 and the norm of the tri containing the edge
1177 ------------------------------------------------------------------------- */
1178
edge2face()1179 int Cut3d::edge2face()
1180 {
1181 int n,iface,nface,ivert;
1182 int faces[6];
1183 double dot0,dot1;
1184 double norm_inward[3];
1185 double *trinorm;
1186 Edge *edge;
1187
1188 // insure each facelist has sufficient length
1189
1190 int nedge = edges.n;
1191 for (int i = 0; i < 6; i++) {
1192 facelist[i].grow(nedge);
1193 facelist[i].n = 0;
1194 }
1195
1196 // loop over edges, assign singlets to exactly one face
1197
1198 for (int iedge = 0; iedge < nedge; iedge++) {
1199 if (!edges[iedge].active) continue;
1200 if (edges[iedge].nvert == 3) continue;
1201 edge = &edges[iedge];
1202
1203 nface = which_faces(edge->p1,edge->p2,faces);
1204 if (nface == 0) {
1205 //printf("ERROR RETURN id %ld nedge %d iedge %d pt1 "
1206 // "%20.16g %20.16g %20.16g %20.16g %20.16g %20.16g\n",
1207 // id,nedge,iedge,
1208 // edge->p1[0],edge->p1[1],edge->p1[2],
1209 // edge->p2[0],edge->p2[1],edge->p2[2]);
1210 return 2;
1211 }
1212
1213 else if (nface == 1) iface = faces[0];
1214
1215 else if (nface == 2) {
1216 if (edge->nvert == 1) ivert = edge->verts[0];
1217 else ivert = edge->verts[1];
1218 trinorm = verts[ivert].norm;
1219
1220 iface = faces[0];
1221 norm_inward[0] = norm_inward[1] = norm_inward[2] = 0.0;
1222 if (iface % 2) norm_inward[iface/2] = -1.0;
1223 else norm_inward[iface/2] = 1.0;
1224 dot0 = norm_inward[0]*trinorm[0] + norm_inward[1]*trinorm[1] +
1225 norm_inward[2]*trinorm[2];
1226 if (dot0 > 0.0) iface = faces[1];
1227
1228 } else return 3;
1229
1230 n = facelist[iface].n;
1231 facelist[iface][n++] = iedge;
1232 facelist[iface].n = n;
1233 }
1234
1235 return 0;
1236 }
1237
1238 /* ----------------------------------------------------------------------
1239 build a 2d CLINES data structure
1240 from all singlet edges assigned to iface (0-5)
1241 order pts in edge for tri traversing edge in forward order
1242 flip edge if in a flip face = faces 0,3,4
1243 edge label in clines = edge index in BPG
1244 ------------------------------------------------------------------------- */
1245
edge2clines(int iface)1246 void Cut3d::edge2clines(int iface)
1247 {
1248 int iedge;
1249 double *p1,*p2;
1250 Edge *edge;
1251 Cut2d::Cline *cline;
1252
1253 MyVec<Cut2d::Cline> *clines = &cut2d->clines;
1254
1255 int flip = 0;
1256 if (iface == 0 || iface == 3 || iface == 4) flip = 1;
1257
1258 int nline = facelist[iface].n;
1259 clines->n = 0;
1260 clines->grow(nline);
1261
1262 for (int i = 0; i < nline; i++) {
1263 iedge = facelist[iface][i];
1264 edge = &edges[iedge];
1265 if (edge->nvert == 1) {
1266 p1 = edge->p1;
1267 p2 = edge->p2;
1268 } else {
1269 p1 = edge->p2;
1270 p2 = edge->p1;
1271 }
1272 cline = &(*clines)[i];
1273 cline->line = iedge;
1274 if (flip) {
1275 compress2d(iface,p1,cline->y);
1276 compress2d(iface,p2,cline->x);
1277 } else {
1278 compress2d(iface,p1,cline->x);
1279 compress2d(iface,p2,cline->y);
1280 }
1281 }
1282
1283 clines->n = nline;
1284 }
1285
1286 /* ----------------------------------------------------------------------
1287 add one or more face polygons as vertices to BPG
1288 have to convert pts computed by cut2d back into 3d pts on face
1289 ------------------------------------------------------------------------- */
1290
add_face_pgons(int iface)1291 int Cut3d::add_face_pgons(int iface)
1292 {
1293 int iloop,mloop,nloop,ipt,mpt,npt;
1294 int iedge,dir,prev,dirprev;
1295 double p1[3],p2[3];
1296 Vertex *vert;
1297 Edge *edge;
1298 Cut2d::PG *pg;
1299 Cut2d::Loop *loop;
1300 Cut2d::Point *p12d,*p22d;
1301
1302 MyVec<Cut2d::PG> *pgs = &cut2d->pgs;
1303 MyVec<Cut2d::Loop> *loops = &cut2d->loops;
1304 MyVec<Cut2d::Point> *points = &cut2d->points;
1305
1306 int flip = 0;
1307 if (iface == 0 || iface == 3 || iface == 4) flip = 1;
1308
1309 double value;
1310 int dim = iface / 2;
1311 int lohi = iface % 2;
1312 if (lohi == 0) value = lo[dim];
1313 else value = hi[dim];
1314
1315 int npg = pgs->n;
1316 int nvert = verts.n;
1317 verts.grow(nvert+npg);
1318
1319 for (int ipg = 0; ipg < npg; ipg++) {
1320 pg = &(*pgs)[ipg];
1321
1322 vert = &verts[nvert];
1323 vert->active = 1;
1324 vert->style = FACEPGON;
1325 vert->label = iface;
1326 if (iface == 5) vert->volume = pg->area * (hi[2]-lo[2]);
1327 else vert->volume = 0.0;
1328 vert->nedge = 0;
1329 vert->norm = NULL;
1330
1331 prev = -1;
1332 dirprev = -1;
1333
1334 nloop = pg->n;
1335 mloop = pg->first;
1336 for (iloop = 0; iloop < nloop; iloop++) {
1337 loop = &(*loops)[mloop];
1338 npt = loop->n;
1339 mpt = loop->first;
1340 edges.grow(edges.n + npt);
1341
1342 for (ipt = 0; ipt < npt; ipt++) {
1343 p12d = &(*points)[mpt];
1344 mpt = p12d->next;
1345 p22d = &(*points)[mpt];
1346 expand2d(iface,value,p12d->x,p1);
1347 expand2d(iface,value,p22d->x,p2);
1348
1349 // edge was from a CTRI vertex
1350 // match in opposite order that CTRI vertex matched it
1351
1352 if (p12d->type == ENTRY || p12d->type == TWO) {
1353 iedge = p12d->line;
1354 edge = &edges[iedge];
1355 edge->style = CTRIFACE;
1356 if (edge->nvert == 1) dir = 1;
1357 else dir = 0;
1358 edge_insert(iedge,dir,nvert,prev,dirprev,-1,-1);
1359 prev = iedge;
1360 dirprev = dir;
1361 continue;
1362 }
1363
1364 // face edge not from a CTRI
1365 // unflip edge if in a flip face
1366
1367 if (flip) iedge = findedge(p2,p1,0,dir);
1368 else iedge = findedge(p1,p2,0,dir);
1369 if (iedge == -2) return 1;
1370
1371 if (iedge >= 0) {
1372 edge_insert(iedge,dir,nvert,prev,dirprev,-1,-1);
1373 prev = iedge;
1374 dirprev = 1;
1375 continue;
1376 }
1377
1378 iedge = edges.n++;
1379 edge = &edges[iedge];
1380 edge->style = FACEPGON;
1381 edge->nvert = 0;
1382 edge->verts[0] = edge->verts[1] = -1;
1383 if (flip) {
1384 memcpy(edge->p1,p2,3*sizeof(double));
1385 memcpy(edge->p2,p1,3*sizeof(double));
1386 } else {
1387 memcpy(edge->p1,p1,3*sizeof(double));
1388 memcpy(edge->p2,p2,3*sizeof(double));
1389 }
1390 dir = 0;
1391 edge_insert(iedge,dir,nvert,prev,dirprev,-1,-1);
1392 prev = iedge;
1393 dirprev = 0;
1394 }
1395 mloop = loop->next;
1396 }
1397
1398 nvert++;
1399 }
1400
1401 verts.n = nvert;
1402 return 0;
1403 }
1404
1405 /* ----------------------------------------------------------------------
1406 add an entire cell face as vertex to BPG
1407 if outerflag2d = 0, create new vertex
1408 else face polygon already exists, so add edges to it
1409 caller sets outerflag2d if cut2d requires adding perimeter face edges
1410 ------------------------------------------------------------------------- */
1411
add_face(int iface,double * lo2d,double * hi2d)1412 int Cut3d::add_face(int iface, double *lo2d, double *hi2d)
1413 {
1414 int i,j,iedge,dir,prev,dirprev;
1415 double p1[3],p2[3];
1416 Vertex *vert;
1417 Edge *edge;
1418
1419 int nvert = verts.n++;
1420 verts.grow(nvert + 1);
1421 vert = &verts[nvert];
1422 vert->active = 1;
1423 vert->style = FACE;
1424 vert->label = iface;
1425 if (iface == 5)
1426 vert->volume = (hi[0]-lo[0]) * (hi[1]-lo[1]) * (hi[2]-lo[2]);
1427 else vert->volume = 0.0;
1428 vert->nedge = 0;
1429 vert->norm = NULL;
1430
1431 double value;
1432 int dim = iface / 2;
1433 int lohi = iface % 2;
1434 if (lohi == 0) value = lo[dim];
1435 else value = hi[dim];
1436
1437 // usual ordering of points in face as LL,LR,UR,UL
1438 // flip order if in a flip face
1439
1440 int flip = 0;
1441 if (iface == 0 || iface == 3 || iface == 4) flip = 1;
1442
1443 double cpts[4][2];
1444
1445 if (flip) {
1446 cpts[0][0] = lo2d[0]; cpts[0][1] = lo2d[1];
1447 cpts[1][0] = lo2d[0]; cpts[1][1] = hi2d[1];
1448 cpts[2][0] = hi2d[0]; cpts[2][1] = hi2d[1];
1449 cpts[3][0] = hi2d[0]; cpts[3][1] = lo2d[1];
1450 } else {
1451 cpts[0][0] = lo2d[0]; cpts[0][1] = lo2d[1];
1452 cpts[1][0] = hi2d[0]; cpts[1][1] = lo2d[1];
1453 cpts[2][0] = hi2d[0]; cpts[2][1] = hi2d[1];
1454 cpts[3][0] = lo2d[0]; cpts[3][1] = hi2d[1];
1455 }
1456
1457 if (vert->nedge) {
1458 prev = vert->last;
1459 dirprev = vert->dirlast;
1460 } else {
1461 prev = -1;
1462 dirprev = -1;
1463 }
1464
1465 edges.grow(edges.n + 4);
1466
1467 for (i = 0; i < 4; i++) {
1468 j = i+1;
1469 if (j == 4) j = 0;
1470 expand2d(iface,value,&cpts[i][0],p1);
1471 expand2d(iface,value,&cpts[j][0],p2);
1472 iedge = findedge(p1,p2,1,dir);
1473 if (iedge == -2) return 1;
1474
1475 if (iedge >= 0) {
1476 edge_insert(iedge,dir,nvert,prev,dirprev,-1,-1);
1477 prev = iedge;
1478 dirprev = 1;
1479 continue;
1480 }
1481
1482 iedge = edges.n++;
1483 edge = &edges[iedge];
1484 edge->style = vert->style;
1485 edge->nvert = 0;
1486 edge->verts[0] = edge->verts[1] = -1;
1487 memcpy(edge->p1,p1,3*sizeof(double));
1488 memcpy(edge->p2,p2,3*sizeof(double));
1489 dir = 0;
1490 edge_insert(iedge,dir,nvert,prev,dirprev,-1,-1);
1491 prev = iedge;
1492 dirprev = 0;
1493 }
1494
1495 return 0;
1496 }
1497
1498 /* ----------------------------------------------------------------------
1499 remove any FACE vertices with one or more unconnected edges
1500 unconnected means the edge is only part of this vertex
1501 mark vertex as inactive, decrement their edges,
1502 also set edges inactive if they are no longer attached to vertices
1503 iterate twice since another face may become unconnected
1504 ------------------------------------------------------------------------- */
1505
remove_faces()1506 void Cut3d::remove_faces()
1507 {
1508 int i,ivert,iedge,dir;
1509 Vertex *vert;
1510 Edge *edge;
1511
1512 int nvert = verts.n;
1513
1514 for (int iter = 0; iter < 2; iter++)
1515 for (ivert = 0; ivert < nvert; ivert++) {
1516 if (!verts[ivert].active) continue;
1517 if (verts[ivert].style != FACE) continue;
1518 vert = &verts[ivert];
1519
1520 iedge = vert->first;
1521 dir = vert->dirfirst;
1522 for (i = 0; i < 4; i++) {
1523 edge = &edges[iedge];
1524 if (edge->nvert == 1 || edge->nvert == 2) break;
1525 iedge = edge->next[dir];
1526 dir = edge->dirnext[dir];
1527 }
1528 if (i < 4) vertex_remove(vert);
1529 }
1530 }
1531
1532 /* ----------------------------------------------------------------------
1533 check BPG for consistency
1534 vertices have 3 or more unique edges that point back to it
1535 edges have 2 unique vertices
1536 ------------------------------------------------------------------------- */
1537
check()1538 int Cut3d::check()
1539 {
1540 int i,iedge,dir,nedge,last,dirlast;
1541 Vertex *vert;
1542 Edge *edge;
1543
1544 // mark all edges as unclipped
1545 // use for detecting duplicate edges in same vertex
1546
1547 nedge = edges.n;
1548 for (iedge = 0; iedge < nedge; iedge++)
1549 if (edges[iedge].active) edges[iedge].clipped = 0;
1550
1551 // check vertices
1552 // for each vertex: mark edges as see them, unmark all edges at end
1553
1554 int nvert = verts.n;
1555 for (int ivert = 0; ivert < nvert; ivert++) {
1556 if (!verts[ivert].active) continue;
1557 vert = &verts[ivert];
1558 if (vert->nedge < 3) return 11;
1559
1560 nedge = vert->nedge;
1561 iedge = vert->first;
1562 dir = vert->dirfirst;
1563
1564 for (i = 0; i < nedge; i++) {
1565 edge = &edges[iedge];
1566 if (!edge->active) return 12;
1567 if (edge->verts[dir] != ivert) return 13;
1568 if (edge->clipped) return 14;
1569 edge->clipped = 1;
1570 last = iedge;
1571 dirlast = dir;
1572 iedge = edge->next[dir];
1573 dir = edge->dirnext[dir];
1574 }
1575
1576 if (last != vert->last || dirlast != vert->dirlast) return 15;
1577
1578 iedge = vert->first;
1579 dir = vert->dirfirst;
1580 for (i = 0; i < nedge; i++) {
1581 edge = &edges[iedge];
1582 edge->clipped = 0;
1583 iedge = edge->next[dir];
1584 dir = edge->dirnext[dir];
1585 }
1586 }
1587
1588 // check edges
1589
1590 nedge = edges.n;
1591 for (int iedge = 0; iedge < nedge; iedge++) {
1592 if (!edges[iedge].active) continue;
1593 edge = &edges[iedge];
1594
1595 if (edge->nvert != 3) return 16;
1596 if (edge->verts[0] == edge->verts[1]) return 17;
1597 if (edge->verts[0] >= nvert || !verts[edge->verts[0]].active) return 18;
1598 if (edge->verts[1] >= nvert || !verts[edge->verts[1]].active) return 19;
1599 }
1600
1601 return 0;
1602 }
1603
1604 /* ----------------------------------------------------------------------
1605 convert BPG into simple closed polyhedra, not nested
1606 walk BPG from any unused vertex, flagging vertices as used
1607 stack is list of new vertices to process
1608 loop over edges of pgon, add its unused neighbors to stack
1609 when stack is empty, loop is closed
1610 accumulate volume of polyhedra as walk it from volume of each vertex
1611 ------------------------------------------------------------------------- */
1612
walk()1613 void Cut3d::walk()
1614 {
1615 int flag,ncount,ivert,firstvert,iedge,dir,nedge,prev;
1616 double volume;
1617 Vertex *vert;
1618 Edge *edge;
1619
1620 // used = 0/1 flag for whether a vertex is already part of a loop
1621 // only active vertices are eligible
1622
1623 int nvert = verts.n;
1624 used.grow(nvert);
1625 for (int ivert = 0; ivert < nvert; ivert++) {
1626 if (verts[ivert].active) used[ivert] = 0;
1627 else used[ivert] = 1;
1628 }
1629 used.n = nvert;
1630
1631 // stack = list of vertex indices to process
1632 // max size = # of vertices
1633
1634 stack.grow(nvert);
1635 int nstack = 0;
1636
1637 // iterate over all vertices
1638 // start a loop at any unused vertex
1639 // add more vertices to loop via stack
1640 // check all neighbor vertices via shared edges
1641 // if neighbor vertex is unused, add to stack
1642 // stop when stack is empty
1643
1644 int nloop = 0;
1645
1646 for (int i = 0; i < nvert; i++) {
1647 if (used[i]) continue;
1648 volume = 0.0;
1649 flag = INTERIOR;
1650 ncount = 0;
1651
1652 stack[0] = firstvert = i;
1653 nstack = 1;
1654 used[i] = 1;
1655 prev = -1;
1656
1657 while (nstack) {
1658 nstack--;
1659 ivert = stack[nstack];
1660 ncount++;
1661
1662 vert = &verts[ivert];
1663 if (vert->style != CTRI) flag = BORDER;
1664 volume += vert->volume;
1665
1666 nedge = vert->nedge;
1667 iedge = vert->first;
1668 dir = vert->dirfirst;
1669
1670 for (i = 0; i < nedge; i++) {
1671 edge = &edges[iedge];
1672 if (!used[edge->verts[0]]) {
1673 stack[nstack++] = edge->verts[0];
1674 used[edge->verts[0]] = 1;
1675 }
1676 if (!used[edge->verts[1]]) {
1677 stack[nstack++] = edge->verts[1];
1678 used[edge->verts[1]] = 1;
1679 }
1680 iedge = edge->next[dir];
1681 dir = edge->dirnext[dir];
1682 }
1683
1684 if (prev >= 0) verts[prev].next = ivert;
1685 prev = ivert;
1686 }
1687 vert->next = -1;
1688
1689 loops.grow(nloop+1);
1690 loops[nloop].volume = volume;
1691 loops[nloop].flag = flag;
1692 loops[nloop].n = ncount;
1693 loops[nloop].first = firstvert;
1694 nloop++;
1695 }
1696
1697 loops.n = nloop;
1698 }
1699
1700 /* ----------------------------------------------------------------------
1701 ------------------------------------------------------------------------- */
1702
loop2ph()1703 int Cut3d::loop2ph()
1704 {
1705 int positive = 0;
1706 int negative = 0;
1707
1708 int nloop = loops.n;
1709
1710 for (int i = 0; i < nloop; i++) {
1711 if (loops[i].volume > 0.0) positive++;
1712 else negative++;
1713 }
1714
1715 // if no positive vols, cell is entirely inside the surf, caller handles it
1716 // this can happen due to epsilon size polyhedron(s)
1717 // e.g. when a tri barely cuts off a cell corner
1718
1719 if (positive == 0) return 4;
1720
1721 // do not allow mulitple positive with one or more negative
1722 // too difficult to figure out which positive each negative is inside of
1723
1724 if (positive > 1 && negative) return 5;
1725
1726 // positive = 1 means 1 PH with vol = sum of all pos/neg loops
1727 // positive > 1 means each loop is a PH
1728
1729 phs.grow(positive);
1730
1731 if (positive == 1) {
1732 double volume = 0.0;
1733 for (int i = 0; i < nloop; i++) {
1734 volume += loops[i].volume;
1735 loops[i].next = i+1;
1736 }
1737 loops[nloop-1].next = -1;
1738
1739 if (volume < 0.0) return 6;
1740
1741 phs[0].volume = volume;
1742 phs[0].n = nloop;
1743 phs[0].first = 0;
1744
1745 } else {
1746 for (int i = 0; i < nloop; i++) {
1747 phs[i].volume = loops[i].volume;
1748 phs[i].n = 1;
1749 phs[i].first = i;
1750 loops[i].next = -1;
1751 }
1752 }
1753
1754 phs.n = positive;
1755 return 0;
1756 }
1757
1758 /* ----------------------------------------------------------------------
1759 assign each tri index in list to one of the split cells in PH
1760 return surfmap[i] = which PH the Ith tri index is assigned to
1761 set surfmap[i] = -1 if the tri did not end up in a PH
1762 could have been discarded in clip_tris()
1763 due to touching cell or lying along a cell edge or face
1764 ------------------------------------------------------------------------- */
1765
create_surfmap(int * surfmap)1766 void Cut3d::create_surfmap(int *surfmap)
1767 {
1768 for (int i = 0; i < nsurf; i++) surfmap[i] = -1;
1769
1770 int iloop,nloop,mloop,ivert,nvert,mvert;
1771
1772 int nph = phs.n;
1773 for (int iph = 0; iph < nph; iph++) {
1774 nloop = phs[iph].n;
1775 mloop = phs[iph].first;
1776 for (iloop = 0; iloop < nloop; iloop++) {
1777 nvert = loops[mloop].n;
1778 mvert = loops[mloop].first;
1779 for (ivert = 0; ivert < nvert; ivert++) {
1780 if (verts[mvert].style == CTRI || verts[mvert].style == CTRIFACE)
1781 surfmap[verts[mvert].label] = iph;
1782 mvert = verts[mvert].next;
1783 }
1784 mloop = loops[mloop].next;
1785 }
1786 }
1787 }
1788
1789 /* ----------------------------------------------------------------------
1790 find a surf point that is inside or on the boundary of the current cell
1791 for external surfs and cells already been flagged as a split cell
1792 surfmap = sub-cell index each surf is part of (-1 if not eligible)
1793 return xsplit = coords of point
1794 return xsub = sub-cell index the chosen surf is in
1795 ------------------------------------------------------------------------- */
1796
split_point_explicit(int * surfmap,double * xsplit,int & xsub)1797 int Cut3d::split_point_explicit(int *surfmap, double *xsplit, int &xsub)
1798 {
1799 int itri;
1800 double *x1,*x2,*x3;
1801
1802 Surf::Tri *tris = surf->tris;
1803
1804 // if end pt of any line with non-negative surfmap is in/on cell, return
1805
1806 for (int i = 0; i < nsurf; i++) {
1807 if (surfmap[i] < 0) continue;
1808 itri = surfs[i];
1809 x1 = tris[itri].p1;
1810 x2 = tris[itri].p2;
1811 x3 = tris[itri].p3;
1812 if (ptflag(x1) != EXTERIOR) {
1813 xsplit[0] = x1[0]; xsplit[1] = x1[1]; xsplit[2] = x1[2];
1814 xsub = surfmap[i];
1815 return 0;
1816 }
1817 if (ptflag(x2) != EXTERIOR) {
1818 xsplit[0] = x2[0]; xsplit[1] = x2[1]; xsplit[2] = x2[2];
1819 xsub = surfmap[i];
1820 return 0;
1821 }
1822 if (ptflag(x3) != EXTERIOR) {
1823 xsplit[0] = x3[0]; xsplit[1] = x3[1]; xsplit[2] = x3[2];
1824 xsub = surfmap[i];
1825 return 0;
1826 }
1827 }
1828
1829 // clip 1st line with non-negative surfmap to cell, and return clip point
1830
1831 for (int i = 0; i < nsurf; i++) {
1832 if (surfmap[i] < 0) continue;
1833 itri = surfs[i];
1834 x1 = tris[itri].p1;
1835 x2 = tris[itri].p2;
1836 x3 = tris[itri].p3;
1837 clip(x1,x2,x3);
1838 xsplit[0] = path1[0][0]; xsplit[1] = path1[0][1]; xsplit[2] = path1[0][2];
1839 xsub = surfmap[i];
1840 return 0;
1841 }
1842
1843 // error return
1844
1845 return 7;
1846 }
1847
1848 /* ----------------------------------------------------------------------
1849 find a surf point that is inside or on the boundary of the current cell
1850 for implicit surfs and cells already been flagged as a split cell
1851 surfmap = sub-cell index each surf is part of (-1 if not eligible)
1852 return xsplit = coords of point
1853 return xsub = sub-cell index the chosen surf is in
1854 ------------------------------------------------------------------------- */
1855
split_point_implicit(int * surfmap,double * xsplit,int & xsub)1856 int Cut3d::split_point_implicit(int *surfmap, double *xsplit, int &xsub)
1857 {
1858 Surf::Tri *tris = surf->tris;
1859
1860 // i = 1st surf with non-negative surfmap
1861
1862 int i = 0;
1863 while (surfmap[i] < 0 && i < nsurf) i++;
1864 if (i == nsurf) return 7;
1865
1866 // xsplit = center point of triangle wholly contained in cell
1867
1868 int itri = surfs[i];
1869 double onethird = 1.0/3.0;
1870 xsplit[0] = onethird * (tris[itri].p1[0] + tris[itri].p2[0] + tris[itri].p3[0]);
1871 xsplit[1] = onethird * (tris[itri].p1[1] + tris[itri].p2[1] + tris[itri].p3[1]);
1872 xsplit[2] = onethird * (tris[itri].p1[2] + tris[itri].p2[2] + tris[itri].p3[2]);
1873
1874 xsub = surfmap[i];
1875
1876 return 0;
1877 }
1878
1879 /* ----------------------------------------------------------------------
1880 insert edge IEDGE in DIR for ivert
1881 also update vertex info for added edge
1882 ------------------------------------------------------------------------- */
1883
edge_insert(int iedge,int dir,int ivert,int iprev,int dirprev,int inext,int dirnext)1884 void Cut3d::edge_insert(int iedge, int dir, int ivert,
1885 int iprev, int dirprev, int inext, int dirnext)
1886 {
1887 Edge *edge = &edges[iedge];
1888
1889 if (dir == 0) {
1890 edge->nvert += 1;
1891 edge->verts[0] = ivert;
1892 } else {
1893 edge->nvert += 2;
1894 edge->verts[1] = ivert;
1895 }
1896
1897 edge->active = 1;
1898 edge->clipped = 0;
1899
1900 // set prev/next pointers for doubly linked list of edges
1901
1902 edge->next[dir] = inext;
1903 edge->prev[dir] = iprev;
1904
1905 if (inext >= 0) {
1906 edge->dirnext[dir] = dirnext;
1907 Edge *next = &edges[inext];
1908 next->prev[dirnext] = iedge;
1909 next->dirprev[dirnext] = dir;
1910 } else edge->dirnext[dir] = -1;
1911
1912 if (iprev >= 0) {
1913 edge->dirprev[dir] = dirprev;
1914 Edge *prev = &edges[iprev];
1915 prev->next[dirprev] = iedge;
1916 prev->dirnext[dirprev] = dir;
1917 } else edge->dirprev[dir] = -1;
1918
1919 // add edge info to owning vertex
1920
1921 verts[ivert].nedge++;
1922 if (iprev < 0) {
1923 verts[ivert].first = iedge;
1924 verts[ivert].dirfirst = dir;
1925 }
1926 if (inext < 0) {
1927 verts[ivert].last = iedge;
1928 verts[ivert].dirlast = dir;
1929 }
1930 }
1931
1932 /* ----------------------------------------------------------------------
1933 complete edge removal in both dirs
1934 will leave edge marked inactive
1935 ------------------------------------------------------------------------- */
1936
edge_remove(Edge * edge)1937 void Cut3d::edge_remove(Edge *edge)
1938 {
1939 if (edge->verts[0] >= 0) edge_remove(edge,0);
1940 if (edge->verts[1] >= 0) edge_remove(edge,1);
1941 }
1942
1943 /* ----------------------------------------------------------------------
1944 edge removal in DIR
1945 also update vertex info for removed edge
1946 mark edge inactive if its nvert -> 0
1947 ------------------------------------------------------------------------- */
1948
edge_remove(Edge * edge,int dir)1949 void Cut3d::edge_remove(Edge *edge, int dir)
1950 {
1951 int ivert = edge->verts[dir];
1952 edge->verts[dir] = -1;
1953 if (dir == 0) edge->nvert--;
1954 else edge->nvert -= 2;
1955 if (edge->nvert == 0) edge->active = 0;
1956
1957 // reset prev/next pointers for doubly linked list to skip this edge
1958
1959 if (edge->prev[dir] >= 0) {
1960 Edge *prev = &edges[edge->prev[dir]];
1961 int dirprev = edge->dirprev[dir];
1962 prev->next[dirprev] = edge->next[dir];
1963 prev->dirnext[dirprev] = edge->dirnext[dir];
1964 }
1965
1966 if (edge->next[dir] >= 0) {
1967 Edge *next = &edges[edge->next[dir]];
1968 int dirnext = edge->dirnext[dir];
1969 next->prev[dirnext] = edge->prev[dir];
1970 next->dirprev[dirnext] = edge->dirprev[dir];
1971 }
1972
1973 // update vertex for removal of this edge
1974
1975 verts[ivert].nedge--;
1976 if (edge->prev[dir] < 0) {
1977 verts[ivert].first = edge->next[dir];
1978 verts[ivert].dirfirst = edge->dirnext[dir];
1979 }
1980 if (edge->next[dir] < 0) {
1981 verts[ivert].last = edge->prev[dir];
1982 verts[ivert].dirlast = edge->dirprev[dir];
1983 }
1984 }
1985
1986 /* ----------------------------------------------------------------------
1987 remove a vertex and all edges it includes
1988 ------------------------------------------------------------------------- */
1989
vertex_remove(Vertex * vert)1990 void Cut3d::vertex_remove(Vertex *vert)
1991 {
1992 Edge *edge;
1993
1994 vert->active = 0;
1995
1996 int iedge = vert->first;
1997 int dir = vert->dirfirst;
1998 int nedge = vert->nedge;
1999
2000 for (int i = 0; i < nedge; i++) {
2001 edge = &edges[iedge];
2002 if (dir == 0) edge->nvert--;
2003 else edge->nvert -= 2;
2004 if (edge->nvert == 0) edge->active = 0;
2005 edge->verts[dir] = -1;
2006 iedge = edge->next[dir];
2007 dir = edge->dirnext[dir];
2008 }
2009 }
2010
2011 /* ----------------------------------------------------------------------
2012 a planar polygon is grazing if it lies entirely in plane of any face of cell
2013 and its normal is outward with respect to cell
2014 return 1 if grazing else 0
2015 ------------------------------------------------------------------------- */
2016
grazing(Vertex * vert)2017 int Cut3d::grazing(Vertex *vert)
2018 {
2019 int count[6];
2020 double *p;
2021 Edge *edge;
2022
2023 int iedge = vert->first;
2024 int idir = vert->dirfirst;
2025 int nedge = vert->nedge;
2026
2027 count[0] = count[1] = count[2] = count[3] = count[4] = count[5] = 0;
2028
2029 for (int i = 0; i < nedge; i++) {
2030 edge = &edges[iedge];
2031 if (idir == 0) p = edge->p1;
2032 else p = edge->p2;
2033
2034 if (p[0] == lo[0]) count[0]++;
2035 if (p[0] == hi[0]) count[1]++;
2036 if (p[1] == lo[1]) count[2]++;
2037 if (p[1] == hi[1]) count[3]++;
2038 if (p[2] == lo[2]) count[4]++;
2039 if (p[2] == hi[2]) count[5]++;
2040
2041 iedge = edge->next[idir];
2042 idir = edge->dirnext[idir];
2043 }
2044
2045 double *norm = vert->norm;
2046 if (count[0] == nedge && norm[0] < 0.0) return 1;
2047 if (count[1] == nedge && norm[0] > 0.0) return 1;
2048 if (count[2] == nedge && norm[1] < 0.0) return 1;
2049 if (count[3] == nedge && norm[1] > 0.0) return 1;
2050 if (count[4] == nedge && norm[2] < 0.0) return 1;
2051 if (count[5] == nedge && norm[2] > 0.0) return 1;
2052 return 0;
2053 }
2054
2055 /* ----------------------------------------------------------------------
2056 identify which cell faces point P is on
2057 return list of face IDs (0-5)
2058 list length can be 0,1,2
2059 ------------------------------------------------------------------------- */
2060
on_faces(double * p,int * faces)2061 int Cut3d::on_faces(double *p, int *faces)
2062 {
2063 int n = 0;
2064 if (p[0] == lo[0]) faces[n++] = 0;
2065 if (p[0] == hi[0]) faces[n++] = 1;
2066 if (p[1] == lo[1]) faces[n++] = 2;
2067 if (p[1] == hi[1]) faces[n++] = 3;
2068 if (p[2] == lo[2]) faces[n++] = 4;
2069 if (p[2] == hi[2]) faces[n++] = 5;
2070 return n;
2071 }
2072
2073 /* ----------------------------------------------------------------------
2074 identify which cell faces edge between p1,p2 is on
2075 p1,p2 assumed to be on surface or interior of cell
2076 return list of face IDs (0-5)
2077 list length can be 0,1,2
2078 ------------------------------------------------------------------------- */
2079
which_faces(double * p1,double * p2,int * faces)2080 int Cut3d::which_faces(double *p1, double *p2, int *faces)
2081 {
2082 int n = 0;
2083 if (p1[0] == lo[0] && p2[0] == lo[0]) faces[n++] = 0;
2084 if (p1[0] == hi[0] && p2[0] == hi[0]) faces[n++] = 1;
2085 if (p1[1] == lo[1] && p2[1] == lo[1]) faces[n++] = 2;
2086 if (p1[1] == hi[1] && p2[1] == hi[1]) faces[n++] = 3;
2087 if (p1[2] == lo[2] && p2[2] == lo[2]) faces[n++] = 4;
2088 if (p1[2] == hi[2] && p2[2] == hi[2]) faces[n++] = 5;
2089 return n;
2090 }
2091
2092 /* ----------------------------------------------------------------------
2093 # extract 2d cell from iface (0-5) of 3d cell
2094 # return lo2d/hi2d = xlo,xhi,ylo,yhi
2095 # for XLO/XHI, keep (y,z) -> (x,y), look at face from inside/outside 3d cell
2096 # for YLO/YHI, keep (x,z) -> (x,y), look at face from outside/inside 3d cell
2097 # for ZLO/ZHI, keep (x,y) -> (x,y), look at face from inside/outside 3d cell
2098 ------------------------------------------------------------------------- */
2099
face_from_cell(int iface,double * lo2d,double * hi2d)2100 void Cut3d::face_from_cell(int iface, double *lo2d, double *hi2d)
2101 {
2102 if (iface < 2) {
2103 lo2d[0] = lo[1]; hi2d[0] = hi[1];
2104 lo2d[1] = lo[2]; hi2d[1] = hi[2];
2105 } else if (iface < 4) {
2106 lo2d[0] = lo[0]; hi2d[0] = hi[0];
2107 lo2d[1] = lo[2]; hi2d[1] = hi[2];
2108 } else {
2109 lo2d[0] = lo[0]; hi2d[0] = hi[0];
2110 lo2d[1] = lo[1]; hi2d[1] = hi[1];
2111 }
2112 }
2113
2114 /* ----------------------------------------------------------------------
2115 compress a 3d pt into a 2d pt on iface
2116 ------------------------------------------------------------------------- */
2117
compress2d(int iface,double * p3,double * p2)2118 void Cut3d::compress2d(int iface, double *p3, double *p2)
2119 {
2120 if (iface < 2) {
2121 p2[0] = p3[1]; p2[1] = p3[2];
2122 } else if (iface < 4) {
2123 p2[0] = p3[0]; p2[1] = p3[2];
2124 } else {
2125 p2[0] = p3[0]; p2[1] = p3[1];
2126 }
2127 }
2128
2129 /* ----------------------------------------------------------------------
2130 expand a 2d pt into 3d pt on iface with extra coord = value
2131 ------------------------------------------------------------------------- */
2132
expand2d(int iface,double value,double * p2,double * p3)2133 void Cut3d::expand2d(int iface, double value, double *p2, double *p3)
2134 {
2135 if (iface < 2) {
2136 p3[0] = value; p3[1] = p2[0]; p3[2] = p2[1];
2137 } else if (iface < 4) {
2138 p3[0] = p2[0]; p3[1] = value; p3[2] = p2[1];
2139 } else {
2140 p3[0] = p2[0]; p3[1] = p2[1]; p3[2] = value;
2141 }
2142 }
2143
2144 /* ----------------------------------------------------------------------
2145 look for edge (x,y) in list of edges
2146 match as (x,y) or (y,x)
2147 if flag, do not match edges that are part of a CTRI (style = CTRI,CTRIFACE)
2148 this is used by add_face() when adding edges of an entire face
2149 this avoids matching an on-face CTRI with norm into cell
2150 error if find edge and it is already part of a vertex in that dir
2151 return = index (0 to nedge-1) if find it, -1 if do not find it
2152 return dir = 0 if matches as (x,y), 1 if matches as (y,x), -1 if no match
2153 return -2 as error if edge already exists in same dir as this one
2154 ------------------------------------------------------------------------- */
2155
findedge(double * x,double * y,int flag,int & dir)2156 int Cut3d::findedge(double *x, double *y, int flag, int &dir)
2157 {
2158 double *p1,*p2;
2159
2160 int nedge = edges.n;
2161
2162 for (int i = 0; i < nedge; i++) {
2163 if (!edges[i].active) continue;
2164 if (flag && (edges[i].style == CTRI || edges[i].style == CTRIFACE))
2165 continue;
2166 p1 = edges[i].p1;
2167 p2 = edges[i].p2;
2168 if (samepoint(x,p1) && samepoint(y,p2)) {
2169 if (edges[i].nvert % 2 == 1) return -2;
2170 dir = 0;
2171 return i;
2172 }
2173 if (samepoint(x,p2) && samepoint(y,p1)) {
2174 if (edges[i].nvert / 2 == 1) return -2;
2175 dir = 1;
2176 return i;
2177 }
2178 }
2179
2180 dir = -1;
2181 return -1;
2182 }
2183
2184 /* ----------------------------------------------------------------------
2185 return intersection pt C of line segment A,B in dim with coord value
2186 guaranteed to intersect by caller
2187 C can be same as A or B, will just overwrite
2188 ------------------------------------------------------------------------- */
2189
between(double * a,double * b,int dim,double value,double * c)2190 void Cut3d::between(double *a, double *b, int dim, double value, double *c)
2191 {
2192 if (dim == 0) {
2193 c[1] = a[1] + (value-a[dim])/(b[dim]-a[dim]) * (b[1]-a[1]);
2194 c[2] = a[2] + (value-a[dim])/(b[dim]-a[dim]) * (b[2]-a[2]);
2195 c[0] = value;
2196 } else if (dim == 1) {
2197 c[0] = a[0] + (value-a[dim])/(b[dim]-a[dim]) * (b[0]-a[0]);
2198 c[2] = a[2] + (value-a[dim])/(b[dim]-a[dim]) * (b[2]-a[2]);
2199 c[1] = value;
2200 } else {
2201 c[0] = a[0] + (value-a[dim])/(b[dim]-a[dim]) * (b[0]-a[0]);
2202 c[1] = a[1] + (value-a[dim])/(b[dim]-a[dim]) * (b[1]-a[1]);
2203 c[2] = value;
2204 }
2205 }
2206
2207 /* ----------------------------------------------------------------------
2208 return 1 if x,y are same point, else 0
2209 ------------------------------------------------------------------------- */
2210
samepoint(double * x,double * y)2211 int Cut3d::samepoint(double *x, double *y)
2212 {
2213 if (x[0] == y[0] && x[1] == y[1] && x[2] == y[2]) return 1;
2214 return 0;
2215 }
2216
2217 /* ----------------------------------------------------------------------
2218 return 0-7 if pt is a corner pt of grid cell
2219 else return -1
2220 ------------------------------------------------------------------------- */
2221
corner(double * pt)2222 int Cut3d::corner(double *pt)
2223 {
2224 if (pt[2] == lo[2]) {
2225 if (pt[1] == lo[1]) {
2226 if (pt[0] == lo[0]) return 0;
2227 else if (pt[0] == hi[0]) return 1;
2228 } else if (pt[1] == hi[1]) {
2229 if (pt[0] == lo[0]) return 2;
2230 else if (pt[0] == hi[0]) return 3;
2231 }
2232 } else if (pt[2] == hi[2]) {
2233 if (pt[1] == lo[1]) {
2234 if (pt[0] == lo[0]) return 4;
2235 else if (pt[0] == hi[0]) return 5;
2236 } else if (pt[1] == hi[1]) {
2237 if (pt[0] == lo[0]) return 6;
2238 else if (pt[0] == hi[0]) return 7;
2239 }
2240 }
2241
2242 return -1;
2243 }
2244
2245 /* ----------------------------------------------------------------------
2246 move point within epsilon of any cell face to be on cell faces
2247 ------------------------------------------------------------------------- */
2248
move_to_faces(double * pt)2249 void Cut3d::move_to_faces(double *pt)
2250 {
2251 if (fabs(pt[0]-lo[0]) < epsilon) pt[0] = lo[0];
2252 if (fabs(pt[0]-hi[0]) < epsilon) pt[0] = hi[0];
2253 if (fabs(pt[1]-lo[1]) < epsilon) pt[1] = lo[1];
2254 if (fabs(pt[1]-hi[1]) < epsilon) pt[1] = hi[1];
2255 if (fabs(pt[2]-lo[2]) < epsilon) pt[2] = lo[2];
2256 if (fabs(pt[2]-hi[2]) < epsilon) pt[2] = hi[2];
2257 }
2258
2259 /* ----------------------------------------------------------------------
2260 check if pt is inside or outside or on cell border
2261 return EXTERIOR,BORDER,INTERIOR
2262 ------------------------------------------------------------------------- */
2263
ptflag(double * pt)2264 int Cut3d::ptflag(double *pt)
2265 {
2266 double x = pt[0];
2267 double y = pt[1];
2268 double z = pt[2];
2269 if (x < lo[0] || x > hi[0] || y < lo[1] || y > hi[1] ||
2270 z < lo[2] || z > hi[2]) return EXTERIOR;
2271 if (x > lo[0] && x < hi[0] && y > lo[1] && y < hi[1] &&
2272 z > lo[2] && z < hi[2]) return INTERIOR;
2273 return BORDER;
2274 }
2275
2276 /* ----------------------------------------------------------------------
2277 print out cell info for cell which failed at cut/split operation
2278 ------------------------------------------------------------------------- */
2279
failed_cell()2280 void Cut3d::failed_cell()
2281 {
2282 printf("Cut3d failed on proc %d in cell ID: " CELLINT_FORMAT "\n",comm->me,id);
2283 Surf::Tri *tris = surf->tris;
2284 printf(" lo corner %g %g %g\n",lo[0],lo[1],lo[2]);
2285 printf(" hi corner %g %g %g\n",hi[0],hi[1],hi[2]);
2286 printf(" # of surfs = %d out of " BIGINT_FORMAT "\n",nsurf,surf->nsurf);
2287 for (int i = 0; i < nsurf; i++) {
2288 printf(" surf " SURFINT_FORMAT ":\n",tris[surfs[i]].id);
2289 printf(" p1: %g %g %g\n",
2290 tris[surfs[i]].p1[0],tris[surfs[i]].p1[1],tris[surfs[i]].p1[2]);
2291 printf(" p2: %g %g %g\n",
2292 tris[surfs[i]].p2[0],tris[surfs[i]].p2[1],tris[surfs[i]].p2[2]);
2293 printf(" p3: %g %g %g\n",
2294 tris[surfs[i]].p3[0],tris[surfs[i]].p3[1],tris[surfs[i]].p3[2]);
2295 }
2296 }
2297
2298 /* ----------------------------------------------------------------------
2299 ------------------------------------------------------------------------- */
2300
print_bpg(const char * str)2301 void Cut3d::print_bpg(const char *str)
2302 {
2303 int iedge,dir,newedge,newdir,prevedge,prevdir;
2304 double *p1,*p2;
2305
2306 printf("%s " CELLINT_FORMAT "\n",str,id);
2307 printf(" Sizes: %d %d\n",verts.n,edges.n);
2308
2309 printf(" Verts:\n");
2310 for (int i = 0; i < verts.n; i++) {
2311 if (verts[i].active == 0) continue;
2312
2313 printf(" %d %d %d %d:",i,
2314 verts[i].active,verts[i].style,verts[i].label);
2315
2316 printf(" edges [");
2317 iedge = verts[i].first;
2318 dir = verts[i].dirfirst;
2319 for (int j = 0; j < verts[i].nedge; j++) {
2320 printf("%d",iedge);
2321 if (j < verts[i].nedge-1) printf(" ");
2322 newedge = edges[iedge].next[dir];
2323 newdir = edges[iedge].dirnext[dir];
2324 iedge = newedge;
2325 dir = newdir;
2326 }
2327 printf("]");
2328
2329 printf(" dirs [");
2330 iedge = verts[i].first;
2331 dir = verts[i].dirfirst;
2332 for (int j = 0; j < verts[i].nedge; j++) {
2333 printf("%d",dir);
2334 if (j < verts[i].nedge-1) printf(" ");
2335 newedge = edges[iedge].next[dir];
2336 newdir = edges[iedge].dirnext[dir];
2337 iedge = newedge;
2338 dir = newdir;
2339 }
2340 printf("]");
2341
2342 printf(" edgelens [");
2343 iedge = verts[i].first;
2344 dir = verts[i].dirfirst;
2345 for (int j = 0; j < verts[i].nedge; j++) {
2346 p1 = edges[iedge].p1;
2347 p2 = edges[iedge].p2;
2348 double dx = p1[0]-p2[0];
2349 double dy = p1[1]-p2[1];
2350 double dz = p1[2]-p2[2];
2351 double delta = sqrt(dx*dx+dy*dy+dz*dz);
2352 printf("%g",delta);
2353 if (j < verts[i].nedge-1) printf(" ");
2354 newedge = edges[iedge].next[dir];
2355 newdir = edges[iedge].dirnext[dir];
2356 iedge = newedge;
2357 dir = newdir;
2358 }
2359 printf("]");
2360
2361 printf(" samept [");
2362 iedge = verts[i].first;
2363 dir = verts[i].dirfirst;
2364 for (int j = 0; j < verts[i].nedge; j++) {
2365 if (j > 0) {
2366 prevedge = edges[iedge].prev[dir];
2367 prevdir = edges[iedge].dirprev[dir];
2368 } else {
2369 prevedge = verts[i].last;
2370 prevdir = verts[i].dirlast;
2371 }
2372 if (dir == 0) p1 = edges[iedge].p1;
2373 else p1 = edges[iedge].p2;
2374 if (prevdir == 0) p2 = edges[prevedge].p2;
2375 else p2 = edges[prevedge].p1;
2376 printf("%d",samepoint(p1,p2));
2377 if (j < verts[i].nedge-1) printf(" ");
2378 newedge = edges[iedge].next[dir];
2379 newdir = edges[iedge].dirnext[dir];
2380 iedge = newedge;
2381 dir = newdir;
2382 }
2383 printf("]");
2384
2385 if (verts[i].norm) {
2386 printf(" norm [%g %g %g]\n",
2387 verts[i].norm[0],verts[i].norm[1],verts[i].norm[2]);
2388 } else printf(" [NULL]\n");
2389 }
2390
2391 printf(" Edges:\n");
2392 for (int i = 0; i < edges.n; i++) {
2393 if (edges[i].active == 0) continue;
2394
2395 printf(" %d %d %d",i,edges[i].active,edges[i].style);
2396 printf(" (%g %g %g)",edges[i].p1[0],edges[i].p1[1],edges[i].p1[2]);
2397 printf(" (%g %g %g)",edges[i].p2[0],edges[i].p2[1],edges[i].p2[2]);
2398 if (edges[i].nvert == 0) printf(" [-1]");
2399 if (edges[i].nvert == 1) {
2400 printf(" [%d]",edges[i].verts[0]);
2401 printf(" p1: [%d %d]",edges[i].prev[0],edges[i].dirprev[0]);
2402 printf(" n1: [%d %d]",edges[i].next[0],edges[i].dirnext[0]);
2403 }
2404 if (edges[i].nvert == 2) {
2405 printf(" [%d]",edges[i].verts[1]);
2406 printf(" p1: [%d %d]",edges[i].prev[1],edges[i].dirprev[1]);
2407 printf(" n1: [%d %d]",edges[i].next[1],edges[i].dirnext[1]);
2408 }
2409 if (edges[i].nvert == 3) {
2410 printf(" [%d %d]",edges[i].verts[0],edges[i].verts[1]);
2411 printf(" p1: [%d %d]",edges[i].prev[0],edges[i].dirprev[0]);
2412 printf(" n1: [%d %d]",edges[i].next[0],edges[i].dirnext[0]);
2413 printf(" p2: [%d %d]",edges[i].prev[1],edges[i].dirprev[1]);
2414 printf(" n2: [%d %d]",edges[i].next[1],edges[i].dirnext[1]);
2415 }
2416 if (edges[i].nvert > 3) printf(" [BIG %d]",edges[i].nvert);
2417 printf("\n");
2418 }
2419 }
2420
2421 /* ----------------------------------------------------------------------
2422 ------------------------------------------------------------------------- */
2423
print_loops()2424 void Cut3d::print_loops()
2425 {
2426 printf("LOOP " CELLINT_FORMAT "\n",id);
2427 printf(" loops %d\n",loops.n);
2428 for (int i = 0; i < loops.n; i++) {
2429 printf(" loop %d\n",i);
2430 printf(" flag %d\n",loops[i].flag);
2431 printf(" volume %g\n",loops[i].volume);
2432 printf(" nverts %d\n",loops[i].n);
2433 printf(" verts: [");
2434 int ivert = loops[i].first;
2435 for (int j = 0; j < loops[i].n; j++) {
2436 printf("%d ",ivert);
2437 ivert = verts[ivert].next;
2438 }
2439 printf("]\n");
2440 }
2441 }
2442