diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h index df5c47089163ee5a341b563ecc13676d54420ce5..929ce4354804c7942626c8fa3f33220374e0defd 100644 --- a/Common/DefaultOptions.h +++ b/Common/DefaultOptions.h @@ -947,12 +947,7 @@ StringXNumber GeometryOptions_Number[] = { StringXNumber MeshOptions_Number[] = { { F|O, "Algorithm" , opt_mesh_algo2d , ALGO_2D_AUTO , "2D mesh algorithm (1=MeshAdapt, 2=Automatic, 5=Delaunay, 6=Frontal, 7=bamg, 8=delquad)" }, - { F|O, "Algorithm3D" , opt_mesh_algo3d , -#if defined(HAVE_TETGEN) - ALGO_3D_DELAUNAY , -#else - ALGO_3D_FRONTAL , -#endif + { F|O, "Algorithm3D" , opt_mesh_algo3d , ALGO_3D_DELAUNAY , "3D mesh algorithm (1=Delaunay, 4=Frontal, 5=Frontal Delaunay, 6=Frontal Hex, 7=MMG3D, 9=R-tree)" }, { F|O, "AngleSmoothNormals" , opt_mesh_angle_smooth_normals , 30.0 , "Threshold angle below which normals are not smoothed" }, diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp index 6542f9a54d9fb5415342d9d75693bf1b59528223..903e7bdc6e4b2b7de42626a284427e2e1ea1c4f9 100644 --- a/Mesh/meshGRegion.cpp +++ b/Mesh/meshGRegion.cpp @@ -592,9 +592,12 @@ void MeshDelaunayVolumeTetgen(std::vector<GRegion*> ®ions) } // uncomment this to test the new code -//#define NEW_CODE +#if !defined(HAVE_TETGEN) +#define NEW_CODE +#endif -static void MeshDelaunayVolumeNewCode(std::vector<GRegion*> ®ions) { +static void MeshDelaunayVolumeNewCode(std::vector<GRegion*> ®ions) +{ GRegion *gr = regions[0]; std::list<GFace*> faces = gr->faces(); std::set<GFace*> allFacesSet; @@ -610,9 +613,7 @@ static void MeshDelaunayVolumeNewCode(std::vector<GRegion*> ®ions) { gr->set(allFaces); try{ - meshGRegionBoundaryRecovery *init = new meshGRegionBoundaryRecovery(); - init->reconstructmesh(gr); - delete init; + meshGRegionBoundaryRecovery(gr); } catch(int err){ Msg::Error("Could not recover boundary: error %d", err); diff --git a/Mesh/meshGRegionBoundaryRecovery.cpp b/Mesh/meshGRegionBoundaryRecovery.cpp index 91f82a9f23d81debd55a337bd6793c461d7e9dbc..91996a197500880cf225c24ba144ff23f7517df8 100644 --- a/Mesh/meshGRegionBoundaryRecovery.cpp +++ b/Mesh/meshGRegionBoundaryRecovery.cpp @@ -1,14460 +1,145 @@ -// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle +// Gmsh - Copyright (C) 1997-2016 C. Geuzaine, J.-F. Remacle // // See the LICENSE.txt file for license information. Please report all // bugs and problems to the public mailing list <gmsh@onelab.info>. -// -// Contributed by Hang Si - -#include <stdio.h> -#include <math.h> -#include <assert.h> -#include <string.h> -#include "meshGRegionBoundaryRecovery.h" -#include "robustPredicates.h" -#include "GFace.h" -#include "MVertex.h" -#include "MLine.h" -#include "MTriangle.h" -#include "MTetrahedron.h" -#include "meshGRegionDelaunayInsertion.h" -#include "OS.h" - -#define orient3d robustPredicates::orient3d -#define insphere robustPredicates::insphere - -#ifdef _MSC_VER // Microsoft Visual C++ -# ifdef _WIN64 - typedef __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -# else // not _WIN64 - typedef int intptr_t; - typedef unsigned int uintptr_t; -# endif -#else // not Visual C++ -# include <stdint.h> -#endif - -/////////////////////////////////////////////////////////////////////////////// -// // -// Primitives for tetrahedra // -// // -/////////////////////////////////////////////////////////////////////////////// - -inline meshGRegionBoundaryRecovery::tetrahedron - meshGRegionBoundaryRecovery::encode(triface& t) { - return (tetrahedron) ((uintptr_t) (t).tet | (uintptr_t) (t).ver); -} - -inline meshGRegionBoundaryRecovery::tetrahedron - meshGRegionBoundaryRecovery::encode2(tetrahedron* ptr, int ver) { - return (tetrahedron) ((uintptr_t) (ptr) | (uintptr_t) (ver)); -} - -inline void meshGRegionBoundaryRecovery::decode(tetrahedron ptr, triface& t) { - (t).ver = (int) ((uintptr_t) (ptr) & (uintptr_t) 15); - (t).tet = (tetrahedron *) ((uintptr_t) (ptr) ^ (uintptr_t) (t).ver); -} - -inline void meshGRegionBoundaryRecovery::bond(triface& t1, triface& t2) { - t1.tet[t1.ver & 3] = encode2(t2.tet, bondtbl[t1.ver][t2.ver]); - t2.tet[t2.ver & 3] = encode2(t1.tet, bondtbl[t2.ver][t1.ver]); -} - -inline void meshGRegionBoundaryRecovery::dissolve(triface& t) { - t.tet[t.ver & 3] = NULL; -} - -inline void meshGRegionBoundaryRecovery::enext(triface& t1, triface& t2) { - t2.tet = t1.tet; - t2.ver = enexttbl[t1.ver]; -} - -inline void meshGRegionBoundaryRecovery::enextself(triface& t) { - t.ver = enexttbl[t.ver]; -} - -inline void meshGRegionBoundaryRecovery::eprev(triface& t1, triface& t2) { - t2.tet = t1.tet; - t2.ver = eprevtbl[t1.ver]; -} - -inline void meshGRegionBoundaryRecovery::eprevself(triface& t) { - t.ver = eprevtbl[t.ver]; -} - -inline void meshGRegionBoundaryRecovery::esym(triface& t1, triface& t2) { - (t2).tet = (t1).tet; - (t2).ver = esymtbl[(t1).ver]; -} - -inline void meshGRegionBoundaryRecovery::esymself(triface& t) { - (t).ver = esymtbl[(t).ver]; -} - -inline void meshGRegionBoundaryRecovery::enextesym(triface& t1, triface& t2) { - t2.tet = t1.tet; - t2.ver = enextesymtbl[t1.ver]; -} - -inline void meshGRegionBoundaryRecovery::enextesymself(triface& t) { - t.ver = enextesymtbl[t.ver]; -} - -inline void meshGRegionBoundaryRecovery::eprevesym(triface& t1, triface& t2) { - t2.tet = t1.tet; - t2.ver = eprevesymtbl[t1.ver]; -} - -inline void meshGRegionBoundaryRecovery::eprevesymself(triface& t) { - t.ver = eprevesymtbl[t.ver]; -} - -inline void meshGRegionBoundaryRecovery::eorgoppo(triface& t1, triface& t2) { - t2.tet = t1.tet; - t2.ver = eorgoppotbl[t1.ver]; -} - -inline void meshGRegionBoundaryRecovery::eorgoppoself(triface& t) { - t.ver = eorgoppotbl[t.ver]; -} - -inline void meshGRegionBoundaryRecovery::edestoppo(triface& t1, triface& t2) { - t2.tet = t1.tet; - t2.ver = edestoppotbl[t1.ver]; -} - -inline void meshGRegionBoundaryRecovery::edestoppoself(triface& t) { - t.ver = edestoppotbl[t.ver]; -} - -inline void meshGRegionBoundaryRecovery::fsym(triface& t1, triface& t2) { - decode((t1).tet[(t1).ver & 3], t2); - t2.ver = fsymtbl[t1.ver][t2.ver]; -} - -#define fsymself(t) \ - t1ver = (t).ver; \ - decode((t).tet[(t).ver & 3], (t));\ - (t).ver = fsymtbl[t1ver][(t).ver] - -inline void meshGRegionBoundaryRecovery::fnext(triface& t1, triface& t2) { - decode(t1.tet[facepivot1[t1.ver]], t2); - t2.ver = facepivot2[t1.ver][t2.ver]; -} - -#define fnextself(t) \ - t1ver = (t).ver; \ - decode((t).tet[facepivot1[(t).ver]], (t)); \ - (t).ver = facepivot2[t1ver][(t).ver] - - -inline meshGRegionBoundaryRecovery::point - meshGRegionBoundaryRecovery::org(triface& t) { - return (point) (t).tet[orgpivot[(t).ver]]; -} - -inline meshGRegionBoundaryRecovery::point - meshGRegionBoundaryRecovery:: dest(triface& t) { - return (point) (t).tet[destpivot[(t).ver]]; -} - -inline meshGRegionBoundaryRecovery::point - meshGRegionBoundaryRecovery::apex(triface& t) { - return (point) (t).tet[apexpivot[(t).ver]]; -} - -inline meshGRegionBoundaryRecovery::point - meshGRegionBoundaryRecovery::oppo(triface& t) { - return (point) (t).tet[oppopivot[(t).ver]]; -} - -inline void meshGRegionBoundaryRecovery::setorg(triface& t, point p) { - (t).tet[orgpivot[(t).ver]] = (tetrahedron) (p); -} - -inline void meshGRegionBoundaryRecovery::setdest(triface& t, point p) { - (t).tet[destpivot[(t).ver]] = (tetrahedron) (p); -} - -inline void meshGRegionBoundaryRecovery:: setapex(triface& t, point p) { - (t).tet[apexpivot[(t).ver]] = (tetrahedron) (p); -} - -inline void meshGRegionBoundaryRecovery::setoppo(triface& t, point p) { - (t).tet[oppopivot[(t).ver]] = (tetrahedron) (p); -} - -#define setvertices(t, torg, tdest, tapex, toppo) \ - (t).tet[orgpivot[(t).ver]] = (tetrahedron) (torg);\ - (t).tet[destpivot[(t).ver]] = (tetrahedron) (tdest); \ - (t).tet[apexpivot[(t).ver]] = (tetrahedron) (tapex); \ - (t).tet[oppopivot[(t).ver]] = (tetrahedron) (toppo) - -inline REAL meshGRegionBoundaryRecovery::elemattribute(tetrahedron* ptr, - int attnum) { - return ((REAL *) (ptr))[elemattribindex + attnum]; -} - -inline void meshGRegionBoundaryRecovery::setelemattribute(tetrahedron* ptr, - int attnum, - REAL value) { - ((REAL *) (ptr))[elemattribindex + attnum] = value; -} - -inline REAL meshGRegionBoundaryRecovery::volumebound(tetrahedron* ptr) { - return ((REAL *) (ptr))[volumeboundindex]; -} - -inline void meshGRegionBoundaryRecovery::setvolumebound(tetrahedron* ptr, - REAL value) { - ((REAL *) (ptr))[volumeboundindex] = value; -} - -inline int meshGRegionBoundaryRecovery::elemindex(tetrahedron* ptr) { - int *iptr = (int *) &(ptr[10]); - return iptr[0]; -} - -inline void meshGRegionBoundaryRecovery::setelemindex(tetrahedron* ptr, - int value) { - int *iptr = (int *) &(ptr[10]); - iptr[0] = value; -} - -inline int meshGRegionBoundaryRecovery::elemmarker(tetrahedron* ptr) { - return ((int *) (ptr))[elemmarkerindex]; -} - -inline void meshGRegionBoundaryRecovery::setelemmarker(tetrahedron* ptr, - int value) { - ((int *) (ptr))[elemmarkerindex] = value; -} - -inline void meshGRegionBoundaryRecovery::infect(triface& t) { - ((int *) (t.tet))[elemmarkerindex] |= 1; -} - -inline void meshGRegionBoundaryRecovery::uninfect(triface& t) { - ((int *) (t.tet))[elemmarkerindex] &= ~1; -} - -inline bool meshGRegionBoundaryRecovery::infected(triface& t) { - return (((int *) (t.tet))[elemmarkerindex] & 1) != 0; -} - -inline void meshGRegionBoundaryRecovery::marktest(triface& t) { - ((int *) (t.tet))[elemmarkerindex] |= 2; -} - -inline void meshGRegionBoundaryRecovery::unmarktest(triface& t) { - ((int *) (t.tet))[elemmarkerindex] &= ~2; -} - -inline bool meshGRegionBoundaryRecovery::marktested(triface& t) { - return (((int *) (t.tet))[elemmarkerindex] & 2) != 0; -} - -inline void meshGRegionBoundaryRecovery::markface(triface& t) { - ((int *) (t.tet))[elemmarkerindex] |= (4 << (t.ver & 3)); -} - -inline void meshGRegionBoundaryRecovery::unmarkface(triface& t) { - ((int *) (t.tet))[elemmarkerindex] &= ~(4 << (t.ver & 3)); -} - -inline bool meshGRegionBoundaryRecovery::facemarked(triface& t) { - return (((int *) (t.tet))[elemmarkerindex] & (4 << (t.ver & 3))) != 0; -} - -inline void meshGRegionBoundaryRecovery::markedge(triface& t) { - ((int *) (t.tet))[elemmarkerindex] |= (int) (64 << ver2edge[(t).ver]); -} - -inline void meshGRegionBoundaryRecovery::unmarkedge(triface& t) { - ((int *) (t.tet))[elemmarkerindex] &= ~(int) (64 << ver2edge[(t).ver]); -} - -inline bool meshGRegionBoundaryRecovery::edgemarked(triface& t) { - return (((int *) (t.tet))[elemmarkerindex] & - (int) (64 << ver2edge[(t).ver])) != 0; -} - -inline void meshGRegionBoundaryRecovery::marktest2(triface& t) { - ((int *) (t.tet))[elemmarkerindex] |= (int) (4096); -} - -inline void meshGRegionBoundaryRecovery::unmarktest2(triface& t) { - ((int *) (t.tet))[elemmarkerindex] &= ~(int) (4096); -} - -inline bool meshGRegionBoundaryRecovery::marktest2ed(triface& t) { - return (((int *) (t.tet))[elemmarkerindex] & (int) (4096)) != 0; -} - -inline int meshGRegionBoundaryRecovery::elemcounter(triface& t) { - return (((int *) (t.tet))[elemmarkerindex]) >> 16; -} - -inline void meshGRegionBoundaryRecovery::setelemcounter(triface& t, int value) { - int c = ((int *) (t.tet))[elemmarkerindex]; - // Clear the old counter while keep the other flags. - c &= 65535; // sum_{i=0^15} 2^i - c |= (value << 16); - ((int *) (t.tet))[elemmarkerindex] = c; -} - -inline void meshGRegionBoundaryRecovery::increaseelemcounter(triface& t) { - int c = elemcounter(t); - setelemcounter(t, c + 1); -} - -inline void meshGRegionBoundaryRecovery::decreaseelemcounter(triface& t) { - int c = elemcounter(t); - setelemcounter(t, c - 1); -} - -inline bool meshGRegionBoundaryRecovery::ishulltet(triface& t) { - return (point) (t).tet[7] == dummypoint; -} - -inline bool meshGRegionBoundaryRecovery::isdeadtet(triface& t) { - return ((t.tet == NULL) || (t.tet[4] == NULL)); -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// Primitives for subfaces and subsegments // -// // -/////////////////////////////////////////////////////////////////////////////// - -inline void meshGRegionBoundaryRecovery::sdecode(shellface sptr, face& s) { - s.shver = (int) ((uintptr_t) (sptr) & (uintptr_t) 7); - s.sh = (shellface *) ((uintptr_t) (sptr) ^ (uintptr_t) (s.shver)); -} - -inline meshGRegionBoundaryRecovery::shellface - meshGRegionBoundaryRecovery::sencode(face& s) { - return (shellface) ((uintptr_t) s.sh | (uintptr_t) s.shver); -} - -inline meshGRegionBoundaryRecovery::shellface - meshGRegionBoundaryRecovery::sencode2(shellface *sh, int shver) { - return (shellface) ((uintptr_t) sh | (uintptr_t) shver); -} - -inline void meshGRegionBoundaryRecovery::sbond(face& s1, face& s2) { - s1.sh[s1.shver >> 1] = sencode(s2); - s2.sh[s2.shver >> 1] = sencode(s1); -} - -inline void meshGRegionBoundaryRecovery::sbond1(face& s1, face& s2) { - s1.sh[s1.shver >> 1] = sencode(s2); -} - -inline void meshGRegionBoundaryRecovery::sdissolve(face& s) { - s.sh[s.shver >> 1] = NULL; -} - -inline void meshGRegionBoundaryRecovery::spivot(face& s1, face& s2) { - shellface sptr = s1.sh[s1.shver >> 1]; - sdecode(sptr, s2); -} - -inline void meshGRegionBoundaryRecovery::spivotself(face& s) { - shellface sptr = s.sh[s.shver >> 1]; - sdecode(sptr, s); -} - -inline meshGRegionBoundaryRecovery::point - meshGRegionBoundaryRecovery::sorg(face& s) { - return (point) s.sh[sorgpivot[s.shver]]; -} - -inline meshGRegionBoundaryRecovery::point - meshGRegionBoundaryRecovery::sdest(face& s) { - return (point) s.sh[sdestpivot[s.shver]]; -} - -inline meshGRegionBoundaryRecovery::point - meshGRegionBoundaryRecovery::sapex(face& s) { - return (point) s.sh[sapexpivot[s.shver]]; -} - -inline void meshGRegionBoundaryRecovery::setsorg(face& s, point pointptr) { - s.sh[sorgpivot[s.shver]] = (shellface) pointptr; -} - -inline void meshGRegionBoundaryRecovery::setsdest(face& s, point pointptr) { - s.sh[sdestpivot[s.shver]] = (shellface) pointptr; -} - -inline void meshGRegionBoundaryRecovery::setsapex(face& s, point pointptr) { - s.sh[sapexpivot[s.shver]] = (shellface) pointptr; -} - -#define setshvertices(s, pa, pb, pc)\ - setsorg(s, pa);\ - setsdest(s, pb);\ - setsapex(s, pc) - -inline void meshGRegionBoundaryRecovery::sesym(face& s1, face& s2) { - s2.sh = s1.sh; - s2.shver = (s1.shver ^ 1); // Inverse the last bit. -} - -inline void meshGRegionBoundaryRecovery::sesymself(face& s) { - s.shver ^= 1; -} - -inline void meshGRegionBoundaryRecovery::senext(face& s1, face& s2) { - s2.sh = s1.sh; - s2.shver = snextpivot[s1.shver]; -} - -inline void meshGRegionBoundaryRecovery::senextself(face& s) { - s.shver = snextpivot[s.shver]; -} - -inline void meshGRegionBoundaryRecovery::senext2(face& s1, face& s2) { - s2.sh = s1.sh; - s2.shver = snextpivot[snextpivot[s1.shver]]; -} - -inline void meshGRegionBoundaryRecovery::senext2self(face& s) { - s.shver = snextpivot[snextpivot[s.shver]]; -} - - -inline REAL meshGRegionBoundaryRecovery::areabound(face& s) { - return ((REAL *) (s.sh))[areaboundindex]; -} - -inline void meshGRegionBoundaryRecovery::setareabound(face& s, REAL value) { - ((REAL *) (s.sh))[areaboundindex] = value; -} - -inline int meshGRegionBoundaryRecovery::shellmark(face& s) { - return ((int *) (s.sh))[shmarkindex]; -} - -inline void meshGRegionBoundaryRecovery::setshellmark(face& s, int value) { - ((int *) (s.sh))[shmarkindex] = value; -} - -inline void meshGRegionBoundaryRecovery::sinfect(face& s) { - ((int *) ((s).sh))[shmarkindex+1] = - (((int *) ((s).sh))[shmarkindex+1] | (int) 1); -} - -inline void meshGRegionBoundaryRecovery::suninfect(face& s) { - ((int *) ((s).sh))[shmarkindex+1] = - (((int *) ((s).sh))[shmarkindex+1] & ~(int) 1); -} - -inline bool meshGRegionBoundaryRecovery::sinfected(face& s) { - return (((int *) ((s).sh))[shmarkindex+1] & (int) 1) != 0; -} - -inline void meshGRegionBoundaryRecovery::smarktest(face& s) { - ((int *) ((s).sh))[shmarkindex+1] = - (((int *)((s).sh))[shmarkindex+1] | (int) 2); -} - -inline void meshGRegionBoundaryRecovery::sunmarktest(face& s) { - ((int *) ((s).sh))[shmarkindex+1] = - (((int *)((s).sh))[shmarkindex+1] & ~(int)2); -} - -inline bool meshGRegionBoundaryRecovery::smarktested(face& s) { - return ((((int *) ((s).sh))[shmarkindex+1] & (int) 2) != 0); -} - -inline void meshGRegionBoundaryRecovery::smarktest2(face& s) { - ((int *) ((s).sh))[shmarkindex+1] = - (((int *)((s).sh))[shmarkindex+1] | (int) 4); -} - -inline void meshGRegionBoundaryRecovery::sunmarktest2(face& s) { - ((int *) ((s).sh))[shmarkindex+1] = - (((int *)((s).sh))[shmarkindex+1] & ~(int)4); -} - -inline bool meshGRegionBoundaryRecovery::smarktest2ed(face& s) { - return ((((int *) ((s).sh))[shmarkindex+1] & (int) 4) != 0); -} - -inline void meshGRegionBoundaryRecovery::smarktest3(face& s) { - ((int *) ((s).sh))[shmarkindex+1] = - (((int *)((s).sh))[shmarkindex+1] | (int) 8); -} - -inline void meshGRegionBoundaryRecovery::sunmarktest3(face& s) { - ((int *) ((s).sh))[shmarkindex+1] = - (((int *)((s).sh))[shmarkindex+1] & ~(int)8); -} - -inline bool meshGRegionBoundaryRecovery::smarktest3ed(face& s) { - return ((((int *) ((s).sh))[shmarkindex+1] & (int) 8) != 0); -} - -inline void meshGRegionBoundaryRecovery::setfacetindex(face& s, int value) { - ((int *) (s.sh))[shmarkindex + 2] = value; -} - -inline int meshGRegionBoundaryRecovery::getfacetindex(face& s) { - return ((int *) (s.sh))[shmarkindex + 2]; -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// Primitives for interacting between tetrahedra and subfaces // -// // -/////////////////////////////////////////////////////////////////////////////// - -inline void meshGRegionBoundaryRecovery::tsbond(triface& t, face& s) { - if ((t).tet[9] == NULL) { - // Allocate space for this tet. - (t).tet[9] = (tetrahedron) tet2subpool->alloc(); - // Initialize. - for (int i = 0; i < 4; i++) { - ((shellface *) (t).tet[9])[i] = NULL; - } - } - // Bond t <== s. - ((shellface *) (t).tet[9])[(t).ver & 3] = - sencode2((s).sh, tsbondtbl[t.ver][s.shver]); - // Bond s <== t. - s.sh[9 + ((s).shver & 1)] = - (shellface) encode2((t).tet, stbondtbl[t.ver][s.shver]); -} - -inline void meshGRegionBoundaryRecovery::tspivot(triface& t, face& s) { - if ((t).tet[9] == NULL) { - (s).sh = NULL; - return; - } - // Get the attached subface s. - sdecode(((shellface *) (t).tet[9])[(t).ver & 3], (s)); - (s).shver = tspivottbl[t.ver][s.shver]; -} - -// Quickly check if the handle (t, v) is a subface. -#define issubface(t) \ - ((t).tet[9] && ((t).tet[9])[(t).ver & 3]) - -inline void meshGRegionBoundaryRecovery::stpivot(face& s, triface& t) { - decode((tetrahedron) s.sh[9 + (s.shver & 1)], t); - if ((t).tet == NULL) { - return; - } - (t).ver = stpivottbl[t.ver][s.shver]; -} - -#define isshtet(s) \ - ((s).sh[9 + ((s).shver & 1)]) - -inline void meshGRegionBoundaryRecovery::tsdissolve(triface& t) { - if ((t).tet[9] != NULL) { - ((shellface *) (t).tet[9])[(t).ver & 3] = NULL; - } -} - -inline void meshGRegionBoundaryRecovery::stdissolve(face& s) { - (s).sh[9] = NULL; - (s).sh[10] = NULL; -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// Primitives for interacting between subfaces and segments // -// // -/////////////////////////////////////////////////////////////////////////////// - -inline void meshGRegionBoundaryRecovery::ssbond(face& s, face& edge) { - s.sh[6 + (s.shver >> 1)] = sencode(edge); - edge.sh[0] = sencode(s); -} - -inline void meshGRegionBoundaryRecovery::ssbond1(face& s, face& edge) { - s.sh[6 + (s.shver >> 1)] = sencode(edge); - //edge.sh[0] = sencode(s); -} - -inline void meshGRegionBoundaryRecovery::ssdissolve(face& s) { - s.sh[6 + (s.shver >> 1)] = NULL; -} - -inline void meshGRegionBoundaryRecovery::sspivot(face& s, face& edge) { - sdecode((shellface) s.sh[6 + (s.shver >> 1)], edge); -} - -#define isshsubseg(s) \ - ((s).sh[6 + ((s).shver >> 1)]) - -/////////////////////////////////////////////////////////////////////////////// -// // -// Primitives for interacting between tetrahedra and segments // -// // -/////////////////////////////////////////////////////////////////////////////// - -inline void meshGRegionBoundaryRecovery::tssbond1(triface& t, face& s) { - if ((t).tet[8] == NULL) { - // Allocate space for this tet. - (t).tet[8] = (tetrahedron) tet2segpool->alloc(); - // Initialization. - for (int i = 0; i < 6; i++) { - ((shellface *) (t).tet[8])[i] = NULL; - } - } - ((shellface *) (t).tet[8])[ver2edge[(t).ver]] = sencode((s)); -} - -inline void meshGRegionBoundaryRecovery::sstbond1(face& s, triface& t) { - ((tetrahedron *) (s).sh)[9] = encode(t); -} - -inline void meshGRegionBoundaryRecovery::tssdissolve1(triface& t) { - if ((t).tet[8] != NULL) { - ((shellface *) (t).tet[8])[ver2edge[(t).ver]] = NULL; - } -} - -inline void meshGRegionBoundaryRecovery::sstdissolve1(face& s) { - ((tetrahedron *) (s).sh)[9] = NULL; -} - -inline void meshGRegionBoundaryRecovery::tsspivot1(triface& t, face& s) { - if ((t).tet[8] != NULL) { - sdecode(((shellface *) (t).tet[8])[ver2edge[(t).ver]], s); - } else { - (s).sh = NULL; - } -} - -#define issubseg(t) \ - ((t).tet[8] && ((t).tet[8])[ver2edge[(t).ver]]) - -inline void meshGRegionBoundaryRecovery::sstpivot1(face& s, triface& t) { - decode((tetrahedron) s.sh[9], t); -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// Primitives for points // -// // -/////////////////////////////////////////////////////////////////////////////// - -inline int meshGRegionBoundaryRecovery::pointmark(point pt) { - return ((int *) (pt))[pointmarkindex]; -} - -inline void meshGRegionBoundaryRecovery::setpointmark(point pt, int value) { - ((int *) (pt))[pointmarkindex] = value; -} - - -inline enum meshGRegionBoundaryRecovery::verttype - meshGRegionBoundaryRecovery::pointtype(point pt) { - return (enum verttype) (((int *) (pt))[pointmarkindex + 1] >> (int) 8); -} - -inline void meshGRegionBoundaryRecovery::setpointtype(point pt, - enum verttype value) { - ((int *) (pt))[pointmarkindex + 1] = - ((int) value << 8) + (((int *) (pt))[pointmarkindex + 1] & (int) 255); -} - -inline int meshGRegionBoundaryRecovery::pointgeomtag(point pt) { - return ((int *) (pt))[pointmarkindex + 2]; -} - -inline void meshGRegionBoundaryRecovery::setpointgeomtag(point pt, int value) { - ((int *) (pt))[pointmarkindex + 2] = value; -} - -inline REAL meshGRegionBoundaryRecovery::pointgeomuv(point pt, int i) { - return pt[pointparamindex + i]; -} - -inline void meshGRegionBoundaryRecovery::setpointgeomuv(point pt, int i, - REAL value) { - pt[pointparamindex + i] = value; -} - -inline void meshGRegionBoundaryRecovery::pinfect(point pt) { - ((int *) (pt))[pointmarkindex + 1] |= (int) 1; -} - -inline void meshGRegionBoundaryRecovery::puninfect(point pt) { - ((int *) (pt))[pointmarkindex + 1] &= ~(int) 1; -} - -inline bool meshGRegionBoundaryRecovery::pinfected(point pt) { - return (((int *) (pt))[pointmarkindex + 1] & (int) 1) != 0; -} - -inline void meshGRegionBoundaryRecovery::pmarktest(point pt) { - ((int *) (pt))[pointmarkindex + 1] |= (int) 2; -} - -inline void meshGRegionBoundaryRecovery::punmarktest(point pt) { - ((int *) (pt))[pointmarkindex + 1] &= ~(int) 2; -} - -inline bool meshGRegionBoundaryRecovery::pmarktested(point pt) { - return (((int *) (pt))[pointmarkindex + 1] & (int) 2) != 0; -} - -inline void meshGRegionBoundaryRecovery::pmarktest2(point pt) { - ((int *) (pt))[pointmarkindex + 1] |= (int) 4; -} - -inline void meshGRegionBoundaryRecovery::punmarktest2(point pt) { - ((int *) (pt))[pointmarkindex + 1] &= ~(int) 4; -} - -inline bool meshGRegionBoundaryRecovery::pmarktest2ed(point pt) { - return (((int *) (pt))[pointmarkindex + 1] & (int) 4) != 0; -} - -inline void meshGRegionBoundaryRecovery::pmarktest3(point pt) { - ((int *) (pt))[pointmarkindex + 1] |= (int) 8; -} - -inline void meshGRegionBoundaryRecovery::punmarktest3(point pt) { - ((int *) (pt))[pointmarkindex + 1] &= ~(int) 8; -} - -inline bool meshGRegionBoundaryRecovery::pmarktest3ed(point pt) { - return (((int *) (pt))[pointmarkindex + 1] & (int) 8) != 0; -} - -inline meshGRegionBoundaryRecovery::tetrahedron - meshGRegionBoundaryRecovery::point2tet(point pt) { - return ((tetrahedron *) (pt))[point2simindex]; -} - -inline void meshGRegionBoundaryRecovery::setpoint2tet(point pt, - tetrahedron value) { - ((tetrahedron *) (pt))[point2simindex] = value; -} - -inline meshGRegionBoundaryRecovery::point - meshGRegionBoundaryRecovery::point2ppt(point pt) { - return (point) ((tetrahedron *) (pt))[point2simindex + 1]; -} - -inline void meshGRegionBoundaryRecovery::setpoint2ppt(point pt, point value) { - ((tetrahedron *) (pt))[point2simindex + 1] = (tetrahedron) value; -} - -inline meshGRegionBoundaryRecovery::shellface - meshGRegionBoundaryRecovery::point2sh(point pt) { - return (shellface) ((tetrahedron *) (pt))[point2simindex + 2]; -} - -inline void meshGRegionBoundaryRecovery::setpoint2sh(point pt, - shellface value) { - ((tetrahedron *) (pt))[point2simindex + 2] = (tetrahedron) value; -} - - -inline meshGRegionBoundaryRecovery::tetrahedron - meshGRegionBoundaryRecovery::point2bgmtet(point pt) { - return ((tetrahedron *) (pt))[point2simindex + 3]; -} - -inline void meshGRegionBoundaryRecovery::setpoint2bgmtet(point pt, - tetrahedron value) { - ((tetrahedron *) (pt))[point2simindex + 3] = value; -} - -inline void meshGRegionBoundaryRecovery::setpointinsradius(point pt, - REAL value) { - pt[pointmtrindex + sizeoftensor - 1] = value; -} - -inline REAL meshGRegionBoundaryRecovery::getpointinsradius(point pt) { - return pt[pointmtrindex + sizeoftensor - 1]; -} - -inline bool meshGRegionBoundaryRecovery::issteinerpoint(point pt) { - return (pointtype(pt) == FREESEGVERTEX) || (pointtype(pt) == FREEFACETVERTEX) - || (pointtype(pt) == FREEVOLVERTEX); -} - -inline void meshGRegionBoundaryRecovery::point2tetorg(point pa, - triface& searchtet) { - decode(point2tet(pa), searchtet); - if ((point) searchtet.tet[4] == pa) { - searchtet.ver = 11; - } else if ((point) searchtet.tet[5] == pa) { - searchtet.ver = 3; - } else if ((point) searchtet.tet[6] == pa) { - searchtet.ver = 7; - } else { - //assert((point) searchtet.tet[7] == pa); // SELF_CHECK - searchtet.ver = 0; - } -} - -inline void meshGRegionBoundaryRecovery::point2shorg(point pa, face& searchsh){ - sdecode(point2sh(pa), searchsh); - if ((point) searchsh.sh[3] == pa) { - searchsh.shver = 0; - } else if ((point) searchsh.sh[4] == pa) { - searchsh.shver = (searchsh.sh[5] != NULL ? 2 : 1); - } else { - //assert((point) searchsh.sh[5] == pa); // SELF_CHECK - searchsh.shver = 4; - } -} - -inline meshGRegionBoundaryRecovery::point - meshGRegionBoundaryRecovery::farsorg(face& s) { - face travesh, neighsh; - travesh = s; - while (1) { - senext2(travesh, neighsh); - spivotself(neighsh); - if (neighsh.sh == NULL) break; - if (sorg(neighsh) != sorg(travesh)) sesymself(neighsh); - senext2(neighsh, travesh); - } - return sorg(travesh); -} - -inline meshGRegionBoundaryRecovery::point - meshGRegionBoundaryRecovery::farsdest(face& s) { - face travesh, neighsh; - travesh = s; - while (1) { - senext(travesh, neighsh); - spivotself(neighsh); - if (neighsh.sh == NULL) break; - if (sdest(neighsh) != sdest(travesh)) sesymself(neighsh); - senext(neighsh, travesh); - } - return sdest(travesh); -} - -// dot() returns the dot product: v1 dot v2. -inline REAL meshGRegionBoundaryRecovery::dot(REAL* v1, REAL* v2) -{ - return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; -} - -// cross() computes the cross product: n = v1 cross v2. -inline void meshGRegionBoundaryRecovery::cross(REAL* v1, REAL* v2, REAL* n) -{ - n[0] = v1[1] * v2[2] - v2[1] * v1[2]; - n[1] = -(v1[0] * v2[2] - v2[0] * v1[2]); - n[2] = v1[0] * v2[1] - v2[0] * v1[1]; -} - -// distance() computes the Euclidean distance between two points. -inline REAL meshGRegionBoundaryRecovery::distance(REAL* p1, REAL* p2) -{ - return sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) + - (p2[1] - p1[1]) * (p2[1] - p1[1]) + - (p2[2] - p1[2]) * (p2[2] - p1[2])); -} - -inline REAL meshGRegionBoundaryRecovery::norm2(REAL x, REAL y, REAL z) -{ - return (x) * (x) + (y) * (y) + (z) * (z); -} - -//// mempool_cxx ////////////////////////////////////////////////////////////// -//// //// -//// //// - -int meshGRegionBoundaryRecovery::bondtbl[12][12] = {{0,},}; -int meshGRegionBoundaryRecovery::enexttbl[12] = {0,}; -int meshGRegionBoundaryRecovery::eprevtbl[12] = {0,}; -int meshGRegionBoundaryRecovery::enextesymtbl[12] = {0,}; -int meshGRegionBoundaryRecovery::eprevesymtbl[12] = {0,}; -int meshGRegionBoundaryRecovery::eorgoppotbl[12] = {0,}; -int meshGRegionBoundaryRecovery::edestoppotbl[12] = {0,}; -int meshGRegionBoundaryRecovery::fsymtbl[12][12] = {{0,},}; -int meshGRegionBoundaryRecovery::facepivot1[12] = {0,}; -int meshGRegionBoundaryRecovery::facepivot2[12][12] = {{0,},}; -int meshGRegionBoundaryRecovery::tsbondtbl[12][6] = {{0,},}; -int meshGRegionBoundaryRecovery::stbondtbl[12][6] = {{0,},}; -int meshGRegionBoundaryRecovery::tspivottbl[12][6] = {{0,},}; -int meshGRegionBoundaryRecovery::stpivottbl[12][6] = {{0,},}; - -int meshGRegionBoundaryRecovery::esymtbl[12] = - {9, 6, 11, 4, 3, 7, 1, 5, 10, 0, 8, 2}; -int meshGRegionBoundaryRecovery:: orgpivot[12] = - {7, 7, 5, 5, 6, 4, 4, 6, 5, 6, 7, 4}; -int meshGRegionBoundaryRecovery::destpivot[12] = - {6, 4, 4, 6, 5, 6, 7, 4, 7, 7, 5, 5}; -int meshGRegionBoundaryRecovery::apexpivot[12] = - {5, 6, 7, 4, 7, 7, 5, 5, 6, 4, 4, 6}; -int meshGRegionBoundaryRecovery::oppopivot[12] = - {4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7}; -int meshGRegionBoundaryRecovery::ver2edge[12] = - {0, 1, 2, 3, 3, 5, 1, 5, 4, 0, 4, 2}; -int meshGRegionBoundaryRecovery::edge2ver[ 6] = {0, 1, 2, 3, 8, 5}; -int meshGRegionBoundaryRecovery::epivot[12] = - {4, 5, 2, 11, 4, 5, 2, 11, 4, 5, 2, 11}; -int meshGRegionBoundaryRecovery::snextpivot[6] = {2, 5, 4, 1, 0, 3}; -int meshGRegionBoundaryRecovery::sorgpivot [6] = {3, 4, 4, 5, 5, 3}; -int meshGRegionBoundaryRecovery::sdestpivot[6] = {4, 3, 5, 4, 3, 5}; -int meshGRegionBoundaryRecovery::sapexpivot[6] = {5, 5, 3, 3, 4, 4}; - -void meshGRegionBoundaryRecovery::inittables() -{ - int i, j; - - // i = t1.ver; j = t2.ver; - for (i = 0; i < 12; i++) { - for (j = 0; j < 12; j++) { - bondtbl[i][j] = (j & 3) + (((i & 12) + (j & 12)) % 12); - } - } - - // i = t1.ver; j = t2.ver - for (i = 0; i < 12; i++) { - for (j = 0; j < 12; j++) { - fsymtbl[i][j] = (j + 12 - (i & 12)) % 12; - } - } - - for (i = 0; i < 12; i++) { - facepivot1[i] = (esymtbl[i] & 3); - } - - for (i = 0; i < 12; i++) { - for (j = 0; j < 12; j++) { - facepivot2[i][j] = fsymtbl[esymtbl[i]][j]; - } - } - - for (i = 0; i < 12; i++) { - enexttbl[i] = (i + 4) % 12; - eprevtbl[i] = (i + 8) % 12; - } - - for (i = 0; i < 12; i++) { - enextesymtbl[i] = esymtbl[enexttbl[i]]; - eprevesymtbl[i] = esymtbl[eprevtbl[i]]; - } - - for (i = 0; i < 12; i++) { - eorgoppotbl [i] = eprevtbl[esymtbl[enexttbl[i]]]; - edestoppotbl[i] = enexttbl[esymtbl[eprevtbl[i]]]; - } - - int soffset, toffset; - - // i = t.ver, j = s.shver - for (i = 0; i < 12; i++) { - for (j = 0; j < 6; j++) { - if ((j & 1) == 0) { - soffset = (6 - ((i & 12) >> 1)) % 6; - toffset = (12 - ((j & 6) << 1)) % 12; - } else { - soffset = (i & 12) >> 1; - toffset = (j & 6) << 1; - } - tsbondtbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6); - stbondtbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12); - } - } - - // i = t.ver, j = s.shver - for (i = 0; i < 12; i++) { - for (j = 0; j < 6; j++) { - if ((j & 1) == 0) { - soffset = (i & 12) >> 1; - toffset = (j & 6) << 1; - } else { - soffset = (6 - ((i & 12) >> 1)) % 6; - toffset = (12 - ((j & 6) << 1)) % 12; - } - tspivottbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6); - stpivottbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12); - } - } -} - -void meshGRegionBoundaryRecovery::arraypool::restart() -{ - objects = 0l; -} - -void meshGRegionBoundaryRecovery::arraypool::poolinit(int sizeofobject, - int log2objperblk) -{ - // Each object must be at least one byte long. - objectbytes = sizeofobject > 1 ? sizeofobject : 1; - - log2objectsperblock = log2objperblk; - // Compute the number of objects in each block. - objectsperblock = ((int) 1) << log2objectsperblock; - objectsperblockmark = objectsperblock - 1; - - // No memory has been allocated. - totalmemory = 0l; - // The top array has not been allocated yet. - toparray = (char **) NULL; - toparraylen = 0; - - // Ready all indices to be allocated. - restart(); -} - -meshGRegionBoundaryRecovery::arraypool::arraypool(int sizeofobject, - int log2objperblk) -{ - poolinit(sizeofobject, log2objperblk); -} - -meshGRegionBoundaryRecovery::arraypool::~arraypool() -{ - int i; - - // Has anything been allocated at all? - if (toparray != (char **) NULL) { - // Walk through the top array. - for (i = 0; i < toparraylen; i++) { - // Check every pointer; NULLs may be scattered randomly. - if (toparray[i] != (char *) NULL) { - // Free an allocated block. - free((void *) toparray[i]); - } - } - // Free the top array. - free((void *) toparray); - } - - // The top array is no longer allocated. - toparray = (char **) NULL; - toparraylen = 0; - objects = 0; - totalmemory = 0; -} - -char* meshGRegionBoundaryRecovery::arraypool::getblock(int objectindex) -{ - char **newarray; - char *block; - int newsize; - int topindex; - int i; - - // Compute the index in the top array (upper bits). - topindex = objectindex >> log2objectsperblock; - // Does the top array need to be allocated or resized? - if (toparray == (char **) NULL) { - // Allocate the top array big enough to hold 'topindex', and NULL out - // its contents. - newsize = topindex + 128; - toparray = (char **) malloc((size_t) (newsize * sizeof(char *))); - toparraylen = newsize; - for (i = 0; i < newsize; i++) { - toparray[i] = (char *) NULL; - } - // Account for the memory. - totalmemory = newsize * (uintptr_t) sizeof(char *); - } else if (topindex >= toparraylen) { - // Resize the top array, making sure it holds 'topindex'. - newsize = 3 * toparraylen; - if (topindex >= newsize) { - newsize = topindex + 128; - } - // Allocate the new array, copy the contents, NULL out the rest, and - // free the old array. - newarray = (char **) malloc((size_t) (newsize * sizeof(char *))); - for (i = 0; i < toparraylen; i++) { - newarray[i] = toparray[i]; - } - for (i = toparraylen; i < newsize; i++) { - newarray[i] = (char *) NULL; - } - free(toparray); - // Account for the memory. - totalmemory += (newsize - toparraylen) * sizeof(char *); - toparray = newarray; - toparraylen = newsize; - } - - // Find the block, or learn that it hasn't been allocated yet. - block = toparray[topindex]; - if (block == (char *) NULL) { - // Allocate a block at this index. - block = (char *) malloc((size_t) (objectsperblock * objectbytes)); - toparray[topindex] = block; - // Account for the memory. - totalmemory += objectsperblock * objectbytes; - } - - // Return a pointer to the block. - return block; -} - -void* meshGRegionBoundaryRecovery::arraypool::lookup(int objectindex) -{ - char *block; - int topindex; - - // Has the top array been allocated yet? - if (toparray == (char **) NULL) { - return (void *) NULL; - } - - // Compute the index in the top array (upper bits). - topindex = objectindex >> log2objectsperblock; - // Does the top index fit in the top array? - if (topindex >= toparraylen) { - return (void *) NULL; - } - - // Find the block, or learn that it hasn't been allocated yet. - block = toparray[topindex]; - if (block == (char *) NULL) { - return (void *) NULL; - } - - // Compute a pointer to the object with the given index. Note that - // 'objectsperblock' is a power of two, so the & operation is a bit mask - // that preserves the lower bits. - return (void *)(block + (objectindex & (objectsperblock - 1)) * objectbytes); -} - -int meshGRegionBoundaryRecovery::arraypool::newindex(void **newptr) -{ - // Allocate an object at index 'firstvirgin'. - int newindex = objects; - *newptr = (void *) (getblock(objects) + - (objects & (objectsperblock - 1)) * objectbytes); - objects++; - - return newindex; -} - - -meshGRegionBoundaryRecovery::memorypool::memorypool() -{ - firstblock = nowblock = (void **) NULL; - nextitem = (void *) NULL; - deaditemstack = (void *) NULL; - pathblock = (void **) NULL; - pathitem = (void *) NULL; - alignbytes = 0; - itembytes = itemwords = 0; - itemsperblock = 0; - items = maxitems = 0l; - unallocateditems = 0; - pathitemsleft = 0; -} - -meshGRegionBoundaryRecovery::memorypool::memorypool(int bytecount, - int itemcount, int wsize, int alignment) -{ - poolinit(bytecount, itemcount, wsize, alignment); -} - -meshGRegionBoundaryRecovery::memorypool::~memorypool() -{ - while (firstblock != (void **) NULL) { - nowblock = (void **) *(firstblock); - free(firstblock); - firstblock = nowblock; - } -} - -void meshGRegionBoundaryRecovery::memorypool::poolinit(int bytecount, - int itemcount,int wordsize, int alignment) -{ - // Find the proper alignment, which must be at least as large as: - // - The parameter `alignment'. - // - The primary word type, to avoid unaligned accesses. - // - sizeof(void *), so the stack of dead items can be maintained - // without unaligned accesses. - if (alignment > wordsize) { - alignbytes = alignment; - } else { - alignbytes = wordsize; - } - if ((int) sizeof(void *) > alignbytes) { - alignbytes = (int) sizeof(void *); - } - itemwords = ((bytecount + alignbytes - 1) / alignbytes) - * (alignbytes / wordsize); - itembytes = itemwords * wordsize; - itemsperblock = itemcount; - - // Allocate a block of items. Space for `itemsperblock' items and one - // pointer (to point to the next block) are allocated, as well as space - // to ensure alignment of the items. - firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *) - + alignbytes); - if (firstblock == (void **) NULL) { - terminateBoundaryRecovery(NULL, 1); - } - // Set the next block pointer to NULL. - *(firstblock) = (void *) NULL; - restart(); -} - -void meshGRegionBoundaryRecovery::memorypool::restart() -{ - uintptr_t alignptr; - - items = 0; - maxitems = 0; - - // Set the currently active block. - nowblock = firstblock; - // Find the first item in the pool. Increment by the size of (void *). - alignptr = (uintptr_t) (nowblock + 1); - // Align the item on an `alignbytes'-byte boundary. - nextitem = (void *) - (alignptr + (uintptr_t) alignbytes - - (alignptr % (uintptr_t) alignbytes)); - // There are lots of unallocated items left in this block. - unallocateditems = itemsperblock; - // The stack of deallocated items is empty. - deaditemstack = (void *) NULL; -} - -void* meshGRegionBoundaryRecovery::memorypool::alloc() -{ - void *newitem; - void **newblock; - uintptr_t alignptr; - - // First check the linked list of dead items. If the list is not - // empty, allocate an item from the list rather than a fresh one. - if (deaditemstack != (void *) NULL) { - newitem = deaditemstack; // Take first item in list. - deaditemstack = * (void **) deaditemstack; - } else { - // Check if there are any free items left in the current block. - if (unallocateditems == 0) { - // Check if another block must be allocated. - if (*nowblock == (void *) NULL) { - // Allocate a new block of items, pointed to by the previous block. - newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *) - + alignbytes); - if (newblock == (void **) NULL) { - terminateBoundaryRecovery(NULL, 1); - } - *nowblock = (void *) newblock; - // The next block pointer is NULL. - *newblock = (void *) NULL; - } - // Move to the new block. - nowblock = (void **) *nowblock; - // Find the first item in the block. - // Increment by the size of (void *). - alignptr = (uintptr_t) (nowblock + 1); - // Align the item on an `alignbytes'-byte boundary. - nextitem = (void *) - (alignptr + (uintptr_t) alignbytes - - (alignptr % (uintptr_t) alignbytes)); - // There are lots of unallocated items left in this block. - unallocateditems = itemsperblock; - } - // Allocate a new item. - newitem = nextitem; - // Advance `nextitem' pointer to next free item in block. - nextitem = (void *) ((uintptr_t) nextitem + itembytes); - unallocateditems--; - maxitems++; - } - items++; - return newitem; -} - -void meshGRegionBoundaryRecovery::memorypool::dealloc(void *dyingitem) -{ - // Push freshly killed item onto stack. - *((void **) dyingitem) = deaditemstack; - deaditemstack = dyingitem; - items--; -} - -void meshGRegionBoundaryRecovery::memorypool::traversalinit() -{ - uintptr_t alignptr; - - // Begin the traversal in the first block. - pathblock = firstblock; - // Find the first item in the block. Increment by the size of (void *). - alignptr = (uintptr_t) (pathblock + 1); - // Align with item on an `alignbytes'-byte boundary. - pathitem = (void *) - (alignptr + (uintptr_t) alignbytes - - (alignptr % (uintptr_t) alignbytes)); - // Set the number of items left in the current block. - pathitemsleft = itemsperblock; -} - -void* meshGRegionBoundaryRecovery::memorypool::traverse() -{ - void *newitem; - uintptr_t alignptr; - - // Stop upon exhausting the list of items. - if (pathitem == nextitem) { - return (void *) NULL; - } - // Check whether any untraversed items remain in the current block. - if (pathitemsleft == 0) { - // Find the next block. - pathblock = (void **) *pathblock; - // Find the first item in the block. Increment by the size of (void *). - alignptr = (uintptr_t) (pathblock + 1); - // Align with item on an `alignbytes'-byte boundary. - pathitem = (void *) - (alignptr + (uintptr_t) alignbytes - - (alignptr % (uintptr_t) alignbytes)); - // Set the number of items left in the current block. - pathitemsleft = itemsperblock; - } - newitem = pathitem; - // Find the next item in the block. - pathitem = (void *) ((uintptr_t) pathitem + itembytes); - pathitemsleft--; - return newitem; -} - -void meshGRegionBoundaryRecovery::makeindex2pointmap(point*& idx2verlist) -{ - point pointloop; - int idx; - - Msg::Debug(" Constructing mapping from indices to points."); - - idx2verlist = new point[points->items + 1]; - - points->traversalinit(); - pointloop = pointtraverse(); - idx = in->firstnumber; - while (pointloop != (point) NULL) { - idx2verlist[idx++] = pointloop; - pointloop = pointtraverse(); - } -} - -void meshGRegionBoundaryRecovery::makepoint2submap(memorypool* pool, - int*& idx2faclist, face*& facperverlist) -{ - face shloop; - int i, j, k; - - Msg::Debug(" Making a map from points to subfaces."); - - // Initialize 'idx2faclist'. - idx2faclist = new int[points->items + 1]; - for (i = 0; i < points->items + 1; i++) idx2faclist[i] = 0; - - // Loop all subfaces, counter the number of subfaces incident at a vertex. - pool->traversalinit(); - shloop.sh = shellfacetraverse(pool); - while (shloop.sh != (shellface *) NULL) { - // Increment the number of incident subfaces for each vertex. - j = pointmark((point) shloop.sh[3]) - in->firstnumber; - idx2faclist[j]++; - j = pointmark((point) shloop.sh[4]) - in->firstnumber; - idx2faclist[j]++; - // Skip the third corner if it is a segment. - if (shloop.sh[5] != NULL) { - j = pointmark((point) shloop.sh[5]) - in->firstnumber; - idx2faclist[j]++; - } - shloop.sh = shellfacetraverse(pool); - } - - // Calculate the total length of array 'facperverlist'. - j = idx2faclist[0]; - idx2faclist[0] = 0; // Array starts from 0 element. - for (i = 0; i < points->items; i++) { - k = idx2faclist[i + 1]; - idx2faclist[i + 1] = idx2faclist[i] + j; - j = k; - } - - // The total length is in the last unit of idx2faclist. - facperverlist = new face[idx2faclist[i]]; - - // Loop all subfaces again, remember the subfaces at each vertex. - pool->traversalinit(); - shloop.sh = shellfacetraverse(pool); - while (shloop.sh != (shellface *) NULL) { - j = pointmark((point) shloop.sh[3]) - in->firstnumber; - shloop.shver = 0; // save the origin. - facperverlist[idx2faclist[j]] = shloop; - idx2faclist[j]++; - // Is it a subface or a subsegment? - if (shloop.sh[5] != NULL) { - j = pointmark((point) shloop.sh[4]) - in->firstnumber; - shloop.shver = 2; // save the origin. - facperverlist[idx2faclist[j]] = shloop; - idx2faclist[j]++; - j = pointmark((point) shloop.sh[5]) - in->firstnumber; - shloop.shver = 4; // save the origin. - facperverlist[idx2faclist[j]] = shloop; - idx2faclist[j]++; - } else { - j = pointmark((point) shloop.sh[4]) - in->firstnumber; - shloop.shver = 1; // save the origin. - facperverlist[idx2faclist[j]] = shloop; - idx2faclist[j]++; - } - shloop.sh = shellfacetraverse(pool); - } - - // Contents in 'idx2faclist' are shifted, now shift them back. - for (i = points->items - 1; i >= 0; i--) { - idx2faclist[i + 1] = idx2faclist[i]; - } - idx2faclist[0] = 0; -} - -void meshGRegionBoundaryRecovery::tetrahedrondealloc(tetrahedron - *dyingtetrahedron) -{ - // Set tetrahedron's vertices to NULL. This makes it possible to detect - // dead tetrahedra when traversing the list of all tetrahedra. - dyingtetrahedron[4] = (tetrahedron) NULL; - - // Dealloc the space to subfaces/subsegments. - if (dyingtetrahedron[8] != NULL) { - tet2segpool->dealloc((shellface *) dyingtetrahedron[8]); - } - if (dyingtetrahedron[9] != NULL) { - tet2subpool->dealloc((shellface *) dyingtetrahedron[9]); - } - - tetrahedrons->dealloc((void *) dyingtetrahedron); -} - -meshGRegionBoundaryRecovery::tetrahedron* - meshGRegionBoundaryRecovery::tetrahedrontraverse() -{ - tetrahedron *newtetrahedron; - - do { - newtetrahedron = (tetrahedron *) tetrahedrons->traverse(); - if (newtetrahedron == (tetrahedron *) NULL) { - return (tetrahedron *) NULL; - } - } while ((newtetrahedron[4] == (tetrahedron) NULL) || - ((point) newtetrahedron[7] == dummypoint)); - return newtetrahedron; -} - -meshGRegionBoundaryRecovery::tetrahedron* - meshGRegionBoundaryRecovery::alltetrahedrontraverse() -{ - tetrahedron *newtetrahedron; - - do { - newtetrahedron = (tetrahedron *) tetrahedrons->traverse(); - if (newtetrahedron == (tetrahedron *) NULL) { - return (tetrahedron *) NULL; - } - } while (newtetrahedron[4] == (tetrahedron) NULL); // Skip dead ones. - return newtetrahedron; -} - -void meshGRegionBoundaryRecovery::shellfacedealloc(memorypool *pool, - shellface *dyingsh) -{ - // Set shellface's vertices to NULL. This makes it possible to detect dead - // shellfaces when traversing the list of all shellfaces. - dyingsh[3] = (shellface) NULL; - pool->dealloc((void *) dyingsh); -} - -meshGRegionBoundaryRecovery::shellface* meshGRegionBoundaryRecovery::shellfacetraverse(memorypool *pool) -{ - shellface *newshellface; - - do { - newshellface = (shellface *) pool->traverse(); - if (newshellface == (shellface *) NULL) { - return (shellface *) NULL; - } - } while (newshellface[3] == (shellface) NULL); // Skip dead ones. - return newshellface; -} - -void meshGRegionBoundaryRecovery::pointdealloc(point dyingpoint) -{ - // Mark the point as dead. This makes it possible to detect dead points - // when traversing the list of all points. - setpointtype(dyingpoint, DEADVERTEX); - points->dealloc((void *) dyingpoint); -} - -meshGRegionBoundaryRecovery::point meshGRegionBoundaryRecovery::pointtraverse() -{ - point newpoint; - - do { - newpoint = (point) points->traverse(); - if (newpoint == (point) NULL) { - return (point) NULL; - } - } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones. - return newpoint; -} - -void meshGRegionBoundaryRecovery::maketetrahedron(triface *newtet) -{ - newtet->tet = (tetrahedron *) tetrahedrons->alloc(); - - // Initialize the four adjoining tetrahedra to be "outer space". - newtet->tet[0] = NULL; - newtet->tet[1] = NULL; - newtet->tet[2] = NULL; - newtet->tet[3] = NULL; - // Four NULL vertices. - newtet->tet[4] = NULL; - newtet->tet[5] = NULL; - newtet->tet[6] = NULL; - newtet->tet[7] = NULL; - // No attached segments and subfaces yet. - newtet->tet[8] = NULL; - newtet->tet[9] = NULL; - // Initialize the marker (clear all flags). - setelemmarker(newtet->tet, 0); - for (int i = 0; i < numelemattrib; i++) { - setelemattribute(newtet->tet, i, 0.0); - } - if (b->varvolume) { - setvolumebound(newtet->tet, -1.0); - } - - // Initialize the version to be Zero. - newtet->ver = 11; -} - -void meshGRegionBoundaryRecovery::makeshellface(memorypool *pool, face *newface) -{ - newface->sh = (shellface *) pool->alloc(); - - // No adjointing subfaces. - newface->sh[0] = NULL; - newface->sh[1] = NULL; - newface->sh[2] = NULL; - // Three NULL vertices. - newface->sh[3] = NULL; - newface->sh[4] = NULL; - newface->sh[5] = NULL; - // No adjoining subsegments. - newface->sh[6] = NULL; - newface->sh[7] = NULL; - newface->sh[8] = NULL; - // No adjoining tetrahedra. - newface->sh[9] = NULL; - newface->sh[10] = NULL; - if (checkconstraints) { - // Initialize the maximum area bound. - setareabound(*newface, 0.0); - } - // Clear the infection and marktest bits. - ((int *) (newface->sh))[shmarkindex + 1] = 0; - if (useinsertradius) { - setfacetindex(*newface, 0); - } - // Set the boundary marker to zero. - setshellmark(*newface, 0); - - newface->shver = 0; -} - -void meshGRegionBoundaryRecovery::makepoint(point* pnewpoint, - enum verttype vtype) -{ - int i; - - *pnewpoint = (point) points->alloc(); - - // Initialize the point attributes. - for (i = 0; i < numpointattrib; i++) { - (*pnewpoint)[3 + i] = 0.0; - } - // Initialize the metric tensor. - for (i = 0; i < sizeoftensor; i++) { - (*pnewpoint)[pointmtrindex + i] = 0.0; - } - setpoint2tet(*pnewpoint, NULL); - setpoint2ppt(*pnewpoint, NULL); - if (b->plc || b->refine) { - // Initialize the point-to-simplex field. - setpoint2sh(*pnewpoint, NULL); - if (b->metric && (bgm != NULL)) { - setpoint2bgmtet(*pnewpoint, NULL); - } - } - // Initialize the point marker (starting from in->firstnumber). - setpointmark(*pnewpoint, (int) (points->items) - (!in->firstnumber)); - // Clear all flags. - ((int *) (*pnewpoint))[pointmarkindex + 1] = 0; - // Initialize (set) the point type. - setpointtype(*pnewpoint, vtype); -} - -void meshGRegionBoundaryRecovery::initializepools() -{ - int pointsize = 0, elesize = 0, shsize = 0; - int i; - - Msg::Debug(" Initializing memorypools."); - Msg::Debug(" tetrahedron per block: %d.", b->tetrahedraperblock); - - inittables(); - - if (b->plc || b->refine) { - // Save the insertion radius for Steiner points if boundaries - // are allowed be split. - if (!b->nobisect || checkconstraints) { - useinsertradius = 1; - } - } - - // The index within each point at which its metric tensor is found. - // Each vertex has three coordinates. - if (b->psc) { - // '-s' option (PSC), the u,v coordinates are provided. - pointmtrindex = 5 + numpointattrib; - // The index within each point at which its u, v coordinates are found. - // Comment: They are saved after the list of point attributes. - pointparamindex = pointmtrindex - 2; - } else { - pointmtrindex = 3 + numpointattrib; - } - // The index within each point at which an element pointer is found, where - // the index is measured in pointers. Ensure the index is aligned to a - // sizeof(tetrahedron)-byte address. - point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL) - + sizeof(tetrahedron) - 1) / sizeof(tetrahedron); - if (b->plc || b->refine || b->voroout) { - // Increase the point size by three pointers, which are: - // - a pointer to a tet, read by point2tet(); - // - a pointer to a parent point, read by point2ppt()). - // - a pointer to a subface or segment, read by point2sh(); - if (b->metric && (bgm != NULL)) { - // Increase one pointer into the background mesh, point2bgmtet(). - pointsize = (point2simindex + 4) * sizeof(tetrahedron); - } else { - pointsize = (point2simindex + 3) * sizeof(tetrahedron); - } - } else { - // Increase the point size by two pointer, which are: - // - a pointer to a tet, read by point2tet(); - // - a pointer to a parent point, read by point2ppt()). -- Used by btree. - pointsize = (point2simindex + 2) * sizeof(tetrahedron); - } - // The index within each point at which the boundary marker is found, - // Ensure the point marker is aligned to a sizeof(int)-byte address. - pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int); - // Now point size is the ints (indicated by pointmarkindex) plus: - // - an integer for boundary marker; - // - an integer for vertex type; - // - an integer for geometry tag (optional, -s option). - pointsize = (pointmarkindex + 2 + (b->psc ? 1 : 0)) * sizeof(tetrahedron); - - // Initialize the pool of vertices. -points = new memorypool(pointsize, b->vertexperblock, sizeof(REAL), 0); - -Msg::Debug(" Size of a point: %d bytes.", points->itembytes); - - // Initialize the infinite vertex. - dummypoint = (point) new char[pointsize]; - // Initialize all fields of this point. - dummypoint[0] = 0.0; - dummypoint[1] = 0.0; - dummypoint[2] = 0.0; - for (i = 0; i < numpointattrib; i++) { - dummypoint[3 + i] = 0.0; - } - // Initialize the metric tensor. - for (i = 0; i < sizeoftensor; i++) { - dummypoint[pointmtrindex + i] = 0.0; - } - setpoint2tet(dummypoint, NULL); - setpoint2ppt(dummypoint, NULL); - if (b->plc || b->psc || b->refine) { - // Initialize the point-to-simplex field. - setpoint2sh(dummypoint, NULL); - if (b->metric && (bgm != NULL)) { - setpoint2bgmtet(dummypoint, NULL); - } - } - // Initialize the point marker (starting from in->firstnumber). - setpointmark(dummypoint, -1); // The unique marker for dummypoint. - // Clear all flags. - ((int *) (dummypoint))[pointmarkindex + 1] = 0; - // Initialize (set) the point type. - setpointtype(dummypoint, UNUSEDVERTEX); // Does not matter. - - elesize = 12 * sizeof(tetrahedron); - - // The index to find the element markers. An integer containing varies - // flags and element counter. - assert(sizeof(int) <= sizeof(tetrahedron)); - assert((sizeof(tetrahedron) % sizeof(int)) == 0); - elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int); - - // The actual number of element attributes. Note that if the - // `b->regionattrib' flag is set, an additional attribute will be added. - //numelemattrib = in->numberoftetrahedronattributes + (b->regionattrib > 0); - numelemattrib = (b->regionattrib > 0); - - // The index within each element at which its attributes are found, where - // the index is measured in REALs. - elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL); - // The index within each element at which the maximum volume bound is - // found, where the index is measured in REALs. - volumeboundindex = elemattribindex + numelemattrib; - // If element attributes or an constraint are needed, increase the number - // of bytes occupied by an element. - if (b->varvolume) { - elesize = (volumeboundindex + 1) * sizeof(REAL); - } else if (numelemattrib > 0) { - elesize = volumeboundindex * sizeof(REAL); - } - - - // Having determined the memory size of an element, initialize the pool. - tetrahedrons = new memorypool(elesize, b->tetrahedraperblock, sizeof(void *), - 16); - - Msg::Debug(" Size of a tetrahedron: %d (%d) bytes.\n", elesize, - tetrahedrons->itembytes); - - if (b->plc || b->refine) { // if (b->useshelles) { - // The number of bytes occupied by a subface. The list of pointers - // stored in a subface are: three to other subfaces, three to corners, - // three to subsegments, two to tetrahedra. - shsize = 11 * sizeof(shellface); - // The index within each subface at which the maximum area bound is - // found, where the index is measured in REALs. - areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL); - // If -q switch is in use, increase the number of bytes occupied by - // a subface for saving maximum area bound. - if (checkconstraints) { - shsize = (areaboundindex + 1) * sizeof(REAL); - } else { - shsize = areaboundindex * sizeof(REAL); - } - // The index within subface at which the facet marker is found. Ensure - // the marker is aligned to a sizeof(int)-byte address. - shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int); - // Increase the number of bytes by two or three integers, one for facet - // marker, one for shellface type, and optionally one for pbc group. - shsize = (shmarkindex + 2) * sizeof(shellface); - if (useinsertradius) { - // Increase the number of byte by one integer for storing facet index. - // set/read by setfacetindex() and getfacetindex. - shsize = (shmarkindex + 3) * sizeof(shellface); - } - - // Initialize the pool of subfaces. Each subface record is eight-byte - // aligned so it has room to store an edge version (from 0 to 5) in - // the least three bits. - subfaces = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8); - - Msg::Debug(" Size of a shellface: %d (%d) bytes.", shsize, - subfaces->itembytes); - - // Initialize the pool of subsegments. The subsegment's record is same - // with subface. - subsegs = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8); - - // Initialize the pool for tet-subseg connections. - tet2segpool = new memorypool(6 * sizeof(shellface), b->shellfaceperblock, - sizeof(void *), 0); - // Initialize the pool for tet-subface connections. - tet2subpool = new memorypool(4 * sizeof(shellface), b->shellfaceperblock, - sizeof(void *), 0); - - // Initialize arraypools for segment & facet recovery. - subsegstack = new arraypool(sizeof(face), 10); - subfacstack = new arraypool(sizeof(face), 10); - subvertstack = new arraypool(sizeof(point), 8); - - // Initialize arraypools for surface point insertion/deletion. - caveshlist = new arraypool(sizeof(face), 8); - caveshbdlist = new arraypool(sizeof(face), 8); - cavesegshlist = new arraypool(sizeof(face), 4); - - cavetetshlist = new arraypool(sizeof(face), 8); - cavetetseglist = new arraypool(sizeof(face), 8); - caveencshlist = new arraypool(sizeof(face), 8); - caveencseglist = new arraypool(sizeof(face), 8); - } - - // Initialize the pools for flips. - flippool = new memorypool(sizeof(badface), 1024, sizeof(void *), 0); - unflipqueue = new arraypool(sizeof(badface), 10); - - // Initialize the arraypools for point insertion. - cavetetlist = new arraypool(sizeof(triface), 10); - cavebdrylist = new arraypool(sizeof(triface), 10); - caveoldtetlist = new arraypool(sizeof(triface), 10); - cavetetvertlist = new arraypool(sizeof(point), 10); -} - -//// //// -//// //// -//// mempool_cxx ////////////////////////////////////////////////////////////// - -//// geom_cxx ///////////////////////////////////////////////////////////////// -//// //// -//// //// - -REAL meshGRegionBoundaryRecovery::PI = 3.14159265358979323846264338327950288419716939937510582; - -REAL meshGRegionBoundaryRecovery::insphere_s(REAL* pa, REAL* pb, REAL* pc, - REAL* pd, REAL* pe) -{ - REAL sign; - - sign = insphere(pa, pb, pc, pd, pe); - if (sign != 0.0) { - return sign; - } - - // Symbolic perturbation. - point pt[5], swappt; - REAL oriA, oriB; - int swaps, count; - int n, i; - - pt[0] = pa; - pt[1] = pb; - pt[2] = pc; - pt[3] = pd; - pt[4] = pe; - - // Sort the five points such that their indices are in the increasing - // order. An optimized bubble sort algorithm is used, i.e., it has - // the worst case O(n^2) runtime, but it is usually much faster. - swaps = 0; // Record the total number of swaps. - n = 5; - do { - count = 0; - n = n - 1; - for (i = 0; i < n; i++) { - if (pointmark(pt[i]) > pointmark(pt[i+1])) { - swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt; - count++; - } - } - swaps += count; - } while (count > 0); // Continue if some points are swapped. - - oriA = orient3d(pt[1], pt[2], pt[3], pt[4]); - if (oriA != 0.0) { - // Flip the sign if there are odd number of swaps. - if ((swaps % 2) != 0) oriA = -oriA; - return oriA; - } - - oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]); - assert(oriB != 0.0); // SELF_CHECK - // Flip the sign if there are odd number of swaps. - if ((swaps % 2) != 0) oriB = -oriB; - return oriB; -} - -inline REAL orient4dfast(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe, - REAL aheight, REAL bheight, REAL cheight, - REAL dheight, REAL eheight) -{ - const REAL aex = pa[0] - pe[0]; - const REAL bex = pb[0] - pe[0]; - const REAL cex = pc[0] - pe[0]; - const REAL dex = pd[0] - pe[0]; - const REAL aey = pa[1] - pe[1]; - const REAL bey = pb[1] - pe[1]; - const REAL cey = pc[1] - pe[1]; - const REAL dey = pd[1] - pe[1]; - const REAL aez = pa[2] - pe[2]; - const REAL bez = pb[2] - pe[2]; - const REAL cez = pc[2] - pe[2]; - const REAL dez = pd[2] - pe[2]; - const REAL aeheight = aheight - eheight; - const REAL beheight = bheight - eheight; - const REAL ceheight = cheight - eheight; - const REAL deheight = dheight - eheight; - - const REAL aexbey = aex * bey; - const REAL bexaey = bex * aey; - const REAL ab = aexbey - bexaey; - const REAL bexcey = bex * cey; - const REAL cexbey = cex * bey; - const REAL bc = bexcey - cexbey; - const REAL cexdey = cex * dey; - const REAL dexcey = dex * cey; - const REAL cd = cexdey - dexcey; - const REAL dexaey = dex * aey; - const REAL aexdey = aex * dey; - const REAL da = dexaey - aexdey; - - const REAL aexcey = aex * cey; - const REAL cexaey = cex * aey; - const REAL ac = aexcey - cexaey; - const REAL bexdey = bex * dey; - const REAL dexbey = dex * bey; - const REAL bd = bexdey - dexbey; - - const REAL abc = aez * bc - bez * ac + cez * ab; - const REAL bcd = bez * cd - cez * bd + dez * bc; - const REAL cda = cez * da + dez * ac + aez * cd; - const REAL dab = dez * ab + aez * bd + bez * da; - - const REAL det = (deheight * abc - ceheight * dab) + (beheight * cda - aeheight * bcd); - - return det; -} - -#define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2) - -#define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp) - -int meshGRegionBoundaryRecovery::tri_edge_2d(point A, point B, point C, - point P, point Q, point R, int level, int *types, int *pos) -{ - point U[3], V[3]; // The permuted vectors of points. - int pu[3], pv[3]; // The original positions of points. - REAL abovept[3]; - REAL sA, sB, sC; - REAL s1, s2, s3, s4; - int z1; - - if (R == NULL) { - // Calculate a lift point. - if (1) { - REAL n[3], len; - // Calculate a lift point, saved in dummypoint. - facenormal(A, B, C, n, 1, NULL); - len = sqrt(dot(n, n)); - if (len != 0) { - n[0] /= len; - n[1] /= len; - n[2] /= len; - len = distance(A, B); - len += distance(B, C); - len += distance(C, A); - len /= 3.0; - R = abovept; //dummypoint; - R[0] = A[0] + len * n[0]; - R[1] = A[1] + len * n[1]; - R[2] = A[2] + len * n[2]; - } else { - // The triangle [A,B,C] is (nearly) degenerate, i.e., it is (close) - // to a line. We need a line-line intersection test. - //assert(0); - // !!! A non-save return value.!!! - return 0; // DISJOINT - } - } - } - - // Test A's, B's, and C's orientations wrt plane PQR. - sA = orient3d(P, Q, R, A); - sB = orient3d(P, Q, R, B); - sC = orient3d(P, Q, R, C); - - - if (sA < 0) { - if (sB < 0) { - if (sC < 0) { // (---). - return 0; - } else { - if (sC > 0) { // (--+). - // All points are in the right positions. - SETVECTOR3(U, A, B, C); // I3 - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 0, 1, 2); - z1 = 0; - } else { // (--0). - SETVECTOR3(U, A, B, C); // I3 - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 0, 1, 2); - z1 = 1; - } - } - } else { - if (sB > 0) { - if (sC < 0) { // (-+-). - SETVECTOR3(U, C, A, B); // PT = ST - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 2, 0, 1); - SETVECTOR3(pv, 0, 1, 2); - z1 = 0; - } else { - if (sC > 0) { // (-++). - SETVECTOR3(U, B, C, A); // PT = ST x ST - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 1, 2, 0); - SETVECTOR3(pv, 1, 0, 2); - z1 = 0; - } else { // (-+0). - SETVECTOR3(U, C, A, B); // PT = ST - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 2, 0, 1); - SETVECTOR3(pv, 0, 1, 2); - z1 = 2; - } - } - } else { - if (sC < 0) { // (-0-). - SETVECTOR3(U, C, A, B); // PT = ST - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 2, 0, 1); - SETVECTOR3(pv, 0, 1, 2); - z1 = 1; - } else { - if (sC > 0) { // (-0+). - SETVECTOR3(U, B, C, A); // PT = ST x ST - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 1, 2, 0); - SETVECTOR3(pv, 1, 0, 2); - z1 = 2; - } else { // (-00). - SETVECTOR3(U, B, C, A); // PT = ST x ST - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 1, 2, 0); - SETVECTOR3(pv, 1, 0, 2); - z1 = 3; - } - } - } - } - } else { - if (sA > 0) { - if (sB < 0) { - if (sC < 0) { // (+--). - SETVECTOR3(U, B, C, A); // PT = ST x ST - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 1, 2, 0); - SETVECTOR3(pv, 0, 1, 2); - z1 = 0; - } else { - if (sC > 0) { // (+-+). - SETVECTOR3(U, C, A, B); // PT = ST - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 2, 0, 1); - SETVECTOR3(pv, 1, 0, 2); - z1 = 0; - } else { // (+-0). - SETVECTOR3(U, C, A, B); // PT = ST - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 2, 0, 1); - SETVECTOR3(pv, 1, 0, 2); - z1 = 2; - } - } - } else { - if (sB > 0) { - if (sC < 0) { // (++-). - SETVECTOR3(U, A, B, C); // I3 - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 1, 0, 2); - z1 = 0; - } else { - if (sC > 0) { // (+++). - return 0; - } else { // (++0). - SETVECTOR3(U, A, B, C); // I3 - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 1, 0, 2); - z1 = 1; - } - } - } else { // (+0#) - if (sC < 0) { // (+0-). - SETVECTOR3(U, B, C, A); // PT = ST x ST - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 1, 2, 0); - SETVECTOR3(pv, 0, 1, 2); - z1 = 2; - } else { - if (sC > 0) { // (+0+). - SETVECTOR3(U, C, A, B); // PT = ST - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 2, 0, 1); - SETVECTOR3(pv, 1, 0, 2); - z1 = 1; - } else { // (+00). - SETVECTOR3(U, B, C, A); // PT = ST x ST - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 1, 2, 0); - SETVECTOR3(pv, 0, 1, 2); - z1 = 3; - } - } - } - } - } else { - if (sB < 0) { - if (sC < 0) { // (0--). - SETVECTOR3(U, B, C, A); // PT = ST x ST - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 1, 2, 0); - SETVECTOR3(pv, 0, 1, 2); - z1 = 1; - } else { - if (sC > 0) { // (0-+). - SETVECTOR3(U, A, B, C); // I3 - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 0, 1, 2); - z1 = 2; - } else { // (0-0). - SETVECTOR3(U, C, A, B); // PT = ST - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 2, 0, 1); - SETVECTOR3(pv, 1, 0, 2); - z1 = 3; - } - } - } else { - if (sB > 0) { - if (sC < 0) { // (0+-). - SETVECTOR3(U, A, B, C); // I3 - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 1, 0, 2); - z1 = 2; - } else { - if (sC > 0) { // (0++). - SETVECTOR3(U, B, C, A); // PT = ST x ST - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 1, 2, 0); - SETVECTOR3(pv, 1, 0, 2); - z1 = 1; - } else { // (0+0). - SETVECTOR3(U, C, A, B); // PT = ST - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 2, 0, 1); - SETVECTOR3(pv, 0, 1, 2); - z1 = 3; - } - } - } else { // (00#) - if (sC < 0) { // (00-). - SETVECTOR3(U, A, B, C); // I3 - SETVECTOR3(V, Q, P, R); // PL = SL - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 1, 0, 2); - z1 = 3; - } else { - if (sC > 0) { // (00+). - SETVECTOR3(U, A, B, C); // I3 - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 0, 1, 2); - z1 = 3; - } else { // (000) - // Not possible unless ABC is degenerate. - // Avoiding compiler warnings. - SETVECTOR3(U, A, B, C); // I3 - SETVECTOR3(V, P, Q, R); // I2 - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 0, 1, 2); - z1 = 4; - } - } - } - } - } - } - - s1 = orient3d(U[0], U[2], R, V[1]); // A, C, R, Q - s2 = orient3d(U[1], U[2], R, V[0]); // B, C, R, P - - if (s1 > 0) { - return 0; - } - if (s2 < 0) { - return 0; - } - - if (level == 0) { - return 1; // They are intersected. - } - - assert(z1 != 4); // SELF_CHECK - - if (z1 == 1) { - if (s1 == 0) { // (0###) - // C = Q. - types[0] = (int) SHAREVERT; - pos[0] = pu[2]; // C - pos[1] = pv[1]; // Q - types[1] = (int) DISJOINT; - } else { - if (s2 == 0) { // (#0##) - // C = P. - types[0] = (int) SHAREVERT; - pos[0] = pu[2]; // C - pos[1] = pv[0]; // P - types[1] = (int) DISJOINT; - } else { // (-+##) - // C in [P, Q]. - types[0] = (int) ACROSSVERT; - pos[0] = pu[2]; // C - pos[1] = pv[0]; // [P, Q] - types[1] = (int) DISJOINT; - } - } - return 4; - } - - s3 = orient3d(U[0], U[2], R, V[0]); // A, C, R, P - s4 = orient3d(U[1], U[2], R, V[1]); // B, C, R, Q - - if (z1 == 0) { // (tritri-03) - if (s1 < 0) { - if (s3 > 0) { - assert(s2 > 0); // SELF_CHECK - if (s4 > 0) { - // [P, Q] overlaps [k, l] (-+++). - types[0] = (int) ACROSSEDGE; - pos[0] = pu[2]; // [C, A] - pos[1] = pv[0]; // [P, Q] - types[1] = (int) TOUCHFACE; - pos[2] = 3; // [A, B, C] - pos[3] = pv[1]; // Q - } else { - if (s4 == 0) { - // Q = l, [P, Q] contains [k, l] (-++0). - types[0] = (int) ACROSSEDGE; - pos[0] = pu[2]; // [C, A] - pos[1] = pv[0]; // [P, Q] - types[1] = (int) TOUCHEDGE; - pos[2] = pu[1]; // [B, C] - pos[3] = pv[1]; // Q - } else { // s4 < 0 - // [P, Q] contains [k, l] (-++-). - types[0] = (int) ACROSSEDGE; - pos[0] = pu[2]; // [C, A] - pos[1] = pv[0]; // [P, Q] - types[1] = (int) ACROSSEDGE; - pos[2] = pu[1]; // [B, C] - pos[3] = pv[0]; // [P, Q] - } - } - } else { - if (s3 == 0) { - assert(s2 > 0); // SELF_CHECK - if (s4 > 0) { - // P = k, [P, Q] in [k, l] (-+0+). - types[0] = (int) TOUCHEDGE; - pos[0] = pu[2]; // [C, A] - pos[1] = pv[0]; // P - types[1] = (int) TOUCHFACE; - pos[2] = 3; // [A, B, C] - pos[3] = pv[1]; // Q - } else { - if (s4 == 0) { - // [P, Q] = [k, l] (-+00). - types[0] = (int) TOUCHEDGE; - pos[0] = pu[2]; // [C, A] - pos[1] = pv[0]; // P - types[1] = (int) TOUCHEDGE; - pos[2] = pu[1]; // [B, C] - pos[3] = pv[1]; // Q - } else { - // P = k, [P, Q] contains [k, l] (-+0-). - types[0] = (int) TOUCHEDGE; - pos[0] = pu[2]; // [C, A] - pos[1] = pv[0]; // P - types[1] = (int) ACROSSEDGE; - pos[2] = pu[1]; // [B, C] - pos[3] = pv[0]; // [P, Q] - } - } - } else { // s3 < 0 - if (s2 > 0) { - if (s4 > 0) { - // [P, Q] in [k, l] (-+-+). - types[0] = (int) TOUCHFACE; - pos[0] = 3; // [A, B, C] - pos[1] = pv[0]; // P - types[1] = (int) TOUCHFACE; - pos[2] = 3; // [A, B, C] - pos[3] = pv[1]; // Q - } else { - if (s4 == 0) { - // Q = l, [P, Q] in [k, l] (-+-0). - types[0] = (int) TOUCHFACE; - pos[0] = 3; // [A, B, C] - pos[1] = pv[0]; // P - types[1] = (int) TOUCHEDGE; - pos[2] = pu[1]; // [B, C] - pos[3] = pv[1]; // Q - } else { // s4 < 0 - // [P, Q] overlaps [k, l] (-+--). - types[0] = (int) TOUCHFACE; - pos[0] = 3; // [A, B, C] - pos[1] = pv[0]; // P - types[1] = (int) ACROSSEDGE; - pos[2] = pu[1]; // [B, C] - pos[3] = pv[0]; // [P, Q] - } - } - } else { // s2 == 0 - // P = l (#0##). - types[0] = (int) TOUCHEDGE; - pos[0] = pu[1]; // [B, C] - pos[1] = pv[0]; // P - types[1] = (int) DISJOINT; - } - } - } - } else { // s1 == 0 - // Q = k (0####) - types[0] = (int) TOUCHEDGE; - pos[0] = pu[2]; // [C, A] - pos[1] = pv[1]; // Q - types[1] = (int) DISJOINT; - } - } else if (z1 == 2) { // (tritri-23) - if (s1 < 0) { - if (s3 > 0) { - assert(s2 > 0); // SELF_CHECK - if (s4 > 0) { - // [P, Q] overlaps [A, l] (-+++). - types[0] = (int) ACROSSVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // [P, Q] - types[1] = (int) TOUCHFACE; - pos[2] = 3; // [A, B, C] - pos[3] = pv[1]; // Q - } else { - if (s4 == 0) { - // Q = l, [P, Q] contains [A, l] (-++0). - types[0] = (int) ACROSSVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // [P, Q] - types[1] = (int) TOUCHEDGE; - pos[2] = pu[1]; // [B, C] - pos[3] = pv[1]; // Q - } else { // s4 < 0 - // [P, Q] contains [A, l] (-++-). - types[0] = (int) ACROSSVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // [P, Q] - types[1] = (int) ACROSSEDGE; - pos[2] = pu[1]; // [B, C] - pos[3] = pv[0]; // [P, Q] - } - } - } else { - if (s3 == 0) { - assert(s2 > 0); // SELF_CHECK - if (s4 > 0) { - // P = A, [P, Q] in [A, l] (-+0+). - types[0] = (int) SHAREVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // P - types[1] = (int) TOUCHFACE; - pos[2] = 3; // [A, B, C] - pos[3] = pv[1]; // Q - } else { - if (s4 == 0) { - // [P, Q] = [A, l] (-+00). - types[0] = (int) SHAREVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // P - types[1] = (int) TOUCHEDGE; - pos[2] = pu[1]; // [B, C] - pos[3] = pv[1]; // Q - } else { // s4 < 0 - // Q = l, [P, Q] in [A, l] (-+0-). - types[0] = (int) SHAREVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // P - types[1] = (int) ACROSSEDGE; - pos[2] = pu[1]; // [B, C] - pos[3] = pv[0]; // [P, Q] - } - } - } else { // s3 < 0 - if (s2 > 0) { - if (s4 > 0) { - // [P, Q] in [A, l] (-+-+). - types[0] = (int) TOUCHFACE; - pos[0] = 3; // [A, B, C] - pos[1] = pv[0]; // P - types[0] = (int) TOUCHFACE; - pos[0] = 3; // [A, B, C] - pos[1] = pv[1]; // Q - } else { - if (s4 == 0) { - // Q = l, [P, Q] in [A, l] (-+-0). - types[0] = (int) TOUCHFACE; - pos[0] = 3; // [A, B, C] - pos[1] = pv[0]; // P - types[0] = (int) TOUCHEDGE; - pos[0] = pu[1]; // [B, C] - pos[1] = pv[1]; // Q - } else { // s4 < 0 - // [P, Q] overlaps [A, l] (-+--). - types[0] = (int) TOUCHFACE; - pos[0] = 3; // [A, B, C] - pos[1] = pv[0]; // P - types[0] = (int) ACROSSEDGE; - pos[0] = pu[1]; // [B, C] - pos[1] = pv[0]; // [P, Q] - } - } - } else { // s2 == 0 - // P = l (#0##). - types[0] = (int) TOUCHEDGE; - pos[0] = pu[1]; // [B, C] - pos[1] = pv[0]; // P - types[1] = (int) DISJOINT; - } - } - } - } else { // s1 == 0 - // Q = A (0###). - types[0] = (int) SHAREVERT; - pos[0] = pu[0]; // A - pos[1] = pv[1]; // Q - types[1] = (int) DISJOINT; - } - } else if (z1 == 3) { // (tritri-33) - if (s1 < 0) { - if (s3 > 0) { - assert(s2 > 0); // SELF_CHECK - if (s4 > 0) { - // [P, Q] overlaps [A, B] (-+++). - types[0] = (int) ACROSSVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // [P, Q] - types[1] = (int) TOUCHEDGE; - pos[2] = pu[0]; // [A, B] - pos[3] = pv[1]; // Q - } else { - if (s4 == 0) { - // Q = B, [P, Q] contains [A, B] (-++0). - types[0] = (int) ACROSSVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // [P, Q] - types[1] = (int) SHAREVERT; - pos[2] = pu[1]; // B - pos[3] = pv[1]; // Q - } else { // s4 < 0 - // [P, Q] contains [A, B] (-++-). - types[0] = (int) ACROSSVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // [P, Q] - types[1] = (int) ACROSSVERT; - pos[2] = pu[1]; // B - pos[3] = pv[0]; // [P, Q] - } - } - } else { - if (s3 == 0) { - assert(s2 > 0); // SELF_CHECK - if (s4 > 0) { - // P = A, [P, Q] in [A, B] (-+0+). - types[0] = (int) SHAREVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // P - types[1] = (int) TOUCHEDGE; - pos[2] = pu[0]; // [A, B] - pos[3] = pv[1]; // Q - } else { - if (s4 == 0) { - // [P, Q] = [A, B] (-+00). - types[0] = (int) SHAREEDGE; - pos[0] = pu[0]; // [A, B] - pos[1] = pv[0]; // [P, Q] - types[1] = (int) DISJOINT; - } else { // s4 < 0 - // P= A, [P, Q] in [A, B] (-+0-). - types[0] = (int) SHAREVERT; - pos[0] = pu[0]; // A - pos[1] = pv[0]; // P - types[1] = (int) ACROSSVERT; - pos[2] = pu[1]; // B - pos[3] = pv[0]; // [P, Q] - } - } - } else { // s3 < 0 - if (s2 > 0) { - if (s4 > 0) { - // [P, Q] in [A, B] (-+-+). - types[0] = (int) TOUCHEDGE; - pos[0] = pu[0]; // [A, B] - pos[1] = pv[0]; // P - types[1] = (int) TOUCHEDGE; - pos[2] = pu[0]; // [A, B] - pos[3] = pv[1]; // Q - } else { - if (s4 == 0) { - // Q = B, [P, Q] in [A, B] (-+-0). - types[0] = (int) TOUCHEDGE; - pos[0] = pu[0]; // [A, B] - pos[1] = pv[0]; // P - types[1] = (int) SHAREVERT; - pos[2] = pu[1]; // B - pos[3] = pv[1]; // Q - } else { // s4 < 0 - // [P, Q] overlaps [A, B] (-+--). - types[0] = (int) TOUCHEDGE; - pos[0] = pu[0]; // [A, B] - pos[1] = pv[0]; // P - types[1] = (int) ACROSSVERT; - pos[2] = pu[1]; // B - pos[3] = pv[0]; // [P, Q] - } - } - } else { // s2 == 0 - // P = B (#0##). - types[0] = (int) SHAREVERT; - pos[0] = pu[1]; // B - pos[1] = pv[0]; // P - types[1] = (int) DISJOINT; - } - } - } - } else { // s1 == 0 - // Q = A (0###). - types[0] = (int) SHAREVERT; - pos[0] = pu[0]; // A - pos[1] = pv[1]; // Q - types[1] = (int) DISJOINT; - } - } - - return 4; -} - -int meshGRegionBoundaryRecovery::tri_edge_tail(point A,point B,point C,point P, - point Q,point R, REAL sP,REAL sQ,int level,int *types,int *pos) -{ - point U[3], V[3]; //, Ptmp; - int pu[3], pv[3]; //, itmp; - REAL s1, s2, s3; - int z1; - - - if (sP < 0) { - if (sQ < 0) { // (--) disjoint - return 0; - } else { - if (sQ > 0) { // (-+) - SETVECTOR3(U, A, B, C); - SETVECTOR3(V, P, Q, R); - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 0, 1, 2); - z1 = 0; - } else { // (-0) - SETVECTOR3(U, A, B, C); - SETVECTOR3(V, P, Q, R); - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 0, 1, 2); - z1 = 1; - } - } - } else { - if (sP > 0) { // (+-) - if (sQ < 0) { - SETVECTOR3(U, A, B, C); - SETVECTOR3(V, Q, P, R); // P and Q are flipped. - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 1, 0, 2); - z1 = 0; - } else { - if (sQ > 0) { // (++) disjoint - return 0; - } else { // (+0) - SETVECTOR3(U, B, A, C); // A and B are flipped. - SETVECTOR3(V, P, Q, R); - SETVECTOR3(pu, 1, 0, 2); - SETVECTOR3(pv, 0, 1, 2); - z1 = 1; - } - } - } else { // sP == 0 - if (sQ < 0) { // (0-) - SETVECTOR3(U, A, B, C); - SETVECTOR3(V, Q, P, R); // P and Q are flipped. - SETVECTOR3(pu, 0, 1, 2); - SETVECTOR3(pv, 1, 0, 2); - z1 = 1; - } else { - if (sQ > 0) { // (0+) - SETVECTOR3(U, B, A, C); // A and B are flipped. - SETVECTOR3(V, Q, P, R); // P and Q are flipped. - SETVECTOR3(pu, 1, 0, 2); - SETVECTOR3(pv, 1, 0, 2); - z1 = 1; - } else { // (00) - // A, B, C, P, and Q are coplanar. - z1 = 2; - } - } - } - } - - if (z1 == 2) { - // The triangle and the edge are coplanar. - return tri_edge_2d(A, B, C, P, Q, R, level, types, pos); - } - - s1 = orient3d(U[0], U[1], V[0], V[1]); - if (s1 < 0) { - return 0; - } - - s2 = orient3d(U[1], U[2], V[0], V[1]); - if (s2 < 0) { - return 0; - } - - s3 = orient3d(U[2], U[0], V[0], V[1]); - if (s3 < 0) { - return 0; - } - - if (level == 0) { - return 1; // The are intersected. - } - - types[1] = (int) DISJOINT; // No second intersection point. - - if (z1 == 0) { - if (s1 > 0) { - if (s2 > 0) { - if (s3 > 0) { // (+++) - // [P, Q] passes interior of [A, B, C]. - types[0] = (int) ACROSSFACE; - pos[0] = 3; // interior of [A, B, C] - pos[1] = 0; // [P, Q] - } else { // s3 == 0 (++0) - // [P, Q] intersects [C, A]. - types[0] = (int) ACROSSEDGE; - pos[0] = pu[2]; // [C, A] - pos[1] = 0; // [P, Q] - } - } else { // s2 == 0 - if (s3 > 0) { // (+0+) - // [P, Q] intersects [B, C]. - types[0] = (int) ACROSSEDGE; - pos[0] = pu[1]; // [B, C] - pos[1] = 0; // [P, Q] - } else { // s3 == 0 (+00) - // [P, Q] passes C. - types[0] = (int) ACROSSVERT; - pos[0] = pu[2]; // C - pos[1] = 0; // [P, Q] - } - } - } else { // s1 == 0 - if (s2 > 0) { - if (s3 > 0) { // (0++) - // [P, Q] intersects [A, B]. - types[0] = (int) ACROSSEDGE; - pos[0] = pu[0]; // [A, B] - pos[1] = 0; // [P, Q] - } else { // s3 == 0 (0+0) - // [P, Q] passes A. - types[0] = (int) ACROSSVERT; - pos[0] = pu[0]; // A - pos[1] = 0; // [P, Q] - } - } else { // s2 == 0 - if (s3 > 0) { // (00+) - // [P, Q] passes B. - types[0] = (int) ACROSSVERT; - pos[0] = pu[1]; // B - pos[1] = 0; // [P, Q] - } else { // s3 == 0 (000) - // Impossible. - assert(0); - } - } - } - } else { // z1 == 1 - if (s1 > 0) { - if (s2 > 0) { - if (s3 > 0) { // (+++) - // Q lies in [A, B, C]. - types[0] = (int) TOUCHFACE; - pos[0] = 0; // [A, B, C] - pos[1] = pv[1]; // Q - } else { // s3 == 0 (++0) - // Q lies on [C, A]. - types[0] = (int) TOUCHEDGE; - pos[0] = pu[2]; // [C, A] - pos[1] = pv[1]; // Q - } - } else { // s2 == 0 - if (s3 > 0) { // (+0+) - // Q lies on [B, C]. - types[0] = (int) TOUCHEDGE; - pos[0] = pu[1]; // [B, C] - pos[1] = pv[1]; // Q - } else { // s3 == 0 (+00) - // Q = C. - types[0] = (int) SHAREVERT; - pos[0] = pu[2]; // C - pos[1] = pv[1]; // Q - } - } - } else { // s1 == 0 - if (s2 > 0) { - if (s3 > 0) { // (0++) - // Q lies on [A, B]. - types[0] = (int) TOUCHEDGE; - pos[0] = pu[0]; // [A, B] - pos[1] = pv[1]; // Q - } else { // s3 == 0 (0+0) - // Q = A. - types[0] = (int) SHAREVERT; - pos[0] = pu[0]; // A - pos[1] = pv[1]; // Q - } - } else { // s2 == 0 - if (s3 > 0) { // (00+) - // Q = B. - types[0] = (int) SHAREVERT; - pos[0] = pu[1]; // B - pos[1] = pv[1]; // Q - } else { // s3 == 0 (000) - // Impossible. - assert(0); - } - } - } - } - - // T and E intersect in a single point. - return 2; -} - -int meshGRegionBoundaryRecovery::tri_edge_test(point A, point B, point C, - point P, point Q, point R, int level, int *types, int *pos) -{ - REAL sP, sQ; - - // Test the locations of P and Q with respect to ABC. - sP = orient3d(A, B, C, P); - sQ = orient3d(A, B, C, Q); - - return tri_edge_tail(A, B, C, P, Q, R, sP, sQ, level, types, pos); -} - -bool meshGRegionBoundaryRecovery::lu_decmp(REAL lu[4][4], int n, int* ps, - REAL* d, int N) -{ - REAL scales[4]; - REAL pivot, biggest, mult, tempf; - int pivotindex = 0; - int i, j, k; - - *d = 1.0; // No row interchanges yet. - - for (i = N; i < n + N; i++) { // For each row. - // Find the largest element in each row for row equilibration - biggest = 0.0; - for (j = N; j < n + N; j++) - if (biggest < (tempf = fabs(lu[i][j]))) - biggest = tempf; - if (biggest != 0.0) - scales[i] = 1.0 / biggest; - else { - scales[i] = 0.0; - return false; // Zero row: singular matrix. - } - ps[i] = i; // Initialize pivot sequence. - } - - for (k = N; k < n + N - 1; k++) { // For each column. - // Find the largest element in each column to pivot around. - biggest = 0.0; - for (i = k; i < n + N; i++) { - if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) { - biggest = tempf; - pivotindex = i; - } - } - if (biggest == 0.0) { - return false; // Zero column: singular matrix. - } - if (pivotindex != k) { // Update pivot sequence. - j = ps[k]; - ps[k] = ps[pivotindex]; - ps[pivotindex] = j; - *d = -(*d); // ...and change the parity of d. - } - - // Pivot, eliminating an extra variable each time - pivot = lu[ps[k]][k]; - for (i = k + 1; i < n + N; i++) { - lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot; - if (mult != 0.0) { - for (j = k + 1; j < n + N; j++) - lu[ps[i]][j] -= mult * lu[ps[k]][j]; - } - } - } - - // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular. - return lu[ps[n + N - 1]][n + N - 1] != 0.0; -} - -void meshGRegionBoundaryRecovery::lu_solve(REAL lu[4][4], int n, int* ps, - REAL* b, int N) -{ - int i, j; - REAL X[4], dot; - - for (i = N; i < n + N; i++) X[i] = 0.0; - - // Vector reduction using U triangular matrix. - for (i = N; i < n + N; i++) { - dot = 0.0; - for (j = N; j < i + N; j++) - dot += lu[ps[i]][j] * X[j]; - X[i] = b[ps[i]] - dot; - } - - // Back substitution, in L triangular matrix. - for (i = n + N - 1; i >= N; i--) { - dot = 0.0; - for (j = i + 1; j < n + N; j++) - dot += lu[ps[i]][j] * X[j]; - X[i] = (X[i] - dot) / lu[ps[i]][i]; - } - - for (i = N; i < n + N; i++) b[i] = X[i]; -} - -REAL meshGRegionBoundaryRecovery::incircle3d(point pa, point pb, point pc, - point pd) -{ - REAL area2[2], n1[3], n2[3], c[3]; - REAL sign, r, d; - - // Calculate the areas of the two triangles [a, b, c] and [b, a, d]. - facenormal(pa, pb, pc, n1, 1, NULL); - area2[0] = dot(n1, n1); - facenormal(pb, pa, pd, n2, 1, NULL); - area2[1] = dot(n2, n2); - - if (area2[0] > area2[1]) { - // Choose [a, b, c] as the base triangle. - circumsphere(pa, pb, pc, NULL, c, &r); - d = distance(c, pd); - } else { - // Choose [b, a, d] as the base triangle. - if (area2[1] > 0) { - circumsphere(pb, pa, pd, NULL, c, &r); - d = distance(c, pc); - } else { - // The four points are collinear. This case only happens on the boundary. - return 0; // Return "not inside". - } - } - - sign = d - r; - if (fabs(sign) / r < b->epsilon) { - sign = 0; - } - - return sign; -} - -void meshGRegionBoundaryRecovery::facenormal(point pa, point pb, point pc, - REAL *n, int pivot, REAL* lav) -{ - REAL v1[3], v2[3], v3[3], *pv1, *pv2; - REAL L1, L2, L3; - - v1[0] = pb[0] - pa[0]; // edge vector v1: a->b - v1[1] = pb[1] - pa[1]; - v1[2] = pb[2] - pa[2]; - v2[0] = pa[0] - pc[0]; // edge vector v2: c->a - v2[1] = pa[1] - pc[1]; - v2[2] = pa[2] - pc[2]; - - // Default, normal is calculated by: v1 x (-v2) (see Fig. fnormal). - if (pivot > 0) { - // Choose edge vectors by Burdakov's algorithm. - v3[0] = pc[0] - pb[0]; // edge vector v3: b->c - v3[1] = pc[1] - pb[1]; - v3[2] = pc[2] - pb[2]; - L1 = dot(v1, v1); - L2 = dot(v2, v2); - L3 = dot(v3, v3); - // Sort the three edge lengths. - if (L1 < L2) { - if (L2 < L3) { - pv1 = v1; pv2 = v2; // n = v1 x (-v2). - } else { - pv1 = v3; pv2 = v1; // n = v3 x (-v1). - } - } else { - if (L1 < L3) { - pv1 = v1; pv2 = v2; // n = v1 x (-v2). - } else { - pv1 = v2; pv2 = v3; // n = v2 x (-v3). - } - } - if (lav) { - // return the average edge length. - *lav = (sqrt(L1) + sqrt(L2) + sqrt(L3)) / 3.0; - } - } else { - pv1 = v1; pv2 = v2; // n = v1 x (-v2). - } - - // Calculate the face normal. - cross(pv1, pv2, n); - // Inverse the direction; - n[0] = -n[0]; - n[1] = -n[1]; - n[2] = -n[2]; -} - -REAL meshGRegionBoundaryRecovery::orient3dfast(REAL *pa, REAL *pb, REAL *pc, - REAL *pd) -{ - REAL adx, bdx, cdx; - REAL ady, bdy, cdy; - REAL adz, bdz, cdz; - - adx = pa[0] - pd[0]; - bdx = pb[0] - pd[0]; - cdx = pc[0] - pd[0]; - ady = pa[1] - pd[1]; - bdy = pb[1] - pd[1]; - cdy = pc[1] - pd[1]; - adz = pa[2] - pd[2]; - bdz = pb[2] - pd[2]; - cdz = pc[2] - pd[2]; - - return adx * (bdy * cdz - bdz * cdy) - + bdx * (cdy * adz - cdz * ady) - + cdx * (ady * bdz - adz * bdy); -} - -bool meshGRegionBoundaryRecovery::tetalldihedral(point pa, point pb, point pc, - point pd, REAL* cosdd, REAL* cosmaxd, REAL* cosmind) -{ - REAL N[4][3], vol, cosd, len; - int f1 = 0, f2 = 0, i, j; - - vol = 0; // Check if the tet is valid or not. - - // Get four normals of faces of the tet. - tetallnormal(pa, pb, pc, pd, N, &vol); - - if (vol > 0) { - // Normalize the normals. - for (i = 0; i < 4; i++) { - len = sqrt(dot(N[i], N[i])); - if (len != 0.0) { - for (j = 0; j < 3; j++) N[i][j] /= len; - } else { - // There are degeneracies, such as duplicated vertices. - vol = 0; //assert(0); - } - } - } - - if (vol <= 0) { // if (vol == 0.0) { - // A degenerated tet or an inverted tet. - facenormal(pc, pb, pd, N[0], 1, NULL); - facenormal(pa, pc, pd, N[1], 1, NULL); - facenormal(pb, pa, pd, N[2], 1, NULL); - facenormal(pa, pb, pc, N[3], 1, NULL); - // Normalize the normals. - for (i = 0; i < 4; i++) { - len = sqrt(dot(N[i], N[i])); - if (len != 0.0) { - for (j = 0; j < 3; j++) N[i][j] /= len; - } else { - // There are degeneracies, such as duplicated vertices. - break; // Not a valid normal. - } - } - if (i < 4) { - // Do not calculate dihedral angles. - // Set all angles be 0 degree. There will be no quality optimization for - // this tet! Use volume optimization to correct it. - if (cosdd != NULL) { - for (i = 0; i < 6; i++) { - cosdd[i] = -1.0; // 180 degree. - } - } - // This tet has zero volume. - if (cosmaxd != NULL) { - *cosmaxd = -1.0; // 180 degree. - } - if (cosmind != NULL) { - *cosmind = -1.0; // 180 degree. - } - return false; - } - } - - // Calculate the cosine of the dihedral angles of the edges. - for (i = 0; i < 6; i++) { - switch (i) { - case 0: f1 = 0; f2 = 1; break; // [c,d]. - case 1: f1 = 1; f2 = 2; break; // [a,d]. - case 2: f1 = 2; f2 = 3; break; // [a,b]. - case 3: f1 = 0; f2 = 3; break; // [b,c]. - case 4: f1 = 2; f2 = 0; break; // [b,d]. - case 5: f1 = 1; f2 = 3; break; // [a,c]. - } - cosd = -dot(N[f1], N[f2]); - if (cosd < -1.0) cosd = -1.0; // Rounding. - if (cosd > 1.0) cosd = 1.0; // Rounding. - if (cosdd) cosdd[i] = cosd; - if (cosmaxd || cosmind) { - if (i == 0) { - if (cosmaxd) *cosmaxd = cosd; - if (cosmind) *cosmind = cosd; - } else { - if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd; - if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind; - } - } - } - - return true; -} - -void meshGRegionBoundaryRecovery::tetallnormal(point pa, point pb, point pc, - point pd, REAL N[4][3], REAL* volume) -{ - REAL A[4][4], rhs[4], D; - int indx[4]; - int i, j; - - // get the entries of A[3][3]. - for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i]; // d->a vec - for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i]; // d->b vec - for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i]; // d->c vec - - // Compute the inverse of matrix A, to get 3 normals of the 4 faces. - if (lu_decmp(A, 3, indx, &D, 0)) { // Decompose the matrix just once. - if (volume != NULL) { - // Get the volume of the tet. - *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0; - } - for (j = 0; j < 3; j++) { - for (i = 0; i < 3; i++) rhs[i] = 0.0; - rhs[j] = 1.0; // Positive means the inside direction - lu_solve(A, 3, indx, rhs, 0); - for (i = 0; i < 3; i++) N[j][i] = rhs[i]; - } - // Get the fourth normal by summing up the first three. - for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i]; - } else { - // The tet is degenerated. - if (volume != NULL) { - *volume = 0; - } - } -} - -REAL meshGRegionBoundaryRecovery::tetaspectratio(point pa, point pb, point pc, - point pd) -{ - REAL vda[3], vdb[3], vdc[3]; - REAL N[4][3], A[4][4], rhs[4], D; - REAL H[4], volume, radius2, minheightinv; - int indx[4]; - int i, j; - - // Set the matrix A = [vda, vdb, vdc]^T. - for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i]; - for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i]; - for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i]; - // Lu-decompose the matrix A. - lu_decmp(A, 3, indx, &D, 0); - // Get the volume of abcd. - volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0; - // Check if it is zero. - if (volume == 0.0) return 1.0e+200; // A degenerate tet. - // if (volume < 0.0) volume = -volume; - // Check the radiu-edge ratio of the tet. - rhs[0] = 0.5 * dot(vda, vda); - rhs[1] = 0.5 * dot(vdb, vdb); - rhs[2] = 0.5 * dot(vdc, vdc); - lu_solve(A, 3, indx, rhs, 0); - // Get the circumcenter. - // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i]; - // Get the square of the circumradius. - radius2 = dot(rhs, rhs); - - // Compute the 4 face normals (N[0], ..., N[3]). - for (j = 0; j < 3; j++) { - for (i = 0; i < 3; i++) rhs[i] = 0.0; - rhs[j] = 1.0; // Positive means the inside direction - lu_solve(A, 3, indx, rhs, 0); - for (i = 0; i < 3; i++) N[j][i] = rhs[i]; - } - // Get the fourth normal by summing up the first three. - for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i]; - // Normalized the normals. - for (i = 0; i < 4; i++) { - // H[i] is the inverse of the height of its corresponding face. - H[i] = sqrt(dot(N[i], N[i])); - // if (H[i] > 0.0) { - // for (j = 0; j < 3; j++) N[i][j] /= H[i]; - // } - } - // Get the radius of the inscribed sphere. - // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]); - // Get the biggest H[i] (corresponding to the smallest height). - minheightinv = H[0]; - for (i = 1; i < 4; i++) { - if (H[i] > minheightinv) minheightinv = H[i]; - } - - return sqrt(radius2) * minheightinv; -} - -bool meshGRegionBoundaryRecovery::circumsphere(REAL* pa, REAL* pb, REAL* pc, - REAL* pd, REAL* cent, REAL* radius) -{ - REAL A[4][4], rhs[4], D; - int indx[4]; - - // Compute the coefficient matrix A (3x3). - A[0][0] = pb[0] - pa[0]; - A[0][1] = pb[1] - pa[1]; - A[0][2] = pb[2] - pa[2]; - A[1][0] = pc[0] - pa[0]; - A[1][1] = pc[1] - pa[1]; - A[1][2] = pc[2] - pa[2]; - if (pd != NULL) { - A[2][0] = pd[0] - pa[0]; - A[2][1] = pd[1] - pa[1]; - A[2][2] = pd[2] - pa[2]; - } else { - cross(A[0], A[1], A[2]); - } - - // Compute the right hand side vector b (3x1). - rhs[0] = 0.5 * dot(A[0], A[0]); - rhs[1] = 0.5 * dot(A[1], A[1]); - if (pd != NULL) { - rhs[2] = 0.5 * dot(A[2], A[2]); - } else { - rhs[2] = 0.0; - } - - // Solve the 3 by 3 equations use LU decomposition with partial pivoting - // and backward and forward substitute.. - if (!lu_decmp(A, 3, indx, &D, 0)) { - if (radius != (REAL *) NULL) *radius = 0.0; - return false; - } - lu_solve(A, 3, indx, rhs, 0); - if (cent != (REAL *) NULL) { - cent[0] = pa[0] + rhs[0]; - cent[1] = pa[1] + rhs[1]; - cent[2] = pa[2] + rhs[2]; - } - if (radius != (REAL *) NULL) { - *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]); - } - return true; -} - -void meshGRegionBoundaryRecovery::planelineint(REAL* pa, REAL* pb, REAL* pc, - REAL* e1, REAL* e2, REAL* ip, REAL* u) -{ - REAL n[3], det, det1; - - // Calculate N. - facenormal(pa, pb, pc, n, 1, NULL); - // Calculate N dot (e2 - e1). - det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1]) - + n[2] * (e2[2] - e1[2]); - if (det != 0.0) { - // Calculate N dot (pa - e1) - det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1]) - + n[2] * (pa[2] - e1[2]); - *u = det1 / det; - ip[0] = e1[0] + *u * (e2[0] - e1[0]); - ip[1] = e1[1] + *u * (e2[1] - e1[1]); - ip[2] = e1[2] + *u * (e2[2] - e1[2]); - } else { - *u = 0.0; - } -} - -int meshGRegionBoundaryRecovery::linelineint(REAL* A, REAL* B, REAL* C, - REAL* D, REAL* P, REAL* Q, REAL* tp, REAL* tq) -{ - REAL vab[3], vcd[3], vca[3]; - REAL vab_vab, vcd_vcd, vab_vcd; - REAL vca_vab, vca_vcd; - REAL det, eps; - int i; - - for (i = 0; i < 3; i++) { - vab[i] = B[i] - A[i]; - vcd[i] = D[i] - C[i]; - vca[i] = A[i] - C[i]; - } - - vab_vab = dot(vab, vab); - vcd_vcd = dot(vcd, vcd); - vab_vcd = dot(vab, vcd); - - det = vab_vab * vcd_vcd - vab_vcd * vab_vcd; - // Round the result. - eps = det / (fabs(vab_vab * vcd_vcd) + fabs(vab_vcd * vab_vcd)); - if (eps < b->epsilon) { - return 0; - } - - vca_vab = dot(vca, vab); - vca_vcd = dot(vca, vcd); - - *tp = (vcd_vcd * (- vca_vab) + vab_vcd * vca_vcd) / det; - *tq = (vab_vcd * (- vca_vab) + vab_vab * vca_vcd) / det; - - for (i = 0; i < 3; i++) P[i] = A[i] + (*tp) * vab[i]; - for (i = 0; i < 3; i++) Q[i] = C[i] + (*tq) * vcd[i]; - - return 1; -} - -REAL meshGRegionBoundaryRecovery::tetprismvol(REAL* p0, REAL* p1, REAL* p2, - REAL* p3) -{ - REAL *p4, *p5, *p6, *p7; - REAL w4, w5, w6, w7; - REAL vol[4]; - - p4 = p0; - p5 = p1; - p6 = p2; - p7 = p3; - - // TO DO: these weights can be pre-calculated! - w4 = dot(p0, p0); - w5 = dot(p1, p1); - w6 = dot(p2, p2); - w7 = dot(p3, p3); - - // Calculate the volume of the tet-prism. - vol[0] = orient4dfast(p5, p6, p4, p3, p7, w5, w6, w4, 0, w7); - vol[1] = orient4dfast(p3, p6, p2, p0, p1, 0, w6, 0, 0, 0); - vol[2] = orient4dfast(p4, p6, p3, p0, p1, w4, w6, 0, 0, 0); - vol[3] = orient4dfast(p6, p5, p4, p3, p1, w6, w5, w4, 0, 0); - - return fabs(vol[0]) + fabs(vol[1]) + fabs(vol[2]) + fabs(vol[3]); -} - -void meshGRegionBoundaryRecovery::calculateabovepoint4(point pa, point pb, - point pc, point pd) -{ - REAL n1[3], n2[3], *norm; - REAL len, len1, len2; - - // Select a base. - facenormal(pa, pb, pc, n1, 1, NULL); - len1 = sqrt(dot(n1, n1)); - facenormal(pa, pb, pd, n2, 1, NULL); - len2 = sqrt(dot(n2, n2)); - if (len1 > len2) { - norm = n1; - len = len1; - } else { - norm = n2; - len = len2; - } - assert(len > 0); - norm[0] /= len; - norm[1] /= len; - norm[2] /= len; - len = distance(pa, pb); - dummypoint[0] = pa[0] + len * norm[0]; - dummypoint[1] = pa[1] + len * norm[1]; - dummypoint[2] = pa[2] + len * norm[2]; -} - -//// //// -//// //// -//// geom_cxx ///////////////////////////////////////////////////////////////// - -//// flip_cxx ///////////////////////////////////////////////////////////////// -//// //// -//// //// - -void meshGRegionBoundaryRecovery::flip23(triface* fliptets, int hullflag, flipconstraints *fc) -{ - triface topcastets[3], botcastets[3]; - triface newface, casface; - point pa, pb, pc, pd, pe; - REAL attrib, volume; - int dummyflag = 0; // range = {-1, 0, 1, 2}. - int i; - - if (hullflag > 0) { - // Check if e is dummypoint. - if (oppo(fliptets[1]) == dummypoint) { - // Swap the two old tets. - newface = fliptets[0]; - fliptets[0] = fliptets[1]; - fliptets[1] = newface; - dummyflag = -1; // d is dummypoint. - } else { - // Check if either a or b is dummypoint. - if (org(fliptets[0]) == dummypoint) { - dummyflag = 1; // a is dummypoint. - enextself(fliptets[0]); - eprevself(fliptets[1]); - } else if (dest(fliptets[0]) == dummypoint) { - dummyflag = 2; // b is dummypoint. - eprevself(fliptets[0]); - enextself(fliptets[1]); - } else { - dummyflag = 0; // either c or d may be dummypoint. - } - } - } - - pa = org(fliptets[0]); - pb = dest(fliptets[0]); - pc = apex(fliptets[0]); - pd = oppo(fliptets[0]); - pe = oppo(fliptets[1]); - - flip23count++; - - // Get the outer boundary faces. - for (i = 0; i < 3; i++) { - fnext(fliptets[0], topcastets[i]); - enextself(fliptets[0]); - } - for (i = 0; i < 3; i++) { - fnext(fliptets[1], botcastets[i]); - eprevself(fliptets[1]); - } - - // Re-use fliptets[0] and fliptets[1]. - fliptets[0].ver = 11; - fliptets[1].ver = 11; - setelemmarker(fliptets[0].tet, 0); // Clear all flags. - setelemmarker(fliptets[1].tet, 0); - // NOTE: the element attributes and volume constraint remain unchanged. - if (checksubsegflag) { - // Dealloc the space to subsegments. - if (fliptets[0].tet[8] != NULL) { - tet2segpool->dealloc((shellface *) fliptets[0].tet[8]); - fliptets[0].tet[8] = NULL; - } - if (fliptets[1].tet[8] != NULL) { - tet2segpool->dealloc((shellface *) fliptets[1].tet[8]); - fliptets[1].tet[8] = NULL; - } - } - if (checksubfaceflag) { - // Dealloc the space to subfaces. - if (fliptets[0].tet[9] != NULL) { - tet2subpool->dealloc((shellface *) fliptets[0].tet[9]); - fliptets[0].tet[9] = NULL; - } - if (fliptets[1].tet[9] != NULL) { - tet2subpool->dealloc((shellface *) fliptets[1].tet[9]); - fliptets[1].tet[9] = NULL; - } - } - // Create a new tet. - maketetrahedron(&(fliptets[2])); - // The new tet have the same attributes from the old tet. - for (i = 0; i < numelemattrib; i++) { - attrib = elemattribute(fliptets[0].tet, i); - setelemattribute(fliptets[2].tet, i, attrib); - } - if (b->varvolume) { - volume = volumebound(fliptets[0].tet); - setvolumebound(fliptets[2].tet, volume); - } - - if (hullflag > 0) { - // Check if d is dummytet. - if (pd != dummypoint) { - setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] * - setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] * - // Check if c is dummypoint. - if (pc != dummypoint) { - setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] * - } else { - setvertices(fliptets[2], pd, pe, pa, pc); // [d,e,a,c] - esymself(fliptets[2]); // [e,d,c,a] * - } - // The hullsize does not change. - } else { - // d is dummypoint. - setvertices(fliptets[0], pa, pb, pe, pd); // [a,b,e,d] - setvertices(fliptets[1], pb, pc, pe, pd); // [b,c,e,d] - setvertices(fliptets[2], pc, pa, pe, pd); // [c,a,e,d] - // Adjust the faces to [e,d,a,b], [e,d,b,c], [e,d,c,a] * - for (i = 0; i < 3; i++) { - eprevesymself(fliptets[i]); - enextself(fliptets[i]); - } - // We deleted one hull tet, and created three hull tets. - hullsize += 2; - } - } else { - setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] * - setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] * - setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] * - } - - if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol - REAL volneg[2], volpos[3], vol_diff; - if (pd != dummypoint) { - if (pc != dummypoint) { - volpos[0] = tetprismvol(pe, pd, pa, pb); - volpos[1] = tetprismvol(pe, pd, pb, pc); - volpos[2] = tetprismvol(pe, pd, pc, pa); - volneg[0] = tetprismvol(pa, pb, pc, pd); - volneg[1] = tetprismvol(pb, pa, pc, pe); - } else { // pc == dummypoint - volpos[0] = tetprismvol(pe, pd, pa, pb); - volpos[1] = 0.; - volpos[2] = 0.; - volneg[0] = 0.; - volneg[1] = 0.; - } - } else { // pd == dummypoint. - volpos[0] = 0.; - volpos[1] = 0.; - volpos[2] = 0.; - volneg[0] = 0.; - volneg[1] = tetprismvol(pb, pa, pc, pe); - } - vol_diff = volpos[0] + volpos[1] + volpos[2] - volneg[0] - volneg[1]; - fc->tetprism_vol_sum += vol_diff; // Update the total sum. - } - - // Bond three new tets together. - for (i = 0; i < 3; i++) { - esym(fliptets[i], newface); - bond(newface, fliptets[(i + 1) % 3]); - } - // Bond to top outer boundary faces (at [a,b,c,d]). - for (i = 0; i < 3; i++) { - eorgoppo(fliptets[i], newface); // At edges [b,a], [c,b], [a,c]. - bond(newface, topcastets[i]); - } - // Bond bottom outer boundary faces (at [b,a,c,e]). - for (i = 0; i < 3; i++) { - edestoppo(fliptets[i], newface); // At edges [a,b], [b,c], [c,a]. - bond(newface, botcastets[i]); - } - - if (checksubsegflag) { - // Bond subsegments if there are. - // Each new tet has 5 edges to be checked (except the edge [e,d]). - face checkseg; - // The middle three: [a,b], [b,c], [c,a]. - for (i = 0; i < 3; i++) { - if (issubseg(topcastets[i])) { - tsspivot1(topcastets[i], checkseg); - eorgoppo(fliptets[i], newface); - tssbond1(newface, checkseg); - sstbond1(checkseg, newface); - if (fc->chkencflag & 1) { - //enqueuesubface(badsubsegs, &checkseg); - } - } - } - // The top three: [d,a], [d,b], [d,c]. Two tets per edge. - for (i = 0; i < 3; i++) { - eprev(topcastets[i], casface); - if (issubseg(casface)) { - tsspivot1(casface, checkseg); - enext(fliptets[i], newface); - tssbond1(newface, checkseg); - sstbond1(checkseg, newface); - esym(fliptets[(i + 2) % 3], newface); - eprevself(newface); - tssbond1(newface, checkseg); - sstbond1(checkseg, newface); - if (fc->chkencflag & 1) { - //enqueuesubface(badsubsegs, &checkseg); - } - } - } - // The bot three: [a,e], [b,e], [c,e]. Two tets per edge. - for (i = 0; i < 3; i++) { - enext(botcastets[i], casface); - if (issubseg(casface)) { - tsspivot1(casface, checkseg); - eprev(fliptets[i], newface); - tssbond1(newface, checkseg); - sstbond1(checkseg, newface); - esym(fliptets[(i + 2) % 3], newface); - enextself(newface); - tssbond1(newface, checkseg); - sstbond1(checkseg, newface); - if (fc->chkencflag & 1) { - //enqueuesubface(badsubsegs, &checkseg); - } - } - } - } // if (checksubsegflag) - - if (checksubfaceflag) { - // Bond 6 subfaces if there are. - face checksh; - for (i = 0; i < 3; i++) { - if (issubface(topcastets[i])) { - tspivot(topcastets[i], checksh); - eorgoppo(fliptets[i], newface); - sesymself(checksh); - tsbond(newface, checksh); - if (fc->chkencflag & 2) { - //enqueuesubface(badsubfacs, &checksh); - } - } - } - for (i = 0; i < 3; i++) { - if (issubface(botcastets[i])) { - tspivot(botcastets[i], checksh); - edestoppo(fliptets[i], newface); - sesymself(checksh); - tsbond(newface, checksh); - if (fc->chkencflag & 2) { - //enqueuesubface(badsubfacs, &checksh); - } - } - } - } // if (checksubfaceflag) - - if (fc->chkencflag & 4) { - // Put three new tets into check list. - for (i = 0; i < 3; i++) { - //enqueuetetrahedron(&(fliptets[i])); - } - } - - // Update the point-to-tet map. - setpoint2tet(pa, (tetrahedron) fliptets[0].tet); - setpoint2tet(pb, (tetrahedron) fliptets[0].tet); - setpoint2tet(pc, (tetrahedron) fliptets[1].tet); - setpoint2tet(pd, (tetrahedron) fliptets[0].tet); - setpoint2tet(pe, (tetrahedron) fliptets[0].tet); - - if (hullflag > 0) { - if (dummyflag != 0) { - // Restore the original position of the points (for flipnm()). - if (dummyflag == -1) { - // Reverse the edge. - for (i = 0; i < 3; i++) { - esymself(fliptets[i]); - } - // Swap the last two new tets. - newface = fliptets[1]; - fliptets[1] = fliptets[2]; - fliptets[2] = newface; - } else { - // either a or b were swapped. - if (dummyflag == 1) { - // a is dummypoint. - newface = fliptets[0]; - fliptets[0] = fliptets[2]; - fliptets[2] = fliptets[1]; - fliptets[1] = newface; - } else { // dummyflag == 2 - // b is dummypoint. - newface = fliptets[0]; - fliptets[0] = fliptets[1]; - fliptets[1] = fliptets[2]; - fliptets[2] = newface; - } - } - } - } - - if (fc->enqflag > 0) { - // Queue faces which may be locally non-Delaunay. - for (i = 0; i < 3; i++) { - eprevesym(fliptets[i], newface); - flippush(flipstack, &newface); - } - if (fc->enqflag > 1) { - for (i = 0; i < 3; i++) { - enextesym(fliptets[i], newface); - flippush(flipstack, &newface); - } - } - } - - recenttet = fliptets[0]; -} - -void meshGRegionBoundaryRecovery::flip32(triface* fliptets, int hullflag, flipconstraints *fc) -{ - triface topcastets[3], botcastets[3]; - triface newface, casface; - face flipshs[3]; - face checkseg; - point pa, pb, pc, pd, pe; - REAL attrib, volume; - int dummyflag = 0; // Rangle = {-1, 0, 1, 2} - int spivot = -1, scount = 0; // for flip22() - int t1ver; - int i, j; - - if (hullflag > 0) { - // Check if e is 'dummypoint'. - if (org(fliptets[0]) == dummypoint) { - // Reverse the edge. - for (i = 0; i < 3; i++) { - esymself(fliptets[i]); - } - // Swap the last two tets. - newface = fliptets[1]; - fliptets[1] = fliptets[2]; - fliptets[2] = newface; - dummyflag = -1; // e is dummypoint. - } else { - // Check if a or b is the 'dummypoint'. - if (apex(fliptets[0]) == dummypoint) { - dummyflag = 1; // a is dummypoint. - newface = fliptets[0]; - fliptets[0] = fliptets[1]; - fliptets[1] = fliptets[2]; - fliptets[2] = newface; - } else if (apex(fliptets[1]) == dummypoint) { - dummyflag = 2; // b is dummypoint. - newface = fliptets[0]; - fliptets[0] = fliptets[2]; - fliptets[2] = fliptets[1]; - fliptets[1] = newface; - } else { - dummyflag = 0; // either c or d may be dummypoint. - } - } - } - - pa = apex(fliptets[0]); - pb = apex(fliptets[1]); - pc = apex(fliptets[2]); - pd = dest(fliptets[0]); - pe = org(fliptets[0]); - - flip32count++; - - // Get the outer boundary faces. - for (i = 0; i < 3; i++) { - eorgoppo(fliptets[i], casface); - fsym(casface, topcastets[i]); - } - for (i = 0; i < 3; i++) { - edestoppo(fliptets[i], casface); - fsym(casface, botcastets[i]); - } - - if (checksubfaceflag) { - // Check if there are interior subfaces at the edge [e,d]. - for (i = 0; i < 3; i++) { - tspivot(fliptets[i], flipshs[i]); - if (flipshs[i].sh != NULL) { - // Found an interior subface. - stdissolve(flipshs[i]); // Disconnect the sub-tet bond. - scount++; - } else { - spivot = i; - } - } - } - - // Re-use fliptets[0] and fliptets[1]. - fliptets[0].ver = 11; - fliptets[1].ver = 11; - setelemmarker(fliptets[0].tet, 0); // Clear all flags. - setelemmarker(fliptets[1].tet, 0); - if (checksubsegflag) { - // Dealloc the space to subsegments. - if (fliptets[0].tet[8] != NULL) { - tet2segpool->dealloc((shellface *) fliptets[0].tet[8]); - fliptets[0].tet[8] = NULL; - } - if (fliptets[1].tet[8] != NULL) { - tet2segpool->dealloc((shellface *) fliptets[1].tet[8]); - fliptets[1].tet[8] = NULL; - } - } - if (checksubfaceflag) { - // Dealloc the space to subfaces. - if (fliptets[0].tet[9] != NULL) { - tet2subpool->dealloc((shellface *) fliptets[0].tet[9]); - fliptets[0].tet[9] = NULL; - } - if (fliptets[1].tet[9] != NULL) { - tet2subpool->dealloc((shellface *) fliptets[1].tet[9]); - fliptets[1].tet[9] = NULL; - } - } - if (checksubfaceflag) { - if (scount > 0) { - // The element attributes and volume constraint must be set correctly. - // There are two subfaces involved in this flip. The three tets are - // separated into two different regions, one may be exterior. The - // first region has two tets, and the second region has only one. - // The two created tets must be in the same region as the first region. - // The element attributes and volume constraint must be set correctly. - //assert(spivot != -1); - // The tet fliptets[spivot] is in the first region. - for (j = 0; j < 2; j++) { - for (i = 0; i < numelemattrib; i++) { - attrib = elemattribute(fliptets[spivot].tet, i); - setelemattribute(fliptets[j].tet, i, attrib); - } - if (b->varvolume) { - volume = volumebound(fliptets[spivot].tet); - setvolumebound(fliptets[j].tet, volume); - } - } - } - } - // Delete an old tet. - tetrahedrondealloc(fliptets[2].tet); - - if (hullflag > 0) { - // Check if c is dummypointc. - if (pc != dummypoint) { - // Check if d is dummypoint. - if (pd != dummypoint) { - // No hull tet is involved. - } else { - // We deleted three hull tets, and created one hull tet. - hullsize -= 2; - } - setvertices(fliptets[0], pa, pb, pc, pd); - setvertices(fliptets[1], pb, pa, pc, pe); - } else { - // c is dummypoint. The two new tets are hull tets. - setvertices(fliptets[0], pb, pa, pd, pc); - setvertices(fliptets[1], pa, pb, pe, pc); - // Adjust badc -> abcd. - esymself(fliptets[0]); - // Adjust abec -> bace. - esymself(fliptets[1]); - // The hullsize does not change. - } - } else { - setvertices(fliptets[0], pa, pb, pc, pd); - setvertices(fliptets[1], pb, pa, pc, pe); - } - - if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol - REAL volneg[3], volpos[2], vol_diff; - if (pc != dummypoint) { - if (pd != dummypoint) { - volneg[0] = tetprismvol(pe, pd, pa, pb); - volneg[1] = tetprismvol(pe, pd, pb, pc); - volneg[2] = tetprismvol(pe, pd, pc, pa); - volpos[0] = tetprismvol(pa, pb, pc, pd); - volpos[1] = tetprismvol(pb, pa, pc, pe); - } else { // pd == dummypoint - volneg[0] = 0.; - volneg[1] = 0.; - volneg[2] = 0.; - volpos[0] = 0.; - volpos[1] = tetprismvol(pb, pa, pc, pe); - } - } else { // pc == dummypoint. - volneg[0] = tetprismvol(pe, pd, pa, pb); - volneg[1] = 0.; - volneg[2] = 0.; - volpos[0] = 0.; - volpos[1] = 0.; - } - vol_diff = volpos[0] + volpos[1] - volneg[0] - volneg[1] - volneg[2]; - fc->tetprism_vol_sum += vol_diff; // Update the total sum. - } - - // Bond abcd <==> bace. - bond(fliptets[0], fliptets[1]); - // Bond new faces to top outer boundary faces (at abcd). - for (i = 0; i < 3; i++) { - esym(fliptets[0], newface); - bond(newface, topcastets[i]); - enextself(fliptets[0]); - } - // Bond new faces to bottom outer boundary faces (at bace). - for (i = 0; i < 3; i++) { - esym(fliptets[1], newface); - bond(newface, botcastets[i]); - eprevself(fliptets[1]); - } - - if (checksubsegflag) { - // Bond 9 segments to new (flipped) tets. - for (i = 0; i < 3; i++) { // edges a->b, b->c, c->a. - if (issubseg(topcastets[i])) { - tsspivot1(topcastets[i], checkseg); - tssbond1(fliptets[0], checkseg); - sstbond1(checkseg, fliptets[0]); - tssbond1(fliptets[1], checkseg); - sstbond1(checkseg, fliptets[1]); - if (fc->chkencflag & 1) { - //enqueuesubface(badsubsegs, &checkseg); - } - } - enextself(fliptets[0]); - eprevself(fliptets[1]); - } - // The three top edges. - for (i = 0; i < 3; i++) { // edges b->d, c->d, a->d. - esym(fliptets[0], newface); - eprevself(newface); - enext(topcastets[i], casface); - if (issubseg(casface)) { - tsspivot1(casface, checkseg); - tssbond1(newface, checkseg); - sstbond1(checkseg, newface); - if (fc->chkencflag & 1) { - //enqueuesubface(badsubsegs, &checkseg); - } - } - enextself(fliptets[0]); - } - // The three bot edges. - for (i = 0; i < 3; i++) { // edges b<-e, c<-e, a<-e. - esym(fliptets[1], newface); - enextself(newface); - eprev(botcastets[i], casface); - if (issubseg(casface)) { - tsspivot1(casface, checkseg); - tssbond1(newface, checkseg); - sstbond1(checkseg, newface); - if (fc->chkencflag & 1) { - //enqueuesubface(badsubsegs, &checkseg); - } - } - eprevself(fliptets[1]); - } - } // if (checksubsegflag) - - if (checksubfaceflag) { - face checksh; - // Bond the top three casing subfaces. - for (i = 0; i < 3; i++) { // At edges [b,a], [c,b], [a,c] - if (issubface(topcastets[i])) { - tspivot(topcastets[i], checksh); - esym(fliptets[0], newface); - sesymself(checksh); - tsbond(newface, checksh); - if (fc->chkencflag & 2) { - //enqueuesubface(badsubfacs, &checksh); - } - } - enextself(fliptets[0]); - } - // Bond the bottom three casing subfaces. - for (i = 0; i < 3; i++) { // At edges [a,b], [b,c], [c,a] - if (issubface(botcastets[i])) { - tspivot(botcastets[i], checksh); - esym(fliptets[1], newface); - sesymself(checksh); - tsbond(newface, checksh); - if (fc->chkencflag & 2) { - //enqueuesubface(badsubfacs, &checksh); - } - } - eprevself(fliptets[1]); - } - - if (scount > 0) { - face flipfaces[2]; - // Perform a 2-to-2 flip in subfaces. - flipfaces[0] = flipshs[(spivot + 1) % 3]; - flipfaces[1] = flipshs[(spivot + 2) % 3]; - sesymself(flipfaces[1]); - flip22(flipfaces, 0, fc->chkencflag); - // Connect the flipped subfaces to flipped tets. - // First go to the corresponding flipping edge. - // Re-use top- and botcastets[0]. - topcastets[0] = fliptets[0]; - botcastets[0] = fliptets[1]; - for (i = 0; i < ((spivot + 1) % 3); i++) { - enextself(topcastets[0]); - eprevself(botcastets[0]); - } - // Connect the top subface to the top tets. - esymself(topcastets[0]); - sesymself(flipfaces[0]); - // Check if there already exists a subface. - tspivot(topcastets[0], checksh); - if (checksh.sh == NULL) { - tsbond(topcastets[0], flipfaces[0]); - fsymself(topcastets[0]); - sesymself(flipfaces[0]); - tsbond(topcastets[0], flipfaces[0]); - } else { - // An invalid 2-to-2 flip. Report a bug. - terminateBoundaryRecovery(this, 2); - } - // Connect the bot subface to the bottom tets. - esymself(botcastets[0]); - sesymself(flipfaces[1]); - // Check if there already exists a subface. - tspivot(botcastets[0], checksh); - if (checksh.sh == NULL) { - tsbond(botcastets[0], flipfaces[1]); - fsymself(botcastets[0]); - sesymself(flipfaces[1]); - tsbond(botcastets[0], flipfaces[1]); - } else { - // An invalid 2-to-2 flip. Report a bug. - terminateBoundaryRecovery(this, 2); - } - } // if (scount > 0) - } // if (checksubfaceflag) - - if (fc->chkencflag & 4) { - // Put two new tets into check list. - for (i = 0; i < 2; i++) { - //enqueuetetrahedron(&(fliptets[i])); - } - } - - setpoint2tet(pa, (tetrahedron) fliptets[0].tet); - setpoint2tet(pb, (tetrahedron) fliptets[0].tet); - setpoint2tet(pc, (tetrahedron) fliptets[0].tet); - setpoint2tet(pd, (tetrahedron) fliptets[0].tet); - setpoint2tet(pe, (tetrahedron) fliptets[1].tet); - - if (hullflag > 0) { - if (dummyflag != 0) { - // Restore the original position of the points (for flipnm()). - if (dummyflag == -1) { - // e were dummypoint. Swap the two new tets. - newface = fliptets[0]; - fliptets[0] = fliptets[1]; - fliptets[1] = newface; - } else { - // a or b was dummypoint. - if (dummyflag == 1) { - eprevself(fliptets[0]); - enextself(fliptets[1]); - } else { // dummyflag == 2 - enextself(fliptets[0]); - eprevself(fliptets[1]); - } - } - } - } - - if (fc->enqflag > 0) { - // Queue faces which may be locally non-Delaunay. - // pa = org(fliptets[0]); // 'a' may be a new vertex. - enextesym(fliptets[0], newface); - flippush(flipstack, &newface); - eprevesym(fliptets[1], newface); - flippush(flipstack, &newface); - if (fc->enqflag > 1) { - //pb = dest(fliptets[0]); - eprevesym(fliptets[0], newface); - flippush(flipstack, &newface); - enextesym(fliptets[1], newface); - flippush(flipstack, &newface); - //pc = apex(fliptets[0]); - esym(fliptets[0], newface); - flippush(flipstack, &newface); - esym(fliptets[1], newface); - flippush(flipstack, &newface); - } - } - - recenttet = fliptets[0]; -} - -void meshGRegionBoundaryRecovery::flip41(triface* fliptets, int hullflag, flipconstraints *fc) -{ - triface topcastets[3], botcastet; - triface newface, neightet; - face flipshs[4]; - point pa, pb, pc, pd, pp; - int dummyflag = 0; // in {0, 1, 2, 3, 4} - int spivot = -1, scount = 0; - int t1ver; - int i; - - pa = org(fliptets[3]); - pb = dest(fliptets[3]); - pc = apex(fliptets[3]); - pd = dest(fliptets[0]); - pp = org(fliptets[0]); // The removing vertex. - - flip41count++; - - // Get the outer boundary faces. - for (i = 0; i < 3; i++) { - enext(fliptets[i], topcastets[i]); - fnextself(topcastets[i]); // [d,a,b,#], [d,b,c,#], [d,c,a,#] - enextself(topcastets[i]); // [a,b,d,#], [b,c,d,#], [c,a,d,#] - } - fsym(fliptets[3], botcastet); // [b,a,c,#] - - if (checksubfaceflag) { - // Check if there are three subfaces at 'p'. - // Re-use 'newface'. - for (i = 0; i < 3; i++) { - fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d]. - tspivot(newface, flipshs[i]); - if (flipshs[i].sh != NULL) { - spivot = i; // Remember this subface. - scount++; - } - enextself(fliptets[3]); - } - if (scount > 0) { - // There are three subfaces connecting at p. - if (scount < 3) { - // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}. - assert(scount == 1); // spivot >= 0 - // Go to the tet containing the three subfaces. - fsym(topcastets[spivot], neightet); - // Get the three subfaces connecting at p. - for (i = 0; i < 3; i++) { - esym(neightet, newface); - tspivot(newface, flipshs[i]); - assert(flipshs[i].sh != NULL); - eprevself(neightet); - } - } else { - spivot = 3; // The new subface is [a,b,c]. - } - } - } // if (checksubfaceflag) - - - // Re-use fliptets[0] for [a,b,c,d]. - fliptets[0].ver = 11; - setelemmarker(fliptets[0].tet, 0); // Clean all flags. - // NOTE: the element attributes and volume constraint remain unchanged. - if (checksubsegflag) { - // Dealloc the space to subsegments. - if (fliptets[0].tet[8] != NULL) { - tet2segpool->dealloc((shellface *) fliptets[0].tet[8]); - fliptets[0].tet[8] = NULL; - } - } - if (checksubfaceflag) { - // Dealloc the space to subfaces. - if (fliptets[0].tet[9] != NULL) { - tet2subpool->dealloc((shellface *) fliptets[0].tet[9]); - fliptets[0].tet[9] = NULL; - } - } - // Delete the other three tets. - for (i = 1; i < 4; i++) { - tetrahedrondealloc(fliptets[i].tet); - } - - if (pp != dummypoint) { - // Mark the point pp as unused. - setpointtype(pp, UNUSEDVERTEX); - unuverts++; - } - - // Create the new tet [a,b,c,d]. - if (hullflag > 0) { - // One of the five vertices may be 'dummypoint'. - if (pa == dummypoint) { - // pa is dummypoint. - setvertices(fliptets[0], pc, pb, pd, pa); - esymself(fliptets[0]); // [b,c,a,d] - eprevself(fliptets[0]); // [a,b,c,d] - dummyflag = 1; - } else if (pb == dummypoint) { - setvertices(fliptets[0], pa, pc, pd, pb); - esymself(fliptets[0]); // [c,a,b,d] - enextself(fliptets[0]); // [a,b,c,d] - dummyflag = 2; - } else if (pc == dummypoint) { - setvertices(fliptets[0], pb, pa, pd, pc); - esymself(fliptets[0]); // [a,b,c,d] - dummyflag = 3; - } else if (pd == dummypoint) { - setvertices(fliptets[0], pa, pb, pc, pd); - dummyflag = 4; - } else { - setvertices(fliptets[0], pa, pb, pc, pd); - if (pp == dummypoint) { - dummyflag = -1; - } else { - dummyflag = 0; - } - } - if (dummyflag > 0) { - // We deleted 3 hull tets, and create 1 hull tet. - hullsize -= 2; - } else if (dummyflag < 0) { - // We deleted 4 hull tets. - hullsize -= 4; - // meshedges does not change. - } - } else { - setvertices(fliptets[0], pa, pb, pc, pd); - } - - if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol - REAL volneg[4], volpos[1], vol_diff; - if (dummyflag > 0) { - if (pa == dummypoint) { - volneg[0] = 0.; - volneg[1] = tetprismvol(pp, pd, pb, pc); - volneg[2] = 0.; - volneg[3] = 0.; - } else if (pb == dummypoint) { - volneg[0] = 0.; - volneg[1] = 0.; - volneg[2] = tetprismvol(pp, pd, pc, pa); - volneg[3] = 0.; - } else if (pc == dummypoint) { - volneg[0] = tetprismvol(pp, pd, pa, pb); - volneg[1] = 0.; - volneg[2] = 0.; - volneg[3] = 0.; - } else { // pd == dummypoint - volneg[0] = 0.; - volneg[1] = 0.; - volneg[2] = 0.; - volneg[3] = tetprismvol(pa, pb, pc, pp); - } - volpos[0] = 0.; - } else if (dummyflag < 0) { - volneg[0] = 0.; - volneg[1] = 0.; - volneg[2] = 0.; - volneg[3] = 0.; - volpos[0] = tetprismvol(pa, pb, pc, pd); - } else { - volneg[0] = tetprismvol(pp, pd, pa, pb); - volneg[1] = tetprismvol(pp, pd, pb, pc); - volneg[2] = tetprismvol(pp, pd, pc, pa); - volneg[3] = tetprismvol(pa, pb, pc, pp); - volpos[0] = tetprismvol(pa, pb, pc, pd); - } - vol_diff = volpos[0] - volneg[0] - volneg[1] - volneg[2] - volneg[3]; - fc->tetprism_vol_sum += vol_diff; // Update the total sum. - } - - // Bond the new tet to adjacent tets. - for (i = 0; i < 3; i++) { - esym(fliptets[0], newface); // At faces [b,a,d], [c,b,d], [a,c,d]. - bond(newface, topcastets[i]); - enextself(fliptets[0]); - } - bond(fliptets[0], botcastet); - - if (checksubsegflag) { - face checkseg; - // Bond 6 segments (at edges of [a,b,c,d]) if there there are. - for (i = 0; i < 3; i++) { - eprev(topcastets[i], newface); // At edges [d,a],[d,b],[d,c]. - if (issubseg(newface)) { - tsspivot1(newface, checkseg); - esym(fliptets[0], newface); - enextself(newface); // At edges [a,d], [b,d], [c,d]. - tssbond1(newface, checkseg); - sstbond1(checkseg, newface); - if (fc->chkencflag & 1) { - //enqueuesubface(badsubsegs, &checkseg); - } - } - enextself(fliptets[0]); - } - for (i = 0; i < 3; i++) { - if (issubseg(topcastets[i])) { - tsspivot1(topcastets[i], checkseg); // At edges [a,b],[b,c],[c,a]. - tssbond1(fliptets[0], checkseg); - sstbond1(checkseg, fliptets[0]); - if (fc->chkencflag & 1) { - //enqueuesubface(badsubsegs, &checkseg); - } - } - enextself(fliptets[0]); - } - } - - if (checksubfaceflag) { - face checksh; - // Bond 4 subfaces (at faces of [a,b,c,d]) if there are. - for (i = 0; i < 3; i++) { - if (issubface(topcastets[i])) { - tspivot(topcastets[i], checksh); // At faces [a,b,d],[b,c,d],[c,a,d] - esym(fliptets[0], newface); // At faces [b,a,d],[c,b,d],[a,c,d] - sesymself(checksh); - tsbond(newface, checksh); - if (fc->chkencflag & 2) { - //enqueuesubface(badsubfacs, &checksh); - } - } - enextself(fliptets[0]); - } - if (issubface(botcastet)) { - tspivot(botcastet, checksh); // At face [b,a,c] - sesymself(checksh); - tsbond(fliptets[0], checksh); - if (fc->chkencflag & 2) { - //enqueuesubface(badsubfacs, &checksh); - } - } - - if (spivot >= 0) { - // Perform a 3-to-1 flip in surface triangulation. - // Depending on the value of 'spivot', the three subfaces are: - // - 0: [a,b,p], [b,d,p], [d,a,p] - // - 1: [b,c,p], [c,d,p], [d,b,p] - // - 2: [c,a,p], [a,d,p], [d,c,p] - // - 3: [a,b,p], [b,c,p], [c,a,p] - // Adjust the three subfaces such that their origins are p, i.e., - // - 3: [p,a,b], [p,b,c], [p,c,a]. (Required by the flip31()). - for (i = 0; i < 3; i++) { - senext2self(flipshs[i]); - } - flip31(flipshs, 0); - // Delete the three old subfaces. - for (i = 0; i < 3; i++) { - shellfacedealloc(subfaces, flipshs[i].sh); - } - if (spivot < 3) { - // // Bond the new subface to the new tet [a,b,c,d]. - tsbond(topcastets[spivot], flipshs[3]); - fsym(topcastets[spivot], newface); - sesym(flipshs[3], checksh); - tsbond(newface, checksh); - } else { - // Bound the new subface [a,b,c] to the new tet [a,b,c,d]. - tsbond(fliptets[0], flipshs[3]); - fsym(fliptets[0], newface); - sesym(flipshs[3], checksh); - tsbond(newface, checksh); - } - } // if (spivot > 0) - } // if (checksubfaceflag) - - if (fc->chkencflag & 4) { - //enqueuetetrahedron(&(fliptets[0])); - } - - // Update the point-to-tet map. - setpoint2tet(pa, (tetrahedron) fliptets[0].tet); - setpoint2tet(pb, (tetrahedron) fliptets[0].tet); - setpoint2tet(pc, (tetrahedron) fliptets[0].tet); - setpoint2tet(pd, (tetrahedron) fliptets[0].tet); - - if (fc->enqflag > 0) { - // Queue faces which may be locally non-Delaunay. - flippush(flipstack, &(fliptets[0])); // [a,b,c] (opposite to new point). - if (fc->enqflag > 1) { - for (i = 0; i < 3; i++) { - esym(fliptets[0], newface); - flippush(flipstack, &newface); - enextself(fliptets[0]); - } - } - } - - recenttet = fliptets[0]; -} - -int meshGRegionBoundaryRecovery::flipnm(triface* abtets, int n, int level, int abedgepivot, - flipconstraints* fc) -{ - triface fliptets[3], spintet, flipedge; - triface *tmpabtets, *parytet; - point pa, pb, pc, pd, pe, pf; - REAL ori; - int hullflag, hulledgeflag; - int reducflag, rejflag; - int reflexlinkedgecount; - int edgepivot; - int n1, nn; - int t1ver; - int i, j; - - pa = org(abtets[0]); - pb = dest(abtets[0]); - - if (n > 3) { - // Try to reduce the size of the Star(ab) by flipping a face in it. - reflexlinkedgecount = 0; - - for (i = 0; i < n; i++) { - // Let the face of 'abtets[i]' be [a,b,c]. - if (checksubfaceflag) { - if (issubface(abtets[i])) { - continue; // Skip a subface. - } - } - // Do not flip this face if it is involved in two Stars. - if ((elemcounter(abtets[i]) > 1) || - (elemcounter(abtets[(i - 1 + n) % n]) > 1)) { - continue; - } - - pc = apex(abtets[i]); - pd = apex(abtets[(i + 1) % n]); - pe = apex(abtets[(i - 1 + n) % n]); - if ((pd == dummypoint) || (pe == dummypoint)) { - continue; // [a,b,c] is a hull face. - } - - - // Decide whether [a,b,c] is flippable or not. - reducflag = 0; - - hullflag = (pc == dummypoint); // pc may be dummypoint. - hulledgeflag = 0; - if (hullflag == 0) { - ori = orient3d(pb, pc, pd, pe); // Is [b,c] locally convex? - if (ori > 0) { - ori = orient3d(pc, pa, pd, pe); // Is [c,a] locally convex? - if (ori > 0) { - // Test if [a,b] is locally convex OR flat. - ori = orient3d(pa, pb, pd, pe); - if (ori > 0) { - // Found a 2-to-3 flip: [a,b,c] => [e,d] - reducflag = 1; - } else if (ori == 0) { - // [a,b] is flat. - if (n == 4) { - // The "flat" tet can be removed immediately by a 3-to-2 flip. - reducflag = 1; - // Check if [e,d] is a hull edge. - pf = apex(abtets[(i + 2) % n]); - hulledgeflag = (pf == dummypoint); - } - } - } - } - if (!reducflag) { - reflexlinkedgecount++; - } - } else { - // 'c' is dummypoint. - if (n == 4) { - // Let the vertex opposite to 'c' is 'f'. - // A 4-to-4 flip is possible if the two tets [d,e,f,a] and [e,d,f,b] - // are valid tets. - // Note: When the mesh is not convex, it is possible that [a,b] is - // locally non-convex (at hull faces [a,b,e] and [b,a,d]). - // In this case, an edge flip [a,b] to [e,d] is still possible. - pf = apex(abtets[(i + 2) % n]); - assert(pf != dummypoint); - ori = orient3d(pd, pe, pf, pa); - if (ori < 0) { - ori = orient3d(pe, pd, pf, pb); - if (ori < 0) { - // Found a 4-to-4 flip: [a,b] => [e,d] - reducflag = 1; - ori = 0; // Signal as a 4-to-4 flip (like a co-planar case). - hulledgeflag = 1; // [e,d] is a hull edge. - } - } - } - } // if (hullflag) - - if (reducflag) { - if (nonconvex && hulledgeflag) { - // We will create a hull edge [e,d]. Make sure it does not exist. - if (getedge(pe, pd, &spintet)) { - // The 2-to-3 flip is not a topological valid flip. - reducflag = 0; - } - } - } - - if (reducflag) { - // [a,b,c] could be removed by a 2-to-3 flip. - rejflag = 0; - if (fc->checkflipeligibility) { - // Check if the flip can be performed. - rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, level, - abedgepivot, fc); - } - if (!rejflag) { - // Do flip: [a,b,c] => [e,d]. - fliptets[0] = abtets[i]; - fsym(fliptets[0], fliptets[1]); // abtets[i-1]. - flip23(fliptets, hullflag, fc); - - // Shrink the array 'abtets', maintain the original order. - // Two tets 'abtets[i-1] ([a,b,e,c])' and 'abtets[i] ([a,b,c,d])' - // are flipped, i.e., they do not in Star(ab) anymore. - // 'fliptets[0]' ([e,d,a,b]) is in Star(ab), it is saved in - // 'abtets[i-1]' (adjust it to be [a,b,e,d]), see below: - // - // before after - // [0] |___________| [0] |___________| - // ... |___________| ... |___________| - // [i-1] |_[a,b,e,c]_| [i-1] |_[a,b,e,d]_| - // [i] |_[a,b,c,d]_| --> [i] |_[a,b,d,#]_| - // [i+1] |_[a,b,d,#]_| [i+1] |_[a,b,#,*]_| - // ... |___________| ... |___________| - // [n-2] |___________| [n-2] |___________| - // [n-1] |___________| [n-1] |_[i]_2-t-3_| - // - edestoppoself(fliptets[0]); // [a,b,e,d] - // Increase the counter of this new tet (it is in Star(ab)). - increaseelemcounter(fliptets[0]); - abtets[(i - 1 + n) % n] = fliptets[0]; - for (j = i; j < n - 1; j++) { - abtets[j] = abtets[j + 1]; // Upshift - } - // The last entry 'abtets[n-1]' is empty. It is used in two ways: - // (i) it remembers the vertex 'c' (in 'abtets[n-1].tet'), and - // (ii) it remembers the position [i] where this flip took place. - // These informations let us to either undo this flip or recover - // the original edge link (for collecting new created tets). - //abtets[n - 1] = fliptets[1]; // [e,d,b,c] is remembered. - abtets[n - 1].tet = (tetrahedron *) pc; - abtets[n - 1].ver = 0; // Clear it. - // 'abtets[n - 1].ver' is in range [0,11] -- only uses 4 bits. - // Use the 5th bit in 'abtets[n - 1].ver' to signal a 2-to-3 flip. - abtets[n - 1].ver |= (1 << 4); - // The poisition [i] of this flip is saved above the 7th bit. - abtets[n - 1].ver |= (i << 6); - - if (fc->collectnewtets) { - // Push the two new tets [e,d,b,c] and [e,d,c,a] into a stack. - // Re-use the global array 'cavetetlist'. - for (j = 1; j < 3; j++) { - cavetetlist->newindex((void **) &parytet); - *parytet = fliptets[j]; // fliptets[1], fliptets[2]. - } - } - - // Star(ab) is reduced. Try to flip the edge [a,b]. - nn = flipnm(abtets, n - 1, level, abedgepivot, fc); - - if (nn == 2) { - // The edge has been flipped. - return nn; - } else { // if (nn > 2) - // The edge is not flipped. - if (fc->unflip || (ori == 0)) { - // Undo the previous 2-to-3 flip, i.e., do a 3-to-2 flip to - // transform [e,d] => [a,b,c]. - // 'ori == 0' means that the previous flip created a degenerated - // tet. It must be removed. - // Remember that 'abtets[i-1]' is [a,b,e,d]. We can use it to - // find another two tets [e,d,b,c] and [e,d,c,a]. - fliptets[0] = abtets[(i-1 + (n-1)) % (n-1)]; // [a,b,e,d] - edestoppoself(fliptets[0]); // [e,d,a,b] - fnext(fliptets[0], fliptets[1]); // [1] is [e,d,b,c] - fnext(fliptets[1], fliptets[2]); // [2] is [e,d,c,a] - assert(apex(fliptets[0]) == oppo(fliptets[2])); // SELF_CHECK - // Restore the two original tets in Star(ab). - flip32(fliptets, hullflag, fc); - // Marktest the two restored tets in Star(ab). - for (j = 0; j < 2; j++) { - increaseelemcounter(fliptets[j]); - } - // Expand the array 'abtets', maintain the original order. - for (j = n - 2; j>= i; j--) { - abtets[j + 1] = abtets[j]; // Downshift - } - // Insert the two new tets 'fliptets[0]' [a,b,c,d] and - // 'fliptets[1]' [b,a,c,e] into the (i-1)-th and i-th entries, - // respectively. - esym(fliptets[1], abtets[(i - 1 + n) % n]); // [a,b,e,c] - abtets[i] = fliptets[0]; // [a,b,c,d] - nn++; - if (fc->collectnewtets) { - // Pop two (flipped) tets from the stack. - cavetetlist->objects -= 2; - } - } // if (unflip || (ori == 0)) - } // if (nn > 2) - - if (!fc->unflip) { - // The flips are not reversed. The current Star(ab) can not be - // further reduced. Return its current size (# of tets). - return nn; - } - // unflip is set. - // Continue the search for flips. - } - } // if (reducflag) - } // i - - // The Star(ab) is not reduced. - if (reflexlinkedgecount > 0) { - // There are reflex edges in the Link(ab). - if (((b->fliplinklevel < 0) && (level < autofliplinklevel)) || - ((b->fliplinklevel >= 0) && (level < b->fliplinklevel))) { - // Try to reduce the Star(ab) by flipping a reflex edge in Link(ab). - for (i = 0; i < n; i++) { - // Do not flip this face [a,b,c] if there are two Stars involved. - if ((elemcounter(abtets[i]) > 1) || - (elemcounter(abtets[(i - 1 + n) % n]) > 1)) { - continue; - } - pc = apex(abtets[i]); - if (pc == dummypoint) { - continue; // [a,b] is a hull edge. - } - pd = apex(abtets[(i + 1) % n]); - pe = apex(abtets[(i - 1 + n) % n]); - if ((pd == dummypoint) || (pe == dummypoint)) { - continue; // [a,b,c] is a hull face. - } - - - edgepivot = 0; // No edge is selected yet. - - // Test if [b,c] is locally convex or flat. - ori = orient3d(pb, pc, pd, pe); - if (ori <= 0) { - // Select the edge [c,b]. - enext(abtets[i], flipedge); // [b,c,a,d] - edgepivot = 1; - } - if (!edgepivot) { - // Test if [c,a] is locally convex or flat. - ori = orient3d(pc, pa, pd, pe); - if (ori <= 0) { - // Select the edge [a,c]. - eprev(abtets[i], flipedge); // [c,a,b,d]. - edgepivot = 2; - } - } - - if (!edgepivot) continue; - - // An edge is selected. - if (checksubsegflag) { - // Do not flip it if it is a segment. - if (issubseg(flipedge)) { - if (fc->collectencsegflag) { - face checkseg, *paryseg; - tsspivot1(flipedge, checkseg); - if (!sinfected(checkseg)) { - // Queue this segment in list. - sinfect(checkseg); - caveencseglist->newindex((void **) &paryseg); - *paryseg = checkseg; - } - } - continue; - } - } - - // Try to flip the selected edge ([c,b] or [a,c]). - esymself(flipedge); - // Count the number of tets at the edge. - n1 = 0; - j = 0; // Sum of the star counters. - spintet = flipedge; - while (1) { - n1++; - j += (elemcounter(spintet)); - fnextself(spintet); - if (spintet.tet == flipedge.tet) break; - } - assert(n1 >= 3); - if (j > 2) { - // The Star(flipedge) overlaps other Stars. - continue; // Do not flip this edge. - } - // Only two tets can be marktested. - assert(j == 2); - - if ((b->flipstarsize > 0) && (n1 > b->flipstarsize)) { - // The star size exceeds the given limit. - continue; // Do not flip it. - } - - // Allocate spaces for Star(flipedge). - tmpabtets = new triface[n1]; - // Form the Star(flipedge). - j = 0; - spintet = flipedge; - while (1) { - tmpabtets[j] = spintet; - // Increase the star counter of this tet. - increaseelemcounter(tmpabtets[j]); - j++; - fnextself(spintet); - if (spintet.tet == flipedge.tet) break; - } - - // Try to flip the selected edge away. - nn = flipnm(tmpabtets, n1, level + 1, edgepivot, fc); - - if (nn == 2) { - // The edge is flipped. Star(ab) is reduced. - // Shrink the array 'abtets', maintain the original order. - if (edgepivot == 1) { - // 'tmpabtets[0]' is [d,a,e,b] => contains [a,b]. - spintet = tmpabtets[0]; // [d,a,e,b] - enextself(spintet); - esymself(spintet); - enextself(spintet); // [a,b,e,d] - } else { - // 'tmpabtets[1]' is [b,d,e,a] => contains [a,b]. - spintet = tmpabtets[1]; // [b,d,e,a] - eprevself(spintet); - esymself(spintet); - eprevself(spintet); // [a,b,e,d] - } // edgepivot == 2 - assert(elemcounter(spintet) == 0); // It's a new tet. - increaseelemcounter(spintet); // It is in Star(ab). - // Put the new tet at [i-1]-th entry. - abtets[(i - 1 + n) % n] = spintet; - for (j = i; j < n - 1; j++) { - abtets[j] = abtets[j + 1]; // Upshift - } - // Remember the flips in the last entry of the array 'abtets'. - // They can be used to recover the flipped edge. - abtets[n - 1].tet = (tetrahedron *) tmpabtets; // The star(fedge). - abtets[n - 1].ver = 0; // Clear it. - // Use the 1st and 2nd bit to save 'edgepivot' (1 or 2). - abtets[n - 1].ver |= edgepivot; - // Use the 6th bit to signal this n1-to-m1 flip. - abtets[n - 1].ver |= (1 << 5); - // The poisition [i] of this flip is saved from 7th to 19th bit. - abtets[n - 1].ver |= (i << 6); - // The size of the star 'n1' is saved from 20th bit. - abtets[n - 1].ver |= (n1 << 19); - - // Remember the flipped link vertex 'c'. It can be used to recover - // the original edge link of [a,b], and to collect new tets. - tmpabtets[0].tet = (tetrahedron *) pc; - tmpabtets[0].ver = (1 << 5); // Flag it as a vertex handle. - - // Continue to flip the edge [a,b]. - nn = flipnm(abtets, n - 1, level, abedgepivot, fc); - - if (nn == 2) { - // The edge has been flipped. - return nn; - } else { // if (nn > 2) { - // The edge is not flipped. - if (fc->unflip) { - // Recover the flipped edge ([c,b] or [a,c]). - assert(nn == (n - 1)); - // The sequence of flips are saved in 'tmpabtets'. - // abtets[(i-1) % (n-1)] is [a,b,e,d], i.e., the tet created by - // the flipping of edge [c,b] or [a,c].It must still exist in - // Star(ab). It is the start tet to recover the flipped edge. - if (edgepivot == 1) { - // The flip edge is [c,b]. - tmpabtets[0] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d] - eprevself(tmpabtets[0]); - esymself(tmpabtets[0]); - eprevself(tmpabtets[0]); // [d,a,e,b] - fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c] - } else { - // The flip edge is [a,c]. - tmpabtets[1] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d] - enextself(tmpabtets[1]); - esymself(tmpabtets[1]); - enextself(tmpabtets[1]); // [b,d,e,a] - fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c] - } // if (edgepivot == 2) - - // Recover the flipped edge ([c,b] or [a,c]). - flipnm_post(tmpabtets, n1, 2, edgepivot, fc); - - // Insert the two recovered tets into Star(ab). - for (j = n - 2; j >= i; j--) { - abtets[j + 1] = abtets[j]; // Downshift - } - if (edgepivot == 1) { - // tmpabtets[0] is [c,b,d,a] ==> contains [a,b] - // tmpabtets[1] is [c,b,a,e] ==> contains [a,b] - // tmpabtets[2] is [c,b,e,d] - fliptets[0] = tmpabtets[1]; - enextself(fliptets[0]); - esymself(fliptets[0]); // [a,b,e,c] - fliptets[1] = tmpabtets[0]; - esymself(fliptets[1]); - eprevself(fliptets[1]); // [a,b,c,d] - } else { - // tmpabtets[0] is [a,c,d,b] ==> contains [a,b] - // tmpabtets[1] is [a,c,b,e] ==> contains [a,b] - // tmpabtets[2] is [a,c,e,d] - fliptets[0] = tmpabtets[1]; - eprevself(fliptets[0]); - esymself(fliptets[0]); // [a,b,e,c] - fliptets[1] = tmpabtets[0]; - esymself(fliptets[1]); - enextself(fliptets[1]); // [a,b,c,d] - } // edgepivot == 2 - for (j = 0; j < 2; j++) { - increaseelemcounter(fliptets[j]); - } - // Insert the two recovered tets into Star(ab). - abtets[(i - 1 + n) % n] = fliptets[0]; - abtets[i] = fliptets[1]; - nn++; - // Release the allocated spaces. - delete [] tmpabtets; - } // if (unflip) - } // if (nn > 2) - - if (!fc->unflip) { - // The flips are not reversed. The current Star(ab) can not be - // further reduced. Return its size (# of tets). - return nn; - } - // unflip is set. - // Continue the search for flips. - } else { - // The selected edge is not flipped. - if (fc->unflip) { - // The memory should already be freed. - assert(nn == n1); - } else { - // Release the memory used in this attempted flip. - flipnm_post(tmpabtets, n1, nn, edgepivot, fc); - } - // Decrease the star counters of tets in Star(flipedge). - for (j = 0; j < nn; j++) { - assert(elemcounter(tmpabtets[j]) > 0); // SELF_CHECK - decreaseelemcounter(tmpabtets[j]); - } - // Release the allocated spaces. - delete [] tmpabtets; - } - } // i - } // if (level...) - } // if (reflexlinkedgecount > 0) - } else { - // Check if a 3-to-2 flip is possible. - // Let the three apexes be c, d,and e. Hull tets may be involved. If so, - // we rearrange them such that the vertex e is dummypoint. - hullflag = 0; - - if (apex(abtets[0]) == dummypoint) { - pc = apex(abtets[1]); - pd = apex(abtets[2]); - pe = apex(abtets[0]); - hullflag = 1; - } else if (apex(abtets[1]) == dummypoint) { - pc = apex(abtets[2]); - pd = apex(abtets[0]); - pe = apex(abtets[1]); - hullflag = 2; - } else { - pc = apex(abtets[0]); - pd = apex(abtets[1]); - pe = apex(abtets[2]); - hullflag = (pe == dummypoint) ? 3 : 0; - } - - reducflag = 0; - rejflag = 0; - - - if (hullflag == 0) { - // Make sure that no inverted tet will be created, i.e. the new tets - // [d,c,e,a] and [c,d,e,b] must be valid tets. - ori = orient3d(pd, pc, pe, pa); - if (ori < 0) { - ori = orient3d(pc, pd, pe, pb); - if (ori < 0) { - reducflag = 1; - } - } - } else { - // [a,b] is a hull edge. - // Note: This can happen when it is in the middle of a 4-to-4 flip. - // Note: [a,b] may even be a non-convex hull edge. - if (!nonconvex) { - // The mesh is convex, only do flip if it is a coplanar hull edge. - ori = orient3d(pa, pb, pc, pd); - if (ori == 0) { - reducflag = 1; - } - } else { // nonconvex - reducflag = 1; - } - if (reducflag == 1) { - // [a,b], [a,b,c] and [a,b,d] are on the convex hull. - // Make sure that no inverted tet will be created. - point searchpt = NULL, chkpt; - REAL bigvol = 0.0, ori1, ori2; - // Search an interior vertex which is an apex of edge [c,d]. - // In principle, it can be arbitrary interior vertex. To avoid - // numerical issue, we choose the vertex which belongs to a tet - // 't' at edge [c,d] and 't' has the biggest volume. - fliptets[0] = abtets[hullflag % 3]; // [a,b,c,d]. - eorgoppoself(fliptets[0]); // [d,c,b,a] - spintet = fliptets[0]; - while (1) { - fnextself(spintet); - chkpt = oppo(spintet); - if (chkpt == pb) break; - if ((chkpt != dummypoint) && (apex(spintet) != dummypoint)) { - ori = -orient3d(pd, pc, apex(spintet), chkpt); - assert(ori > 0); - if (ori > bigvol) { - bigvol = ori; - searchpt = chkpt; - } - } - } - if (searchpt != NULL) { - // Now valid the configuration. - ori1 = orient3d(pd, pc, searchpt, pa); - ori2 = orient3d(pd, pc, searchpt, pb); - if (ori1 * ori2 >= 0.0) { - reducflag = 0; // Not valid. - } else { - ori1 = orient3d(pa, pb, searchpt, pc); - ori2 = orient3d(pa, pb, searchpt, pd); - if (ori1 * ori2 >= 0.0) { - reducflag = 0; // Not valid. - } - } - } else { - // No valid searchpt is found. - reducflag = 0; // Do not flip it. - } - } // if (reducflag == 1) - } // if (hullflag == 1) - - if (reducflag) { - // A 3-to-2 flip is possible. - if (checksubfaceflag) { - // This edge (must not be a segment) can be flipped ONLY IF it belongs - // to either 0 or 2 subfaces. In the latter case, a 2-to-2 flip in - // the surface mesh will be automatically performed within the - // 3-to-2 flip. - nn = 0; - edgepivot = -1; // Re-use it. - for (j = 0; j < 3; j++) { - if (issubface(abtets[j])) { - nn++; // Found a subface. - } else { - edgepivot = j; - } - } - assert(nn < 3); - if (nn == 1) { - // Found only 1 subface containing this edge. This can happen in - // the boundary recovery phase. The neighbor subface is not yet - // recovered. This edge should not be flipped at this moment. - rejflag = 1; - } else if (nn == 2) { - // Found two subfaces. A 2-to-2 flip is possible. Validate it. - // Below we check if the two faces [p,q,a] and [p,q,b] are subfaces. - eorgoppo(abtets[(edgepivot + 1) % 3], spintet); // [q,p,b,a] - if (issubface(spintet)) { - rejflag = 1; // Conflict to a 2-to-2 flip. - } else { - esymself(spintet); - if (issubface(spintet)) { - rejflag = 1; // Conflict to a 2-to-2 flip. - } - } - } - } - if (!rejflag && fc->checkflipeligibility) { - // Here we must exchange 'a' and 'b'. Since in the check... function, - // we assume the following point sequence, 'a,b,c,d,e', where - // the face [a,b,c] will be flipped and the edge [e,d] will be - // created. The two new tets are [a,b,c,d] and [b,a,c,e]. - rejflag = checkflipeligibility(2, pc, pd, pe, pb, pa, level, - abedgepivot, fc); - } - if (!rejflag) { - // Do flip: [a,b] => [c,d,e] - flip32(abtets, hullflag, fc); - if (fc->remove_ndelaunay_edge) { - if (level == 0) { - // It is the desired removing edge. Check if we have improved - // the objective function. - if ((fc->tetprism_vol_sum >= 0.0) || - (fabs(fc->tetprism_vol_sum) < fc->bak_tetprism_vol)) { - // No improvement! flip back: [c,d,e] => [a,b]. - flip23(abtets, hullflag, fc); - // Increase the element counter -- They are in cavity. - for (j = 0; j < 3; j++) { - increaseelemcounter(abtets[j]); - } - return 3; - } - } // if (level == 0) - } - if (fc->collectnewtets) { - // Collect new tets. - if (level == 0) { - // Push the two new tets into stack. - for (j = 0; j < 2; j++) { - cavetetlist->newindex((void **) &parytet); - *parytet = abtets[j]; - } - } else { - // Only one of the new tets is collected. The other one is inside - // the reduced edge star. 'abedgepivot' is either '1' or '2'. - cavetetlist->newindex((void **) &parytet); - if (abedgepivot == 1) { // [c,b] - *parytet = abtets[1]; - } else { - assert(abedgepivot == 2); // [a,c] - *parytet = abtets[0]; - } - } - } // if (fc->collectnewtets) - return 2; - } - } // if (reducflag) - } // if (n == 3) - - // The current (reduced) Star size. - return n; -} - -int meshGRegionBoundaryRecovery::flipnm_post(triface* abtets, int n, int nn, - int abedgepivot, flipconstraints* fc) -{ - triface fliptets[3], flipface; - triface *tmpabtets; - int fliptype; - int edgepivot; - int t, n1; - int i, j; - - - if (nn == 2) { - // The edge [a,b] has been flipped. - // 'abtets[0]' is [c,d,e,b] or [#,#,#,b]. - // 'abtets[1]' is [d,c,e,a] or [#,#,#,a]. - if (fc->unflip) { - // Do a 2-to-3 flip to recover the edge [a,b]. There may be hull tets. - flip23(abtets, 1, fc); - if (fc->collectnewtets) { - // Pop up new (flipped) tets from the stack. - if (abedgepivot == 0) { - // Two new tets were collected. - cavetetlist->objects -= 2; - } else { - // Only one of the two new tets was collected. - cavetetlist->objects -= 1; - } - } - } - // The initial size of Star(ab) is 3. - nn++; - } - - // Walk through the performed flips. - for (i = nn; i < n; i++) { - // At the beginning of each step 'i', the size of the Star([a,b]) is 'i'. - // At the end of this step, the size of the Star([a,b]) is 'i+1'. - // The sizes of the Link([a,b]) are the same. - fliptype = ((abtets[i].ver >> 4) & 3); // 0, 1, or 2. - if (fliptype == 1) { - // It was a 2-to-3 flip: [a,b,c]->[e,d]. - t = (abtets[i].ver >> 6); - assert(t <= i); - if (fc->unflip) { - if (b->verbose > 2) { - printf(" Recover a 2-to-3 flip at f[%d].\n", t); - } - // 'abtets[(t-1)%i]' is the tet [a,b,e,d] in current Star(ab), i.e., - // it is created by a 2-to-3 flip [a,b,c] => [e,d]. - fliptets[0] = abtets[((t - 1) + i) % i]; // [a,b,e,d] - eprevself(fliptets[0]); - esymself(fliptets[0]); - enextself(fliptets[0]); // [e,d,a,b] - fnext(fliptets[0], fliptets[1]); // [e,d,b,c] - fnext(fliptets[1], fliptets[2]); // [e,d,c,a] - // Do a 3-to-2 flip: [e,d] => [a,b,c]. - // NOTE: hull tets may be invloved. - flip32(fliptets, 1, fc); - // Expand the array 'abtets', maintain the original order. - // The new array length is (i+1). - for (j = i - 1; j >= t; j--) { - abtets[j + 1] = abtets[j]; // Downshift - } - // The tet abtets[(t-1)%i] is deleted. Insert the two new tets - // 'fliptets[0]' [a,b,c,d] and 'fliptets[1]' [b,a,c,e] into - // the (t-1)-th and t-th entries, respectively. - esym(fliptets[1], abtets[((t-1) + (i+1)) % (i+1)]); // [a,b,e,c] - abtets[t] = fliptets[0]; // [a,b,c,d] - if (fc->collectnewtets) { - // Pop up two (flipped) tets from the stack. - cavetetlist->objects -= 2; - } - } - } else if (fliptype == 2) { - tmpabtets = (triface *) (abtets[i].tet); - n1 = ((abtets[i].ver >> 19) & 8191); // \sum_{i=0^12}{2^i} = 8191 - edgepivot = (abtets[i].ver & 3); - t = ((abtets[i].ver >> 6) & 8191); - assert(t <= i); - if (fc->unflip) { - if (b->verbose > 2) { - printf(" Recover a %d-to-m flip at e[%d] of f[%d].\n", n1, - edgepivot, t); - } - // Recover the flipped edge ([c,b] or [a,c]). - // abtets[(t - 1 + i) % i] is [a,b,e,d], i.e., the tet created by - // the flipping of edge [c,b] or [a,c]. It must still exist in - // Star(ab). Use it to recover the flipped edge. - if (edgepivot == 1) { - // The flip edge is [c,b]. - tmpabtets[0] = abtets[(t - 1 + i) % i]; // [a,b,e,d] - eprevself(tmpabtets[0]); - esymself(tmpabtets[0]); - eprevself(tmpabtets[0]); // [d,a,e,b] - fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c] - } else { - // The flip edge is [a,c]. - tmpabtets[1] = abtets[(t - 1 + i) % i]; // [a,b,e,d] - enextself(tmpabtets[1]); - esymself(tmpabtets[1]); - enextself(tmpabtets[1]); // [b,d,e,a] - fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c] - } // if (edgepivot == 2) - - // Do a n1-to-m1 flip to recover the flipped edge ([c,b] or [a,c]). - flipnm_post(tmpabtets, n1, 2, edgepivot, fc); - - // Insert the two recovered tets into the original Star(ab). - for (j = i - 1; j >= t; j--) { - abtets[j + 1] = abtets[j]; // Downshift - } - if (edgepivot == 1) { - // tmpabtets[0] is [c,b,d,a] ==> contains [a,b] - // tmpabtets[1] is [c,b,a,e] ==> contains [a,b] - // tmpabtets[2] is [c,b,e,d] - fliptets[0] = tmpabtets[1]; - enextself(fliptets[0]); - esymself(fliptets[0]); // [a,b,e,c] - fliptets[1] = tmpabtets[0]; - esymself(fliptets[1]); - eprevself(fliptets[1]); // [a,b,c,d] - } else { - // tmpabtets[0] is [a,c,d,b] ==> contains [a,b] - // tmpabtets[1] is [a,c,b,e] ==> contains [a,b] - // tmpabtets[2] is [a,c,e,d] - fliptets[0] = tmpabtets[1]; - eprevself(fliptets[0]); - esymself(fliptets[0]); // [a,b,e,c] - fliptets[1] = tmpabtets[0]; - esymself(fliptets[1]); - enextself(fliptets[1]); // [a,b,c,d] - } // edgepivot == 2 - // Insert the two recovered tets into Star(ab). - abtets[((t-1) + (i+1)) % (i+1)] = fliptets[0]; - abtets[t] = fliptets[1]; - } - else { - // Only free the spaces. - flipnm_post(tmpabtets, n1, 2, edgepivot, fc); - } // if (!unflip) - if (b->verbose > 2) { - printf(" Release %d spaces at f[%d].\n", n1, i); - } - delete [] tmpabtets; - } - } // i - - return 1; -} - -int meshGRegionBoundaryRecovery::insertpoint(point insertpt, - triface *searchtet, face *splitsh, face *splitseg, insertvertexflags *ivf) -{ - arraypool *swaplist; - triface *cavetet, spintet, neightet, neineitet, *parytet; - triface oldtet, newtet, newneitet; - face checksh, neighsh, *parysh; - face checkseg, *paryseg; - point *pts, pa, pb, pc, *parypt; - enum locateresult loc = OUTSIDE; - REAL sign, ori; - REAL attrib, volume; - bool enqflag; - int t1ver; - int i, j, k, s; - - if (b->verbose > 2) { - printf(" Insert point %d\n", pointmark(insertpt)); - } - - // Locate the point. - if (searchtet->tet != NULL) { - loc = (enum locateresult) ivf->iloc; - } - - if (loc == OUTSIDE) { - if (searchtet->tet == NULL) { - if (!b->weighted) { - randomsample(insertpt, searchtet); - } else { - // Weighted DT. There may exist dangling vertex. - *searchtet = recenttet; - } - } - // Locate the point. - loc = locate(insertpt, searchtet); - } - - ivf->iloc = (int) loc; // The return value. - - /* - if (b->weighted) { - if (loc != OUTSIDE) { - // Check if this vertex is regular. - pts = (point *) searchtet->tet; - assert(pts[7] != dummypoint); - sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt, - pts[4][3], pts[5][3], pts[6][3], pts[7][3], - insertpt[3]); - if (sign > 0) { - // This new vertex does not lie below the lower hull. Skip it. - setpointtype(insertpt, NREGULARVERTEX); - nonregularcount++; - ivf->iloc = (int) NONREGULAR; - return 0; - } - } - } - */ - - // Create the initial cavity C(p) which contains all tetrahedra that - // intersect p. It may include 1, 2, or n tetrahedra. - // If p lies on a segment or subface, also create the initial sub-cavity - // sC(p) which contains all subfaces (and segment) which intersect p. - - if (loc == OUTSIDE) { - flip14count++; - // The current hull will be enlarged. - // Add four adjacent boundary tets into list. - for (i = 0; i < 4; i++) { - decode(searchtet->tet[i], neightet); - neightet.ver = epivot[neightet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neightet; - } - infect(*searchtet); - caveoldtetlist->newindex((void **) &parytet); - *parytet = *searchtet; - } else if (loc == INTETRAHEDRON) { - flip14count++; - // Add four adjacent boundary tets into list. - for (i = 0; i < 4; i++) { - decode(searchtet->tet[i], neightet); - neightet.ver = epivot[neightet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neightet; - } - infect(*searchtet); - caveoldtetlist->newindex((void **) &parytet); - *parytet = *searchtet; - } else if (loc == ONFACE) { - flip26count++; - // Add six adjacent boundary tets into list. - j = (searchtet->ver & 3); // The current face number. - for (i = 1; i < 4; i++) { - decode(searchtet->tet[(j + i) % 4], neightet); - neightet.ver = epivot[neightet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neightet; - } - decode(searchtet->tet[j], spintet); - j = (spintet.ver & 3); // The current face number. - for (i = 1; i < 4; i++) { - decode(spintet.tet[(j + i) % 4], neightet); - neightet.ver = epivot[neightet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neightet; - } - infect(spintet); - caveoldtetlist->newindex((void **) &parytet); - *parytet = spintet; - infect(*searchtet); - caveoldtetlist->newindex((void **) &parytet); - *parytet = *searchtet; - - if (ivf->splitbdflag) { - if ((splitsh != NULL) && (splitsh->sh != NULL)) { - // Create the initial sub-cavity sC(p). - smarktest(*splitsh); - caveshlist->newindex((void **) &parysh); - *parysh = *splitsh; - } - } // if (splitbdflag) - } else if (loc == ONEDGE) { - flipn2ncount++; - // Add all adjacent boundary tets into list. - spintet = *searchtet; - while (1) { - eorgoppo(spintet, neightet); - decode(neightet.tet[neightet.ver & 3], neightet); - neightet.ver = epivot[neightet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neightet; - edestoppo(spintet, neightet); - decode(neightet.tet[neightet.ver & 3], neightet); - neightet.ver = epivot[neightet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neightet; - infect(spintet); - caveoldtetlist->newindex((void **) &parytet); - *parytet = spintet; - fnextself(spintet); - if (spintet.tet == searchtet->tet) break; - } // while (1) - - if (ivf->splitbdflag) { - // Create the initial sub-cavity sC(p). - if ((splitseg != NULL) && (splitseg->sh != NULL)) { - smarktest(*splitseg); - splitseg->shver = 0; - spivot(*splitseg, *splitsh); - } - if (splitsh != NULL) { - if (splitsh->sh != NULL) { - // Collect all subfaces share at this edge. - pa = sorg(*splitsh); - neighsh = *splitsh; - while (1) { - // Adjust the origin of its edge to be 'pa'. - if (sorg(neighsh) != pa) { - sesymself(neighsh); - } - // Add this face into list (in B-W cavity). - smarktest(neighsh); - caveshlist->newindex((void **) &parysh); - *parysh = neighsh; - // Add this face into face-at-splitedge list. - cavesegshlist->newindex((void **) &parysh); - *parysh = neighsh; - // Go to the next face at the edge. - spivotself(neighsh); - // Stop if all faces at the edge have been visited. - if (neighsh.sh == splitsh->sh) break; - if (neighsh.sh == NULL) break; - } // while (1) - } // if (not a dangling segment) - } - } // if (splitbdflag) - } else if (loc == INSTAR) { - // We assume that all tets in the star are given in 'caveoldtetlist', - // and they are all infected. - assert(caveoldtetlist->objects > 0); - // Collect the boundary faces of the star. - for (i = 0; i < caveoldtetlist->objects; i++) { - cavetet = (triface *) fastlookup(caveoldtetlist, i); - // Check its 4 neighbor tets. - for (j = 0; j < 4; j++) { - decode(cavetet->tet[j], neightet); - if (!infected(neightet)) { - // It's a boundary face. - neightet.ver = epivot[neightet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neightet; - } - } - } - } else if (loc == ONVERTEX) { - // The point already exist. Do nothing and return. - return 0; - } - - /* - if (ivf->assignmeshsize) { - // Assign mesh size for the new point. - if (bgm != NULL) { - // Interpolate the mesh size from the background mesh. - bgm->decode(point2bgmtet(org(*searchtet)), neightet); - int bgmloc = (int) bgm->scoutpoint(insertpt, &neightet, 0); - if (bgmloc != (int) OUTSIDE) { - insertpt[pointmtrindex] = - bgm->getpointmeshsize(insertpt, &neightet, bgmloc); - setpoint2bgmtet(insertpt, bgm->encode(neightet)); - } - } else { - insertpt[pointmtrindex] = getpointmeshsize(insertpt,searchtet,(int)loc); - } - } // if (assignmeshsize) - */ - - if (ivf->bowywat) { - // Update the cavity C(p) using the Bowyer-Watson algorithm. - swaplist = cavetetlist; - cavetetlist = cavebdrylist; - cavebdrylist = swaplist; - for (i = 0; i < cavetetlist->objects; i++) { - // 'cavetet' is an adjacent tet at outside of the cavity. - cavetet = (triface *) fastlookup(cavetetlist, i); - // The tet may be tested and included in the (enlarged) cavity. - if (!infected(*cavetet)) { - // Check for two possible cases for this tet: - // (1) It is a cavity tet, or - // (2) it is a cavity boundary face. - enqflag = false; - if (!marktested(*cavetet)) { - // Do Delaunay (in-sphere) test. - pts = (point *) cavetet->tet; - if (pts[7] != dummypoint) { - // A volume tet. Operate on it. - if (b->weighted) { - /* - sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt, - pts[4][3], pts[5][3], pts[6][3], pts[7][3], - insertpt[3]); - */ - } else { - sign = insphere_s(pts[4], pts[5], pts[6], pts[7], insertpt); - } - enqflag = (sign < 0.0); - } else { - if (!nonconvex) { - // Test if this hull face is visible by the new point. - ori = orient3d(pts[4], pts[5], pts[6], insertpt); - if (ori < 0) { - // A visible hull face. - //if (!nonconvex) { - // Include it in the cavity. The convex hull will be enlarged. - enqflag = true; // (ori < 0.0); - //} - } else if (ori == 0.0) { - // A coplanar hull face. We need to test if this hull face is - // Delaunay or not. We test if the adjacent tet (not faked) - // of this hull face is Delaunay or not. - decode(cavetet->tet[3], neineitet); - if (!infected(neineitet)) { - if (!marktested(neineitet)) { - // Do Delaunay test on this tet. - pts = (point *) neineitet.tet; - assert(pts[7] != dummypoint); - if (b->weighted) { - /* - sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt, - pts[4][3], pts[5][3], pts[6][3], - pts[7][3], insertpt[3]); - */ - } else { - sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt); - } - enqflag = (sign < 0.0); - } - } else { - // The adjacent tet is non-Delaunay. The hull face is non- - // Delaunay as well. Include it in the cavity. - enqflag = true; - } // if (!infected(neineitet)) - } // if (ori == 0.0) - } else { - // A hull face (must be a subface). - // We FIRST include it in the initial cavity if the adjacent tet - // (not faked) of this hull face is not Delaunay wrt p. - // Whether it belongs to the final cavity will be determined - // during the validation process. 'validflag'. - decode(cavetet->tet[3], neineitet); - if (!infected(neineitet)) { - if (!marktested(neineitet)) { - // Do Delaunay test on this tet. - pts = (point *) neineitet.tet; - assert(pts[7] != dummypoint); - if (b->weighted) { - /* - sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt, - pts[4][3], pts[5][3], pts[6][3], - pts[7][3], insertpt[3]); - */ - } else { - sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt); - } - enqflag = (sign < 0.0); - } - } else { - // The adjacent tet is non-Delaunay. The hull face is non- - // Delaunay as well. Include it in the cavity. - enqflag = true; - } // if (infected(neineitet)) - } // if (nonconvex) - } // if (pts[7] != dummypoint) - marktest(*cavetet); // Only test it once. - } // if (!marktested(*cavetet)) - - if (enqflag) { - // Found a tet in the cavity. Put other three faces in check list. - k = (cavetet->ver & 3); // The current face number - for (j = 1; j < 4; j++) { - decode(cavetet->tet[(j + k) % 4], neightet); - cavetetlist->newindex((void **) &parytet); - *parytet = neightet; - } - infect(*cavetet); - caveoldtetlist->newindex((void **) &parytet); - *parytet = *cavetet; - } else { - // Found a boundary face of the cavity. - cavetet->ver = epivot[cavetet->ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = *cavetet; - } - } // if (!infected(*cavetet)) - } // i - - cavetetlist->restart(); // Clear the working list. - } // if (ivf->bowywat) - - if (checksubsegflag) { - // Collect all segments of C(p). - shellface *ssptr; - for (i = 0; i < caveoldtetlist->objects; i++) { - cavetet = (triface *) fastlookup(caveoldtetlist, i); - if ((ssptr = (shellface*) cavetet->tet[8]) != NULL) { - for (j = 0; j < 6; j++) { - if (ssptr[j]) { - sdecode(ssptr[j], checkseg); - if (!sinfected(checkseg)) { - sinfect(checkseg); - cavetetseglist->newindex((void **) &paryseg); - *paryseg = checkseg; - } - } - } // j - } - } // i - // Uninfect collected segments. - for (i = 0; i < cavetetseglist->objects; i++) { - paryseg = (face *) fastlookup(cavetetseglist, i); - suninfect(*paryseg); - } - - /* - if (ivf->rejflag & 1) { - // Reject this point if it encroaches upon any segment. - face *paryseg1; - for (i = 0; i < cavetetseglist->objects; i++) { - paryseg1 = (face *) fastlookup(cavetetseglist, i); - if (checkseg4encroach((point) paryseg1->sh[3], (point) paryseg1->sh[4], - insertpt)) { - encseglist->newindex((void **) &paryseg); - *paryseg = *paryseg1; - } - } // i - if (encseglist->objects > 0) { - insertpoint_abort(splitseg, ivf); - ivf->iloc = (int) ENCSEGMENT; - return 0; - } - } - */ - } // if (checksubsegflag) - - if (checksubfaceflag) { - // Collect all subfaces of C(p). - shellface *sptr; - for (i = 0; i < caveoldtetlist->objects; i++) { - cavetet = (triface *) fastlookup(caveoldtetlist, i); - if ((sptr = (shellface*) cavetet->tet[9]) != NULL) { - for (j = 0; j < 4; j++) { - if (sptr[j]) { - sdecode(sptr[j], checksh); - if (!sinfected(checksh)) { - sinfect(checksh); - cavetetshlist->newindex((void **) &parysh); - *parysh = checksh; - } - } - } // j - } - } // i - // Uninfect collected subfaces. - for (i = 0; i < cavetetshlist->objects; i++) { - parysh = (face *) fastlookup(cavetetshlist, i); - suninfect(*parysh); - } - - /* - if (ivf->rejflag & 2) { - REAL rd, cent[3]; - badface *bface; - // Reject this point if it encroaches upon any subface. - for (i = 0; i < cavetetshlist->objects; i++) { - parysh = (face *) fastlookup(cavetetshlist, i); - if (checkfac4encroach((point) parysh->sh[3], (point) parysh->sh[4], - (point) parysh->sh[5], insertpt, cent, &rd)) { - encshlist->newindex((void **) &bface); - bface->ss = *parysh; - bface->forg = (point) parysh->sh[3]; // Not a dad one. - for (j = 0; j < 3; j++) bface->cent[j] = cent[j]; - bface->key = rd; - } - } - if (encshlist->objects > 0) { - insertpoint_abort(splitseg, ivf); - ivf->iloc = (int) ENCSUBFACE; - return 0; - } - } - */ - } // if (checksubfaceflag) - - if ((ivf->iloc == (int) OUTSIDE) && ivf->refineflag) { - // The vertex lies outside of the domain. And it does not encroach - // upon any boundary segment or subface. Do not insert it. - insertpoint_abort(splitseg, ivf); - return 0; - } - - if (ivf->splitbdflag) { - // The new point locates in surface mesh. Update the sC(p). - // We have already 'smarktested' the subfaces which directly intersect - // with p in 'caveshlist'. From them, we 'smarktest' their neighboring - // subfaces which are included in C(p). Do not across a segment. - for (i = 0; i < caveshlist->objects; i++) { - parysh = (face *) fastlookup(caveshlist, i); - assert(smarktested(*parysh)); - checksh = *parysh; - for (j = 0; j < 3; j++) { - if (!isshsubseg(checksh)) { - spivot(checksh, neighsh); - assert(neighsh.sh != NULL); - if (!smarktested(neighsh)) { - stpivot(neighsh, neightet); - if (infected(neightet)) { - fsymself(neightet); - if (infected(neightet)) { - // This subface is inside C(p). - // Check if its diametrical circumsphere encloses 'p'. - // The purpose of this check is to avoid forming invalid - // subcavity in surface mesh. - sign = incircle3d(sorg(neighsh), sdest(neighsh), - sapex(neighsh), insertpt); - if (sign < 0) { - smarktest(neighsh); - caveshlist->newindex((void **) &parysh); - *parysh = neighsh; - } - } - } - } - } - senextself(checksh); - } // j - } // i - } // if (ivf->splitbdflag) - - if (ivf->validflag) { - // Validate C(p) and update it if it is not star-shaped. - int cutcount = 0; - - if (ivf->respectbdflag) { - // The initial cavity may include subfaces which are not on the facets - // being splitting. Find them and make them as boundary of C(p). - // Comment: We have already 'smarktested' the subfaces in sC(p). They - // are completely inside C(p). - for (i = 0; i < cavetetshlist->objects; i++) { - parysh = (face *) fastlookup(cavetetshlist, i); - stpivot(*parysh, neightet); - if (infected(neightet)) { - fsymself(neightet); - if (infected(neightet)) { - // Found a subface inside C(p). - if (!smarktested(*parysh)) { - // It is possible that this face is a boundary subface. - // Check if it is a hull face. - //assert(apex(neightet) != dummypoint); - if (oppo(neightet) != dummypoint) { - fsymself(neightet); - } - if (oppo(neightet) != dummypoint) { - ori = orient3d(org(neightet), dest(neightet), apex(neightet), - insertpt); - if (ori < 0) { - // A visible face, get its neighbor face. - fsymself(neightet); - ori = -ori; // It must be invisible by p. - } - } else { - // A hull tet. It needs to be cut. - ori = 1; - } - // Cut this tet if it is either invisible by or coplanar with p. - if (ori >= 0) { - uninfect(neightet); - unmarktest(neightet); - cutcount++; - neightet.ver = epivot[neightet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neightet; - // Add three new faces to find new boundaries. - for (j = 0; j < 3; j++) { - esym(neightet, neineitet); - neineitet.ver = epivot[neineitet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neineitet; - enextself(neightet); - } - } // if (ori >= 0) - } - } - } - } // i - - // The initial cavity may include segments in its interior. We need to - // Update the cavity so that these segments are on the boundary of - // the cavity. - for (i = 0; i < cavetetseglist->objects; i++) { - paryseg = (face *) fastlookup(cavetetseglist, i); - // Check this segment if it is not a splitting segment. - if (!smarktested(*paryseg)) { - sstpivot1(*paryseg, neightet); - spintet = neightet; - while (1) { - if (!infected(spintet)) break; - fnextself(spintet); - if (spintet.tet == neightet.tet) break; - } - if (infected(spintet)) { - // Find an adjacent tet at this segment such that both faces - // at this segment are not visible by p. - pa = org(neightet); - pb = dest(neightet); - spintet = neightet; - j = 0; - while (1) { - // Check if this face is visible by p. - pc = apex(spintet); - if (pc != dummypoint) { - ori = orient3d(pa, pb, pc, insertpt); - if (ori >= 0) { - // Not visible. Check another face in this tet. - esym(spintet, neineitet); - pc = apex(neineitet); - if (pc != dummypoint) { - ori = orient3d(pb, pa, pc, insertpt); - if (ori >= 0) { - // Not visible. Found this face. - j = 1; // Flag that it is found. - break; - } - } - } - } - fnextself(spintet); - if (spintet.tet == neightet.tet) break; - } - if (j == 0) { - // Not found such a face. - assert(0); // debug this case. - } - neightet = spintet; - if (b->verbose > 3) { - printf(" Cut tet (%d, %d, %d, %d)\n", - pointmark(org(neightet)), pointmark(dest(neightet)), - pointmark(apex(neightet)), pointmark(oppo(neightet))); - } - uninfect(neightet); - unmarktest(neightet); - cutcount++; - neightet.ver = epivot[neightet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neightet; - // Add three new faces to find new boundaries. - for (j = 0; j < 3; j++) { - esym(neightet, neineitet); - neineitet.ver = epivot[neineitet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neineitet; - enextself(neightet); - } - } - } - } // i - } // if (ivf->respectbdflag) - - // Update the cavity by removing invisible faces until it is star-shaped. - for (i = 0; i < cavebdrylist->objects; i++) { - cavetet = (triface *) fastlookup(cavebdrylist, i); - // 'cavetet' is an exterior tet adjacent to the cavity. - // Check if its neighbor is inside C(p). - fsym(*cavetet, neightet); - if (infected(neightet)) { - if (apex(*cavetet) != dummypoint) { - // It is a cavity boundary face. Check its visibility. - if (oppo(neightet) != dummypoint) { - ori = orient3d(org(*cavetet), dest(*cavetet), apex(*cavetet), - insertpt); - enqflag = (ori > 0); - // Comment: if ori == 0 (coplanar case), we also cut the tet. - } else { - // It is a hull face. And its adjacent tet (at inside of the - // domain) has been cut from the cavity. Cut it as well. - //assert(nonconvex); - enqflag = false; - } - } else { - enqflag = true; // A hull edge. - } - if (enqflag) { - // This face is valid, save it. - cavetetlist->newindex((void **) &parytet); - *parytet = *cavetet; - } else { - uninfect(neightet); - unmarktest(neightet); - cutcount++; - // Add three new faces to find new boundaries. - for (j = 0; j < 3; j++) { - esym(neightet, neineitet); - neineitet.ver = epivot[neineitet.ver]; - cavebdrylist->newindex((void **) &parytet); - *parytet = neineitet; - enextself(neightet); - } - // 'cavetet' is not on the cavity boundary anymore. - unmarktest(*cavetet); - } - } else { - // 'cavetet' is not on the cavity boundary anymore. - unmarktest(*cavetet); - } - } // i - - if (cutcount > 0) { - // The cavity has been updated. - // Update the cavity boundary faces. - cavebdrylist->restart(); - for (i = 0; i < cavetetlist->objects; i++) { - cavetet = (triface *) fastlookup(cavetetlist, i); - // 'cavetet' was an exterior tet adjacent to the cavity. - fsym(*cavetet, neightet); - if (infected(neightet)) { - // It is a cavity boundary face. - cavebdrylist->newindex((void **) &parytet); - *parytet = *cavetet; - } else { - // Not a cavity boundary face. - unmarktest(*cavetet); - } - } - - // Update the list of old tets. - cavetetlist->restart(); - for (i = 0; i < caveoldtetlist->objects; i++) { - cavetet = (triface *) fastlookup(caveoldtetlist, i); - if (infected(*cavetet)) { - cavetetlist->newindex((void **) &parytet); - *parytet = *cavetet; - } - } - // Swap 'cavetetlist' and 'caveoldtetlist'. - swaplist = caveoldtetlist; - caveoldtetlist = cavetetlist; - cavetetlist = swaplist; - - // The cavity should contain at least one tet. - if (caveoldtetlist->objects == 0l) { - insertpoint_abort(splitseg, ivf); - ivf->iloc = (int) BADELEMENT; - return 0; - } - - if (ivf->splitbdflag) { - int cutshcount = 0; - // Update the sub-cavity sC(p). - for (i = 0; i < caveshlist->objects; i++) { - parysh = (face *) fastlookup(caveshlist, i); - if (smarktested(*parysh)) { - enqflag = false; - stpivot(*parysh, neightet); - if (infected(neightet)) { - fsymself(neightet); - if (infected(neightet)) { - enqflag = true; - } - } - if (!enqflag) { - sunmarktest(*parysh); - // Use the last entry of this array to fill this entry. - j = caveshlist->objects - 1; - checksh = * (face *) fastlookup(caveshlist, j); - *parysh = checksh; - cutshcount++; - caveshlist->objects--; // The list is shrinked. - i--; - } - } - } - - if (cutshcount > 0) { - i = 0; // Count the number of invalid subfaces/segments. - // Valid the updated sub-cavity sC(p). - if (loc == ONFACE) { - if ((splitsh != NULL) && (splitsh->sh != NULL)) { - // The to-be split subface should be in sC(p). - if (!smarktested(*splitsh)) i++; - } - } else if (loc == ONEDGE) { - if ((splitseg != NULL) && (splitseg->sh != NULL)) { - // The to-be split segment should be in sC(p). - if (!smarktested(*splitseg)) i++; - } - if ((splitsh != NULL) && (splitsh->sh != NULL)) { - // All subfaces at this edge should be in sC(p). - pa = sorg(*splitsh); - neighsh = *splitsh; - while (1) { - // Adjust the origin of its edge to be 'pa'. - if (sorg(neighsh) != pa) { - sesymself(neighsh); - } - // Add this face into list (in B-W cavity). - if (!smarktested(neighsh)) i++; - // Go to the next face at the edge. - spivotself(neighsh); - // Stop if all faces at the edge have been visited. - if (neighsh.sh == splitsh->sh) break; - if (neighsh.sh == NULL) break; - } // while (1) - } - } - - if (i > 0) { - // The updated sC(p) is invalid. Do not insert this vertex. - insertpoint_abort(splitseg, ivf); - ivf->iloc = (int) BADELEMENT; - return 0; - } - } // if (cutshcount > 0) - } // if (ivf->splitbdflag) - } // if (cutcount > 0) - - } // if (ivf->validflag) - - if (ivf->refineflag) { - // The new point is inserted by Delaunay refinement, i.e., it is the - // circumcenter of a tetrahedron, or a subface, or a segment. - // Do not insert this point if the tetrahedron, or subface, or segment - // is not inside the final cavity. - if (((ivf->refineflag == 1) && !infected(ivf->refinetet)) || - ((ivf->refineflag == 2) && !smarktested(ivf->refinesh))) { - insertpoint_abort(splitseg, ivf); - ivf->iloc = (int) BADELEMENT; - return 0; - } - } // if (ivf->refineflag) - - if (b->plc && (loc != INSTAR)) { - // Reject the new point if it lies too close to an existing point (b->plc), - // or it lies inside a protecting ball of near vertex (ivf->rejflag & 4). - // Collect the list of vertices of the initial cavity. - if (loc == OUTSIDE) { - pts = (point *) &(searchtet->tet[4]); - for (i = 0; i < 3; i++) { - cavetetvertlist->newindex((void **) &parypt); - *parypt = pts[i]; - } - } else if (loc == INTETRAHEDRON) { - pts = (point *) &(searchtet->tet[4]); - for (i = 0; i < 4; i++) { - cavetetvertlist->newindex((void **) &parypt); - *parypt = pts[i]; - } - } else if (loc == ONFACE) { - pts = (point *) &(searchtet->tet[4]); - for (i = 0; i < 3; i++) { - cavetetvertlist->newindex((void **) &parypt); - *parypt = pts[i]; - } - if (pts[3] != dummypoint) { - cavetetvertlist->newindex((void **) &parypt); - *parypt = pts[3]; - } - fsym(*searchtet, spintet); - if (oppo(spintet) != dummypoint) { - cavetetvertlist->newindex((void **) &parypt); - *parypt = oppo(spintet); - } - } else if (loc == ONEDGE) { - spintet = *searchtet; - cavetetvertlist->newindex((void **) &parypt); - *parypt = org(spintet); - cavetetvertlist->newindex((void **) &parypt); - *parypt = dest(spintet); - while (1) { - if (apex(spintet) != dummypoint) { - cavetetvertlist->newindex((void **) &parypt); - *parypt = apex(spintet); - } - fnextself(spintet); - if (spintet.tet == searchtet->tet) break; - } - } - - int rejptflag = (ivf->rejflag & 4); - REAL rd; - pts = NULL; - - for (i = 0; i < cavetetvertlist->objects; i++) { - parypt = (point *) fastlookup(cavetetvertlist, i); - rd = distance(*parypt, insertpt); - // Is the point very close to an existing point? - if (rd < b->minedgelength) { - pts = parypt; - loc = NEARVERTEX; - break; - } - if (rejptflag) { - // Is the point encroaches upon an existing point? - if (rd < (0.5 * (*parypt)[pointmtrindex])) { - pts = parypt; - loc = ENCVERTEX; - break; - } - } - } - cavetetvertlist->restart(); // Clear the work list. - - if (pts != NULL) { - // The point is either too close to an existing vertex (NEARVERTEX) - // or encroaches upon (inside the protecting ball) of that vertex. - if (loc == NEARVERTEX) { - if (b->nomergevertex) { // -M0/1 option. - // In this case, we still insert this vertex. Although it is very - // close to an existing vertex. Give a warning, anyway. - Msg::Warning("Warning: Two points, %d and %d, are very close.", - pointmark(insertpt), pointmark(*pts)); - Msg::Warning(" Creating a very short edge (len = %g) (< %g).", - rd, b->minedgelength); - Msg::Warning(" You may try a smaller tolerance (-T) (current is %g)", - b->epsilon); - Msg::Warning(" to avoid this warning."); - } else { - insertpt[3] = rd; // Only for reporting. - setpoint2ppt(insertpt, *pts); - insertpoint_abort(splitseg, ivf); - ivf->iloc = (int) loc; - return 0; - } - } else { // loc == ENCVERTEX - // The point lies inside the protection ball. - setpoint2ppt(insertpt, *pts); - insertpoint_abort(splitseg, ivf); - ivf->iloc = (int) loc; - return 0; - } - } -} // if (b->plc && (loc != INSTAR)) - - if (b->weighted || ivf->cdtflag || ivf->smlenflag - ) { - // There may be other vertices inside C(p). We need to find them. - // Collect all vertices of C(p). - for (i = 0; i < caveoldtetlist->objects; i++) { - cavetet = (triface *) fastlookup(caveoldtetlist, i); - //assert(infected(*cavetet)); - pts = (point *) &(cavetet->tet[4]); - for (j = 0; j < 4; j++) { - if (pts[j] != dummypoint) { - if (!pinfected(pts[j])) { - pinfect(pts[j]); - cavetetvertlist->newindex((void **) &parypt); - *parypt = pts[j]; - } - } - } // j - } // i - // Uninfect all collected (cavity) vertices. - for (i = 0; i < cavetetvertlist->objects; i++) { - parypt = (point *) fastlookup(cavetetvertlist, i); - puninfect(*parypt); - } - if (ivf->smlenflag) { - REAL len; - // Get the length of the shortest edge connecting to 'newpt'. - parypt = (point *) fastlookup(cavetetvertlist, 0); - ivf->smlen = distance(*parypt, insertpt); - ivf->parentpt = *parypt; - for (i = 1; i < cavetetvertlist->objects; i++) { - parypt = (point *) fastlookup(cavetetvertlist, i); - len = distance(*parypt, insertpt); - if (len < ivf->smlen) { - ivf->smlen = len; - ivf->parentpt = *parypt; - } - } - } - } - - - if (ivf->cdtflag) { - // Unmark tets. - for (i = 0; i < caveoldtetlist->objects; i++) { - cavetet = (triface *) fastlookup(caveoldtetlist, i); - unmarktest(*cavetet); - } - for (i = 0; i < cavebdrylist->objects; i++) { - cavetet = (triface *) fastlookup(cavebdrylist, i); - unmarktest(*cavetet); - } - // Clean up arrays which are not needed. - cavetetlist->restart(); - if (checksubsegflag) { - cavetetseglist->restart(); - } - if (checksubfaceflag) { - cavetetshlist->restart(); - } - return 1; - } - - // Before re-mesh C(p). Process the segments and subfaces which are on the - // boundary of C(p). Make sure that each such segment or subface is - // connecting to a tet outside C(p). So we can re-connect them to the - // new tets inside the C(p) later. - - if (checksubsegflag) { - for (i = 0; i < cavetetseglist->objects; i++) { - paryseg = (face *) fastlookup(cavetetseglist, i); - // Operate on it if it is not the splitting segment, i.e., in sC(p). - if (!smarktested(*paryseg)) { - // Check if the segment is inside the cavity. - // 'j' counts the num of adjacent tets of this seg. - // 'k' counts the num of adjacent tets which are 'sinfected'. - j = k = 0; - sstpivot1(*paryseg, neightet); - spintet = neightet; - while (1) { - j++; - if (!infected(spintet)) { - neineitet = spintet; // An outer tet. Remember it. - } else { - k++; // An in tet. - } - fnextself(spintet); - if (spintet.tet == neightet.tet) break; - } - // assert(j > 0); - if (k == 0) { - // The segment is not connect to C(p) anymore. Remove it by - // Replacing it by the last entry of this list. - s = cavetetseglist->objects - 1; - checkseg = * (face *) fastlookup(cavetetseglist, s); - *paryseg = checkseg; - cavetetseglist->objects--; - i--; - } else if (k < j) { - // The segment is on the boundary of C(p). - sstbond1(*paryseg, neineitet); - } else { // k == j - // The segment is inside C(p). - if (!ivf->splitbdflag) { - checkseg = *paryseg; - sinfect(checkseg); // Flag it as an interior segment. - caveencseglist->newindex((void **) &paryseg); - *paryseg = checkseg; - } else { - assert(0); // Not possible. - } - } - } else { - // assert(smarktested(*paryseg)); - // Flag it as an interior segment. Do not queue it, since it will - // be deleted after the segment splitting. - sinfect(*paryseg); - } - } // i - } // if (checksubsegflag) - - if (checksubfaceflag) { - for (i = 0; i < cavetetshlist->objects; i++) { - parysh = (face *) fastlookup(cavetetshlist, i); - // Operate on it if it is not inside the sub-cavity sC(p). - if (!smarktested(*parysh)) { - // Check if this subface is inside the cavity. - k = 0; - for (j = 0; j < 2; j++) { - stpivot(*parysh, neightet); - if (!infected(neightet)) { - checksh = *parysh; // Remember this side. - } else { - k++; - } - sesymself(*parysh); - } - if (k == 0) { - // The subface is not connected to C(p). Remove it. - s = cavetetshlist->objects - 1; - checksh = * (face *) fastlookup(cavetetshlist, s); - *parysh = checksh; - cavetetshlist->objects--; - i--; - } else if (k == 1) { - // This side is the outer boundary of C(p). - *parysh = checksh; - } else { // k == 2 - if (!ivf->splitbdflag) { - checksh = *parysh; - sinfect(checksh); // Flag it. - caveencshlist->newindex((void **) &parysh); - *parysh = checksh; - } else { - assert(0); // Not possible. - } - } - } else { - // assert(smarktested(*parysh)); - // Flag it as an interior subface. Do not queue it. It will be - // deleted after the facet point insertion. - sinfect(*parysh); - } - } // i - } // if (checksubfaceflag) - - // Create new tetrahedra to fill the cavity. - - for (i = 0; i < cavebdrylist->objects; i++) { - cavetet = (triface *) fastlookup(cavebdrylist, i); - neightet = *cavetet; - unmarktest(neightet); // Unmark it. - // Get the oldtet (inside the cavity). - fsym(neightet, oldtet); - if (apex(neightet) != dummypoint) { - // Create a new tet in the cavity. - maketetrahedron(&newtet); - setorg(newtet, dest(neightet)); - setdest(newtet, org(neightet)); - setapex(newtet, apex(neightet)); - setoppo(newtet, insertpt); - } else { - // Create a new hull tet. - hullsize++; - maketetrahedron(&newtet); - setorg(newtet, org(neightet)); - setdest(newtet, dest(neightet)); - setapex(newtet, insertpt); - setoppo(newtet, dummypoint); // It must opposite to face 3. - // Adjust back to the cavity bounday face. - esymself(newtet); - } - // The new tet inherits attribtes from the old tet. - for (j = 0; j < numelemattrib; j++) { - attrib = elemattribute(oldtet.tet, j); - setelemattribute(newtet.tet, j, attrib); - } - if (b->varvolume) { - volume = volumebound(oldtet.tet); - setvolumebound(newtet.tet, volume); - } - // Connect newtet <==> neightet, this also disconnect the old bond. - bond(newtet, neightet); - // oldtet still connects to neightet. - *cavetet = oldtet; // *cavetet = newtet; - } // i - - // Set a handle for speeding point location. - recenttet = newtet; - //setpoint2tet(insertpt, encode(newtet)); - setpoint2tet(insertpt, (tetrahedron) (newtet.tet)); - - // Re-use this list to save new interior cavity faces. - cavetetlist->restart(); - - // Connect adjacent new tetrahedra together. - for (i = 0; i < cavebdrylist->objects; i++) { - cavetet = (triface *) fastlookup(cavebdrylist, i); - // cavtet is an oldtet, get the newtet at this face. - oldtet = *cavetet; - fsym(oldtet, neightet); - fsym(neightet, newtet); - // Comment: oldtet and newtet must be at the same directed edge. - // Connect the three other faces of this newtet. - for (j = 0; j < 3; j++) { - esym(newtet, neightet); // Go to the face. - if (neightet.tet[neightet.ver & 3] == NULL) { - // Find the adjacent face of this newtet. - spintet = oldtet; - while (1) { - fnextself(spintet); - if (!infected(spintet)) break; - } - fsym(spintet, newneitet); - esymself(newneitet); - assert(newneitet.tet[newneitet.ver & 3] == NULL); - bond(neightet, newneitet); - if (ivf->lawson > 1) { - cavetetlist->newindex((void **) &parytet); - *parytet = neightet; - } - } - //setpoint2tet(org(newtet), encode(newtet)); - setpoint2tet(org(newtet), (tetrahedron) (newtet.tet)); - enextself(newtet); - enextself(oldtet); - } - *cavetet = newtet; // Save the new tet. - } // i - - if (checksubfaceflag) { - // Connect subfaces on the boundary of the cavity to the new tets. - for (i = 0; i < cavetetshlist->objects; i++) { - parysh = (face *) fastlookup(cavetetshlist, i); - // Connect it if it is not a missing subface. - if (!sinfected(*parysh)) { - stpivot(*parysh, neightet); - fsym(neightet, spintet); - sesymself(*parysh); - tsbond(spintet, *parysh); - } - } - } - - if (checksubsegflag) { - // Connect segments on the boundary of the cavity to the new tets. - for (i = 0; i < cavetetseglist->objects; i++) { - paryseg = (face *) fastlookup(cavetetseglist, i); - // Connect it if it is not a missing segment. - if (!sinfected(*paryseg)) { - sstpivot1(*paryseg, neightet); - spintet = neightet; - while (1) { - tssbond1(spintet, *paryseg); - fnextself(spintet); - if (spintet.tet == neightet.tet) break; - } - } - } - } - - if (((splitsh != NULL) && (splitsh->sh != NULL)) || - ((splitseg != NULL) && (splitseg->sh != NULL))) { - // Split a subface or a segment. - sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0); - } - - if (checksubfaceflag) { - if (ivf->splitbdflag) { - // Recover new subfaces in C(p). - for (i = 0; i < caveshbdlist->objects; i++) { - // Get an old subface at edge [a, b]. - parysh = (face *) fastlookup(caveshbdlist, i); - spivot(*parysh, checksh); // The new subface [a, b, p]. - // Do not recover a deleted new face (degenerated). - if (checksh.sh[3] != NULL) { - // Note that the old subface still connects to adjacent old tets - // of C(p), which still connect to the tets outside C(p). - stpivot(*parysh, neightet); - assert(infected(neightet)); - // Find the adjacent tet containing the edge [a,b] outside C(p). - spintet = neightet; - while (1) { - fnextself(spintet); - if (!infected(spintet)) break; - assert(spintet.tet != neightet.tet); - } - // The adjacent tet connects to a new tet in C(p). - fsym(spintet, neightet); - assert(!infected(neightet)); - // Find the tet containing the face [a, b, p]. - spintet = neightet; - while (1) { - fnextself(spintet); - if (apex(spintet) == insertpt) break; - assert(spintet.tet != neightet.tet); - } - // Adjust the edge direction in spintet and checksh. - if (sorg(checksh) != org(spintet)) { - sesymself(checksh); - assert(sorg(checksh) == org(spintet)); - } - assert(sdest(checksh) == dest(spintet)); - // Connect the subface to two adjacent tets. - tsbond(spintet, checksh); - fsymself(spintet); - sesymself(checksh); - tsbond(spintet, checksh); - } // if (checksh.sh[3] != NULL) - } - // There should be no missing interior subfaces in C(p). - assert(caveencshlist->objects == 0l); - } else { - // The Boundary recovery phase. - // Put all new subfaces into stack for recovery. - for (i = 0; i < caveshbdlist->objects; i++) { - // Get an old subface at edge [a, b]. - parysh = (face *) fastlookup(caveshbdlist, i); - spivot(*parysh, checksh); // The new subface [a, b, p]. - // Do not recover a deleted new face (degenerated). - if (checksh.sh[3] != NULL) { - subfacstack->newindex((void **) &parysh); - *parysh = checksh; - } - } - // Put all interior subfaces into stack for recovery. - for (i = 0; i < caveencshlist->objects; i++) { - parysh = (face *) fastlookup(caveencshlist, i); - assert(sinfected(*parysh)); - // Some subfaces inside C(p) might be split in sinsertvertex(). - // Only queue those faces which are not split. - if (!smarktested(*parysh)) { - checksh = *parysh; - suninfect(checksh); - stdissolve(checksh); // Detach connections to old tets. - subfacstack->newindex((void **) &parysh); - *parysh = checksh; - } - } - } - } // if (checksubfaceflag) - - if (checksubsegflag) { - if (ivf->splitbdflag) { - if (splitseg != NULL) { - // Recover the two new subsegments in C(p). - for (i = 0; i < cavesegshlist->objects; i++) { - paryseg = (face *) fastlookup(cavesegshlist, i); - // Insert this subsegment into C(p). - checkseg = *paryseg; - // Get the adjacent new subface. - checkseg.shver = 0; - spivot(checkseg, checksh); - if (checksh.sh != NULL) { - // Get the adjacent new tetrahedron. - stpivot(checksh, neightet); - } else { - // It's a dangling segment. - point2tetorg(sorg(checkseg), neightet); - finddirection(&neightet, sdest(checkseg)); - assert(dest(neightet) == sdest(checkseg)); - } - assert(!infected(neightet)); - sstbond1(checkseg, neightet); - spintet = neightet; - while (1) { - tssbond1(spintet, checkseg); - fnextself(spintet); - if (spintet.tet == neightet.tet) break; - } - } - } // if (splitseg != NULL) - // There should be no interior segment in C(p). - assert(caveencseglist->objects == 0l); - } else { - // The Boundary Recovery Phase. - // Queue missing segments in C(p) for recovery. - if (splitseg != NULL) { - // Queue two new subsegments in C(p) for recovery. - for (i = 0; i < cavesegshlist->objects; i++) { - paryseg = (face *) fastlookup(cavesegshlist, i); - checkseg = *paryseg; - //sstdissolve1(checkseg); // It has not been connected yet. - s = randomnation(subsegstack->objects + 1); - subsegstack->newindex((void **) &paryseg); - *paryseg = * (face *) fastlookup(subsegstack, s); - paryseg = (face *) fastlookup(subsegstack, s); - *paryseg = checkseg; - } - } // if (splitseg != NULL) - for (i = 0; i < caveencseglist->objects; i++) { - paryseg = (face *) fastlookup(caveencseglist, i); - assert(sinfected(*paryseg)); - if (!smarktested(*paryseg)) { // It may be split. - checkseg = *paryseg; - suninfect(checkseg); - sstdissolve1(checkseg); // Detach connections to old tets. - s = randomnation(subsegstack->objects + 1); - subsegstack->newindex((void **) &paryseg); - *paryseg = * (face *) fastlookup(subsegstack, s); - paryseg = (face *) fastlookup(subsegstack, s); - *paryseg = checkseg; - } - } - } - } // if (checksubsegflag) - - if (b->weighted - ) { - // Some vertices may be completed inside the cavity. They must be - // detected and added to recovering list. - // Since every "live" vertex must contain a pointer to a non-dead - // tetrahedron, we can check for each vertex this pointer. - for (i = 0; i < cavetetvertlist->objects; i++) { - pts = (point *) fastlookup(cavetetvertlist, i); - decode(point2tet(*pts), *searchtet); - assert(searchtet->tet != NULL); // No tet has been deleted yet. - if (infected(*searchtet)) { - if (b->weighted) { - Msg::Debug(" Point #%d is non-regular after the insertion of #%d.", - pointmark(*pts), pointmark(insertpt)); - setpointtype(*pts, NREGULARVERTEX); - nonregularcount++; - } - } - } - } - - if (ivf->chkencflag & 1) { - // Queue all segment outside C(p). - for (i = 0; i < cavetetseglist->objects; i++) { - paryseg = (face *) fastlookup(cavetetseglist, i); - // Skip if it is the split segment. - if (!sinfected(*paryseg)) { - //enqueuesubface(badsubsegs, paryseg); - } - } - if (splitseg != NULL) { - // Queue the two new subsegments inside C(p). - for (i = 0; i < cavesegshlist->objects; i++) { - paryseg = (face *) fastlookup(cavesegshlist, i); - //enqueuesubface(badsubsegs, paryseg); - } - } - } // if (chkencflag & 1) - - if (ivf->chkencflag & 2) { - // Queue all subfaces outside C(p). - for (i = 0; i < cavetetshlist->objects; i++) { - parysh = (face *) fastlookup(cavetetshlist, i); - // Skip if it is a split subface. - if (!sinfected(*parysh)) { - //enqueuesubface(badsubfacs, parysh); - } - } - // Queue all new subfaces inside C(p). - for (i = 0; i < caveshbdlist->objects; i++) { - // Get an old subface at edge [a, b]. - parysh = (face *) fastlookup(caveshbdlist, i); - spivot(*parysh, checksh); // checksh is a new subface [a, b, p]. - // Do not recover a deleted new face (degenerated). - if (checksh.sh[3] != NULL) { - //enqueuesubface(badsubfacs, &checksh); - } - } - } // if (chkencflag & 2) - - if (ivf->chkencflag & 4) { - // Queue all new tetrahedra in C(p). - for (i = 0; i < cavebdrylist->objects; i++) { - cavetet = (triface *) fastlookup(cavebdrylist, i); - //enqueuetetrahedron(cavetet); - } - } - - // C(p) is re-meshed successfully. - - // Delete the old tets in C(p). - for (i = 0; i < caveoldtetlist->objects; i++) { - searchtet = (triface *) fastlookup(caveoldtetlist, i); - if (ishulltet(*searchtet)) { - hullsize--; - } - tetrahedrondealloc(searchtet->tet); - } - - if (((splitsh != NULL) && (splitsh->sh != NULL)) || - ((splitseg != NULL) && (splitseg->sh != NULL))) { - // Delete the old subfaces in sC(p). - for (i = 0; i < caveshlist->objects; i++) { - parysh = (face *) fastlookup(caveshlist, i); - if (checksubfaceflag) {//if (bowywat == 2) { - // It is possible that this subface still connects to adjacent - // tets which are not in C(p). If so, clear connections in the - // adjacent tets at this subface. - stpivot(*parysh, neightet); - if (neightet.tet != NULL) { - if (neightet.tet[4] != NULL) { - // Found an adjacent tet. It must be not in C(p). - assert(!infected(neightet)); - tsdissolve(neightet); - fsymself(neightet); - assert(!infected(neightet)); - tsdissolve(neightet); - } - } - } - shellfacedealloc(subfaces, parysh->sh); - } - if ((splitseg != NULL) && (splitseg->sh != NULL)) { - // Delete the old segment in sC(p). - shellfacedealloc(subsegs, splitseg->sh); - } - } - - if (ivf->lawson) { - for (i = 0; i < cavebdrylist->objects; i++) { - searchtet = (triface *) fastlookup(cavebdrylist, i); - flippush(flipstack, searchtet); - } - if (ivf->lawson > 1) { - for (i = 0; i < cavetetlist->objects; i++) { - searchtet = (triface *) fastlookup(cavetetlist, i); - flippush(flipstack, searchtet); - } - } - } - - - // Clean the working lists. - - caveoldtetlist->restart(); - cavebdrylist->restart(); - cavetetlist->restart(); - - if (checksubsegflag) { - cavetetseglist->restart(); - caveencseglist->restart(); - } - - if (checksubfaceflag) { - cavetetshlist->restart(); - caveencshlist->restart(); - } - - if (b->weighted || ivf->validflag) { - cavetetvertlist->restart(); - } - - if (((splitsh != NULL) && (splitsh->sh != NULL)) || - ((splitseg != NULL) && (splitseg->sh != NULL))) { - caveshlist->restart(); - caveshbdlist->restart(); - cavesegshlist->restart(); - } - - return 1; // Point is inserted. -} - -void meshGRegionBoundaryRecovery::insertpoint_abort(face *splitseg, insertvertexflags *ivf) -{ - triface *cavetet; - face *parysh; - int i; - - for (i = 0; i < caveoldtetlist->objects; i++) { - cavetet = (triface *) fastlookup(caveoldtetlist, i); - uninfect(*cavetet); - unmarktest(*cavetet); - } - for (i = 0; i < cavebdrylist->objects; i++) { - cavetet = (triface *) fastlookup(cavebdrylist, i); - unmarktest(*cavetet); - } - cavetetlist->restart(); - cavebdrylist->restart(); - caveoldtetlist->restart(); - cavetetseglist->restart(); - cavetetshlist->restart(); - if (ivf->splitbdflag) { - if ((splitseg != NULL) && (splitseg->sh != NULL)) { - sunmarktest(*splitseg); - } - for (i = 0; i < caveshlist->objects; i++) { - parysh = (face *) fastlookup(caveshlist, i); - assert(smarktested(*parysh)); - sunmarktest(*parysh); - } - caveshlist->restart(); - cavesegshlist->restart(); - } -} - -//// //// -//// //// -//// flip_cxx ///////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// // -// hilbert_init() Initialize the Gray code permutation table. // -// // -// The table 'transgc' has 8 x 3 x 8 entries. It contains all possible Gray // -// code sequences traveled by the 1st order Hilbert curve in 3 dimensions. // -// The first column is the Gray code of the entry point of the curve, and // -// the second column is the direction (0, 1, or 2, 0 means the x-axis) where // -// the exit point of curve lies. // -// // -// The table 'tsb1mod3' contains the numbers of trailing set '1' bits of the // -// indices from 0 to 7, modulo by '3'. The code for generating this table is // -// from: http://graphics.stanford.edu/~seander/bithacks.html. // -// // -/////////////////////////////////////////////////////////////////////////////// - -void meshGRegionBoundaryRecovery::hilbert_init(int n) -{ - int gc[8], N, mask, travel_bit; - int e, d, f, k, g; - int v, c; - int i; - - N = (n == 2) ? 4 : 8; - mask = (n == 2) ? 3 : 7; - - // Generate the Gray code sequence. - for (i = 0; i < N; i++) { - gc[i] = i ^ (i >> 1); - } - - for (e = 0; e < N; e++) { - for (d = 0; d < n; d++) { - // Calculate the end point (f). - f = e ^ (1 << d); // Toggle the d-th bit of 'e'. - // travel_bit = 2**p, the bit we want to travel. - travel_bit = e ^ f; - for (i = 0; i < N; i++) { - // // Rotate gc[i] left by (p + 1) % n bits. - k = gc[i] * (travel_bit * 2); - g = ((k | (k / N)) & mask); - // Calculate the permuted Gray code by xor with the start point (e). - transgc[e][d][i] = (g ^ e); - } - assert(transgc[e][d][0] == e); - assert(transgc[e][d][N - 1] == f); - } // d - } // e - - // Count the consecutive '1' bits (trailing) on the right. - tsb1mod3[0] = 0; - for (i = 1; i < N; i++) { - v = ~i; // Count the 0s. - v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest - for (c = 0; v; c++) { - v >>= 1; - } - tsb1mod3[i] = c % n; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// hilbert_sort3() Sort points using the 3d Hilbert curve. // -// // -/////////////////////////////////////////////////////////////////////////////// - -int meshGRegionBoundaryRecovery::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1, - REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, - REAL bzmin, REAL bzmax) -{ - point swapvert; - int axis, d; - REAL split; - int i, j; - - - // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which - // correspoding to x-, or y- or z-axis. - axis = (gc0 ^ gc1) >> 1; - - // Calulate the split position along the axis. - if (axis == 0) { - split = 0.5 * (bxmin + bxmax); - } else if (axis == 1) { - split = 0.5 * (bymin + bymax); - } else { // == 2 - split = 0.5 * (bzmin + bzmax); - } - - // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction - // of the axis is to the positive of the axis, otherwise, it is -1. - d = ((gc0 & (1<<axis)) == 0) ? 1 : -1; - - - // Partition the vertices into left- and right-arrays such that left points - // have Hilbert indices lower than the right points. - i = 0; - j = arraysize - 1; - - // Partition the vertices into left- and right-arrays. - if (d > 0) { - do { - for (; i < arraysize; i++) { - if (vertexarray[i][axis] >= split) break; - } - for (; j >= 0; j--) { - if (vertexarray[j][axis] < split) break; - } - // Is the partition finished? - if (i == (j + 1)) break; - // Swap i-th and j-th vertices. - swapvert = vertexarray[i]; - vertexarray[i] = vertexarray[j]; - vertexarray[j] = swapvert; - // Continue patitioning the array; - } while (true); - } else { - do { - for (; i < arraysize; i++) { - if (vertexarray[i][axis] <= split) break; - } - for (; j >= 0; j--) { - if (vertexarray[j][axis] > split) break; - } - // Is the partition finished? - if (i == (j + 1)) break; - // Swap i-th and j-th vertices. - swapvert = vertexarray[i]; - vertexarray[i] = vertexarray[j]; - vertexarray[j] = swapvert; - // Continue patitioning the array; - } while (true); - } - - return i; -} - -void meshGRegionBoundaryRecovery::hilbert_sort3(point* vertexarray, int arraysize, int e, int d, - REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, - REAL bzmin, REAL bzmax, int depth) -{ - REAL x1, x2, y1, y2, z1, z2; - int p[9], w, e_w, d_w, k, ei, di; - int n = 3, mask = 7; - - p[0] = 0; - p[8] = arraysize; - - // Sort the points according to the 1st order Hilbert curve in 3d. - p[4] = hilbert_split(vertexarray, p[8], transgc[e][d][3], transgc[e][d][4], - bxmin, bxmax, bymin, bymax, bzmin, bzmax); - p[2] = hilbert_split(vertexarray, p[4], transgc[e][d][1], transgc[e][d][2], - bxmin, bxmax, bymin, bymax, bzmin, bzmax); - p[1] = hilbert_split(vertexarray, p[2], transgc[e][d][0], transgc[e][d][1], - bxmin, bxmax, bymin, bymax, bzmin, bzmax); - p[3] = hilbert_split(&(vertexarray[p[2]]), p[4] - p[2], - transgc[e][d][2], transgc[e][d][3], - bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[2]; - p[6] = hilbert_split(&(vertexarray[p[4]]), p[8] - p[4], - transgc[e][d][5], transgc[e][d][6], - bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4]; - p[5] = hilbert_split(&(vertexarray[p[4]]), p[6] - p[4], - transgc[e][d][4], transgc[e][d][5], - bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4]; - p[7] = hilbert_split(&(vertexarray[p[6]]), p[8] - p[6], - transgc[e][d][6], transgc[e][d][7], - bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[6]; - - if (b->hilbert_order > 0) { - // A maximum order is prescribed. - if ((depth + 1) == b->hilbert_order) { - // The maximum prescribed order is reached. - return; - } - } - - // Recursively sort the points in sub-boxes. - for (w = 0; w < 8; w++) { - // w is the local Hilbert index (NOT Gray code). - // Sort into the sub-box either there are more than 2 points in it, or - // the prescribed order of the curve is not reached yet. - //if ((p[w+1] - p[w] > b->hilbert_limit) || (b->hilbert_order > 0)) { - if ((p[w+1] - p[w]) > b->hilbert_limit) { - // Calculcate the start point (ei) of the curve in this sub-box. - // update e = e ^ (e(w) left_rotate (d+1)). - if (w == 0) { - e_w = 0; - } else { - // calculate e(w) = gc(2 * floor((w - 1) / 2)). - k = 2 * ((w - 1) / 2); - e_w = k ^ (k >> 1); // = gc(k). - } - k = e_w; - e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask); - ei = e ^ e_w; - // Calulcate the direction (di) of the curve in this sub-box. - // update d = (d + d(w) + 1) % n - if (w == 0) { - d_w = 0; - } else { - d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w]; - } - di = (d + d_w + 1) % n; - // Calculate the bounding box of the sub-box. - if (transgc[e][d][w] & 1) { // x-axis - x1 = 0.5 * (bxmin + bxmax); - x2 = bxmax; - } else { - x1 = bxmin; - x2 = 0.5 * (bxmin + bxmax); - } - if (transgc[e][d][w] & 2) { // y-axis - y1 = 0.5 * (bymin + bymax); - y2 = bymax; - } else { - y1 = bymin; - y2 = 0.5 * (bymin + bymax); - } - if (transgc[e][d][w] & 4) { // z-axis - z1 = 0.5 * (bzmin + bzmax); - z2 = bzmax; - } else { - z1 = bzmin; - z2 = 0.5 * (bzmin + bzmax); - } - hilbert_sort3(&(vertexarray[p[w]]), p[w+1] - p[w], ei, di, - x1, x2, y1, y2, z1, z2, depth+1); - } // if (p[w+1] - p[w] > 1) - } // w -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// brio_multiscale_sort() Sort the points using BRIO and Hilbert curve. // -// // -/////////////////////////////////////////////////////////////////////////////// - -void meshGRegionBoundaryRecovery::brio_multiscale_sort(point* vertexarray, int arraysize, - int threshold, REAL ratio, int *depth) -{ - int middle; - - middle = 0; - if (arraysize >= threshold) { - (*depth)++; - middle = arraysize * ratio; - brio_multiscale_sort(vertexarray, middle, threshold, ratio, depth); - } - // Sort the right-array (rnd-th round) using the Hilbert curve. - hilbert_sort3(&(vertexarray[middle]), arraysize - middle, 0, 0, // e, d - xmin, xmax, ymin, ymax, zmin, zmax, 0); // depth. -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// randomnation() Generate a random number between 0 and 'choices' - 1. // -// // -/////////////////////////////////////////////////////////////////////////////// - -unsigned long meshGRegionBoundaryRecovery::randomnation(unsigned int choices) -{ - unsigned long newrandom; - - if (choices >= 714025l) { - newrandom = (randomseed * 1366l + 150889l) % 714025l; - randomseed = (newrandom * 1366l + 150889l) % 714025l; - newrandom = newrandom * (choices / 714025l) + randomseed; - if (newrandom >= choices) { - return newrandom - choices; - } else { - return newrandom; - } - } else { - randomseed = (randomseed * 1366l + 150889l) % 714025l; - return randomseed % choices; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// randomsample() Randomly sample the tetrahedra for point loation. // -// // -// Searching begins from one of handles: the input 'searchtet', a recently // -// encountered tetrahedron 'recenttet', or from one chosen from a random // -// sample. The choice is made by determining which one's origin is closest // -// to the point we are searching for. // -// // -/////////////////////////////////////////////////////////////////////////////// - -void meshGRegionBoundaryRecovery::randomsample(point searchpt,triface *searchtet) -{ - tetrahedron *firsttet, *tetptr; - point torg; - void **sampleblock; - uintptr_t alignptr; - long sampleblocks, samplesperblock, samplenum; - long tetblocks, i, j; - REAL searchdist, dist; - - if (b->verbose > 2) { - printf(" Random sampling tetrahedra for searching point %d.\n", - pointmark(searchpt)); - } - - if (!nonconvex) { - if (searchtet->tet == NULL) { - // A null tet. Choose the recenttet as the starting tet. - *searchtet = recenttet; - // Recenttet should not be dead. - assert(recenttet.tet[4] != NULL); - } - - // 'searchtet' should be a valid tetrahedron. Choose the base face - // whose vertices must not be 'dummypoint'. - searchtet->ver = 3; - // Record the distance from its origin to the searching point. - torg = org(*searchtet); - searchdist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) + - (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) + - (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]); - - // If a recently encountered tetrahedron has been recorded and has not - // been deallocated, test it as a good starting point. - if (recenttet.tet != searchtet->tet) { - recenttet.ver = 3; - torg = org(recenttet); - dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) + - (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) + - (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]); - if (dist < searchdist) { - *searchtet = recenttet; - searchdist = dist; - } - } - } else { - // The mesh is non-convex. Do not use 'recenttet'. - assert(samples >= 1l); // Make sure at least 1 sample. - searchdist = longest; - } - - // Select "good" candidate using k random samples, taking the closest one. - // The number of random samples taken is proportional to the fourth root - // of the number of tetrahedra in the mesh. - while (samples * samples * samples * samples < tetrahedrons->items) { - samples++; - } - // Find how much blocks in current tet pool. - tetblocks = (tetrahedrons->maxitems + b->tetrahedraperblock - 1) - / b->tetrahedraperblock; - // Find the average samples per block. Each block at least have 1 sample. - samplesperblock = 1 + (samples / tetblocks); - sampleblocks = samples / samplesperblock; - sampleblock = tetrahedrons->firstblock; - for (i = 0; i < sampleblocks; i++) { - alignptr = (uintptr_t) (sampleblock + 1); - firsttet = (tetrahedron *) - (alignptr + (uintptr_t) tetrahedrons->alignbytes - - (alignptr % (uintptr_t) tetrahedrons->alignbytes)); - for (j = 0; j < samplesperblock; j++) { - if (i == tetblocks - 1) { - // This is the last block. - samplenum = randomnation((int) - (tetrahedrons->maxitems - (i * b->tetrahedraperblock))); - } else { - samplenum = randomnation(b->tetrahedraperblock); - } - tetptr = (tetrahedron *) - (firsttet + (samplenum * tetrahedrons->itemwords)); - torg = (point) tetptr[4]; - if (torg != (point) NULL) { - dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) + - (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) + - (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]); - if (dist < searchdist) { - searchtet->tet = tetptr; - searchtet->ver = 11; // torg = org(t); - searchdist = dist; - } - } else { - // A dead tet. Re-sample it. - if (i != tetblocks - 1) j--; - } - } - sampleblock = (void **) *sampleblock; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// locate() Find a tetrahedron containing a given point. // -// // -// Begins its search from 'searchtet', assume there is a line segment L from // -// a vertex of 'searchtet' to the query point 'searchpt', and simply walk // -// towards 'searchpt' by traversing all faces intersected by L. // -// // -// On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The // -// returned value indicates one of the following cases: // -// - ONVERTEX, the search point lies on the origin of 'searchtet'. // -// - ONEDGE, the search point lies on an edge of 'searchtet'. // -// - ONFACE, the search point lies on a face of 'searchtet'. // -// - INTET, the search point lies in the interior of 'searchtet'. // -// - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a // -// hull face which is visible by the search point. // -// // -// WARNING: This routine is designed for convex triangulations, and will not // -// generally work after the holes and concavities have been carved. // -// // -/////////////////////////////////////////////////////////////////////////////// - -enum meshGRegionBoundaryRecovery::locateresult meshGRegionBoundaryRecovery::locate(point searchpt, - triface* searchtet) -{ - point torg, tdest, tapex, toppo; - enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove; - REAL ori, oriorg, oridest, oriapex; - enum locateresult loc = OUTSIDE; - int t1ver; - int s; - - if (searchtet->tet == NULL) { - // A null tet. Choose the recenttet as the starting tet. - searchtet->tet = recenttet.tet; - } - - // Check if we are in the outside of the convex hull. - if (ishulltet(*searchtet)) { - // Get its adjacent tet (inside the hull). - searchtet->ver = 3; - fsymself(*searchtet); - } - - // Let searchtet be the face such that 'searchpt' lies above to it. - for (searchtet->ver = 0; searchtet->ver < 4; searchtet->ver++) { - torg = org(*searchtet); - tdest = dest(*searchtet); - tapex = apex(*searchtet); - ori = orient3d(torg, tdest, tapex, searchpt); - if (ori < 0.0) break; - } - assert(searchtet->ver != 4); - - // Walk through tetrahedra to locate the point. - while (true) { - - toppo = oppo(*searchtet); - - // Check if the vertex is we seek. - if (toppo == searchpt) { - // Adjust the origin of searchtet to be searchpt. - esymself(*searchtet); - eprevself(*searchtet); - loc = ONVERTEX; // return ONVERTEX; - break; - } - - // We enter from one of serarchtet's faces, which face do we exit? - oriorg = orient3d(tdest, tapex, toppo, searchpt); - oridest = orient3d(tapex, torg, toppo, searchpt); - oriapex = orient3d(torg, tdest, toppo, searchpt); - - // Now decide which face to move. It is possible there are more than one - // faces are viable moves. If so, randomly choose one. - if (oriorg < 0) { - if (oridest < 0) { - if (oriapex < 0) { - // All three faces are possible. - s = randomnation(3); // 's' is in {0,1,2}. - if (s == 0) { - nextmove = ORGMOVE; - } else if (s == 1) { - nextmove = DESTMOVE; - } else { - nextmove = APEXMOVE; - } - } else { - // Two faces, opposite to origin and destination, are viable. - //s = randomnation(2); // 's' is in {0,1}. - if (randomnation(2)) { - nextmove = ORGMOVE; - } else { - nextmove = DESTMOVE; - } - } - } else { - if (oriapex < 0) { - // Two faces, opposite to origin and apex, are viable. - //s = randomnation(2); // 's' is in {0,1}. - if (randomnation(2)) { - nextmove = ORGMOVE; - } else { - nextmove = APEXMOVE; - } - } else { - // Only the face opposite to origin is viable. - nextmove = ORGMOVE; - } - } - } else { - if (oridest < 0) { - if (oriapex < 0) { - // Two faces, opposite to destination and apex, are viable. - //s = randomnation(2); // 's' is in {0,1}. - if (randomnation(2)) { - nextmove = DESTMOVE; - } else { - nextmove = APEXMOVE; - } - } else { - // Only the face opposite to destination is viable. - nextmove = DESTMOVE; - } - } else { - if (oriapex < 0) { - // Only the face opposite to apex is viable. - nextmove = APEXMOVE; - } else { - // The point we seek must be on the boundary of or inside this - // tetrahedron. Check for boundary cases. - if (oriorg == 0) { - // Go to the face opposite to origin. - enextesymself(*searchtet); - if (oridest == 0) { - eprevself(*searchtet); // edge oppo->apex - if (oriapex == 0) { - // oppo is duplicated with p. - loc = ONVERTEX; // return ONVERTEX; - break; - } - loc = ONEDGE; // return ONEDGE; - break; - } - if (oriapex == 0) { - enextself(*searchtet); // edge dest->oppo - loc = ONEDGE; // return ONEDGE; - break; - } - loc = ONFACE; // return ONFACE; - break; - } - if (oridest == 0) { - // Go to the face opposite to destination. - eprevesymself(*searchtet); - if (oriapex == 0) { - eprevself(*searchtet); // edge oppo->org - loc = ONEDGE; // return ONEDGE; - break; - } - loc = ONFACE; // return ONFACE; - break; - } - if (oriapex == 0) { - // Go to the face opposite to apex - esymself(*searchtet); - loc = ONFACE; // return ONFACE; - break; - } - loc = INTETRAHEDRON; // return INTETRAHEDRON; - break; - } - } - } - - // Move to the selected face. - if (nextmove == ORGMOVE) { - enextesymself(*searchtet); - } else if (nextmove == DESTMOVE) { - eprevesymself(*searchtet); - } else { - esymself(*searchtet); - } - // Move to the adjacent tetrahedron (maybe a hull tetrahedron). - fsymself(*searchtet); - if (oppo(*searchtet) == dummypoint) { - loc = OUTSIDE; // return OUTSIDE; - break; - } - - // Retreat the three vertices of the base face. - torg = org(*searchtet); - tdest = dest(*searchtet); - tapex = apex(*searchtet); - - } // while (true) - - return loc; -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// flippush() Push a face (possibly will be flipped) into flipstack. // -// // -// The face is marked. The flag is used to check the validity of the face on // -// its popup. Some other flips may change it already. // -// // -/////////////////////////////////////////////////////////////////////////////// - -void meshGRegionBoundaryRecovery::flippush(badface*& fstack, triface* flipface) -{ - if (!facemarked(*flipface)) { - badface *newflipface = (badface *) flippool->alloc(); - newflipface->tt = *flipface; - markface(newflipface->tt); - // Push this face into stack. - newflipface->nextitem = fstack; - fstack = newflipface; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// initialdelaunay() Create an initial Delaunay tetrahedralization. // -// // -// The tetrahedralization contains only one tetrahedron abcd, and four hull // -// tetrahedra. The points pa, pb, pc, and pd must be linearly independent. // -// // -/////////////////////////////////////////////////////////////////////////////// - -void meshGRegionBoundaryRecovery::initialdelaunay(point pa, point pb, point pc, point pd) -{ - triface firsttet, tetopa, tetopb, tetopc, tetopd; - triface worktet, worktet1; - - if (b->verbose > 2) { - printf(" Create init tet (%d, %d, %d, %d)\n", pointmark(pa), - pointmark(pb), pointmark(pc), pointmark(pd)); - } - - // Create the first tetrahedron. - maketetrahedron(&firsttet); - setvertices(firsttet, pa, pb, pc, pd); - // Create four hull tetrahedra. - maketetrahedron(&tetopa); - setvertices(tetopa, pb, pc, pd, dummypoint); - maketetrahedron(&tetopb); - setvertices(tetopb, pc, pa, pd, dummypoint); - maketetrahedron(&tetopc); - setvertices(tetopc, pa, pb, pd, dummypoint); - maketetrahedron(&tetopd); - setvertices(tetopd, pb, pa, pc, dummypoint); - hullsize += 4; - - // Connect hull tetrahedra to firsttet (at four faces of firsttet). - bond(firsttet, tetopd); - esym(firsttet, worktet); - bond(worktet, tetopc); // ab - enextesym(firsttet, worktet); - bond(worktet, tetopa); // bc - eprevesym(firsttet, worktet); - bond(worktet, tetopb); // ca - - // Connect hull tetrahedra together (at six edges of firsttet). - esym(tetopc, worktet); - esym(tetopd, worktet1); - bond(worktet, worktet1); // ab - esym(tetopa, worktet); - eprevesym(tetopd, worktet1); - bond(worktet, worktet1); // bc - esym(tetopb, worktet); - enextesym(tetopd, worktet1); - bond(worktet, worktet1); // ca - eprevesym(tetopc, worktet); - enextesym(tetopb, worktet1); - bond(worktet, worktet1); // da - eprevesym(tetopa, worktet); - enextesym(tetopc, worktet1); - bond(worktet, worktet1); // db - eprevesym(tetopb, worktet); - enextesym(tetopa, worktet1); - bond(worktet, worktet1); // dc - - // Set the vertex type. - if (pointtype(pa) == UNUSEDVERTEX) { - setpointtype(pa, VOLVERTEX); - } - if (pointtype(pb) == UNUSEDVERTEX) { - setpointtype(pb, VOLVERTEX); - } - if (pointtype(pc) == UNUSEDVERTEX) { - setpointtype(pc, VOLVERTEX); - } - if (pointtype(pd) == UNUSEDVERTEX) { - setpointtype(pd, VOLVERTEX); - } - - setpoint2tet(pa, encode(firsttet)); - setpoint2tet(pb, encode(firsttet)); - setpoint2tet(pc, encode(firsttet)); - setpoint2tet(pd, encode(firsttet)); - - // Remember the first tetrahedron. - recenttet = firsttet; -} - -//// //// -//// //// -//// delaunay_cxx ///////////////////////////////////////////////////////////// - -//// surface_cxx ////////////////////////////////////////////////////////////// -//// //// -//// //// - -void meshGRegionBoundaryRecovery::flipshpush(face* flipedge) -{ - badface *newflipface; - - newflipface = (badface *) flippool->alloc(); - newflipface->ss = *flipedge; - newflipface->forg = sorg(*flipedge); - newflipface->fdest = sdest(*flipedge); - newflipface->nextitem = flipstack; - flipstack = newflipface; -} - -void meshGRegionBoundaryRecovery::flip22(face* flipfaces, int flipflag, - int chkencflag) -{ - face bdedges[4], outfaces[4], infaces[4]; - face bdsegs[4]; - face checkface; - point pa, pb, pc, pd; - int i; - - pa = sorg(flipfaces[0]); - pb = sdest(flipfaces[0]); - pc = sapex(flipfaces[0]); - pd = sapex(flipfaces[1]); - - if (sorg(flipfaces[1]) != pb) { - sesymself(flipfaces[1]); - } - - flip22count++; - - // Collect the four boundary edges. - senext(flipfaces[0], bdedges[0]); - senext2(flipfaces[0], bdedges[1]); - senext(flipfaces[1], bdedges[2]); - senext2(flipfaces[1], bdedges[3]); - - // Collect outer boundary faces. - for (i = 0; i < 4; i++) { - spivot(bdedges[i], outfaces[i]); - infaces[i] = outfaces[i]; - sspivot(bdedges[i], bdsegs[i]); - if (outfaces[i].sh != NULL) { - if (isshsubseg(bdedges[i])) { - spivot(infaces[i], checkface); - while (checkface.sh != bdedges[i].sh) { - infaces[i] = checkface; - spivot(infaces[i], checkface); - } - } - } - } - - // The flags set in these two subfaces do not change. - // Shellmark does not change. - // area constraint does not change. - - // Transform [a,b,c] -> [c,d,b]. - setshvertices(flipfaces[0], pc, pd, pb); - // Transform [b,a,d] -> [d,c,a]. - setshvertices(flipfaces[1], pd, pc, pa); - - // Update the point-to-subface map. - if (pointtype(pa) == FREEFACETVERTEX) { - setpoint2sh(pa, sencode(flipfaces[1])); - } - if (pointtype(pb) == FREEFACETVERTEX) { - setpoint2sh(pb, sencode(flipfaces[0])); - } - if (pointtype(pc) == FREEFACETVERTEX) { - setpoint2sh(pc, sencode(flipfaces[0])); - } - if (pointtype(pd) == FREEFACETVERTEX) { - setpoint2sh(pd, sencode(flipfaces[0])); - } - - // Reconnect boundary edges to outer boundary faces. - for (i = 0; i < 4; i++) { - if (outfaces[(3 + i) % 4].sh != NULL) { - // Make sure that the subface has the ori as the segment. - if (bdsegs[(3 + i) % 4].sh != NULL) { - bdsegs[(3 + i) % 4].shver = 0; - if (sorg(bdedges[i]) != sorg(bdsegs[(3 + i) % 4])) { - sesymself(bdedges[i]); - } - } - sbond1(bdedges[i], outfaces[(3 + i) % 4]); - sbond1(infaces[(3 + i) % 4], bdedges[i]); - } else { - sdissolve(bdedges[i]); - } - if (bdsegs[(3 + i) % 4].sh != NULL) { - ssbond(bdedges[i], bdsegs[(3 + i) % 4]); - if (chkencflag & 1) { - // Queue this segment for encroaching check. - //enqueuesubface(badsubsegs, &(bdsegs[(3 + i) % 4])); - } - } else { - ssdissolve(bdedges[i]); - } - } - - if (chkencflag & 2) { - // Queue the flipped subfaces for quality/encroaching checks. - for (i = 0; i < 2; i++) { - //enqueuesubface(badsubfacs, &(flipfaces[i])); - } - } - - recentsh = flipfaces[0]; - - if (flipflag) { - // Put the boundary edges into flip stack. - for (i = 0; i < 4; i++) { - flipshpush(&(bdedges[i])); - } - } -} - -void meshGRegionBoundaryRecovery::flip31(face* flipfaces, int flipflag) -{ - face bdedges[3], outfaces[3], infaces[3]; - face bdsegs[3]; - face checkface; - point pa, pb, pc; - int i; - - pa = sdest(flipfaces[0]); - pb = sdest(flipfaces[1]); - pc = sdest(flipfaces[2]); - - flip31count++; - - // Collect all infos at the three boundary edges. - for (i = 0; i < 3; i++) { - senext(flipfaces[i], bdedges[i]); - spivot(bdedges[i], outfaces[i]); - infaces[i] = outfaces[i]; - sspivot(bdedges[i], bdsegs[i]); - if (outfaces[i].sh != NULL) { - if (isshsubseg(bdedges[i])) { - spivot(infaces[i], checkface); - while (checkface.sh != bdedges[i].sh) { - infaces[i] = checkface; - spivot(infaces[i], checkface); - } - } - } - } // i - - // Create a new subface. - makeshellface(subfaces, &(flipfaces[3])); - setshvertices(flipfaces[3], pa, pb,pc); - setshellmark(flipfaces[3], shellmark(flipfaces[0])); - if (checkconstraints) { - //area = areabound(flipfaces[0]); - setareabound(flipfaces[3], areabound(flipfaces[0])); - } - if (useinsertradius) { - setfacetindex(flipfaces[3], getfacetindex(flipfaces[0])); - } - - // Update the point-to-subface map. - if (pointtype(pa) == FREEFACETVERTEX) { - setpoint2sh(pa, sencode(flipfaces[3])); - } - if (pointtype(pb) == FREEFACETVERTEX) { - setpoint2sh(pb, sencode(flipfaces[3])); - } - if (pointtype(pc) == FREEFACETVERTEX) { - setpoint2sh(pc, sencode(flipfaces[3])); - } - - // Update the three new boundary edges. - bdedges[0] = flipfaces[3]; // [a,b] - senext(flipfaces[3], bdedges[1]); // [b,c] - senext2(flipfaces[3], bdedges[2]); // [c,a] - - // Reconnect boundary edges to outer boundary faces. - for (i = 0; i < 3; i++) { - if (outfaces[i].sh != NULL) { - // Make sure that the subface has the ori as the segment. - if (bdsegs[i].sh != NULL) { - bdsegs[i].shver = 0; - if (sorg(bdedges[i]) != sorg(bdsegs[i])) { - sesymself(bdedges[i]); - } - } - sbond1(bdedges[i], outfaces[i]); - sbond1(infaces[i], bdedges[i]); - } - if (bdsegs[i].sh != NULL) { - ssbond(bdedges[i], bdsegs[i]); - } - } - - recentsh = flipfaces[3]; - - if (flipflag) { - // Put the boundary edges into flip stack. - for (i = 0; i < 3; i++) { - flipshpush(&(bdedges[i])); - } - } -} - -long meshGRegionBoundaryRecovery::lawsonflip() -{ - badface *popface; - face flipfaces[2]; - point pa, pb, pc, pd; - REAL sign; - long flipcount = 0; - - if (b->verbose > 2) { - printf(" Lawson flip %ld edges.\n", flippool->items); - } - - while (flipstack != (badface *) NULL) { - - // Pop an edge from the stack. - popface = flipstack; - flipfaces[0] = popface->ss; - pa = popface->forg; - pb = popface->fdest; - flipstack = popface->nextitem; // The next top item in stack. - flippool->dealloc((void *) popface); - - // Skip it if it is dead. - if (flipfaces[0].sh[3] == NULL) continue; - // Skip it if it is not the same edge as we saved. - if ((sorg(flipfaces[0]) != pa) || (sdest(flipfaces[0]) != pb)) continue; - // Skip it if it is a subsegment. - if (isshsubseg(flipfaces[0])) continue; - - // Get the adjacent face. - spivot(flipfaces[0], flipfaces[1]); - if (flipfaces[1].sh == NULL) continue; // Skip a hull edge. - pc = sapex(flipfaces[0]); - pd = sapex(flipfaces[1]); - - sign = incircle3d(pa, pb, pc, pd); - - if (sign < 0) { - // It is non-locally Delaunay. Flip it. - flip22(flipfaces, 1, 0); - flipcount++; - } - } - - if (b->verbose > 2) { - printf(" Performed %ld flips.\n", flipcount); - } - - return flipcount; -} - -int meshGRegionBoundaryRecovery::sinsertvertex(point insertpt, face *searchsh, - face *splitseg, int iloc, int bowywat, int rflag) -{ - face cavesh, neighsh, *parysh; - face newsh, casout, casin; - face checkseg; - point pa, pb; - enum locateresult loc = OUTSIDE; - REAL sign, ori; - int i, j; - - if (b->verbose > 2) { - printf(" Insert facet point %d.\n", pointmark(insertpt)); - } - - if (bowywat == 3) { - loc = INSTAR; - } - - if ((splitseg != NULL) && (splitseg->sh != NULL)) { - // A segment is going to be split, no point location. - spivot(*splitseg, *searchsh); - if (loc != INSTAR) loc = ONEDGE; - } else { - if (loc != INSTAR) loc = (enum locateresult) iloc; - if (loc == OUTSIDE) { - // Do point location in surface mesh. - if (searchsh->sh == NULL) { - *searchsh = recentsh; - } - // Search the vertex. An above point must be provided ('aflag' = 1). - loc = slocate(insertpt, searchsh, 1, 1, rflag); - } - } - - - // Form the initial sC(p). - if (loc == ONFACE) { - // Add the face into list (in B-W cavity). - smarktest(*searchsh); - caveshlist->newindex((void **) &parysh); - *parysh = *searchsh; - } else if (loc == ONEDGE) { - if ((splitseg != NULL) && (splitseg->sh != NULL)) { - splitseg->shver = 0; - pa = sorg(*splitseg); - } else { - pa = sorg(*searchsh); - } - if (searchsh->sh != NULL) { - // Collect all subfaces share at this edge. - neighsh = *searchsh; - while (1) { - // Adjust the origin of its edge to be 'pa'. - if (sorg(neighsh) != pa) sesymself(neighsh); - // Add this face into list (in B-W cavity). - smarktest(neighsh); - caveshlist->newindex((void **) &parysh); - *parysh = neighsh; - // Add this face into face-at-splitedge list. - cavesegshlist->newindex((void **) &parysh); - *parysh = neighsh; - // Go to the next face at the edge. - spivotself(neighsh); - // Stop if all faces at the edge have been visited. - if (neighsh.sh == searchsh->sh) break; - if (neighsh.sh == NULL) break; - } - } // If (not a non-dangling segment). - } else if (loc == ONVERTEX) { - return (int) loc; - } else if (loc == OUTSIDE) { - // Comment: This should only happen during the surface meshing step. - // Enlarge the convex hull of the triangulation by including p. - // An above point of the facet is set in 'dummypoint' to replace - // orient2d tests by orient3d tests. - // Imagine that the current edge a->b (in 'searchsh') is horizontal in a - // plane, and a->b is directed from left to right, p lies above a->b. - // Find the right-most edge of the triangulation which is visible by p. - neighsh = *searchsh; - while (1) { - senext2self(neighsh); - spivot(neighsh, casout); - if (casout.sh == NULL) { - // A convex hull edge. Is it visible by p. - ori = orient3d(sorg(neighsh), sdest(neighsh), dummypoint, insertpt); - if (ori < 0) { - *searchsh = neighsh; // Visible, update 'searchsh'. - } else { - break; // 'searchsh' is the right-most visible edge. - } - } else { - if (sorg(casout) != sdest(neighsh)) sesymself(casout); - neighsh = casout; - } - } - // Create new triangles for all visible edges of p (from right to left). - casin.sh = NULL; // No adjacent face at right. - pa = sorg(*searchsh); - pb = sdest(*searchsh); - while (1) { - // Create a new subface on top of the (visible) edge. - makeshellface(subfaces, &newsh); - setshvertices(newsh, pb, pa, insertpt); - setshellmark(newsh, shellmark(*searchsh)); - if (checkconstraints) { - //area = areabound(*searchsh); - setareabound(newsh, areabound(*searchsh)); - } - if (useinsertradius) { - setfacetindex(newsh, getfacetindex(*searchsh)); - } - // Connect the new subface to the bottom subfaces. - sbond1(newsh, *searchsh); - sbond1(*searchsh, newsh); - // Connect the new subface to its right-adjacent subface. - if (casin.sh != NULL) { - senext(newsh, casout); - sbond1(casout, casin); - sbond1(casin, casout); - } - // The left-adjacent subface has not been created yet. - senext2(newsh, casin); - // Add the new face into list (inside the B-W cavity). - smarktest(newsh); - caveshlist->newindex((void **) &parysh); - *parysh = newsh; - // Move to the convex hull edge at the left of 'searchsh'. - neighsh = *searchsh; - while (1) { - senextself(neighsh); - spivot(neighsh, casout); - if (casout.sh == NULL) { - *searchsh = neighsh; - break; - } - if (sorg(casout) != sdest(neighsh)) sesymself(casout); - neighsh = casout; - } - // A convex hull edge. Is it visible by p. - pa = sorg(*searchsh); - pb = sdest(*searchsh); - ori = orient3d(pa, pb, dummypoint, insertpt); - // Finish the process if p is not visible by the hull edge. - if (ori >= 0) break; - } - } else if (loc == INSTAR) { - // Under this case, the sub-cavity sC(p) has already been formed in - // insertvertex(). - } - - // Form the Bowyer-Watson cavity sC(p). - for (i = 0; i < caveshlist->objects; i++) { - cavesh = * (face *) fastlookup(caveshlist, i); - for (j = 0; j < 3; j++) { - if (!isshsubseg(cavesh)) { - spivot(cavesh, neighsh); - if (neighsh.sh != NULL) { - // The adjacent face exists. - if (!smarktested(neighsh)) { - if (bowywat) { - if (loc == INSTAR) { // if (bowywat > 2) { - // It must be a boundary edge. - sign = 1; - } else { - // Check if this subface is connected to adjacent tet(s). - if (!isshtet(neighsh)) { - // Check if the subface is non-Delaunay wrt. the new pt. - sign = incircle3d(sorg(neighsh), sdest(neighsh), - sapex(neighsh), insertpt); - } else { - // It is connected to an adjacent tet. A boundary edge. - sign = 1; - } - } - if (sign < 0) { - // Add the adjacent face in list (in B-W cavity). - smarktest(neighsh); - caveshlist->newindex((void **) &parysh); - *parysh = neighsh; - } - } else { - sign = 1; // A boundary edge. - } - } else { - sign = -1; // Not a boundary edge. - } - } else { - // No adjacent face. It is a hull edge. - if (loc == OUTSIDE) { - // It is a boundary edge if it does not contain p. - if ((sorg(cavesh) == insertpt) || (sdest(cavesh) == insertpt)) { - sign = -1; // Not a boundary edge. - } else { - sign = 1; // A boundary edge. - } - } else { - sign = 1; // A boundary edge. - } - } - } else { - // Do not across a segment. It is a boundary edge. - sign = 1; - } - if (sign >= 0) { - // Add a boundary edge. - caveshbdlist->newindex((void **) &parysh); - *parysh = cavesh; - } - senextself(cavesh); - } // j - } // i - - - // Creating new subfaces. - for (i = 0; i < caveshbdlist->objects; i++) { - parysh = (face *) fastlookup(caveshbdlist, i); - sspivot(*parysh, checkseg); - if ((parysh->shver & 01) != 0) sesymself(*parysh); - pa = sorg(*parysh); - pb = sdest(*parysh); - // Create a new subface. - makeshellface(subfaces, &newsh); - setshvertices(newsh, pa, pb, insertpt); - setshellmark(newsh, shellmark(*parysh)); - if (checkconstraints) { - //area = areabound(*parysh); - setareabound(newsh, areabound(*parysh)); - } - if (useinsertradius) { - setfacetindex(newsh, getfacetindex(*parysh)); - } - // Update the point-to-subface map. - if (pointtype(pa) == FREEFACETVERTEX) { - setpoint2sh(pa, sencode(newsh)); - } - if (pointtype(pb) == FREEFACETVERTEX) { - setpoint2sh(pb, sencode(newsh)); - } - // Connect newsh to outer subfaces. - spivot(*parysh, casout); - if (casout.sh != NULL) { - casin = casout; - if (checkseg.sh != NULL) { - // Make sure that newsh has the right ori at this segment. - checkseg.shver = 0; - if (sorg(newsh) != sorg(checkseg)) { - sesymself(newsh); - sesymself(*parysh); // This side should also be inverse. - } - spivot(casin, neighsh); - while (neighsh.sh != parysh->sh) { - casin = neighsh; - spivot(casin, neighsh); - } - } - sbond1(newsh, casout); - sbond1(casin, newsh); - } - if (checkseg.sh != NULL) { - ssbond(newsh, checkseg); - } - // Connect oldsh <== newsh (for connecting adjacent new subfaces). - // *parysh and newsh point to the same edge and the same ori. - sbond1(*parysh, newsh); - } - - if (newsh.sh != NULL) { - // Set a handle for searching. - recentsh = newsh; - } - - // Update the point-to-subface map. - if (pointtype(insertpt) == FREEFACETVERTEX) { - setpoint2sh(insertpt, sencode(newsh)); - } - - // Connect adjacent new subfaces together. - for (i = 0; i < caveshbdlist->objects; i++) { - // Get an old subface at edge [a, b]. - parysh = (face *) fastlookup(caveshbdlist, i); - spivot(*parysh, newsh); // The new subface [a, b, p]. - senextself(newsh); // At edge [b, p]. - spivot(newsh, neighsh); - if (neighsh.sh == NULL) { - // Find the adjacent new subface at edge [b, p]. - pb = sdest(*parysh); - neighsh = *parysh; - while (1) { - senextself(neighsh); - spivotself(neighsh); - if (neighsh.sh == NULL) break; - if (!smarktested(neighsh)) break; - if (sdest(neighsh) != pb) sesymself(neighsh); - } - if (neighsh.sh != NULL) { - // Now 'neighsh' is a new subface at edge [b, #]. - if (sorg(neighsh) != pb) sesymself(neighsh); - senext2self(neighsh); // Go to the open edge [p, b]. - sbond(newsh, neighsh); - } else { - // There is no adjacent new face at this side. - assert(loc == OUTSIDE); // SELF_CHECK - } - } - spivot(*parysh, newsh); // The new subface [a, b, p]. - senext2self(newsh); // At edge [p, a]. - spivot(newsh, neighsh); - if (neighsh.sh == NULL) { - // Find the adjacent new subface at edge [p, a]. - pa = sorg(*parysh); - neighsh = *parysh; - while (1) { - senext2self(neighsh); - spivotself(neighsh); - if (neighsh.sh == NULL) break; - if (!smarktested(neighsh)) break; - if (sorg(neighsh) != pa) sesymself(neighsh); - } - if (neighsh.sh != NULL) { - // Now 'neighsh' is a new subface at edge [#, a]. - if (sdest(neighsh) != pa) sesymself(neighsh); - senextself(neighsh); // Go to the open edge [a, p]. - sbond(newsh, neighsh); - } else { - // There is no adjacent new face at this side. - assert(loc == OUTSIDE); // SELF_CHECK - } - } - } - - if ((loc == ONEDGE) || ((splitseg != NULL) && (splitseg->sh != NULL)) - || (cavesegshlist->objects > 0l)) { - // An edge is being split. We distinguish two cases: - // (1) the edge is not on the boundary of the cavity; - // (2) the edge is on the boundary of the cavity. - // In case (2), the edge is either a segment or a hull edge. There are - // degenerated new faces in the cavity. They must be removed. - face aseg, bseg, aoutseg, boutseg; - - for (i = 0; i < cavesegshlist->objects; i++) { - // Get the saved old subface. - parysh = (face *) fastlookup(cavesegshlist, i); - // Get a possible new degenerated subface. - spivot(*parysh, cavesh); - if (sapex(cavesh) == insertpt) { - // Found a degenerated new subface, i.e., case (2). - if (cavesegshlist->objects > 1) { - // There are more than one subface share at this edge. - j = (i + 1) % (int) cavesegshlist->objects; - parysh = (face *) fastlookup(cavesegshlist, j); - spivot(*parysh, neighsh); - // Adjust cavesh and neighsh both at edge a->b, and has p as apex. - if (sorg(neighsh) != sorg(cavesh)) { - sesymself(neighsh); - assert(sorg(neighsh) == sorg(cavesh)); // SELF_CHECK - } - assert(sapex(neighsh) == insertpt); // SELF_CHECK - // Connect adjacent faces at two other edges of cavesh and neighsh. - // As a result, the two degenerated new faces are squeezed from the - // new triangulation of the cavity. Note that the squeezed faces - // still hold the adjacent informations which will be used in - // re-connecting subsegments (if they exist). - for (j = 0; j < 2; j++) { - senextself(cavesh); - senextself(neighsh); - spivot(cavesh, newsh); - spivot(neighsh, casout); - sbond1(newsh, casout); // newsh <- casout. - } - } else { - // There is only one subface containing this edge [a,b]. Squeeze the - // degenerated new face [a,b,c] by disconnecting it from its two - // adjacent subfaces at edges [b,c] and [c,a]. Note that the face - // [a,b,c] still hold the connection to them. - for (j = 0; j < 2; j++) { - senextself(cavesh); - spivot(cavesh, newsh); - sdissolve(newsh); - } - } - //recentsh = newsh; - // Update the point-to-subface map. - if (pointtype(insertpt) == FREEFACETVERTEX) { - setpoint2sh(insertpt, sencode(newsh)); - } - } - } - - if ((splitseg != NULL) && (splitseg->sh != NULL)) { - if (loc != INSTAR) { // if (bowywat < 3) { - smarktest(*splitseg); // Mark it as being processed. - } - - aseg = *splitseg; - pa = sorg(*splitseg); - pb = sdest(*splitseg); - - // Insert the new point p. - makeshellface(subsegs, &aseg); - makeshellface(subsegs, &bseg); - - setshvertices(aseg, pa, insertpt, NULL); - setshvertices(bseg, insertpt, pb, NULL); - setshellmark(aseg, shellmark(*splitseg)); - setshellmark(bseg, shellmark(*splitseg)); - if (checkconstraints) { - setareabound(aseg, areabound(*splitseg)); - setareabound(bseg, areabound(*splitseg)); - } - if (useinsertradius) { - setfacetindex(aseg, getfacetindex(*splitseg)); - setfacetindex(bseg, getfacetindex(*splitseg)); - } - - // Connect [#, a]<->[a, p]. - senext2(*splitseg, boutseg); // Temporarily use boutseg. - spivotself(boutseg); - if (boutseg.sh != NULL) { - senext2(aseg, aoutseg); - sbond(boutseg, aoutseg); - } - // Connect [p, b]<->[b, #]. - senext(*splitseg, aoutseg); - spivotself(aoutseg); - if (aoutseg.sh != NULL) { - senext(bseg, boutseg); - sbond(boutseg, aoutseg); - } - // Connect [a, p] <-> [p, b]. - senext(aseg, aoutseg); - senext2(bseg, boutseg); - sbond(aoutseg, boutseg); - - // Connect subsegs [a, p] and [p, b] to adjacent new subfaces. - // Although the degenerated new faces have been squeezed. They still - // hold the connections to the actual new faces. - for (i = 0; i < cavesegshlist->objects; i++) { - parysh = (face *) fastlookup(cavesegshlist, i); - spivot(*parysh, neighsh); - // neighsh is a degenerated new face. - if (sorg(neighsh) != pa) { - sesymself(neighsh); - } - senext2(neighsh, newsh); - spivotself(newsh); // The edge [p, a] in newsh - ssbond(newsh, aseg); - senext(neighsh, newsh); - spivotself(newsh); // The edge [b, p] in newsh - ssbond(newsh, bseg); - } - - - // Let the point remember the segment it lies on. - if (pointtype(insertpt) == FREESEGVERTEX) { - setpoint2sh(insertpt, sencode(aseg)); - } - // Update the point-to-seg map. - if (pointtype(pa) == FREESEGVERTEX) { - setpoint2sh(pa, sencode(aseg)); - } - if (pointtype(pb) == FREESEGVERTEX) { - setpoint2sh(pb, sencode(bseg)); - } - } // if ((splitseg != NULL) && (splitseg->sh != NULL)) - - // Delete all degenerated new faces. - for (i = 0; i < cavesegshlist->objects; i++) { - parysh = (face *) fastlookup(cavesegshlist, i); - spivotself(*parysh); - if (sapex(*parysh) == insertpt) { - shellfacedealloc(subfaces, parysh->sh); - } - } - cavesegshlist->restart(); - - if ((splitseg != NULL) && (splitseg->sh != NULL)) { - // Return the two new subsegments (for further process). - // Re-use 'cavesegshlist'. - cavesegshlist->newindex((void **) &parysh); - *parysh = aseg; - cavesegshlist->newindex((void **) &parysh); - *parysh = bseg; - } - } // if (loc == ONEDGE) - - - return (int) loc; -} - -int meshGRegionBoundaryRecovery::sremovevertex(point delpt, face* parentsh, - face* parentseg, int lawson) -{ - face flipfaces[4], spinsh, *parysh; - point pa, pb, pc, pd; - REAL ori1, ori2; - int it, i, j; - - if (parentseg != NULL) { - // 'delpt' (p) should be a Steiner point inserted in a segment [a,b], - // where 'parentseg' should be [p,b]. Find the segment [a,p]. - face startsh, neighsh, nextsh; - face abseg, prevseg, checkseg; - face adjseg1, adjseg2; - face fakesh; - senext2(*parentseg, prevseg); - spivotself(prevseg); - prevseg.shver = 0; - assert(sdest(prevseg) == delpt); - // Restore the original segment [a,b]. - pa = sorg(prevseg); - pb = sdest(*parentseg); - if (b->verbose > 2) { - printf(" Remove vertex %d from segment [%d, %d].\n", - pointmark(delpt), pointmark(pa), pointmark(pb)); - } - makeshellface(subsegs, &abseg); - setshvertices(abseg, pa, pb, NULL); - setshellmark(abseg, shellmark(*parentseg)); - if (checkconstraints) { - setareabound(abseg, areabound(*parentseg)); - } - if (useinsertradius) { - setfacetindex(abseg, getfacetindex(*parentseg)); - } - // Connect [#, a]<->[a, b]. - senext2(prevseg, adjseg1); - spivotself(adjseg1); - if (adjseg1.sh != NULL) { - adjseg1.shver = 0; - assert(sdest(adjseg1) == pa); - senextself(adjseg1); - senext2(abseg, adjseg2); - sbond(adjseg1, adjseg2); - } - // Connect [a, b]<->[b, #]. - senext(*parentseg, adjseg1); - spivotself(adjseg1); - if (adjseg1.sh != NULL) { - adjseg1.shver = 0; - assert(sorg(adjseg1) == pb); - senext2self(adjseg1); - senext(abseg, adjseg2); - sbond(adjseg1, adjseg2); - } - // Update the point-to-segment map. - setpoint2sh(pa, sencode(abseg)); - setpoint2sh(pb, sencode(abseg)); - - // Get the faces in face ring at segment [p, b]. - // Re-use array 'caveshlist'. - spivot(*parentseg, *parentsh); - if (parentsh->sh != NULL) { - spinsh = *parentsh; - while (1) { - // Save this face in list. - caveshlist->newindex((void **) &parysh); - *parysh = spinsh; - // Go to the next face in the ring. - spivotself(spinsh); - if (spinsh.sh == parentsh->sh) break; - } - } - - // Create the face ring of the new segment [a,b]. Each face in the ring - // is [a,b,p] (degenerated!). It will be removed (automatically). - for (i = 0; i < caveshlist->objects; i++) { - parysh = (face *) fastlookup(caveshlist, i); - startsh = *parysh; - if (sorg(startsh) != delpt) { - sesymself(startsh); - assert(sorg(startsh) == delpt); - } - // startsh is [p, b, #1], find the subface [a, p, #2]. - neighsh = startsh; - while (1) { - senext2self(neighsh); - sspivot(neighsh, checkseg); - if (checkseg.sh != NULL) { - // It must be the segment [a, p]. - assert(checkseg.sh == prevseg.sh); - break; - } - spivotself(neighsh); - assert(neighsh.sh != NULL); - if (sorg(neighsh) != delpt) sesymself(neighsh); - } - // Now neighsh is [a, p, #2]. - if (neighsh.sh != startsh.sh) { - // Detach the two subsegments [a,p] and [p,b] from subfaces. - ssdissolve(startsh); - ssdissolve(neighsh); - // Create a degenerated subface [a,b,p]. It is used to: (1) hold the - // new segment [a,b]; (2) connect to the two adjacent subfaces - // [p,b,#] and [a,p,#]. - makeshellface(subfaces, &fakesh); - setshvertices(fakesh, pa, pb, delpt); - setshellmark(fakesh, shellmark(startsh)); - // Connect fakesh to the segment [a,b]. - ssbond(fakesh, abseg); - // Connect fakesh to adjacent subfaces: [p,b,#1] and [a,p,#2]. - senext(fakesh, nextsh); - sbond(nextsh, startsh); - senext2(fakesh, nextsh); - sbond(nextsh, neighsh); - smarktest(fakesh); // Mark it as faked. - } else { - // Special case. There exists already a degenerated face [a,b,p]! - // There is no need to create a faked subface here. - senext2self(neighsh); // [a,b,p] - assert(sapex(neighsh) == delpt); - // Since we will re-connect the face ring using the faked subfaces. - // We put the adjacent face of [a,b,p] to the list. - spivot(neighsh, startsh); // The original adjacent subface. - if (sorg(startsh) != pa) sesymself(startsh); - sdissolve(startsh); - // Connect fakesh to the segment [a,b]. - ssbond(startsh, abseg); - fakesh = startsh; // Do not mark it! - // Delete the degenerated subface. - shellfacedealloc(subfaces, neighsh.sh); - } - // Save the fakesh in list (for re-creating the face ring). - cavesegshlist->newindex((void **) &parysh); - *parysh = fakesh; - } // i - caveshlist->restart(); - - // Re-create the face ring. - if (cavesegshlist->objects > 1) { - for (i = 0; i < cavesegshlist->objects; i++) { - parysh = (face *) fastlookup(cavesegshlist, i); - fakesh = *parysh; - // Get the next face in the ring. - j = (i + 1) % cavesegshlist->objects; - parysh = (face *) fastlookup(cavesegshlist, j); - nextsh = *parysh; - sbond1(fakesh, nextsh); - } - } - - // Delete the two subsegments containing p. - shellfacedealloc(subsegs, parentseg->sh); - shellfacedealloc(subsegs, prevseg.sh); - // Return the new segment. - *parentseg = abseg; - } else { - // p is inside the surface. - if (b->verbose > 2) { - printf(" Remove vertex %d from surface.\n", pointmark(delpt)); - } - assert(sorg(*parentsh) == delpt); - // Let 'delpt' be its apex. - senextself(*parentsh); - // For unifying the code, we add parentsh to list. - cavesegshlist->newindex((void **) &parysh); - *parysh = *parentsh; - } - - // Remove the point (p). - - for (it = 0; it < cavesegshlist->objects; it++) { - parentsh = (face *) fastlookup(cavesegshlist, it); // [a,b,p] - senextself(*parentsh); // [b,p,a]. - spivotself(*parentsh); - if (sorg(*parentsh) != delpt) sesymself(*parentsh); - // now parentsh is [p,b,#]. - if (sorg(*parentsh) != delpt) { - // The vertex has already been removed in above special case. - assert(!smarktested(*parentsh)); - continue; - } - - while (1) { - // Initialize the flip edge list. Re-use 'caveshlist'. - spinsh = *parentsh; // [p, b, #] - while (1) { - caveshlist->newindex((void **) &parysh); - *parysh = spinsh; - senext2self(spinsh); - spivotself(spinsh); - assert(spinsh.sh != NULL); - if (spinsh.sh == parentsh->sh) break; - if (sorg(spinsh) != delpt) sesymself(spinsh); - assert(sorg(spinsh) == delpt); - } // while (1) - - if (caveshlist->objects == 3) { - // Delete the point by a 3-to-1 flip. - for (i = 0; i < 3; i++) { - parysh = (face *) fastlookup(caveshlist, i); - flipfaces[i] = *parysh; - } - flip31(flipfaces, lawson); - for (i = 0; i < 3; i++) { - shellfacedealloc(subfaces, flipfaces[i].sh); - } - caveshlist->restart(); - // Save the new subface. - caveshbdlist->newindex((void **) &parysh); - *parysh = flipfaces[3]; - // The vertex is removed. - break; - } - - // Search an edge to flip. - for (i = 0; i < caveshlist->objects; i++) { - parysh = (face *) fastlookup(caveshlist, i); - flipfaces[0] = *parysh; - spivot(flipfaces[0], flipfaces[1]); - if (sorg(flipfaces[0]) != sdest(flipfaces[1])) - sesymself(flipfaces[1]); - // Skip this edge if it belongs to a faked subface. - if (!smarktested(flipfaces[0]) && !smarktested(flipfaces[1])) { - pa = sorg(flipfaces[0]); - pb = sdest(flipfaces[0]); - pc = sapex(flipfaces[0]); - pd = sapex(flipfaces[1]); - calculateabovepoint4(pa, pb, pc, pd); - // Check if a 2-to-2 flip is possible. - ori1 = orient3d(pc, pd, dummypoint, pa); - ori2 = orient3d(pc, pd, dummypoint, pb); - if (ori1 * ori2 < 0) { - // A 2-to-2 flip is found. - flip22(flipfaces, lawson, 0); - // The i-th edge is flipped. The i-th and (i-1)-th subfaces are - // changed. The 'flipfaces[1]' contains p as its apex. - senext2(flipfaces[1], *parentsh); - // Save the new subface. - caveshbdlist->newindex((void **) &parysh); - *parysh = flipfaces[0]; - break; - } - } // - } // i - - if (i == caveshlist->objects) { - // This can happen only if there are 4 edges at p, and they are - // orthogonal to each other, see Fig. 2010-11-01. - assert(caveshlist->objects == 4); - // Do a flip22 and a flip31 to remove p. - parysh = (face *) fastlookup(caveshlist, 0); - flipfaces[0] = *parysh; - spivot(flipfaces[0], flipfaces[1]); - if (sorg(flipfaces[0]) != sdest(flipfaces[1])) { - sesymself(flipfaces[1]); - } - flip22(flipfaces, lawson, 0); - senext2(flipfaces[1], *parentsh); - // Save the new subface. - caveshbdlist->newindex((void **) &parysh); - *parysh = flipfaces[0]; - } - - // The edge list at p are changed. - caveshlist->restart(); - } // while (1) - - } // it - - cavesegshlist->restart(); - - if (b->verbose > 2) { - printf(" Created %ld new subfaces.\n", caveshbdlist->objects); - } - - - if (lawson) { - lawsonflip(); - } - - return 0; -} - -enum meshGRegionBoundaryRecovery::locateresult - meshGRegionBoundaryRecovery::slocate(point searchpt, face* searchsh, - int aflag, int cflag, int rflag) -{ - face neighsh; - point pa, pb, pc; - enum locateresult loc; - enum {MOVE_BC, MOVE_CA} nextmove; - REAL ori, ori_bc, ori_ca; - int i; - - pa = sorg(*searchsh); - pb = sdest(*searchsh); - pc = sapex(*searchsh); - - if (!aflag) { - // No above point is given. Calculate an above point for this facet. - calculateabovepoint4(pa, pb, pc, searchpt); - } - - // 'dummypoint' is given. Make sure it is above [a,b,c] - ori = orient3d(pa, pb, pc, dummypoint); - assert(ori != 0); // SELF_CHECK - if (ori > 0) { - sesymself(*searchsh); // Reverse the face orientation. - } - - // Find an edge of the face s.t. p lies on its right-hand side (CCW). - for (i = 0; i < 3; i++) { - pa = sorg(*searchsh); - pb = sdest(*searchsh); - ori = orient3d(pa, pb, dummypoint, searchpt); - if (ori > 0) break; - senextself(*searchsh); - } - assert(i < 3); // SELF_CHECK - - pc = sapex(*searchsh); - - if (pc == searchpt) { - senext2self(*searchsh); - return ONVERTEX; - } - - while (1) { - - ori_bc = orient3d(pb, pc, dummypoint, searchpt); - ori_ca = orient3d(pc, pa, dummypoint, searchpt); - - if (ori_bc < 0) { - if (ori_ca < 0) { // (--) - // Any of the edges is a viable move. - if (randomnation(2)) { - nextmove = MOVE_CA; - } else { - nextmove = MOVE_BC; - } - } else { // (-#) - // Edge [b, c] is viable. - nextmove = MOVE_BC; - } - } else { - if (ori_ca < 0) { // (#-) - // Edge [c, a] is viable. - nextmove = MOVE_CA; - } else { - if (ori_bc > 0) { - if (ori_ca > 0) { // (++) - loc = ONFACE; // Inside [a, b, c]. - break; - } else { // (+0) - senext2self(*searchsh); // On edge [c, a]. - loc = ONEDGE; - break; - } - } else { // ori_bc == 0 - if (ori_ca > 0) { // (0+) - senextself(*searchsh); // On edge [b, c]. - loc = ONEDGE; - break; - } else { // (00) - // p is coincident with vertex c. - senext2self(*searchsh); - return ONVERTEX; - } - } - } - } - - // Move to the next face. - if (nextmove == MOVE_BC) { - senextself(*searchsh); - } else { - senext2self(*searchsh); - } - if (!cflag) { - // NON-convex case. Check if we will cross a boundary. - if (isshsubseg(*searchsh)) { - return ENCSEGMENT; - } - } - spivot(*searchsh, neighsh); - if (neighsh.sh == NULL) { - return OUTSIDE; // A hull edge. - } - // Adjust the edge orientation. - if (sorg(neighsh) != sdest(*searchsh)) { - sesymself(neighsh); - } - assert(sorg(neighsh) == sdest(*searchsh)); // SELF_CHECK - - // Update the newly discovered face and its endpoints. - *searchsh = neighsh; - pa = sorg(*searchsh); - pb = sdest(*searchsh); - pc = sapex(*searchsh); - - if (pc == searchpt) { - senext2self(*searchsh); - return ONVERTEX; - } - - } // while (1) - - // assert(loc == ONFACE || loc == ONEDGE); - - - if (rflag) { - // Round the locate result before return. - REAL n[3], area_abc, area_abp, area_bcp, area_cap; - - pa = sorg(*searchsh); - pb = sdest(*searchsh); - pc = sapex(*searchsh); - - facenormal(pa, pb, pc, n, 1, NULL); - area_abc = sqrt(dot(n, n)); - - facenormal(pb, pc, searchpt, n, 1, NULL); - area_bcp = sqrt(dot(n, n)); - if ((area_bcp / area_abc) < b->epsilon) { - area_bcp = 0; // Rounding. - } - - facenormal(pc, pa, searchpt, n, 1, NULL); - area_cap = sqrt(dot(n, n)); - if ((area_cap / area_abc) < b->epsilon) { - area_cap = 0; // Rounding - } - - if ((loc == ONFACE) || (loc == OUTSIDE)) { - facenormal(pa, pb, searchpt, n, 1, NULL); - area_abp = sqrt(dot(n, n)); - if ((area_abp / area_abc) < b->epsilon) { - area_abp = 0; // Rounding - } - } else { // loc == ONEDGE - area_abp = 0; - } - - if (area_abp == 0) { - if (area_bcp == 0) { - assert(area_cap != 0); - senextself(*searchsh); - loc = ONVERTEX; // p is close to b. - } else { - if (area_cap == 0) { - loc = ONVERTEX; // p is close to a. - } else { - loc = ONEDGE; // p is on edge [a,b]. - } - } - } else if (area_bcp == 0) { - if (area_cap == 0) { - senext2self(*searchsh); - loc = ONVERTEX; // p is close to c. - } else { - senextself(*searchsh); - loc = ONEDGE; // p is on edge [b,c]. - } - } else if (area_cap == 0) { - senext2self(*searchsh); - loc = ONEDGE; // p is on edge [c,a]. - } else { - loc = ONFACE; // p is on face [a,b,c]. - } - } // if (rflag) - - return loc; -} - -//// //// -//// //// -//// surface_cxx ////////////////////////////////////////////////////////////// - -//// steiner_cxx ////////////////////////////////////////////////////////////// -//// //// -//// //// - -enum meshGRegionBoundaryRecovery::interresult - meshGRegionBoundaryRecovery::finddirection(triface* searchtet, point endpt) -{ - triface neightet; - point pa, pb, pc, pd; - enum {HMOVE, RMOVE, LMOVE} nextmove; - REAL hori, rori, lori; - int t1ver; - int s; - - // The origin is fixed. - pa = org(*searchtet); - if ((point) searchtet->tet[7] == dummypoint) { - // A hull tet. Choose the neighbor of its base face. - decode(searchtet->tet[3], *searchtet); - // Reset the origin to be pa. - if ((point) searchtet->tet[4] == pa) { - searchtet->ver = 11; - } else if ((point) searchtet->tet[5] == pa) { - searchtet->ver = 3; - } else if ((point) searchtet->tet[6] == pa) { - searchtet->ver = 7; - } else { - assert((point) searchtet->tet[7] == pa); - searchtet->ver = 0; - } - } - - pb = dest(*searchtet); - // Check whether the destination or apex is 'endpt'. - if (pb == endpt) { - // pa->pb is the search edge. - return ACROSSVERT; - } - - pc = apex(*searchtet); - if (pc == endpt) { - // pa->pc is the search edge. - eprevesymself(*searchtet); - return ACROSSVERT; - } - - // Walk through tets around pa until the right one is found. - while (1) { - - pd = oppo(*searchtet); - // Check whether the opposite vertex is 'endpt'. - if (pd == endpt) { - // pa->pd is the search edge. - esymself(*searchtet); - enextself(*searchtet); - return ACROSSVERT; - } - // Check if we have entered outside of the domain. - if (pd == dummypoint) { - // This is possible when the mesh is non-convex. - assert(nonconvex); - return ACROSSSUB; // Hit a bounday. - } - - // Now assume that the base face abc coincides with the horizon plane, - // and d lies above the horizon. The search point 'endpt' may lie - // above or below the horizon. We test the orientations of 'endpt' - // with respect to three planes: abc (horizon), bad (right plane), - // and acd (left plane). - hori = orient3d(pa, pb, pc, endpt); - rori = orient3d(pb, pa, pd, endpt); - lori = orient3d(pa, pc, pd, endpt); - - // Now decide the tet to move. It is possible there are more than one - // tets are viable moves. Is so, randomly choose one. - if (hori > 0) { - if (rori > 0) { - if (lori > 0) { - // Any of the three neighbors is a viable move. - s = randomnation(3); - if (s == 0) { - nextmove = HMOVE; - } else if (s == 1) { - nextmove = RMOVE; - } else { - nextmove = LMOVE; - } - } else { - // Two tets, below horizon and below right, are viable. - //s = randomnation(2); - if (randomnation(2)) { - nextmove = HMOVE; - } else { - nextmove = RMOVE; - } - } - } else { - if (lori > 0) { - // Two tets, below horizon and below left, are viable. - //s = randomnation(2); - if (randomnation(2)) { - nextmove = HMOVE; - } else { - nextmove = LMOVE; - } - } else { - // The tet below horizon is chosen. - nextmove = HMOVE; - } - } - } else { - if (rori > 0) { - if (lori > 0) { - // Two tets, below right and below left, are viable. - //s = randomnation(2); - if (randomnation(2)) { - nextmove = RMOVE; - } else { - nextmove = LMOVE; - } - } else { - // The tet below right is chosen. - nextmove = RMOVE; - } - } else { - if (lori > 0) { - // The tet below left is chosen. - nextmove = LMOVE; - } else { - // 'endpt' lies either on the plane(s) or across face bcd. - if (hori == 0) { - if (rori == 0) { - // pa->'endpt' is COLLINEAR with pa->pb. - return ACROSSVERT; - } - if (lori == 0) { - // pa->'endpt' is COLLINEAR with pa->pc. - eprevesymself(*searchtet); // // [a,c,d] - return ACROSSVERT; - } - // pa->'endpt' crosses the edge pb->pc. - return ACROSSEDGE; - } - if (rori == 0) { - if (lori == 0) { - // pa->'endpt' is COLLINEAR with pa->pd. - esymself(*searchtet); // face bad. - enextself(*searchtet); // face [a,d,b] - return ACROSSVERT; - } - // pa->'endpt' crosses the edge pb->pd. - esymself(*searchtet); // face bad. - enextself(*searchtet); // face adb - return ACROSSEDGE; - } - if (lori == 0) { - // pa->'endpt' crosses the edge pc->pd. - eprevesymself(*searchtet); // [a,c,d] - return ACROSSEDGE; - } - // pa->'endpt' crosses the face bcd. - return ACROSSFACE; - } - } - } - - // Move to the next tet, fix pa as its origin. - if (nextmove == RMOVE) { - fnextself(*searchtet); - } else if (nextmove == LMOVE) { - eprevself(*searchtet); - fnextself(*searchtet); - enextself(*searchtet); - } else { // HMOVE - fsymself(*searchtet); - enextself(*searchtet); - } - assert(org(*searchtet) == pa); - pb = dest(*searchtet); - pc = apex(*searchtet); - - } // while (1) -} - -int meshGRegionBoundaryRecovery::checkflipeligibility(int fliptype, point pa, - point pb, point pc, point pd, point pe, int level, int edgepivot, - flipconstraints* fc) -{ - point tmppts[3]; - enum interresult dir; - int types[2], poss[4]; - int intflag; - int rejflag = 0; - int i; - - if (fc->seg[0] != NULL) { - // A constraining edge is given (e.g., for edge recovery). - if (fliptype == 1) { - // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c]. - tmppts[0] = pa; - tmppts[1] = pb; - tmppts[2] = pc; - for (i = 0; i < 3 && !rejflag; i++) { - if (tmppts[i] != dummypoint) { - // Test if the face [e,d,#] intersects the edge. - intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1], - NULL, 1, types, poss); - if (intflag == 2) { - // They intersect at a single point. - dir = (enum interresult) types[0]; - if (dir == ACROSSFACE) { - // The interior of [e,d,#] intersect the segment. - rejflag = 1; - } else if (dir == ACROSSEDGE) { - if (poss[0] == 0) { - // The interior of [e,d] intersect the segment. - // Since [e,d] is the newly created edge. Reject this flip. - rejflag = 1; - } - } - } else if (intflag == 4) { - // They may intersect at either a point or a line segment. - dir = (enum interresult) types[0]; - if (dir == ACROSSEDGE) { - if (poss[0] == 0) { - // The interior of [e,d] intersect the segment. - // Since [e,d] is the newly created edge. Reject this flip. - rejflag = 1; - } - } - } - } // if (tmppts[0] != dummypoint) - } // i - } else if (fliptype == 2) { - // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c] - if (pc != dummypoint) { - // Check if the new face [a,b,c] intersect the edge in its interior. - intflag = tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL, - 1, types, poss); - if (intflag == 2) { - // They intersect at a single point. - dir = (enum interresult) types[0]; - if (dir == ACROSSFACE) { - // The interior of [a,b,c] intersect the segment. - rejflag = 1; // Do not flip. - } - } else if (intflag == 4) { - // [a,b,c] is coplanar with the edge. - dir = (enum interresult) types[0]; - if (dir == ACROSSEDGE) { - // The boundary of [a,b,c] intersect the segment. - rejflag = 1; // Do not flip. - } - } - } // if (pc != dummypoint) - } - } // if (fc->seg[0] != NULL) - - if ((fc->fac[0] != NULL) && !rejflag) { - // A constraining face is given (e.g., for face recovery). - if (fliptype == 1) { - // A 2-to-3 flip. - // Test if the new edge [e,d] intersects the face. - intflag = tri_edge_test(fc->fac[0], fc->fac[1], fc->fac[2], pe, pd, - NULL, 1, types, poss); - if (intflag == 2) { - // They intersect at a single point. - dir = (enum interresult) types[0]; - if (dir == ACROSSFACE) { - rejflag = 1; - } else if (dir == ACROSSEDGE) { - rejflag = 1; - } - } else if (intflag == 4) { - // The edge [e,d] is coplanar with the face. - // There may be two intersections. - for (i = 0; i < 2 && !rejflag; i++) { - dir = (enum interresult) types[i]; - if (dir == ACROSSFACE) { - rejflag = 1; - } else if (dir == ACROSSEDGE) { - rejflag = 1; - } - } - } - } // if (fliptype == 1) - } // if (fc->fac[0] != NULL) - - if ((fc->remvert != NULL) && !rejflag) { - // The vertex is going to be removed. Do not create a new edge which - // contains this vertex. - if (fliptype == 1) { - // A 2-to-3 flip. - if ((pd == fc->remvert) || (pe == fc->remvert)) { - rejflag = 1; - } - } - } - - if (fc->remove_large_angle && !rejflag) { - // Remove a large dihedral angle. Do not create a new small angle. - REAL cosmaxd = 0, diff; - if (fliptype == 1) { - // We assume that neither 'a' nor 'b' is dummypoint. - assert((pa != dummypoint) && (pb != dummypoint)); // SELF_CHECK - // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c]. - // The new tet [e,d,a,b] will be flipped later. Only two new tets: - // [e,d,b,c] and [e,d,c,a] need to be checked. - if ((pc != dummypoint) && (pe != dummypoint) && (pd != dummypoint)) { - // Get the largest dihedral angle of [e,d,b,c]. - tetalldihedral(pe, pd, pb, pc, NULL, &cosmaxd, NULL); - diff = cosmaxd - fc->cosdihed_in; - if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding. - if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) { - rejflag = 1; - } else { - // Record the largest new angle. - if (cosmaxd < fc->cosdihed_out) { - fc->cosdihed_out = cosmaxd; - } - // Get the largest dihedral angle of [e,d,c,a]. - tetalldihedral(pe, pd, pc, pa, NULL, &cosmaxd, NULL); - diff = cosmaxd - fc->cosdihed_in; - if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding. - if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) { - rejflag = 1; - } else { - // Record the largest new angle. - if (cosmaxd < fc->cosdihed_out) { - fc->cosdihed_out = cosmaxd; - } - } - } - } // if (pc != dummypoint && ...) - } else if (fliptype == 2) { - // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c] - // We assume that neither 'e' nor 'd' is dummypoint. - assert((pe != dummypoint) && (pd != dummypoint)); // SELF_CHECK - if (level == 0) { - // Both new tets [a,b,c,d] and [b,a,c,e] are new tets. - if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) { - // Get the largest dihedral angle of [a,b,c,d]. - tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL); - diff = cosmaxd - fc->cosdihed_in; - if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding - if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) { - rejflag = 1; - } else { - // Record the largest new angle. - if (cosmaxd < fc->cosdihed_out) { - fc->cosdihed_out = cosmaxd; - } - // Get the largest dihedral angle of [b,a,c,e]. - tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL); - diff = cosmaxd - fc->cosdihed_in; - if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding - if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) { - rejflag = 1; - } else { - // Record the largest new angle. - if (cosmaxd < fc->cosdihed_out) { - fc->cosdihed_out = cosmaxd; - } - } - } - } - } else { // level > 0 - assert(edgepivot != 0); - if (edgepivot == 1) { - // The new tet [a,b,c,d] will be flipped. Only check [b,a,c,e]. - if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) { - // Get the largest dihedral angle of [b,a,c,e]. - tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL); - diff = cosmaxd - fc->cosdihed_in; - if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding - if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) { - rejflag = 1; - } else { - // Record the largest new angle. - if (cosmaxd < fc->cosdihed_out) { - fc->cosdihed_out = cosmaxd; - } - } - } - } else { - assert(edgepivot == 2); - // The new tet [b,a,c,e] will be flipped. Only check [a,b,c,d]. - if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) { - // Get the largest dihedral angle of [b,a,c,e]. - tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL); - diff = cosmaxd - fc->cosdihed_in; - if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding - if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) { - rejflag = 1; - } else { - // Record the largest new angle. - if (cosmaxd < fc->cosdihed_out) { - fc->cosdihed_out = cosmaxd; - } - } - } - } // edgepivot - } // level - } - } - - return rejflag; -} - -int meshGRegionBoundaryRecovery::removeedgebyflips(triface *flipedge, flipconstraints* fc) -{ - triface *abtets, spintet; - int t1ver; - int n, nn, i; - - - if (checksubsegflag) { - // Do not flip a segment. - if (issubseg(*flipedge)) { - if (fc->collectencsegflag) { - face checkseg, *paryseg; - tsspivot1(*flipedge, checkseg); - if (!sinfected(checkseg)) { - // Queue this segment in list. - sinfect(checkseg); - caveencseglist->newindex((void **) &paryseg); - *paryseg = checkseg; - } - } - return 0; - } - } - - // Count the number of tets at edge [a,b]. - n = 0; - spintet = *flipedge; - while (1) { - n++; - fnextself(spintet); - if (spintet.tet == flipedge->tet) break; - } - assert(n >= 3); - - if ((b->flipstarsize > 0) && (n > b->flipstarsize)) { - // The star size exceeds the limit. - return 0; // Do not flip it. - } - - // Allocate spaces. - abtets = new triface[n]; - // Collect the tets at edge [a,b]. - spintet = *flipedge; - i = 0; - while (1) { - abtets[i] = spintet; - setelemcounter(abtets[i], 1); - i++; - fnextself(spintet); - if (spintet.tet == flipedge->tet) break; - } - - - // Try to flip the edge (level = 0, edgepivot = 0). - nn = flipnm(abtets, n, 0, 0, fc); - - - if (nn > 2) { - // Edge is not flipped. Unmarktest the remaining tets in Star(ab). - for (i = 0; i < nn; i++) { - setelemcounter(abtets[i], 0); - } - // Restore the input edge (needed by Lawson's flip). - *flipedge = abtets[0]; - } - - // Release the temporary allocated spaces. - // NOTE: fc->unflip must be 0. - int bakunflip = fc->unflip; - fc->unflip = 0; - flipnm_post(abtets, n, nn, 0, fc); - fc->unflip = bakunflip; - - delete [] abtets; - - return nn; -} - -int meshGRegionBoundaryRecovery::removefacebyflips(triface *flipface, flipconstraints* fc) -{ - if (checksubfaceflag) { - if (issubface(*flipface)) { - return 0; - } - } - - triface fliptets[3], flipedge; - point pa, pb, pc, pd, pe; - REAL ori; - int reducflag = 0; - - fliptets[0] = *flipface; - fsym(*flipface, fliptets[1]); - pa = org(fliptets[0]); - pb = dest(fliptets[0]); - pc = apex(fliptets[0]); - pd = oppo(fliptets[0]); - pe = oppo(fliptets[1]); - - ori = orient3d(pa, pb, pd, pe); - if (ori > 0) { - ori = orient3d(pb, pc, pd, pe); - if (ori > 0) { - ori = orient3d(pc, pa, pd, pe); - if (ori > 0) { - // Found a 2-to-3 flip. - reducflag = 1; - } else { - eprev(*flipface, flipedge); // [c,a] - } - } else { - enext(*flipface, flipedge); // [b,c] - } - } else { - flipedge = *flipface; // [a,b] - } - - if (reducflag) { - // A 2-to-3 flip is found. - flip23(fliptets, 0, fc); - return 1; - } else { - // Try to flip the selected edge of this face. - if (removeedgebyflips(&flipedge, fc) == 2) { - return 1; - } - } - - // Face is not removed. - return 0; -} - -int meshGRegionBoundaryRecovery::recoveredgebyflips(point startpt, - point endpt, triface* searchtet, int fullsearch) -{ - flipconstraints fc; - enum interresult dir; - - fc.seg[0] = startpt; - fc.seg[1] = endpt; - fc.checkflipeligibility = 1; - - // The mainloop of the edge reocvery. - while (1) { // Loop I - - // Search the edge from 'startpt'. - point2tetorg(startpt, *searchtet); - dir = finddirection(searchtet, endpt); - if (dir == ACROSSVERT) { - if (dest(*searchtet) == endpt) { - return 1; // Edge is recovered. - } else { - terminateBoundaryRecovery(this, 3); // // It may be a PLC problem. - } - } - - // The edge is missing. - - // Try to flip the first intersecting face/edge. - enextesymself(*searchtet); // Go to the opposite face. - if (dir == ACROSSFACE) { - // A face is intersected with the segment. Try to flip it. - if (removefacebyflips(searchtet, &fc)) { - continue; - } - } else if (dir == ACROSSEDGE) { - // An edge is intersected with the segment. Try to flip it. - if (removeedgebyflips(searchtet, &fc) == 2) { - continue; - } - } else { - terminateBoundaryRecovery(this, 3); // It may be a PLC problem. - } - - // The edge is missing. - - if (fullsearch) { - // Try to flip one of the faces/edges which intersects the edge. - triface neightet, spintet; - point pa, pb, pc, pd; - badface bakface; - enum interresult dir1; - int types[2], poss[4], pos = 0; - int success = 0; - int t1ver; - int i, j; - - // Loop through the sequence of intersecting faces/edges from - // 'startpt' to 'endpt'. - point2tetorg(startpt, *searchtet); - dir = finddirection(searchtet, endpt); - //assert(dir != ACROSSVERT); - - // Go to the face/edge intersecting the searching edge. - enextesymself(*searchtet); // Go to the opposite face. - // This face/edge has been tried in previous step. - - while (1) { // Loop I-I - - // Find the next intersecting face/edge. - fsymself(*searchtet); - if (dir == ACROSSFACE) { - neightet = *searchtet; - j = (neightet.ver & 3); // j is the current face number. - for (i = j + 1; i < j + 4; i++) { - neightet.ver = (i % 4); - pa = org(neightet); - pb = dest(neightet); - pc = apex(neightet); - pd = oppo(neightet); // The above point. - if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) { - dir = (enum interresult) types[0]; - pos = poss[0]; - break; - } else { - dir = DISJOINT; - pos = 0; - } - } // i - // There must be an intersection face/edge. - assert(dir != DISJOINT); // SELF_CHECK - } else { - assert(dir == ACROSSEDGE); - while (1) { // Loop I-I-I - // Check the two opposite faces (of the edge) in 'searchtet'. - for (i = 0; i < 2; i++) { - if (i == 0) { - enextesym(*searchtet, neightet); - } else { - eprevesym(*searchtet, neightet); - } - pa = org(neightet); - pb = dest(neightet); - pc = apex(neightet); - pd = oppo(neightet); // The above point. - if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) { - dir = (enum interresult) types[0]; - pos = poss[0]; - break; // for loop - } else { - dir = DISJOINT; - pos = 0; - } - } // i - if (dir != DISJOINT) { - // Find an intersection face/edge. - break; // Loop I-I-I - } - // No intersection. Rotate to the next tet at the edge. - fnextself(*searchtet); - } // while (1) // Loop I-I-I - } - - // Adjust to the intersecting edge/vertex. - for (i = 0; i < pos; i++) { - enextself(neightet); - } - - if (dir == SHAREVERT) { - // Check if we have reached the 'endpt'. - pd = org(neightet); - if (pd == endpt) { - // Failed to recover the edge. - break; // Loop I-I - } else { - // We need to further check this case. It might be a PLC problem - // or a Steiner point that was added at a bad location. - assert(0); - } - } - - // The next to be flipped face/edge. - *searchtet = neightet; - - // Bakup this face (tetrahedron). - bakface.forg = org(*searchtet); - bakface.fdest = dest(*searchtet); - bakface.fapex = apex(*searchtet); - bakface.foppo = oppo(*searchtet); - - // Try to flip this intersecting face/edge. - if (dir == ACROSSFACE) { - if (removefacebyflips(searchtet, &fc)) { - success = 1; - break; // Loop I-I - } - } else if (dir == ACROSSEDGE) { - if (removeedgebyflips(searchtet, &fc) == 2) { - success = 1; - break; // Loop I-I - } - } else { - assert(0); // A PLC problem. - } - - // The face/edge is not flipped. - if ((searchtet->tet == NULL) || - (org(*searchtet) != bakface.forg) || - (dest(*searchtet) != bakface.fdest) || - (apex(*searchtet) != bakface.fapex) || - (oppo(*searchtet) != bakface.foppo)) { - // 'searchtet' was flipped. We must restore it. - point2tetorg(bakface.forg, *searchtet); - dir1 = finddirection(searchtet, bakface.fdest); - if (dir1 == ACROSSVERT) { - assert(dest(*searchtet) == bakface.fdest); - spintet = *searchtet; - while (1) { - if (apex(spintet) == bakface.fapex) { - // Found the face. - *searchtet = spintet; - break; - } - fnextself(spintet); - if (spintet.tet == searchtet->tet) { - searchtet->tet = NULL; - break; // Not find. - } - } // while (1) - if (searchtet->tet != NULL) { - if (oppo(*searchtet) != bakface.foppo) { - fsymself(*searchtet); - if (oppo(*searchtet) != bakface.foppo) { - assert(0); // Check this case. - searchtet->tet = NULL; - break; // Not find. - } - } - } - } else { - searchtet->tet = NULL; // Not find. - } - if (searchtet->tet == NULL) { - success = 0; // This face/edge has been destroyed. - break; // Loop I-I - } - } - } // while (1) // Loop I-I - - if (success) { - // One of intersecting faces/edges is flipped. - continue; - } - - } // if (fullsearch) - - // The edge is missing. - break; // Loop I - - } // while (1) // Loop I - - return 0; -} - -int meshGRegionBoundaryRecovery:: - add_steinerpt_in_schoenhardtpoly(triface *abtets, int n, int chkencflag) -{ - triface worktet, *parytet; - triface faketet1, faketet2; - point pc, pd, steinerpt; - insertvertexflags ivf; - optparameters opm; - REAL vcd[3], sampt[3], smtpt[3]; - REAL maxminvol = 0.0, minvol = 0.0, ori; - int success, maxidx = 0; - int it, i; - - - pc = apex(abtets[0]); // pc = p0 - pd = oppo(abtets[n-1]); // pd = p_(n-1) - - - // Find an optimial point in edge [c,d]. It is visible by all outer faces - // of 'abtets', and it maxmizes the min volume. - - // initialize the list of 2n boundary faces. - for (i = 0; i < n; i++) { - edestoppo(abtets[i], worktet); // [p_i,p_i+1,a] - cavetetlist->newindex((void **) &parytet); - *parytet = worktet; - eorgoppo(abtets[i], worktet); // [p_i+1,p_i,b] - cavetetlist->newindex((void **) &parytet); - *parytet = worktet; - } - - int N = 100; - REAL stepi = 0.01; - - // Search the point along the edge [c,d]. - for (i = 0; i < 3; i++) vcd[i] = pd[i] - pc[i]; - - // Sample N points in edge [c,d]. - for (it = 1; it < N; it++) { - for (i = 0; i < 3; i++) { - sampt[i] = pc[i] + (stepi * (double) it) * vcd[i]; - } - for (i = 0; i < cavetetlist->objects; i++) { - parytet = (triface *) fastlookup(cavetetlist, i); - ori = orient3d(dest(*parytet), org(*parytet), apex(*parytet), sampt); - if (i == 0) { - minvol = ori; - } else { - if (minvol > ori) minvol = ori; - } - } // i - if (it == 1) { - maxminvol = minvol; - maxidx = it; - } else { - if (maxminvol < minvol) { - maxminvol = minvol; - maxidx = it; - } - } - } // it - - if (maxminvol <= 0) { - cavetetlist->restart(); - return 0; - } - - for (i = 0; i < 3; i++) { - smtpt[i] = pc[i] + (stepi * (double) maxidx) * vcd[i]; - } - - // Create two faked tets to hold the two non-existing boundary faces: - // [d,c,a] and [c,d,b]. - maketetrahedron(&faketet1); - setvertices(faketet1, pd, pc, org(abtets[0]), dummypoint); - cavetetlist->newindex((void **) &parytet); - *parytet = faketet1; - maketetrahedron(&faketet2); - setvertices(faketet2, pc, pd, dest(abtets[0]), dummypoint); - cavetetlist->newindex((void **) &parytet); - *parytet = faketet2; - - // Point smooth options. - opm.max_min_volume = 1; - opm.numofsearchdirs = 20; - opm.searchstep = 0.001; - opm.maxiter = 100; // Limit the maximum iterations. - opm.initval = 0.0; // Initial volume is zero. - - // Try to relocate the point into the inside of the polyhedron. - success = smoothpoint(smtpt, cavetetlist, 1, &opm); - - if (success) { - while (opm.smthiter == 100) { - // It was relocated and the prescribed maximum iteration reached. - // Try to increase the search stepsize. - opm.searchstep *= 10.0; - //opm.maxiter = 100; // Limit the maximum iterations. - opm.initval = opm.imprval; - opm.smthiter = 0; // Init. - smoothpoint(smtpt, cavetetlist, 1, &opm); - } - } // if (success) - - // Delete the two faked tets. - tetrahedrondealloc(faketet1.tet); - tetrahedrondealloc(faketet2.tet); - - cavetetlist->restart(); - - if (!success) { - return 0; - } - - - // Insert the Steiner point. - makepoint(&steinerpt, FREEVOLVERTEX); - for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i]; - - // Insert the created Steiner point. - for (i = 0; i < n; i++) { - infect(abtets[i]); - caveoldtetlist->newindex((void **) &parytet); - *parytet = abtets[i]; - } - worktet = abtets[0]; // No need point location. - ivf.iloc = (int) INSTAR; - ivf.chkencflag = chkencflag; - ivf.assignmeshsize = b->metric; - if (ivf.assignmeshsize) { - // Search the tet containing 'steinerpt' for size interpolation. - locate(steinerpt, &(abtets[0])); - worktet = abtets[0]; - } - - // Insert the new point into the tetrahedralization T. - // Note that T is convex (nonconvex = 0). - if (insertpoint(steinerpt, &worktet, NULL, NULL, &ivf)) { - // The vertex has been inserted. - st_volref_count++; - if (steinerleft > 0) steinerleft--; - return 1; - } else { - // Not inserted. - pointdealloc(steinerpt); - return 0; - } -} - -int meshGRegionBoundaryRecovery::add_steinerpt_in_segment(face* misseg, - int searchlevel) -{ - triface searchtet; - face *paryseg, candseg; - point startpt, endpt, pc, pd; - flipconstraints fc; - enum interresult dir; - REAL P[3], Q[3], tp, tq; - REAL len, smlen = 0, split = 0, split_q = 0; - int success; - int i; - - startpt = sorg(*misseg); - endpt = sdest(*misseg); - - fc.seg[0] = startpt; - fc.seg[1] = endpt; - fc.checkflipeligibility = 1; - fc.collectencsegflag = 1; - - point2tetorg(startpt, searchtet); - dir = finddirection(&searchtet, endpt); - //assert(dir != ACROSSVERT); - - // Try to flip the first intersecting face/edge. - enextesymself(searchtet); // Go to the opposite face. - - int bak_fliplinklevel = b->fliplinklevel; - b->fliplinklevel = searchlevel; - - if (dir == ACROSSFACE) { - // A face is intersected with the segment. Try to flip it. - success = removefacebyflips(&searchtet, &fc); - assert(success == 0); - } else if (dir == ACROSSEDGE) { - // An edge is intersected with the segment. Try to flip it. - success = removeedgebyflips(&searchtet, &fc); - assert(success != 2); - } else { - terminateBoundaryRecovery(this, 3); // It may be a PLC problem. - } - - split = 0; - for (i = 0; i < caveencseglist->objects; i++) { - paryseg = (face *) fastlookup(caveencseglist, i); - suninfect(*paryseg); - // Calculate the shortest edge between the two lines. - pc = sorg(*paryseg); - pd = sdest(*paryseg); - tp = tq = 0; - if (linelineint(startpt, endpt, pc, pd, P, Q, &tp, &tq)) { - // Does the shortest edge lie between the two segments? - // Round tp and tq. - if ((tp > 0) && (tq < 1)) { - if (tp < 0.5) { - if (tp < (b->epsilon * 1e+3)) tp = 0.0; - } else { - if ((1.0 - tp) < (b->epsilon * 1e+3)) tp = 1.0; - } - } - if ((tp <= 0) || (tp >= 1)) continue; - if ((tq > 0) && (tq < 1)) { - if (tq < 0.5) { - if (tq < (b->epsilon * 1e+3)) tq = 0.0; - } else { - if ((1.0 - tq) < (b->epsilon * 1e+3)) tq = 1.0; - } - } - if ((tq <= 0) || (tq >= 1)) continue; - // It is a valid shortest edge. Calculate its length. - len = distance(P, Q); - if (split == 0) { - smlen = len; - split = tp; - split_q = tq; - candseg = *paryseg; - } else { - if (len < smlen) { - smlen = len; - split = tp; - split_q = tq; - candseg = *paryseg; - } - } - } - } - - caveencseglist->restart(); - b->fliplinklevel = bak_fliplinklevel; - - if (split == 0) { - // Found no crossing segment. - return 0; - } - - face splitsh; - face splitseg; - point steinerpt, *parypt; - insertvertexflags ivf; - - if (b->addsteiner_algo == 1) { - // Split the segment at the closest point to a near segment. - makepoint(&steinerpt, FREESEGVERTEX); - for (i = 0; i < 3; i++) { - steinerpt[i] = startpt[i] + split * (endpt[i] - startpt[i]); - } - } else { // b->addsteiner_algo == 2 - for (i = 0; i < 3; i++) { - P[i] = startpt[i] + split * (endpt[i] - startpt[i]); - } - pc = sorg(candseg); - pd = sdest(candseg); - for (i = 0; i < 3; i++) { - Q[i] = pc[i] + split_q * (pd[i] - pc[i]); - } - makepoint(&steinerpt, FREEVOLVERTEX); - for (i = 0; i < 3; i++) { - steinerpt[i] = 0.5 * (P[i] + Q[i]); - } - } - - // We need to locate the point. Start searching from 'searchtet'. - if (split < 0.5) { - point2tetorg(startpt, searchtet); - } else { - point2tetorg(endpt, searchtet); - } - if (b->addsteiner_algo == 1) { - splitseg = *misseg; - spivot(*misseg, splitsh); - } else { - splitsh.sh = NULL; - splitseg.sh = NULL; - } - ivf.iloc = (int) OUTSIDE; - ivf.bowywat = 1; - ivf.lawson = 0; - ivf.rejflag = 0; - ivf.chkencflag = 0; - ivf.sloc = (int) ONEDGE; - ivf.sbowywat = 1; - ivf.splitbdflag = 0; - ivf.validflag = 1; - ivf.respectbdflag = 1; - ivf.assignmeshsize = b->metric; - - if (!insertpoint(steinerpt, &searchtet, &splitsh, &splitseg, &ivf)) { - pointdealloc(steinerpt); - return 0; - } - - if (b->addsteiner_algo == 1) { - // Save this Steiner point (for removal). - // Re-use the array 'subvertstack'. - subvertstack->newindex((void **) &parypt); - *parypt = steinerpt; - st_segref_count++; - } else { // b->addsteiner_algo == 2 - // Queue the segment for recovery. - subsegstack->newindex((void **) &paryseg); - *paryseg = *misseg; - st_volref_count++; - } - if (steinerleft > 0) steinerleft--; - - return 1; -} - -int meshGRegionBoundaryRecovery::addsteiner4recoversegment(face* misseg, - int splitsegflag) -{ - triface *abtets, searchtet, spintet; - face splitsh; - face *paryseg; - point startpt, endpt; - point pa, pb, pd, steinerpt, *parypt; - enum interresult dir; - insertvertexflags ivf; - int types[2], poss[4]; - int n, endi, success; - int t1ver; - int i; - - startpt = sorg(*misseg); - if (pointtype(startpt) == FREESEGVERTEX) { - sesymself(*misseg); - startpt = sorg(*misseg); - } - endpt = sdest(*misseg); - - // Try to recover the edge by adding Steiner points. - point2tetorg(startpt, searchtet); - dir = finddirection(&searchtet, endpt); - enextself(searchtet); - //assert(apex(searchtet) == startpt); - - if (dir == ACROSSFACE) { - // The segment is crossing at least 3 faces. Find the common edge of - // the first 3 crossing faces. - esymself(searchtet); - fsym(searchtet, spintet); - pd = oppo(spintet); - for (i = 0; i < 3; i++) { - pa = org(spintet); - pb = dest(spintet); - //pc = apex(neightet); - if (tri_edge_test(pa, pb, pd, startpt, endpt, NULL, 1, types, poss)) { - break; // Found the edge. - } - enextself(spintet); - eprevself(searchtet); - } - assert(i < 3); - esymself(searchtet); - } else { - assert(dir == ACROSSEDGE); - // PLC check. - if (issubseg(searchtet)) { - face checkseg; - tsspivot1(searchtet, checkseg); - Msg::Debug("Found two segments intersect each other."); - pa = farsorg(*misseg); - pb = farsdest(*misseg); - Msg::Debug(" 1st: [%d,%d] %d.", pointmark(pa), pointmark(pb), - shellmark(*misseg)); - pa = farsorg(checkseg); - pb = farsdest(checkseg); - Msg::Debug(" 2nd: [%d,%d] %d.", pointmark(pa), pointmark(pb), - shellmark(checkseg)); - terminateBoundaryRecovery(this, 3); - } - } - assert(apex(searchtet) == startpt); - - spintet = searchtet; - n = 0; endi = -1; - while (1) { - // Check if the endpt appears in the star. - if (apex(spintet) == endpt) { - endi = n; // Remember the position of endpt. - } - n++; // Count a tet in the star. - fnextself(spintet); - if (spintet.tet == searchtet.tet) break; - } - assert(n >= 3); - - if (endi > 0) { - // endpt is also in the edge star - // Get all tets in the edge star. - abtets = new triface[n]; - spintet = searchtet; - for (i = 0; i < n; i++) { - abtets[i] = spintet; - fnextself(spintet); - } - - success = 0; - - if (dir == ACROSSFACE) { - // Find a Steiner points inside the polyhedron. - if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) { - success = 1; - } - } else if (dir == ACROSSEDGE) { - if (n > 4) { - // In this case, 'abtets' is separated by the plane (containing the - // two intersecting edges) into two parts, P1 and P2, where P1 - // consists of 'endi' tets: abtets[0], abtets[1], ..., - // abtets[endi-1], and P2 consists of 'n - endi' tets: - // abtets[endi], abtets[endi+1], abtets[n-1]. - if (endi > 2) { // P1 - // There are at least 3 tets in the first part. - if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) { - success++; - } - } - if ((n - endi) > 2) { // P2 - // There are at least 3 tets in the first part. - if (add_steinerpt_in_schoenhardtpoly(&(abtets[endi]), n - endi, 0)) { - success++; - } - } - } else { - // In this case, a 4-to-4 flip should be re-cover the edge [c,d]. - // However, there will be invalid tets (either zero or negtive - // volume). Otherwise, [c,d] should already be recovered by the - // recoveredge() function. - terminateBoundaryRecovery(this, 2); // Report a bug. - } - } else { - terminateBoundaryRecovery(this, 10); // A PLC problem. - } - - delete [] abtets; - - if (success) { - // Add the missing segment back to the recovering list. - subsegstack->newindex((void **) &paryseg); - *paryseg = *misseg; - return 1; - } - } // if (endi > 0) - - if (!splitsegflag) { - return 0; - } - - if (b->verbose > 2) { - printf(" Splitting segment (%d, %d)\n", pointmark(startpt), - pointmark(endpt)); - } - steinerpt = NULL; - - if (b->addsteiner_algo > 0) { // -Y/1 or -Y/2 - if (add_steinerpt_in_segment(misseg, 3)) { - return 1; - } - sesymself(*misseg); - if (add_steinerpt_in_segment(misseg, 3)) { - return 1; - } - sesymself(*misseg); - } - - - - - if (steinerpt == NULL) { - // Split the segment at its midpoint. - makepoint(&steinerpt, FREESEGVERTEX); - for (i = 0; i < 3; i++) { - steinerpt[i] = 0.5 * (startpt[i] + endpt[i]); - } - - // We need to locate the point. - assert(searchtet.tet != NULL); // Start searching from 'searchtet'. - spivot(*misseg, splitsh); - ivf.iloc = (int) OUTSIDE; - ivf.bowywat = 1; - ivf.lawson = 0; - ivf.rejflag = 0; - ivf.chkencflag = 0; - ivf.sloc = (int) ONEDGE; - ivf.sbowywat = 1; - ivf.splitbdflag = 0; - ivf.validflag = 1; - ivf.respectbdflag = 1; - ivf.assignmeshsize = b->metric; - if (!insertpoint(steinerpt, &searchtet, &splitsh, misseg, &ivf)) { - assert(0); - } - } // if (endi > 0) - - // Save this Steiner point (for removal). - // Re-use the array 'subvertstack'. - subvertstack->newindex((void **) &parypt); - *parypt = steinerpt; - - st_segref_count++; - if (steinerleft > 0) steinerleft--; - - return 1; -} - -int meshGRegionBoundaryRecovery::recoversegments(arraypool *misseglist, - int fullsearch, int steinerflag) -{ - triface searchtet, spintet; - face sseg, *paryseg; - point startpt, endpt; - int success; - int t1ver; - long bak_inpoly_count = st_volref_count; - long bak_segref_count = st_segref_count; - - if (b->verbose > 1) { - printf(" Recover segments [%s level = %2d] #: %ld.\n", - (b->fliplinklevel > 0) ? "fixed" : "auto", - (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel, - subsegstack->objects); - } - - // Loop until 'subsegstack' is empty. - while (subsegstack->objects > 0l) { - // seglist is used as a stack. - subsegstack->objects--; - paryseg = (face *) fastlookup(subsegstack, subsegstack->objects); - sseg = *paryseg; - - // Check if this segment has been recovered. - sstpivot1(sseg, searchtet); - if (searchtet.tet != NULL) { - continue; // Not a missing segment. - } - - startpt = sorg(sseg); - endpt = sdest(sseg); - - if (b->verbose > 2) { - printf(" Recover segment (%d, %d).\n", pointmark(startpt), - pointmark(endpt)); - } - - success = 0; - - if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) { - success = 1; - } else { - // Try to recover it from the other direction. - if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) { - success = 1; - } - } - - if (!success && fullsearch) { - if (recoveredgebyflips(startpt, endpt, &searchtet, fullsearch)) { - success = 1; - } - } - - if (success) { - // Segment is recovered. Insert it. - // Let the segment remember an adjacent tet. - sstbond1(sseg, searchtet); - // Bond the segment to all tets containing it. - spintet = searchtet; - do { - tssbond1(spintet, sseg); - fnextself(spintet); - } while (spintet.tet != searchtet.tet); - } else { - if (steinerflag > 0) { - // Try to recover the segment but do not split it. - if (addsteiner4recoversegment(&sseg, 0)) { - success = 1; - } - if (!success && (steinerflag > 1)) { - // Split the segment. - addsteiner4recoversegment(&sseg, 1); - success = 1; - } - } - if (!success) { - if (misseglist != NULL) { - // Save this segment. - misseglist->newindex((void **) &paryseg); - *paryseg = sseg; - } - } - } - - } // while (subsegstack->objects > 0l) - - if (steinerflag) { - if (b->verbose > 1) { - // Report the number of added Steiner points. - if (st_volref_count > bak_inpoly_count) { - Msg::Debug(" Add %ld Steiner points in volume.", - st_volref_count - bak_inpoly_count); - } - if (st_segref_count > bak_segref_count) { - Msg::Debug(" Add %ld Steiner points in segments.", - st_segref_count - bak_segref_count); - } - } - } - - return 0; -} - -int meshGRegionBoundaryRecovery::recoverfacebyflips(point pa, point pb, - point pc, face *searchsh, triface* searchtet) -{ - triface spintet, flipedge; - point pd, pe; - enum interresult dir; - flipconstraints fc; - int types[2], poss[4], intflag; - int success, success1; - int t1ver; - int i, j; - - - fc.fac[0] = pa; - fc.fac[1] = pb; - fc.fac[2] = pc; - fc.checkflipeligibility = 1; - success = 0; - - for (i = 0; i < 3 && !success; i++) { - while (1) { - // Get a tet containing the edge [a,b]. - point2tetorg(fc.fac[i], *searchtet); - dir = finddirection(searchtet, fc.fac[(i+1)%3]); - //assert(dir == ACROSSVERT); - assert(dest(*searchtet) == fc.fac[(i+1)%3]); - // Search the face [a,b,c] - spintet = *searchtet; - while (1) { - if (apex(spintet) == fc.fac[(i+2)%3]) { - // Found the face. - *searchtet = spintet; - // Return the face [a,b,c]. - for (j = i; j > 0; j--) { - eprevself(*searchtet); - } - success = 1; - break; - } - fnextself(spintet); - if (spintet.tet == searchtet->tet) break; - } // while (1) - if (success) break; - // The face is missing. Try to recover it. - success1 = 0; - // Find a crossing edge of this face. - spintet = *searchtet; - while (1) { - pd = apex(spintet); - pe = oppo(spintet); - if ((pd != dummypoint) && (pe != dummypoint)) { - // Check if [d,e] intersects [a,b,c] - intflag = tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss); - if (intflag > 0) { - // By our assumptions, they can only intersect at a single point. - if (intflag == 2) { - // Check the intersection type. - dir = (enum interresult) types[0]; - if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) { - // Go to the edge [d,e]. - edestoppo(spintet, flipedge); // [d,e,a,b] - if (searchsh != NULL) { - // Check if [e,d] is a segment. - if (issubseg(flipedge)) { - if (!b->quiet) { - face checkseg; - tsspivot1(flipedge, checkseg); - Msg::Debug("Found a segment and a subface intersect."); - pd = farsorg(checkseg); - pe = farsdest(checkseg); - Msg::Debug(" 1st: [%d, %d] %d.", pointmark(pd), - pointmark(pe), shellmark(checkseg)); - Msg::Debug(" 2nd: [%d,%d,%d] %d", pointmark(pa), - pointmark(pb), pointmark(pc), shellmark(*searchsh)); - } - terminateBoundaryRecovery(this, 3); - } - } - // Try to flip the edge [d,e]. - success1 = (removeedgebyflips(&flipedge, &fc) == 2); - } else { - if (dir == TOUCHFACE) { - point touchpt, *parypt; - if (poss[1] == 0) { - touchpt = pd; // pd is a coplanar vertex. - } else { - touchpt = pe; // pe is a coplanar vertex. - } - if (pointtype(touchpt) == FREEVOLVERTEX) { - // A volume Steiner point was added in this subface. - // Split this subface by this point. - face checksh, *parysh; - int siloc = (int) ONFACE; - int sbowat = 0; // Only split this subface. - setpointtype(touchpt, FREEFACETVERTEX); - sinsertvertex(touchpt, searchsh, NULL, siloc, sbowat, 0); - st_volref_count--; - st_facref_count++; - // Queue this vertex for removal. - subvertstack->newindex((void **) &parypt); - *parypt = touchpt; - // Queue new subfaces for recovery. - // Put all new subfaces into stack for recovery. - for (i = 0; i < caveshbdlist->objects; i++) { - // Get an old subface at edge [a, b]. - parysh = (face *) fastlookup(caveshbdlist, i); - spivot(*parysh, checksh); // The new subface [a, b, p]. - // Do not recover a deleted new face (degenerated). - if (checksh.sh[3] != NULL) { - subfacstack->newindex((void **) &parysh); - *parysh = checksh; - } - } - // Delete the old subfaces in sC(p). - assert(caveshlist->objects == 1); - for (i = 0; i < caveshlist->objects; i++) { - parysh = (face *) fastlookup(caveshlist, i); - shellfacedealloc(subfaces, parysh->sh); - } - // Clear working lists. - caveshlist->restart(); - caveshbdlist->restart(); - cavesegshlist->restart(); - // We can return this function. - searchsh->sh = NULL; // It has been split. - success1 = 0; - success = 1; - } else { - // It should be a PLC problem. - if (pointtype(touchpt) == FREESEGVERTEX) { - // A segment and a subface intersect. - } else if (pointtype(touchpt) == FREEFACETVERTEX) { - // Two facets self-intersect. - } - terminateBoundaryRecovery(this, 3); - } - } else { - assert(0); // Unknown cases. Debug. - } - } - break; - } else { // intflag == 4. Coplanar case. - // This may be an input PLC error. - assert(0); - } - } // if (intflag > 0) - } - fnextself(spintet); - assert(spintet.tet != searchtet->tet); - } // while (1) - if (!success1) break; - } // while (1) - } // i - - return success; -} - -int meshGRegionBoundaryRecovery::recoversubfaces(arraypool *misshlist, - int steinerflag) -{ - triface searchtet, neightet, spintet; - face searchsh, neighsh, neineish, *parysh; - face bdsegs[3]; - point startpt, endpt, apexpt, *parypt; - point steinerpt; - enum interresult dir; - insertvertexflags ivf; - int success; - int t1ver; - int i, j; - - if (b->verbose > 1) { - printf(" Recover subfaces [%s level = %2d] #: %ld.\n", - (b->fliplinklevel > 0) ? "fixed" : "auto", - (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel, - subfacstack->objects); - } - - // Loop until 'subfacstack' is empty. - while (subfacstack->objects > 0l) { - - subfacstack->objects--; - parysh = (face *) fastlookup(subfacstack, subfacstack->objects); - searchsh = *parysh; - - if (searchsh.sh[3] == NULL) continue; // Skip a dead subface. - - stpivot(searchsh, neightet); - if (neightet.tet != NULL) continue; // Skip a recovered subface. - - - if (b->verbose > 2) { - printf(" Recover subface (%d, %d, %d).\n",pointmark(sorg(searchsh)), - pointmark(sdest(searchsh)), pointmark(sapex(searchsh))); - } - - // The three edges of the face need to be existed first. - for (i = 0; i < 3; i++) { - sspivot(searchsh, bdsegs[i]); - if (bdsegs[i].sh != NULL) { - // The segment must exist. - sstpivot1(bdsegs[i], searchtet); - if (searchtet.tet == NULL) { - assert(0); - } - } else { - // This edge is not a segment (due to a Steiner point). - // Check whether it exists or not. - success = 0; - startpt = sorg(searchsh); - endpt = sdest(searchsh); - point2tetorg(startpt, searchtet); - dir = finddirection(&searchtet, endpt); - if (dir == ACROSSVERT) { - if (dest(searchtet) == endpt) { - success = 1; - } else { - //assert(0); // A PLC problem. - terminateBoundaryRecovery(this, 3); - } - } else { - // The edge is missing. Try to recover it. - if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) { - success = 1; - } else { - if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) { - success = 1; - } - } - } - if (success) { - // Insert a temporary segment to protect this edge. - makeshellface(subsegs, &(bdsegs[i])); - setshvertices(bdsegs[i], startpt, endpt, NULL); - smarktest2(bdsegs[i]); // It's a temporary segment. - // Insert this segment into surface mesh. - ssbond(searchsh, bdsegs[i]); - spivot(searchsh, neighsh); - if (neighsh.sh != NULL) { - ssbond(neighsh, bdsegs[i]); - } - // Insert this segment into tetrahedralization. - sstbond1(bdsegs[i], searchtet); - // Bond the segment to all tets containing it. - spintet = searchtet; - do { - tssbond1(spintet, bdsegs[i]); - fnextself(spintet); - } while (spintet.tet != searchtet.tet); - } else { - // An edge of this subface is missing. Can't recover this subface. - // Delete any temporary segment that has been created. - for (j = (i - 1); j >= 0; j--) { - if (smarktest2ed(bdsegs[j])) { - spivot(bdsegs[j], neineish); - assert(neineish.sh != NULL); - //if (neineish.sh != NULL) { - ssdissolve(neineish); - spivot(neineish, neighsh); - if (neighsh.sh != NULL) { - ssdissolve(neighsh); - // There should be only two subfaces at this segment. - spivotself(neighsh); // SELF_CHECK - assert(neighsh.sh == neineish.sh); - } - //} - sstpivot1(bdsegs[j], searchtet); - assert(searchtet.tet != NULL); - //if (searchtet.tet != NULL) { - spintet = searchtet; - while (1) { - tssdissolve1(spintet); - fnextself(spintet); - if (spintet.tet == searchtet.tet) break; - } - //} - shellfacedealloc(subsegs, bdsegs[j].sh); - } - } // j - if (steinerflag) { - // Add a Steiner point at the midpoint of this edge. - if (b->verbose > 2) { - printf(" Add a Steiner point in subedge (%d, %d).\n", - pointmark(startpt), pointmark(endpt)); - } - makepoint(&steinerpt, FREEFACETVERTEX); - for (j = 0; j < 3; j++) { - steinerpt[j] = 0.5 * (startpt[j] + endpt[j]); - } - - point2tetorg(startpt, searchtet); // Start from 'searchtet'. - ivf.iloc = (int) OUTSIDE; // Need point location. - ivf.bowywat = 1; - ivf.lawson = 0; - ivf.rejflag = 0; - ivf.chkencflag = 0; - ivf.sloc = (int) ONEDGE; - ivf.sbowywat = 1; // Allow flips in facet. - ivf.splitbdflag = 0; - ivf.validflag = 1; - ivf.respectbdflag = 1; - ivf.assignmeshsize = b->metric; - if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) { - assert(0); - } - // Save this Steiner point (for removal). - // Re-use the array 'subvertstack'. - subvertstack->newindex((void **) &parypt); - *parypt = steinerpt; - - st_facref_count++; - if (steinerleft > 0) steinerleft--; - } // if (steinerflag) - break; - } - } - senextself(searchsh); - } // i - - if (i == 3) { - // Recover the subface. - startpt = sorg(searchsh); - endpt = sdest(searchsh); - apexpt = sapex(searchsh); - - success = recoverfacebyflips(startpt,endpt,apexpt,&searchsh,&searchtet); - - // Delete any temporary segment that has been created. - for (j = 0; j < 3; j++) { - if (smarktest2ed(bdsegs[j])) { - spivot(bdsegs[j], neineish); - assert(neineish.sh != NULL); - //if (neineish.sh != NULL) { - ssdissolve(neineish); - spivot(neineish, neighsh); - if (neighsh.sh != NULL) { - ssdissolve(neighsh); - // There should be only two subfaces at this segment. - spivotself(neighsh); // SELF_CHECK - assert(neighsh.sh == neineish.sh); - } - //} - sstpivot1(bdsegs[j], neightet); - assert(neightet.tet != NULL); - //if (neightet.tet != NULL) { - spintet = neightet; - while (1) { - tssdissolve1(spintet); - fnextself(spintet); - if (spintet.tet == neightet.tet) break; - } - //} - shellfacedealloc(subsegs, bdsegs[j].sh); - } - } // j - - if (success) { - if (searchsh.sh != NULL) { - // Face is recovered. Insert it. - tsbond(searchtet, searchsh); - fsymself(searchtet); - sesymself(searchsh); - tsbond(searchtet, searchsh); - } - } else { - if (steinerflag) { - // Add a Steiner point at the barycenter of this subface. - if (b->verbose > 2) { - printf(" Add a Steiner point in subface (%d, %d, %d).\n", - pointmark(startpt), pointmark(endpt), pointmark(apexpt)); - } - makepoint(&steinerpt, FREEFACETVERTEX); - for (j = 0; j < 3; j++) { - steinerpt[j] = (startpt[j] + endpt[j] + apexpt[j]) / 3.0; - } - - point2tetorg(startpt, searchtet); // Start from 'searchtet'. - ivf.iloc = (int) OUTSIDE; // Need point location. - ivf.bowywat = 1; - ivf.lawson = 0; - ivf.rejflag = 0; - ivf.chkencflag = 0; - ivf.sloc = (int) ONFACE; - ivf.sbowywat = 1; // Allow flips in facet. - ivf.splitbdflag = 0; - ivf.validflag = 1; - ivf.respectbdflag = 1; - ivf.assignmeshsize = b->metric; - if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) { - assert(0); - } - // Save this Steiner point (for removal). - // Re-use the array 'subvertstack'. - subvertstack->newindex((void **) &parypt); - *parypt = steinerpt; - - st_facref_count++; - if (steinerleft > 0) steinerleft--; - } // if (steinerflag) - } - } else { - success = 0; - } - - if (!success) { - if (misshlist != NULL) { - // Save this subface. - misshlist->newindex((void **) &parysh); - *parysh = searchsh; - } - } - - } // while (subfacstack->objects > 0l) - - return 0; -} - -int meshGRegionBoundaryRecovery::getvertexstar(int fullstar, point searchpt, - arraypool* tetlist, arraypool* vertlist, arraypool* shlist) -{ - triface searchtet, neightet, *parytet; - face checksh, *parysh; - point pt, *parypt; - int collectflag; - int t1ver; - int i, j; - - point2tetorg(searchpt, searchtet); - - // Go to the opposite face (the link face) of the vertex. - enextesymself(searchtet); - //assert(oppo(searchtet) == searchpt); - infect(searchtet); // Collect this tet (link face). - tetlist->newindex((void **) &parytet); - *parytet = searchtet; - if (vertlist != NULL) { - // Collect three (link) vertices. - j = (searchtet.ver & 3); // The current vertex index. - for (i = 1; i < 4; i++) { - pt = (point) searchtet.tet[4 + ((j + i) % 4)]; - pinfect(pt); - vertlist->newindex((void **) &parypt); - *parypt = pt; - } - } - - collectflag = 1; - esym(searchtet, neightet); - if (issubface(neightet)) { - if (shlist != NULL) { - tspivot(neightet, checksh); - if (!sinfected(checksh)) { - // Collect this subface (link edge). - sinfected(checksh); - shlist->newindex((void **) &parysh); - *parysh = checksh; - } - } - if (!fullstar) { - collectflag = 0; - } - } - if (collectflag) { - fsymself(neightet); // Goto the adj tet of this face. - esymself(neightet); // Goto the oppo face of this vertex. - // assert(oppo(neightet) == searchpt); - infect(neightet); // Collect this tet (link face). - tetlist->newindex((void **) &parytet); - *parytet = neightet; - if (vertlist != NULL) { - // Collect its apex. - pt = apex(neightet); - pinfect(pt); - vertlist->newindex((void **) &parypt); - *parypt = pt; - } - } // if (collectflag) - - // Continue to collect all tets in the star. - for (i = 0; i < tetlist->objects; i++) { - searchtet = * (triface *) fastlookup(tetlist, i); - // Note that 'searchtet' is a face opposite to 'searchpt', and the neighbor - // tet at the current edge is already collected. - // Check the neighbors at the other two edges of this face. - for (j = 0; j < 2; j++) { - collectflag = 1; - enextself(searchtet); - esym(searchtet, neightet); - if (issubface(neightet)) { - if (shlist != NULL) { - tspivot(neightet, checksh); - if (!sinfected(checksh)) { - // Collect this subface (link edge). - sinfected(checksh); - shlist->newindex((void **) &parysh); - *parysh = checksh; - } - } - if (!fullstar) { - collectflag = 0; - } - } - if (collectflag) { - fsymself(neightet); - if (!infected(neightet)) { - esymself(neightet); // Go to the face opposite to 'searchpt'. - infect(neightet); - tetlist->newindex((void **) &parytet); - *parytet = neightet; - if (vertlist != NULL) { - // Check if a vertex is collected. - pt = apex(neightet); - if (!pinfected(pt)) { - pinfect(pt); - vertlist->newindex((void **) &parypt); - *parypt = pt; - } - } - } // if (!infected(neightet)) - } // if (collectflag) - } // j - } // i - - - // Uninfect the list of tets and vertices. - for (i = 0; i < tetlist->objects; i++) { - parytet = (triface *) fastlookup(tetlist, i); - uninfect(*parytet); - } - - if (vertlist != NULL) { - for (i = 0; i < vertlist->objects; i++) { - parypt = (point *) fastlookup(vertlist, i); - puninfect(*parypt); - } - } - - if (shlist != NULL) { - for (i = 0; i < shlist->objects; i++) { - parysh = (face *) fastlookup(shlist, i); - suninfect(*parysh); - } - } - - return (int) tetlist->objects; -} - -int meshGRegionBoundaryRecovery::getedge(point e1, point e2, triface *tedge) -{ - triface searchtet, neightet, *parytet; - point pt; - int done; - int i, j; - - if (b->verbose > 2) { - printf(" Get edge from %d to %d.\n", pointmark(e1), pointmark(e2)); - } - - // Quickly check if 'tedge' is just this edge. - if (!isdeadtet(*tedge)) { - if (org(*tedge) == e1) { - if (dest(*tedge) == e2) { - return 1; - } - } else if (org(*tedge) == e2) { - if (dest(*tedge) == e1) { - esymself(*tedge); - return 1; - } - } - } - - // Search for the edge [e1, e2]. - point2tetorg(e1, *tedge); - finddirection(tedge, e2); - if (dest(*tedge) == e2) { - return 1; - } else { - // Search for the edge [e2, e1]. - point2tetorg(e2, *tedge); - finddirection(tedge, e1); - if (dest(*tedge) == e1) { - esymself(*tedge); - return 1; - } - } - - - // Go to the link face of e1. - point2tetorg(e1, searchtet); - enextesymself(searchtet); - //assert(oppo(searchtet) == e1); - - assert(cavebdrylist->objects == 0l); // It will re-use this list. - arraypool *tetlist = cavebdrylist; - - // Search e2. - for (i = 0; i < 3; i++) { - pt = apex(searchtet); - if (pt == e2) { - // Found. 'searchtet' is [#,#,e2,e1]. - eorgoppo(searchtet, *tedge); // [e1,e2,#,#]. - return 1; - } - enextself(searchtet); - } - - // Get the adjacent link face at 'searchtet'. - fnext(searchtet, neightet); - esymself(neightet); - // assert(oppo(neightet) == e1); - pt = apex(neightet); - if (pt == e2) { - // Found. 'neightet' is [#,#,e2,e1]. - eorgoppo(neightet, *tedge); // [e1,e2,#,#]. - return 1; - } - - // Continue searching in the link face of e1. - infect(searchtet); - tetlist->newindex((void **) &parytet); - *parytet = searchtet; - infect(neightet); - tetlist->newindex((void **) &parytet); - *parytet = neightet; - - done = 0; - - for (i = 0; (i < tetlist->objects) && !done; i++) { - parytet = (triface *) fastlookup(tetlist, i); - searchtet = *parytet; - for (j = 0; (j < 2) && !done; j++) { - enextself(searchtet); - fnext(searchtet, neightet); - if (!infected(neightet)) { - esymself(neightet); - pt = apex(neightet); - if (pt == e2) { - // Found. 'neightet' is [#,#,e2,e1]. - eorgoppo(neightet, *tedge); - done = 1; - } else { - infect(neightet); - tetlist->newindex((void **) &parytet); - *parytet = neightet; - } - } - } // j - } // i - - // Uninfect the list of visited tets. - for (i = 0; i < tetlist->objects; i++) { - parytet = (triface *) fastlookup(tetlist, i); - uninfect(*parytet); - } - tetlist->restart(); - - return done; -} - -int meshGRegionBoundaryRecovery::reduceedgesatvertex(point startpt, - arraypool* endptlist) -{ - triface searchtet; - point *pendpt, *parypt; - enum interresult dir; - flipconstraints fc; - int reduceflag; - int count; - int n, i, j; - - - fc.remvert = startpt; - fc.checkflipeligibility = 1; - - while (1) { - - count = 0; - - for (i = 0; i < endptlist->objects; i++) { - pendpt = (point *) fastlookup(endptlist, i); - if (*pendpt == dummypoint) { - continue; // Do not reduce a virtual edge. - } - reduceflag = 0; - // Find the edge. - if (nonconvex) { - if (getedge(startpt, *pendpt, &searchtet)) { - dir = ACROSSVERT; - } else { - // The edge does not exist (was flipped). - dir = INTERSECT; - } - } else { - point2tetorg(startpt, searchtet); - dir = finddirection(&searchtet, *pendpt); - } - if (dir == ACROSSVERT) { - if (dest(searchtet) == *pendpt) { - // Do not flip a segment. - if (!issubseg(searchtet)) { - n = removeedgebyflips(&searchtet, &fc); - if (n == 2) { - reduceflag = 1; - } - } - } else { - assert(0); // A plc problem. - } - } else { - // The edge has been flipped. - reduceflag = 1; - } - if (reduceflag) { - count++; - // Move the last vertex into this slot. - j = endptlist->objects - 1; - parypt = (point *) fastlookup(endptlist, j); - *pendpt = *parypt; - endptlist->objects--; - i--; - } - } // i - - if (count == 0) { - // No edge is reduced. - break; - } - - } // while (1) - - return (int) endptlist->objects; -} - -int meshGRegionBoundaryRecovery::removevertexbyflips(point steinerpt) -{ - triface *fliptets = NULL, wrktets[4]; - triface searchtet, spintet, neightet; - face parentsh, spinsh, checksh; - face leftseg, rightseg, checkseg; - point lpt = NULL, rpt = NULL, apexpt; //, *parypt; - flipconstraints fc; - enum verttype vt; - enum locateresult loc; - int valence, removeflag; - int slawson; - int t1ver; - int n, i; - - vt = pointtype(steinerpt); - - if (vt == FREESEGVERTEX) { - sdecode(point2sh(steinerpt), leftseg); - assert(leftseg.sh != NULL); - leftseg.shver = 0; - if (sdest(leftseg) == steinerpt) { - senext(leftseg, rightseg); - spivotself(rightseg); - assert(rightseg.sh != NULL); - rightseg.shver = 0; - assert(sorg(rightseg) == steinerpt); - } else { - assert(sorg(leftseg) == steinerpt); - rightseg = leftseg; - senext2(rightseg, leftseg); - spivotself(leftseg); - assert(leftseg.sh != NULL); - leftseg.shver = 0; - assert(sdest(leftseg) == steinerpt); - } - lpt = sorg(leftseg); - rpt = sdest(rightseg); - if (b->verbose > 2) { - printf(" Removing Steiner point %d in segment (%d, %d).\n", - pointmark(steinerpt), pointmark(lpt), pointmark(rpt)); - - } - } else if (vt == FREEFACETVERTEX) { - if (b->verbose > 2) { - printf(" Removing Steiner point %d in facet.\n", - pointmark(steinerpt)); - } - } else if (vt == FREEVOLVERTEX) { - if (b->verbose > 2) { - printf(" Removing Steiner point %d in volume.\n", - pointmark(steinerpt)); - } - } else if (vt == VOLVERTEX) { - if (b->verbose > 2) { - printf(" Removing a point %d in volume.\n", - pointmark(steinerpt)); - } - } else { - // It is not a Steiner point. - return 0; - } - - // Try to reduce the number of edges at 'p' by flips. - getvertexstar(1, steinerpt, cavetetlist, cavetetvertlist, NULL); - cavetetlist->restart(); // This list may be re-used. - if (cavetetvertlist->objects > 3l) { - valence = reduceedgesatvertex(steinerpt, cavetetvertlist); - } else { - valence = cavetetvertlist->objects; - } - assert(cavetetlist->objects == 0l); - cavetetvertlist->restart(); - - removeflag = 0; - - if (valence == 4) { - // Only 4 vertices (4 tets) left! 'p' is inside the convex hull of the 4 - // vertices. This case is due to that 'p' is not exactly on the segment. - point2tetorg(steinerpt, searchtet); - loc = INTETRAHEDRON; - removeflag = 1; - } else if (valence == 5) { - // There are 5 edges. - if (vt == FREESEGVERTEX) { - sstpivot1(leftseg, searchtet); - if (org(searchtet) != steinerpt) { - esymself(searchtet); - } - assert(org(searchtet) == steinerpt); - assert(dest(searchtet) == lpt); - i = 0; // Count the numbe of tet at the edge [p,lpt]. - neightet.tet = NULL; // Init the face. - spintet = searchtet; - while (1) { - i++; - if (apex(spintet) == rpt) { - // Remember the face containing the edge [lpt, rpt]. - neightet = spintet; - } - fnextself(spintet); - if (spintet.tet == searchtet.tet) break; - } - if (i == 3) { - // This case has been checked below. - } else if (i == 4) { - // There are 4 tets sharing at [p,lpt]. There must be 4 tets sharing - // at [p,rpt]. There must be a face [p, lpt, rpt]. - if (apex(neightet) == rpt) { - // The edge (segment) has been already recovered! - // Check if a 6-to-2 flip is possible (to remove 'p'). - // Let 'searchtet' be [p,d,a,b] - esym(neightet, searchtet); - enextself(searchtet); - // Check if there are exactly three tets at edge [p,d]. - wrktets[0] = searchtet; // [p,d,a,b] - for (i = 0; i < 2; i++) { - fnext(wrktets[i], wrktets[i+1]); // [p,d,b,c], [p,d,c,a] - } - if (apex(wrktets[0]) == oppo(wrktets[2])) { - loc = ONFACE; - removeflag = 1; - } - } - } - } else if (vt == FREEFACETVERTEX) { - // It is possible to do a 6-to-2 flip to remove the vertex. - point2tetorg(steinerpt, searchtet); - // Get the three faces of 'searchtet' which share at p. - // All faces has p as origin. - wrktets[0] = searchtet; - wrktets[1] = searchtet; - esymself(wrktets[1]); - enextself(wrktets[1]); - wrktets[2] = searchtet; - eprevself(wrktets[2]); - esymself(wrktets[2]); - // All internal edges of the six tets have valance either 3 or 4. - // Get one edge which has valance 3. - searchtet.tet = NULL; - for (i = 0; i < 3; i++) { - spintet = wrktets[i]; - valence = 0; - while (1) { - valence++; - fnextself(spintet); - if (spintet.tet == wrktets[i].tet) break; - } - if (valence == 3) { - // Found the edge. - searchtet = wrktets[i]; - break; - } else { - assert(valence == 4); - } - } - assert(searchtet.tet != NULL); - // Note, we do not detach the three subfaces at p. - // They will be removed within a 4-to-1 flip. - loc = ONFACE; - removeflag = 1; - } else { - // assert(0); DEBUG IT - } - //removeflag = 1; - } - - if (!removeflag) { - if (vt == FREESEGVERTEX) { - // Check is it possible to recover the edge [lpt,rpt]. - // The condition to check is: Whether each tet containing 'leftseg' is - // adjacent to a tet containing 'rightseg'. - sstpivot1(leftseg, searchtet); - if (org(searchtet) != steinerpt) { - esymself(searchtet); - } - assert(org(searchtet) == steinerpt); - assert(dest(searchtet) == lpt); - spintet = searchtet; - while (1) { - // Go to the bottom face of this tet. - eprev(spintet, neightet); - esymself(neightet); // [steinerpt, p1, p2, lpt] - // Get the adjacent tet. - fsymself(neightet); // [p1, steinerpt, p2, rpt] - if (oppo(neightet) != rpt) { - // Found a non-matching adjacent tet. - break; - } - fnextself(spintet); - if (spintet.tet == searchtet.tet) { - // 'searchtet' is [p,d,p1,p2]. - loc = ONEDGE; - removeflag = 1; - break; - } - } - } // if (vt == FREESEGVERTEX) - } - - if (!removeflag) { - if (vt == FREESEGVERTEX) { - // Check if the edge [lpt, rpt] exists. - if (getedge(lpt, rpt, &searchtet)) { - // We have recovered this edge. Shift the vertex into the volume. - // We can recover this edge if the subfaces are not recovered yet. - if (!checksubfaceflag) { - // Remove the vertex from the surface mesh. - // This will re-create the segment [lpt, rpt] and re-triangulate - // all the facets at the segment. - // Detach the subsegments from their surrounding tets. - for (i = 0; i < 2; i++) { - checkseg = (i == 0) ? leftseg : rightseg; - sstpivot1(checkseg, neightet); - spintet = neightet; - while (1) { - tssdissolve1(spintet); - fnextself(spintet); - if (spintet.tet == neightet.tet) break; - } - sstdissolve1(checkseg); - } // i - slawson = 1; // Do lawson flip after removal. - spivot(rightseg, parentsh); // 'rightseg' has p as its origin. - sremovevertex(steinerpt, &parentsh, &rightseg, slawson); - // Clear the list for new subfaces. - caveshbdlist->restart(); - // Insert the new segment. - assert(org(searchtet) == lpt); - assert(dest(searchtet) == rpt); - sstbond1(rightseg, searchtet); - spintet = searchtet; - while (1) { - tsspivot1(spintet, checkseg); // FOR DEBUG ONLY - assert(checkseg.sh == NULL); // FOR DEBUG ONLY - tssbond1(spintet, rightseg); - fnextself(spintet); - if (spintet.tet == searchtet.tet) break; - } - // The Steiner point has been shifted into the volume. - setpointtype(steinerpt, FREEVOLVERTEX); - st_segref_count--; - st_volref_count++; - return 1; - } // if (!checksubfaceflag) - } // if (getedge(...)) - } // if (vt == FREESEGVERTEX) - } // if (!removeflag) - - if (!removeflag) { - return 0; - } - - assert(org(searchtet) == steinerpt); - - if (vt == FREESEGVERTEX) { - // Detach the subsegments from their surronding tets. - for (i = 0; i < 2; i++) { - checkseg = (i == 0) ? leftseg : rightseg; - sstpivot1(checkseg, neightet); - spintet = neightet; - while (1) { - tssdissolve1(spintet); - fnextself(spintet); - if (spintet.tet == neightet.tet) break; - } - sstdissolve1(checkseg); - } // i - if (checksubfaceflag) { - // Detach the subfaces at the subsegments from their attached tets. - for (i = 0; i < 2; i++) { - checkseg = (i == 0) ? leftseg : rightseg; - spivot(checkseg, parentsh); - if (parentsh.sh != NULL) { - spinsh = parentsh; - while (1) { - stpivot(spinsh, neightet); - if (neightet.tet != NULL) { - tsdissolve(neightet); - } - sesymself(spinsh); - stpivot(spinsh, neightet); - if (neightet.tet != NULL) { - tsdissolve(neightet); - } - stdissolve(spinsh); - spivotself(spinsh); // Go to the next subface. - if (spinsh.sh == parentsh.sh) break; - } - } - } // i - } // if (checksubfaceflag) - } - - if (loc == INTETRAHEDRON) { - // Collect the four tets containing 'p'. - fliptets = new triface[4]; - fliptets[0] = searchtet; // [p,d,a,b] - for (i = 0; i < 2; i++) { - fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a] - } - eprev(fliptets[0], fliptets[3]); - fnextself(fliptets[3]); // it is [a,p,b,c] - eprevself(fliptets[3]); - esymself(fliptets[3]); // [a,b,c,p]. - // Remove p by a 4-to-1 flip. - //flip41(fliptets, 1, 0, 0); - flip41(fliptets, 1, &fc); - //recenttet = fliptets[0]; - } else if (loc == ONFACE) { - // Let the original two tets be [a,b,c,d] and [b,a,c,e]. And p is in - // face [a,b,c]. Let 'searchtet' be the tet [p,d,a,b]. - // Collect the six tets containing 'p'. - fliptets = new triface[6]; - fliptets[0] = searchtet; // [p,d,a,b] - for (i = 0; i < 2; i++) { - fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a] - } - eprev(fliptets[0], fliptets[3]); - fnextself(fliptets[3]); // [a,p,b,e] - esymself(fliptets[3]); // [p,a,e,b] - eprevself(fliptets[3]); // [e,p,a,b] - for (i = 3; i < 5; i++) { - fnext(fliptets[i], fliptets[i+1]); // [e,p,b,c], [e,p,c,a] - } - if (vt == FREEFACETVERTEX) { - // We need to determine the location of three subfaces at p. - valence = 0; // Re-use it. - // Check if subfaces are all located in the lower three tets. - // i.e., [e,p,a,b], [e,p,b,c], and [e,p,c,a]. - for (i = 3; i < 6; i++) { - if (issubface(fliptets[i])) valence++; - } - if (valence > 0) { - assert(valence == 2); - // We must do 3-to-2 flip in the upper part. We simply re-arrange - // the six tets. - for (i = 0; i < 3; i++) { - esym(fliptets[i+3], wrktets[i]); - esym(fliptets[i], fliptets[i+3]); - fliptets[i] = wrktets[i]; - } - // Swap the last two pairs, i.e., [1]<->[[2], and [4]<->[5] - wrktets[1] = fliptets[1]; - fliptets[1] = fliptets[2]; - fliptets[2] = wrktets[1]; - wrktets[1] = fliptets[4]; - fliptets[4] = fliptets[5]; - fliptets[5] = wrktets[1]; - } - } - // Remove p by a 6-to-2 flip, which is a combination of two flips: - // a 3-to-2 (deletes the edge [e,p]), and - // a 4-to-1 (deletes the vertex p). - // First do a 3-to-2 flip on [e,p,a,b],[e,p,b,c],[e,p,c,a]. It creates - // two new tets: [a,b,c,p] and [b,a,c,e]. The new tet [a,b,c,p] is - // degenerate (has zero volume). It will be deleted in the followed - // 4-to-1 flip. - //flip32(&(fliptets[3]), 1, 0, 0); - flip32(&(fliptets[3]), 1, &fc); - // Second do a 4-to-1 flip on [p,d,a,b],[p,d,b,c],[p,d,c,a],[a,b,c,p]. - // This creates a new tet [a,b,c,d]. - //flip41(fliptets, 1, 0, 0); - flip41(fliptets, 1, &fc); - //recenttet = fliptets[0]; - } else if (loc == ONEDGE) { - // Let the original edge be [e,d] and p is in [e,d]. Assume there are n - // tets sharing at edge [e,d] originally. We number the link vertices - // of [e,d]: p_0, p_1, ..., p_n-1. 'searchtet' is [p,d,p_0,p_1]. - // Count the number of tets at edge [e,p] and [p,d] (this is n). - n = 0; - spintet = searchtet; - while (1) { - n++; - fnextself(spintet); - if (spintet.tet == searchtet.tet) break; - } - assert(n >= 3); - // Collect the 2n tets containing 'p'. - fliptets = new triface[2 * n]; - fliptets[0] = searchtet; // [p,b,p_0,p_1] - for (i = 0; i < (n - 1); i++) { - fnext(fliptets[i], fliptets[i+1]); // [p,d,p_i,p_i+1]. - } - eprev(fliptets[0], fliptets[n]); - fnextself(fliptets[n]); // [p_0,p,p_1,e] - esymself(fliptets[n]); // [p,p_0,e,p_1] - eprevself(fliptets[n]); // [e,p,p_0,p_1] - for (i = n; i < (2 * n - 1); i++) { - fnext(fliptets[i], fliptets[i+1]); // [e,p,p_i,p_i+1]. - } - // Remove p by a 2n-to-n flip, it is a sequence of n flips: - // - Do a 2-to-3 flip on - // [p_0,p_1,p,d] and - // [p,p_1,p_0,e]. - // This produces: - // [e,d,p_0,p_1], - // [e,d,p_1,p] (degenerated), and - // [e,d,p,p_0] (degenerated). - wrktets[0] = fliptets[0]; // [p,d,p_0,p_1] - eprevself(wrktets[0]); // [p_0,p,d,p_1] - esymself(wrktets[0]); // [p,p_0,p_1,d] - enextself(wrktets[0]); // [p_0,p_1,p,d] [0] - wrktets[1] = fliptets[n]; // [e,p,p_0,p_1] - enextself(wrktets[1]); // [p,p_0,e,p_1] - esymself(wrktets[1]); // [p_0,p,p_1,e] - eprevself(wrktets[1]); // [p_1,p_0,p,e] [1] - //flip23(wrktets, 1, 0, 0); - flip23(wrktets, 1, &fc); - // Save the new tet [e,d,p,p_0] (degenerated). - fliptets[n] = wrktets[2]; - // Save the new tet [e,d,p_0,p_1]. - fliptets[0] = wrktets[0]; - // - Repeat from i = 1 to n-2: (n - 2) flips - // - Do a 3-to-2 flip on - // [p,p_i,d,e], - // [p,p_i,e,p_i+1], and - // [p,p_i,p_i+1,d]. - // This produces: - // [d,e,p_i+1,p_i], and - // [e,d,p_i+1,p] (degenerated). - for (i = 1; i < (n - 1); i++) { - wrktets[0] = wrktets[1]; // [e,d,p_i,p] (degenerated). - enextself(wrktets[0]); // [d,p_i,e,p] (...) - esymself(wrktets[0]); // [p_i,d,p,e] (...) - eprevself(wrktets[0]); // [p,p_i,d,e] (degenerated) [0]. - wrktets[1] = fliptets[n+i]; // [e,p,p_i,p_i+1] - enextself(wrktets[1]); // [p,p_i,e,p_i+1] [1] - wrktets[2] = fliptets[i]; // [p,d,p_i,p_i+1] - eprevself(wrktets[2]); // [p_i,p,d,p_i+1] - esymself(wrktets[2]); // [p,p_i,p_i+1,d] [2] - //flip32(wrktets, 1, 0, 0); - flip32(wrktets, 1, &fc); - // Save the new tet [e,d,p_i,p_i+1]. // FOR DEBUG ONLY - fliptets[i] = wrktets[0]; // [d,e,p_i+1,p_i] // FOR DEBUG ONLY - esymself(fliptets[i]); // [e,d,p_i,p_i+1] // FOR DEBUG ONLY - } - // - Do a 4-to-1 flip on - // [p,p_0,e,d], [d,e,p_0,p], - // [p,p_0,d,p_n-1], [e,p_n-1,p_0,p], - // [p,p_0,p_n-1,e], [p_0,p_n-1,d,p], and - // [e,d,p_n-1,p]. - // This produces - // [e,d,p_n-1,p_0] and - // deletes p. - wrktets[3] = wrktets[1]; // [e,d,p_n-1,p] (degenerated) [3] - wrktets[0] = fliptets[n]; // [e,d,p,p_0] (degenerated) - eprevself(wrktets[0]); // [p,e,d,p_0] (...) - esymself(wrktets[0]); // [e,p,p_0,d] (...) - enextself(wrktets[0]); // [p,p_0,e,d] (degenerated) [0] - wrktets[1] = fliptets[n-1]; // [p,d,p_n-1,p_0] - esymself(wrktets[1]); // [d,p,p_0,p_n-1] - enextself(wrktets[1]); // [p,p_0,d,p_n-1] [1] - wrktets[2] = fliptets[2*n-1]; // [e,p,p_n-1,p_0] - enextself(wrktets[2]); // [p_p_n-1,e,p_0] - esymself(wrktets[2]); // [p_n-1,p,p_0,e] - enextself(wrktets[2]); // [p,p_0,p_n-1,e] [2] - //flip41(wrktets, 1, 0, 0); - flip41(wrktets, 1, &fc); - // Save the new tet [e,d,p_n-1,p_0] // FOR DEBUG ONLY - fliptets[n-1] = wrktets[0]; // [e,d,p_n-1,p_0] // FOR DEBUG ONLY - //recenttet = fliptets[0]; - } else { - assert(0); // Unknown location. - } // if (iloc == ...) - - delete [] fliptets; - - if (vt == FREESEGVERTEX) { - // Remove the vertex from the surface mesh. - // This will re-create the segment [lpt, rpt] and re-triangulate - // all the facets at the segment. - // Only do lawson flip when subfaces are not recovery yet. - slawson = (checksubfaceflag ? 0 : 1); - spivot(rightseg, parentsh); // 'rightseg' has p as its origin. - sremovevertex(steinerpt, &parentsh, &rightseg, slawson); - - // The original segment is returned in 'rightseg'. - rightseg.shver = 0; - assert(sorg(rightseg) == lpt); - assert(sdest(rightseg) == rpt); - - // Insert the new segment. - point2tetorg(lpt, searchtet); - finddirection(&searchtet, rpt); - assert(dest(searchtet) == rpt); - sstbond1(rightseg, searchtet); - spintet = searchtet; - while (1) { - tsspivot1(spintet, checkseg); // FOR DEBUG ONLY - assert(checkseg.sh == NULL); // FOR DEBUG ONLY - tssbond1(spintet, rightseg); - fnextself(spintet); - if (spintet.tet == searchtet.tet) break; - } - - if (checksubfaceflag) { - // Insert subfaces at segment [lpt,rpt] into the tetrahedralization. - spivot(rightseg, parentsh); - if (parentsh.sh != NULL) { - spinsh = parentsh; - while (1) { - if (sorg(spinsh) != lpt) { - sesymself(spinsh); - assert(sorg(spinsh) == lpt); - } - assert(sdest(spinsh) == rpt); - apexpt = sapex(spinsh); - // Find the adjacent tet of [lpt,rpt,apexpt]; - spintet = searchtet; - while (1) { - if (apex(spintet) == apexpt) { - tsbond(spintet, spinsh); - sesymself(spinsh); // Get to another side of this face. - fsym(spintet, neightet); - tsbond(neightet, spinsh); - sesymself(spinsh); // Get back to the original side. - break; - } - fnextself(spintet); - assert(spintet.tet != searchtet.tet); - //if (spintet.tet == searchtet.tet) break; - } - spivotself(spinsh); - if (spinsh.sh == parentsh.sh) break; - } - } - } // if (checksubfaceflag) - - // Clear the set of new subfaces. - caveshbdlist->restart(); - } // if (vt == FREESEGVERTEX) - - // The point has been removed. - if (pointtype(steinerpt) != UNUSEDVERTEX) { - setpointtype(steinerpt, UNUSEDVERTEX); - unuverts++; - } - if (vt != VOLVERTEX) { - // Update the correspinding counters. - if (vt == FREESEGVERTEX) { - st_segref_count--; - } else if (vt == FREEFACETVERTEX) { - st_facref_count--; - } else if (vt == FREEVOLVERTEX) { - st_volref_count--; - } - if (steinerleft > 0) steinerleft++; - } - - return 1; -} - -int meshGRegionBoundaryRecovery::suppressbdrysteinerpoint(point steinerpt) -{ - face parentsh, spinsh, *parysh; - face leftseg, rightseg; - point lpt = NULL, rpt = NULL; - int i; - - verttype vt = pointtype(steinerpt); - - if (vt == FREESEGVERTEX) { - sdecode(point2sh(steinerpt), leftseg); - leftseg.shver = 0; - if (sdest(leftseg) == steinerpt) { - senext(leftseg, rightseg); - spivotself(rightseg); - assert(rightseg.sh != NULL); - rightseg.shver = 0; - assert(sorg(rightseg) == steinerpt); - } else { - assert(sorg(leftseg) == steinerpt); - rightseg = leftseg; - senext2(rightseg, leftseg); - spivotself(leftseg); - assert(leftseg.sh != NULL); - leftseg.shver = 0; - assert(sdest(leftseg) == steinerpt); - } - lpt = sorg(leftseg); - rpt = sdest(rightseg); - if (b->verbose > 2) { - printf(" Suppressing Steiner point %d in segment (%d, %d).\n", - pointmark(steinerpt), pointmark(lpt), pointmark(rpt)); - } - // Get all subfaces at the left segment [lpt, steinerpt]. - spivot(leftseg, parentsh); - spinsh = parentsh; - while (1) { - cavesegshlist->newindex((void **) &parysh); - *parysh = spinsh; - // Orient the face consistently. - if (sorg(*parysh)!= sorg(parentsh)) sesymself(*parysh); - spivotself(spinsh); - if (spinsh.sh == NULL) break; - if (spinsh.sh == parentsh.sh) break; - } - if (cavesegshlist->objects < 2) { - // It is a single segment. Not handle it yet. - cavesegshlist->restart(); - return 0; - } - } else if (vt == FREEFACETVERTEX) { - if (b->verbose > 2) { - printf(" Suppressing Steiner point %d from facet.\n", - pointmark(steinerpt)); - } - sdecode(point2sh(steinerpt), parentsh); - // A facet Steiner point. There are exactly two sectors. - for (i = 0; i < 2; i++) { - cavesegshlist->newindex((void **) &parysh); - *parysh = parentsh; - sesymself(parentsh); - } - } else { - return 0; - } - - triface searchtet, neightet, *parytet; - point pa, pb, pc, pd; - REAL v1[3], v2[3], len, u; - - REAL startpt[3] = {0,}, samplept[3] = {0,}, candpt[3] = {0,}; - REAL ori, minvol, smallvol; - int samplesize; - int it, j, k; - - int n = (int) cavesegshlist->objects; - point *newsteiners = new point[n]; - for (i = 0; i < n; i++) newsteiners[i] = NULL; - - // Search for each sector an interior vertex. - for (i = 0; i < cavesegshlist->objects; i++) { - parysh = (face *) fastlookup(cavesegshlist, i); - stpivot(*parysh, searchtet); - // Skip it if it is outside. - if (ishulltet(searchtet)) continue; - // Get the "half-ball". Tets in 'cavetetlist' all contain 'steinerpt' as - // opposite. Subfaces in 'caveshlist' all contain 'steinerpt' as apex. - // Moreover, subfaces are oriented towards the interior of the ball. - setpoint2tet(steinerpt, encode(searchtet)); - getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist); - // Calculate the searching vector. - pa = sorg(*parysh); - pb = sdest(*parysh); - pc = sapex(*parysh); - facenormal(pa, pb, pc, v1, 1, NULL); - len = sqrt(dot(v1, v1)); - assert(len > 0.0); - v1[0] /= len; - v1[1] /= len; - v1[2] /= len; - if (vt == FREESEGVERTEX) { - parysh = (face *) fastlookup(cavesegshlist, (i + 1) % n); - pd = sapex(*parysh); - facenormal(pb, pa, pd, v2, 1, NULL); - len = sqrt(dot(v2, v2)); - assert(len > 0.0); - v2[0] /= len; - v2[1] /= len; - v2[2] /= len; - // Average the two vectors. - v1[0] = 0.5 * (v1[0] + v2[0]); - v1[1] = 0.5 * (v1[1] + v2[1]); - v1[2] = 0.5 * (v1[2] + v2[2]); - } - // Search the intersection of the ray starting from 'steinerpt' to - // the search direction 'v1' and the shell of the half-ball. - // - Construct an endpoint. - len = distance(pa, pb); - v2[0] = steinerpt[0] + len * v1[0]; - v2[1] = steinerpt[1] + len * v1[1]; - v2[2] = steinerpt[2] + len * v1[2]; - for (j = 0; j < cavetetlist->objects; j++) { - parytet = (triface *) fastlookup(cavetetlist, j); - pa = org(*parytet); - pb = dest(*parytet); - pc = apex(*parytet); - // Test if the ray startpt->v2 lies in the cone: where 'steinerpt' - // is the apex, and three sides are defined by the triangle - // [pa, pb, pc]. - ori = orient3d(steinerpt, pa, pb, v2); - if (ori >= 0) { - ori = orient3d(steinerpt, pb, pc, v2); - if (ori >= 0) { - ori = orient3d(steinerpt, pc, pa, v2); - if (ori >= 0) { - // Found! Calculate the intersection. - planelineint(pa, pb, pc, steinerpt, v2, startpt, &u); - assert(u != 0.0); - break; - } - } - } - } // j - assert(j < cavetetlist->objects); // There must be an intersection. - // Close the ball by adding the subfaces. - for (j = 0; j < caveshlist->objects; j++) { - parysh = (face *) fastlookup(caveshlist, j); - stpivot(*parysh, neightet); - cavetetlist->newindex((void **) &parytet); - *parytet = neightet; - } - // Search a best point inside the segment [startpt, steinerpt]. - it = 0; - samplesize = 100; - v1[0] = steinerpt[0] - startpt[0]; - v1[1] = steinerpt[1] - startpt[1]; - v1[2] = steinerpt[2] - startpt[2]; - minvol = -1.0; - while (it < 3) { - for (j = 1; j < samplesize - 1; j++) { - samplept[0] = startpt[0] + ((REAL) j / (REAL) samplesize) * v1[0]; - samplept[1] = startpt[1] + ((REAL) j / (REAL) samplesize) * v1[1]; - samplept[2] = startpt[2] + ((REAL) j / (REAL) samplesize) * v1[2]; - // Find the minimum volume for 'samplept'. - smallvol = -1; - for (k = 0; k < cavetetlist->objects; k++) { - parytet = (triface *) fastlookup(cavetetlist, k); - pa = org(*parytet); - pb = dest(*parytet); - pc = apex(*parytet); - ori = orient3d(pb, pa, pc, samplept); - if (ori <= 0) { - break; // An invalid tet. - } - if (smallvol == -1) { - smallvol = ori; - } else { - if (ori < smallvol) smallvol = ori; - } - } // k - if (k == cavetetlist->objects) { - // Found a valid point. Remember it. - if (minvol == -1.0) { - candpt[0] = samplept[0]; - candpt[1] = samplept[1]; - candpt[2] = samplept[2]; - minvol = smallvol; - } else { - if (minvol < smallvol) { - // It is a better location. Remember it. - candpt[0] = samplept[0]; - candpt[1] = samplept[1]; - candpt[2] = samplept[2]; - minvol = smallvol; - } else { - // No improvement of smallest volume. - // Since we are searching along the line [startpt, steinerpy], - // The smallest volume can only be decreased later. - break; - } - } - } - } // j - if (minvol > 0) break; - samplesize *= 10; - it++; - } // while (it < 3) - if (minvol == -1.0) { - // Failed to find a valid point. - cavetetlist->restart(); - caveshlist->restart(); - break; - } - // Create a new Steiner point inside this section. - makepoint(&(newsteiners[i]), FREEVOLVERTEX); - newsteiners[i][0] = candpt[0]; - newsteiners[i][1] = candpt[1]; - newsteiners[i][2] = candpt[2]; - cavetetlist->restart(); - caveshlist->restart(); - } // i - - if (i < cavesegshlist->objects) { - // Failed to suppress the vertex. - for (; i > 0; i--) { - if (newsteiners[i - 1] != NULL) { - pointdealloc(newsteiners[i - 1]); - } - } - delete [] newsteiners; - cavesegshlist->restart(); - return 0; - } - - // Remove p from the segment or the facet. - triface newtet, newface, spintet; - face newsh, neighsh; - face *splitseg, checkseg; - int slawson = 0; // Do not do flip afterword. - int t1ver; - - if (vt == FREESEGVERTEX) { - // Detach 'leftseg' and 'rightseg' from their adjacent tets. - // These two subsegments will be deleted. - sstpivot1(leftseg, neightet); - spintet = neightet; - while (1) { - tssdissolve1(spintet); - fnextself(spintet); - if (spintet.tet == neightet.tet) break; - } - sstpivot1(rightseg, neightet); - spintet = neightet; - while (1) { - tssdissolve1(spintet); - fnextself(spintet); - if (spintet.tet == neightet.tet) break; - } - } - - // Loop through all sectors bounded by facets at this segment. - // Within each sector, create a new Steiner point 'np', and replace 'p' - // by 'np' for all tets in this sector. - for (i = 0; i < cavesegshlist->objects; i++) { - parysh = (face *) fastlookup(cavesegshlist, i); - // 'parysh' is the face [lpt, steinerpt, #]. - stpivot(*parysh, neightet); - // Get all tets in this sector. - setpoint2tet(steinerpt, encode(neightet)); - getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist); - if (!ishulltet(neightet)) { - // Within each tet in the ball, replace 'p' by 'np'. - for (j = 0; j < cavetetlist->objects; j++) { - parytet = (triface *) fastlookup(cavetetlist, j); - setoppo(*parytet, newsteiners[i]); - } // j - // Point to a parent tet. - parytet = (triface *) fastlookup(cavetetlist, 0); - setpoint2tet(newsteiners[i], (tetrahedron) (parytet->tet)); - st_volref_count++; - if (steinerleft > 0) steinerleft--; - } - // Disconnect the set of boundary faces. They're temporarily open faces. - // They will be connected to the new tets after 'p' is removed. - for (j = 0; j < caveshlist->objects; j++) { - // Get a boundary face. - parysh = (face *) fastlookup(caveshlist, j); - stpivot(*parysh, neightet); - //assert(apex(neightet) == newpt); - // Clear the connection at this face. - dissolve(neightet); - tsdissolve(neightet); - } - // Clear the working lists. - cavetetlist->restart(); - caveshlist->restart(); - } // i - cavesegshlist->restart(); - - if (vt == FREESEGVERTEX) { - spivot(rightseg, parentsh); // 'rightseg' has p as its origin. - splitseg = &rightseg; - } else { - if (sdest(parentsh) == steinerpt) { - senextself(parentsh); - } else if (sapex(parentsh) == steinerpt) { - senext2self(parentsh); - } - assert(sorg(parentsh) == steinerpt); - splitseg = NULL; - } - sremovevertex(steinerpt, &parentsh, splitseg, slawson); - - if (vt == FREESEGVERTEX) { - // The original segment is returned in 'rightseg'. - rightseg.shver = 0; - } - - // For each new subface, create two new tets at each side of it. - // Both of the two new tets have its opposite be dummypoint. - for (i = 0; i < caveshbdlist->objects; i++) { - parysh = (face *) fastlookup(caveshbdlist, i); - sinfect(*parysh); // Mark it for connecting new tets. - newsh = *parysh; - pa = sorg(newsh); - pb = sdest(newsh); - pc = sapex(newsh); - maketetrahedron(&newtet); - maketetrahedron(&neightet); - setvertices(newtet, pa, pb, pc, dummypoint); - setvertices(neightet, pb, pa, pc, dummypoint); - bond(newtet, neightet); - tsbond(newtet, newsh); - sesymself(newsh); - tsbond(neightet, newsh); - } - // Temporarily increase the hullsize. - hullsize += (caveshbdlist->objects * 2l); - - if (vt == FREESEGVERTEX) { - // Connecting new tets at the recovered segment. - spivot(rightseg, parentsh); - assert(parentsh.sh != NULL); - spinsh = parentsh; - while (1) { - if (sorg(spinsh) != lpt) sesymself(spinsh); - // Get the new tet at this subface. - stpivot(spinsh, newtet); - tssbond1(newtet, rightseg); - // Go to the other face at this segment. - spivot(spinsh, neighsh); - if (sorg(neighsh) != lpt) sesymself(neighsh); - sesymself(neighsh); - stpivot(neighsh, neightet); - tssbond1(neightet, rightseg); - sstbond1(rightseg, neightet); - // Connecting two adjacent tets at this segment. - esymself(newtet); - esymself(neightet); - // Connect the two tets (at rightseg) together. - bond(newtet, neightet); - // Go to the next subface. - spivotself(spinsh); - if (spinsh.sh == parentsh.sh) break; - } - } - - // Connecting new tets at new subfaces together. - for (i = 0; i < caveshbdlist->objects; i++) { - parysh = (face *) fastlookup(caveshbdlist, i); - newsh = *parysh; - //assert(sinfected(newsh)); - // Each new subface contains two new tets. - for (k = 0; k < 2; k++) { - stpivot(newsh, newtet); - for (j = 0; j < 3; j++) { - // Check if this side is open. - esym(newtet, newface); - if (newface.tet[newface.ver & 3] == NULL) { - // An open face. Connect it to its adjacent tet. - sspivot(newsh, checkseg); - if (checkseg.sh != NULL) { - // A segment. It must not be the recovered segment. - tssbond1(newtet, checkseg); - sstbond1(checkseg, newtet); - } - spivot(newsh, neighsh); - if (neighsh.sh != NULL) { - // The adjacent subface exists. It's not a dangling segment. - if (sorg(neighsh) != sdest(newsh)) sesymself(neighsh); - stpivot(neighsh, neightet); - if (sinfected(neighsh)) { - esymself(neightet); - assert(neightet.tet[neightet.ver & 3] == NULL); - } else { - // Search for an open face at this edge. - spintet = neightet; - while (1) { - esym(spintet, searchtet); - fsym(searchtet, spintet); - if (spintet.tet == NULL) break; - assert(spintet.tet != neightet.tet); - } - // Found an open face at 'searchtet'. - neightet = searchtet; - } - } else { - // The edge (at 'newsh') is a dangling segment. - assert(checkseg.sh != NULL); - // Get an adjacent tet at this segment. - sstpivot1(checkseg, neightet); - assert(!isdeadtet(neightet)); - if (org(neightet) != sdest(newsh)) esymself(neightet); - assert((org(neightet) == sdest(newsh)) && - (dest(neightet) == sorg(newsh))); - // Search for an open face at this edge. - spintet = neightet; - while (1) { - esym(spintet, searchtet); - fsym(searchtet, spintet); - if (spintet.tet == NULL) break; - assert(spintet.tet != neightet.tet); - } - // Found an open face at 'searchtet'. - neightet = searchtet; - } - pc = apex(newface); - if (apex(neightet) == steinerpt) { - // Exterior case. The 'neightet' is a hull tet which contain - // 'steinerpt'. It will be deleted after 'steinerpt' is removed. - assert(pc == dummypoint); - caveoldtetlist->newindex((void **) &parytet); - *parytet = neightet; - // Connect newface to the adjacent hull tet of 'neightet', which - // has the same edge as 'newface', and does not has 'steinerpt'. - fnextself(neightet); - } else { - if (pc == dummypoint) { - if (apex(neightet) != dummypoint) { - setapex(newface, apex(neightet)); - // A hull tet has turned into an interior tet. - hullsize--; // Must update the hullsize. - } - } - } - bond(newface, neightet); - } // if (newface.tet[newface.ver & 3] == NULL) - enextself(newtet); - senextself(newsh); - } // j - sesymself(newsh); - } // k - } // i - - // Unmark all new subfaces. - for (i = 0; i < caveshbdlist->objects; i++) { - parysh = (face *) fastlookup(caveshbdlist, i); - suninfect(*parysh); - } - caveshbdlist->restart(); - - if (caveoldtetlist->objects > 0l) { - // Delete hull tets which contain 'steinerpt'. - for (i = 0; i < caveoldtetlist->objects; i++) { - parytet = (triface *) fastlookup(caveoldtetlist, i); - tetrahedrondealloc(parytet->tet); - } - // Must update the hullsize. - hullsize -= caveoldtetlist->objects; - caveoldtetlist->restart(); - } - - setpointtype(steinerpt, UNUSEDVERTEX); - unuverts++; - if (vt == FREESEGVERTEX) { - st_segref_count--; - } else { // vt == FREEFACETVERTEX - st_facref_count--; - } - if (steinerleft > 0) steinerleft++; // We've removed a Steiner points. - - - point *parypt; - int steinercount = 0; - - int bak_fliplinklevel = b->fliplinklevel; - b->fliplinklevel = 100000; // Unlimited flip level. - - // Try to remove newly added Steiner points. - for (i = 0; i < n; i++) { - if (newsteiners[i] != NULL) { - if (!removevertexbyflips(newsteiners[i])) { - if (b->nobisect_param > 0) { // Not -Y0 - // Save it in subvertstack for removal. - subvertstack->newindex((void **) &parypt); - *parypt = newsteiners[i]; - } - steinercount++; - } - } - } - - b->fliplinklevel = bak_fliplinklevel; - - if (steinercount > 0) { - if (b->verbose > 2) { - printf(" Added %d interior Steiner points.\n", steinercount); - } - } - - delete [] newsteiners; - - return 1; -} - - -int meshGRegionBoundaryRecovery::suppresssteinerpoints() -{ - - Msg::Info(" --> Suppressing Steiner points ..."); - point rempt, *parypt; - - int bak_fliplinklevel = b->fliplinklevel; - b->fliplinklevel = 100000; // Unlimited flip level. - int suppcount = 0, remcount = 0; - int i; - - // Try to suppress boundary Steiner points. - for (i = 0; i < subvertstack->objects; i++) { - parypt = (point *) fastlookup(subvertstack, i); - rempt = *parypt; - if (pointtype(rempt) != UNUSEDVERTEX) { - if ((pointtype(rempt) == FREESEGVERTEX) || - (pointtype(rempt) == FREEFACETVERTEX)) { - if (suppressbdrysteinerpoint(rempt)) { - suppcount++; - } - } - } - } // i - - if (suppcount > 0) { - Msg::Info(" Suppressed %d boundary Steiner points.", suppcount); - } - - if (b->nobisect_param > 0) { // -Y1 - for (i = 0; i < subvertstack->objects; i++) { - parypt = (point *) fastlookup(subvertstack, i); - rempt = *parypt; - if (pointtype(rempt) != UNUSEDVERTEX) { - if (pointtype(rempt) == FREEVOLVERTEX) { - if (removevertexbyflips(rempt)) { - remcount++; - } - } - } - } - } - - if (remcount > 0) { - if (b->verbose) { - printf(" Removed %d interior Steiner points.\n", remcount); - } - } - - b->fliplinklevel = bak_fliplinklevel; - - if (b->nobisect_param > 1) { // -Y2 - // Smooth interior Steiner points. - optparameters opm; - triface *parytet; - point *ppt; - REAL ori; - int smtcount, count, ivcount; - int nt, j; - - // Point smooth options. - opm.max_min_volume = 1; - opm.numofsearchdirs = 20; - opm.searchstep = 0.001; - opm.maxiter = 30; // Limit the maximum iterations. - - smtcount = 0; - - do { - - nt = 0; - - while (1) { - count = 0; - ivcount = 0; // Clear the inverted count. - - for (i = 0; i < subvertstack->objects; i++) { - parypt = (point *) fastlookup(subvertstack, i); - rempt = *parypt; - if (pointtype(rempt) == FREEVOLVERTEX) { - getvertexstar(1, rempt, cavetetlist, NULL, NULL); - // Calculate the initial smallest volume (maybe zero or negative). - for (j = 0; j < cavetetlist->objects; j++) { - parytet = (triface *) fastlookup(cavetetlist, j); - ppt = (point *) &(parytet->tet[4]); - ori = orient3dfast(ppt[1], ppt[0], ppt[2], ppt[3]); - if (j == 0) { - opm.initval = ori; - } else { - if (opm.initval > ori) opm.initval = ori; - } - } - if (smoothpoint(rempt, cavetetlist, 1, &opm)) { - count++; - } - if (opm.imprval <= 0.0) { - ivcount++; // The mesh contains inverted elements. - } - cavetetlist->restart(); - } - } // i - - smtcount += count; - - if (count == 0) { - // No point has been smoothed. - break; - } - - nt++; - if (nt > 2) { - break; // Already three iterations. - } - } // while - - if (ivcount > 0) { - // There are inverted elements! - if (opm.maxiter > 0) { - // Set unlimited smoothing steps. Try again. - opm.numofsearchdirs = 30; - opm.searchstep = 0.0001; - opm.maxiter = -1; - continue; - } - } - - break; - } while (1); // Additional loop for (ivcount > 0) - - if (ivcount > 0) { - printf("BUG Report! The mesh contain inverted elements.\n"); - } - - if (b->verbose) { - if (smtcount > 0) { - printf(" Smoothed %d Steiner points.\n", smtcount); - } - } - } // -Y2 - - subvertstack->restart(); - - return 1; -} - -void meshGRegionBoundaryRecovery::recoverboundary() -{ - arraypool *misseglist, *misshlist; - arraypool *bdrysteinerptlist; - face searchsh, *parysh; - face searchseg, *paryseg; - point rempt, *parypt; - long ms; // The number of missing segments/subfaces. - int nit; // The number of iterations. - int s, i; - - // Counters. - long bak_segref_count, bak_facref_count, bak_volref_count; - - if (!b->quiet) { - Msg::Info(" --> Recovering boundaries ..."); - } - - - if (b->verbose) { - Msg::Info(" --> Recovering segments ..."); - } - - // Segments will be introduced. - checksubsegflag = 1; - - misseglist = new arraypool(sizeof(face), 8); - bdrysteinerptlist = new arraypool(sizeof(point), 8); - - // In random order. - subsegs->traversalinit(); - for (i = 0; i < subsegs->items; i++) { - s = randomnation(i + 1); - // Move the s-th seg to the i-th. - subsegstack->newindex((void **) &paryseg); - *paryseg = * (face *) fastlookup(subsegstack, s); - // Put i-th seg to be the s-th. - searchseg.sh = shellfacetraverse(subsegs); - paryseg = (face *) fastlookup(subsegstack, s); - *paryseg = searchseg; - } - - // The init number of missing segments. - ms = subsegs->items; - nit = 0; - if (b->fliplinklevel < 0) { - autofliplinklevel = 1; // Init value. - } - - // First, trying to recover segments by only doing flips. - while (1) { - recoversegments(misseglist, 0, 0); - - if (misseglist->objects > 0) { - if (b->fliplinklevel >= 0) { - break; - } else { - if (misseglist->objects >= ms) { - nit++; - if (nit >= 3) { - //break; - // Do the last round with unbounded flip link level. - b->fliplinklevel = 100000; - } - } else { - ms = misseglist->objects; - if (nit > 0) { - nit--; - } - } - for (i = 0; i < misseglist->objects; i++) { - subsegstack->newindex((void **) &paryseg); - *paryseg = * (face *) fastlookup(misseglist, i); - } - misseglist->restart(); - autofliplinklevel+=b->fliplinklevelinc; - } - } else { - // All segments are recovered. - break; - } - } // while (1) - - if (b->verbose) { - printf(" %ld (%ld) segments are recovered (missing).\n", - subsegs->items - misseglist->objects, misseglist->objects); - } - - if (misseglist->objects > 0) { - // Second, trying to recover segments by doing more flips (fullsearch). - while (misseglist->objects > 0) { - ms = misseglist->objects; - for (i = 0; i < misseglist->objects; i++) { - subsegstack->newindex((void **) &paryseg); - *paryseg = * (face *) fastlookup(misseglist, i); - } - misseglist->restart(); - - recoversegments(misseglist, 1, 0); - - if (misseglist->objects < ms) { - // The number of missing segments is reduced. - continue; - } else { - break; - } - } - if (b->verbose) { - printf(" %ld (%ld) segments are recovered (missing).\n", - subsegs->items - misseglist->objects, misseglist->objects); - } - } - - if (misseglist->objects > 0) { - // Third, trying to recover segments by doing more flips (fullsearch) - // and adding Steiner points in the volume. - while (misseglist->objects > 0) { - ms = misseglist->objects; - for (i = 0; i < misseglist->objects; i++) { - subsegstack->newindex((void **) &paryseg); - *paryseg = * (face *) fastlookup(misseglist, i); - } - misseglist->restart(); - - recoversegments(misseglist, 1, 1); - - if (misseglist->objects < ms) { - // The number of missing segments is reduced. - continue; - } else { - break; - } - } - if (b->verbose) { - printf(" Added %ld Steiner points in volume.\n", st_volref_count); - } - } - - if (misseglist->objects > 0) { - // Last, trying to recover segments by doing more flips (fullsearch), - // and adding Steiner points in the volume, and splitting segments. - long bak_inpoly_count = st_volref_count; //st_inpoly_count; - for (i = 0; i < misseglist->objects; i++) { - subsegstack->newindex((void **) &paryseg); - *paryseg = * (face *) fastlookup(misseglist, i); - } - misseglist->restart(); - - recoversegments(misseglist, 1, 2); - - if (b->verbose) { - printf(" Added %ld Steiner points in segments.\n", st_segref_count); - if (st_volref_count > bak_inpoly_count) { - printf(" Added another %ld Steiner points in volume.\n", - st_volref_count - bak_inpoly_count); - } - } - assert(misseglist->objects == 0l); - } - - - if (st_segref_count > 0) { - // Try to remove the Steiner points added in segments. - bak_segref_count = st_segref_count; - bak_volref_count = st_volref_count; - for (i = 0; i < subvertstack->objects; i++) { - // Get the Steiner point. - parypt = (point *) fastlookup(subvertstack, i); - rempt = *parypt; - if (!removevertexbyflips(rempt)) { - // Save it in list. - bdrysteinerptlist->newindex((void **) &parypt); - *parypt = rempt; - } - } - if (b->verbose) { - if (st_segref_count < bak_segref_count) { - if (bak_volref_count < st_volref_count) { - printf(" Suppressed %ld Steiner points in segments.\n", - st_volref_count - bak_volref_count); - } - if ((st_segref_count + (st_volref_count - bak_volref_count)) < - bak_segref_count) { - printf(" Removed %ld Steiner points in segments.\n", - bak_segref_count - - (st_segref_count + (st_volref_count - bak_volref_count))); - } - } - } - subvertstack->restart(); - } - - - if (b->verbose) { - printf(" Recovering facets.\n"); - } - - // Subfaces will be introduced. - checksubfaceflag = 1; - - misshlist = new arraypool(sizeof(face), 8); - - // Randomly order the subfaces. - subfaces->traversalinit(); - for (i = 0; i < subfaces->items; i++) { - s = randomnation(i + 1); - // Move the s-th subface to the i-th. - subfacstack->newindex((void **) &parysh); - *parysh = * (face *) fastlookup(subfacstack, s); - // Put i-th subface to be the s-th. - searchsh.sh = shellfacetraverse(subfaces); - parysh = (face *) fastlookup(subfacstack, s); - *parysh = searchsh; - } - - ms = subfaces->items; - nit = 0; - b->fliplinklevel = -1; // Init. - if (b->fliplinklevel < 0) { - autofliplinklevel = 1; // Init value. - } - - while (1) { - recoversubfaces(misshlist, 0); - - if (misshlist->objects > 0) { - if (b->fliplinklevel >= 0) { - break; - } else { - if (misshlist->objects >= ms) { - nit++; - if (nit >= 3) { - //break; - // Do the last round with unbounded flip link level. - b->fliplinklevel = 100000; - } - } else { - ms = misshlist->objects; - if (nit > 0) { - nit--; - } - } - for (i = 0; i < misshlist->objects; i++) { - subfacstack->newindex((void **) &parysh); - *parysh = * (face *) fastlookup(misshlist, i); - } - misshlist->restart(); - autofliplinklevel+=b->fliplinklevelinc; - } - } else { - // All subfaces are recovered. - break; - } - } // while (1) - - if (b->verbose) { - printf(" %ld (%ld) subfaces are recovered (missing).\n", - subfaces->items - misshlist->objects, misshlist->objects); - } - - if (misshlist->objects > 0) { - // There are missing subfaces. Add Steiner points. - for (i = 0; i < misshlist->objects; i++) { - subfacstack->newindex((void **) &parysh); - *parysh = * (face *) fastlookup(misshlist, i); - } - misshlist->restart(); - - recoversubfaces(NULL, 1); - - if (b->verbose) { - printf(" Added %ld Steiner points in facets.\n", st_facref_count); - } - } - - - if (st_facref_count > 0) { - // Try to remove the Steiner points added in facets. - bak_facref_count = st_facref_count; - for (i = 0; i < subvertstack->objects; i++) { - // Get the Steiner point. - parypt = (point *) fastlookup(subvertstack, i); - rempt = *parypt; - if (!removevertexbyflips(*parypt)) { - // Save it in list. - bdrysteinerptlist->newindex((void **) &parypt); - *parypt = rempt; - } - } - if (b->verbose) { - if (st_facref_count < bak_facref_count) { - printf(" Removed %ld Steiner points in facets.\n", - bak_facref_count - st_facref_count); - } - } - subvertstack->restart(); - } - - - if (bdrysteinerptlist->objects > 0) { - if (b->verbose) { - printf(" %ld Steiner points remained in boundary.\n", - bdrysteinerptlist->objects); - } - } // if - - - // Accumulate the dynamic memory. - totalworkmemory += (misseglist->totalmemory + misshlist->totalmemory + - bdrysteinerptlist->totalmemory); - - delete bdrysteinerptlist; - delete misseglist; - delete misshlist; -} - -//// //// -//// //// -//// steiner_cxx ////////////////////////////////////////////////////////////// - - -//// reconstruct_cxx ////////////////////////////////////////////////////////// -//// //// -//// //// - -void meshGRegionBoundaryRecovery::carveholes() -{ - arraypool *tetarray, *hullarray; - triface tetloop, neightet, *parytet, *parytet1; - triface *regiontets = NULL; - face checksh, *parysh; - face checkseg; - point ptloop, *parypt; - int t1ver; - int i, j, k; - - if (!b->quiet) { - if (b->convex) { - Msg::Info(" --> Marking exterior tetrahedra ..."); - } else { - Msg::Info(" --> Removing exterior tetrahedra ..."); - } - } - - // Initialize the pool of exterior tets. - tetarray = new arraypool(sizeof(triface), 10); - hullarray = new arraypool(sizeof(triface), 10); - - // Collect unprotected tets and hull tets. - tetrahedrons->traversalinit(); - tetloop.ver = 11; // The face opposite to dummypoint. - tetloop.tet = alltetrahedrontraverse(); - while (tetloop.tet != (tetrahedron *) NULL) { - if (ishulltet(tetloop)) { - // Is this side protected by a subface? - if (!issubface(tetloop)) { - // Collect an unprotected hull tet and tet. - infect(tetloop); - hullarray->newindex((void **) &parytet); - *parytet = tetloop; - // tetloop's face number is 11 & 3 = 3. - decode(tetloop.tet[3], neightet); - if (!infected(neightet)) { - infect(neightet); - tetarray->newindex((void **) &parytet); - *parytet = neightet; - } - } - } - tetloop.tet = alltetrahedrontraverse(); - } - - // Collect all exterior tets (in concave place and in holes). - for (i = 0; i < tetarray->objects; i++) { - parytet = (triface *) fastlookup(tetarray, i); - j = (parytet->ver & 3); // j is the current face number. - // Check the other three adjacent tets. - for (k = 1; k < 4; k++) { - decode(parytet->tet[(j + k) % 4], neightet); - // neightet may be a hull tet. - if (!infected(neightet)) { - // Is neightet protected by a subface. - if (!issubface(neightet)) { - // Not proected. Collect it. (It must not be a hull tet). - infect(neightet); - tetarray->newindex((void **) &parytet1); - *parytet1 = neightet; - } else { - // Protected. Check if it is a hull tet. - if (ishulltet(neightet)) { - // A hull tet. Collect it. - infect(neightet); - hullarray->newindex((void **) &parytet1); - *parytet1 = neightet; - // Both sides of this subface are exterior. - tspivot(neightet, checksh); - // Queue this subface (to be deleted later). - assert(!sinfected(checksh)); - sinfect(checksh); // Only queue it once. - subfacstack->newindex((void **) &parysh); - *parysh = checksh; - } - } - } else { - // Both sides of this face are in exterior. - // If there is a subface. It should be collected. - if (issubface(neightet)) { - tspivot(neightet, checksh); - if (!sinfected(checksh)) { - sinfect(checksh); - subfacstack->newindex((void **) &parysh); - *parysh = checksh; - } - } - } - } // j, k - } // i - - // Collect vertices which point to infected tets. These vertices - // may get deleted after the removal of exterior tets. - // If -Y1 option is used, collect all Steiner points for removal. - // The lists 'cavetetvertlist' and 'subvertstack' are re-used. - points->traversalinit(); - ptloop = pointtraverse(); - while (ptloop != NULL) { - if ((pointtype(ptloop) != UNUSEDVERTEX) && - (pointtype(ptloop) != DUPLICATEDVERTEX)) { - decode(point2tet(ptloop), neightet); - if (infected(neightet)) { - cavetetvertlist->newindex((void **) &parypt); - *parypt = ptloop; - } - if (b->nobisect && (b->nobisect_param > 0)) { // -Y1 - // Queue it if it is a Steiner point. - //if (pointmark(ptloop) > - // (in->numberofpoints - (in->firstnumber ? 0 : 1))) { - if (issteinerpoint(ptloop)) { - subvertstack->newindex((void **) &parypt); - *parypt = ptloop; - } - } - } - ptloop = pointtraverse(); - } - - if (!b->convex && (tetarray->objects > 0l)) { // No -c option. - // Remove exterior tets. Hull tets are updated. - arraypool *newhullfacearray; - triface hulltet, casface; - point pa, pb, pc; - - newhullfacearray = new arraypool(sizeof(triface), 10); - - // Create and save new hull tets. - for (i = 0; i < tetarray->objects; i++) { - parytet = (triface *) fastlookup(tetarray, i); - for (j = 0; j < 4; j++) { - decode(parytet->tet[j], tetloop); - if (!infected(tetloop)) { - // Found a new hull face (must be a subface). - tspivot(tetloop, checksh); - maketetrahedron(&hulltet); - pa = org(tetloop); - pb = dest(tetloop); - pc = apex(tetloop); - setvertices(hulltet, pb, pa, pc, dummypoint); - bond(tetloop, hulltet); - // Update the subface-to-tet map. - sesymself(checksh); - tsbond(hulltet, checksh); - // Update the segment-to-tet map. - for (k = 0; k < 3; k++) { - if (issubseg(tetloop)) { - tsspivot1(tetloop, checkseg); - tssbond1(hulltet, checkseg); - sstbond1(checkseg, hulltet); - } - enextself(tetloop); - eprevself(hulltet); - } - // Update the point-to-tet map. - setpoint2tet(pa, (tetrahedron) tetloop.tet); - setpoint2tet(pb, (tetrahedron) tetloop.tet); - setpoint2tet(pc, (tetrahedron) tetloop.tet); - // Save the exterior tet at this hull face. It still holds pointer - // to the adjacent interior tet. Use it to connect new hull tets. - newhullfacearray->newindex((void **) &parytet1); - parytet1->tet = parytet->tet; - parytet1->ver = j; - } // if (!infected(tetloop)) - } // j - } // i - - // Connect new hull tets. - for (i = 0; i < newhullfacearray->objects; i++) { - parytet = (triface *) fastlookup(newhullfacearray, i); - fsym(*parytet, neightet); - // Get the new hull tet. - fsym(neightet, hulltet); - for (j = 0; j < 3; j++) { - esym(hulltet, casface); - if (casface.tet[casface.ver & 3] == NULL) { - // Since the boundary of the domain may not be a manifold, we - // find the adjacent hull face by traversing the tets in the - // exterior (which are all infected tets). - neightet = *parytet; - while (1) { - fnextself(neightet); - if (!infected(neightet)) break; - } - if (!ishulltet(neightet)) { - // An interior tet. Get the new hull tet. - fsymself(neightet); - esymself(neightet); - } - // Bond them together. - bond(casface, neightet); - } - enextself(hulltet); - enextself(*parytet); - } // j - } // i - - if (subfacstack->objects > 0l) { - // Remove all subfaces which do not attach to any tetrahedron. - // Segments which are not attached to any subfaces and tets - // are deleted too. - face casingout, casingin; - long delsegcount = 0l; - - for (i = 0; i < subfacstack->objects; i++) { - parysh = (face *) fastlookup(subfacstack, i); - if (i == 0) { - if (b->verbose) { - printf("Warning: Removing an open face (%d, %d, %d)\n", - pointmark(sorg(*parysh)), pointmark(sdest(*parysh)), - pointmark(sapex(*parysh))); - } - } - // Dissolve this subface from face links. - for (j = 0; j < 3; j++) { - spivot(*parysh, casingout); - sspivot(*parysh, checkseg); - if (casingout.sh != NULL) { - casingin = casingout; - while (1) { - spivot(casingin, checksh); - if (checksh.sh == parysh->sh) break; - casingin = checksh; - } - if (casingin.sh != casingout.sh) { - // Update the link: ... -> casingin -> casingout ->... - sbond1(casingin, casingout); - } else { - // Only one subface at this edge is left. - sdissolve(casingout); - } - if (checkseg.sh != NULL) { - // Make sure the segment does not connect to a dead one. - ssbond(casingout, checkseg); - } - } else { - if (checkseg.sh != NULL) { - // The segment is also dead. - if (delsegcount == 0) { - if (b->verbose) { - printf("Warning: Removing a dangling segment (%d, %d)\n", - pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); - } - } - shellfacedealloc(subsegs, checkseg.sh); - delsegcount++; - } - } - senextself(*parysh); - } // j - // Delete this subface. - shellfacedealloc(subfaces, parysh->sh); - } // i - if (b->verbose) { - printf(" Deleted %ld subfaces.\n", subfacstack->objects); - if (delsegcount > 0) { - printf(" Deleted %ld segments.\n", delsegcount); - } - } - subfacstack->restart(); - } // if (subfacstack->objects > 0l) - - if (cavetetvertlist->objects > 0l) { - // Some vertices may lie in exterior. Marke them as UNUSEDVERTEX. - long delvertcount = unuverts; - long delsteinercount = 0l; - - for (i = 0; i < cavetetvertlist->objects; i++) { - parypt = (point *) fastlookup(cavetetvertlist, i); - decode(point2tet(*parypt), neightet); - if (infected(neightet)) { - // Found an exterior vertex. - //if (pointmark(*parypt) > - // (in->numberofpoints - (in->firstnumber ? 0 : 1))) { - if (issteinerpoint(*parypt)) { - // A Steiner point. - if (pointtype(*parypt) == FREESEGVERTEX) { - st_segref_count--; - } else if (pointtype(*parypt) == FREEFACETVERTEX) { - st_facref_count--; - } else { - assert(pointtype(*parypt) == FREEVOLVERTEX); - st_volref_count--; - } - delsteinercount++; - if (steinerleft > 0) steinerleft++; - } - setpointtype(*parypt, UNUSEDVERTEX); - unuverts++; - } - } - - if (b->verbose) { - if (unuverts > delvertcount) { - if (delsteinercount > 0l) { - if (unuverts > (delvertcount + delsteinercount)) { - printf(" Removed %ld exterior input vertices.\n", - unuverts - delvertcount - delsteinercount); - } - printf(" Removed %ld exterior Steiner vertices.\n", - delsteinercount); - } else { - printf(" Removed %ld exterior input vertices.\n", - unuverts - delvertcount); - } - } - } - cavetetvertlist->restart(); - // Comment: 'subvertstack' will be cleaned in routine - // suppresssteinerpoints(). - } // if (cavetetvertlist->objects > 0l) - - // Update the hull size. - hullsize += (newhullfacearray->objects - hullarray->objects); - - // Delete all exterior tets and old hull tets. - for (i = 0; i < tetarray->objects; i++) { - parytet = (triface *) fastlookup(tetarray, i); - tetrahedrondealloc(parytet->tet); - } - tetarray->restart(); - - for (i = 0; i < hullarray->objects; i++) { - parytet = (triface *) fastlookup(hullarray, i); - tetrahedrondealloc(parytet->tet); - } - hullarray->restart(); - - delete newhullfacearray; - } // if (!b->convex && (tetarray->objects > 0l)) - - if (b->convex && (tetarray->objects > 0l)) { // With -c option - // In this case, all exterior tets get a region marker '-1'. - assert(b->regionattrib > 0); // -A option must be enabled. - int attrnum = numelemattrib - 1; - - for (i = 0; i < tetarray->objects; i++) { - parytet = (triface *) fastlookup(tetarray, i); - setelemattribute(parytet->tet, attrnum, -1); - } - tetarray->restart(); - - for (i = 0; i < hullarray->objects; i++) { - parytet = (triface *) fastlookup(hullarray, i); - uninfect(*parytet); - } - hullarray->restart(); - - if (subfacstack->objects > 0l) { - for (i = 0; i < subfacstack->objects; i++) { - parysh = (face *) fastlookup(subfacstack, i); - suninfect(*parysh); - } - subfacstack->restart(); - } - - if (cavetetvertlist->objects > 0l) { - cavetetvertlist->restart(); - } - } // if (b->convex && (tetarray->objects > 0l)) - - if (b->regionattrib) { // With -A option. - if (!b->quiet) { - Msg::Info(" --> Spreading region attributes ..."); - } - REAL volume; - int attr, maxattr = 0; // Choose a small number here. - int attrnum = numelemattrib - 1; - // Comment: The element region marker is at the end of the list of - // the element attributes. - int regioncount = 0; - - // Set attributes for all tetrahedra. - attr = maxattr + 1; - tetrahedrons->traversalinit(); - tetloop.tet = tetrahedrontraverse(); - while (tetloop.tet != (tetrahedron *) NULL) { - if (!infected(tetloop)) { - // An unmarked region. - tetarray->restart(); // Re-use this array. - infect(tetloop); - tetarray->newindex((void **) &parytet); - *parytet = tetloop; - // Find and mark all tets. - for (j = 0; j < tetarray->objects; j++) { - parytet = (triface *) fastlookup(tetarray, j); - tetloop = *parytet; - setelemattribute(tetloop.tet, attrnum, attr); - for (k = 0; k < 4; k++) { - decode(tetloop.tet[k], neightet); - // Is the adjacent tet already checked? - if (!infected(neightet)) { - // Is this side protected by a subface? - if (!issubface(neightet)) { - infect(neightet); - tetarray->newindex((void **) &parytet); - *parytet = neightet; - } - } - } // k - } // j - attr++; // Increase the attribute. - regioncount++; - } - tetloop.tet = tetrahedrontraverse(); - } - // Until here, every tet has a region attribute. - - // Uninfect processed tets. - tetrahedrons->traversalinit(); - tetloop.tet = tetrahedrontraverse(); - while (tetloop.tet != (tetrahedron *) NULL) { - uninfect(tetloop); - tetloop.tet = tetrahedrontraverse(); - } - - if (b->verbose) { - //assert(regioncount > 0); - if (regioncount > 1) { - printf(" Found %d subdomains.\n", regioncount); - } else { - printf(" Found %d domain.\n", regioncount); - } - } - } // if (b->regionattrib) - - if (regiontets != NULL) { - delete [] regiontets; - } - delete tetarray; - delete hullarray; - - if (!b->convex) { // No -c option - // The mesh is non-convex now. - nonconvex = 1; - - // Push all hull tets into 'flipstack'. - tetrahedrons->traversalinit(); - tetloop.ver = 11; // The face opposite to dummypoint. - tetloop.tet = alltetrahedrontraverse(); - while (tetloop.tet != (tetrahedron *) NULL) { - if ((point) tetloop.tet[7] == dummypoint) { - fsym(tetloop, neightet); - flippush(flipstack, &neightet); - } - tetloop.tet = alltetrahedrontraverse(); - } - - flipconstraints fc; - fc.enqflag = 2; - long sliver_peel_count = lawsonflip3d(&fc); - - if (sliver_peel_count > 0l) { - if (b->verbose) { - printf(" Removed %ld hull slivers.\n", sliver_peel_count); - } - } - unflipqueue->restart(); - } // if (!b->convex) -} - -//// //// -//// //// -//// reconstruct_cxx ////////////////////////////////////////////////////////// - -//// optimize_cxx ///////////////////////////////////////////////////////////// -//// //// -//// //// - -long meshGRegionBoundaryRecovery::lawsonflip3d(flipconstraints *fc) -{ - triface fliptets[5], neightet, hulltet; - face checksh, casingout; - badface *popface, *bface; - point pd, pe, *pts; - REAL sign, ori; - long flipcount, totalcount = 0l; - long sliver_peels = 0l; - int t1ver; - int i; - - - while (1) { - - if (b->verbose > 2) { - printf(" Lawson flip %ld faces.\n", flippool->items); - } - flipcount = 0l; - - while (flipstack != (badface *) NULL) { - // Pop a face from the stack. - popface = flipstack; - fliptets[0] = popface->tt; - flipstack = flipstack->nextitem; // The next top item in stack. - flippool->dealloc((void *) popface); - - // Skip it if it is a dead tet (destroyed by previous flips). - if (isdeadtet(fliptets[0])) continue; - // Skip it if it is not the same tet as we saved. - if (!facemarked(fliptets[0])) continue; - - unmarkface(fliptets[0]); - - if (ishulltet(fliptets[0])) continue; - - fsym(fliptets[0], fliptets[1]); - if (ishulltet(fliptets[1])) { - if (nonconvex) { - // Check if 'fliptets[0]' it is a hull sliver. - tspivot(fliptets[0], checksh); - for (i = 0; i < 3; i++) { - if (!isshsubseg(checksh)) { - spivot(checksh, casingout); - //assert(casingout.sh != NULL); - if (sorg(checksh) != sdest(casingout)) sesymself(casingout); - stpivot(casingout, neightet); - if (neightet.tet == fliptets[0].tet) { - // Found a hull sliver 'neightet'. Let it be [e,d,a,b], where - // [e,d,a] and [d,e,b] are hull faces. - edestoppo(neightet, hulltet); // [a,b,e,d] - fsymself(hulltet); // [b,a,e,#] - if (oppo(hulltet) == dummypoint) { - pe = org(neightet); - if ((pointtype(pe) == FREEFACETVERTEX) || - (pointtype(pe) == FREESEGVERTEX)) { - removevertexbyflips(pe); - } - } else { - eorgoppo(neightet, hulltet); // [b,a,d,e] - fsymself(hulltet); // [a,b,d,#] - if (oppo(hulltet) == dummypoint) { - pd = dest(neightet); - if ((pointtype(pd) == FREEFACETVERTEX) || - (pointtype(pd) == FREESEGVERTEX)) { - removevertexbyflips(pd); - } - } else { - // Perform a 3-to-2 flip to remove the sliver. - fliptets[0] = neightet; // [e,d,a,b] - fnext(fliptets[0], fliptets[1]); // [e,d,b,c] - fnext(fliptets[1], fliptets[2]); // [e,d,c,a] - flip32(fliptets, 1, fc); - // Update counters. - flip32count--; - flip22count--; - sliver_peels++; - if (fc->remove_ndelaunay_edge) { - // Update the volume (must be decreased). - //assert(fc->tetprism_vol_sum <= 0); - tetprism_vol_sum += fc->tetprism_vol_sum; - fc->tetprism_vol_sum = 0.0; // Clear it. - } - } - } - break; - } // if (neightet.tet == fliptets[0].tet) - } // if (!isshsubseg(checksh)) - senextself(checksh); - } // i - } // if (nonconvex) - continue; - } - - if (checksubfaceflag) { - // Do not flip if it is a subface. - if (issubface(fliptets[0])) continue; - } - - // Test whether the face is locally Delaunay or not. - pts = (point *) fliptets[1].tet; - sign = insphere_s(pts[4], pts[5], pts[6], pts[7], oppo(fliptets[0])); - - if (sign < 0) { - // A non-Delaunay face. Try to flip it. - pd = oppo(fliptets[0]); - pe = oppo(fliptets[1]); - - // Check the convexity of its three edges. Stop checking either a - // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is - // encountered, and 'fliptet' represents that edge. - for (i = 0; i < 3; i++) { - ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe); - if (ori <= 0) break; - enextself(fliptets[0]); - } - - if (ori > 0) { - // A 2-to-3 flip is found. - // [0] [a,b,c,d], - // [1] [b,a,c,e]. no dummypoint. - flip23(fliptets, 0, fc); - flipcount++; - if (fc->remove_ndelaunay_edge) { - // Update the volume (must be decreased). - //assert(fc->tetprism_vol_sum <= 0); - tetprism_vol_sum += fc->tetprism_vol_sum; - fc->tetprism_vol_sum = 0.0; // Clear it. - } - continue; - } else { // ori <= 0 - // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat, - // where the edge [a',b'] is one of [a,b], [b,c], and [c,a]. - if (checksubsegflag) { - // Do not flip if it is a segment. - if (issubseg(fliptets[0])) continue; - } - // Check if there are three or four tets sharing at this edge. - esymself(fliptets[0]); // [b,a,d,c] - for (i = 0; i < 3; i++) { - fnext(fliptets[i], fliptets[i+1]); - } - if (fliptets[3].tet == fliptets[0].tet) { - // A 3-to-2 flip is found. (No hull tet.) - flip32(fliptets, 0, fc); - flipcount++; - if (fc->remove_ndelaunay_edge) { - // Update the volume (must be decreased). - //assert(fc->tetprism_vol_sum <= 0); - tetprism_vol_sum += fc->tetprism_vol_sum; - fc->tetprism_vol_sum = 0.0; // Clear it. - } - continue; - } else { - // There are more than 3 tets at this edge. - fnext(fliptets[3], fliptets[4]); - if (fliptets[4].tet == fliptets[0].tet) { - // There are exactly 4 tets at this edge. - if (nonconvex) { - if (apex(fliptets[3]) == dummypoint) { - // This edge is locally non-convex on the hull. - // It can be removed by a 4-to-4 flip. - ori = 0; - } - } // if (nonconvex) - if (ori == 0) { - // A 4-to-4 flip is found. (Two hull tets may be involved.) - // Current tets in 'fliptets': - // [0] [b,a,d,c] (d may be newpt) - // [1] [b,a,c,e] - // [2] [b,a,e,f] (f may be dummypoint) - // [3] [b,a,f,d] - esymself(fliptets[0]); // [a,b,c,d] - // A 2-to-3 flip replaces face [a,b,c] by edge [e,d]. - // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]). - // It will be removed by the followed 3-to-2 flip. - flip23(fliptets, 0, fc); // No hull tet. - fnext(fliptets[3], fliptets[1]); - fnext(fliptets[1], fliptets[2]); - // Current tets in 'fliptets': - // [0] [...] - // [1] [b,a,d,e] (degenerated, d may be new point). - // [2] [b,a,e,f] (f may be dummypoint) - // [3] [b,a,f,d] - // A 3-to-2 flip replaces edge [b,a] by face [d,e,f]. - // Hull tets may be involved (f may be dummypoint). - flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc); - flipcount++; - flip23count--; - flip32count--; - flip44count++; - if (fc->remove_ndelaunay_edge) { - // Update the volume (must be decreased). - //assert(fc->tetprism_vol_sum <= 0); - tetprism_vol_sum += fc->tetprism_vol_sum; - fc->tetprism_vol_sum = 0.0; // Clear it. - } - continue; - } // if (ori == 0) - } - } - } // if (ori <= 0) - - // This non-Delaunay face is unflippable. Save it. - unflipqueue->newindex((void **) &bface); - bface->tt = fliptets[0]; - bface->forg = org(fliptets[0]); - bface->fdest = dest(fliptets[0]); - bface->fapex = apex(fliptets[0]); - } // if (sign < 0) - } // while (flipstack) - - if (b->verbose > 2) { - if (flipcount > 0) { - printf(" Performed %ld flips.\n", flipcount); - } - } - // Accumulate the counter of flips. - totalcount += flipcount; - - assert(flippool->items == 0l); - // Return if no unflippable faces left. - if (unflipqueue->objects == 0l) break; - // Return if no flip has been performed. - if (flipcount == 0l) break; - - // Try to flip the unflippable faces. - for (i = 0; i < unflipqueue->objects; i++) { - bface = (badface *) fastlookup(unflipqueue, i); - if (!isdeadtet(bface->tt) && - (org(bface->tt) == bface->forg) && - (dest(bface->tt) == bface->fdest) && - (apex(bface->tt) == bface->fapex)) { - flippush(flipstack, &(bface->tt)); - } - } - unflipqueue->restart(); - - } // while (1) - - if (b->verbose > 2) { - if (totalcount > 0) { - printf(" Performed %ld flips.\n", totalcount); - } - if (sliver_peels > 0) { - printf(" Removed %ld hull slivers.\n", sliver_peels); - } - if (unflipqueue->objects > 0l) { - printf(" %ld unflippable edges remained.\n", unflipqueue->objects); - } - } - - return totalcount + sliver_peels; -} - -bool meshGRegionBoundaryRecovery::recoverdelaunay() -{ - arraypool *flipqueue, *nextflipqueue, *swapqueue; - triface tetloop, neightet, *parytet; - badface *bface, *parybface; - point *ppt; - flipconstraints fc; - int i, j; - - if (!b->quiet) { - Msg::Info(" --> Recovering Delaunayness ..."); - } - - tetprism_vol_sum = 0.0; // Initialize it. - - // Put all interior faces of the mesh into 'flipstack'. - tetrahedrons->traversalinit(); - tetloop.tet = tetrahedrontraverse(); - while (tetloop.tet != NULL) { - for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) { - decode(tetloop.tet[tetloop.ver], neightet); - if (!facemarked(neightet)) { - flippush(flipstack, &tetloop); - } - } - ppt = (point *) &(tetloop.tet[4]); - tetprism_vol_sum += tetprismvol(ppt[0], ppt[1], ppt[2], ppt[3]); - tetloop.tet = tetrahedrontraverse(); - } - - // Calulate a relatively lower bound for small improvement. - // Used to avoid rounding error in volume calculation. - fc.bak_tetprism_vol = tetprism_vol_sum * b->epsilon * 1e-3; - - if (b->verbose) { - printf(" Initial obj = %.17g\n", tetprism_vol_sum); - } - - if (b->verbose > 1) { - printf(" Recover Delaunay [Lawson] : %ld\n", flippool->items); - } - - // First only use the basic Lawson's flip. - fc.remove_ndelaunay_edge = 1; - fc.enqflag = 2; - - lawsonflip3d(&fc); - - if (b->verbose > 1) { - printf(" obj (after Lawson) = %.17g\n", tetprism_vol_sum); - } - - if (unflipqueue->objects == 0l) { - return true; // The mesh is Delaunay. - } - - fc.unflip = 1; // Unflip if the edge is not flipped. - fc.collectnewtets = 1; // new tets are returned in 'cavetetlist'. - fc.enqflag = 0; - - autofliplinklevel = 1; // Init level. - b->fliplinklevel = -1; // No fixed level. - - // For efficiency reason, we limit the maximium size of the edge star. - int bakmaxflipstarsize = b->flipstarsize; - b->flipstarsize = 10; // default - - flipqueue = new arraypool(sizeof(badface), 10); - nextflipqueue = new arraypool(sizeof(badface), 10); - - // Swap the two flip queues. - swapqueue = flipqueue; - flipqueue = unflipqueue; - unflipqueue = swapqueue; - - while (flipqueue->objects > 0l) { - - if (b->verbose > 1) { - printf(" Recover Delaunay [level = %2d] #: %ld.\n", - autofliplinklevel, flipqueue->objects); - } - - for (i = 0; i < flipqueue->objects; i++) { - bface = (badface *) fastlookup(flipqueue, i); - if (getedge(bface->forg, bface->fdest, &bface->tt)) { - if (removeedgebyflips(&(bface->tt), &fc) == 2) { - tetprism_vol_sum += fc.tetprism_vol_sum; - fc.tetprism_vol_sum = 0.0; // Clear it. - // Queue new faces for flips. - for (j = 0; j < cavetetlist->objects; j++) { - parytet = (triface *) fastlookup(cavetetlist, j); - // A queued new tet may be dead. - if (!isdeadtet(*parytet)) { - for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) { - // Avoid queue a face twice. - decode(parytet->tet[parytet->ver], neightet); - if (!facemarked(neightet)) { - flippush(flipstack, parytet); - } - } // parytet->ver - } - } // j - cavetetlist->restart(); - // Remove locally non-Delaunay faces. New non-Delaunay edges - // may be found. They are saved in 'unflipqueue'. - fc.enqflag = 2; - lawsonflip3d(&fc); - fc.enqflag = 0; - // There may be unflipable faces. Add them in flipqueue. - for (j = 0; j < unflipqueue->objects; j++) { - bface = (badface *) fastlookup(unflipqueue, j); - flipqueue->newindex((void **) &parybface); - *parybface = *bface; - } - unflipqueue->restart(); - } else { - // Unable to remove this edge. Save it. - nextflipqueue->newindex((void **) &parybface); - *parybface = *bface; - // Normally, it should be zero. - //assert(fc.tetprism_vol_sum == 0.0); - // However, due to rounding errors, a tiny value may appear. - fc.tetprism_vol_sum = 0.0; - } - } - } // i - - if (b->verbose > 1) { - printf(" obj (after level %d) = %.17g.\n", autofliplinklevel, - tetprism_vol_sum); - } - flipqueue->restart(); - - // Swap the two flip queues. - swapqueue = flipqueue; - flipqueue = nextflipqueue; - nextflipqueue = swapqueue; - - if (flipqueue->objects > 0l) { - // default 'b->delmaxfliplevel' is 1. - if (autofliplinklevel >= b->delmaxfliplevel) { - // For efficiency reason, we do not search too far. - break; - } - autofliplinklevel+=b->fliplinklevelinc; - } - } // while (flipqueue->objects > 0l) - - bool returnValue = true; - if (flipqueue->objects > 0l) { - returnValue = false; - if (b->verbose > 1) { - printf(" %ld non-Delaunay edges remained.\n", flipqueue->objects); - } - } - - if (b->verbose) { - printf(" Final obj = %.17g\n", tetprism_vol_sum); - } - - b->flipstarsize = bakmaxflipstarsize; - delete flipqueue; - delete nextflipqueue; - return returnValue; -} - -int meshGRegionBoundaryRecovery::gettetrahedron(point pa, point pb, point pc, - point pd, triface *searchtet) -{ - triface spintet; - int t1ver; - - if (getedge(pa, pb, searchtet)) { - spintet = *searchtet; - while (1) { - if (apex(spintet) == pc) { - *searchtet = spintet; - break; - } - fnextself(spintet); - if (spintet.tet == searchtet->tet) break; - } - if (apex(*searchtet) == pc) { - if (oppo(*searchtet) == pd) { - return 1; - } else { - fsymself(*searchtet); - if (oppo(*searchtet) == pd) { - return 1; - } - } - } - } - - return 0; -} - -long meshGRegionBoundaryRecovery::improvequalitybyflips() -{ - arraypool *flipqueue, *nextflipqueue, *swapqueue; - badface *bface, *parybface; - triface *parytet; - point *ppt; - flipconstraints fc; - REAL *cosdd, ncosdd[6], maxdd; - long totalremcount, remcount; - int remflag; - int n, i, j, k; - - //assert(unflipqueue->objects > 0l); - flipqueue = new arraypool(sizeof(badface), 10); - nextflipqueue = new arraypool(sizeof(badface), 10); - - // Backup flip edge options. - int bakautofliplinklevel = autofliplinklevel; - int bakfliplinklevel = b->fliplinklevel; - int bakmaxflipstarsize = b->flipstarsize; - - // Set flip edge options. - autofliplinklevel = 1; - b->fliplinklevel = -1; - b->flipstarsize = 10; // b->optmaxflipstarsize; - - fc.remove_large_angle = 1; - fc.unflip = 1; - fc.collectnewtets = 1; - fc.checkflipeligibility = 1; - - totalremcount = 0l; - - // Swap the two flip queues. - swapqueue = flipqueue; - flipqueue = unflipqueue; - unflipqueue = swapqueue; - - while (flipqueue->objects > 0l) { - - remcount = 0l; - - while (flipqueue->objects > 0l) { - if (b->verbose > 1) { - printf(" Improving mesh qualiy by flips [%d]#: %ld.\n", - autofliplinklevel, flipqueue->objects); - } - - for (k = 0; k < flipqueue->objects; k++) { - bface = (badface *) fastlookup(flipqueue, k); - if (gettetrahedron(bface->forg, bface->fdest, bface->fapex, - bface->foppo, &bface->tt)) { - //assert(!ishulltet(bface->tt)); - // There are bad dihedral angles in this tet. - if (bface->tt.ver != 11) { - // The dihedral angles are permuted. - // Here we simply re-compute them. Slow!!. - ppt = (point *) & (bface->tt.tet[4]); - tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, - &bface->key, NULL); - bface->forg = ppt[0]; - bface->fdest = ppt[1]; - bface->fapex = ppt[2]; - bface->foppo = ppt[3]; - bface->tt.ver = 11; - } - if (bface->key == 0) { - // Re-comput the quality values. Due to smoothing operations. - ppt = (point *) & (bface->tt.tet[4]); - tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, - &bface->key, NULL); - } - cosdd = bface->cent; - remflag = 0; - for (i = 0; (i < 6) && !remflag; i++) { - if (cosdd[i] < cosmaxdihed) { - // Found a large dihedral angle. - bface->tt.ver = edge2ver[i]; // Go to the edge. - fc.cosdihed_in = cosdd[i]; - fc.cosdihed_out = 0.0; // 90 degree. - n = removeedgebyflips(&(bface->tt), &fc); - if (n == 2) { - // Edge is flipped. - remflag = 1; - if (fc.cosdihed_out < cosmaxdihed) { - // Queue new bad tets for further improvements. - for (j = 0; j < cavetetlist->objects; j++) { - parytet = (triface *) fastlookup(cavetetlist, j); - if (!isdeadtet(*parytet)) { - ppt = (point *) & (parytet->tet[4]); - // Do not test a hull tet. - if (ppt[3] != dummypoint) { - tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, - &maxdd, NULL); - if (maxdd < cosmaxdihed) { - // There are bad dihedral angles in this tet. - nextflipqueue->newindex((void **) &parybface); - parybface->tt.tet = parytet->tet; - parybface->tt.ver = 11; - parybface->forg = ppt[0]; - parybface->fdest = ppt[1]; - parybface->fapex = ppt[2]; - parybface->foppo = ppt[3]; - parybface->key = maxdd; - for (n = 0; n < 6; n++) { - parybface->cent[n] = ncosdd[n]; - } - } - } // if (ppt[3] != dummypoint) - } - } // j - } // if (fc.cosdihed_out < cosmaxdihed) - cavetetlist->restart(); - remcount++; - } - } - } // i - if (!remflag) { - // An unremoved bad tet. Queue it again. - unflipqueue->newindex((void **) &parybface); - *parybface = *bface; - } - } // if (gettetrahedron(...)) - } // k - - flipqueue->restart(); - - // Swap the two flip queues. - swapqueue = flipqueue; - flipqueue = nextflipqueue; - nextflipqueue = swapqueue; - } // while (flipqueues->objects > 0) - - if (b->verbose > 1) { - printf(" Removed %ld bad tets.\n", remcount); - } - totalremcount += remcount; - - if (unflipqueue->objects > 0l) { - //if (autofliplinklevel >= b->optmaxfliplevel) { - if (autofliplinklevel >= b->optlevel) { - break; - } - autofliplinklevel+=b->fliplinklevelinc; - //b->flipstarsize = 10 + (1 << (b->optlevel - 1)); - } - - // Swap the two flip queues. - swapqueue = flipqueue; - flipqueue = unflipqueue; - unflipqueue = swapqueue; - } // while (flipqueues->objects > 0) - - // Restore original flip edge options. - autofliplinklevel = bakautofliplinklevel; - b->fliplinklevel = bakfliplinklevel; - b->flipstarsize = bakmaxflipstarsize; - - delete flipqueue; - delete nextflipqueue; - - return totalremcount; -} - -int meshGRegionBoundaryRecovery::smoothpoint(point smtpt, - arraypool *linkfacelist, int ccw, optparameters *opm) -{ - triface *parytet, *parytet1, swaptet; - point pa, pb, pc; - REAL fcent[3], startpt[3], nextpt[3], bestpt[3]; - REAL oldval, minval = 0.0, val; - REAL maxcosd; // oldang, newang; - REAL ori, diff; - int numdirs, iter; - int i, j, k; - - // Decide the number of moving directions. - numdirs = (int) linkfacelist->objects; - if (numdirs > opm->numofsearchdirs) { - numdirs = opm->numofsearchdirs; // Maximum search directions. - } - - // Set the initial value. - if (!opm->max_min_volume) { - assert(opm->initval >= 0.0); - } - opm->imprval = opm->initval; - iter = 0; - - for (i = 0; i < 3; i++) { - bestpt[i] = startpt[i] = smtpt[i]; - } - - // Iterate until the obj function is not improved. - while (1) { - - // Find the best next location. - oldval = opm->imprval; - - for (i = 0; i < numdirs; i++) { - // Randomly pick a link face (0 <= k <= objects - i - 1). - k = (int) randomnation(linkfacelist->objects - i); - parytet = (triface *) fastlookup(linkfacelist, k); - // Calculate a new position from 'p' to the center of this face. - pa = org(*parytet); - pb = dest(*parytet); - pc = apex(*parytet); - for (j = 0; j < 3; j++) { - fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0; - } - for (j = 0; j < 3; j++) { - nextpt[j] = startpt[j] + opm->searchstep * (fcent[j] - startpt[j]); - } - // Calculate the largest minimum function value for the new location. - for (j = 0; j < linkfacelist->objects; j++) { - parytet = (triface *) fastlookup(linkfacelist, j); - if (ccw) { - pa = org(*parytet); - pb = dest(*parytet); - } else { - pb = org(*parytet); - pa = dest(*parytet); - } - pc = apex(*parytet); - ori = orient3d(pa, pb, pc, nextpt); - if (ori < 0.0) { - // Calcuate the objective function value. - if (opm->max_min_volume) { - //val = -ori; - val = - orient3dfast(pa, pb, pc, nextpt); - } else if (opm->min_max_aspectratio) { - val = tetaspectratio(pa, pb, pc, nextpt); - } else if (opm->min_max_dihedangle) { - tetalldihedral(pa, pb, pc, nextpt, NULL, &maxcosd, NULL); - if (maxcosd < -1) maxcosd = -1.0; // Rounding. - val = maxcosd + 1.0; // Make it be positive. - } else { - // Unknown objective function. - val = 0.0; - } - } else { // ori >= 0.0; - // An invalid new tet. - // This may happen if the mesh contains inverted elements. - if (opm->max_min_volume) { - //val = -ori; - val = - orient3dfast(pa, pb, pc, nextpt); - } else { - // Discard this point. - break; // j - } - } // if (ori >= 0.0) - // Stop looping when the object value is not improved. - if (val <= opm->imprval) { - break; // j - } else { - // Remember the smallest improved value. - if (j == 0) { - minval = val; - } else { - minval = (val < minval) ? val : minval; - } - } - } // j - if (j == linkfacelist->objects) { - // The function value has been improved. - opm->imprval = minval; - // Save the new location of the point. - for (j = 0; j < 3; j++) bestpt[j] = nextpt[j]; - } - // Swap k-th and (object-i-1)-th entries. - j = linkfacelist->objects - i - 1; - parytet = (triface *) fastlookup(linkfacelist, k); - parytet1 = (triface *) fastlookup(linkfacelist, j); - swaptet = *parytet1; - *parytet1 = *parytet; - *parytet = swaptet; - } // i - - diff = opm->imprval - oldval; - if (diff > 0.0) { - // Is the function value improved effectively? - if (opm->max_min_volume) { - //if ((diff / oldval) < b->epsilon) diff = 0.0; - } else if (opm->min_max_aspectratio) { - if ((diff / oldval) < 1e-3) diff = 0.0; - } else if (opm->min_max_dihedangle) { - //oldang = acos(oldval - 1.0); - //newang = acos(opm->imprval - 1.0); - //if ((oldang - newang) < 0.00174) diff = 0.0; // about 0.1 degree. - } else { - // Unknown objective function. - assert(0); // Not possible. - } - } - - if (diff > 0.0) { - // Yes, move p to the new location and continue. - for (j = 0; j < 3; j++) startpt[j] = bestpt[j]; - iter++; - if ((opm->maxiter > 0) && (iter >= opm->maxiter)) { - // Maximum smoothing iterations reached. - break; - } - } else { - break; - } - - } // while (1) - - if (iter > 0) { - // The point has been smoothed. - opm->smthiter = iter; // Remember the number of iterations. - // The point has been smoothed. Update it to its new position. - for (i = 0; i < 3; i++) smtpt[i] = startpt[i]; - } - - return iter; -} - - -long meshGRegionBoundaryRecovery::improvequalitybysmoothing(optparameters *opm) -{ - arraypool *flipqueue, *swapqueue; - triface *parytet; - badface *bface, *parybface; - point *ppt; - long totalsmtcount, smtcount; - int smtflag; - int iter, i, j, k; - - //assert(unflipqueue->objects > 0l); - flipqueue = new arraypool(sizeof(badface), 10); - - // Swap the two flip queues. - swapqueue = flipqueue; - flipqueue = unflipqueue; - unflipqueue = swapqueue; - - totalsmtcount = 0l; - iter = 0; - - while (flipqueue->objects > 0l) { - - smtcount = 0l; - - if (b->verbose > 1) { - printf(" Improving mesh quality by smoothing [%d]#: %ld.\n", - iter, flipqueue->objects); - } - - for (k = 0; k < flipqueue->objects; k++) { - bface = (badface *) fastlookup(flipqueue, k); - if (gettetrahedron(bface->forg, bface->fdest, bface->fapex, - bface->foppo, &bface->tt)) { - // Operate on it if it is not in 'unflipqueue'. - if (!marktested(bface->tt)) { - // Here we simply re-compute the quality. Since other smoothing - // operation may have moved the vertices of this tet. - ppt = (point *) & (bface->tt.tet[4]); - tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, - &bface->key, NULL); - if (bface->key < cossmtdihed) { // if (maxdd < cosslidihed) { - // It is a sliver. Try to smooth its vertices. - smtflag = 0; - opm->initval = bface->key + 1.0; - for (i = 0; (i < 4) && !smtflag; i++) { - if (pointtype(ppt[i]) == FREEVOLVERTEX) { - getvertexstar(1, ppt[i], cavetetlist, NULL, NULL); - opm->searchstep = 0.001; // Search step size - smtflag = smoothpoint(ppt[i], cavetetlist, 1, opm); - if (smtflag) { - while (opm->smthiter == opm->maxiter) { - opm->searchstep *= 10.0; // Increase the step size. - opm->initval = opm->imprval; - opm->smthiter = 0; // reset - smoothpoint(ppt[i], cavetetlist, 1, opm); - } - // This tet is modifed. - smtcount++; - if ((opm->imprval - 1.0) < cossmtdihed) { - // There are slivers in new tets. Queue them. - for (j = 0; j < cavetetlist->objects; j++) { - parytet = (triface *) fastlookup(cavetetlist, j); - assert(!isdeadtet(*parytet)); - // Operate it if it is not in 'unflipqueue'. - if (!marktested(*parytet)) { - // Evaluate its quality. - // Re-use ppt, bface->key, bface->cent. - ppt = (point *) & (parytet->tet[4]); - tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], - bface->cent, &bface->key, NULL); - if (bface->key < cossmtdihed) { - // A new sliver. Queue it. - marktest(*parytet); // It is in unflipqueue. - unflipqueue->newindex((void **) &parybface); - parybface->tt = *parytet; - parybface->forg = ppt[0]; - parybface->fdest = ppt[1]; - parybface->fapex = ppt[2]; - parybface->foppo = ppt[3]; - parybface->tt.ver = 11; - parybface->key = 0.0; - } - } - } // j - } // if ((opm->imprval - 1.0) < cossmtdihed) - } // if (smtflag) - cavetetlist->restart(); - } // if (pointtype(ppt[i]) == FREEVOLVERTEX) - } // i - if (!smtflag) { - // Didn't smooth. Queue it again. - marktest(bface->tt); // It is in unflipqueue. - unflipqueue->newindex((void **) &parybface); - parybface->tt = bface->tt; - parybface->forg = ppt[0]; - parybface->fdest = ppt[1]; - parybface->fapex = ppt[2]; - parybface->foppo = ppt[3]; - parybface->tt.ver = 11; - parybface->key = 0.0; - } - } // if (maxdd < cosslidihed) - } // if (!marktested(...)) - } // if (gettetrahedron(...)) - } // k - - flipqueue->restart(); - - // Unmark the tets in unflipqueue. - for (i = 0; i < unflipqueue->objects; i++) { - bface = (badface *) fastlookup(unflipqueue, i); - unmarktest(bface->tt); - } - - if (b->verbose > 1) { - printf(" Smooth %ld points.\n", smtcount); - } - totalsmtcount += smtcount; - - if (smtcount == 0l) { - // No point has been smoothed. - break; - } else { - iter++; - if (iter == 2) { //if (iter >= b->optpasses) { - break; - } - } - - // Swap the two flip queues. - swapqueue = flipqueue; - flipqueue = unflipqueue; - unflipqueue = swapqueue; - } // while - - delete flipqueue; - - return totalsmtcount; -} - -int meshGRegionBoundaryRecovery::splitsliver(triface *slitet, REAL cosd, - int chkencflag) -{ - triface *abtets; - triface searchtet, spintet, *parytet; - point pa, pb, steinerpt; - optparameters opm; - insertvertexflags ivf; - REAL smtpt[3], midpt[3]; - int success; - int t1ver; - int n, i; - - // 'slitet' is [c,d,a,b], where [c,d] has a big dihedral angle. - // Go to the opposite edge [a,b]. - edestoppo(*slitet, searchtet); // [a,b,c,d]. - - // Do not split a segment. - if (issubseg(searchtet)) { - return 0; - } - - // Count the number of tets shared at [a,b]. - // Do not split it if it is a hull edge. - spintet = searchtet; - n = 0; - while (1) { - if (ishulltet(spintet)) break; - n++; - fnextself(spintet); - if (spintet.tet == searchtet.tet) break; - } - if (ishulltet(spintet)) { - return 0; // It is a hull edge. - } - assert(n >= 3); - - // Get all tets at edge [a,b]. - abtets = new triface[n]; - spintet = searchtet; - for (i = 0; i < n; i++) { - abtets[i] = spintet; - fnextself(spintet); - } - - // Initialize the list of 2n boundary faces. - for (i = 0; i < n; i++) { - eprev(abtets[i], searchtet); - esymself(searchtet); // [a,p_i,p_i+1]. - cavetetlist->newindex((void **) &parytet); - *parytet = searchtet; - enext(abtets[i], searchtet); - esymself(searchtet); // [p_i,b,p_i+1]. - cavetetlist->newindex((void **) &parytet); - *parytet = searchtet; - } - - // Init the Steiner point at the midpoint of edge [a,b]. - pa = org(abtets[0]); - pb = dest(abtets[0]); - for (i = 0; i < 3; i++) { - smtpt[i] = midpt[i] = 0.5 * (pa[i] + pb[i]); - } - - // Point smooth options. - opm.min_max_dihedangle = 1; - opm.initval = cosd + 1.0; // Initial volume is zero. - opm.numofsearchdirs = 20; - opm.searchstep = 0.001; - opm.maxiter = 100; // Limit the maximum iterations. - - success = smoothpoint(smtpt, cavetetlist, 1, &opm); - - if (success) { - while (opm.smthiter == opm.maxiter) { - // It was relocated and the prescribed maximum iteration reached. - // Try to increase the search stepsize. - opm.searchstep *= 10.0; - //opm.maxiter = 100; // Limit the maximum iterations. - opm.initval = opm.imprval; - opm.smthiter = 0; // Init. - smoothpoint(smtpt, cavetetlist, 1, &opm); - } - } // if (success) - - cavetetlist->restart(); - - if (!success) { - delete [] abtets; - return 0; - } - - - // Insert the Steiner point. - makepoint(&steinerpt, FREEVOLVERTEX); - for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i]; - - // Insert the created Steiner point. - for (i = 0; i < n; i++) { - infect(abtets[i]); - caveoldtetlist->newindex((void **) &parytet); - *parytet = abtets[i]; - } - - searchtet = abtets[0]; // No need point location. - if (b->metric) { - locate(steinerpt, &searchtet); // For size interpolation. - } - - delete [] abtets; - - ivf.iloc = (int) INSTAR; - ivf.chkencflag = chkencflag; - ivf.assignmeshsize = b->metric; - - - if (insertpoint(steinerpt, &searchtet, NULL, NULL, &ivf)) { - // The vertex has been inserted. - st_volref_count++; - if (steinerleft > 0) steinerleft--; - return 1; - } else { - // The Steiner point is too close to an existing vertex. Reject it. - pointdealloc(steinerpt); - return 0; - } -} - -long meshGRegionBoundaryRecovery::removeslivers(int chkencflag) -{ - arraypool *flipqueue, *swapqueue; - badface *bface, *parybface; - triface slitet, *parytet; - point *ppt; - REAL cosdd[6], maxcosd; - long totalsptcount, sptcount; - int iter, i, j, k; - - //assert(unflipqueue->objects > 0l); - flipqueue = new arraypool(sizeof(badface), 10); - - // Swap the two flip queues. - swapqueue = flipqueue; - flipqueue = unflipqueue; - unflipqueue = swapqueue; - - totalsptcount = 0l; - iter = 0; - - while ((flipqueue->objects > 0l) && (steinerleft != 0)) { - - sptcount = 0l; - - if (b->verbose > 1) { - printf(" Splitting bad quality tets [%d]#: %ld.\n", - iter, flipqueue->objects); - } - - for (k = 0; (k < flipqueue->objects) && (steinerleft != 0); k++) { - bface = (badface *) fastlookup(flipqueue, k); - if (gettetrahedron(bface->forg, bface->fdest, bface->fapex, - bface->foppo, &bface->tt)) { - if ((bface->key == 0) || (bface->tt.ver != 11)) { - // Here we need to re-compute the quality. Since other smoothing - // operation may have moved the vertices of this tet. - ppt = (point *) & (bface->tt.tet[4]); - tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, - &bface->key, NULL); - } - if (bface->key < cosslidihed) { - // It is a sliver. Try to split it. - slitet.tet = bface->tt.tet; - //cosdd = bface->cent; - for (j = 0; j < 6; j++) { - if (bface->cent[j] < cosslidihed) { - // Found a large dihedral angle. - slitet.ver = edge2ver[j]; // Go to the edge. - if (splitsliver(&slitet, bface->cent[j], chkencflag)) { - sptcount++; - break; - } - } - } // j - if (j < 6) { - // A sliver is split. Queue new slivers. - badtetrahedrons->traversalinit(); - parytet = (triface *) badtetrahedrons->traverse(); - while (parytet != NULL) { - unmarktest2(*parytet); - ppt = (point *) & (parytet->tet[4]); - tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], cosdd, - &maxcosd, NULL); - if (maxcosd < cosslidihed) { - // A new sliver. Queue it. - unflipqueue->newindex((void **) &parybface); - parybface->forg = ppt[0]; - parybface->fdest = ppt[1]; - parybface->fapex = ppt[2]; - parybface->foppo = ppt[3]; - parybface->tt.tet = parytet->tet; - parybface->tt.ver = 11; - parybface->key = maxcosd; - for (i = 0; i < 6; i++) { - parybface->cent[i] = cosdd[i]; - } - } - parytet = (triface *) badtetrahedrons->traverse(); - } - badtetrahedrons->restart(); - } else { - // Didn't split. Queue it again. - unflipqueue->newindex((void **) &parybface); - *parybface = *bface; - } // if (j == 6) - } // if (bface->key < cosslidihed) - } // if (gettetrahedron(...)) - } // k - - flipqueue->restart(); - - if (b->verbose > 1) { - printf(" Split %ld tets.\n", sptcount); - } - totalsptcount += sptcount; - - if (sptcount == 0l) { - // No point has been smoothed. - break; - } else { - iter++; - if (iter == 2) { //if (iter >= b->optpasses) { - break; - } - } - - // Swap the two flip queues. - swapqueue = flipqueue; - flipqueue = unflipqueue; - unflipqueue = swapqueue; - } // while - - delete flipqueue; - - return totalsptcount; -} - -void meshGRegionBoundaryRecovery::optimizemesh() -{ - badface *parybface; - triface checktet; - point *ppt; - int optpasses; - optparameters opm; - REAL ncosdd[6], maxdd; - long totalremcount, remcount; - long totalsmtcount, smtcount; - long totalsptcount, sptcount; - int chkencflag; - int iter; - int n; - - if (!b->quiet) { - Msg::Info(" --> Optimizing mesh..."); - } - - optpasses = ((1 << b->optlevel) - 1); - - if (b->verbose) { - printf(" Optimization level = %d.\n", b->optlevel); - printf(" Optimization scheme = %d.\n", b->optscheme); - printf(" Number of iteration = %d.\n", optpasses); - printf(" Min_Max dihed angle = %g.\n", b->optmaxdihedral); - } - - totalsmtcount = totalsptcount = totalremcount = 0l; - - cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI); - cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI); - cosslidihed = cos(b->optminslidihed / 180.0 * PI); - - int attrnum = numelemattrib - 1; - - // Put all bad tetrahedra into array. - tetrahedrons->traversalinit(); - checktet.tet = tetrahedrontraverse(); - while (checktet.tet != NULL) { - if (b->convex) { // -c - // Skip this tet if it lies in the exterior. - if (elemattribute(checktet.tet, attrnum) == -1.0) { - checktet.tet = tetrahedrontraverse(); - continue; - } - } - ppt = (point *) & (checktet.tet[4]); - tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, &maxdd, NULL); - if (maxdd < cosmaxdihed) { - // There are bad dihedral angles in this tet. - unflipqueue->newindex((void **) &parybface); - parybface->tt.tet = checktet.tet; - parybface->tt.ver = 11; - parybface->forg = ppt[0]; - parybface->fdest = ppt[1]; - parybface->fapex = ppt[2]; - parybface->foppo = ppt[3]; - parybface->key = maxdd; - for (n = 0; n < 6; n++) { - parybface->cent[n] = ncosdd[n]; - } - } - checktet.tet = tetrahedrontraverse(); - } - - totalremcount = improvequalitybyflips(); - - if ((unflipqueue->objects > 0l) && - ((b->optscheme & 2) || (b->optscheme & 4))) { - // The pool is only used by removeslivers(). - badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock, - sizeof(void *), 0); - - // Smoothing options. - opm.min_max_dihedangle = 1; - opm.numofsearchdirs = 10; - // opm.searchstep = 0.001; - opm.maxiter = 30; // Limit the maximum iterations. - //opm.checkencflag = 4; // Queue affected tets after smoothing. - chkencflag = 4; // Queue affected tets after splitting a sliver. - iter = 0; - - while (iter < optpasses) { - smtcount = sptcount = remcount = 0l; - if (b->optscheme & 2) { - smtcount += improvequalitybysmoothing(&opm); - totalsmtcount += smtcount; - if (smtcount > 0l) { - remcount = improvequalitybyflips(); - totalremcount += remcount; - } - } - if (unflipqueue->objects > 0l) { - if (b->optscheme & 4) { - sptcount += removeslivers(chkencflag); - totalsptcount += sptcount; - if (sptcount > 0l) { - remcount = improvequalitybyflips(); - totalremcount += remcount; - } - } - } - if (unflipqueue->objects > 0l) { - if (remcount > 0l) { - iter++; - } else { - break; - } - } else { - break; - } - } // while (iter) - - delete badtetrahedrons; - - } - - if (unflipqueue->objects > 0l) { - if (b->verbose > 1) { - printf(" %ld bad tets remained.\n", unflipqueue->objects); - } - unflipqueue->restart(); - } - - if (b->verbose) { - if (totalremcount > 0l) { - printf(" Removed %ld edges.\n", totalremcount); - } - if (totalsmtcount > 0l) { - printf(" Smoothed %ld points.\n", totalsmtcount); - } - if (totalsptcount > 0l) { - printf(" Split %ld slivers.\n", totalsptcount); - } - } -} - -//// //// -//// //// -//// optimize_cxx ///////////////////////////////////////////////////////////// - -// Dump the input surface mesh. -// 'mfilename' is a filename without suffix. -void meshGRegionBoundaryRecovery::outsurfacemesh(const char* mfilename) -{ - FILE *outfile = NULL; - char sfilename[256]; - int firstindex; - - point pointloop; - int pointnumber; - strcpy(sfilename, mfilename); - strcat(sfilename, ".node"); - outfile = fopen(sfilename, "w"); - if (!b->quiet) { - printf("Writing %s.\n", sfilename); - } - fprintf(outfile, "%ld 3 0 0\n", points->items); - // Determine the first index (0 or 1). - firstindex = b->zeroindex ? 0 : in->firstnumber; - points->traversalinit(); - pointloop = pointtraverse(); - pointnumber = firstindex; // in->firstnumber; - while (pointloop != (point) NULL) { - // Point number, x, y and z coordinates. - fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, - pointloop[0], pointloop[1], pointloop[2]); - fprintf(outfile, "\n"); - pointloop = pointtraverse(); - pointnumber++; - } - fclose(outfile); - - face faceloop; - point torg, tdest, tapex; - strcpy(sfilename, mfilename); - strcat(sfilename, ".smesh"); - outfile = fopen(sfilename, "w"); - if (!b->quiet) { - printf("Writing %s.\n", sfilename); - } - int shift = 0; // Default no shiftment. - if ((in->firstnumber == 1) && (firstindex == 0)) { - shift = 1; // Shift the output indices by 1. - } - fprintf(outfile, "0 3 0 0\n"); - fprintf(outfile, "%ld 1\n", subfaces->items); - subfaces->traversalinit(); - faceloop.sh = shellfacetraverse(subfaces); - while (faceloop.sh != (shellface *) NULL) { - torg = sorg(faceloop); - tdest = sdest(faceloop); - tapex = sapex(faceloop); - fprintf(outfile, "3 %4d %4d %4d %d\n", - pointmark(torg) - shift, pointmark(tdest) - shift, - pointmark(tapex) - shift, shellmark(faceloop)); - faceloop.sh = shellfacetraverse(subfaces); - } - fprintf(outfile, "0\n"); - fprintf(outfile, "0\n"); - fclose(outfile); - - face edgeloop; - int edgenumber; - strcpy(sfilename, mfilename); - strcat(sfilename, ".edge"); - outfile = fopen(sfilename, "w"); - if (!b->quiet) { - printf("Writing %s.\n", sfilename); - } - fprintf(outfile, "%ld 1\n", subsegs->items); - subsegs->traversalinit(); - edgeloop.sh = shellfacetraverse(subsegs); - edgenumber = firstindex; // in->firstnumber; - while (edgeloop.sh != (shellface *) NULL) { - torg = sorg(edgeloop); - tdest = sdest(edgeloop); - fprintf(outfile, "%5d %4d %4d %d\n", edgenumber, - pointmark(torg) - shift, pointmark(tdest) - shift, - shellmark(edgeloop)); - edgenumber++; - edgeloop.sh = shellfacetraverse(subsegs); - } - fclose(outfile); -} -void meshGRegionBoundaryRecovery::outmesh2medit(const char* mfilename) -{ - FILE *outfile; - char mefilename[256]; - tetrahedron* tetptr; - triface tface, tsymface; - face segloop, checkmark; - point ptloop, p1, p2, p3, p4; - long ntets, faces; - int shift = 0; - int marker; - - if (mfilename != (char *) NULL && mfilename[0] != '\0') { - strcpy(mefilename, mfilename); - } else { - strcpy(mefilename, "unnamed"); - } - strcat(mefilename, ".mesh"); - - if (!b->quiet) { - printf("Writing %s.\n", mefilename); - } - outfile = fopen(mefilename, "w"); - if (outfile == (FILE *) NULL) { - printf("File I/O Error: Cannot create file %s.\n", mefilename); - return; - } +#include <stdio.h> +#include <assert.h> +#include "meshGRegionBoundaryRecovery.h" +#include "meshGRegionDelaunayInsertion.h" +#include "robustPredicates.h" +#include "GRegion.h" +#include "GFace.h" +#include "MVertex.h" +#include "MLine.h" +#include "MTriangle.h" +#include "MTetrahedron.h" +#include "OS.h" - fprintf(outfile, "MeshVersionFormatted 1\n"); - fprintf(outfile, "\n"); - fprintf(outfile, "Dimension\n"); - fprintf(outfile, "3\n"); - fprintf(outfile, "\n"); +#define REAL double - fprintf(outfile, "\n# Set of mesh vertices\n"); - fprintf(outfile, "Vertices\n"); - fprintf(outfile, "%ld\n", points->items); +// dummy tetgenio class (not used) +class tetgenio{ +public: - points->traversalinit(); - ptloop = pointtraverse(); - //pointnumber = 1; - while (ptloop != (point) NULL) { - // Point coordinates. - fprintf(outfile, "%.17g %.17g %.17g", ptloop[0], ptloop[1], ptloop[2]); - fprintf(outfile, " 0\n"); - //setpointmark(ptloop, pointnumber); - ptloop = pointtraverse(); - //pointnumber++; - } + typedef struct { + int *vertexlist; + int numberofvertices; + } polygon; - // Medit need start number form 1. - if (in->firstnumber == 1) { - shift = 0; - } else { - shift = 1; - } + // A "facet" describes a polygonal region possibly with holes, edges, and + // points floating in it. Each facet consists of a list of polygons and + // a list of hole points (which lie strictly inside holes). + typedef struct { + polygon *polygonlist; + int numberofpolygons; + REAL *holelist; + int numberofholes; + } facet; - // Compute the number of faces. - ntets = tetrahedrons->items - hullsize; - faces = (ntets * 4l + hullsize) / 2l; + typedef struct{ + REAL uv[2]; + int tag; + int type; + } pointparam; - /* - fprintf(outfile, "\n# Set of Triangles\n"); - fprintf(outfile, "Triangles\n"); - fprintf(outfile, "%ld\n", faces); + int firstnumber; + int numberofpointattributes; - tetrahedrons->traversalinit(); - tface.tet = tetrahedrontraverse(); - while (tface.tet != (tetrahedron *) NULL) { - for (tface.ver = 0; tface.ver < 4; tface.ver ++) { - fsym(tface, tsymface); - if (ishulltet(tsymface) || - (elemindex(tface.tet) < elemindex(tsymface.tet))) { - p1 = org (tface); - p2 = dest(tface); - p3 = apex(tface); - fprintf(outfile, "%5d %5d %5d", - pointmark(p1)+shift, pointmark(p2)+shift, pointmark(p3)+shift); - // Check if it is a subface. - tspivot(tface, checkmark); - if (checkmark.sh == NULL) { - marker = 0; // It is an inner face. It's marker is 0. - } else { - marker = 1; // The default marker for subface is 1. - } - fprintf(outfile, " %d\n", marker); - } - } - tface.tet = tetrahedrontraverse(); - } - */ + int numberoftetrahedronattributes; - fprintf(outfile, "\n# Set of Tetrahedra\n"); - fprintf(outfile, "Tetrahedra\n"); - fprintf(outfile, "%ld\n", ntets); + int numberofsegmentconstraints; + REAL *segmentconstraintlist; - tetrahedrons->traversalinit(); - tetptr = tetrahedrontraverse(); - while (tetptr != (tetrahedron *) NULL) { - if (!b->reversetetori) { - p1 = (point) tetptr[4]; - p2 = (point) tetptr[5]; - } else { - p1 = (point) tetptr[5]; - p2 = (point) tetptr[4]; - } - p3 = (point) tetptr[6]; - p4 = (point) tetptr[7]; - fprintf(outfile, "%5d %5d %5d %5d", - pointmark(p1)+shift, pointmark(p2)+shift, - pointmark(p3)+shift, pointmark(p4)+shift); - if (numelemattrib > 0) { - fprintf(outfile, " %.17g", elemattribute(tetptr, 0)); - } else { - fprintf(outfile, " 0"); - } - fprintf(outfile, "\n"); - tetptr = tetrahedrontraverse(); - } + int numberoffacetconstraints; + REAL *facetconstraintlist; - fprintf(outfile, "\nEnd\n"); - fclose(outfile); -} + int numberofpoints; + int *pointlist; + int *pointattributelist; + pointparam *pointparamlist; -/////////////////////////////////////////////////////////////////////////////// + int numberofpointmakers; + int *pointmarkerlist; + int numberofpointmtrs; + int *pointmtrlist; + int numberofedges; + int *edgelist; + int *edgemarkerlist; -/////////////////////////////////////////////////////////////////////////////// + int numberoffacets; + facet *facetlist; + int *facetmarkerlist; -void meshGRegionBoundaryRecovery::unifysubfaces(face *f1, face *f2) -{ - if (b->psc) { - // In this case, it is possible that two subfaces are identical. - // While they must belong to two different surfaces. - return; - } + int numberofholes; + REAL *holelist; - point pa, pb, pc, pd; + int numberofregions; + REAL *regionlist; - pa = sorg(*f1); - pb = sdest(*f1); - pc = sapex(*f1); - pd = sapex(*f2); + int mesh_dim; - if (pc != pd) { - printf("Found two facets intersect each other.\n"); - printf(" 1st: [%d, %d, %d] #%d\n", - pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1)); - printf(" 2nd: [%d, %d, %d] #%d\n", - pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2)); - terminateBoundaryRecovery(this, 3); - } else { - printf("Found two duplicated facets.\n"); - printf(" 1st: [%d, %d, %d] #%d\n", - pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1)); - printf(" 2nd: [%d, %d, %d] #%d\n", - pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2)); - terminateBoundaryRecovery(this, 3); - } + tetgenio() + { + firstnumber = 0; + numberofpointattributes = 0; + numberoftetrahedronattributes = 0; + numberofsegmentconstraints = 0; + segmentconstraintlist = 0; + numberoffacetconstraints = 0; + facetconstraintlist = 0; + numberofpoints = 0; + pointlist = 0; + pointattributelist = 0; + pointparamlist = 0; + numberofpointmakers = 0; + pointmarkerlist = 0; + numberofpointmtrs = 0; + pointmtrlist = 0; + numberofedges = 0; + edgelist = 0; + edgemarkerlist = 0; + numberoffacets = 0; + facetlist = 0; + facetmarkerlist = 0; + numberofholes = 0; + holelist = 0; + numberofregions = 0; + regionlist = 0; + mesh_dim = 0; + } +}; + +// redefinition of predicates using our own +#define exactinit robustPredicates::exactinit +#define incircle robustPredicates::incircle +#define insphere robustPredicates::insphere +#define orient2d robustPredicates::orient2d +#define orient3d robustPredicates::orient3d +double orient4d(double*, double *, double *, double *, double *, + double, double, double, double, double){ return 0.;} -} +#include "tetgenBR.h" +#include "tetgenBR.cxx" -void meshGRegionBoundaryRecovery::unifysegments() +bool meshGRegionBoundaryRecovery(GRegion *gr) { - badface *facelink = NULL, *newlinkitem, *f1, *f2; - face *facperverlist, sface; - face subsegloop, testseg; - point torg, tdest; - REAL ori1, ori2, ori3; - REAL n1[3], n2[3]; - int *idx2faclist; - int idx, k, m; - - if (b->verbose > 1) { - printf(" Unifying segments.\n"); - } - - // Create a mapping from vertices to subfaces. - makepoint2submap(subfaces, idx2faclist, facperverlist); - - subsegloop.shver = 0; - subsegs->traversalinit(); - subsegloop.sh = shellfacetraverse(subsegs); - while (subsegloop.sh != (shellface *) NULL) { - torg = sorg(subsegloop); - tdest = sdest(subsegloop); - - idx = pointmark(torg) - in->firstnumber; - // Loop through the set of subfaces containing 'torg'. Get all the - // subfaces containing the edge (torg, tdest). Save and order them - // in 'sfacelist', the ordering is defined by the right-hand rule - // with thumb points from torg to tdest. - for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) { - sface = facperverlist[k]; - // The face may be deleted if it is a duplicated face. - if (sface.sh[3] == NULL) continue; - // Search the edge torg->tdest. - assert(sorg(sface) == torg); // SELF_CHECK - if (sdest(sface) != tdest) { - senext2self(sface); - sesymself(sface); - } - if (sdest(sface) != tdest) continue; - - // Save the face f in facelink. - if (flippool->items >= 2) { - f1 = facelink; - for (m = 0; m < flippool->items - 1; m++) { - f2 = f1->nextitem; - ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(f2->ss)); - ori2 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface)); - if (ori1 > 0) { - // apex(f2) is below f1. - if (ori2 > 0) { - // apex(f) is below f1 (see Fig.1). - ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface)); - if (ori3 > 0) { - // apex(f) is below f2, insert it. - break; - } else if (ori3 < 0) { - // apex(f) is above f2, continue. - } else { // ori3 == 0; - // f is coplanar and codirection with f2. - unifysubfaces(&(f2->ss), &sface); - break; - } - } else if (ori2 < 0) { - // apex(f) is above f1 below f2, inset it (see Fig. 2). - break; - } else { // ori2 == 0; - // apex(f) is coplanar with f1 (see Fig. 5). - ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface)); - if (ori3 > 0) { - // apex(f) is below f2, insert it. - break; - } else { - // f is coplanar and codirection with f1. - unifysubfaces(&(f1->ss), &sface); - break; - } - } - } else if (ori1 < 0) { - // apex(f2) is above f1. - if (ori2 > 0) { - // apex(f) is below f1, continue (see Fig. 3). - } else if (ori2 < 0) { - // apex(f) is above f1 (see Fig.4). - ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface)); - if (ori3 > 0) { - // apex(f) is below f2, insert it. - break; - } else if (ori3 < 0) { - // apex(f) is above f2, continue. - } else { // ori3 == 0; - // f is coplanar and codirection with f2. - unifysubfaces(&(f2->ss), &sface); - break; - } - } else { // ori2 == 0; - // f is coplanar and with f1 (see Fig. 6). - ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface)); - if (ori3 > 0) { - // f is also codirection with f1. - unifysubfaces(&(f1->ss), &sface); - break; - } else { - // f is above f2, continue. - } - } - } else { // ori1 == 0; - // apex(f2) is coplanar with f1. By assumption, f1 is not - // coplanar and codirection with f2. - if (ori2 > 0) { - // apex(f) is below f1, continue (see Fig. 7). - } else if (ori2 < 0) { - // apex(f) is above f1, insert it (see Fig. 7). - break; - } else { // ori2 == 0. - // apex(f) is coplanar with f1 (see Fig. 8). - // f is either codirection with f1 or is codirection with f2. - facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL); - facenormal(torg, tdest, sapex(sface), n2, 1, NULL); - if (dot(n1, n2) > 0) { - unifysubfaces(&(f1->ss), &sface); - } else { - unifysubfaces(&(f2->ss), &sface); - } - break; - } - } - // Go to the next item; - f1 = f2; - } // for (m = 0; ...) - if (sface.sh[3] != NULL) { - // Insert sface between f1 and f2. - newlinkitem = (badface *) flippool->alloc(); - newlinkitem->ss = sface; - newlinkitem->nextitem = f1->nextitem; - f1->nextitem = newlinkitem; - } - } else if (flippool->items == 1) { - f1 = facelink; - // Make sure that f is not coplanar and codirection with f1. - ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface)); - if (ori1 == 0) { - // f is coplanar with f1 (see Fig. 8). - facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL); - facenormal(torg, tdest, sapex(sface), n2, 1, NULL); - if (dot(n1, n2) > 0) { - // The two faces are codirectional as well. - unifysubfaces(&(f1->ss), &sface); - } - } - // Add this face to link if it is not deleted. - if (sface.sh[3] != NULL) { - // Add this face into link. - newlinkitem = (badface *) flippool->alloc(); - newlinkitem->ss = sface; - newlinkitem->nextitem = NULL; - f1->nextitem = newlinkitem; - } - } else { - // The first face. - newlinkitem = (badface *) flippool->alloc(); - newlinkitem->ss = sface; - newlinkitem->nextitem = NULL; - facelink = newlinkitem; - } - } // for (k = idx2faclist[idx]; ...) - - if (b->psc) { - // Set Steiner point -to- segment map. - if (pointtype(torg) == FREESEGVERTEX) { - setpoint2sh(torg, sencode(subsegloop)); - } - if (pointtype(tdest) == FREESEGVERTEX) { - setpoint2sh(tdest, sencode(subsegloop)); - } - } - - // Set the connection between this segment and faces containing it, - // at the same time, remove redundant segments. - f1 = facelink; - for (k = 0; k < flippool->items; k++) { - sspivot(f1->ss, testseg); - // If 'testseg' is not 'subsegloop' and is not dead, it is redundant. - if ((testseg.sh != subsegloop.sh) && (testseg.sh[3] != NULL)) { - shellfacedealloc(subsegs, testseg.sh); - } - // Bonds the subface and the segment together. - ssbond(f1->ss, subsegloop); - f1 = f1->nextitem; - } - - // Create the face ring at the segment. - if (flippool->items > 1) { - f1 = facelink; - for (k = 1; k <= flippool->items; k++) { - k < flippool->items ? f2 = f1->nextitem : f2 = facelink; - sbond1(f1->ss, f2->ss); - f1 = f2; - } - } - - // All identified segments has an init marker "0". - flippool->restart(); - - subsegloop.sh = shellfacetraverse(subsegs); - } - - delete [] idx2faclist; - delete [] facperverlist; + tetgenmesh *m = new tetgenmesh(); + bool ret = m->reconstructmesh((void*)gr); + delete m; + return ret; } -void meshGRegionBoundaryRecovery::jettisonnodes() +bool tetgenmesh::reconstructmesh(void *p) { - point pointloop; - bool jetflag; - int oldidx, newidx; - int remcount; + GRegion *_gr = (GRegion*)p; - if (!b->quiet) { - printf("Jettisoning redundant points.\n"); - } - - points->traversalinit(); - pointloop = pointtraverse(); - oldidx = newidx = 0; // in->firstnumber; - remcount = 0; - while (pointloop != (point) NULL) { - jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) || - (pointtype(pointloop) == UNUSEDVERTEX); - if (jetflag) { - // It is a duplicated or unused point, delete it. - pointdealloc(pointloop); - remcount++; - } else { - // Re-index it. - setpointmark(pointloop, newidx + in->firstnumber); - /* - if (in->pointmarkerlist != (int *) NULL) { - if (oldidx < in->numberofpoints) { - // Re-index the point marker as well. - in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx]; - } - } - */ - newidx++; - } - oldidx++; - pointloop = pointtraverse(); - } - if (b->verbose) { - printf(" %ld duplicated vertices are removed.\n", dupverts); - printf(" %ld unused vertices are removed.\n", unuverts); - } - dupverts = 0l; - unuverts = 0l; - - // The following line ensures that dead items in the pool of nodes cannot - // be allocated for the new created nodes. This ensures that the input - // nodes will occur earlier in the output files, and have lower indices. - points->deaditemstack = (void *) NULL; -} - -/////////////////////////////////////////////////////////////////////////////// - -bool meshGRegionBoundaryRecovery::reconstructmesh(GRegion *_gr) -{ + in = new tetgenio(); + b = new tetgenbehavior(); + char *opt = "pY"; + b->parse_commandline(opt); bool returnValue (true); double t_start = Cpu(); @@ -14481,6 +166,8 @@ bool meshGRegionBoundaryRecovery::reconstructmesh(GRegion *_gr) delaunayMeshIn3D(_vertices, tets, false); + Msg::Debug("Points have been tetrahedralized"); + { //transfernodes(); point pointloop; REAL x, y, z; @@ -14519,8 +206,8 @@ bool meshGRegionBoundaryRecovery::reconstructmesh(GRegion *_gr) } // Two identical points are distinguished by 'lengthlimit'. - if (b->minedgelength == 0.0) { - b->minedgelength = longest * b->epsilon; + if (minedgelength == 0.0) { + minedgelength = longest * b->epsilon; } } // transfernodes(); @@ -14839,7 +526,7 @@ bool meshGRegionBoundaryRecovery::reconstructmesh(GRegion *_gr) insegments = subsegs->items; if (0) { - outsurfacemesh("dump"); + //outsurfacemesh("dump"); } } // meshsurface() @@ -14849,7 +536,8 @@ bool meshGRegionBoundaryRecovery::reconstructmesh(GRegion *_gr) //////////////////////////////////////////////////////// // Boundary recovery. - recoverboundary(); + clock_t t; + recoverboundary(t); carveholes(); @@ -14857,7 +545,7 @@ bool meshGRegionBoundaryRecovery::reconstructmesh(GRegion *_gr) suppresssteinerpoints(); } - returnValue = recoverdelaunay(); + recoverdelaunay(); // let's trry optimizemesh(); @@ -15167,9 +855,5 @@ bool meshGRegionBoundaryRecovery::reconstructmesh(GRegion *_gr) if (returnValue)Msg::Info("Reconstruct time : %g sec (mesh is Delaunay)",Cpu()-t_start); else Msg::Info("Reconstruct time : %g sec (mesh is not Delaunay)",Cpu()-t_start); return returnValue; -} -void terminateBoundaryRecovery(void *, int exitcode) -{ - throw exitcode; } diff --git a/Mesh/meshGRegionBoundaryRecovery.h b/Mesh/meshGRegionBoundaryRecovery.h index 0bfc189d40fc4dc5e1c69e81d501cf18acb262d8..dfadf9cd1506bf3e949cf7d6daf60a2763cb6162 100644 --- a/Mesh/meshGRegionBoundaryRecovery.h +++ b/Mesh/meshGRegionBoundaryRecovery.h @@ -6,877 +6,8 @@ #ifndef _MESH_GREGION_BOUNDARY_RECOVERY_H_ #define _MESH_GREGION_BOUNDARY_RECOVERY_H_ -#include "GRegion.h" -#include <time.h> +class GRegion; -#define REAL double - -class meshGRegionInputs { - public: - int firstnumber; - meshGRegionInputs() { - firstnumber = 0; - } -}; - -class meshGRegionOptions { - - public: - - int plc; - int psc; - int refine; - int quality; - int nobisect; - int coarsen; - int weighted; - int brio_hilbert; - int incrflip; - int flipinsert; - int metric; - int varvolume; - int fixedvolume; - int regionattrib; - int conforming; - int insertaddpoints; - int diagnose; - int convex; - int nomergefacet; - int nomergevertex; - int noexact; - int nostaticfilter; - int zeroindex; - int facesout; - int edgesout; - int neighout; - int voroout; - int meditview; - int vtkview; - int nobound; - int nonodewritten; - int noelewritten; - int nofacewritten; - int noiterationnum; - int nojettison; - int reversetetori; - int docheck; - int quiet; - int verbose; - - int vertexperblock; - int tetrahedraperblock; - int shellfaceperblock; - int nobisect_param; - int addsteiner_algo; - int coarsen_param; - int weighted_param; - int fliplinklevel; - int flipstarsize; - int fliplinklevelinc; - int reflevel; - int optlevel; - int optscheme; - int delmaxfliplevel; - int order; - int steinerleft; - int no_sort; - int hilbert_order; - int hilbert_limit; - int brio_threshold; - REAL brio_ratio; - REAL facet_ang_tol; - REAL maxvolume; - REAL minratio; - REAL mindihedral; - REAL optmaxdihedral; - REAL optminsmtdihed; - REAL optminslidihed; - REAL epsilon; - REAL minedgelength; - REAL coarsen_percent; - - // Initialize all variables. - meshGRegionOptions() - { - plc = 1; // -p - psc = 0; - refine = 0; - quality = 0; - nobisect = 1; - coarsen = 0; - metric = 0; - weighted = 0; - brio_hilbert = 1; // -Y - incrflip = 0; - flipinsert = 0; - varvolume = 0; - fixedvolume = 0; - noexact = 0; - nostaticfilter = 0; - insertaddpoints = 0; - regionattrib = 1; // -A - conforming = 0; - diagnose = 0; - convex = 1; // -c - zeroindex = 0; - facesout = 0; - edgesout = 0; - neighout = 0; - voroout = 0; - meditview = 0; - vtkview = 0; - nobound = 0; - nonodewritten = 0; - noelewritten = 0; - nofacewritten = 0; - noiterationnum = 0; - nomergefacet = 0; - nomergevertex = 0; - nojettison = 0; - reversetetori = 0; - docheck = 0; - quiet = 0; - verbose = 0; - - vertexperblock = 4092; - tetrahedraperblock = 8188; - shellfaceperblock = 4092; - nobisect_param = 2; - addsteiner_algo = 1; - coarsen_param = 0; - weighted_param = 0; - fliplinklevel = -1; // No limit on linklevel. - flipstarsize = -1; // No limit on flip star size. - fliplinklevelinc = 1; - reflevel = 3; - optscheme = 7; // 1 & 2 & 4, // min_max_dihedral. - optlevel = 2; - delmaxfliplevel = 1; - order = 1; - steinerleft = -1; - no_sort = 0; - hilbert_order = 52; //-1; - hilbert_limit = 8; - brio_threshold = 64; - brio_ratio = 0.125; - facet_ang_tol = 179.9; - maxvolume = -1.0; - minratio = 2.0; - mindihedral = 0.0; // 5.0; - optmaxdihedral = 179.0; - optminsmtdihed = 179.999; - optminslidihed = 179.999; - epsilon = 1.0e-8; - minedgelength = 0.0; - coarsen_percent = 1.0; - } -}; - -class meshGRegionBoundaryRecovery { - - public: - - // Mesh data structure - typedef REAL **tetrahedron; - typedef REAL **shellface; - typedef REAL *point; - - // Mesh handles - class triface { - public: - tetrahedron *tet; - int ver; // Range from 0 to 11. - triface() : tet(0), ver(0) {} - triface& operator=(const triface& t) { - tet = t.tet; ver = t.ver; - return *this; - } - }; - - class face { - public: - shellface *sh; - int shver; // Range from 0 to 5. - face() : sh(0), shver(0) {} - face& operator=(const face& s) { - sh = s.sh; shver = s.shver; - return *this; - } - }; - - // Arraypool (J. R. Shewchuk) - class arraypool { - public: - int objectbytes; - int objectsperblock; - int log2objectsperblock; - int objectsperblockmark; - int toparraylen; - char **toparray; - long objects; - unsigned long totalmemory; - void restart(); - void poolinit(int sizeofobject, int log2objperblk); - char* getblock(int objectindex); - void* lookup(int objectindex); - int newindex(void **newptr); - arraypool(int sizeofobject, int log2objperblk); - ~arraypool(); - }; - -#define fastlookup(pool, index) \ - (void *) ((pool)->toparray[(index) >> (pool)->log2objectsperblock] + \ - ((index) & (pool)->objectsperblockmark) * (pool)->objectbytes) - - // Memorypool (J. R. Shewchuk) - class memorypool { - public: - void **firstblock, **nowblock; - void *nextitem; - void *deaditemstack; - void **pathblock; - void *pathitem; - int alignbytes; - int itembytes, itemwords; - int itemsperblock; - long items, maxitems; - int unallocateditems; - int pathitemsleft; - memorypool(); - memorypool(int, int, int, int); - ~memorypool(); - void poolinit(int, int, int, int); - void restart(); - void *alloc(); - void dealloc(void*); - void traversalinit(); - void *traverse(); - }; - - class badface { - public: - triface tt; - face ss; - REAL key, cent[6]; // circumcenter or cos(dihedral angles) at 6 edges. - point forg, fdest, fapex, foppo, noppo; - badface *nextitem; - badface() : key(0), forg(0), fdest(0), fapex(0), foppo(0), noppo(0), - nextitem(0) {} - }; - - // Parameters for vertex insertion, flips, and optimizations. - class insertvertexflags { - public: - int iloc; // input/output. - int bowywat, lawson; - int splitbdflag, validflag, respectbdflag; - int rejflag, chkencflag, cdtflag; - int assignmeshsize; - int sloc, sbowywat; - // Used by Delaunay refinement. - int refineflag; // 0, 1, 2, 3 - triface refinetet; - face refinesh; - int smlenflag; // for useinsertradius. - REAL smlen; // for useinsertradius. - point parentpt; - - insertvertexflags() { - iloc = bowywat = lawson = 0; - splitbdflag = validflag = respectbdflag = 0; - rejflag = chkencflag = cdtflag = 0; - assignmeshsize = 0; - sloc = sbowywat = 0; - - refineflag = 0; - refinetet.tet = NULL; - refinesh.sh = NULL; - smlenflag = 0; - smlen = 0.0; - } - }; - - class flipconstraints { - public: - // Elementary flip flags. - int enqflag; // (= flipflag) - int chkencflag; - // Control flags - int unflip; // Undo the performed flips. - int collectnewtets; // Collect the new tets created by flips. - int collectencsegflag; - // Optimization flags. - int remove_ndelaunay_edge; // Remove a non-Delaunay edge. - REAL bak_tetprism_vol; // The value to be minimized. - REAL tetprism_vol_sum; - int remove_large_angle; // Remove a large dihedral angle at edge. - REAL cosdihed_in; // The input cosine of the dihedral angle (> 0). - REAL cosdihed_out; // The improved cosine of the dihedral angle. - // Boundary recovery flags. - int checkflipeligibility; - point seg[2]; // A constraining edge to be recovered. - point fac[3]; // A constraining face to be recovered. - point remvert; // A vertex to be removed. - - flipconstraints() { - enqflag = 0; - chkencflag = 0; - unflip = 0; - collectnewtets = 0; - collectencsegflag = 0; - remove_ndelaunay_edge = 0; - bak_tetprism_vol = 0.0; - tetprism_vol_sum = 0.0; - remove_large_angle = 0; - cosdihed_in = 0.0; - cosdihed_out = 0.0; - checkflipeligibility = 0; - seg[0] = NULL; - fac[0] = NULL; - remvert = NULL; - } - }; - - class optparameters { - public: - // The one of goals of optimization. - int max_min_volume; // Maximize the minimum volume. - int min_max_aspectratio; // Minimize the maximum aspect ratio. - int min_max_dihedangle; // Minimize the maximum dihedral angle. - // The initial and improved value. - REAL initval, imprval; - int numofsearchdirs; - REAL searchstep; - int maxiter; // Maximum smoothing iterations (disabled by -1). - int smthiter; // Performed iterations. - - optparameters() { - max_min_volume = 0; - min_max_aspectratio = 0; - min_max_dihedangle = 0; - initval = imprval = 0.0; - numofsearchdirs = 10; - searchstep = 0.01; - maxiter = -1; // Unlimited smoothing iterations. - smthiter = 0; - } - }; - - // Labels - enum verttype {UNUSEDVERTEX, DUPLICATEDVERTEX, RIDGEVERTEX, ACUTEVERTEX, - FACETVERTEX, VOLVERTEX, FREESEGVERTEX, FREEFACETVERTEX, - FREEVOLVERTEX, NREGULARVERTEX, DEADVERTEX}; - enum interresult {DISJOINT, INTERSECT, SHAREVERT, SHAREEDGE, SHAREFACE, - TOUCHEDGE, TOUCHFACE, ACROSSVERT, ACROSSEDGE, ACROSSFACE, - COLLISIONFACE, ACROSSSEG, ACROSSSUB}; - enum locateresult {UNKNOWN, OUTSIDE, INTETRAHEDRON, ONFACE, ONEDGE, ONVERTEX, - ENCVERTEX, ENCSEGMENT, ENCSUBFACE, NEARVERTEX, NONREGULAR, - INSTAR, BADELEMENT}; - - meshGRegionInputs *in; - meshGRegionOptions *b; - meshGRegionBoundaryRecovery *bgm; - - // Class variables - memorypool *tetrahedrons, *subfaces, *subsegs, *points; - memorypool *tet2subpool, *tet2segpool; - - memorypool *flippool; - arraypool *unflipqueue; - badface *flipstack; - - memorypool *badtetrahedrons, *badsubfacs, *badsubsegs; - - // Arrays used for point insertion (the Bowyer-Watson algorithm). - arraypool *cavetetlist, *cavebdrylist, *caveoldtetlist; - arraypool *cavetetshlist, *cavetetseglist, *cavetetvertlist; - arraypool *caveencshlist, *caveencseglist; - arraypool *caveshlist, *caveshbdlist, *cavesegshlist; - - // Stacks used for CDT construction and boundary recovery. - arraypool *subsegstack, *subfacstack, *subvertstack; - - // The infinite vertex. - point dummypoint; - // The recently visited tetrahedron, subface. - triface recenttet; - face recentsh; - - // PI is the ratio of a circle's circumference to its diameter. - static REAL PI; - - // Various variables. - int numpointattrib; - int numelemattrib; - int sizeoftensor; - int pointmtrindex; - int pointparamindex; - int point2simindex; - int pointmarkindex; - int pointinsradiusindex; - int elemattribindex; - int volumeboundindex; - int elemmarkerindex; - int shmarkindex; - int areaboundindex; - int checksubsegflag; - int checksubfaceflag; - int checkconstraints; - int nonconvex; - int autofliplinklevel; - int useinsertradius; - long samples; - unsigned long randomseed; - REAL cosmaxdihed, cosmindihed; - REAL cossmtdihed; - REAL cosslidihed; - REAL minfaceang, minfacetdihed; - REAL tetprism_vol_sum; - REAL longest; - REAL xmax, xmin, ymax, ymin, zmax, zmin; - - // Counters. - long insegments; - long hullsize; - long meshedges; - long meshhulledges; - long steinerleft; - long dupverts; - long unuverts; - long nonregularcount; - long st_segref_count, st_facref_count, st_volref_count; - long fillregioncount, cavitycount, cavityexpcount; - long flip14count, flip26count, flipn2ncount; - long flip23count, flip32count, flip44count, flip41count; - long flip31count, flip22count; - unsigned long totalworkmemory; // Total memory used by working arrays. - - // Fast lookup tables for mesh manipulation primitives. - static int bondtbl[12][12], fsymtbl[12][12]; - static int esymtbl[12], enexttbl[12], eprevtbl[12]; - static int enextesymtbl[12], eprevesymtbl[12]; - static int eorgoppotbl[12], edestoppotbl[12]; - static int facepivot1[12], facepivot2[12][12]; - static int orgpivot[12], destpivot[12], apexpivot[12], oppopivot[12]; - static int tsbondtbl[12][6], stbondtbl[12][6]; - static int tspivottbl[12][6], stpivottbl[12][6]; - static int ver2edge[12], edge2ver[6], epivot[12]; - static int sorgpivot [6], sdestpivot[6], sapexpivot[6]; - static int snextpivot[6]; - void inittables(); - - // Primitives for tetrahedra. - inline tetrahedron encode(triface& t); - inline tetrahedron encode2(tetrahedron* ptr, int ver); - inline void decode(tetrahedron ptr, triface& t); - inline void bond(triface& t1, triface& t2); - inline void dissolve(triface& t); - inline void esym(triface& t1, triface& t2); - inline void esymself(triface& t); - inline void enext(triface& t1, triface& t2); - inline void enextself(triface& t); - inline void eprev(triface& t1, triface& t2); - inline void eprevself(triface& t); - inline void enextesym(triface& t1, triface& t2); - inline void enextesymself(triface& t); - inline void eprevesym(triface& t1, triface& t2); - inline void eprevesymself(triface& t); - inline void eorgoppo(triface& t1, triface& t2); - inline void eorgoppoself(triface& t); - inline void edestoppo(triface& t1, triface& t2); - inline void edestoppoself(triface& t); - inline void fsym(triface& t1, triface& t2); - inline void fsymself(triface& t); - inline void fnext(triface& t1, triface& t2); - inline void fnextself(triface& t); - inline point org (triface& t); - inline point dest(triface& t); - inline point apex(triface& t); - inline point oppo(triface& t); - inline void setorg (triface& t, point p); - inline void setdest(triface& t, point p); - inline void setapex(triface& t, point p); - inline void setoppo(triface& t, point p); - inline REAL elemattribute(tetrahedron* ptr, int attnum); - inline void setelemattribute(tetrahedron* ptr, int attnum, REAL value); - inline REAL volumebound(tetrahedron* ptr); - inline void setvolumebound(tetrahedron* ptr, REAL value); - inline int elemindex(tetrahedron* ptr); - inline void setelemindex(tetrahedron* ptr, int value); - inline int elemmarker(tetrahedron* ptr); - inline void setelemmarker(tetrahedron* ptr, int value); - inline void infect(triface& t); - inline void uninfect(triface& t); - inline bool infected(triface& t); - inline void marktest(triface& t); - inline void unmarktest(triface& t); - inline bool marktested(triface& t); - inline void markface(triface& t); - inline void unmarkface(triface& t); - inline bool facemarked(triface& t); - inline void markedge(triface& t); - inline void unmarkedge(triface& t); - inline bool edgemarked(triface& t); - inline void marktest2(triface& t); - inline void unmarktest2(triface& t); - inline bool marktest2ed(triface& t); - inline int elemcounter(triface& t); - inline void setelemcounter(triface& t, int value); - inline void increaseelemcounter(triface& t); - inline void decreaseelemcounter(triface& t); - inline bool ishulltet(triface& t); - inline bool isdeadtet(triface& t); - - // Primitives for subfaces and subsegments. - inline void sdecode(shellface sptr, face& s); - inline shellface sencode(face& s); - inline shellface sencode2(shellface *sh, int shver); - inline void spivot(face& s1, face& s2); - inline void spivotself(face& s); - inline void sbond(face& s1, face& s2); - inline void sbond1(face& s1, face& s2); - inline void sdissolve(face& s); - inline point sorg(face& s); - inline point sdest(face& s); - inline point sapex(face& s); - inline void setsorg(face& s, point pointptr); - inline void setsdest(face& s, point pointptr); - inline void setsapex(face& s, point pointptr); - inline void sesym(face& s1, face& s2); - inline void sesymself(face& s); - inline void senext(face& s1, face& s2); - inline void senextself(face& s); - inline void senext2(face& s1, face& s2); - inline void senext2self(face& s); - inline REAL areabound(face& s); - inline void setareabound(face& s, REAL value); - inline int shellmark(face& s); - inline void setshellmark(face& s, int value); - inline void sinfect(face& s); - inline void suninfect(face& s); - inline bool sinfected(face& s); - inline void smarktest(face& s); - inline void sunmarktest(face& s); - inline bool smarktested(face& s); - inline void smarktest2(face& s); - inline void sunmarktest2(face& s); - inline bool smarktest2ed(face& s); - inline void smarktest3(face& s); - inline void sunmarktest3(face& s); - inline bool smarktest3ed(face& s); - inline void setfacetindex(face& f, int value); - inline int getfacetindex(face& f); - - // Primitives for interacting tetrahedra and subfaces. - inline void tsbond(triface& t, face& s); - inline void tsdissolve(triface& t); - inline void stdissolve(face& s); - inline void tspivot(triface& t, face& s); - inline void stpivot(face& s, triface& t); - - // Primitives for interacting tetrahedra and segments. - inline void tssbond1(triface& t, face& seg); - inline void sstbond1(face& s, triface& t); - inline void tssdissolve1(triface& t); - inline void sstdissolve1(face& s); - inline void tsspivot1(triface& t, face& s); - inline void sstpivot1(face& s, triface& t); - - // Primitives for interacting subfaces and segments. - inline void ssbond(face& s, face& edge); - inline void ssbond1(face& s, face& edge); - inline void ssdissolve(face& s); - inline void sspivot(face& s, face& edge); - - // Primitives for points. - inline int pointmark(point pt); - inline void setpointmark(point pt, int value); - inline enum verttype pointtype(point pt); - inline void setpointtype(point pt, enum verttype value); - inline int pointgeomtag(point pt); - inline void setpointgeomtag(point pt, int value); - inline REAL pointgeomuv(point pt, int i); - inline void setpointgeomuv(point pt, int i, REAL value); - inline void pinfect(point pt); - inline void puninfect(point pt); - inline bool pinfected(point pt); - inline void pmarktest(point pt); - inline void punmarktest(point pt); - inline bool pmarktested(point pt); - inline void pmarktest2(point pt); - inline void punmarktest2(point pt); - inline bool pmarktest2ed(point pt); - inline void pmarktest3(point pt); - inline void punmarktest3(point pt); - inline bool pmarktest3ed(point pt); - inline tetrahedron point2tet(point pt); - inline void setpoint2tet(point pt, tetrahedron value); - inline shellface point2sh(point pt); - inline void setpoint2sh(point pt, shellface value); - inline point point2ppt(point pt); - inline void setpoint2ppt(point pt, point value); - inline tetrahedron point2bgmtet(point pt); - inline void setpoint2bgmtet(point pt, tetrahedron value); - inline void setpointinsradius(point pt, REAL value); - inline REAL getpointinsradius(point pt); - inline bool issteinerpoint(point pt); - - // Advanced primitives. - inline void point2tetorg(point pt, triface& t); - inline void point2shorg(point pa, face& s); - inline point farsorg(face& seg); - inline point farsdest(face& seg); - - // Memory managment - void tetrahedrondealloc(tetrahedron*); - tetrahedron *tetrahedrontraverse(); - tetrahedron *alltetrahedrontraverse(); - void shellfacedealloc(memorypool*, shellface*); - shellface *shellfacetraverse(memorypool*); - void pointdealloc(point); - point pointtraverse(); - - void makeindex2pointmap(point*&); - void makepoint2submap(memorypool*, int*&, face*&); - void maketetrahedron(triface*); - void makeshellface(memorypool*, face*); - void makepoint(point*, enum verttype); - - void initializepools(); - - // Symbolic perturbations (robust) - REAL insphere_s(REAL*, REAL*, REAL*, REAL*, REAL*); - - // Triangle-edge intersection test (robust) - int tri_edge_2d(point, point, point, point, point, point, int, int*, int*); - int tri_edge_tail(point, point, point, point, point, point, REAL, REAL, int, - int*, int*); - int tri_edge_test(point, point, point, point, point, point, int, int*, int*); - - // Linear algebra functions - inline REAL dot(REAL* v1, REAL* v2); - inline void cross(REAL* v1, REAL* v2, REAL* n); - bool lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N); - void lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N); - - // Geometric calculations (non-robust) - REAL orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd); - inline REAL norm2(REAL x, REAL y, REAL z); - inline REAL distance(REAL* p1, REAL* p2); - REAL incircle3d(point pa, point pb, point pc, point pd); - void facenormal(point pa, point pb, point pc, REAL *n, int pivot, REAL *lav); - bool tetalldihedral(point, point, point, point, REAL*, REAL*, REAL*); - void tetallnormal(point, point, point, point, REAL N[4][3], REAL* volume); - REAL tetaspectratio(point, point, point, point); - bool circumsphere(REAL*, REAL*, REAL*, REAL*, REAL* cent, REAL* radius); - void planelineint(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*); - int linelineint(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*); - REAL tetprismvol(REAL* pa, REAL* pb, REAL* pc, REAL* pd); - void calculateabovepoint4(point, point, point, point); - - // The elementary flips. - void flip23(triface*, int, flipconstraints* fc); - void flip32(triface*, int, flipconstraints* fc); - void flip41(triface*, int, flipconstraints* fc); - // A generalized edge flip. - int flipnm(triface*, int n, int level, int, flipconstraints* fc); - int flipnm_post(triface*, int n, int nn, int, flipconstraints* fc); - // Point insertion. - int insertpoint(point, triface*, face*, face*, insertvertexflags*); - void insertpoint_abort(face*, insertvertexflags*); - - // Point sorting. - int transgc[8][3][8], tsb1mod3[8]; - void hilbert_init(int n); - int hilbert_split(point* vertexarray, int arraysize, int gc0, int gc1, - REAL, REAL, REAL, REAL, REAL, REAL); - void hilbert_sort3(point* vertexarray, int arraysize, int e, int d, - REAL, REAL, REAL, REAL, REAL, REAL, int depth); - void brio_multiscale_sort(point*,int,int threshold,REAL ratio,int* depth); - - // Point location. - unsigned long randomnation(unsigned int choices); - void randomsample(point searchpt, triface *searchtet); - enum locateresult locate(point searchpt, triface *searchtet); - - // Incremental flips. - void flippush(badface*&, triface*); - int incrementalflip(point newpt, int, flipconstraints *fc); - - // Incremental Delaunay construction. - void initialdelaunay(point pa, point pb, point pc, point pd); - void incrementaldelaunay(); - - // Surface meshing. - void flipshpush(face*); - void flip22(face*, int, int); - void flip31(face*, int); - long lawsonflip(); - int sinsertvertex(point newpt, face*, face*, int iloc, int bowywat, int); - int sremovevertex(point delpt, face*, face*, int lawson); - enum locateresult slocate(point, face*, int, int, int); - - // Boundary recovery - enum interresult finddirection(triface* searchtet, point endpt); - int checkflipeligibility(int fliptype, point, point, point, point, point, - int level, int edgepivot, flipconstraints* fc); - - int removeedgebyflips(triface*, flipconstraints*); - int removefacebyflips(triface*, flipconstraints*); - int recoveredgebyflips(point, point, triface*, int fullsearch); - int add_steinerpt_in_schoenhardtpoly(triface*, int, int chkencflag); - int add_steinerpt_in_segment(face*, int searchlevel); - int addsteiner4recoversegment(face*, int); - int recoversegments(arraypool*, int fullsearch, int steinerflag); - int recoverfacebyflips(point, point, point, face*, triface*); - int recoversubfaces(arraypool*, int steinerflag); - int getvertexstar(int, point searchpt, arraypool*, arraypool*, arraypool*); - int getedge(point, point, triface*); - int reduceedgesatvertex(point startpt, arraypool* endptlist); - int removevertexbyflips(point steinerpt); - int suppressbdrysteinerpoint(point steinerpt); - int suppresssteinerpoints(); - void recoverboundary(); - - // Mesh reconstruct - void carveholes(); - - // Mesh optimize - long lawsonflip3d(flipconstraints *fc); - bool recoverdelaunay(); - int gettetrahedron(point, point, point, point, triface *); - long improvequalitybyflips(); - int smoothpoint(point smtpt, arraypool*, int ccw, optparameters *opm); - long improvequalitybysmoothing(optparameters *opm); - int splitsliver(triface *, REAL, int); - long removeslivers(int); - void optimizemesh(); - - // Constructor & desctructor. - meshGRegionBoundaryRecovery() - { - in = new meshGRegionInputs(); - b = new meshGRegionOptions(); - bgm = NULL; - - tetrahedrons = subfaces = subsegs = points = NULL; - badtetrahedrons = badsubfacs = badsubsegs = NULL; - tet2segpool = tet2subpool = NULL; - flippool = NULL; - - dummypoint = NULL; - flipstack = NULL; - unflipqueue = NULL; - - cavetetlist = cavebdrylist = caveoldtetlist = NULL; - cavetetshlist = cavetetseglist = cavetetvertlist = NULL; - caveencshlist = caveencseglist = NULL; - caveshlist = caveshbdlist = cavesegshlist = NULL; - - subsegstack = subfacstack = subvertstack = NULL; - - numpointattrib = numelemattrib = 0; - sizeoftensor = 0; - pointmtrindex = 0; - pointparamindex = 0; - pointmarkindex = 0; - point2simindex = 0; - pointinsradiusindex = 0; - elemattribindex = 0; - volumeboundindex = 0; - shmarkindex = 0; - areaboundindex = 0; - checksubsegflag = 0; - checksubfaceflag = 0; - checkconstraints = 0; - nonconvex = 0; - autofliplinklevel = 1; - useinsertradius = 0; - samples = 0l; - randomseed = 1l; - minfaceang = minfacetdihed = PI; - tetprism_vol_sum = 0.0; - longest = 0.0; - xmax = xmin = ymax = ymin = zmax = zmin = 0.0; - - insegments = 0l; - hullsize = 0l; - meshedges = meshhulledges = 0l; - steinerleft = -1; - dupverts = 0l; - unuverts = 0l; - nonregularcount = 0l; - st_segref_count = st_facref_count = st_volref_count = 0l; - fillregioncount = cavitycount = cavityexpcount = 0l; - flip14count = flip26count = flipn2ncount = 0l; - flip23count = flip32count = flip44count = flip41count = 0l; - flip22count = flip31count = 0l; - totalworkmemory = 0l; - } - - ~meshGRegionBoundaryRecovery() - { - delete in; - delete b; - - if (points != (memorypool *) NULL) { - delete points; - delete [] dummypoint; - } - - if (tetrahedrons != (memorypool *) NULL) { - delete tetrahedrons; - } - - if (subfaces != (memorypool *) NULL) { - delete subfaces; - delete subsegs; - } - - if (tet2segpool != NULL) { - delete tet2segpool; - delete tet2subpool; - } - - if (flippool != NULL) { - delete flippool; - delete unflipqueue; - } - - if (cavetetlist != NULL) { - delete cavetetlist; - delete cavebdrylist; - delete caveoldtetlist; - delete cavetetvertlist; - } - - if (caveshlist != NULL) { - delete caveshlist; - delete caveshbdlist; - delete cavesegshlist; - delete cavetetshlist; - delete cavetetseglist; - delete caveencshlist; - delete caveencseglist; - } - - if (subsegstack != NULL) { - delete subsegstack; - delete subfacstack; - delete subvertstack; - } - } - - // Debug functions - void outsurfacemesh(const char* mfilename); - void outmesh2medit(const char* mfilename); - - void unifysubfaces(face *f1, face *f2); - void unifysegments(); - void jettisonnodes(); - bool reconstructmesh(GRegion *_gr); -}; - -void terminateBoundaryRecovery(void *, int exitcode); +bool meshGRegionBoundaryRecovery(GRegion *gr); #endif