Created
December 26, 2014 03:18
-
-
Save ialhashim/373a08ed160c43f028bb to your computer and use it in GitHub Desktop.
Portable Powercrust in C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Portable version of powercrust, adapted from https://github.com/timhutton/vtkpowercrust | |
/*=================================================================================================== | |
vtkPowerCrustSurfaceReconstruction algorithm reconstructs surfaces from unorganized point data. | |
Copyright (C) 2014 Arash Akbarinia, Tim Hutton, Bruce Lamond Dieter Pfeffer, Oliver Moss | |
====================================================================================================*/ | |
/* | |
#include "CellArray.h" | |
#include "FloatArray.h" | |
#include "Information.h" | |
#include "InformationVector.h" | |
#include "ObjectFactory.h" | |
#include "PointData.h" | |
*/ | |
#include <assert.h> | |
#include <float.h> | |
#include <vector> | |
#include <iostream> | |
#include <fstream> | |
#include <sstream> | |
typedef double Coord; | |
typedef Coord* point; | |
typedef point site; | |
#define MAXBLOCKS 10000 | |
#define Nobj 10000 | |
#define STORAGE_GLOBALS(X) \ | |
\ | |
extern size_t X##_size; \ | |
extern X *X##_list; \ | |
extern X *new_block_##X(int); \ | |
void free_##X##_storage(void); \ | |
#define INCP(X,p,k) ((X*) ( (char*)p + (k) * X##_size)) /* portability? */ | |
#define STORAGE(X) \ | |
\ | |
size_t X##_size; \ | |
X *X##_list = 0; \ | |
\ | |
X *new_block_##X(int make_blocks) \ | |
{ int i; \ | |
static X *X##_block_table[MAXBLOCKS]; \ | |
X *xlm, *xbt; \ | |
static int num_##X##_blocks; \ | |
if (make_blocks) { \ | |
assert(num_##X##_blocks<MAXBLOCKS); \ | |
DEB(0, before) DEBEXP(0, Nobj * X##_size) \ | |
\ | |
xbt = X##_block_table[num_##X##_blocks++] = (X*)malloc(Nobj * X##_size); \ | |
memset(xbt,0,Nobj * X##_size); \ | |
if (!xbt) { \ | |
DEBEXP(-10,num_##X##_blocks) \ | |
} \ | |
assert(xbt); \ | |
\ | |
xlm = INCP(X,xbt,Nobj); \ | |
for (i=0;i<Nobj; i++) { \ | |
xlm = INCP(X,xlm,(-1)); \ | |
xlm->next = X##_list; \ | |
X##_list = xlm; \ | |
} \ | |
\ | |
return X##_list; \ | |
} \ | |
\ | |
for (i=0; i<num_##X##_blocks; i++) \ | |
free(X##_block_table[i]); \ | |
num_##X##_blocks = 0; \ | |
X##_list = 0; \ | |
return 0; \ | |
} \ | |
\ | |
void free_##X##_storage(void) {new_block_##X(0);} \ | |
/*end of STORAGE*/ | |
#define NEWL(X,p) \ | |
{ \ | |
p = X##_list ? X##_list : new_block_##X(1); \ | |
assert(p); \ | |
X##_list = p->next; \ | |
} \ | |
#define NEWLRC(X,p) \ | |
{ \ | |
p = X##_list ? X##_list : new_block_##X(1); \ | |
assert(p); \ | |
X##_list = p->next; \ | |
p->ref_count = 1; \ | |
} \ | |
#define FREEL(X,p) \ | |
{ \ | |
memset((p),0,X##_size); \ | |
(p)->next = X##_list; \ | |
X##_list = p; \ | |
} \ | |
#define dec_ref(X,v) {if ((v) && --(v)->ref_count == 0) FREEL(X,(v));} | |
#define inc_ref(X,v) {if (v) v->ref_count++;} | |
#define NULLIFY(X,v) {dec_ref(X,v); v = NULL;} | |
#define mod_refs(op,s) \ | |
{ \ | |
int i; \ | |
neighbor *mrsn; \ | |
\ | |
for (i=-1,mrsn=s->neigh-1;i<cdim;i++,mrsn++) \ | |
op##_ref(basis_s, mrsn->basis); \ | |
} | |
#define copy_simp(new,s) \ | |
{ NEWL(simplex,new); \ | |
memcpy(new,s,simplex_size); \ | |
mod_refs(inc,s); \ | |
} \ | |
#define DEBS(qq) {if (DEBUG>qq) { | |
#define EDEBS }} | |
#define DEBOUT 0 | |
#define DEB(ll,mes) DEBS(ll) if(DEBOUT){fprintf(DEBOUT,#mes "\n");fflush(DEBOUT);} EDEBS | |
#define DEBEXP(ll,exp) DEBS(ll) if(DEBOUT){fprintf(DEBOUT,#exp "=%G\n", (double) exp); fflush(DEBOUT);} EDEBS | |
#define MAXDIM 8 | |
#define BLOCKSIZE 100000 | |
#define DEBUG -7 | |
#define EXACT 1 /* sunghee */ | |
#define CNV 0 /* sunghee : status of simplex, if it's on convex hull */ | |
#define VV 1 /* sunghee : if it's regular simplex */ | |
#define SLV -1 /* sunghee : if orient3d=0, sliver simplex */ | |
#define AV 2 /* if av contains the averaged pole vector */ | |
#define POLE_OUTPUT 3 /* VV is pole and it's ouput */ | |
#define SQ(a) ((a)*(a)) /* sunghee */ | |
#define BAD_POLE -1 | |
// next two lines added by TJH to avoid name collision | |
#undef IN | |
#undef OUT | |
#define IN 2 | |
#define OUT 1 | |
#define INIT 0 | |
#define NO 1 | |
#define FIRST_EDGE 0 | |
#define POW 1 | |
#define VISITED 3 | |
#define VALIDEDGE 24 | |
#define ADDAXIS 13 | |
/* for priority queue */ | |
#define LEFT(i) ((i) * 2) | |
#define RIGHT(i) ((i) * 2 + 1) | |
#define PARENT(i) ((i) / 2) | |
typedef struct basis_s | |
{ | |
struct basis_s *next; /* free list */ | |
int ref_count; /* storage management */ | |
int lscale; /* the log base 2 of total scaling of vector */ | |
Coord sqa, sqb; /* sums of squared norms of a part and b part */ | |
Coord vecs[1]; /* the actual vectors, extended by malloc'ing bigger */ | |
} basis_s; | |
typedef struct neighbor | |
{ | |
site vert; /* vertex of simplex */ | |
/* short edgestatus[3]; FIRST_EDGE if not visited | |
NOT_POW if not dual to powercrust faces | |
POW if dual to powercrust faces */ | |
struct simplex *simp; /* neighbor sharing all vertices but vert */ | |
basis_s *basis; /* derived vectors */ | |
} neighbor; | |
typedef struct simplex | |
{ | |
simplex() : isVvNull(false) {} | |
simplex *next; /* used in free list */ | |
short mark; | |
double vv[3]; | |
bool isVvNull; | |
double sqradius; /* squared radius of Voronoi ball */ | |
short status;/* sunghee : 0(CNV) if on conv hull so vv contains normal vector; | |
1(VV) if vv points to circumcenter of simplex; | |
-1(SLV) if cond=0 so vv points to hull | |
2(AV) if av contains averaged pole */ | |
long poleindex; /* for 1st DT, if status==POLE_OUTPUT, contains poleindex; for 2nd, contains vertex index for powercrust output for OFF file format */ | |
short edgestatus[6]; /* edge status :(01)(02)(03)(12)(13)(23) | |
FIRST_EDGE if not visited | |
VISITED | |
NOT_POW if not dual to powercrust faces | |
POW if dual to powercrust faces */ | |
/* short tristatus[4]; triangle status : | |
FIRST if not visited | |
NO if not a triangle | |
DEG if degenerate triangle | |
SURF if surface triangle | |
NORM if fails normal test | |
VOR if falis voronoi edge test | |
VOR_NORM if fails both test */ | |
/* NOTE!!! neighbors has to be the LAST field in the simplex stucture, | |
since it's length gets altered by some tricky Clarkson-move. | |
Also peak has to be the one before it. | |
Don't try to move these babies!! */ | |
long visit; /* number of last site visiting this simplex */ | |
basis_s* normal; /* normal vector pointing inward */ | |
neighbor peak; /* if null, remaining vertices give facet */ | |
neighbor neigh[1]; /* neighbors of simplex */ | |
} simplex; | |
/* structure for list of opposite poles, opplist. */ | |
typedef struct plist | |
{ | |
long pid; | |
double angle; | |
plist *next; | |
} plist; | |
/* regular triangulation edge, between pole pid to center of simp? */ | |
typedef struct edgesimp | |
{ | |
short kth; | |
double angle; /* angle between balls */ | |
simplex *simp; | |
long pid; | |
edgesimp *next; | |
} edgesimp; | |
/* additional info about poles: label for pole, pointer to list of regular | |
triangulation edges, squared radius of polar ball. adjlist is an | |
array of polelabels. */ | |
typedef struct polelabel | |
{ | |
edgesimp *eptr; | |
short bad; | |
short label; | |
double in; /* 12/7/99 Sunghee for priority queue */ | |
double out; /* 12/7/99 Sunghee for priority queue */ | |
int hid; /* 0 if not in the heap, otherwise heap index 1..heap_size*/ | |
double sqradius; | |
double oppradius; /* minimum squared radius of this or any opposite ball */ | |
double samp_distance; | |
int grafindex; /* index in thinning graph data structure */ | |
} polelabel; | |
typedef struct fg_node fg; | |
typedef struct tree_node Tree; | |
struct tree_node | |
{ | |
Tree *left, *right; | |
site key; | |
int size; /* maintained to be the number of nodes rooted here */ | |
fg *fgs; | |
Tree *next; /* freelist */ | |
}; | |
typedef struct fg_node | |
{ | |
Tree *facets; | |
double dist, vol; /* of Voronoi face dual to this */ | |
fg *next; /* freelist */ | |
short mark; | |
int ref_count; | |
} fg_node; | |
typedef struct heap_array | |
{ | |
int pid; | |
double pri; | |
} heap_array; | |
STORAGE_GLOBALS(basis_s) | |
STORAGE_GLOBALS(fg) | |
STORAGE_GLOBALS(Tree) | |
STORAGE_GLOBALS(simplex) | |
STORAGE(basis_s) | |
STORAGE(fg) | |
STORAGE(Tree) | |
STORAGE(simplex) | |
//===================================================================== | |
class PowerCrustSurfaceReconstructionImpl | |
{ | |
private: | |
typedef void* (PowerCrustSurfaceReconstructionImpl::*visit_func) (simplex *, void *); | |
typedef int (PowerCrustSurfaceReconstructionImpl::*test_func) (simplex *, int, void *); | |
void ASSERT(int b, const char* message = ""); | |
int pcFALSE; | |
int pcTRUE; | |
site p; | |
std::vector<point> site_blocks; | |
std::vector<point> site_blocks_pointers; | |
int num_blocks; | |
int pdim; | |
Coord infinity[10]; /* point at infinity for Delaunay triang */ | |
int rdim, /* region dimension: (max) number of sites specifying region */ | |
cdim, /* number of sites currently specifying region */ | |
site_size; /* size of malloc needed for a site */ | |
site get_site_offline(long); | |
double bound[8][3]; | |
double mult_up; | |
Coord mins[MAXDIM]; | |
Coord maxs[MAXDIM]; | |
double Huge; | |
void read_bounding_box(long); | |
void construct_face(simplex *, short); | |
void compute_distance(simplex**, int, double*); | |
#define MAXPOINTS 10000 | |
short mi[MAXPOINTS], mo[MAXPOINTS]; | |
int correct_orientation(double*, double*, double*, double*, double*); | |
#ifndef _RAND48_H_ | |
#define _RAND48_H_ | |
void _dorand48(unsigned short xseed[3]); | |
#define RAND48_MULT_0 (0xe66d) | |
#define RAND48_MULT_1 (0xdeec) | |
#define RAND48_MULT_2 (0x0005) | |
#define RAND48_ADD (0x000b) | |
#endif /* _RAND48_H_ */ | |
double omaxs[3], omins[3]; /* 8 vertices for bounding box */ | |
int num_vtxs; | |
int num_poles; | |
/* Data structures for poles */ | |
simplex **pole1, **pole2; /* arrays of poles - per sample*/ | |
std::vector<polelabel> adjlist; | |
std::vector<plist*> opplist; | |
double* lfs_lb; /* array of lower bounds for lfs of each sample */ | |
double est_r; /* estimated value of r - user input */ | |
double *pole1_distance, *pole2_distance; | |
/* for priority queue */ | |
int heap_size; | |
int scount; | |
int v1[6]; | |
int v2[6]; | |
int v3[6]; | |
int v4[6]; | |
long num_sites; | |
short vd_new; | |
short power_diagram; /* 1 if power diagram */ | |
int dim; | |
long s_num; /* site number */ | |
double theta; /* input argument - angle defining deep intersection */ | |
double deep; /* input argument.. same as theta for labeling unlabled pole */ | |
long site_numm(site p); | |
site new_site(site p, long j); | |
// TJH: trying to replace file use | |
site read_next_site(long j); | |
site pole_read_next_site(long j); | |
std::vector<long> shufmat; | |
long mat_size; // EPRO set to global to reinitialize | |
void make_shuffle(void); | |
long shufflef(long i); | |
long (PowerCrustSurfaceReconstructionImpl::*shuf) (long); | |
long (PowerCrustSurfaceReconstructionImpl::*site_num) (site); | |
site(PowerCrustSurfaceReconstructionImpl::*get_site) (); | |
site(PowerCrustSurfaceReconstructionImpl::*get_site_n) (long); | |
site get_next_site(void); | |
void make_output(simplex *root, void * (PowerCrustSurfaceReconstructionImpl::*visit_gen) (simplex*, visit_func), visit_func visit); | |
neighbor p_neigh; // EPRO added set to global | |
basis_s *seesB; | |
simplex **st_search; | |
simplex **st_visit_triang_gen; | |
basis_s *check_perps_b; | |
#define swap_points(a,b) {point t; t=a; a=b; b=t;} | |
double alpha_test_alpha; | |
/* variables for tracking infinite loop */ | |
/* (This should never occur, but it did in early versions) */ | |
int loopStart; | |
int count; | |
int lastCount; | |
#define compare(i,j) (( this->*site_num )(i)-( this->*site_num )(j)) | |
#define node_size(x) ((x) ? ((x)->size) : 0 ) | |
heap_array *heap_A; | |
int heap_length; | |
long pnum; | |
#define push(x, st, tms) *(st + tms++) = x; | |
#define pop(x, st, tms) x = *(st + --tms); | |
long visit_triang_gen_vnum; | |
long visit_triang_gen_ss; | |
simplex *make_facets_ns; | |
long search_ss; | |
simplex *ch_root; | |
#define NEARZERO(d) ((d) < FLT_EPSILON && (d) > -FLT_EPSILON) | |
#define SWAP(X,a,b) {X t; t = a; a = b; b = t;} | |
#define DELIFT 0 | |
int basis_vec_size; | |
int exact_bits; | |
double b_err_min, b_err_min_sq; | |
short vd; | |
basis_s tt_basis; | |
basis_s *tt_basisp; | |
basis_s *infinity_basis; | |
#define VA(x) ((x)->vecs+rdim) | |
#define VB(x) ((x)->vecs) | |
#define two_to(x) ( ((x)<20) ? 1<<(x) : ldexp(1.0,(x)) ) // EPRO added | |
int sc_lscale; | |
double sc_max_scale, sc_ldetbound, sc_Sb; | |
Coord Vec_dot(point x, point y); | |
Coord Vec_dot_pdim(point x, point y); | |
Coord Norm2(point x); | |
void Ax_plus_y(Coord a, point x, point y); | |
void Ax_plus_y_test(Coord a, point x, point y); | |
void Vec_scale_test(int n, Coord a, Coord *x); | |
double sc(basis_s *v, simplex *s, int k, int j); | |
int reduce_inner(basis_s *v, simplex *s, int k); | |
void trans(point z, point p, point q); | |
#define lift(z,s) {if (vd) z[2*rdim-1] =z[rdim-1]= ldexp(Vec_dot_pdim(z,z), -DELIFT);} | |
int reduce(basis_s **v, point p, simplex *s, int k); | |
void get_basis_sede(simplex *s); | |
int out_of_flat(simplex *root, point p); | |
double cosangle_sq(basis_s* v, basis_s* w); | |
int check_perps(simplex *s); | |
void get_normal_sede(simplex *s); | |
void get_normal(simplex *s); | |
int sees(site p, simplex *s); | |
double radsq(simplex *s); | |
void* zero_marks(simplex* s, void* dum); | |
void* one_marks(simplex* s, void* dum); | |
void* conv_facetv(simplex* s, void* dum); | |
void* mark_points(simplex* s, void* dum); | |
int alph_test(simplex *s, int i, void *alphap); | |
void* visit_outside_ashape(simplex *root, visit_func visit); | |
int check_ashape(simplex *root, double alpha); | |
simplex *build_convex_hull(short dim, short vdd); | |
void free_hull_storage(void); | |
void *compute_vv(simplex *s, void *p); | |
void *compute_pole2(simplex *s, void *p); | |
void *compute_3d_power_vv(simplex *s, void *p); | |
void *compute_axis(simplex *s, void *p); | |
int close_pole(double* v, double* p, double lfs_lb); | |
int antiLabel(int label); | |
/* computes angle between two opposite poles */ | |
double computePoleAngle(simplex* pole1, simplex* pole2, double* samp); | |
/* Adds a new pair of opposite poles to each other's lists */ | |
void newOpposite(int p1index, int p2index, double pole_angle); | |
/* Outputs a pole, saving it's squared radius in adjlist */ | |
void outputPole(simplex* pole, int poleid, double* samp, int* num_poles, double distance); | |
/* Splay using the key i (which may or may not be in the tree.) */ | |
/* The starting root is t, and the tree used is defined by rat */ | |
/* size fields are maintained */ | |
Tree * splay(site i, Tree *t); | |
Tree * insert(site i, Tree * t); | |
void free_heap(); | |
void init_heap(int num); | |
void heapify(int hi); | |
int extract_max(); | |
int insert_heap(int pi, double pr); | |
/* make the element heap_A[hi].pr = pr ... */ | |
void update(int hi, double pr); | |
void *visit_triang_gen(simplex *s, visit_func visit, test_func test); | |
int truet(simplex *s, int i, void *dum); | |
void *visit_triang(simplex *root, visit_func visit); | |
int hullt(simplex *s, int i, void *dummy); | |
void *facet_test(simplex *s, void *dummy); | |
/* visit all simplices with facets of the current hull */ | |
void *visit_hull(simplex *root, visit_func visit); | |
#define lookup(a, b, what) \ | |
{ \ | |
int i; \ | |
neighbor *x; \ | |
for (i = 0, x = a->neigh; (x->what != b) && (i < cdim) ; i++, x++); \ | |
if (i < cdim) \ | |
return x; \ | |
else { \ | |
ASSERT(pcFALSE, "adjacency failure!"); \ | |
return 0; \ | |
} \ | |
} \ | |
neighbor *op_simp(simplex *a, simplex *b); | |
neighbor *op_vert(simplex *a, site b); | |
void connect(simplex *s); | |
simplex *make_facets(simplex *seen); | |
simplex *extend_simplices(simplex *s); | |
simplex *search(simplex *root); | |
point get_another_site(void); | |
void buildhull(simplex *root); | |
int propagate(); | |
void opp_update(int pi); | |
void sym_update(int pi); | |
void update_pri(int hi, int pi); | |
void label_unlabeled(int num); | |
double sqdist(double a[3], double b[3]); | |
void dir_and_dist(double a[3], double b[3], double dir[3], double* dist); | |
void tetcircumcenter(double a[3], double b[3], double c[3], double d[3], double circumcenter[3], double *cond); | |
void tetorthocenter(double a[4], double b[4], double c[4], double d[4], double orthocenter[3], double *cnum); | |
#define INEXACT /* Nothing */ | |
#define REAL double /* float or double */ | |
#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) | |
#define Fast_Two_Sum_Tail(a, b, x, y) \ | |
bvirt = x - a; \ | |
y = b - bvirt | |
#define Fast_Two_Sum(a, b, x, y) \ | |
x = (REAL) (a + b); \ | |
Fast_Two_Sum_Tail(a, b, x, y) | |
#define Two_Sum_Tail(a, b, x, y) \ | |
bvirt = (REAL) (x - a); \ | |
avirt = x - bvirt; \ | |
bround = b - bvirt; \ | |
around = a - avirt; \ | |
y = around + bround | |
#define Two_Sum(a, b, x, y) \ | |
x = (REAL) (a + b); \ | |
Two_Sum_Tail(a, b, x, y) | |
#define Two_Diff_Tail(a, b, x, y) \ | |
bvirt = (REAL) (a - x); \ | |
avirt = x + bvirt; \ | |
bround = bvirt - b; \ | |
around = a - avirt; \ | |
y = around + bround | |
#define Two_Diff(a, b, x, y) \ | |
x = (REAL) (a - b); \ | |
Two_Diff_Tail(a, b, x, y) | |
#define Split(a, ahi, alo) \ | |
c = (REAL) (splitter * a); \ | |
abig = (REAL) (c - a); \ | |
ahi = c - abig; \ | |
alo = a - ahi | |
#define Two_Product_Tail(a, b, x, y) \ | |
Split(a, ahi, alo); \ | |
Split(b, bhi, blo); \ | |
err1 = x - (ahi * bhi); \ | |
err2 = err1 - (alo * bhi); \ | |
err3 = err2 - (ahi * blo); \ | |
y = (alo * blo) - err3 | |
#define Two_Product(a, b, x, y) \ | |
x = (REAL) (a * b); \ | |
Two_Product_Tail(a, b, x, y) | |
/* Two_Product_Presplit() is Two_Product() where one of the inputs has */ | |
/* already been split. Avoids redundant splitting. */ | |
#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ | |
x = (REAL) (a * b); \ | |
Split(a, ahi, alo); \ | |
err1 = x - (ahi * bhi); \ | |
err2 = err1 - (alo * bhi); \ | |
err3 = err2 - (ahi * blo); \ | |
y = (alo * blo) - err3 | |
/* Macros for summing expansions of various fixed lengths. These are all */ | |
/* unrolled versions of Expansion_Sum(). */ | |
#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ | |
Two_Diff(a0, b , _i, x0); \ | |
Two_Sum( a1, _i, x2, x1) | |
#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ | |
Two_One_Diff(a1, a0, b0, _j, _0, x0); \ | |
Two_One_Diff(_j, _0, b1, x3, x2, x1) | |
#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \ | |
Split(b, bhi, blo); \ | |
Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ | |
Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ | |
Two_Sum(_i, _0, _k, x1); \ | |
Fast_Two_Sum(_j, _k, x3, x2) | |
REAL splitter; /* = 2^ceiling(p / 2) + 1. Used to split floats in half. */ | |
REAL epsilon; /* = 2^(-p). Used to estimate roundoff errors. */ | |
/* A set of coefficients used to calculate maximum roundoff errors. */ | |
REAL resulterrbound; | |
REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; | |
REAL o3derrboundA, o3derrboundB, o3derrboundC; | |
void exactinit(); | |
int fast_expansion_sum_zeroelim(int elen, REAL *e, int flen, REAL *f, REAL *h); | |
int scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h); | |
REAL estimate(int elen, REAL *e); | |
REAL orient2dadapt(REAL* pa, REAL* pb, REAL* pc, REAL detsum); | |
REAL orient3dadapt(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL permanent); | |
REAL orient3d(REAL* pa, REAL* pb, REAL* pc, REAL* pd); | |
unsigned short X[3]; | |
double double_rand(void); | |
void init_rand(void); | |
double logb(double x); | |
double local_erand48(unsigned short xseed[3]) throw(); | |
unsigned short _rand48_mult[3]; | |
unsigned short _rand48_add; | |
public: | |
PowerCrustSurfaceReconstructionImpl(void); | |
void pcInit(); | |
void freeAll(void); | |
void adapted_main(double m_mult_up = 1000000); | |
// these globals are here so we can access them from anywhere in the powercrust code | |
// if you can find a neat way to improve this then please feel free | |
struct PolyData | |
{ | |
double * GetPoint(long j) | |
{ | |
return &data[j * 3]; | |
} | |
double GetWeight(long j) | |
{ | |
return weights[j]; | |
} | |
long GetNumberOfPoints() | |
{ | |
return (long)data.size() / 3; | |
} | |
void InsertNextPoint(double vx, double vy, double vz) | |
{ | |
data.push_back(vx); | |
data.push_back(vy); | |
data.push_back(vz); | |
} | |
void InsertNextPoint(float * v) | |
{ | |
data.push_back(v[0]); | |
data.push_back(v[1]); | |
data.push_back(v[2]); | |
} | |
void InsertWeight(double weight) | |
{ | |
weights.push_back(weight); | |
} | |
void InsertTriangle(long v1, long v2, long v3) | |
{ | |
indices.push_back(v1); | |
indices.push_back(v2); | |
indices.push_back(v3); | |
} | |
void InsertCell(std::vector<int> & indices) | |
{ | |
cells.push_back(indices); | |
} | |
void readXYZ(std::string filename) | |
{ | |
std::ifstream ifs(filename); | |
std::string line; | |
std::vector<std::string> words; | |
while (std::getline(ifs, line)) | |
{ | |
std::stringstream linestream(line); | |
copy(std::istream_iterator<std::string>(linestream), | |
std::istream_iterator<std::string>(), | |
std::back_inserter(words)); | |
} | |
for (auto & word : words) | |
{ | |
data.push_back( std::atof(word.c_str()) ); | |
} | |
} | |
void writeOFF(std::string filename) | |
{ | |
std::ofstream ofs(filename); | |
std::ostringstream ss; | |
// Header | |
ss << "OFF " << GetNumberOfPoints() << " " << cells.size() << " 0\n"; | |
// Points | |
for (int i = 0; i < GetNumberOfPoints(); i++){ | |
auto p = GetPoint(i); | |
ss << p[0] << " " << p[1] << " " << p[2] << "\n"; | |
} | |
// Faces | |
for (int i = 0; i < (int)cells.size(); i++){ | |
ss << cells[i].size() << " "; | |
for (int j = 0; j < (int)cells[i].size(); j++) | |
ss << cells[i][j] << " "; | |
ss << "\n"; | |
} | |
ofs << ss.str(); | |
} | |
std::vector< std::vector<double> > GetPoints() | |
{ | |
std::vector< std::vector<double> > pts; | |
for (int i = 0; i < GetNumberOfPoints(); i++){ | |
std::vector<double> pnt; | |
auto p = GetPoint(i); | |
pnt.push_back(p[0]); | |
pnt.push_back(p[1]); | |
pnt.push_back(p[2]); | |
pts.push_back(pnt); | |
} | |
return pts; | |
} | |
std::vector < std::vector<int> > GetFaces(){ return cells; } | |
std::vector < double > data; | |
std::vector < double > weights; | |
std::vector < long > indices; | |
std::vector < std::vector<int> > cells; | |
}; | |
PolyData input; | |
PolyData output; | |
PolyData medial_surface; | |
}; | |
//===================================================================== | |
PowerCrustSurfaceReconstructionImpl::PowerCrustSurfaceReconstructionImpl(void) | |
{ | |
} | |
long PowerCrustSurfaceReconstructionImpl::site_numm(site p) | |
{ | |
if ((vd_new || power_diagram) && p == infinity) return -1; | |
if (!p) return -2; | |
for (int i = 0; i < num_blocks; i++) | |
{ | |
long j; | |
if ((j = p - site_blocks[i]) >= 0 && j < BLOCKSIZE * dim) | |
return j / dim + BLOCKSIZE * i; | |
} | |
return -3; | |
} | |
site PowerCrustSurfaceReconstructionImpl::new_site(site p, long j) | |
{ | |
assert(num_blocks + 1 < MAXBLOCKS); | |
if (0 == (j % BLOCKSIZE)) | |
{ | |
num_blocks++; | |
site_blocks.resize(num_blocks); | |
site_blocks[num_blocks - 1] = (site)malloc(BLOCKSIZE * site_size); | |
site_blocks_pointers.push_back(site_blocks[num_blocks - 1]); | |
return site_blocks[num_blocks - 1]; | |
} | |
else | |
return p + dim; | |
} | |
void PowerCrustSurfaceReconstructionImpl::read_bounding_box(long j) | |
{ | |
int i, k; | |
double center[3], width; | |
omaxs[0] = maxs[0]; | |
omins[0] = mins[0]; | |
omaxs[1] = maxs[1]; | |
omins[1] = mins[1]; | |
omaxs[2] = maxs[2]; | |
omins[2] = mins[2]; | |
center[0] = (maxs[0] - mins[0]) / 2; | |
center[1] = (maxs[1] - mins[1]) / 2; | |
center[2] = (maxs[2] - mins[2]) / 2; | |
if ((maxs[0] - mins[0]) > (maxs[1] - mins[1])) | |
{ | |
if ((maxs[2] - mins[2]) > (maxs[0] - mins[0])) | |
width = maxs[2] - mins[2]; | |
else width = maxs[0] - mins[0]; | |
} | |
else | |
{ | |
if ((maxs[1] - mins[1]) > (maxs[2] - mins[2])) | |
width = maxs[1] - mins[1]; | |
else width = maxs[2] - mins[2]; | |
} | |
width = width * 4; | |
bound[0][0] = center[0] + width; | |
bound[1][0] = bound[0][0]; | |
bound[2][0] = bound[0][0]; | |
bound[3][0] = bound[0][0]; | |
bound[0][1] = center[1] + width; | |
bound[1][1] = bound[0][1]; | |
bound[4][1] = bound[0][1]; | |
bound[5][1] = bound[0][1]; | |
bound[0][2] = center[2] + width; | |
bound[2][2] = bound[0][2]; | |
bound[4][2] = bound[0][2]; | |
bound[6][2] = bound[0][2]; | |
bound[4][0] = center[0] - width; | |
bound[5][0] = bound[4][0]; | |
bound[6][0] = bound[4][0]; | |
bound[7][0] = bound[4][0]; | |
bound[2][1] = center[1] - width; | |
bound[3][1] = bound[2][1]; | |
bound[6][1] = bound[2][1]; | |
bound[7][1] = bound[2][1]; | |
bound[1][2] = center[2] - width; | |
bound[3][2] = bound[1][2]; | |
bound[5][2] = bound[1][2]; | |
bound[7][2] = bound[1][2]; | |
for (k = 0; k < 3; k++) | |
{ | |
p[k] = bound[0][k]; | |
} | |
for (i = 1; i < 8; i++) | |
{ | |
p = new_site(p, j + i); | |
for (k = 0; k < 3; k++) | |
{ | |
p[k] = bound[i][k]; | |
} | |
} | |
maxs[0] = bound[0][0]; | |
mins[0] = bound[4][0]; | |
maxs[1] = bound[0][1]; | |
mins[1] = bound[2][1]; | |
maxs[2] = bound[0][2]; | |
mins[2] = bound[1][2]; | |
} | |
site PowerCrustSurfaceReconstructionImpl::read_next_site(long j) | |
{ | |
ASSERT(j >= 0, "read_next_site "); | |
p = new_site(p, j); | |
for (int i = 0; i < dim; i++) | |
{ | |
p[i] = (double)input.GetPoint(j)[i]; | |
p[i] = floor(mult_up*p[i] + 0.5); | |
mins[i] = (mins[i] < p[i]) ? mins[i] : p[i]; | |
maxs[i] = (maxs[i] > p[i]) ? maxs[i] : p[i]; | |
} | |
return p; | |
} | |
site PowerCrustSurfaceReconstructionImpl::pole_read_next_site(long j) | |
{ | |
ASSERT(j >= 0, "pole_read_next_site"); | |
p = new_site(p, j); | |
for (int i = 0; i < dim; i++) | |
{ | |
if (i < 3) | |
p[i] = (double)medial_surface.GetPoint(j)[i]; | |
else | |
p[i] = medial_surface.GetWeight(j); // (double)medial_surface.GetPointData()->GetScalars()->GetTuple1(j); | |
p[i] = floor(mult_up*p[i] + 0.5); | |
mins[i] = (mins[i] < p[i]) ? mins[i] : p[i]; | |
maxs[i] = (maxs[i] > p[i]) ? maxs[i] : p[i]; | |
} | |
return p; | |
} | |
site PowerCrustSurfaceReconstructionImpl::get_site_offline(long i) | |
{ | |
if (i >= num_sites) return NULL; | |
else | |
{ | |
return site_blocks[i / BLOCKSIZE] + (i % BLOCKSIZE) * dim; | |
} | |
} | |
void PowerCrustSurfaceReconstructionImpl::make_shuffle(void) | |
{ | |
if (mat_size <= num_sites) | |
{ | |
mat_size = num_sites + 1; | |
shufmat.resize(mat_size); | |
} | |
for (long i = 0; i <= num_sites; i++) | |
{ | |
shufmat[i] = i; | |
} | |
for (long i = 0; i < num_sites; i++) | |
{ | |
long t = shufmat[i]; | |
long j = i + (long)((num_sites - i) *double_rand()); // cast to long added by TJH | |
shufmat[i] = shufmat[j]; | |
shufmat[j] = t; | |
} | |
} | |
long PowerCrustSurfaceReconstructionImpl::shufflef(long i) | |
{ | |
return shufmat[i]; | |
} | |
site PowerCrustSurfaceReconstructionImpl::get_next_site(void) | |
{ | |
return (this->*get_site_n) ((this->*shuf) (s_num++)); | |
} | |
void PowerCrustSurfaceReconstructionImpl::make_output(simplex *root, void * (PowerCrustSurfaceReconstructionImpl::*visit_gen) (simplex*, visit_func), visit_func visit) | |
{ | |
// ( this->*visit ) ( 0, ( void ( * ) ) out_funcp ); | |
(this->*visit_gen) (root, visit); | |
} | |
void PowerCrustSurfaceReconstructionImpl::ASSERT(int b, const char*) | |
{ | |
if (!b) | |
{ | |
//our_filter->Error ( message ); | |
} | |
} | |
void PowerCrustSurfaceReconstructionImpl::freeAll(void) | |
{ | |
for (unsigned int i = 0; i < adjlist.size(); i++) | |
{ | |
edgesimp *tmpEdgesimp; | |
edgesimp *curEdgesimp; | |
curEdgesimp = adjlist[i].eptr; | |
while (curEdgesimp) | |
{ | |
tmpEdgesimp = curEdgesimp; | |
curEdgesimp = tmpEdgesimp->next; | |
free(tmpEdgesimp); | |
} | |
} | |
for (unsigned int i = 0; i < opplist.size(); i++) | |
{ | |
if (opplist[i] != NULL) | |
{ | |
plist *tmpPlist; | |
plist *curPlist; | |
curPlist = opplist[i]; | |
while (curPlist) | |
{ | |
tmpPlist = curPlist; | |
curPlist = tmpPlist->next; | |
free(tmpPlist); | |
} | |
} | |
} | |
free(pole1_distance); | |
free(pole2_distance); | |
free(pole1); | |
free(pole2); | |
free(lfs_lb); | |
free_hull_storage(); | |
free(p_neigh.basis); | |
free(seesB); | |
free(st_search); | |
free(st_visit_triang_gen); | |
for (unsigned int i = 0; i < site_blocks_pointers.size(); i++) | |
free(site_blocks_pointers[i]); | |
free_heap(); // EPRO added | |
} | |
void PowerCrustSurfaceReconstructionImpl::adapted_main(double m_mult_up) | |
{ | |
int num_poles = 0; | |
simplex *root; | |
edgesimp *eindex; | |
visit_func pr; | |
mult_up = m_mult_up; | |
//est_r = our_filter->GetEstimateR(); | |
short bad = 0; | |
long poleid = 0; | |
double samp[3]; | |
dim = 3; | |
if (dim > MAXDIM) ASSERT(pcFALSE, "dimension bound MAXDIM exceeded"); | |
site_size = sizeof(Coord) *dim; | |
// TJH: we've replaced this file-reading loop with the loop below | |
for (num_sites = 0; num_sites < input.GetNumberOfPoints(); num_sites++) | |
{ | |
read_next_site(num_sites); | |
} | |
num_sites--; | |
read_bounding_box(num_sites); | |
num_sites += 8; | |
init_rand(); | |
make_shuffle(); | |
shuf = &PowerCrustSurfaceReconstructionImpl::shufflef; | |
get_site_n = &PowerCrustSurfaceReconstructionImpl::get_site_offline; | |
/* Step 1: compute DT of input point set */ | |
root = build_convex_hull(dim, vd_new); | |
/* Step 2: Find poles */ | |
pole1 = (simplex **)calloc(num_sites, sizeof(simplex *)); | |
pole2 = (simplex **)calloc(num_sites, sizeof(simplex *)); | |
lfs_lb = (double*)calloc(num_sites, sizeof(double)); | |
exactinit(); /* Shewchuk's exact arithmetic initialization */ | |
pr = &PowerCrustSurfaceReconstructionImpl::compute_vv; | |
make_output(root, &PowerCrustSurfaceReconstructionImpl::visit_hull, pr); | |
pr = &PowerCrustSurfaceReconstructionImpl::compute_pole2; | |
make_output(root, &PowerCrustSurfaceReconstructionImpl::visit_hull, pr); | |
/* initialize the sample distance info for the poles */ | |
pole1_distance = (double *)malloc(num_sites*sizeof(double)); | |
pole2_distance = (double *)malloc(num_sites*sizeof(double)); | |
compute_distance(pole1, num_sites - 8, pole1_distance); | |
compute_distance(pole2, num_sites - 8, pole2_distance); | |
/* intialize list of lists of pointers to opposite poles */ | |
opplist.resize(2 * num_sites); | |
/* data about poles; adjacencies, labels, radii */ | |
adjlist.resize(2 * num_sites); | |
/* loop through sites, writing out poles */ | |
for (int i = 0; i < num_sites - 8; i++) | |
{ | |
/* rescale the sample to real input coordinates */ | |
for (int k = 0; k < 3; k++) | |
samp[k] = get_site_offline(i)[k] / mult_up; | |
/* output poles, both to debugging file and for weighted DT */ | |
/* remembers sqaured radius */ | |
if ((pole1[i] != NULL) && (pole1[i]->status != POLE_OUTPUT)) | |
{ | |
/* if second pole is closer than we think it should be... */ | |
if ((pole2[i] != NULL) && bad && close_pole(samp, pole2[i]->vv, lfs_lb[i])) | |
{ | |
} | |
else | |
{ | |
outputPole(pole1[i], poleid++, samp, &num_poles, pole1_distance[i]); | |
} | |
} | |
if ((pole2[i] != NULL) && (pole2[i]->status != POLE_OUTPUT)) | |
{ | |
/* if pole is closer than we think it should be... */ | |
if (close_pole(samp, pole2[i]->vv, lfs_lb[i])) | |
{ | |
/* remember opposite bad for late labeling */ | |
if (!bad) adjlist[pole1[i]->poleindex].bad = BAD_POLE; | |
continue; | |
} | |
outputPole(pole2[i], poleid++, samp, &num_poles, pole2_distance[i]); | |
} | |
/* keep list of opposite poles for later coloring */ | |
if ((pole1[i] != NULL) && (pole2[i] != NULL) && (pole1[i]->status == POLE_OUTPUT) && (pole2[i]->status == POLE_OUTPUT)) | |
{ | |
double pole_angle = computePoleAngle(pole1[i], pole2[i], samp); | |
newOpposite(pole1[i]->poleindex, pole2[i]->poleindex, pole_angle); | |
newOpposite(pole2[i]->poleindex, pole1[i]->poleindex, pole_angle); | |
} | |
} | |
free_hull_storage(); | |
power_diagram = 1; | |
vd_new = 0; | |
dim = 4; | |
// TJH: uncommented this line, seemed like we need to free this memory before num_blocks gets reset | |
for (unsigned int i = 0; i < site_blocks_pointers.size(); i++) | |
{ | |
free(site_blocks_pointers[i]); | |
} | |
site_blocks_pointers.clear(); | |
num_blocks = 0; | |
s_num = 0; | |
scount = 0; | |
site_size = sizeof(Coord) *dim; | |
/* save points in order read */ | |
for (num_sites = 0; num_sites < medial_surface.GetNumberOfPoints(); num_sites++) | |
{ | |
pole_read_next_site(num_sites); | |
} | |
//num_sites--; | |
/* set up the shuffle */ | |
init_rand(); | |
make_shuffle(); | |
shuf = &PowerCrustSurfaceReconstructionImpl::shufflef; | |
get_site_n = &PowerCrustSurfaceReconstructionImpl::get_site_offline; /* returns stored points, unshuffled */ | |
/* Compute weighted DT */ | |
root = build_convex_hull(dim, vd_new); | |
/* compute adjacencies and find angles of ball intersections */ | |
pr = &PowerCrustSurfaceReconstructionImpl::compute_3d_power_vv; | |
make_output(root, &PowerCrustSurfaceReconstructionImpl::visit_hull, pr); | |
/* labeling */ | |
init_heap(num_poles); | |
for (int i = 0; i < num_poles; i++) | |
{ | |
if ((get_site_offline(i)[0]>(2 * omaxs[0] - omins[0])) || | |
(get_site_offline(i)[0]< (2 * omins[0] - omaxs[0])) || | |
(get_site_offline(i)[1]> (2 * omaxs[1] - omins[1])) || | |
(get_site_offline(i)[1]< (2 * omins[1] - omaxs[1])) || | |
(get_site_offline(i)[2]> (2 * omaxs[2] - omins[2])) || | |
(get_site_offline(i)[2] < (2 * omins[2] - omaxs[2]))) | |
{ | |
adjlist[i].hid = insert_heap(i, 1.0); | |
adjlist[i].out = 1.0; | |
adjlist[i].label = OUT; | |
} | |
} | |
while (heap_size != 0) | |
propagate(); | |
label_unlabeled(num_poles); | |
for (int i = 0; i < num_poles; i++) | |
{ | |
if ((adjlist[i].label != IN) && (adjlist[i].label != OUT)) | |
{ | |
} | |
else | |
{ | |
eindex = adjlist[i].eptr; | |
while (eindex != NULL) | |
{ | |
if ((i < eindex->pid) && (antiLabel(adjlist[i].label) == adjlist[eindex->pid].label)) | |
{ | |
construct_face(eindex->simp, eindex->kth); | |
} | |
eindex = eindex->next; | |
} | |
} | |
} | |
/* compute the medial axis */ | |
pr = &PowerCrustSurfaceReconstructionImpl::compute_axis; | |
make_output(root, &PowerCrustSurfaceReconstructionImpl::visit_hull, pr); | |
} | |
void PowerCrustSurfaceReconstructionImpl::compute_distance(simplex** poles, int size, double* distance) | |
{ | |
double indices[4][3]; /* the coords of the four vertices of the simplex*/ | |
point v[MAXDIM]; | |
simplex* currSimplex; | |
double maxdistance = 0; | |
for (int l = 0; l < size; l++) /* for each pole do*/ | |
{ | |
if (poles[l] != NULL) | |
{ | |
currSimplex = poles[l]; | |
/* get the coordinates of the four endpoints */ | |
for (int j = 0; j < 4; j++) | |
{ | |
v[j] = currSimplex->neigh[j].vert; | |
for (int k = 0; k < 3; k++) | |
indices[j][k] = v[j][k] / mult_up; | |
} | |
/* now compute the actual distance */ | |
maxdistance = 0; | |
for (int i = 0; i < 4; i++) | |
{ | |
for (int j = i + 1; j < 4; j++) | |
{ | |
double currdistance = SQ(indices[i][0] - indices[j][0]) + SQ(indices[i][1] - indices[j][1]) + SQ(indices[i][2] - indices[j][2]); | |
currdistance = sqrt(currdistance); | |
if (maxdistance < currdistance) | |
maxdistance = currdistance; | |
} | |
} | |
distance[l] = maxdistance; | |
} | |
} | |
} | |
void PowerCrustSurfaceReconstructionImpl::pcInit() | |
{ | |
pcFALSE = (1 == 0); | |
pcTRUE = (1 == 1); | |
//input = NULL; | |
//output = NULL; | |
//medial_surface = NULL; | |
//our_filter = NULL; | |
seesB = NULL; | |
check_perps_b = NULL; | |
p = NULL; | |
pole1_distance = NULL; | |
pole2_distance = NULL; | |
st_search = NULL; | |
st_visit_triang_gen = NULL; | |
ch_root = NULL; | |
pole1 = NULL; | |
pole2 = NULL; | |
lfs_lb = NULL; | |
site_num = NULL; | |
heap_A = NULL; | |
make_facets_ns = NULL; | |
site_blocks.clear(); | |
site_blocks_pointers.clear(); | |
adjlist.clear(); | |
opplist.clear(); | |
num_blocks = 0; | |
mult_up = 1.0; | |
num_vtxs = 0; | |
est_r = 0.6; | |
num_poles = 0; | |
heap_size = 0; | |
scount = 0; | |
vd_new = 1; | |
power_diagram = 0; | |
s_num = 0; | |
theta = 0.0; | |
deep = 0.0; | |
mat_size = 0; | |
loopStart = -1; | |
count = 0; | |
lastCount = 0; | |
visit_triang_gen_vnum = -1; | |
visit_triang_gen_ss = 2000; | |
pdim = 0; | |
rdim = 0; | |
cdim = 0; | |
site_size = 0; | |
pnum = 0; | |
num_sites = 0; | |
dim = 0; | |
basis_vec_size = 0; | |
exact_bits = 0; | |
b_err_min = 0; | |
b_err_min_sq = 0; | |
sc_lscale = 0; | |
sc_max_scale = 0; | |
sc_ldetbound = 0; | |
sc_Sb = 0; | |
alpha_test_alpha = 0; | |
heap_length = 0; | |
search_ss = MAXDIM; | |
Huge = DBL_MAX; | |
vd = 0; | |
_rand48_add = RAND48_ADD; | |
infinity[0] = 57.2; | |
infinity[1] = 0; | |
infinity[2] = 0; | |
infinity[3] = 0; | |
infinity[4] = 0; | |
v1[0] = 0; | |
v1[1] = 0; | |
v1[2] = 0; | |
v1[3] = 1; | |
v1[4] = 1; | |
v1[5] = 2; | |
v2[0] = 1; | |
v2[1] = 2; | |
v2[2] = 3; | |
v2[3] = 2; | |
v2[4] = 3; | |
v2[5] = 3; | |
v3[0] = 2; | |
v3[1] = 3; | |
v3[2] = 1; | |
v3[3] = 3; | |
v3[4] = 0; | |
v3[5] = 0; | |
v4[0] = 3; | |
v4[1] = 1; | |
v4[2] = 2; | |
v4[3] = 0; | |
v4[4] = 2; | |
v4[5] = 1; | |
for (int i = 0; i < 8; i++) | |
{ | |
for (int j = 0; j < 3; j++) | |
{ | |
bound[i][j] = 0; | |
} | |
} | |
for (int i = 0; i < MAXPOINTS; i++) | |
{ | |
mi[i] = 0; | |
mo[i] = 0; | |
} | |
omins[0] = 0; | |
omins[1] = 0; | |
omins[2] = 0; | |
omaxs[0] = 0; | |
omaxs[1] = 0; | |
omaxs[2] = 0; | |
p_neigh.vert = 0; | |
p_neigh.basis = 0; | |
p_neigh.simp = 0; | |
X[0] = 0; | |
X[1] = 10000; | |
X[2] = 0; | |
for (int i = 0; i < MAXDIM; i++) | |
{ | |
mins[i] = DBL_MAX; | |
maxs[i] = -DBL_MAX; | |
} | |
tt_basis.next = 0; | |
tt_basis.ref_count = 1; | |
tt_basis.lscale = -1; | |
tt_basis.sqa = 0; | |
tt_basis.sqb = 0; | |
tt_basis.vecs[0] = 0; | |
tt_basisp = &tt_basis; | |
infinity_basis = NULL; | |
X[0] = 0; | |
X[1] = 0; | |
X[2] = 0; | |
_rand48_mult[0] = RAND48_MULT_0; | |
_rand48_mult[1] = RAND48_MULT_1; | |
_rand48_mult[2] = RAND48_MULT_2; | |
_rand48_add = RAND48_ADD; | |
} | |
void PowerCrustSurfaceReconstructionImpl::_dorand48(unsigned short xseed[3]) | |
{ | |
unsigned long accu; | |
unsigned short temp[2]; | |
accu = (unsigned long)_rand48_mult[0] * (unsigned long)xseed[0] + (unsigned long)_rand48_add; | |
temp[0] = (unsigned short)accu; /* lower 16 bits */ | |
accu >>= sizeof(unsigned short) * 8; | |
accu += (unsigned long)_rand48_mult[0] * (unsigned long)xseed[1] + (unsigned long)_rand48_mult[1] * (unsigned long)xseed[0]; | |
temp[1] = (unsigned short)accu; /* middle 16 bits */ | |
accu >>= sizeof(unsigned short) * 8; | |
accu += _rand48_mult[0] * xseed[2] + _rand48_mult[1] * xseed[1] + _rand48_mult[2] * xseed[0]; | |
xseed[0] = temp[0]; | |
xseed[1] = temp[1]; | |
xseed[2] = (unsigned short)accu; | |
} | |
double PowerCrustSurfaceReconstructionImpl::local_erand48(unsigned short xseed[3]) throw() | |
{ | |
_dorand48(xseed); | |
return ldexp((double)xseed[0], -48) + ldexp((double)xseed[1], -32) + ldexp((double)xseed[2], -16); | |
} | |
double PowerCrustSurfaceReconstructionImpl::double_rand(void) | |
{ | |
return local_erand48(X); | |
} | |
void PowerCrustSurfaceReconstructionImpl::init_rand(void) | |
{ | |
X[1] = 10000; | |
} | |
double PowerCrustSurfaceReconstructionImpl::logb(double x) | |
{ | |
return log(x) / log(2.0); // EPRO added | |
} | |
REAL PowerCrustSurfaceReconstructionImpl::orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent) | |
{ | |
INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; | |
REAL det, errbound; | |
INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; | |
REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; | |
REAL bc[4], ca[4], ab[4]; | |
INEXACT REAL bc3, ca3, ab3; | |
REAL adet[8], bdet[8], cdet[8]; | |
int alen, blen, clen; | |
REAL abdet[16]; | |
int ablen; | |
REAL *finnow, *finother, *finswap; | |
REAL fin1[192], fin2[192]; | |
int finlength; | |
REAL adxtail, bdxtail, cdxtail; | |
REAL adytail, bdytail, cdytail; | |
REAL adztail, bdztail, cdztail; | |
INEXACT REAL at_blarge, at_clarge; | |
INEXACT REAL bt_clarge, bt_alarge; | |
INEXACT REAL ct_alarge, ct_blarge; | |
REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4]; | |
int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen; | |
INEXACT REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1; | |
INEXACT REAL adxt_cdy1, adxt_bdy1, bdxt_ady1; | |
REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0; | |
REAL adxt_cdy0, adxt_bdy0, bdxt_ady0; | |
INEXACT REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1; | |
INEXACT REAL adyt_cdx1, adyt_bdx1, bdyt_adx1; | |
REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0; | |
REAL adyt_cdx0, adyt_bdx0, bdyt_adx0; | |
REAL bct[8], cat[8], abt[8]; | |
int bctlen, catlen, abtlen; | |
INEXACT REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1; | |
INEXACT REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1; | |
REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0; | |
REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0; | |
REAL u[4], v[12], w[16]; | |
INEXACT REAL u3; | |
int vlength, wlength; | |
REAL negate; | |
INEXACT REAL bvirt; | |
REAL avirt, bround, around; | |
INEXACT REAL c; | |
INEXACT REAL abig; | |
REAL ahi, alo, bhi, blo; | |
REAL err1, err2, err3; | |
INEXACT REAL _i, _j, _k; | |
REAL _0; | |
adx = (REAL)(pa[0] - pd[0]); | |
bdx = (REAL)(pb[0] - pd[0]); | |
cdx = (REAL)(pc[0] - pd[0]); | |
ady = (REAL)(pa[1] - pd[1]); | |
bdy = (REAL)(pb[1] - pd[1]); | |
cdy = (REAL)(pc[1] - pd[1]); | |
adz = (REAL)(pa[2] - pd[2]); | |
bdz = (REAL)(pb[2] - pd[2]); | |
cdz = (REAL)(pc[2] - pd[2]); | |
Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); | |
Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); | |
Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); | |
bc[3] = bc3; | |
alen = scale_expansion_zeroelim(4, bc, adz, adet); | |
Two_Product(cdx, ady, cdxady1, cdxady0); | |
Two_Product(adx, cdy, adxcdy1, adxcdy0); | |
Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); | |
ca[3] = ca3; | |
blen = scale_expansion_zeroelim(4, ca, bdz, bdet); | |
Two_Product(adx, bdy, adxbdy1, adxbdy0); | |
Two_Product(bdx, ady, bdxady1, bdxady0); | |
Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); | |
ab[3] = ab3; | |
clen = scale_expansion_zeroelim(4, ab, cdz, cdet); | |
ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); | |
finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); | |
det = estimate(finlength, fin1); | |
errbound = o3derrboundB * permanent; | |
if ((det >= errbound) || (-det >= errbound)) | |
{ | |
return det; | |
} | |
Two_Diff_Tail(pa[0], pd[0], adx, adxtail); | |
Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); | |
Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); | |
Two_Diff_Tail(pa[1], pd[1], ady, adytail); | |
Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); | |
Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); | |
Two_Diff_Tail(pa[2], pd[2], adz, adztail); | |
Two_Diff_Tail(pb[2], pd[2], bdz, bdztail); | |
Two_Diff_Tail(pc[2], pd[2], cdz, cdztail); | |
if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) | |
&& (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0) | |
&& (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) | |
{ | |
return det; | |
} | |
errbound = o3derrboundC * permanent + resulterrbound * Absolute(det); | |
det += (adz * ((bdx * cdytail + cdy * bdxtail) | |
- (bdy * cdxtail + cdx * bdytail)) | |
+ adztail * (bdx * cdy - bdy * cdx)) | |
+ (bdz * ((cdx * adytail + ady * cdxtail) | |
- (cdy * adxtail + adx * cdytail)) | |
+ bdztail * (cdx * ady - cdy * adx)) | |
+ (cdz * ((adx * bdytail + bdy * adxtail) | |
- (ady * bdxtail + bdx * adytail)) | |
+ cdztail * (adx * bdy - ady * bdx)); | |
if ((det >= errbound) || (-det >= errbound)) | |
{ | |
return det; | |
} | |
finnow = fin1; | |
finother = fin2; | |
if (adxtail == 0.0) | |
{ | |
if (adytail == 0.0) | |
{ | |
at_b[0] = 0.0; | |
at_blen = 1; | |
at_c[0] = 0.0; | |
at_clen = 1; | |
} | |
else | |
{ | |
negate = -adytail; | |
Two_Product(negate, bdx, at_blarge, at_b[0]); | |
at_b[1] = at_blarge; | |
at_blen = 2; | |
Two_Product(adytail, cdx, at_clarge, at_c[0]); | |
at_c[1] = at_clarge; | |
at_clen = 2; | |
} | |
} | |
else | |
{ | |
if (adytail == 0.0) | |
{ | |
Two_Product(adxtail, bdy, at_blarge, at_b[0]); | |
at_b[1] = at_blarge; | |
at_blen = 2; | |
negate = -adxtail; | |
Two_Product(negate, cdy, at_clarge, at_c[0]); | |
at_c[1] = at_clarge; | |
at_clen = 2; | |
} | |
else | |
{ | |
Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0); | |
Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0); | |
Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0, | |
at_blarge, at_b[2], at_b[1], at_b[0]); | |
at_b[3] = at_blarge; | |
at_blen = 4; | |
Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0); | |
Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0); | |
Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0, | |
at_clarge, at_c[2], at_c[1], at_c[0]); | |
at_c[3] = at_clarge; | |
at_clen = 4; | |
} | |
} | |
if (bdxtail == 0.0) | |
{ | |
if (bdytail == 0.0) | |
{ | |
bt_c[0] = 0.0; | |
bt_clen = 1; | |
bt_a[0] = 0.0; | |
bt_alen = 1; | |
} | |
else | |
{ | |
negate = -bdytail; | |
Two_Product(negate, cdx, bt_clarge, bt_c[0]); | |
bt_c[1] = bt_clarge; | |
bt_clen = 2; | |
Two_Product(bdytail, adx, bt_alarge, bt_a[0]); | |
bt_a[1] = bt_alarge; | |
bt_alen = 2; | |
} | |
} | |
else | |
{ | |
if (bdytail == 0.0) | |
{ | |
Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]); | |
bt_c[1] = bt_clarge; | |
bt_clen = 2; | |
negate = -bdxtail; | |
Two_Product(negate, ady, bt_alarge, bt_a[0]); | |
bt_a[1] = bt_alarge; | |
bt_alen = 2; | |
} | |
else | |
{ | |
Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0); | |
Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0); | |
Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0, | |
bt_clarge, bt_c[2], bt_c[1], bt_c[0]); | |
bt_c[3] = bt_clarge; | |
bt_clen = 4; | |
Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0); | |
Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0); | |
Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0, | |
bt_alarge, bt_a[2], bt_a[1], bt_a[0]); | |
bt_a[3] = bt_alarge; | |
bt_alen = 4; | |
} | |
} | |
if (cdxtail == 0.0) | |
{ | |
if (cdytail == 0.0) | |
{ | |
ct_a[0] = 0.0; | |
ct_alen = 1; | |
ct_b[0] = 0.0; | |
ct_blen = 1; | |
} | |
else | |
{ | |
negate = -cdytail; | |
Two_Product(negate, adx, ct_alarge, ct_a[0]); | |
ct_a[1] = ct_alarge; | |
ct_alen = 2; | |
Two_Product(cdytail, bdx, ct_blarge, ct_b[0]); | |
ct_b[1] = ct_blarge; | |
ct_blen = 2; | |
} | |
} | |
else | |
{ | |
if (cdytail == 0.0) | |
{ | |
Two_Product(cdxtail, ady, ct_alarge, ct_a[0]); | |
ct_a[1] = ct_alarge; | |
ct_alen = 2; | |
negate = -cdxtail; | |
Two_Product(negate, bdy, ct_blarge, ct_b[0]); | |
ct_b[1] = ct_blarge; | |
ct_blen = 2; | |
} | |
else | |
{ | |
Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0); | |
Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0); | |
Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0, | |
ct_alarge, ct_a[2], ct_a[1], ct_a[0]); | |
ct_a[3] = ct_alarge; | |
ct_alen = 4; | |
Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0); | |
Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0); | |
Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0, | |
ct_blarge, ct_b[2], ct_b[1], ct_b[0]); | |
ct_b[3] = ct_blarge; | |
ct_blen = 4; | |
} | |
} | |
bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct); | |
wlength = scale_expansion_zeroelim(bctlen, bct, adz, w); | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat); | |
wlength = scale_expansion_zeroelim(catlen, cat, bdz, w); | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt); | |
wlength = scale_expansion_zeroelim(abtlen, abt, cdz, w); | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
if (adztail != 0.0) | |
{ | |
vlength = scale_expansion_zeroelim(4, bc, adztail, v); | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
if (bdztail != 0.0) | |
{ | |
vlength = scale_expansion_zeroelim(4, ca, bdztail, v); | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
if (cdztail != 0.0) | |
{ | |
vlength = scale_expansion_zeroelim(4, ab, cdztail, v); | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
if (adxtail != 0.0) | |
{ | |
if (bdytail != 0.0) | |
{ | |
Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0); | |
Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
if (cdztail != 0.0) | |
{ | |
Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
} | |
if (cdytail != 0.0) | |
{ | |
negate = -adxtail; | |
Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0); | |
Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
if (bdztail != 0.0) | |
{ | |
Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
} | |
} | |
if (bdxtail != 0.0) | |
{ | |
if (cdytail != 0.0) | |
{ | |
Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0); | |
Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
if (adztail != 0.0) | |
{ | |
Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
} | |
if (adytail != 0.0) | |
{ | |
negate = -bdxtail; | |
Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0); | |
Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
if (cdztail != 0.0) | |
{ | |
Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
} | |
} | |
if (cdxtail != 0.0) | |
{ | |
if (adytail != 0.0) | |
{ | |
Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0); | |
Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
if (bdztail != 0.0) | |
{ | |
Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
} | |
if (bdytail != 0.0) | |
{ | |
negate = -cdxtail; | |
Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0); | |
Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
if (adztail != 0.0) | |
{ | |
Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
} | |
} | |
if (adztail != 0.0) | |
{ | |
wlength = scale_expansion_zeroelim(bctlen, bct, adztail, w); | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
if (bdztail != 0.0) | |
{ | |
wlength = scale_expansion_zeroelim(catlen, cat, bdztail, w); | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
if (cdztail != 0.0) | |
{ | |
wlength = scale_expansion_zeroelim(abtlen, abt, cdztail, w); | |
finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, | |
finother); | |
finswap = finnow; | |
finnow = finother; | |
finother = finswap; | |
} | |
return finnow[finlength - 1]; | |
} | |
REAL PowerCrustSurfaceReconstructionImpl::orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd) | |
{ | |
REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; | |
REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; | |
REAL det; | |
REAL permanent, errbound; | |
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]; | |
bdxcdy = bdx * cdy; | |
cdxbdy = cdx * bdy; | |
cdxady = cdx * ady; | |
adxcdy = adx * cdy; | |
adxbdy = adx * bdy; | |
bdxady = bdx * ady; | |
det = adz * (bdxcdy - cdxbdy) | |
+ bdz * (cdxady - adxcdy) | |
+ cdz * (adxbdy - bdxady); | |
permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz) | |
+ (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz) | |
+ (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz); | |
errbound = o3derrboundA * permanent; | |
if ((det > errbound) || (-det > errbound)) | |
{ | |
return det; | |
} | |
return orient3dadapt(pa, pb, pc, pd, permanent); | |
} | |
REAL PowerCrustSurfaceReconstructionImpl::estimate(int elen, REAL *e) | |
{ | |
REAL Q; | |
int eindex; | |
Q = e[0]; | |
for (eindex = 1; eindex < elen; eindex++) | |
{ | |
Q += e[eindex]; | |
} | |
return Q; | |
} | |
REAL PowerCrustSurfaceReconstructionImpl::orient2dadapt(REAL *pa, REAL *pb, REAL *pc, REAL detsum) | |
{ | |
INEXACT REAL acx, acy, bcx, bcy; | |
REAL acxtail, acytail, bcxtail, bcytail; | |
INEXACT REAL detleft, detright; | |
REAL detlefttail, detrighttail; | |
REAL det, errbound; | |
REAL B[4], C1[8], C2[12], D[16]; | |
INEXACT REAL B3; | |
int C1length, C2length, Dlength; | |
REAL u[4]; | |
INEXACT REAL u3; | |
INEXACT REAL s1, t1; | |
REAL s0, t0; | |
INEXACT REAL bvirt; | |
REAL avirt, bround, around; | |
INEXACT REAL c; | |
INEXACT REAL abig; | |
REAL ahi, alo, bhi, blo; | |
REAL err1, err2, err3; | |
INEXACT REAL _i, _j; | |
REAL _0; | |
acx = (REAL)(pa[0] - pc[0]); | |
bcx = (REAL)(pb[0] - pc[0]); | |
acy = (REAL)(pa[1] - pc[1]); | |
bcy = (REAL)(pb[1] - pc[1]); | |
Two_Product(acx, bcy, detleft, detlefttail); | |
Two_Product(acy, bcx, detright, detrighttail); | |
Two_Two_Diff(detleft, detlefttail, detright, detrighttail, | |
B3, B[2], B[1], B[0]); | |
B[3] = B3; | |
det = estimate(4, B); | |
errbound = ccwerrboundB * detsum; | |
if ((det >= errbound) || (-det >= errbound)) | |
{ | |
return det; | |
} | |
Two_Diff_Tail(pa[0], pc[0], acx, acxtail); | |
Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); | |
Two_Diff_Tail(pa[1], pc[1], acy, acytail); | |
Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); | |
if ((acxtail == 0.0) && (acytail == 0.0) | |
&& (bcxtail == 0.0) && (bcytail == 0.0)) | |
{ | |
return det; | |
} | |
errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det); | |
det += (acx * bcytail + bcy * acxtail) | |
- (acy * bcxtail + bcx * acytail); | |
if ((det >= errbound) || (-det >= errbound)) | |
{ | |
return det; | |
} | |
Two_Product(acxtail, bcy, s1, s0); | |
Two_Product(acytail, bcx, t1, t0); | |
Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); | |
Two_Product(acx, bcytail, s1, s0); | |
Two_Product(acy, bcxtail, t1, t0); | |
Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); | |
Two_Product(acxtail, bcytail, s1, s0); | |
Two_Product(acytail, bcxtail, t1, t0); | |
Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); | |
u[3] = u3; | |
Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); | |
return (D[Dlength - 1]); | |
} | |
int PowerCrustSurfaceReconstructionImpl::scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h) | |
{ | |
INEXACT REAL Q, sum; | |
REAL hh; | |
INEXACT REAL product1; | |
REAL product0; | |
int eindex, hindex; | |
REAL enow; | |
INEXACT REAL bvirt; | |
REAL avirt, bround, around; | |
INEXACT REAL c; | |
INEXACT REAL abig; | |
REAL ahi, alo, bhi, blo; | |
REAL err1, err2, err3; | |
Split(b, bhi, blo); | |
Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); | |
hindex = 0; | |
if (hh != 0) | |
{ | |
h[hindex++] = hh; | |
} | |
for (eindex = 1; eindex < elen; eindex++) | |
{ | |
enow = e[eindex]; | |
Two_Product_Presplit(enow, b, bhi, blo, product1, product0); | |
Two_Sum(Q, product0, sum, hh); | |
if (hh != 0) | |
{ | |
h[hindex++] = hh; | |
} | |
Fast_Two_Sum(product1, sum, Q, hh); | |
if (hh != 0) | |
{ | |
h[hindex++] = hh; | |
} | |
} | |
if ((Q != 0.0) || (hindex == 0)) | |
{ | |
h[hindex++] = Q; | |
} | |
return hindex; | |
} | |
int PowerCrustSurfaceReconstructionImpl::fast_expansion_sum_zeroelim(int elen, REAL *e, int flen, REAL *f, REAL *h) | |
{ | |
REAL Q; | |
INEXACT REAL Qnew; | |
INEXACT REAL hh; | |
INEXACT REAL bvirt; | |
REAL avirt, bround, around; | |
int eindex, findex, hindex; | |
REAL enow, fnow; | |
enow = e[0]; | |
fnow = f[0]; | |
eindex = findex = 0; | |
if ((fnow > enow) == (fnow > -enow)) | |
{ | |
Q = enow; | |
enow = e[++eindex]; | |
} | |
else | |
{ | |
Q = fnow; | |
fnow = f[++findex]; | |
} | |
hindex = 0; | |
if ((eindex < elen) && (findex < flen)) | |
{ | |
if ((fnow > enow) == (fnow > -enow)) | |
{ | |
Fast_Two_Sum(enow, Q, Qnew, hh); | |
enow = e[++eindex]; | |
} | |
else | |
{ | |
Fast_Two_Sum(fnow, Q, Qnew, hh); | |
fnow = f[++findex]; | |
} | |
Q = Qnew; | |
if (hh != 0.0) | |
{ | |
h[hindex++] = hh; | |
} | |
while ((eindex < elen) && (findex < flen)) | |
{ | |
if ((fnow > enow) == (fnow > -enow)) | |
{ | |
Two_Sum(Q, enow, Qnew, hh); | |
enow = e[++eindex]; | |
} | |
else | |
{ | |
Two_Sum(Q, fnow, Qnew, hh); | |
fnow = f[++findex]; | |
} | |
Q = Qnew; | |
if (hh != 0.0) | |
{ | |
h[hindex++] = hh; | |
} | |
} | |
} | |
while (eindex < elen) | |
{ | |
Two_Sum(Q, enow, Qnew, hh); | |
enow = e[++eindex]; | |
Q = Qnew; | |
if (hh != 0.0) | |
{ | |
h[hindex++] = hh; | |
} | |
} | |
while (findex < flen) | |
{ | |
Two_Sum(Q, fnow, Qnew, hh); | |
fnow = f[++findex]; | |
Q = Qnew; | |
if (hh != 0.0) | |
{ | |
h[hindex++] = hh; | |
} | |
} | |
if ((Q != 0.0) || (hindex == 0)) | |
{ | |
h[hindex++] = Q; | |
} | |
return hindex; | |
} | |
void PowerCrustSurfaceReconstructionImpl::exactinit() | |
{ | |
REAL half; | |
REAL check, lastcheck; | |
int every_other; | |
every_other = 1; | |
half = 0.5; | |
epsilon = 1.0; | |
splitter = 1.0; | |
check = 1.0; | |
/* Repeatedly divide `epsilon' by two until it is too small to add to */ | |
/* one without causing roundoff. (Also check if the sum is equal to */ | |
/* the previous sum, for machines that round up instead of using exact */ | |
/* rounding. Not that this library will work on such machines anyway. */ | |
do | |
{ | |
lastcheck = check; | |
epsilon *= half; | |
if (every_other) | |
{ | |
splitter *= 2.0; | |
} | |
every_other = !every_other; | |
check = 1.0 + epsilon; | |
} while ((check != 1.0) && (check != lastcheck)); | |
splitter += 1.0; | |
/* Error bounds for orientation and incircle tests. */ | |
resulterrbound = (3.0 + 8.0 * epsilon) * epsilon; | |
ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon; | |
ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon; | |
ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon; | |
o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon; | |
o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon; | |
o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon; | |
} | |
void PowerCrustSurfaceReconstructionImpl::tetorthocenter(double a[4], double b[4], double c[4], double d[4], double orthocenter[3], double *cnum) | |
{ | |
double xba, yba, zba, xca, yca, zca, xda, yda, zda, wba, wca, wda; | |
double balength, calength, dalength; | |
double xcrosscd, ycrosscd, zcrosscd; | |
double xcrossdb, ycrossdb, zcrossdb; | |
double xcrossbc, ycrossbc, zcrossbc; | |
double denominator; | |
double xcirca, ycirca, zcirca; | |
double wa, wb, wc, wd; | |
wa = a[0] * a[0] + a[1] * a[1] + a[2] * a[2] - a[3]; | |
wb = b[0] * b[0] + b[1] * b[1] + b[2] * b[2] - b[3]; | |
wc = c[0] * c[0] + c[1] * c[1] + c[2] * c[2] - c[3]; | |
wd = d[0] * d[0] + d[1] * d[1] + d[2] * d[2] - d[3]; | |
/* Use coordinates relative to point `a' of the tetrahedron. */ | |
xba = b[0] - a[0]; | |
yba = b[1] - a[1]; | |
zba = b[2] - a[2]; | |
wba = wb - wa; | |
xca = c[0] - a[0]; | |
yca = c[1] - a[1]; | |
zca = c[2] - a[2]; | |
wca = wc - wa; | |
xda = d[0] - a[0]; | |
yda = d[1] - a[1]; | |
zda = d[2] - a[2]; | |
wda = wd - wa; | |
/* Squares of lengths of the edges incident to `a'. */ | |
balength = xba * xba + yba * yba + zba * zba - wba; | |
calength = xca * xca + yca * yca + zca * zca - wca; | |
dalength = xda * xda + yda * yda + zda * zda - wda; | |
/* Cross products of these edges. */ | |
xcrosscd = yca * zda - yda * zca; | |
ycrosscd = zca * xda - zda * xca; | |
zcrosscd = xca * yda - xda * yca; | |
xcrossdb = yda * zba - yba * zda; | |
ycrossdb = zda * xba - zba * xda; | |
zcrossdb = xda * yba - xba * yda; | |
xcrossbc = yba * zca - yca * zba; | |
ycrossbc = zba * xca - zca * xba; | |
zcrossbc = xba * yca - xca * yba; | |
/* Calculate the denominator of the formulae. */ | |
#ifdef EXACT | |
/* Use orient3d() from http://www.cs.cmu.edu/~quake/robust.html */ | |
/* to ensure a correctly signed (and reasonably accurate) result, */ | |
/* avoiding any possibility of division by zero. */ | |
*cnum = orient3d(b, c, d, a); | |
denominator = 0.5 / (*cnum); | |
#else | |
/* Take your chances with floating-point roundoff. */ | |
denominator = 0.5 / (xba * xcrosscd + yba * ycrosscd + zba * zcrosscd); | |
#endif | |
/* Calculate offset (from `a') of circumcenter. */ | |
xcirca = (balength * xcrosscd + calength * xcrossdb + dalength * xcrossbc) * | |
denominator; | |
ycirca = (balength * ycrosscd + calength * ycrossdb + dalength * ycrossbc) * | |
denominator; | |
zcirca = (balength * zcrosscd + calength * zcrossdb + dalength * zcrossbc) * | |
denominator; | |
orthocenter[0] = xcirca; | |
orthocenter[1] = ycirca; | |
orthocenter[2] = zcirca; | |
} | |
void PowerCrustSurfaceReconstructionImpl::tetcircumcenter(double a[3], double b[3], double c[3], double d[3], double circumcenter[3], double *cond) | |
{ | |
double xba, yba, zba, xca, yca, zca, xda, yda, zda; | |
double balength, calength, dalength; | |
double xcrosscd, ycrosscd, zcrosscd; | |
double xcrossdb, ycrossdb, zcrossdb; | |
double xcrossbc, ycrossbc, zcrossbc; | |
double denominator; | |
double xcirca, ycirca, zcirca; | |
/* Use coordinates relative to point `a' of the tetrahedron. */ | |
xba = b[0] - a[0]; | |
yba = b[1] - a[1]; | |
zba = b[2] - a[2]; | |
xca = c[0] - a[0]; | |
yca = c[1] - a[1]; | |
zca = c[2] - a[2]; | |
xda = d[0] - a[0]; | |
yda = d[1] - a[1]; | |
zda = d[2] - a[2]; | |
/* Squares of lengths of the edges incident to `a'. */ | |
balength = xba * xba + yba * yba + zba * zba; | |
calength = xca * xca + yca * yca + zca * zca; | |
dalength = xda * xda + yda * yda + zda * zda; | |
/* Cross products of these edges. */ | |
xcrosscd = yca * zda - yda * zca; | |
ycrosscd = zca * xda - zda * xca; | |
zcrosscd = xca * yda - xda * yca; | |
xcrossdb = yda * zba - yba * zda; | |
ycrossdb = zda * xba - zba * xda; | |
zcrossdb = xda * yba - xba * yda; | |
xcrossbc = yba * zca - yca * zba; | |
ycrossbc = zba * xca - zca * xba; | |
zcrossbc = xba * yca - xca * yba; | |
/* Calculate the denominator of the formulae. */ | |
#ifdef EXACT | |
/* Use orient3d() from http://www.cs.cmu.edu/~quake/robust.html */ | |
/* to ensure a correctly signed (and reasonably accurate) result, */ | |
/* avoiding any possibility of division by zero. */ | |
*cond = orient3d(b, c, d, a); | |
denominator = 0.5 / (*cond); | |
#else | |
/* Take your chances with floating-point roundoff. */ | |
denominator = 0.5 / (xba * xcrosscd + yba * ycrosscd + zba * zcrosscd); | |
#endif | |
/* Calculate offset (from `a') of circumcenter. */ | |
xcirca = (balength * xcrosscd + calength * xcrossdb + dalength * xcrossbc) * | |
denominator; | |
ycirca = (balength * ycrosscd + calength * ycrossdb + dalength * ycrossbc) * | |
denominator; | |
zcirca = (balength * zcrosscd + calength * zcrossdb + dalength * zcrossbc) * | |
denominator; | |
circumcenter[0] = xcirca; | |
circumcenter[1] = ycirca; | |
circumcenter[2] = zcirca; | |
} | |
double PowerCrustSurfaceReconstructionImpl::sqdist(double a[3], double b[3]) | |
{ | |
/* returns the squared distance between a and b */ | |
return SQ(a[0] - b[0]) + SQ(a[1] - b[1]) + SQ(a[2] - b[2]); | |
} | |
void PowerCrustSurfaceReconstructionImpl::dir_and_dist(double a[3], double b[3], double dir[3], double* dist) | |
{ | |
int k; | |
for (k = 0; k < 3; k++) dir[k] = b[k] - a[k]; | |
*dist = sqrt(SQ(dir[0]) + SQ(dir[1]) + SQ(dir[2])); | |
for (k = 0; k<3; k++) dir[k] = dir[k] / (*dist); | |
} | |
int PowerCrustSurfaceReconstructionImpl::propagate() | |
{ | |
int pid = extract_max(); | |
if (adjlist[pid].in > adjlist[pid].out) | |
adjlist[pid].label = IN; | |
else adjlist[pid].label = OUT; | |
if (pid != -1) | |
{ | |
opp_update(pid); | |
sym_update(pid); | |
} | |
return pid; | |
} | |
void PowerCrustSurfaceReconstructionImpl::opp_update(int pi) | |
{ | |
plist *pindex; | |
pindex = opplist[pi]; | |
while (pindex != NULL) | |
{ | |
int npi = pindex->pid; | |
if (adjlist[npi].label == INIT) /* not yet labeled */ | |
{ | |
if (adjlist[npi].hid == 0) /* not in the heap */ | |
{ | |
if (adjlist[pi].in > adjlist[pi].out) | |
{ | |
/* propagate in*cos to out */ | |
adjlist[npi].out = (-1.0) * adjlist[pi].in * pindex->angle; | |
insert_heap(npi, adjlist[npi].out); | |
} | |
else if (adjlist[pi].in < adjlist[pi].out) | |
{ | |
/* propagate out*cos to in */ | |
adjlist[npi].in = (-1.0) * adjlist[pi].out * pindex->angle; | |
insert_heap(npi, adjlist[npi].in); | |
} | |
} | |
else /* in the heap */ | |
{ | |
int nhi = adjlist[npi].hid; | |
if (adjlist[pi].in > adjlist[pi].out) | |
{ | |
/* propagate in*cos to out */ | |
double temp = (-1.0) * adjlist[pi].in * pindex->angle; | |
if (temp > adjlist[npi].out) | |
{ | |
adjlist[npi].out = temp; | |
update_pri(nhi, npi); | |
} | |
} | |
else if (adjlist[pi].in < adjlist[pi].out) | |
{ | |
/* propagate out*cos to in */ | |
double temp = (-1.0) * adjlist[pi].out * pindex->angle; | |
if (temp > adjlist[npi].in) | |
{ | |
adjlist[npi].in = temp; | |
update_pri(nhi, npi); | |
} | |
} | |
} | |
} | |
pindex = pindex->next; | |
} | |
} | |
void PowerCrustSurfaceReconstructionImpl::sym_update(int pi) | |
{ | |
edgesimp *eindex; | |
eindex = adjlist[pi].eptr; | |
while (eindex != NULL) | |
{ | |
int npi = eindex->pid; | |
/* try to label deeply intersecting unlabeled neighbors */ | |
if ((adjlist[npi].label == INIT) && (eindex->angle > theta)) | |
{ | |
/* not yet labeled */ | |
if (adjlist[npi].hid == 0) /* not in the heap */ | |
{ | |
if (adjlist[pi].in > adjlist[pi].out) | |
{ | |
/* propagate in*cos to in */ | |
adjlist[npi].in = adjlist[pi].in * eindex->angle; | |
insert_heap(npi, adjlist[npi].in); | |
} | |
else if (adjlist[pi].in < adjlist[pi].out) | |
{ | |
/* propagate out*cos to out */ | |
adjlist[npi].out = adjlist[pi].out * eindex->angle; | |
insert_heap(npi, adjlist[npi].out); | |
} | |
} | |
else /* in the heap */ | |
{ | |
int nhi = adjlist[npi].hid; | |
if (adjlist[pi].in > adjlist[pi].out) | |
{ | |
/* propagate in*cos to in */ | |
double temp = adjlist[pi].in * eindex->angle; | |
if (temp > adjlist[npi].in) | |
{ | |
adjlist[npi].in = temp; | |
update_pri(nhi, npi); | |
} | |
} | |
else if (adjlist[pi].in < adjlist[pi].out) | |
{ | |
/* propagate out*cos to out */ | |
double temp = adjlist[pi].out * eindex->angle; | |
if (temp > adjlist[npi].out) | |
{ | |
adjlist[npi].out = temp; | |
update_pri(nhi, npi); | |
} | |
} | |
} | |
} | |
eindex = eindex->next; | |
} | |
} | |
void PowerCrustSurfaceReconstructionImpl::update_pri(int hi, int pi) | |
{ | |
double pr; | |
if ((heap_A[hi].pid != pi) || (adjlist[pi].hid != hi)) | |
{ | |
return; | |
} | |
if (adjlist[pi].in == 0.0) | |
{ | |
pr = adjlist[pi].out; | |
} | |
else if (adjlist[pi].out == 0.0) | |
{ | |
pr = adjlist[pi].in; | |
} | |
else /* both in/out nonzero */ | |
{ | |
if (adjlist[pi].in > adjlist[pi].out) | |
{ | |
pr = adjlist[pi].in - adjlist[pi].out - 1; | |
} | |
else | |
{ | |
pr = adjlist[pi].out - adjlist[pi].in - 1; | |
} | |
} | |
update(hi, pr); | |
} | |
void PowerCrustSurfaceReconstructionImpl::label_unlabeled(int num) | |
{ | |
plist *pindex; | |
edgesimp *eindex; | |
int opplabel; | |
for (int i = 0; i < num; i++) | |
{ | |
if (adjlist[i].label == INIT) /* pole i is unlabeled.. try to label now */ | |
{ | |
opplabel = INIT; | |
pindex = opplist[i]; | |
if ((pindex == NULL) && (adjlist[i].eptr == NULL)) | |
{ | |
continue; | |
} | |
/* check whether there is opp pole */ | |
while (pindex != NULL) /* opp pole */ | |
{ | |
int npi = pindex->pid; | |
if (adjlist[npi].label != INIT) | |
{ | |
if (opplabel == INIT) opplabel = adjlist[npi].label; | |
else if (opplabel != adjlist[npi].label) | |
{ | |
opplabel = INIT; /* ignore the label of opposite poles */ | |
} | |
} | |
pindex = pindex->next; | |
} | |
double tangle = -3.0; | |
double tangle1 = -3.0; | |
eindex = adjlist[i].eptr; | |
while (eindex != NULL) | |
{ | |
int npi = eindex->pid; | |
if (adjlist[npi].label == IN) | |
{ | |
if (tangle < eindex->angle) | |
{ | |
tangle = eindex->angle; | |
} | |
} | |
else if (adjlist[npi].label == OUT) | |
{ | |
if (tangle1 < eindex->angle) | |
{ | |
tangle1 = eindex->angle; | |
} | |
} | |
eindex = eindex->next; | |
} | |
/* now tangle, tangle 1 are angles of most deeply interesecting in, out poles */ | |
if (tangle == -3.0) /* there was no in poles */ | |
{ | |
if (tangle1 == -3.0) /* there was no out poles */ | |
{ | |
if (opplabel == INIT) /* cannot trust opp pole or no labeled opp pole */ | |
{ | |
} | |
else if (opplabel == IN) | |
{ | |
adjlist[i].label = OUT; | |
} | |
else adjlist[i].label = IN; | |
} | |
else if (tangle1 > deep) /* interesecting deeply only out poles */ | |
{ | |
adjlist[i].label = OUT; | |
} | |
else /* no deeply intersecting poles . use opp pole */ | |
{ | |
if (opplabel == INIT) /* cannot trust opp pole or no labeled opp pole */ | |
{ | |
} | |
else if (opplabel == IN) | |
{ | |
adjlist[i].label = OUT; | |
} | |
else adjlist[i].label = IN; | |
} | |
} | |
else if (tangle1 == -3.0) /* there are in pole but no out pole */ | |
{ | |
if (tangle > deep) /* interesecting deeply only in poles */ | |
{ | |
adjlist[i].label = IN; | |
} | |
else /* no deeply intersecting poles . use opp pole */ | |
{ | |
if (opplabel == INIT) /* cannot trust opp pole or no labeled opp pole */ | |
{ | |
} | |
else if (opplabel == IN) | |
{ | |
adjlist[i].label = OUT; | |
} | |
else adjlist[i].label = IN; | |
} | |
} | |
else /* there are both in/out poles */ | |
{ | |
if (tangle > deep) | |
{ | |
if (tangle1 > deep) /* intersecting both deeply */ | |
{ | |
/* use opp */ | |
if (opplabel == INIT) /* cannot trust opp pole or no labeled opp pole */ | |
{ | |
/* then give label with bigger angle */ | |
if (tangle > tangle1) | |
{ | |
adjlist[i].label = IN; | |
} | |
else adjlist[i].label = OUT; | |
} | |
else if (opplabel == IN) | |
{ | |
adjlist[i].label = OUT; | |
} | |
else adjlist[i].label = IN; | |
} | |
else /* intersecting only in deeply */ | |
{ | |
adjlist[i].label = IN; | |
} | |
} | |
else if (tangle1 > deep) /* intersecting only out deeply */ | |
{ | |
adjlist[i].label = OUT; | |
} | |
else /* no deeply intersecting poles . use opp pole */ | |
{ | |
if (opplabel == INIT) /* cannot trust opp pole or no labeled opp pole */ | |
{ | |
} | |
else if (opplabel == IN) | |
{ | |
adjlist[i].label = OUT; | |
} | |
else adjlist[i].label = IN; | |
} | |
} | |
} | |
} | |
} | |
neighbor * PowerCrustSurfaceReconstructionImpl::op_simp(simplex *a, simplex *b) | |
{ | |
lookup(a, b, simp) | |
} | |
neighbor * PowerCrustSurfaceReconstructionImpl::op_vert(simplex *a, site b) | |
{ | |
lookup(a, b, vert) | |
} | |
void PowerCrustSurfaceReconstructionImpl::connect(simplex *s) | |
{ | |
/* make neighbor connections between newly created simplices incident to p */ | |
site xf, xb, xfi; | |
simplex *sb, *sf, *seen; | |
int i; | |
neighbor *sn; | |
if (!s) | |
{ | |
return; | |
} | |
assert(!s->peak.vert && s->peak.simp->peak.vert == p && !op_vert(s, p)->simp->peak.vert); | |
if (s->visit == pnum) | |
{ | |
return; | |
} | |
s->visit = pnum; | |
seen = s->peak.simp; | |
xfi = op_simp(seen, s)->vert; | |
for (i = 0, sn = s->neigh; i < cdim; i++, sn++) | |
{ | |
xb = sn->vert; | |
if (p == xb) | |
{ | |
continue; | |
} | |
sb = seen; | |
sf = sn->simp; | |
xf = xfi; | |
if (!sf->peak.vert) /* are we done already? */ | |
{ | |
sf = op_vert(seen, xb)->simp; | |
if (sf->peak.vert) | |
{ | |
continue; | |
} | |
} | |
else | |
{ | |
int LoopCounter = 0; | |
do | |
{ | |
if (LoopCounter == 100) | |
{ | |
ASSERT(pcFALSE, "new adjacency failure!"); | |
} | |
xb = xf; | |
xf = op_simp(sf, sb)->vert; | |
sb = sf; | |
sf = op_vert(sb, xb)->simp; | |
LoopCounter++; | |
} while (sf->peak.vert); | |
} | |
sn->simp = sf; | |
op_vert(sf, xf)->simp = s; | |
connect(sf); | |
} | |
} | |
simplex * PowerCrustSurfaceReconstructionImpl::make_facets(simplex *seen) | |
{ | |
/* visit simplices s with sees(p,s), and make a facet for every neighbor | |
* of s not seen by p */ | |
simplex *n; | |
neighbor *bn; | |
int i; | |
if (!seen) return NULL; | |
seen->peak.vert = p; | |
for (i = 0, bn = seen->neigh; i < cdim; i++, bn++) | |
{ | |
n = bn->simp; | |
if (pnum != n->visit) | |
{ | |
n->visit = pnum; | |
if (sees(p, n)) make_facets(n); | |
} | |
if (n->peak.vert) continue; | |
copy_simp(make_facets_ns, seen); | |
make_facets_ns->visit = 0; | |
make_facets_ns->peak.vert = 0; | |
make_facets_ns->normal = 0; | |
make_facets_ns->peak.simp = seen; | |
/* ns->Sb -= ns->neigh[i].basis->sqb; */ | |
NULLIFY(basis_s, make_facets_ns->neigh[i].basis); | |
make_facets_ns->neigh[i].vert = p; | |
bn->simp = op_simp(n, seen)->simp = make_facets_ns; | |
} | |
return make_facets_ns; | |
} | |
simplex * PowerCrustSurfaceReconstructionImpl::extend_simplices(simplex *s) | |
{ | |
/* p lies outside flat containing previous sites; | |
* make p a vertex of every current simplex, and create some new simplices */ | |
int i; | |
int ocdim = cdim - 1; | |
simplex *ns; | |
neighbor *nsn; | |
if (s->visit == pnum) return s->peak.vert ? s->neigh[ocdim].simp : s; | |
s->visit = pnum; | |
s->neigh[ocdim].vert = p; | |
NULLIFY(basis_s, s->normal); | |
NULLIFY(basis_s, s->neigh[0].basis); | |
if (!s->peak.vert) | |
{ | |
s->neigh[ocdim].simp = extend_simplices(s->peak.simp); | |
return s; | |
} | |
else | |
{ | |
copy_simp(ns, s); | |
s->neigh[ocdim].simp = ns; | |
ns->peak.vert = NULL; | |
ns->peak.simp = s; | |
ns->neigh[ocdim] = s->peak; | |
inc_ref(basis_s, s->peak.basis); | |
for (i = 0, nsn = ns->neigh; i < cdim; i++, nsn++) | |
nsn->simp = extend_simplices(nsn->simp); | |
} | |
return ns; | |
} | |
simplex * PowerCrustSurfaceReconstructionImpl::search(simplex *root) | |
{ | |
/* return a simplex s that corresponds to a facet of the | |
* current hull, and sees(p, s) */ | |
simplex *s; | |
neighbor *sn; | |
int i; | |
long tms = 0; | |
if (!st_search) | |
{ | |
st_search = (simplex **)malloc((search_ss + MAXDIM + 1) *sizeof(simplex*)); | |
} | |
push(root->peak.simp, st_search, tms); | |
root->visit = pnum; | |
if (!sees(p, root)) | |
for (i = 0, sn = root->neigh; i < cdim; i++, sn++) | |
push(sn->simp, st_search, tms); | |
while (tms) | |
{ | |
if (tms > search_ss) | |
{ | |
st_search = (simplex**)realloc(st_search, ((search_ss += search_ss) + MAXDIM + 1) *sizeof(simplex*)); | |
assert(st_search); | |
} | |
pop(s, st_search, tms); | |
if (s->visit == pnum) | |
continue; | |
s->visit = pnum; | |
if (!sees(p, s)) | |
continue; | |
if (!s->peak.vert) | |
{ | |
return s; | |
} | |
for (i = 0, sn = s->neigh; i < cdim; i++, sn++) | |
push(sn->simp, st_search, tms); | |
} | |
return NULL; | |
} | |
point PowerCrustSurfaceReconstructionImpl::get_another_site(void) | |
{ | |
point pnext; | |
if (!(++scount % 1000)) | |
{ | |
} | |
pnext = (this->*get_site) (); | |
if (!pnext) | |
{ | |
return NULL; | |
} | |
pnum = (this->*site_num) (pnext)+2; | |
return pnext; | |
} | |
void PowerCrustSurfaceReconstructionImpl::buildhull(simplex *root) | |
{ | |
while (cdim < rdim) | |
{ | |
p = get_another_site(); | |
if (!p) | |
{ | |
return; | |
} | |
if (out_of_flat(root, p)) | |
{ | |
extend_simplices(root); | |
} | |
else | |
{ | |
connect(make_facets(search(root))); | |
} | |
} | |
while ((p = get_another_site()) != NULL) | |
{ | |
connect(make_facets(search(root))); | |
} | |
} | |
int PowerCrustSurfaceReconstructionImpl::reduce(basis_s **v, point p, simplex *s, int k) | |
{ | |
point z; | |
point tt = s->neigh[0].vert; | |
if (!*v) NEWLRC(basis_s, (*v)) | |
else (*v)->lscale = 0; | |
z = VB(*v); | |
if (vd || power_diagram) | |
{ | |
if (p == infinity) memcpy(*v, infinity_basis, basis_s_size); | |
else | |
{ | |
trans(z, p, tt); | |
lift(z, s); | |
} | |
} | |
else trans(z, p, tt); | |
return reduce_inner(*v, s, k); | |
} | |
void PowerCrustSurfaceReconstructionImpl::get_basis_sede(simplex *s) | |
{ | |
int k = 1; | |
neighbor *sn = s->neigh + 1, | |
*sn0 = s->neigh; | |
if ((vd || power_diagram) && sn0->vert == infinity && cdim > 1) | |
{ | |
SWAP(neighbor, *sn0, *sn); | |
NULLIFY(basis_s, sn0->basis); | |
sn0->basis = tt_basisp; | |
tt_basisp->ref_count++; | |
} | |
else | |
{ | |
if (!sn0->basis) | |
{ | |
sn0->basis = tt_basisp; | |
tt_basisp->ref_count++; | |
} | |
else while (k < cdim && sn->basis) | |
{ | |
k++; | |
sn++; | |
} | |
} | |
while (k < cdim) | |
{ | |
NULLIFY(basis_s, sn->basis); | |
reduce(&sn->basis, sn->vert, s, k); | |
k++; | |
sn++; | |
} | |
} | |
int PowerCrustSurfaceReconstructionImpl::out_of_flat(simplex *root, point p) | |
{ | |
if (!p_neigh.basis) | |
p_neigh.basis = (basis_s*)malloc(basis_s_size); | |
p_neigh.vert = p; | |
cdim++; | |
root->neigh[cdim - 1].vert = root->peak.vert; | |
NULLIFY(basis_s, root->neigh[cdim - 1].basis); | |
get_basis_sede(root); | |
if ((vd || power_diagram) && root->neigh[0].vert == infinity) return 1; | |
reduce(&p_neigh.basis, p, root, cdim); | |
if (p_neigh.basis->sqa != 0) return 1; | |
cdim--; | |
return 0; | |
} | |
double PowerCrustSurfaceReconstructionImpl::cosangle_sq(basis_s* v, basis_s* w) | |
{ | |
double dd; | |
point vv = v->vecs, wv = w->vecs; | |
dd = Vec_dot(vv, wv); | |
return dd*dd / Norm2(vv) / Norm2(wv); | |
} | |
int PowerCrustSurfaceReconstructionImpl::check_perps(simplex *s) | |
{ | |
point z, y; | |
point tt; | |
for (int i = 1; i < cdim; i++) if (NEARZERO(s->neigh[i].basis->sqb)) return 0; | |
if (!check_perps_b) | |
{ | |
check_perps_b = (basis_s*)malloc(basis_s_size); | |
assert(check_perps_b); | |
} | |
else check_perps_b->lscale = 0; | |
z = VB(check_perps_b); | |
tt = s->neigh[0].vert; | |
for (int i = 1; i < cdim; i++) | |
{ | |
y = s->neigh[i].vert; | |
if ((vd || power_diagram) && y == infinity) memcpy(check_perps_b, infinity_basis, basis_s_size); | |
else | |
{ | |
trans(z, y, tt); | |
lift(z, s); | |
} | |
if (s->normal && cosangle_sq(check_perps_b, s->normal) > b_err_min_sq) | |
{ | |
return 0; | |
} | |
for (int j = i + 1; j < cdim; j++) | |
{ | |
if (cosangle_sq(check_perps_b, s->neigh[j].basis) > b_err_min_sq) | |
{ | |
return 0; | |
} | |
} | |
} | |
return 1; | |
} | |
void PowerCrustSurfaceReconstructionImpl::get_normal_sede(simplex *s) | |
{ | |
neighbor *rn; | |
int i, j; | |
get_basis_sede(s); | |
if (rdim == 3 && cdim == 3) | |
{ | |
point c; | |
point a = VB(s->neigh[1].basis); | |
point b = VB(s->neigh[2].basis); | |
NEWLRC(basis_s, s->normal); | |
c = VB(s->normal); | |
c[0] = a[1] * b[2] - a[2] * b[1]; | |
c[1] = a[2] * b[0] - a[0] * b[2]; | |
c[2] = a[0] * b[1] - a[1] * b[0]; | |
s->normal->sqb = Norm2(c); | |
for (i = cdim + 1, rn = ch_root->neigh + cdim - 1; i; i--, rn--) | |
{ | |
for (j = 0; j < cdim && rn->vert != s->neigh[j].vert; j++); | |
if (j < cdim) continue; | |
if (rn->vert == infinity) | |
{ | |
if (c[2] > -b_err_min) continue; | |
} | |
else if (!sees(rn->vert, s)) continue; | |
c[0] = -c[0]; | |
c[1] = -c[1]; | |
c[2] = -c[2]; | |
break; | |
} | |
return; | |
} | |
for (i = cdim + 1, rn = ch_root->neigh + cdim - 1; i; i--, rn--) | |
{ | |
for (j = 0; j < cdim && rn->vert != s->neigh[j].vert; j++); | |
if (j < cdim) continue; | |
reduce(&s->normal, rn->vert, s, cdim); | |
if (s->normal->sqb != 0) break; | |
} | |
} | |
void PowerCrustSurfaceReconstructionImpl::get_normal(simplex *s) | |
{ | |
get_normal_sede(s); | |
return; | |
} | |
int PowerCrustSurfaceReconstructionImpl::sees(site p, simplex *s) | |
{ | |
point tt, zz; | |
double dd, dds; | |
int i; | |
if (!seesB) | |
{ | |
seesB = (basis_s*)malloc(basis_s_size); | |
assert(seesB); | |
} | |
else | |
seesB->lscale = 0; | |
zz = VB(seesB); | |
if (cdim == 0) | |
return 0; | |
if (!s->normal) | |
{ | |
get_normal_sede(s); | |
for (i = 0; i < cdim; i++) | |
NULLIFY(basis_s, s->neigh[i].basis); | |
} | |
tt = s->neigh[0].vert; | |
if (vd || power_diagram) | |
{ | |
if (p == infinity) | |
memcpy(seesB, infinity_basis, basis_s_size); | |
else | |
{ | |
trans(zz, p, tt); | |
lift(zz, s); | |
} | |
} | |
else | |
trans(zz, p, tt); | |
for (i = 0; i < 3; i++) | |
{ | |
dd = Vec_dot(zz, s->normal->vecs); | |
if (dd == 0.0) | |
{ | |
return 0; | |
} | |
dds = dd*dd / s->normal->sqb / Norm2(zz); | |
if (dds > b_err_min_sq) | |
return (dd < 0); | |
get_basis_sede(s); | |
reduce_inner(seesB, s, cdim); | |
} | |
return 0; | |
} | |
double PowerCrustSurfaceReconstructionImpl::radsq(simplex *s) | |
{ | |
point n; | |
neighbor *sn; | |
int i; | |
/* square of ratio of circumcircle radius to max edge length for Delaunay tetrahedra */ | |
for (i = 0, sn = s->neigh; i < cdim; i++, sn++) | |
if (sn->vert == infinity) return Huge; | |
if (!s->normal) get_normal_sede(s); | |
/* compute circumradius */ | |
n = s->normal->vecs; | |
if (NEARZERO(n[rdim - 1])) | |
{ | |
return Huge; | |
} | |
return Vec_dot_pdim(n, n) / 4 / n[rdim - 1] / n[rdim - 1]; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::zero_marks(simplex * s, void *) | |
{ | |
s->mark = 0; | |
return NULL; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::one_marks(simplex * s, void *) | |
{ | |
s->mark = 1; | |
return NULL; | |
} | |
int PowerCrustSurfaceReconstructionImpl::alph_test(simplex *s, int i, void *alphap) | |
{ | |
/*returns 1 if not an alpha-facet */ | |
simplex *si; | |
neighbor *scn, *sin; | |
int k; | |
if (alphap) | |
{ | |
alpha_test_alpha = *(double*)alphap; | |
if (!s) return 1; | |
} | |
if (i == -1) return 0; | |
si = s->neigh[i].simp; | |
scn = s->neigh + cdim - 1; | |
sin = s->neigh + i; | |
int nsees = 0; | |
for (k = 0; k < cdim; k++) if (s->neigh[k].vert == infinity && k != i) return 1; | |
double rs = radsq(s); | |
double rsi = radsq(si); | |
if (rs < alpha_test_alpha && rsi < alpha_test_alpha) return 1; | |
swap_points(scn->vert, sin->vert); | |
NULLIFY(basis_s, s->neigh[i].basis); | |
cdim--; | |
get_basis_sede(s); | |
reduce(&s->normal, infinity, s, cdim); | |
double rsfi = radsq(s); | |
for (k = 0; k < cdim; k++) if (si->neigh[k].simp == s) break; | |
int ssees = sees(scn->vert, s); | |
if (!ssees) nsees = sees(si->neigh[k].vert, s); | |
swap_points(scn->vert, sin->vert); | |
cdim++; | |
NULLIFY(basis_s, s->normal); | |
NULLIFY(basis_s, s->neigh[i].basis); | |
if (ssees) return alpha_test_alpha < rs; | |
if (nsees) return alpha_test_alpha < rsi; | |
assert(rsfi <= rs + FLT_EPSILON && rsfi <= rsi + FLT_EPSILON); | |
return alpha_test_alpha <= rsfi; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::conv_facetv(simplex *s, void *) | |
{ | |
for (int i = 0; i < cdim; i++) | |
if (s->neigh[i].vert == infinity) | |
{ | |
return s; | |
} | |
return NULL; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::mark_points(simplex *s, void *) | |
{ | |
int i, snum; | |
neighbor *sn; | |
for (i = 0, sn = s->neigh; i < cdim; i++, sn++) | |
{ | |
if (sn->vert == infinity) continue; | |
snum = (this->*site_num) (sn->vert); | |
if (s->mark) mo[snum] = 1; | |
else mi[snum] = 1; | |
} | |
return NULL; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::visit_outside_ashape(simplex *root, visit_func visit) | |
{ | |
return visit_triang_gen((simplex*)visit_hull(root, &PowerCrustSurfaceReconstructionImpl::conv_facetv), visit, &PowerCrustSurfaceReconstructionImpl::alph_test); | |
} | |
int PowerCrustSurfaceReconstructionImpl::check_ashape(simplex *root, double alpha) | |
{ | |
for (int i = 0; i < MAXPOINTS; i++) | |
{ | |
mi[i] = mo[i] = 0; | |
} | |
visit_hull(root, &PowerCrustSurfaceReconstructionImpl::zero_marks); | |
alph_test(0, 0, &alpha); | |
visit_outside_ashape(root, &PowerCrustSurfaceReconstructionImpl::one_marks); | |
visit_hull(root, &PowerCrustSurfaceReconstructionImpl::mark_points); | |
for (int i = 0; i < MAXPOINTS; i++) if (mo[i] && !mi[i]) | |
{ | |
return 0; | |
} | |
return 1; | |
} | |
simplex * PowerCrustSurfaceReconstructionImpl::build_convex_hull(short dim, short vdd) | |
{ | |
/* | |
get_s returns next site each call; | |
hull construction stops when NULL returned; | |
site_numm returns number of site when given site; | |
dim dimension of point set; | |
vdd if (vdd) then return Delaunay triangulation | |
*/ | |
simplex *s, *root; | |
cdim = 0; | |
get_site = &PowerCrustSurfaceReconstructionImpl::get_next_site; | |
site_num = &PowerCrustSurfaceReconstructionImpl::site_numm; | |
pdim = dim; | |
vd = vdd; | |
exact_bits = (int)(DBL_MANT_DIG*log(FLT_RADIX) / log(2.0)); // cast to int added by TJH // EPRO added | |
b_err_min = DBL_EPSILON*MAXDIM* (1 << MAXDIM) * MAXDIM * 3.01; | |
b_err_min_sq = b_err_min * b_err_min; | |
assert(get_site != NULL); | |
assert(site_num != NULL); | |
rdim = vd ? pdim + 1 : pdim; | |
if (rdim > MAXDIM) | |
ASSERT(pcFALSE, "dimension bound MAXDIM exceeded"); | |
site_size = sizeof(Coord) *pdim; | |
basis_vec_size = sizeof(Coord) *rdim; | |
basis_s_size = sizeof(basis_s) + (2 * rdim - 1) *sizeof(Coord); | |
simplex_size = sizeof(simplex) + (rdim - 1) *sizeof(neighbor); | |
Tree_size = sizeof(Tree); | |
fg_size = sizeof(fg); | |
root = NULL; | |
if (vd || power_diagram) | |
{ | |
p = infinity; | |
NEWLRC(basis_s, infinity_basis); | |
infinity_basis->vecs[2 * rdim - 1] = infinity_basis->vecs[rdim - 1] = 1; | |
infinity_basis->sqa = infinity_basis->sqb = 1; | |
} | |
else if (!(p = (this->*get_site) ())) return 0; | |
NEWL(simplex, root); | |
ch_root = root; | |
copy_simp(s, root); | |
root->peak.vert = p; | |
root->peak.simp = s; | |
s->peak.simp = root; | |
buildhull(root); | |
return root; | |
} | |
void PowerCrustSurfaceReconstructionImpl::free_hull_storage(void) | |
{ | |
free_basis_s_storage(); | |
free_simplex_storage(); | |
free_Tree_storage(); | |
free_fg_storage(); | |
} | |
void * PowerCrustSurfaceReconstructionImpl::compute_vv(simplex *s, void *) | |
{ | |
/* computes Voronoi vertices */ | |
point v[MAXDIM]; | |
int inf = 0; | |
double cc[3], cond, ta[4][3]; | |
if (!s) return NULL; | |
for (int j = 0; j < cdim; j++) | |
{ | |
v[j] = s->neigh[j].vert; | |
/* v[j] stores coordinates of j'th vertex of simplex s; j=0..3 */ | |
if (v[j] == infinity) /* means simplex s is on the convex hull */ | |
{ | |
inf = 1; | |
break; /* skip the rest of the for loop, ignore convex hull faces (= bounding box ) */ | |
} | |
for (int k = 0; k < cdim - 1; k++) | |
{ | |
ta[j][k] = v[j][k] / mult_up; /* restore original coords */ | |
} | |
} | |
if (!inf) /* if not faces on convex hull, compute circumcenter*/ | |
{ | |
tetcircumcenter(ta[0], ta[1], ta[2], ta[3], cc, &cond); | |
if (cond != 0) /* ignore them if cond = 0 */ | |
{ | |
s->isVvNull = false; | |
for (int k = 0; k < cdim - 1; k++) | |
{ | |
s->vv[k] = ta[0][k] + cc[k]; | |
} | |
s->status = VV; | |
} | |
else | |
{ | |
s->isVvNull = true; | |
s->status = SLV; | |
} | |
} | |
else /* if on conv hull */ | |
{ | |
s->status = CNV; | |
} | |
/* computing poles */ | |
for (int j = 0; j < cdim; j++) /* compute 1st pole for vertex j */ | |
{ | |
int i = (this->*site_num) (s->neigh[j].vert); | |
if (i == -1) continue; | |
/* Ignore poles that are too far away to matter - a relic of the | |
original California-style crust. Probably no longer needed */ | |
if ((s->neigh[j].vert[0] > omaxs[0]) || | |
(s->neigh[j].vert[0] < omins[0]) || | |
(s->neigh[j].vert[1] > omaxs[1]) || | |
(s->neigh[j].vert[1] < omins[1]) || | |
(s->neigh[j].vert[2] > omaxs[2]) || | |
(s->neigh[j].vert[2] < omins[2])) | |
{ | |
pole1[i] = NULL; | |
continue; | |
} | |
else | |
{ | |
if (pole1[i] == NULL) | |
{ | |
/* the vertex i is encountered for the 1st time */ | |
if (s->status == VV) /* we don't store infinite poles */ | |
{ | |
pole1[i] = s; | |
continue; | |
} | |
} | |
if ((s->status == VV) && (pole1[i]->status == VV)) | |
{ | |
if (sqdist(pole1[i]->vv, ta[j]) < sqdist(s->vv, ta[j])) | |
{ | |
pole1[i] = s; /* update 1st pole */ | |
} | |
} | |
} | |
} | |
return NULL; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::compute_pole2(simplex *s, void *p) | |
{ | |
point v[MAXDIM]; | |
int inf = 0; | |
double a[3] = { 0, 0, 0 }; | |
site t; | |
double dir_s[3], dir_p[3], dist_s, dist_p; | |
if (p) | |
{ | |
if (!s) return NULL; | |
} | |
for (int j = 0; j < cdim; j++) | |
{ | |
v[j] = s->neigh[j].vert; | |
int i = (this->*site_num) (v[j]); | |
if (i == -1) inf = 1; | |
} | |
double cos_2r = cos(2 * est_r); | |
for (int j = 0; j < cdim; j++) /* compute 2nd poles */ | |
{ | |
t = s->neigh[j].vert; | |
int i = (this->*site_num) (t); | |
if (i < 0) continue; /* not a vertex */ | |
if (inf) /* on conv hull */ | |
{ | |
if (s->status == CNV) | |
{ | |
continue; | |
} | |
} | |
if (!pole1[i]) | |
{ | |
continue; | |
} | |
if (pole1[i]->isVvNull) //pole1[i]->vv==NULL | |
{ | |
continue; | |
} | |
if (s->isVvNull) //!s->vv | |
{ | |
if (s->status != SLV) | |
continue; | |
} | |
for (int k = 0; k < cdim - 1; k++) /* a stores orig vertex coord */ | |
{ | |
a[k] = t[k] / mult_up; | |
} | |
/* compute direction and length of vector from sample to first pole */ | |
dir_and_dist(a, pole1[i]->vv, dir_p, &dist_p); | |
/* We have a vertex, and there is a good first pole. */ | |
if ((s->status == VV) && (pole1[i]->status == VV)) | |
{ | |
/* make direction vector from sample to this Voronoi vertex */ | |
dir_and_dist(a, s->vv, dir_s, &dist_s); | |
/* cosine of angle between angle to vertex and angle to pole */ | |
double cos_sp = dir_s[0] * dir_p[0] + dir_s[1] * dir_p[1] + dir_s[2] * dir_p[2]; | |
/* if there is an estimate for r, use it to estimate lfs */ | |
if (est_r < 1.0) | |
{ | |
/* near vertices - should be close to sample (a) */ | |
if ((cos_sp < cos_2r) && (cos_sp > -cos_2r)) | |
{ | |
/* use to get lower bound on lfs */ | |
double est_lfs = dist_s / est_r * ((sqrt(1 - cos_sp*cos_sp)) - est_r); | |
if (est_lfs > lfs_lb[i]) lfs_lb[i] = est_lfs; | |
} | |
} | |
else | |
{ | |
lfs_lb[i] = 0; | |
} | |
if (cos_sp > 0) | |
{ | |
/* s->vv is in the same side of pole1 */ | |
continue; | |
} | |
/* s->vv is a candidate for pole2 */ | |
if (!pole2[i]) | |
{ | |
/* 1st pole2 candidate for vertex i */ | |
pole2[i] = s; | |
continue; | |
} | |
else if (!pole2[i]->vv) /* 2nd pole points null */ | |
{ | |
continue; | |
} | |
else if ((pole2[i]->status == VV) && (sqdist(a, pole2[i]->vv) < sqdist(a, s->vv))) | |
pole2[i] = s; /* update 2nd pole */ | |
} | |
} | |
return NULL; | |
} | |
int PowerCrustSurfaceReconstructionImpl::close_pole(double* v, double* p, double lfs_lb) | |
{ | |
return (sqdist(v, p) < lfs_lb * lfs_lb); | |
} | |
int PowerCrustSurfaceReconstructionImpl::antiLabel(int label) | |
{ | |
if (label == IN) return (OUT); | |
if (label == OUT) return (IN); | |
return (label); | |
} | |
double PowerCrustSurfaceReconstructionImpl::computePoleAngle(simplex* pole1, simplex* pole2, double* samp) | |
{ | |
return (((pole1->vv[0] - samp[0]) * (pole2->vv[0] - samp[0]) + | |
(pole1->vv[1] - samp[1]) * (pole2->vv[1] - samp[1]) + | |
(pole1->vv[2] - samp[2]) * (pole2->vv[2] - samp[2])) / | |
(sqrt(SQ(pole1->vv[0] - samp[0]) + SQ(pole1->vv[1] - samp[1]) + SQ(pole1->vv[2] - samp[2])) * | |
sqrt(SQ(pole2->vv[0] - samp[0]) + SQ(pole2->vv[1] - samp[1]) + SQ(pole2->vv[2] - samp[2])))); | |
} | |
void PowerCrustSurfaceReconstructionImpl::newOpposite(int p1index, int p2index, double pole_angle) | |
{ | |
plist* newplist; | |
newplist = (plist *)malloc(sizeof(plist)); | |
newplist->pid = p2index; | |
newplist->angle = pole_angle; | |
newplist->next = opplist[p1index]; | |
opplist[p1index] = newplist; | |
if (adjlist[p1index].oppradius > adjlist[p2index].sqradius) | |
{ | |
assert(adjlist[p2index].sqradius > 0.0); | |
adjlist[p1index].oppradius = adjlist[p2index].sqradius; | |
} | |
} | |
void PowerCrustSurfaceReconstructionImpl::outputPole(simplex* pole, int poleid, double* samp, int* num_poles, double distance) | |
{ | |
double r2 = SQ(pole->vv[0] - samp[0]) + SQ(pole->vv[1] - samp[1]) + SQ(pole->vv[2] - samp[2]); | |
double weight = SQ(pole->vv[0]) + SQ(pole->vv[1]) + SQ(pole->vv[2]) - r2; | |
pole->status = POLE_OUTPUT; | |
pole->poleindex = poleid; | |
medial_surface.InsertNextPoint(pole->vv[0], pole->vv[1], pole->vv[2]); | |
medial_surface.InsertWeight(weight); | |
/* remember squared radius */ | |
adjlist[poleid].sqradius = r2; | |
adjlist[poleid].samp_distance = distance; | |
/* initialize perp dist to MA */ | |
adjlist[poleid].oppradius = r2; | |
/* initialize */ | |
adjlist[poleid].grafindex = -1; | |
/* keep count! */ | |
(*num_poles)++; | |
} | |
Tree * PowerCrustSurfaceReconstructionImpl::splay(site i, Tree *t) | |
{ | |
Tree N, *l, *r, *y; | |
if (!t) return t; | |
N.left = N.right = NULL; | |
l = r = &N; | |
int l_size = 0; | |
int r_size = 0; | |
for (;;) | |
{ | |
int comp = compare(i, t->key); | |
if (comp < 0) | |
{ | |
if (!t->left) break; | |
if (compare(i, t->left->key) < 0) | |
{ | |
y = t->left; /* rotate right */ | |
t->left = y->right; | |
y->right = t; | |
t->size = node_size(t->left) + node_size(t->right) + 1; | |
t = y; | |
if (!t->left) break; | |
} | |
r->left = t; /* link right */ | |
r = t; | |
t = t->left; | |
r_size += 1 + node_size(r->right); | |
} | |
else if (comp > 0) | |
{ | |
if (!t->right) break; | |
if (compare(i, t->right->key) > 0) | |
{ | |
y = t->right; /* rotate left */ | |
t->right = y->left; | |
y->left = t; | |
t->size = node_size(t->left) + node_size(t->right) + 1; | |
t = y; | |
if (!t->right) break; | |
} | |
l->right = t; /* link left */ | |
l = t; | |
t = t->right; | |
l_size += 1 + node_size(l->left); | |
} | |
else break; | |
} | |
l_size += node_size(t->left); /* Now l_size and r_size are the sizes of */ | |
r_size += node_size(t->right); /* the left and right trees we just built.*/ | |
t->size = l_size + r_size + 1; | |
l->right = r->left = NULL; | |
/* The following two loops correct the size fields of the right path */ | |
/* from the left child of the root and the right path from the left */ | |
/* child of the root. */ | |
for (y = N.right; y != NULL; y = y->right) | |
{ | |
y->size = l_size; | |
l_size -= 1 + node_size(y->left); | |
} | |
for (y = N.left; y != NULL; y = y->left) | |
{ | |
y->size = r_size; | |
r_size -= 1 + node_size(y->right); | |
} | |
l->right = t->left; /* assemble */ | |
r->left = t->right; | |
t->left = N.right; | |
t->right = N.left; | |
return t; | |
} | |
Tree * PowerCrustSurfaceReconstructionImpl::insert(site i, Tree * t) | |
{ | |
/* Insert key i into the tree t, if it is not already there. */ | |
/* Return a pointer to the resulting tree. */ | |
Tree *new_tree; | |
if (t != NULL) | |
{ | |
t = splay(i, t); | |
if (compare(i, t->key) == 0) | |
{ | |
return t; /* it's already there */ | |
} | |
} | |
NEWL(Tree, new_tree) | |
if (!t) | |
{ | |
new_tree->left = new_tree->right = NULL; | |
} | |
else if (compare(i, t->key) < 0) | |
{ | |
new_tree->left = t->left; | |
new_tree->right = t; | |
t->left = NULL; | |
t->size = 1 + node_size(t->right); | |
} | |
else | |
{ | |
new_tree->right = t->right; | |
new_tree->left = t; | |
t->right = NULL; | |
t->size = 1 + node_size(t->left); | |
} | |
new_tree->key = i; | |
new_tree->size = 1 + node_size(new_tree->left) + node_size(new_tree->right); | |
return new_tree; | |
} | |
void PowerCrustSurfaceReconstructionImpl::free_heap() | |
{ | |
free(heap_A); | |
} | |
void PowerCrustSurfaceReconstructionImpl::init_heap(int num) | |
{ | |
heap_A = (heap_array *)calloc(num + 1, sizeof(heap_array)); // EPRO added | |
heap_size = 0; | |
heap_length = num; | |
} | |
void PowerCrustSurfaceReconstructionImpl::heapify(int hi) | |
{ | |
int largest; | |
if ((LEFT(hi) <= heap_size) && (heap_A[LEFT(hi)].pri > heap_A[hi].pri)) | |
largest = LEFT(hi); | |
else largest = hi; | |
if ((RIGHT(hi) <= heap_size) && (heap_A[RIGHT(hi)].pri > heap_A[largest].pri)) | |
largest = RIGHT(hi); | |
if (largest != hi) | |
{ | |
int temp = heap_A[hi].pid; | |
heap_A[hi].pid = heap_A[largest].pid; | |
adjlist[heap_A[hi].pid].hid = hi; | |
heap_A[largest].pid = temp; | |
adjlist[heap_A[largest].pid].hid = largest; | |
double td = heap_A[hi].pri; | |
heap_A[hi].pri = heap_A[largest].pri; | |
heap_A[largest].pri = td; | |
heapify(largest); | |
} | |
} | |
int PowerCrustSurfaceReconstructionImpl::extract_max() | |
{ | |
if (heap_size < 1) return -1; | |
int max = heap_A[1].pid; | |
heap_A[1].pid = heap_A[heap_size].pid; | |
heap_A[1].pri = heap_A[heap_size].pri; | |
adjlist[heap_A[1].pid].hid = 1; | |
heap_size--; | |
heapify(1); | |
return max; | |
} | |
int PowerCrustSurfaceReconstructionImpl::insert_heap(int pi, double pr) | |
{ | |
heap_size++; | |
int i = heap_size; | |
while ((i > 1) && (heap_A[PARENT(i)].pri < pr)) | |
{ | |
heap_A[i].pid = heap_A[PARENT(i)].pid; | |
heap_A[i].pri = heap_A[PARENT(i)].pri; | |
adjlist[heap_A[i].pid].hid = i; | |
i = PARENT(i); | |
}; | |
heap_A[i].pri = pr; | |
heap_A[i].pid = pi; | |
adjlist[pi].hid = i; | |
return i; | |
} | |
void PowerCrustSurfaceReconstructionImpl::update(int hi, double pr) | |
{ | |
heap_A[hi].pri = pr; | |
int pi = heap_A[hi].pid; | |
if (pr > heap_A[PARENT(hi)].pri) | |
{ | |
int i = hi; | |
while ((i > 1) && (heap_A[PARENT(i)].pri < pr)) | |
{ | |
heap_A[i].pid = heap_A[PARENT(i)].pid; | |
heap_A[i].pri = heap_A[PARENT(i)].pri; | |
adjlist[heap_A[i].pid].hid = i; | |
i = PARENT(i); | |
}; | |
heap_A[i].pri = pr; | |
heap_A[i].pid = pi; | |
adjlist[pi].hid = i; | |
} | |
else heapify(hi); | |
} | |
void * PowerCrustSurfaceReconstructionImpl::visit_triang_gen(simplex *s, visit_func visit, test_func test) | |
{ | |
/* starting at s, visit simplices t such that test(s,i,0) is true, | |
* and t is the i'th neighbor of s; | |
* apply visit function to all visited simplices; | |
* when visit returns nonNULL, exit and return its value */ | |
neighbor *sn; | |
void *v; | |
simplex *t; | |
int i; | |
long tms = 0; | |
visit_triang_gen_vnum--; | |
if (!st_visit_triang_gen) | |
{ | |
st_visit_triang_gen = (simplex**)malloc((visit_triang_gen_ss + MAXDIM + 1) * sizeof(simplex*)); | |
assert(st_visit_triang_gen); | |
} | |
if (s) push(s, st_visit_triang_gen, tms); | |
while (tms) | |
{ | |
if (tms > visit_triang_gen_ss) | |
{ | |
st_visit_triang_gen = (simplex**)realloc(st_visit_triang_gen, ((visit_triang_gen_ss += visit_triang_gen_ss) + MAXDIM + 1) * sizeof(simplex*)); | |
assert(st_visit_triang_gen); | |
} | |
pop(t, st_visit_triang_gen, tms); | |
if (!t || t->visit == visit_triang_gen_vnum) continue; | |
t->visit = visit_triang_gen_vnum; | |
if ((v = (this->*visit) (t, 0)) != NULL) | |
{ | |
return v; | |
} | |
for (i = -1, sn = t->neigh - 1; i < cdim; i++, sn++) | |
if ((sn->simp->visit != visit_triang_gen_vnum) && sn->simp && (this->*test) (t, i, 0)) | |
push(sn->simp, st_visit_triang_gen, tms); | |
} | |
return NULL; | |
} | |
int PowerCrustSurfaceReconstructionImpl::truet(simplex *, int , void *) | |
{ | |
return 1; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::visit_triang(simplex *root, visit_func visit) | |
{ | |
return visit_triang_gen(root, visit, &PowerCrustSurfaceReconstructionImpl::truet); | |
} | |
int PowerCrustSurfaceReconstructionImpl::hullt(simplex *, int i, void *) | |
{ | |
return i > -1; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::facet_test(simplex *s, void *) | |
{ | |
return (!s->peak.vert) ? s : NULL; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::visit_hull(simplex *root, visit_func visit) | |
{ | |
return visit_triang_gen((simplex*)visit_triang(root, &PowerCrustSurfaceReconstructionImpl::facet_test), visit, &PowerCrustSurfaceReconstructionImpl::hullt); | |
} | |
Coord PowerCrustSurfaceReconstructionImpl::Vec_dot(point x, point y) | |
{ | |
Coord sum = 0; | |
for (int i = 0; i < rdim; i++) sum += x[i] * y[i]; | |
return sum; | |
} | |
Coord PowerCrustSurfaceReconstructionImpl::Vec_dot_pdim(point x, point y) | |
{ | |
Coord sum = 0; | |
for (int i = 0; i < pdim; i++) sum += x[i] * y[i]; | |
return sum; | |
} | |
Coord PowerCrustSurfaceReconstructionImpl::Norm2(point x) | |
{ | |
Coord sum = 0; | |
for (int i = 0; i < rdim; i++) sum += x[i] * x[i]; | |
return sum; | |
} | |
void PowerCrustSurfaceReconstructionImpl::Ax_plus_y(Coord a, point x, point y) | |
{ | |
for (int i = 0; i < rdim; i++) | |
{ | |
*y++ += a * *x++; | |
} | |
} | |
void PowerCrustSurfaceReconstructionImpl::Ax_plus_y_test(Coord a, point x, point y) | |
{ | |
for (int i = 0; i < rdim; i++) | |
{ | |
*y++ += a * *x++; | |
} | |
} | |
void PowerCrustSurfaceReconstructionImpl::Vec_scale_test(int n, Coord a, Coord *x) | |
{ | |
register Coord *xx = x, *xend = xx + n; | |
while (xx != xend) | |
{ | |
*xx *= a; | |
xx++; | |
} | |
} | |
double PowerCrustSurfaceReconstructionImpl::sc(basis_s *v, simplex *s, int k, int j) | |
{ | |
/* amount by which to scale up vector, for reduce_inner */ | |
if (j < 10) | |
{ | |
double labound = logb(v->sqa) / 2; | |
sc_max_scale = exact_bits - labound - 0.66* (k - 2) - 1 - DELIFT; | |
if (sc_max_scale < 1) | |
{ | |
sc_max_scale = 1; | |
} | |
if (j == 0) | |
{ | |
int i; | |
neighbor *sni; | |
basis_s *snib; | |
sc_ldetbound = DELIFT; | |
sc_Sb = 0; | |
for (i = k - 1, sni = s->neigh + k - 1; i > 0; i--, sni--) | |
{ | |
snib = sni->basis; | |
sc_Sb += snib->sqb; | |
sc_ldetbound += logb(snib->sqb) / 2 + 1; | |
sc_ldetbound -= snib->lscale; | |
} | |
} | |
} | |
if (sc_ldetbound - v->lscale + logb(v->sqb) / 2 + 1 < 0) | |
{ | |
return 0; | |
} | |
else | |
{ | |
sc_lscale = (int)(logb(2 * sc_Sb / (v->sqb + v->sqa*b_err_min)) / 2); // cast to int added by TJH | |
if (sc_lscale > sc_max_scale) | |
{ | |
sc_lscale = (int)sc_max_scale; // cast added by TJH (is lscale really meant to be int, not double?) | |
} | |
else if (sc_lscale < 0) sc_lscale = 0; | |
v->lscale += sc_lscale; | |
return two_to(sc_lscale); | |
} | |
} | |
int PowerCrustSurfaceReconstructionImpl::reduce_inner(basis_s *v, simplex *s, int k) | |
{ | |
point va = VA(v), vb = VB(v); | |
int i; | |
basis_s *snibv; | |
neighbor *sni; | |
v->sqa = v->sqb = Norm2(vb); | |
if (k <= 1) | |
{ | |
memcpy(vb, va, basis_vec_size); | |
return 1; | |
} | |
for (int j = 0; j < 250; j++) | |
{ | |
memcpy(vb, va, basis_vec_size); | |
for (i = k - 1, sni = s->neigh + k - 1; i > 0; i--, sni--) | |
{ | |
snibv = sni->basis; | |
double dd = -Vec_dot(VB(snibv), vb) / snibv->sqb; | |
Ax_plus_y(dd, VA(snibv), vb); | |
} | |
v->sqb = Norm2(vb); | |
v->sqa = Norm2(va); | |
if (2 * v->sqb >= v->sqa) | |
{ | |
return 1; | |
} | |
Vec_scale_test(rdim, sc(v, s, k, j), va); | |
for (i = k - 1, sni = s->neigh + k - 1; i > 0; i--, sni--) | |
{ | |
snibv = sni->basis; | |
double dd = -Vec_dot(VB(snibv), va) / snibv->sqb; | |
dd = floor(dd + 0.5); | |
Ax_plus_y_test(dd, VA(snibv), va); | |
} | |
} | |
return 0; | |
} | |
void PowerCrustSurfaceReconstructionImpl::trans(point z, point p, point q) | |
{ | |
for (int i = 0; i < pdim; i++) | |
z[i + rdim] = z[i] = p[i] - q[i]; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::compute_3d_power_vv(simplex *s, void *p) | |
{ | |
point v[MAXDIM]; | |
int inf = 0; | |
int index = 0; | |
double cc[3], cond, ta[4][4]; | |
edgesimp *pindex; | |
if (p) | |
{ | |
if (!s) return NULL; | |
} | |
for (int j = 0; j < cdim; j++) | |
{ | |
v[j] = s->neigh[j].vert; | |
/* v[j] stores coordinates of j'th vertex of simplex s; j=0..3 */ | |
if (v[j] == infinity) /* means simplex s is on the convex hull */ | |
{ | |
inf = 1; | |
continue; /* skip the rest of the for loop; process next vertex */ | |
} | |
for (int k = 0; k < 4; k++) | |
{ | |
ta[index][k] = v[j][k] / mult_up; /* restore original coords */ | |
} | |
index++; | |
} | |
/* if not faces on convex hull, process */ | |
if (!inf) | |
{ | |
/* build structure for each edge, including angle of intersection */ | |
for (int k = 0; k < 6; k++) | |
{ | |
if (s->edgestatus[k] == FIRST_EDGE) /* not visited edge */ | |
{ | |
pindex = adjlist[(this->*site_num) (v[v1[k]])].eptr; | |
bool visited_edge = false; | |
while (pindex != NULL) | |
{ | |
if (pindex->pid == (this->*site_num) (v[v2[k]])) /* already in the list */ | |
{ | |
visited_edge = true; | |
break; | |
} | |
pindex = pindex->next; | |
} | |
if (!visited_edge) | |
{ | |
double d = sqdist(ta[v1[k]], ta[v2[k]]); | |
double r1 = SQ(ta[v1[k]][0]) + SQ(ta[v1[k]][1]) + SQ(ta[v1[k]][2]) - ta[v1[k]][3]; | |
double r2 = SQ(ta[v2[k]][0]) + SQ(ta[v2[k]][1]) + SQ(ta[v2[k]][2]) - ta[v2[k]][3]; | |
double e = 2 * sqrt(r1) * sqrt(r2); | |
edgesimp *newplist1; | |
newplist1 = (edgesimp *)malloc(sizeof(edgesimp)); | |
newplist1->simp = s; | |
newplist1->kth = k; | |
newplist1->angle = (r1 + r2 - d) / e; | |
newplist1->pid = (this->*site_num) (v[v1[k]]); | |
newplist1->next = adjlist[(this->*site_num) (v[v2[k]])].eptr; | |
adjlist[(this->*site_num) (v[v2[k]])].eptr = newplist1; | |
edgesimp *newplist2; | |
newplist2 = (edgesimp *)malloc(sizeof(edgesimp)); | |
newplist2->simp = s; | |
newplist2->kth = k; | |
newplist2->angle = (r1 + r2 - d) / e; | |
newplist2->pid = (this->*site_num) (v[v2[k]]); | |
newplist2->next = adjlist[(this->*site_num) (v[v1[k]])].eptr; | |
adjlist[(this->*site_num) (v[v1[k]])].eptr = newplist2; | |
s->edgestatus[k] = VISITED; | |
} | |
} | |
} | |
tetorthocenter(ta[0], ta[1], ta[2], ta[3], cc, &cond); | |
/* cc is the displacement of orthocenter from ta[0] */ | |
/* cond is the denominator ( orient2d ) value */ | |
if (cond != 0) /* ignore them if cond = 0 */ | |
{ | |
s->isVvNull = false; | |
for (int k = 0; k < 3; k++) | |
{ | |
s->vv[k] = ta[0][k] + cc[k]; | |
} | |
s->status = VV; | |
} | |
else /* if cond=0, s is SLIVER */ | |
{ | |
s->isVvNull = true; | |
s->status = SLV; | |
} | |
} | |
else /* if on conv hull, ignore */ | |
{ | |
s->isVvNull = true; | |
s->status = CNV; | |
} | |
return NULL; | |
} | |
void * PowerCrustSurfaceReconstructionImpl::compute_axis(simplex *s, void *p) | |
{ | |
point v[MAXDIM]; | |
point point1, point2; | |
int edgedata[6]; | |
int indices[6]; | |
if (p) | |
{ | |
if (!s) return NULL; | |
} | |
if ((s->status == CNV) || (s->status == SLV)) return NULL; /* skip inf faces */ | |
for (int j = 0; j < cdim; j++) | |
{ | |
v[j] = s->neigh[j].vert; | |
} | |
for (int k = 0; k < 6; k++) /* for each edge */ | |
{ | |
edgedata[k] = 0; | |
if ((s->edgestatus[k] != POW)) /* not dual to a power face */ | |
{ | |
point1 = v[v1[k]]; | |
point2 = v[v2[k]]; | |
int pindex = (this->*site_num) (point1); | |
int qindex = (this->*site_num) (point2); | |
if (adjlist[pindex].label == IN && adjlist[qindex].label == IN) | |
{ | |
if (s->edgestatus[k] != ADDAXIS) | |
{ | |
} | |
edgedata[k] = VALIDEDGE; | |
indices[v1[k]] = pindex; | |
indices[v2[k]] = qindex; | |
s->edgestatus[k] = ADDAXIS; | |
} | |
/* now start adding triangles if present */ | |
} | |
} | |
if ((edgedata[0] == VALIDEDGE) && (edgedata[1] == VALIDEDGE) && (edgedata[3] == VALIDEDGE)) | |
{ | |
{ | |
medial_surface.InsertTriangle(indices[v1[0]], indices[v2[1]], indices[v1[3]]); | |
} | |
} | |
if ((edgedata[1] == VALIDEDGE) && (edgedata[2] == VALIDEDGE) && (edgedata[5] == VALIDEDGE)) | |
{ | |
{ | |
medial_surface.InsertTriangle(indices[v1[1]], indices[v2[2]], indices[v1[5]]); | |
} | |
} | |
if ((edgedata[0] == VALIDEDGE) && (edgedata[2] == VALIDEDGE) && (edgedata[4] == VALIDEDGE)) | |
{ | |
{ | |
medial_surface.InsertTriangle(indices[v1[0]], indices[v2[2]], indices[v1[4]]); | |
} | |
} | |
if ((edgedata[3] == VALIDEDGE) && (edgedata[4] == VALIDEDGE) && (edgedata[5] == VALIDEDGE)) | |
{ | |
{ | |
medial_surface.InsertTriangle(indices[v1[3]], indices[v2[4]], indices[v1[5]]); | |
} | |
} | |
return NULL; | |
} | |
void PowerCrustSurfaceReconstructionImpl::construct_face(simplex *s, short k) | |
{ | |
site edge0, edge1, nextv, remv, prevv, outsite, insite; | |
simplex *prevs, *nexts; | |
int j, numedges, l1, l2, nk, l, nedge0 = 0, nedge1 = 0, nremv = 0, nnextv = 0, i; | |
char indface[1024][32]; /* the indices of the face */ | |
double plane[3][3]; | |
double outpole[3], inpole[3]; | |
edge0 = s->neigh[v1[k]].vert; | |
edge1 = s->neigh[v2[k]].vert; | |
if (adjlist[(this->*site_num) (edge0)].label == OUT) | |
{ | |
outsite = edge0; | |
insite = edge1; | |
} | |
else | |
{ | |
outsite = edge1; | |
insite = edge0; | |
} | |
for (j = 0; j < 3; j++) | |
{ | |
outpole[j] = outsite[j] / mult_up; | |
inpole[j] = insite[j] / mult_up; | |
} | |
nextv = s->neigh[v3[k]].vert; | |
/* nextv is the opposite vtx of the next simplex */ | |
remv = s->neigh[v4[k]].vert; | |
/* remv is a vtx of the next simplex with edge0, edge1 */ | |
prevv = remv; | |
/* prevv is the vtx shared by prevs and nexts besides edge0, edge1 */ | |
/* construct its dual power face */ | |
s->edgestatus[k] = POW; | |
/* visit the next simplex */ | |
prevs = s; | |
nexts = s->neigh[v3[k]].simp; | |
numedges = 0; | |
while (nexts != s) | |
{ | |
if (nexts->status == CNV) | |
{ | |
break; | |
} | |
else | |
{ | |
if (prevs->status != POLE_OUTPUT) | |
{ | |
/* this vertex is not yet output */ | |
prevs->status = POLE_OUTPUT; | |
prevs->poleindex = num_vtxs++; | |
// TJH: PC contains the points for the powercrust surface | |
// so we hijack the data and pipe it to our structure | |
{ | |
float vp[3]; | |
vp[0] = prevs->vv[0]; | |
vp[1] = prevs->vv[1]; | |
vp[2] = prevs->vv[2]; | |
output.InsertNextPoint(vp); | |
} | |
} | |
if (numedges < 3) | |
{ | |
plane[numedges][0] = prevs->vv[0]; | |
plane[numedges][1] = prevs->vv[1]; | |
plane[numedges][2] = prevs->vv[2]; | |
} | |
sprintf(indface[numedges], "%ld ", prevs->poleindex); | |
numedges++; | |
/* find edgenumber k of nexts for this edge */ | |
for (l = 0; l < 4; l++) | |
{ | |
if (nexts->neigh[l].vert == edge0) | |
{ | |
nedge0 = l; | |
continue; | |
} | |
else if (nexts->neigh[l].vert == edge1) | |
{ | |
nedge1 = l; | |
continue; | |
} | |
else if (nexts->neigh[l].vert == prevv) | |
{ | |
nremv = l; | |
continue; | |
} | |
else if (nexts->neigh[l].vert == nextv) | |
{ | |
nnextv = l; | |
continue; | |
} | |
else | |
{ | |
nnextv = l; | |
} | |
} | |
if (nedge0 > nedge1) | |
{ | |
l1 = nedge1; | |
l2 = nedge0; | |
} | |
else | |
{ | |
l2 = nedge1; | |
l1 = nedge0; | |
} | |
if (l1 == 0) | |
{ | |
if (l2 == 1) nk = 0; | |
else if (l2 == 2) nk = 1; | |
else nk = 2; | |
} | |
else if (l1 == 1) | |
{ | |
if (l2 == 2) nk = 3; | |
else nk = 4; | |
} | |
else nk = 5; | |
/* found nk for the edge */ | |
nexts->edgestatus[nk] = POW; /* record that it's visited */ | |
/* visit next simplex (opposite vertex ns )*/ | |
prevs = nexts; | |
prevv = nexts->neigh[nnextv].vert; | |
nexts = nexts->neigh[nremv].simp; | |
} | |
} | |
if (prevs->status != POLE_OUTPUT) | |
{ | |
prevs->status = POLE_OUTPUT; | |
prevs->poleindex = num_vtxs++; | |
// TJH: PC contains the points for the powercrust surface | |
// so we hijack the data and pipe it to our structure | |
{ | |
float vp[3]; | |
vp[0] = prevs->vv[0]; | |
vp[1] = prevs->vv[1]; | |
vp[2] = prevs->vv[2]; | |
output.InsertNextPoint(vp); | |
} | |
} | |
if (numedges < 3) | |
{ | |
plane[numedges][0] = prevs->vv[0]; | |
plane[numedges][1] = prevs->vv[1]; | |
plane[numedges][2] = prevs->vv[2]; | |
} | |
sprintf(indface[numedges], "%ld ", prevs->poleindex); | |
numedges++; | |
//output.InsertNextCell(numedges); | |
std::vector<int> indices; | |
if (!correct_orientation(plane[0], plane[1], plane[2], inpole, outpole)) | |
for (i = numedges - 1; i >= 0; i--) | |
{ | |
{ | |
//output.GetPolys()->InsertCellPoint(atoi(indface[i])); | |
indices.push_back(atoi(indface[i])); | |
} | |
} | |
else | |
{ | |
for (i = 0; i < numedges; i++) | |
{ | |
{ | |
//output.GetPolys()->InsertCellPoint(atoi(indface[i])); | |
indices.push_back(atoi(indface[i])); | |
} | |
} | |
} | |
output.InsertCell(indices); | |
} | |
int PowerCrustSurfaceReconstructionImpl::correct_orientation(double *p1, double *p2, double *p3, double *inp, double *outp) | |
{ | |
double normal[3]; | |
double v1[3], v2[3]; | |
double xcross, ycross, zcross; | |
int numplus = 0, numminus = 0; | |
normal[0] = outp[0] - inp[0]; | |
normal[1] = outp[1] - inp[1]; | |
normal[2] = outp[2] - inp[2]; | |
v1[0] = p2[0] - p1[0]; | |
v1[1] = p2[1] - p1[1]; | |
v1[2] = p2[2] - p1[2]; | |
v2[0] = p3[0] - p2[0]; | |
v2[1] = p3[1] - p2[1]; | |
v2[2] = p3[2] - p2[2]; | |
xcross = v1[1] * v2[2] - v1[2] * v2[1]; | |
ycross = v1[2] * v2[0] - v1[0] * v2[2]; | |
zcross = v1[0] * v2[1] - v1[1] * v2[0]; | |
if ((xcross*normal[0]) > 0) | |
numplus++; | |
else | |
numminus++; | |
if ((ycross*normal[1]) > 0) | |
numplus++; | |
else | |
numminus++; | |
if ((zcross*normal[2]) > 0) | |
numplus++; | |
else | |
numminus++; | |
if (numplus > numminus) | |
return 1; | |
else | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment