You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3071 lines
63 KiB
3071 lines
63 KiB
/*
|
|
|
|
Implementations of Octree member functions.
|
|
|
|
Copyright (C) 2011 Tao Ju
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public License
|
|
(LGPL) as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include "octree.h"
|
|
#include "PLYWriter.h"
|
|
|
|
#include <iostream>
|
|
|
|
Octree::Octree()
|
|
{
|
|
}
|
|
|
|
Octree::Octree(char* fname)
|
|
{
|
|
// Recognize file format
|
|
|
|
if (strstr(fname, ".sog") != NULL || strstr(fname, ".SOG") != NULL)
|
|
{
|
|
printf("Reading SOG file format.\n");
|
|
this->hasQEF = 0;
|
|
readSOG(fname);
|
|
}
|
|
else if (strstr(fname, ".dcf") != NULL || strstr(fname, ".DCF") != NULL)
|
|
{
|
|
printf("Reading DCF file format.\n");
|
|
this->hasQEF = 1;
|
|
readDCF(fname);
|
|
}
|
|
else
|
|
{
|
|
printf("Wrong input format. Must be SOG/DCF.\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
Octree::~Octree()
|
|
{
|
|
if (root)
|
|
delete root;
|
|
root = 0;
|
|
}
|
|
|
|
void Octree::simplify(float thresh)
|
|
{
|
|
if (this->hasQEF)
|
|
{
|
|
int st[3] = { 0,0,0 };
|
|
this->root = simplify(root, st, dimen, thresh);
|
|
}
|
|
}
|
|
|
|
OctreeNode* Octree::simplify(OctreeNode* node, int st[3], int len, float thresh)
|
|
{
|
|
if (node == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
int type = node->getType();
|
|
|
|
if (type == 0)
|
|
{
|
|
// Internal node
|
|
InternalNode* inode = ((InternalNode*)node);
|
|
|
|
int simple = 1;
|
|
|
|
float ata[6] = { 0, 0, 0, 0, 0, 0 };
|
|
float atb[3] = { 0, 0, 0 };
|
|
float pt[3] = { 0, 0, 0 };
|
|
float mp[3] = { 0, 0, 0 };
|
|
float btb = 0;
|
|
int signs[8] = { -1,-1,-1,-1,-1,-1,-1,-1 };
|
|
int midsign = -1;
|
|
|
|
int nlen = len / 2;
|
|
int nst[3];
|
|
int ec = 0;
|
|
int ht;
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
nst[0] = st[0] + vertMap[i][0] * nlen;
|
|
nst[1] = st[1] + vertMap[i][1] * nlen;
|
|
nst[2] = st[2] + vertMap[i][2] * nlen;
|
|
|
|
inode->child[i] = simplify(inode->child[i], nst, nlen, thresh);
|
|
|
|
if (inode->child[i] != NULL)
|
|
{
|
|
if (inode->child[i]->getType() == 0)
|
|
{
|
|
simple = 0;
|
|
}
|
|
else if (inode->child[i]->getType() == 1)
|
|
{
|
|
LeafNode* lnode = (LeafNode*)inode->child[i];
|
|
ht = lnode->height;
|
|
|
|
for (int j = 0; j < 6; j++)
|
|
{
|
|
ata[j] += lnode->ata[j];
|
|
}
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
atb[j] += lnode->atb[j];
|
|
pt[j] += lnode->mp[j];
|
|
}
|
|
if (lnode->mp[0] == 0)
|
|
{
|
|
printf("%f %f %f, Height: %d\n", lnode->mp[0], lnode->mp[1], lnode->mp[2], ht);
|
|
}
|
|
btb += lnode->btb;
|
|
ec++;
|
|
|
|
midsign = lnode->getSign(7 - i);
|
|
signs[i] = lnode->getSign(i);
|
|
}
|
|
else
|
|
{
|
|
PseudoLeafNode* pnode = (PseudoLeafNode*)inode->child[i];
|
|
ht = pnode->height;
|
|
|
|
for (int j = 0; j < 6; j++)
|
|
{
|
|
ata[j] += pnode->ata[j];
|
|
}
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
atb[j] += pnode->atb[j];
|
|
pt[j] += pnode->mp[j];
|
|
}
|
|
btb += pnode->btb;
|
|
ec++;
|
|
|
|
midsign = pnode->getSign(7 - i);
|
|
signs[i] = pnode->getSign(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (simple)
|
|
{
|
|
// Ok, let's collapse
|
|
if (ec == 0)
|
|
{
|
|
delete node;
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
pt[0] = pt[0] / ec;
|
|
pt[1] = pt[1] / ec;
|
|
pt[2] = pt[2] / ec;
|
|
if (pt[0] < st[0] || pt[1] < st[1] || pt[2] < st[2] ||
|
|
pt[0] > st[0] + len || pt[1] > st[1] + len || pt[2] > st[2] + len)
|
|
{
|
|
//printf("Out! %f %f %f, Box: (%d %d %d) Len: %d ec: %d\n", pt[0], pt[1], pt[2], st[0],st[1],st[2],len,ec) ;
|
|
}
|
|
|
|
unsigned char sg = 0;
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if (signs[i] == 1)
|
|
{
|
|
sg |= (1 << i);
|
|
}
|
|
else if (signs[i] == -1)
|
|
{
|
|
// Undetermined, use center sign instead
|
|
if (midsign == 1)
|
|
{
|
|
sg |= (1 << i);
|
|
}
|
|
else if (midsign == -1)
|
|
{
|
|
printf("Wrong!");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Solve
|
|
float mat[10];
|
|
BoundingBoxf* box = new BoundingBoxf;
|
|
box->begin.x = (float)st[0];
|
|
box->begin.y = (float)st[1];
|
|
box->begin.z = (float)st[2];
|
|
box->end.x = (float)st[0] + len;
|
|
box->end.y = (float)st[1] + len;
|
|
box->end.z = (float)st[2] + len;
|
|
|
|
float error = calcPoint(ata, atb, btb, pt, mp, box, mat);
|
|
#ifdef CLAMP
|
|
if (mp[0] < st[0] || mp[1] < st[1] || mp[2] < st[2] ||
|
|
mp[0] > st[0] + len || mp[1] > st[1] + len || mp[2] > st[2] + len)
|
|
{
|
|
mp[0] = pt[0];
|
|
mp[1] = pt[1];
|
|
mp[2] = pt[2];
|
|
}
|
|
#endif
|
|
if (error <= thresh)
|
|
{
|
|
//mp[0] = st[0] + len / 2 ;
|
|
//mp[1] = st[1] + len / 2 ;
|
|
//mp[2] = st[2] + len / 2 ;
|
|
|
|
PseudoLeafNode* pnode = new PseudoLeafNode(ht + 1, sg, ata, atb, btb, mp);
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
pnode->child[i] = inode->child[i];
|
|
}
|
|
|
|
delete inode;
|
|
return pnode;
|
|
}
|
|
else
|
|
{
|
|
return node;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return node;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return node;
|
|
}
|
|
}
|
|
|
|
void Octree::readSOG(char* fname)
|
|
{
|
|
FILE* fin = fopen(fname, "rb");
|
|
if (fin == NULL)
|
|
{
|
|
printf("Can not open file %s.\n", fname);
|
|
}
|
|
|
|
// Process header
|
|
char header[] = "SOG.Format 1.0";
|
|
float origin[3];
|
|
float range;
|
|
|
|
fread(header, sizeof(char), strlen(header) + 1, fin);
|
|
if (strcmp(header, "SOG.Format 1.0"))
|
|
{
|
|
printf("Incorrect file format.\n", fname);
|
|
exit(1);
|
|
}
|
|
fread(origin, sizeof(float), 3, fin);
|
|
fread(&range, sizeof(float), 1, fin);
|
|
printf("Origin: (%f, %f, %f), Range: %f.\n", origin[0], origin[1], origin[2], range);
|
|
|
|
int nlen = 128 - 4 * 4 - strlen(header) - 1;
|
|
char* header2 = new char[nlen];
|
|
fread(header2, sizeof(char), nlen, fin);
|
|
|
|
fread(&(this->dimen), sizeof(int), 1, fin);
|
|
this->maxDepth = 0;
|
|
int temp = 1;
|
|
while (temp < this->dimen)
|
|
{
|
|
maxDepth++;
|
|
temp <<= 1;
|
|
}
|
|
printf("Dimensions: %d Depth: %d\n", this->dimen, maxDepth);
|
|
|
|
// Recursive reader
|
|
int st[3] = { 0,0,0 };
|
|
this->root = readSOG(fin, st, dimen, maxDepth, origin, range);
|
|
|
|
printf("Done reading.\n");
|
|
fclose(fin);
|
|
}
|
|
|
|
OctreeNode* Octree::readSOG(FILE* fin, int st[3], int len, int ht, float origin[3], float range)
|
|
{
|
|
OctreeNode* rvalue = NULL;
|
|
int i;
|
|
|
|
// Get type
|
|
char type;
|
|
fread(&type, sizeof(char), 1, fin);
|
|
|
|
if (type == 0)
|
|
{
|
|
// Internal node
|
|
rvalue = new InternalNode();
|
|
|
|
int nlen = len / 2;
|
|
int nst[3];
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
nst[0] = st[0] + vertMap[i][0] * nlen;
|
|
nst[1] = st[1] + vertMap[i][1] * nlen;
|
|
nst[2] = st[2] + vertMap[i][2] * nlen;
|
|
|
|
((InternalNode*)rvalue)->child[i] = readSOG(fin, nst, nlen, ht - 1, origin, range);
|
|
}
|
|
}
|
|
else if (type == 1)
|
|
{
|
|
// Empty node
|
|
char sg;
|
|
fread(&sg, sizeof(char), 1, fin);
|
|
sg = ~sg;
|
|
}
|
|
else if (type == 2)
|
|
{
|
|
// Leaf node
|
|
unsigned char sg;
|
|
fread(&sg, sizeof(unsigned char), 1, fin);
|
|
sg = ~sg;
|
|
|
|
float coord[3];
|
|
fread(coord, sizeof(float), 3, fin);
|
|
|
|
#ifdef SOG_RELATIVE
|
|
coord[0] = st[0] + len * coord[0];
|
|
coord[1] = st[1] + len * coord[1];
|
|
coord[2] = st[2] + len * coord[2];
|
|
#else
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
coord[i] = (coord[i] - origin[i]) * dimen / range;
|
|
}
|
|
#endif
|
|
|
|
rvalue = new LeafNode(ht, sg, coord);
|
|
}
|
|
else if (type == 3)
|
|
{
|
|
// Pseudo-leaf node
|
|
unsigned char sg;
|
|
fread(&sg, sizeof(unsigned char), 1, fin);
|
|
sg = ~sg;
|
|
|
|
float coord[3];
|
|
fread(coord, sizeof(float), 3, fin);
|
|
|
|
#ifdef SOG_RELATIVE
|
|
coord[0] = st[0] + len * coord[0];
|
|
coord[1] = st[1] + len * coord[1];
|
|
coord[2] = st[2] + len * coord[2];
|
|
#else
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
coord[i] = (coord[i] - origin[i]) * dimen / range;
|
|
}
|
|
#endif
|
|
|
|
rvalue = new PseudoLeafNode(ht, sg, coord);
|
|
|
|
int nlen = len / 2;
|
|
int nst[3];
|
|
|
|
for (int k = 0; i < 8; i++)
|
|
{
|
|
nst[0] = st[0] + vertMap[i][0] * nlen;
|
|
nst[1] = st[1] + vertMap[i][1] * nlen;
|
|
nst[2] = st[2] + vertMap[i][2] * nlen;
|
|
((PseudoLeafNode*)rvalue)->child[i] = readSOG(fin, nst, nlen, ht - 1, origin, range);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Wrong! Type: %d\n", type);
|
|
}
|
|
return rvalue;
|
|
}
|
|
|
|
void Octree::readDCF(char* fname)
|
|
{
|
|
FILE* fin = fopen(fname, "rb");
|
|
if (fin == NULL)
|
|
{
|
|
printf("Can not open file %s.\n", fname);
|
|
}
|
|
|
|
// Process header
|
|
char version[10];
|
|
fread(version, sizeof(char), 10, fin);
|
|
//std::cout << version << std::endl;
|
|
if (strcmp(version, "multisign") != 0)
|
|
{
|
|
printf("Wrong DCF version.\n");
|
|
exit(0);
|
|
}
|
|
|
|
fread(&(this->dimen), sizeof(int), 1, fin);
|
|
//std::cout << this->dimen << ' ';
|
|
fread(&(this->dimen), sizeof(int), 1, fin);
|
|
//std::cout << this->dimen << ' ';
|
|
fread(&(this->dimen), sizeof(int), 1, fin);
|
|
//std::cout << this->dimen << std::endl;
|
|
this->maxDepth = 0;
|
|
int temp = 1;
|
|
while (temp < this->dimen)
|
|
{
|
|
maxDepth++;
|
|
temp <<= 1;
|
|
}
|
|
printf("Dimensions: %d Depth: %d\n", this->dimen, maxDepth);
|
|
|
|
// Recursive reader
|
|
int st[3] = { 0, 0, 0 };
|
|
this->root = readDCF(fin, st, dimen, maxDepth);
|
|
|
|
printf("Done reading.\n");
|
|
fclose(fin);
|
|
}
|
|
|
|
OctreeNode* Octree::readDCF(FILE* fin, int st[3], int len, int ht)
|
|
{
|
|
OctreeNode* rvalue = NULL;
|
|
|
|
// Get type
|
|
int type;
|
|
fread(&type, sizeof(int), 1, fin);
|
|
//std::cout << space <<"t" << type << std::endl;
|
|
// printf("Type: %d\n", type);
|
|
if (type == 0)
|
|
{
|
|
// Internal node
|
|
rvalue = new InternalNode();
|
|
int nlen = len / 2;
|
|
int nst[3];
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
nst[0] = st[0] + vertMap[i][0] * nlen;
|
|
nst[1] = st[1] + vertMap[i][1] * nlen;
|
|
nst[2] = st[2] + vertMap[i][2] * nlen;
|
|
|
|
((InternalNode*)rvalue)->child[i] = readDCF(fin, nst, nlen, ht - 1);
|
|
}
|
|
}
|
|
else if (type == 1)
|
|
{
|
|
// Empty node
|
|
//short sg ;
|
|
//fread( &sg, sizeof( short ), 1, fin ) ;
|
|
////std::cout << space << sg << std::endl;
|
|
}
|
|
else if (type == 2)
|
|
{
|
|
// Leaf node
|
|
//short rsg[8] ;
|
|
//fread( rsg, sizeof( short ), 8, fin ) ;
|
|
//unsigned char sg = 0 ;
|
|
|
|
//for ( int i = 0 ; i < 8 ; i ++ )
|
|
//{
|
|
// //std::cout << space << rsg[i] << std::endl;
|
|
// if ( rsg[i] != 0 )
|
|
// {
|
|
// sg |= ( 1 << i ) ;
|
|
// }
|
|
//}
|
|
int sg = 0;
|
|
fread(&sg, sizeof(int), 1, fin);
|
|
//std::cout << space << sg << std::endl;
|
|
float inters[12][3], norms[12][3];
|
|
int numinters = 0;
|
|
|
|
for (int i = 0; i < 12; i++)
|
|
{
|
|
int num;
|
|
fread(&num, sizeof(int), 1, fin);
|
|
//std::cout << space << num << std::endl;
|
|
if (num > 0)
|
|
{
|
|
for (int j = 0; j < num; j++)
|
|
{
|
|
float off;
|
|
fread(&off, sizeof(float), 1, fin);
|
|
fread(norms[numinters], sizeof(float), 3, fin);
|
|
|
|
//std::cout << space << norms[numinters][0] << ' ' << norms[numinters][1] << ' ' << norms[numinters][2] << std::endl;
|
|
|
|
int dir = i / 4;
|
|
int base = edgevmap[i][0];
|
|
inters[numinters][0] = st[0] + vertMap[base][0] * len;
|
|
inters[numinters][1] = st[1] + vertMap[base][1] * len;
|
|
inters[numinters][2] = st[2] + vertMap[base][2] * len;
|
|
inters[numinters][dir] += off;
|
|
|
|
numinters++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (numinters > 0)
|
|
{
|
|
rvalue = new LeafNode(ht, (unsigned char)sg, st, len, numinters, inters, norms);
|
|
}
|
|
else
|
|
{
|
|
rvalue = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Wrong! Type: %d\n", type);
|
|
}
|
|
return rvalue;
|
|
}
|
|
|
|
void Octree::genContourNoInter2(const char* fname)
|
|
{
|
|
int numTris = 0;
|
|
int numVertices = 0;
|
|
IndexedTriangleList* tlist = new IndexedTriangleList;
|
|
VertexList* vlist = new VertexList;
|
|
tlist->next = NULL;
|
|
vlist->next = NULL;
|
|
|
|
founds = 0;
|
|
news = 0;
|
|
|
|
// generate triangles
|
|
faceVerts = 0;
|
|
edgeVerts = 0;
|
|
HashMap* hash = new HashMap();
|
|
int st[3] = { 0,0,0 };
|
|
printf("Processing contour...\n");
|
|
|
|
clock_t start = clock();
|
|
cellProcContourNoInter2(root, st, dimen, hash, tlist, numTris, vlist, numVertices);
|
|
clock_t finish = clock();
|
|
printf("Time used: %f seconds.\n", (float)(finish - start) / (float)CLOCKS_PER_SEC);
|
|
|
|
printf("Face vertices: %d Edge vertices: %d\n", faceVerts, edgeVerts);
|
|
printf("New hash entries: %d. Found times: %d\n", news, founds);
|
|
|
|
// Finally, turn into PLY
|
|
FILE* fout = fopen(fname, "wb");
|
|
printf("Vertices counted: %d Triangles counted: %d \n", numVertices, numTris);
|
|
PLYWriter::writeHeader(fout, numVertices, numTris);
|
|
float p[3];
|
|
VertexList* v = vlist->next;
|
|
while (v != NULL)
|
|
{
|
|
to_world(v->vt, p);
|
|
PLYWriter::writeVertex(fout, p);
|
|
//PLYWriter::writeVertex(fout, v->vt);
|
|
v = v->next;
|
|
}
|
|
|
|
IndexedTriangleList* t = tlist->next;
|
|
for (int i = 0; i < numTris; i++)
|
|
{
|
|
int inds[] = { numVertices - 1 - t->vt[0], numVertices - 1 - t->vt[2], numVertices - 1 - t->vt[1] };
|
|
|
|
PLYWriter::writeFace(fout, 3, inds);
|
|
t = t->next;
|
|
}
|
|
|
|
fclose(fout);
|
|
|
|
// Clear up
|
|
delete hash;
|
|
v = vlist;
|
|
while (v != NULL)
|
|
{
|
|
vlist = v->next;
|
|
delete v;
|
|
v = vlist;
|
|
}
|
|
t = tlist;
|
|
while (t != NULL)
|
|
{
|
|
tlist = t->next;
|
|
delete t;
|
|
t = tlist;
|
|
}
|
|
}
|
|
|
|
void Octree::genContourNoInter(const char* fname)
|
|
{
|
|
int numTris = 0;
|
|
TriangleList* list = new TriangleList;
|
|
list->next = NULL;
|
|
|
|
founds = 0;
|
|
news = 0;
|
|
|
|
// generate triangles
|
|
faceVerts = 0;
|
|
edgeVerts = 0;
|
|
HashMap2* hash = new HashMap2();
|
|
int st[3] = { 0,0,0 };
|
|
printf("Processing contour...\n");
|
|
cellProcContourNoInter(root, st, dimen, hash, list, numTris);
|
|
printf("Face vertices: %d Edge vertices: %d\n", faceVerts, edgeVerts);
|
|
printf("New hash entries: %d. Found times: %d\n", news, founds);
|
|
|
|
// Finally, turn into PLY
|
|
int numVertices = 3 * numTris;
|
|
|
|
FILE* fout = fopen(fname, "wb");
|
|
printf("Vertices counted: %d Triangles counted: %d \n", numVertices, numTris);
|
|
PLYWriter::writeHeader(fout, numVertices, numTris);
|
|
|
|
float p[3];
|
|
TriangleList* t = list->next;
|
|
while (t != NULL)
|
|
{
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
to_world(t->vt[j], p);
|
|
PLYWriter::writeVertex(fout, p);
|
|
//PLYWriter::writeVertex(fout, t->vt[j]);
|
|
}
|
|
|
|
t = t->next;
|
|
}
|
|
|
|
t = list->next;
|
|
for (int i = 0; i < numTris; i++)
|
|
{
|
|
int tind[] = { 3 * i, 3 * i + 2 , 3 * i + 1};
|
|
PLYWriter::writeFace(fout, 3, tind);
|
|
|
|
t = t->next;
|
|
}
|
|
|
|
fclose(fout);
|
|
|
|
// Clear up
|
|
delete hash;
|
|
t = list;
|
|
while (t != NULL)
|
|
{
|
|
list = t->next;
|
|
delete t;
|
|
t = list;
|
|
}
|
|
}
|
|
|
|
void Octree::genContour(const char* fname)
|
|
{
|
|
int numTris = 0;
|
|
int numVertices = 0;
|
|
|
|
FILE* fout = fopen(fname, "wb");
|
|
cellProcCount(root, numVertices, numTris);
|
|
printf("Vertices counted: %d Triangles counted: %d \n", numVertices, numTris);
|
|
PLYWriter::writeHeader(fout, numVertices, numTris);
|
|
int offset = 0;
|
|
|
|
clock_t start = clock();
|
|
generateVertexIndex(root, offset, fout);
|
|
actualTris = 0;
|
|
cellProcContour(this->root, fout);
|
|
clock_t finish = clock();
|
|
printf("Time used: %f seconds.\n", (float)(finish - start) / (float)CLOCKS_PER_SEC);
|
|
|
|
printf("Actual triangles written: %d\n", actualTris);
|
|
|
|
fclose(fout);
|
|
}
|
|
|
|
void Octree::generateVertexIndex(OctreeNode* node, int& offset, FILE* fout)
|
|
{
|
|
int type = node->getType();
|
|
|
|
if (type == 0)
|
|
{
|
|
// Internal node
|
|
InternalNode* inode = ((InternalNode*)node);
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if (inode->child[i] != NULL)
|
|
{
|
|
generateVertexIndex(inode->child[i], offset, fout);
|
|
}
|
|
}
|
|
}
|
|
else if (type == 1)
|
|
{
|
|
// Leaf node
|
|
LeafNode* lnode = ((LeafNode*)node);
|
|
float p[3];
|
|
to_world(lnode->mp, p);
|
|
PLYWriter::writeVertex(fout, p);
|
|
//PLYWriter::writeVertex(fout, lnode->mp);
|
|
|
|
lnode->index = offset;
|
|
offset++;
|
|
}
|
|
else if (type == 2)
|
|
{
|
|
// Pseudo leaf node
|
|
PseudoLeafNode* pnode = ((PseudoLeafNode*)node);
|
|
float p[3];
|
|
to_world(pnode->mp, p);
|
|
PLYWriter::writeVertex(fout, p);
|
|
//PLYWriter::writeVertex(fout, pnode->mp);
|
|
|
|
pnode->index = offset;
|
|
offset++;
|
|
}
|
|
}
|
|
|
|
void Octree::to_world(const float pos[3], float newpos[3])
|
|
{
|
|
newpos[0] = pos[0] * scale - shift[0];
|
|
newpos[1] = pos[1] * scale - shift[1];
|
|
newpos[2] = pos[2] * scale - shift[2];
|
|
}
|
|
|
|
void Octree::cellProcContour(OctreeNode* node, FILE* fout)
|
|
{
|
|
if (node == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int type = node->getType();
|
|
|
|
if (type == 0)
|
|
{
|
|
InternalNode* inode = ((InternalNode*)node);
|
|
|
|
// 8 Cell calls
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
cellProcContour(inode->child[i], fout);
|
|
}
|
|
|
|
// 12 face calls
|
|
OctreeNode* fcd[2];
|
|
for (int i = 0; i < 12; i++)
|
|
{
|
|
int c[2] = { cellProcFaceMask[i][0], cellProcFaceMask[i][1] };
|
|
|
|
fcd[0] = inode->child[c[0]];
|
|
fcd[1] = inode->child[c[1]];
|
|
|
|
faceProcContour(fcd, cellProcFaceMask[i][2], fout);
|
|
}
|
|
|
|
// 6 edge calls
|
|
OctreeNode* ecd[4];
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
int c[4] = { cellProcEdgeMask[i][0], cellProcEdgeMask[i][1], cellProcEdgeMask[i][2], cellProcEdgeMask[i][3] };
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
ecd[j] = inode->child[c[j]];
|
|
}
|
|
|
|
edgeProcContour(ecd, cellProcEdgeMask[i][4], fout);
|
|
}
|
|
}
|
|
};
|
|
|
|
void Octree::faceProcContour(OctreeNode* node[2], int dir, FILE* fout)
|
|
{
|
|
// printf("I am at a face! %d\n", dir ) ;
|
|
if (!(node[0] && node[1]))
|
|
{
|
|
// printf("I am none.\n") ;
|
|
return;
|
|
}
|
|
|
|
int type[2] = { node[0]->getType(), node[1]->getType() };
|
|
|
|
if (type[0] == 0 || type[1] == 0)
|
|
{
|
|
int i, j;
|
|
|
|
// 4 face calls
|
|
OctreeNode* fcd[2];
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int c[2] = { faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1] };
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
if (type[j] > 0)
|
|
{
|
|
fcd[j] = node[j];
|
|
}
|
|
else
|
|
{
|
|
fcd[j] = ((InternalNode*)node[j])->child[c[j]];
|
|
}
|
|
}
|
|
faceProcContour(fcd, faceProcFaceMask[dir][i][2], fout);
|
|
}
|
|
|
|
// 4 edge calls
|
|
int orders[2][4] = { { 0, 0, 1, 1 }, { 0, 1, 0, 1 } };
|
|
OctreeNode* ecd[4];
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int c[4] = { faceProcEdgeMask[dir][i][1], faceProcEdgeMask[dir][i][2],
|
|
faceProcEdgeMask[dir][i][3], faceProcEdgeMask[dir][i][4] };
|
|
int* order = orders[faceProcEdgeMask[dir][i][0]];
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (type[order[j]] > 0)
|
|
{
|
|
ecd[j] = node[order[j]];
|
|
}
|
|
else
|
|
{
|
|
ecd[j] = ((InternalNode*)node[order[j]])->child[c[j]];
|
|
}
|
|
}
|
|
|
|
edgeProcContour(ecd, faceProcEdgeMask[dir][i][5], fout);
|
|
}
|
|
// printf("I am done.\n") ;
|
|
}
|
|
else
|
|
{
|
|
// printf("I don't have any children.\n") ;
|
|
}
|
|
};
|
|
|
|
void Octree::edgeProcContour(OctreeNode* node[4], int dir, FILE* fout)
|
|
{
|
|
if (!(node[0] && node[1] && node[2] && node[3]))
|
|
{
|
|
return;
|
|
}
|
|
|
|
int type[4] = { node[0]->getType(), node[1]->getType(), node[2]->getType(), node[3]->getType() };
|
|
|
|
if (type[0] > 0 && type[1] > 0 && type[2] > 0 && type[3] > 0)
|
|
{
|
|
processEdgeWrite(node, dir, fout);
|
|
}
|
|
else
|
|
{
|
|
int i, j;
|
|
|
|
// 2 edge calls
|
|
OctreeNode* ecd[4];
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
int c[4] = { edgeProcEdgeMask[dir][i][0],
|
|
edgeProcEdgeMask[dir][i][1],
|
|
edgeProcEdgeMask[dir][i][2],
|
|
edgeProcEdgeMask[dir][i][3] };
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (type[j] > 0)
|
|
{
|
|
ecd[j] = node[j];
|
|
}
|
|
else
|
|
{
|
|
ecd[j] = ((InternalNode*)node[j])->child[c[j]];
|
|
}
|
|
}
|
|
|
|
edgeProcContour(ecd, edgeProcEdgeMask[dir][i][4], fout);
|
|
}
|
|
}
|
|
};
|
|
|
|
void Octree::processEdgeWrite(OctreeNode* node[4], int dir, FILE* fout)
|
|
{
|
|
// Get minimal cell
|
|
int i, type, ht, minht = maxDepth + 1, mini = -1;
|
|
int ind[4], sc[4], flip[4] = { 0,0,0,0 };
|
|
int flip2;
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (node[i]->getType() == 1)
|
|
{
|
|
LeafNode* lnode = ((LeafNode*)node[i]);
|
|
|
|
int ed = processEdgeMask[dir][i];
|
|
int c1 = edgevmap[ed][0];
|
|
int c2 = edgevmap[ed][1];
|
|
|
|
if (lnode->height < minht)
|
|
{
|
|
minht = lnode->height;
|
|
mini = i;
|
|
if (lnode->getSign(c1) > 0)
|
|
{
|
|
flip2 = 1;
|
|
}
|
|
else
|
|
{
|
|
flip2 = 0;
|
|
}
|
|
}
|
|
ind[i] = lnode->index;
|
|
|
|
if (lnode->getSign(c1) == lnode->getSign(c2))
|
|
{
|
|
sc[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
sc[i] = 1;
|
|
|
|
// if ( lnode->getSign(c1) > 0 )
|
|
// {
|
|
// flip[ i ] = 1 ;
|
|
// }
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PseudoLeafNode* pnode = ((PseudoLeafNode*)node[i]);
|
|
|
|
int ed = processEdgeMask[dir][i];
|
|
int c1 = edgevmap[ed][0];
|
|
int c2 = edgevmap[ed][1];
|
|
|
|
if (pnode->height < minht)
|
|
{
|
|
minht = pnode->height;
|
|
mini = i;
|
|
if (pnode->getSign(c1) > 0)
|
|
{
|
|
flip2 = 1;
|
|
}
|
|
else
|
|
{
|
|
flip2 = 0;
|
|
}
|
|
}
|
|
ind[i] = pnode->index;
|
|
|
|
if (pnode->getSign(c1) == pnode->getSign(c2))
|
|
{
|
|
sc[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
sc[i] = 1;
|
|
|
|
// if ( pnode->getSign(c1) > 0 )
|
|
// {
|
|
// flip[ i ] = 1 ;
|
|
// flip2 = 1 ;
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sc[mini] == 1)
|
|
{
|
|
if (flip2 == 0)
|
|
{
|
|
actualTris++;
|
|
if (ind[0] == ind[1])
|
|
{
|
|
int tind[] = { ind[0], ind[2], ind[3] };
|
|
PLYWriter::writeFace(fout, 3, tind);
|
|
}
|
|
else if (ind[1] == ind[3])
|
|
{
|
|
int tind[] = { ind[0], ind[2], ind[1] };
|
|
PLYWriter::writeFace(fout, 3, tind);
|
|
}
|
|
else if (ind[3] == ind[2])
|
|
{
|
|
int tind[] = { ind[0], ind[3], ind[1] };
|
|
PLYWriter::writeFace(fout, 3, tind);
|
|
}
|
|
else if (ind[2] == ind[0])
|
|
{
|
|
int tind[] = { ind[1], ind[2], ind[3] };
|
|
PLYWriter::writeFace(fout, 3, tind);
|
|
}
|
|
else
|
|
{
|
|
int tind1[] = { ind[0], ind[3], ind[1] };
|
|
PLYWriter::writeFace(fout, 3, tind1);
|
|
int tind2[] = { ind[0], ind[2], ind[3] };
|
|
PLYWriter::writeFace(fout, 3, tind2);
|
|
actualTris++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
actualTris++;
|
|
if (ind[0] == ind[1])
|
|
{
|
|
int tind[] = { ind[0], ind[3], ind[2] };
|
|
PLYWriter::writeFace(fout, 3, tind);
|
|
}
|
|
else if (ind[1] == ind[3])
|
|
{
|
|
int tind[] = { ind[0], ind[1], ind[2] };
|
|
PLYWriter::writeFace(fout, 3, tind);
|
|
}
|
|
else if (ind[3] == ind[2])
|
|
{
|
|
int tind[] = { ind[0], ind[1], ind[3] };
|
|
PLYWriter::writeFace(fout, 3, tind);
|
|
}
|
|
else if (ind[2] == ind[0])
|
|
{
|
|
int tind[] = { ind[1], ind[3], ind[2] };
|
|
PLYWriter::writeFace(fout, 3, tind);
|
|
}
|
|
else
|
|
{
|
|
int tind1[] = { ind[0], ind[1], ind[3] };
|
|
PLYWriter::writeFace(fout, 3, tind1);
|
|
int tind2[] = { ind[0], ind[3], ind[2] };
|
|
PLYWriter::writeFace(fout, 3, tind2);
|
|
actualTris++;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void Octree::cellProcCount(OctreeNode* node, int& nverts, int& nfaces)
|
|
{
|
|
if (node == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int type = node->getType();
|
|
|
|
if (type > 0)
|
|
{
|
|
nverts++;
|
|
}
|
|
else
|
|
{
|
|
InternalNode* inode = ((InternalNode*)node);
|
|
|
|
// 8 Cell calls
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
cellProcCount(inode->child[i], nverts, nfaces);
|
|
}
|
|
|
|
// 12 face calls
|
|
OctreeNode* fcd[2];
|
|
for (int i = 0; i < 12; i++)
|
|
{
|
|
int c[2] = { cellProcFaceMask[i][0], cellProcFaceMask[i][1] };
|
|
|
|
fcd[0] = inode->child[c[0]];
|
|
fcd[1] = inode->child[c[1]];
|
|
|
|
faceProcCount(fcd, cellProcFaceMask[i][2], nverts, nfaces);
|
|
}
|
|
|
|
// 6 edge calls
|
|
OctreeNode* ecd[4];
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
int c[4] = { cellProcEdgeMask[i][0], cellProcEdgeMask[i][1], cellProcEdgeMask[i][2], cellProcEdgeMask[i][3] };
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
ecd[j] = inode->child[c[j]];
|
|
}
|
|
|
|
edgeProcCount(ecd, cellProcEdgeMask[i][4], nverts, nfaces);
|
|
}
|
|
}
|
|
};
|
|
|
|
void Octree::faceProcCount(OctreeNode* node[2], int dir, int& nverts, int& nfaces)
|
|
{
|
|
if (!(node[0] && node[1]))
|
|
{
|
|
return;
|
|
}
|
|
|
|
int type[2] = { node[0]->getType(), node[1]->getType() };
|
|
|
|
if (type[0] == 0 || type[1] == 0)
|
|
{
|
|
int i, j;
|
|
|
|
// 4 face calls
|
|
OctreeNode* fcd[2];
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int c[2] = { faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1] };
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
if (type[j] > 0)
|
|
{
|
|
fcd[j] = node[j];
|
|
}
|
|
else
|
|
{
|
|
fcd[j] = ((InternalNode*)node[j])->child[c[j]];
|
|
}
|
|
}
|
|
faceProcCount(fcd, faceProcFaceMask[dir][i][2], nverts, nfaces);
|
|
}
|
|
|
|
// 4 edge calls
|
|
int orders[2][4] = { { 0, 0, 1, 1 }, { 0, 1, 0, 1 } };
|
|
OctreeNode* ecd[4];
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int c[4] = { faceProcEdgeMask[dir][i][1], faceProcEdgeMask[dir][i][2],
|
|
faceProcEdgeMask[dir][i][3], faceProcEdgeMask[dir][i][4] };
|
|
int* order = orders[faceProcEdgeMask[dir][i][0]];
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (type[order[j]] > 0)
|
|
{
|
|
ecd[j] = node[order[j]];
|
|
}
|
|
else
|
|
{
|
|
ecd[j] = ((InternalNode*)node[order[j]])->child[c[j]];
|
|
}
|
|
}
|
|
|
|
edgeProcCount(ecd, faceProcEdgeMask[dir][i][5], nverts, nfaces);
|
|
}
|
|
}
|
|
};
|
|
|
|
void Octree::edgeProcCount(OctreeNode* node[4], int dir, int& nverts, int& nfaces)
|
|
{
|
|
if (!(node[0] && node[1] && node[2] && node[3]))
|
|
{
|
|
return;
|
|
}
|
|
|
|
int type[4] = { node[0]->getType(), node[1]->getType(), node[2]->getType(), node[3]->getType() };
|
|
|
|
if (type[0] > 0 && type[1] > 0 && type[2] > 0 && type[3] > 0)
|
|
{
|
|
processEdgeCount(node, dir, nverts, nfaces);
|
|
}
|
|
else
|
|
{
|
|
int i, j;
|
|
|
|
// 2 edge calls
|
|
OctreeNode* ecd[4];
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
int c[4] = { edgeProcEdgeMask[dir][i][0],
|
|
edgeProcEdgeMask[dir][i][1],
|
|
edgeProcEdgeMask[dir][i][2],
|
|
edgeProcEdgeMask[dir][i][3] };
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (type[j] > 0)
|
|
{
|
|
ecd[j] = node[j];
|
|
}
|
|
else
|
|
{
|
|
ecd[j] = ((InternalNode*)node[j])->child[c[j]];
|
|
}
|
|
}
|
|
|
|
edgeProcCount(ecd, edgeProcEdgeMask[dir][i][4], nverts, nfaces);
|
|
}
|
|
}
|
|
};
|
|
|
|
void Octree::processEdgeCount(OctreeNode* node[4], int dir, int& nverts, int& nfaces)
|
|
{
|
|
// Get minimal cell
|
|
int i, type, ht, minht = maxDepth + 1, mini = -1;
|
|
int ind[4], sc[4], flip[4] = { 0,0,0,0 };
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (node[i]->getType() == 1)
|
|
{
|
|
LeafNode* lnode = ((LeafNode*)node[i]);
|
|
|
|
if (lnode->height < minht)
|
|
{
|
|
minht = lnode->height;
|
|
mini = i;
|
|
}
|
|
ind[i] = lnode->index;
|
|
|
|
int ed = processEdgeMask[dir][i];
|
|
int c1 = edgevmap[ed][0];
|
|
int c2 = edgevmap[ed][1];
|
|
|
|
if (lnode->getSign(c1) == lnode->getSign(c2))
|
|
{
|
|
sc[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
sc[i] = 1;
|
|
|
|
if (lnode->getSign(c1) > 0)
|
|
{
|
|
flip[i] = 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PseudoLeafNode* pnode = ((PseudoLeafNode*)node[i]);
|
|
|
|
if (pnode->height < minht)
|
|
{
|
|
minht = pnode->height;
|
|
mini = i;
|
|
}
|
|
ind[i] = pnode->index;
|
|
|
|
int ed = processEdgeMask[dir][i];
|
|
int c1 = edgevmap[ed][0];
|
|
int c2 = edgevmap[ed][1];
|
|
|
|
if (pnode->getSign(c1) == pnode->getSign(c2))
|
|
{
|
|
sc[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
sc[i] = 1;
|
|
|
|
if (pnode->getSign(c1) > 0)
|
|
{
|
|
flip[i] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sc[mini] == 1)
|
|
{
|
|
nfaces++;
|
|
if (node[0] != node[1] && node[1] != node[3] && node[3] != node[2] && node[2] != node[0])
|
|
{
|
|
nfaces++;
|
|
}
|
|
}
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* Start Non-inters */
|
|
/************************************************************************/
|
|
|
|
void Octree::cellProcContourNoInter(OctreeNode* node, int st[3], int len, HashMap2* hash, TriangleList* list, int& numTris)
|
|
{
|
|
if (node == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int type = node->getType();
|
|
|
|
if (type == 0)
|
|
{
|
|
InternalNode* inode = ((InternalNode*)node);
|
|
|
|
// 8 Cell calls
|
|
int nlen = len / 2;
|
|
int nst[3];
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
nst[0] = st[0] + vertMap[i][0] * nlen;
|
|
nst[1] = st[1] + vertMap[i][1] * nlen;
|
|
nst[2] = st[2] + vertMap[i][2] * nlen;
|
|
cellProcContourNoInter(inode->child[i], nst, nlen, hash, list, numTris);
|
|
}
|
|
|
|
// 12 face calls
|
|
OctreeNode* fcd[2];
|
|
int dirCell2[3][4][3] = {
|
|
{{0,-1,-1},{0,-1,0},{0,0,-1},{0,0,0}},
|
|
{{-1,0,-1},{0,0,-1},{-1,0,0},{0,0,0}},
|
|
{{-1,-1,0},{-1,0,0},{0,-1,0},{0,0,0}} };
|
|
for (int i = 0; i < 3; i++)
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
nst[0] = st[0] + nlen + dirCell2[i][j][0] * nlen;
|
|
nst[1] = st[1] + nlen + dirCell2[i][j][1] * nlen;
|
|
nst[2] = st[2] + nlen + dirCell2[i][j][2] * nlen;
|
|
|
|
int ed = i * 4 + j;
|
|
int c[2] = { cellProcFaceMask[ed][0], cellProcFaceMask[ed][1] };
|
|
|
|
fcd[0] = inode->child[c[0]];
|
|
fcd[1] = inode->child[c[1]];
|
|
|
|
faceProcContourNoInter(fcd, nst, nlen, cellProcFaceMask[ed][2], hash, list, numTris);
|
|
}
|
|
|
|
// 6 edge calls
|
|
OctreeNode* ecd[4];
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
int c[4] = { cellProcEdgeMask[i][0], cellProcEdgeMask[i][1], cellProcEdgeMask[i][2], cellProcEdgeMask[i][3] };
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
ecd[j] = inode->child[c[j]];
|
|
}
|
|
|
|
int dir = cellProcEdgeMask[i][4];
|
|
nst[0] = st[0] + nlen;
|
|
nst[1] = st[1] + nlen;
|
|
nst[2] = st[2] + nlen;
|
|
if (i % 2 == 0)
|
|
{
|
|
nst[dir] -= nlen;
|
|
}
|
|
|
|
edgeProcContourNoInter(ecd, nst, nlen, dir, hash, list, numTris);
|
|
}
|
|
}
|
|
};
|
|
|
|
void Octree::faceProcContourNoInter(OctreeNode* node[2], int st[3], int len, int dir, HashMap2* hash, TriangleList* list, int& numTris)
|
|
{
|
|
printf("I am at a face! %d %d %d, %d, %d\n", st[0], st[1], st[2], len, dir);
|
|
if (!(node[0] && node[1]))
|
|
{
|
|
printf("I am none.\n");
|
|
return;
|
|
}
|
|
|
|
int type[2] = { node[0]->getType(), node[1]->getType() };
|
|
|
|
if (type[0] == 0 || type[1] == 0)
|
|
{
|
|
int i, j;
|
|
int nlen = len / 2;
|
|
int nst[3];
|
|
|
|
// 4 face calls
|
|
OctreeNode* fcd[2];
|
|
int iface = faceProcFaceMask[dir][0][0];
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int c[2] = { faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1] };
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
if (type[j] > 0)
|
|
{
|
|
fcd[j] = node[j];
|
|
}
|
|
else
|
|
{
|
|
fcd[j] = ((InternalNode*)node[j])->child[c[j]];
|
|
}
|
|
}
|
|
|
|
nst[0] = st[0] + nlen * (vertMap[c[0]][0] - vertMap[iface][0]);
|
|
nst[1] = st[1] + nlen * (vertMap[c[0]][1] - vertMap[iface][1]);
|
|
nst[2] = st[2] + nlen * (vertMap[c[0]][2] - vertMap[iface][2]);
|
|
|
|
faceProcContourNoInter(fcd, nst, nlen, faceProcFaceMask[dir][i][2], hash, list, numTris);
|
|
}
|
|
|
|
// 4 edge calls
|
|
int orders[2][4] = { { 0, 0, 1, 1 }, { 0, 1, 0, 1 } };
|
|
OctreeNode* ecd[4];
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int c[4] = { faceProcEdgeMask[dir][i][1], faceProcEdgeMask[dir][i][2],
|
|
faceProcEdgeMask[dir][i][3], faceProcEdgeMask[dir][i][4] };
|
|
int* order = orders[faceProcEdgeMask[dir][i][0]];
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (type[order[j]] > 0)
|
|
{
|
|
ecd[j] = node[order[j]];
|
|
}
|
|
else
|
|
{
|
|
ecd[j] = ((InternalNode*)node[order[j]])->child[c[j]];
|
|
}
|
|
}
|
|
|
|
int ndir = faceProcEdgeMask[dir][i][5];
|
|
nst[0] = st[0] + nlen;
|
|
nst[1] = st[1] + nlen;
|
|
nst[2] = st[2] + nlen;
|
|
nst[dir] -= nlen;
|
|
if (i % 2 == 0)
|
|
{
|
|
nst[ndir] -= nlen;
|
|
}
|
|
|
|
edgeProcContourNoInter(ecd, nst, nlen, ndir, hash, list, numTris);
|
|
}
|
|
printf("I am done.\n");
|
|
}
|
|
else
|
|
{
|
|
printf("I don't have any children.\n");
|
|
}
|
|
};
|
|
|
|
void Octree::edgeProcContourNoInter(OctreeNode* node[4], int st[3], int len, int dir, HashMap2* hash, TriangleList* list, int& numTris)
|
|
{
|
|
if (!(node[0] && node[1] && node[2] && node[3]))
|
|
{
|
|
return;
|
|
}
|
|
|
|
int type[4] = { node[0]->getType(), node[1]->getType(), node[2]->getType(), node[3]->getType() };
|
|
|
|
if (type[0] > 0 && type[1] > 0 && type[2] > 0 && type[3] > 0)
|
|
{
|
|
this->processEdgeNoInter(node, st, len, dir, hash, list, numTris);
|
|
}
|
|
else
|
|
{
|
|
int i, j;
|
|
int nlen = len / 2;
|
|
int nst[3];
|
|
|
|
// 2 edge calls
|
|
OctreeNode* ecd[4];
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
int c[4] = { edgeProcEdgeMask[dir][i][0],
|
|
edgeProcEdgeMask[dir][i][1],
|
|
edgeProcEdgeMask[dir][i][2],
|
|
edgeProcEdgeMask[dir][i][3] };
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (type[j] > 0)
|
|
{
|
|
ecd[j] = node[j];
|
|
}
|
|
else
|
|
{
|
|
ecd[j] = ((InternalNode*)node[j])->child[c[j]];
|
|
}
|
|
}
|
|
|
|
nst[0] = st[0];
|
|
nst[1] = st[1];
|
|
nst[2] = st[2];
|
|
nst[dir] += nlen * i;
|
|
|
|
edgeProcContourNoInter(ecd, nst, nlen, edgeProcEdgeMask[dir][i][4], hash, list, numTris);
|
|
}
|
|
}
|
|
};
|
|
|
|
void Octree::processEdgeNoInter(OctreeNode* node[4], int st[3], int len, int dir, HashMap2* hash, TriangleList* list, int& numTris)
|
|
{
|
|
// Get minimal cell
|
|
int i, type, minht = maxDepth + 1, mini = -1;
|
|
int ind[4], sc[4], flip[4] = { 0,0,0,0 }, ht[4];
|
|
float mp[4][3];
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (node[i]->getType() == 1)
|
|
{
|
|
LeafNode* lnode = ((LeafNode*)node[i]);
|
|
ht[i] = lnode->height;
|
|
mp[i][0] = lnode->mp[0];
|
|
mp[i][1] = lnode->mp[1];
|
|
mp[i][2] = lnode->mp[2];
|
|
|
|
if (lnode->height < minht)
|
|
{
|
|
minht = lnode->height;
|
|
mini = i;
|
|
}
|
|
ind[i] = lnode->index;
|
|
|
|
int ed = processEdgeMask[dir][i];
|
|
int c1 = edgevmap[ed][0];
|
|
int c2 = edgevmap[ed][1];
|
|
|
|
if (lnode->getSign(c1) == lnode->getSign(c2))
|
|
{
|
|
sc[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
sc[i] = 1;
|
|
}
|
|
}
|
|
else if (node[i]->getType() == 2)
|
|
{
|
|
PseudoLeafNode* pnode = ((PseudoLeafNode*)node[i]);
|
|
ht[i] = pnode->height;
|
|
mp[i][0] = pnode->mp[0];
|
|
mp[i][1] = pnode->mp[1];
|
|
mp[i][2] = pnode->mp[2];
|
|
|
|
if (pnode->height < minht)
|
|
{
|
|
minht = pnode->height;
|
|
mini = i;
|
|
}
|
|
ind[i] = pnode->index;
|
|
|
|
int ed = processEdgeMask[dir][i];
|
|
int c1 = edgevmap[ed][0];
|
|
int c2 = edgevmap[ed][1];
|
|
|
|
if (pnode->getSign(c1) == pnode->getSign(c2))
|
|
{
|
|
sc[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
sc[i] = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Wrong!\n");
|
|
}
|
|
}
|
|
|
|
if (sc[mini] == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Performing test */
|
|
/************************************************************************/
|
|
|
|
float fverts[4][3];
|
|
int hasFverts[4] = { 0, 0, 0, 0 };
|
|
float evert[3] = { 0,0,0 };
|
|
int needTess = 0;
|
|
|
|
// First, face test
|
|
int nbr[4][2] = { {0,1},{1,3},{2,3},{0,2} };
|
|
int fdir[3][4] = {
|
|
{2,1,2,1},
|
|
{0,2,0,2},
|
|
{1,0,1,0} };
|
|
int dir3[3][4][2] = {
|
|
{{1, -1},{2, 0},{1, 0},{2, -1}},
|
|
{{2, -1},{0, 0},{2, 0},{0, -1}},
|
|
{{0, -1},{1, 0},{0, 0},{1, -1}} };
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int a = nbr[i][0];
|
|
int b = nbr[i][1];
|
|
|
|
if (ht[a] != ht[b])
|
|
{
|
|
// Different level, check if the dual edge passes through the face
|
|
if (hash->FindKey(reinterpret_cast<std::intptr_t>(node[a]), reinterpret_cast<std::intptr_t>(node[b]), fverts[i]))
|
|
{
|
|
// The vertex was found previously
|
|
founds++;
|
|
hasFverts[i] = 1;
|
|
needTess = 1;
|
|
}
|
|
else
|
|
{
|
|
// Otherwise, we test it here
|
|
int sht = (ht[a] > ht[b] ? ht[b] : ht[a]);
|
|
int flen = (1 << sht);
|
|
int fst[3];
|
|
|
|
fst[fdir[dir][i]] = st[fdir[dir][i]];
|
|
fst[dir3[dir][i][0]] = st[dir3[dir][i][0]] + flen * dir3[dir][i][1];
|
|
fst[dir] = st[dir] - (st[dir] & ((1 << sht) - 1));
|
|
|
|
if (testFace(fst, flen, fdir[dir][i], mp[a], mp[b]) == 0)
|
|
{
|
|
// Dual edge does not pass face, let's make a new vertex
|
|
makeFaceVertex(fst, flen, fdir[dir][i], node[a], node[b], fverts[i]);
|
|
hash->InsertKey(reinterpret_cast<std::intptr_t>(node[a]), reinterpret_cast<std::intptr_t>(node[b]), fverts[i]);
|
|
hasFverts[i] = 1;
|
|
needTess = 1;
|
|
news++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Next, edge test
|
|
int diag = 1;
|
|
if (needTess == 0)
|
|
{
|
|
// Even if all dual edges pass through faces, the dual complex of an edge may not be convex
|
|
//int st2[3] = { st[0], st[1], st[2] } ;
|
|
//st2[ dir ] += len ;
|
|
|
|
diag = testEdge(st, len, dir, node, mp);
|
|
if (diag == 0)
|
|
{
|
|
// When this happens, we need to create an extra vertex on the primal edge
|
|
needTess = 1;
|
|
}
|
|
}
|
|
|
|
if (needTess)
|
|
{
|
|
edgeVerts++;
|
|
makeEdgeVertex(st, len, dir, node, mp, evert);
|
|
|
|
/* Just take centroid
|
|
int num = 0 ;
|
|
evert[0] = st[0] ;
|
|
evert[1] = st[1] ;
|
|
evert[2] = st[2] ;
|
|
evert[dir] = 0 ;
|
|
for ( i = 0 ; i < 4 ; i ++ )
|
|
{
|
|
evert[dir] += mp[i][dir] ;
|
|
num ++ ;
|
|
|
|
if ( hasFverts[ i ] )
|
|
{
|
|
evert[dir] += fverts[i][dir] ;
|
|
num ++ ;
|
|
}
|
|
}
|
|
evert[dir] /= num ;
|
|
*/
|
|
|
|
/* Avoid bad triangles
|
|
int dir2 = ( dir + 1 ) % 3 ;
|
|
int dir3 = ( dir2 + 1 ) % 3 ;
|
|
float epsilon = 0.01f ;
|
|
for ( i = 0 ; i < 4 ; i ++ )
|
|
{
|
|
if ( hasFverts[ i ] && fabs( fverts[i][dir2] - st[dir2] ) < epsilon && fabs( fverts[i][dir3] - st[dir3] ) < epsilon )
|
|
{
|
|
evert[dir] = fverts[i][dir] ;
|
|
break ;
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
if ( evert[dir] < st[dir] )
|
|
{
|
|
evert[dir] = st[dir] ;
|
|
}
|
|
else if ( evert[dir] > st[dir] + len )
|
|
{
|
|
evert[dir] = st[dir] + len ;
|
|
}
|
|
*/
|
|
}
|
|
|
|
// Finally, let's output triangle
|
|
if (needTess == 0)
|
|
{
|
|
// Normal splitting of quad
|
|
if (diag == 1)
|
|
{
|
|
if (node[0] != node[1] && node[1] != node[3])
|
|
{
|
|
int tind1[] = { 0,1,3 };
|
|
|
|
numTris++;
|
|
TriangleList* t1 = new TriangleList;
|
|
t1->next = list->next;
|
|
list->next = t1;
|
|
for (int j = 0; j < 3; j++)
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
t1->vt[j][k] = mp[tind1[j]][k];
|
|
}
|
|
}
|
|
|
|
if (node[3] != node[2] && node[2] != node[0])
|
|
{
|
|
int tind2[] = { 3,2,0 };
|
|
|
|
numTris++;
|
|
TriangleList* t2 = new TriangleList;
|
|
t2->next = list->next;
|
|
list->next = t2;
|
|
for (int j = 0; j < 3; j++)
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
t2->vt[j][k] = mp[tind2[j]][k];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (node[0] != node[1] && node[1] != node[2])
|
|
{
|
|
int tind1[] = { 0,1,2 };
|
|
|
|
numTris++;
|
|
TriangleList* t1 = new TriangleList;
|
|
t1->next = list->next;
|
|
list->next = t1;
|
|
for (int j = 0; j < 3; j++)
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
t1->vt[j][k] = mp[tind1[j]][k];
|
|
}
|
|
}
|
|
|
|
if (node[1] != node[3] && node[3] != node[2])
|
|
{
|
|
int tind2[] = { 1,3,2 };
|
|
|
|
numTris++;
|
|
TriangleList* t2 = new TriangleList;
|
|
t2->next = list->next;
|
|
list->next = t2;
|
|
for (int j = 0; j < 3; j++)
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
t2->vt[j][k] = mp[tind2[j]][k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Center-splitting
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int a = nbr[i][0];
|
|
int b = nbr[i][1];
|
|
|
|
if (hasFverts[i])
|
|
{
|
|
// Further split each triangle into two
|
|
numTris += 2;
|
|
|
|
TriangleList* t = new TriangleList;
|
|
t->next = list->next;
|
|
list->next = t;
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
t->vt[0][k] = mp[a][k];
|
|
t->vt[1][k] = evert[k];
|
|
t->vt[2][k] = fverts[i][k];
|
|
}
|
|
|
|
t = new TriangleList;
|
|
t->next = list->next;
|
|
list->next = t;
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
t->vt[0][k] = mp[b][k];
|
|
t->vt[1][k] = evert[k];
|
|
t->vt[2][k] = fverts[i][k];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// For one triangle with center vertex
|
|
if (node[a] != node[b])
|
|
{
|
|
numTris++;
|
|
TriangleList* t = new TriangleList;
|
|
t->next = list->next;
|
|
list->next = t;
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
t->vt[0][k] = mp[a][k];
|
|
t->vt[1][k] = mp[b][k];
|
|
t->vt[2][k] = evert[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
int Octree::testFace(int st[3], int len, int dir, float v1[3], float v2[3])
|
|
{
|
|
#ifdef TESS_UNIFORM
|
|
return 0;
|
|
#endif
|
|
|
|
#ifdef TESS_NONE
|
|
return 1;
|
|
#endif
|
|
float vec[3] = { v2[0] - v1[0], v2[1] - v1[1], v2[2] - v1[2] };
|
|
float ax1[3], ax2[3];
|
|
float ed1[3] = { 0,0,0 }, ed2[3] = { 0,0,0 };
|
|
ed1[(dir + 1) % 3] = 1;
|
|
ed2[(dir + 2) % 3] = 1;
|
|
|
|
Intersection::cross(ed1, vec, ax1);
|
|
Intersection::cross(ed2, vec, ax2);
|
|
|
|
Triangle* t1 = new Triangle;
|
|
Triangle* t2 = new Triangle;
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
t1->vt[0][i] = v1[i];
|
|
t1->vt[1][i] = v2[i];
|
|
t1->vt[2][i] = v2[i];
|
|
|
|
t2->vt[0][i] = st[i];
|
|
t2->vt[1][i] = st[i];
|
|
t2->vt[2][i] = st[i];
|
|
}
|
|
t2->vt[1][(dir + 1) % 3] += len;
|
|
t2->vt[2][(dir + 2) % 3] += len;
|
|
|
|
if (Intersection::separating(ax1, t1, t2) || Intersection::separating(ax2, t1, t2))
|
|
{
|
|
faceVerts++;
|
|
/*
|
|
printf("\n{{{%d, %d, %d},%d,%d},{{%f, %f, %f},{%f, %f, %f}}}\n",
|
|
st[0],st[1], st[2],
|
|
len, dir+1,
|
|
v1[0], v1[1], v1[2],
|
|
v2[0], v2[1], v2[2]) ;
|
|
*/
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
int Octree::testEdge(int st[3], int len, int dir, OctreeNode* node[4], float v[4][3])
|
|
{
|
|
#ifdef TESS_UNIFORM
|
|
return 0;
|
|
#endif
|
|
|
|
#ifdef TESS_NONE
|
|
return 1;
|
|
#endif
|
|
|
|
if (node[0] == node[1] || node[1] == node[3] || node[3] == node[2] || node[2] == node[0])
|
|
{
|
|
// return 1 ;
|
|
}
|
|
|
|
float p1[3] = { (float)st[0], (float)st[1], (float)st[2] };
|
|
float p2[3] = { (float)st[0], (float)st[1], (float)st[2] };
|
|
p2[dir] += len;
|
|
|
|
int nbr[] = { 0,1,3,2,0 };
|
|
int nbr2[] = { 3,2,0,1,3 };
|
|
float nm[3], vec1[4][3], vec2[4][3];
|
|
float d1, d2;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
vec1[i][j] = v[i][j] - p1[j];
|
|
vec2[i][j] = v[i][j] - p2[j];
|
|
}
|
|
}
|
|
|
|
#ifdef EDGE_TEST_CONVEXITY
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int a = nbr[i];
|
|
int b = nbr[i + 1];
|
|
int c = nbr2[i];
|
|
int d = nbr2[i + 1];
|
|
|
|
if (node[a] == node[b])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Intersection::cross(vec1[a], vec1[b], nm);
|
|
d1 = Intersection::dot(vec1[c], nm);
|
|
d2 = Intersection::dot(vec1[d], nm);
|
|
|
|
if (d1 * d2 < 0)
|
|
{
|
|
/*
|
|
printf("1\n{{{%f, %f, %f},{%f, %f, %f}},{{%f, %f, %f},{%f, %f, %f},{%f, %f, %f},{%f, %f, %f}}}\n",
|
|
p1[0], p1[1], p1[2],
|
|
p2[0], p2[1], p2[2],
|
|
v[0][0], v[0][1], v[0][2],
|
|
v[1][0], v[1][1], v[1][2],
|
|
v[2][0], v[2][1], v[2][2],
|
|
v[3][0], v[3][1], v[3][2]) ;
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
Intersection::cross(vec2[a], vec2[b], nm);
|
|
d1 = Intersection::dot(vec2[c], nm);
|
|
d2 = Intersection::dot(vec2[d], nm);
|
|
|
|
if (d1 * d2 < 0)
|
|
{
|
|
/*
|
|
printf("2\n{{{%f, %f, %f},{%f, %f, %f}},{{%f, %f, %f},{%f, %f, %f},{%f, %f, %f},{%f, %f, %f}}}\n",
|
|
p1[0], p1[1], p1[2],
|
|
p2[0], p2[1], p2[2],
|
|
v[0][0], v[0][1], v[0][2],
|
|
v[1][0], v[1][1], v[1][2],
|
|
v[2][0], v[2][1], v[2][2],
|
|
v[3][0], v[3][1], v[3][2]) ;
|
|
*/
|
|
return 0;
|
|
}
|
|
}
|
|
#else
|
|
#ifdef EDGE_TEST_FLIPDIAGONAL
|
|
Triangle* t1 = new Triangle;
|
|
Triangle* t2 = new Triangle;
|
|
int tri[2][2][4] = { {{0,1,3,2},{3,2,0,1}},{{2,0,1,3},{1,3,2,0}} };
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
int good = 1;
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
// Top
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
t1->vt[0][k] = v[tri[i][j][0]][k];
|
|
t1->vt[1][k] = v[tri[i][j][1]][k];
|
|
t1->vt[2][k] = v[tri[i][j][2]][k];
|
|
|
|
t2->vt[0][k] = p1[k];
|
|
t2->vt[1][k] = v[tri[i][j][2]][k];
|
|
t2->vt[2][k] = v[tri[i][j][3]][k];
|
|
}
|
|
|
|
if (Intersection::testIntersection(t1, t2))
|
|
{
|
|
good = 0;
|
|
break;
|
|
}
|
|
|
|
// Bottom
|
|
for (k = 0; k < 3; k++)
|
|
{
|
|
t2->vt[0][k] = p2[k];
|
|
t2->vt[1][k] = v[tri[i][j][2]][k];
|
|
t2->vt[2][k] = v[tri[i][j][3]][k];
|
|
}
|
|
|
|
if (Intersection::testIntersection(t1, t2))
|
|
{
|
|
good = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (good)
|
|
{
|
|
return (i + 1);
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
#else
|
|
#ifdef EDGE_TEST_NEW
|
|
Triangle* t1 = new Triangle;
|
|
int tri[2][2][4] = { {{0,1,3,2},{3,2,0,1}},{{2,0,1,3},{1,3,2,0}} };
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
// For each triangulation
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
// Starting with each triangle
|
|
int k;
|
|
|
|
// Check triangle and dual edge
|
|
float vec1[3], vec2[3], vec3[3], vec[3];
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
t1->vt[0][k] = v[tri[i][j][0]][k];
|
|
t1->vt[1][k] = v[tri[i][j][1]][k];
|
|
t1->vt[2][k] = v[tri[i][j][2]][k];
|
|
|
|
vec1[k] = t1->vt[1][k] - t1->vt[0][k];
|
|
vec2[k] = t1->vt[2][k] - t1->vt[1][k];
|
|
}
|
|
|
|
float axes[3];
|
|
Intersection::cross(vec1, vec2, axes);
|
|
|
|
if (Intersection::separating(axes, t1, p1, p2))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check diagonal and the other triangle
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
t1->vt[0][k] = p1[k];
|
|
t1->vt[1][k] = p2[k];
|
|
t1->vt[2][k] = v[tri[i][j][3]][k];
|
|
|
|
vec1[k] = t1->vt[1][k] - t1->vt[0][k];
|
|
vec2[k] = t1->vt[2][k] - t1->vt[1][k];
|
|
vec3[k] = t1->vt[0][k] - t1->vt[2][k];
|
|
|
|
vec[k] = v[tri[i][j][2]][k] - v[tri[i][j][0]][k];
|
|
}
|
|
|
|
float axes1[3], axes2[3], axes3[3];
|
|
Intersection::cross(vec1, vec, axes1);
|
|
Intersection::cross(vec2, vec, axes2);
|
|
Intersection::cross(vec3, vec, axes3);
|
|
|
|
if (Intersection::separating(axes1, t1, v[tri[i][j][0]], v[tri[i][j][2]]) ||
|
|
Intersection::separating(axes2, t1, v[tri[i][j][0]], v[tri[i][j][2]]) ||
|
|
Intersection::separating(axes3, t1, v[tri[i][j][0]], v[tri[i][j][2]]))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return (i + 1);
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
#endif
|
|
|
|
return 1;
|
|
};
|
|
|
|
void Octree::makeFaceVertex(int st[3], int len, int dir, OctreeNode* node1, OctreeNode* node2, float v[3])
|
|
{
|
|
int nlen = len / 2;
|
|
v[0] = st[0] + nlen;
|
|
v[1] = st[1] + nlen;
|
|
v[2] = st[2] + nlen;
|
|
v[dir] -= nlen;
|
|
|
|
// return ;
|
|
|
|
// if ( this->hasQEF == 0 )
|
|
// {
|
|
// return ;
|
|
// }
|
|
|
|
int i, j;
|
|
float ata[6] = { 0, 0, 0, 0, 0, 0 };
|
|
float atb[3] = { 0, 0, 0 };
|
|
float btb = 0;
|
|
OctreeNode* node[2] = { node1, node2 };
|
|
|
|
// Gather QEF
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
if (node[j]->getType() == 1)
|
|
{
|
|
LeafNode* lnode = ((LeafNode*)node[j]);
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
ata[i] += lnode->ata[i];
|
|
}
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
atb[i] += lnode->atb[i];
|
|
}
|
|
btb += lnode->btb;
|
|
}
|
|
else
|
|
{
|
|
PseudoLeafNode* lnode = ((PseudoLeafNode*)node[j]);
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
ata[i] += lnode->ata[i];
|
|
}
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
atb[i] += lnode->atb[i];
|
|
}
|
|
btb += lnode->btb;
|
|
}
|
|
}
|
|
|
|
// Form 2 by 2 matrix nata and 2-vector natb
|
|
float nata[2][2], natb[2];
|
|
int dir2, dir3;
|
|
switch (dir)
|
|
{
|
|
case 0:
|
|
nata[0][0] = ata[3];
|
|
nata[0][1] = ata[4];
|
|
nata[1][0] = ata[4];
|
|
nata[1][1] = ata[5];
|
|
natb[0] = atb[1] - st[dir] * ata[1];
|
|
natb[1] = atb[2] - st[dir] * ata[2];
|
|
dir2 = 1;
|
|
dir3 = 2;
|
|
break;
|
|
case 1:
|
|
nata[0][0] = ata[0];
|
|
nata[0][1] = ata[2];
|
|
nata[1][0] = ata[2];
|
|
nata[1][1] = ata[5];
|
|
natb[0] = atb[0] - st[dir] * ata[1];
|
|
natb[1] = atb[2] - st[dir] * ata[4];
|
|
dir2 = 0;
|
|
dir3 = 2;
|
|
break;
|
|
case 2:
|
|
nata[0][0] = ata[0];
|
|
nata[0][1] = ata[1];
|
|
nata[1][0] = ata[1];
|
|
nata[1][1] = ata[3];
|
|
natb[0] = atb[0] - st[dir] * ata[2];
|
|
natb[1] = atb[1] - st[dir] * ata[4];
|
|
dir2 = 0;
|
|
dir3 = 1;
|
|
break;
|
|
}
|
|
|
|
// Solve
|
|
float det = nata[0][0] * nata[1][1] - nata[0][1] * nata[1][0];
|
|
if (det == 0)
|
|
{
|
|
/*
|
|
float a2 = nata[ 0 ][ 0 ] * nata[ 0 ][ 0 ] ;
|
|
float b2 = nata[ 0 ][ 1 ] * nata[ 1 ][ 0 ] ;
|
|
float det2 = ( a2 + b2 ) * ( a2 + b2 ) ;
|
|
inv[ 0 ][ 0 ] = nata[ 0 ][ 0 ] * a2 / det2 ;
|
|
inv[ 0 ][ 1 ] = nata[ 0 ][ 1 ] * a2 / det2 ;
|
|
inv[ 1 ][ 0 ] = nata[ 1 ][ 0 ] * a2 / det2 ;
|
|
inv[ 1 ][ 1 ] = nata[ 1 ][ 1 ] * a2 / det2 ;
|
|
*/
|
|
//printf("det is zero.\n") ;
|
|
|
|
float cent[2] = { 0, 0 };
|
|
int n = 0;
|
|
float x, y;
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if (nata[i][0] != 0)
|
|
{
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
y = st[dir3] + len * j;
|
|
x = (natb[i] - nata[i][1] * y) / nata[i][0];
|
|
if (x >= st[dir2] && x <= st[dir2] + len)
|
|
{
|
|
cent[0] += x;
|
|
cent[1] += y;
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
if (nata[i][1] != 0)
|
|
{
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
x = st[dir2] + len * j;
|
|
y = (natb[i] - nata[i][0] * x) / nata[i][1];
|
|
if (y >= st[dir3] && y <= st[dir3] + len)
|
|
{
|
|
cent[0] += x;
|
|
cent[1] += y;
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (n > 0)
|
|
{
|
|
v[dir2] = cent[0] / n;
|
|
v[dir3] = cent[1] / n;
|
|
}
|
|
else
|
|
{
|
|
printf("No good choices of face points.\n");
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
float inv[2][2];
|
|
inv[0][0] = nata[1][1] / det;
|
|
inv[0][1] = -nata[0][1] / det;
|
|
inv[1][0] = -nata[0][1] / det;
|
|
inv[1][1] = nata[0][0] / det;
|
|
|
|
v[dir2] = inv[0][0] * natb[0] + inv[0][1] * natb[1];
|
|
v[dir3] = inv[1][0] * natb[0] + inv[1][1] * natb[1];
|
|
|
|
if (v[dir2] < st[dir2])
|
|
{
|
|
v[dir2] = st[dir2];
|
|
}
|
|
else if (v[dir2] > st[dir2] + len)
|
|
{
|
|
v[dir2] = st[dir2] + len;
|
|
}
|
|
|
|
if (v[dir3] < st[dir3])
|
|
{
|
|
v[dir3] = st[dir3];
|
|
}
|
|
else if (v[dir3] > st[dir3] + len)
|
|
{
|
|
v[dir3] = st[dir3] + len;
|
|
}
|
|
}
|
|
};
|
|
|
|
void Octree::makeEdgeVertex(int st[3], int len, int dir, OctreeNode* node[4], float mp[4][3], float v[3])
|
|
{
|
|
int nlen = len / 2;
|
|
v[0] = st[0];
|
|
v[1] = st[1];
|
|
v[2] = st[2];
|
|
v[dir] += nlen;
|
|
|
|
//return ;
|
|
|
|
// if ( this->hasQEF == 0 )
|
|
// {
|
|
// return ;
|
|
// }
|
|
|
|
/* QEF based method
|
|
|
|
int i, j ;
|
|
float ata[6] = { 0, 0, 0, 0, 0, 0 };
|
|
float atb[3] = { 0, 0, 0 } ;
|
|
float btb = 0 ;
|
|
|
|
// Gather QEF
|
|
for ( j = 0 ; j < 4 ; j ++ )
|
|
{
|
|
if ( node[j]->getType() == 1 )
|
|
{
|
|
LeafNode* lnode = ((LeafNode *) node[j]) ;
|
|
for ( i = 0 ; i < 6 ; i ++ )
|
|
{
|
|
ata[i] += lnode->ata[i] ;
|
|
}
|
|
for ( i = 0 ; i < 3 ; i ++ )
|
|
{
|
|
atb[i] += lnode->atb[i] ;
|
|
}
|
|
btb += lnode->btb ;
|
|
}
|
|
else
|
|
{
|
|
PseudoLeafNode* lnode = ((PseudoLeafNode *) node[j]) ;
|
|
for ( i = 0 ; i < 6 ; i ++ )
|
|
{
|
|
ata[i] += lnode->ata[i] ;
|
|
}
|
|
for ( i = 0 ; i < 3 ; i ++ )
|
|
{
|
|
atb[i] += lnode->atb[i] ;
|
|
}
|
|
btb += lnode->btb ;
|
|
}
|
|
}
|
|
|
|
// Find coefficient A and b
|
|
float A, b ;
|
|
switch ( dir )
|
|
{
|
|
case 0 :
|
|
A = ata[ 0 ] ;
|
|
b = atb[ 0 ] - ata[ 1 ] * st[ 1 ] - ata[ 2 ] * st[ 2 ] ;
|
|
break ;
|
|
case 1 :
|
|
A = ata[ 3 ] ;
|
|
b = atb[ 1 ] - ata[ 1 ] * st[ 0 ] - ata[ 4 ] * st[ 2 ] ;
|
|
break ;
|
|
case 2 :
|
|
A = ata[ 5 ] ;
|
|
b = atb[ 2 ] - ata[ 2 ] * st[ 0 ] - ata[ 4 ] * st[ 1 ] ;
|
|
break ;
|
|
}
|
|
|
|
if ( A == 0 )
|
|
{
|
|
printf("A is zero!\n") ;
|
|
return ;
|
|
}
|
|
else
|
|
{
|
|
v[ dir ] = b / A ;
|
|
if ( v[ dir ] < st[ dir ] )
|
|
{
|
|
v[ dir ] = st[ dir ] ;
|
|
}
|
|
else if ( v[ dir ] > st[ dir ] + len)
|
|
{
|
|
v[ dir ] = st[ dir ] + len ;
|
|
}
|
|
}
|
|
*/
|
|
|
|
/* Barycentric approach */
|
|
float pt[4][2], pv[4], x[2];
|
|
int dir2 = (dir + 1) % 3;
|
|
int dir3 = (dir2 + 1) % 3;
|
|
int seq[] = { 0,1,3,2 };
|
|
float epsilon = 0.000001f;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
pt[i][0] = mp[seq[i]][dir2];
|
|
pt[i][1] = mp[seq[i]][dir3];
|
|
pv[i] = mp[seq[i]][dir];
|
|
}
|
|
x[0] = st[dir2];
|
|
x[1] = st[dir3];
|
|
|
|
// Compute mean-value interpolation
|
|
|
|
float vec[4][2], d[4];
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
vec[i][0] = pt[i][0] - x[0];
|
|
vec[i][1] = pt[i][1] - x[1];
|
|
|
|
d[i] = sqrt(vec[i][0] * vec[i][0] + vec[i][1] * vec[i][1]);
|
|
|
|
if (d[i] < epsilon)
|
|
{
|
|
v[dir] = pv[i];
|
|
if (v[dir] < st[dir])
|
|
{
|
|
v[dir] = st[dir];
|
|
}
|
|
else if (v[dir] > st[dir] + len)
|
|
{
|
|
v[dir] = st[dir] + len;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
float w[4] = { 0,0,0,0 }, totw = 0;
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
int i2 = (i + 1) % 4;
|
|
float sine = (vec[i][0] * vec[i2][1] - vec[i][1] * vec[i2][0]) / (d[i] * d[i2]);
|
|
float cosine = (vec[i][0] * vec[i2][0] + vec[i][1] * vec[i2][1]) / (d[i] * d[i2]);
|
|
|
|
if (fabs(cosine + 1) < epsilon)
|
|
{
|
|
v[dir] = (pv[i] * d[i2] + pv[i2] * d[i]) / (d[i] + d[i2]);
|
|
|
|
if (v[dir] < st[dir])
|
|
{
|
|
v[dir] = st[dir];
|
|
}
|
|
else if (v[dir] > st[dir] + len)
|
|
{
|
|
v[dir] = st[dir] + len;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
float tan2 = sine / (1 + cosine);
|
|
|
|
w[i] += (tan2 / d[i]);
|
|
w[i2] += (tan2 / d[i2]);
|
|
|
|
totw += (tan2 / d[i]);
|
|
totw += (tan2 / d[i2]);
|
|
}
|
|
|
|
v[dir] = 0;
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
v[dir] += (w[i] * pv[i] / totw);
|
|
}
|
|
/**/
|
|
if (v[dir] < st[dir])
|
|
{
|
|
v[dir] = st[dir];
|
|
}
|
|
else if (v[dir] > st[dir] + len)
|
|
{
|
|
v[dir] = st[dir] + len;
|
|
}
|
|
};
|
|
|
|
void Octree::cellProcContourNoInter2(OctreeNode* node, int st[3], int len, HashMap* hash, IndexedTriangleList* tlist, int& numTris, VertexList* vlist, int& numVerts)
|
|
{
|
|
// printf("I am at a cell! %d %d %d, %d \n", st[0], st[1], st[2], len ) ;
|
|
if (node == NULL)
|
|
{
|
|
// printf("Empty cell.\n") ;
|
|
return;
|
|
}
|
|
|
|
int type = node->getType();
|
|
|
|
if (type == 0)
|
|
{
|
|
InternalNode* inode = ((InternalNode*)node);
|
|
|
|
// 8 Cell calls
|
|
// printf("Process cell calls!\n") ;
|
|
int nlen = len / 2;
|
|
int nst[3];
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
// printf("Cell %d..\n", i) ;
|
|
nst[0] = st[0] + vertMap[i][0] * nlen;
|
|
nst[1] = st[1] + vertMap[i][1] * nlen;
|
|
nst[2] = st[2] + vertMap[i][2] * nlen;
|
|
cellProcContourNoInter2(inode->child[i], nst, nlen, hash, tlist, numTris, vlist, numVerts);
|
|
// printf("Return from %d %d %d, %d \n", nst[0], nst[1], nst[2], nlen ) ;
|
|
}
|
|
// printf("I am done with cells!\n") ;
|
|
|
|
// 12 face calls
|
|
// printf("Process face calls!\n") ;
|
|
OctreeNode* fcd[2];
|
|
int dirCell2[3][4][3] = {
|
|
{{0,-1,-1},{0,-1,0},{0,0,-1},{0,0,0}},
|
|
{{-1,0,-1},{0,0,-1},{-1,0,0},{0,0,0}},
|
|
{{-1,-1,0},{-1,0,0},{0,-1,0},{0,0,0}} };
|
|
for (int i = 0; i < 3; i++)
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
nst[0] = st[0] + nlen + dirCell2[i][j][0] * nlen;
|
|
nst[1] = st[1] + nlen + dirCell2[i][j][1] * nlen;
|
|
nst[2] = st[2] + nlen + dirCell2[i][j][2] * nlen;
|
|
|
|
int ed = i * 4 + j;
|
|
int c[2] = { cellProcFaceMask[ed][0], cellProcFaceMask[ed][1] };
|
|
|
|
fcd[0] = inode->child[c[0]];
|
|
fcd[1] = inode->child[c[1]];
|
|
|
|
faceProcContourNoInter2(fcd, nst, nlen, cellProcFaceMask[ed][2], hash, tlist, numTris, vlist, numVerts);
|
|
}
|
|
// printf("I am done with faces!\n") ;
|
|
|
|
// 6 edge calls
|
|
// printf("Process edge calls!\n") ;
|
|
OctreeNode* ecd[4];
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
int c[4] = { cellProcEdgeMask[i][0], cellProcEdgeMask[i][1], cellProcEdgeMask[i][2], cellProcEdgeMask[i][3] };
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
ecd[j] = inode->child[c[j]];
|
|
}
|
|
|
|
int dir = cellProcEdgeMask[i][4];
|
|
nst[0] = st[0] + nlen;
|
|
nst[1] = st[1] + nlen;
|
|
nst[2] = st[2] + nlen;
|
|
if (i % 2 == 0)
|
|
{
|
|
nst[dir] -= nlen;
|
|
}
|
|
|
|
edgeProcContourNoInter2(ecd, nst, nlen, dir, hash, tlist, numTris, vlist, numVerts);
|
|
}
|
|
// printf("I am done with edges!\n") ;
|
|
}
|
|
// printf("I am done with cell %d %d %d, %d \n", st[0], st[1], st[2], len ) ;
|
|
};
|
|
|
|
void Octree::faceProcContourNoInter2(OctreeNode* node[2], int st[3], int len, int dir, HashMap* hash, IndexedTriangleList* tlist, int& numTris, VertexList* vlist, int& numVerts)
|
|
{
|
|
// printf("I am at a face! %d %d %d, %d, %d\n", st[0], st[1], st[2], len, dir ) ;
|
|
if (!(node[0] && node[1]))
|
|
{
|
|
// printf("I am none.\n") ;
|
|
return;
|
|
}
|
|
|
|
int type[2] = { node[0]->getType(), node[1]->getType() };
|
|
|
|
if (type[0] == 0 || type[1] == 0)
|
|
{
|
|
int i, j;
|
|
int nlen = len / 2;
|
|
int nst[3];
|
|
|
|
// 4 face calls
|
|
OctreeNode* fcd[2];
|
|
int iface = faceProcFaceMask[dir][0][0];
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int c[2] = { faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1] };
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
if (type[j] > 0)
|
|
{
|
|
fcd[j] = node[j];
|
|
}
|
|
else
|
|
{
|
|
fcd[j] = ((InternalNode*)node[j])->child[c[j]];
|
|
}
|
|
}
|
|
|
|
nst[0] = st[0] + nlen * (vertMap[c[0]][0] - vertMap[iface][0]);
|
|
nst[1] = st[1] + nlen * (vertMap[c[0]][1] - vertMap[iface][1]);
|
|
nst[2] = st[2] + nlen * (vertMap[c[0]][2] - vertMap[iface][2]);
|
|
|
|
faceProcContourNoInter2(fcd, nst, nlen, faceProcFaceMask[dir][i][2], hash, tlist, numTris, vlist, numVerts);
|
|
}
|
|
|
|
// 4 edge calls
|
|
int orders[2][4] = { { 0, 0, 1, 1 }, { 0, 1, 0, 1 } };
|
|
OctreeNode* ecd[4];
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int c[4] = { faceProcEdgeMask[dir][i][1], faceProcEdgeMask[dir][i][2],
|
|
faceProcEdgeMask[dir][i][3], faceProcEdgeMask[dir][i][4] };
|
|
int* order = orders[faceProcEdgeMask[dir][i][0]];
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (type[order[j]] > 0)
|
|
{
|
|
ecd[j] = node[order[j]];
|
|
}
|
|
else
|
|
{
|
|
ecd[j] = ((InternalNode*)node[order[j]])->child[c[j]];
|
|
}
|
|
}
|
|
|
|
int ndir = faceProcEdgeMask[dir][i][5];
|
|
nst[0] = st[0] + nlen;
|
|
nst[1] = st[1] + nlen;
|
|
nst[2] = st[2] + nlen;
|
|
nst[dir] -= nlen;
|
|
if (i % 2 == 0)
|
|
{
|
|
nst[ndir] -= nlen;
|
|
}
|
|
|
|
edgeProcContourNoInter2(ecd, nst, nlen, ndir, hash, tlist, numTris, vlist, numVerts);
|
|
}
|
|
// printf("I am done.\n") ;
|
|
}
|
|
else
|
|
{
|
|
// printf("i don't have children.\n");
|
|
}
|
|
};
|
|
|
|
void Octree::edgeProcContourNoInter2(OctreeNode* node[4], int st[3], int len, int dir, HashMap* hash, IndexedTriangleList* tlist, int& numTris, VertexList* vlist, int& numVerts)
|
|
{
|
|
// printf("I am at an edge! %d %d %d \n", st[0], st[1], st[2] ) ;
|
|
if (!(node[0] && node[1] && node[2] && node[3]))
|
|
{
|
|
// printf("I am done!\n") ;
|
|
return;
|
|
}
|
|
|
|
int type[4] = { node[0]->getType(), node[1]->getType(), node[2]->getType(), node[3]->getType() };
|
|
|
|
if (type[0] > 0 && type[1] > 0 && type[2] > 0 && type[3] > 0)
|
|
{
|
|
this->processEdgeNoInter2(node, st, len, dir, hash, tlist, numTris, vlist, numVerts);
|
|
}
|
|
else
|
|
{
|
|
int i, j;
|
|
int nlen = len / 2;
|
|
int nst[3];
|
|
|
|
// 2 edge calls
|
|
OctreeNode* ecd[4];
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
int c[4] = { edgeProcEdgeMask[dir][i][0],
|
|
edgeProcEdgeMask[dir][i][1],
|
|
edgeProcEdgeMask[dir][i][2],
|
|
edgeProcEdgeMask[dir][i][3] };
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if (type[j] > 0)
|
|
{
|
|
ecd[j] = node[j];
|
|
}
|
|
else
|
|
{
|
|
ecd[j] = ((InternalNode*)node[j])->child[c[j]];
|
|
}
|
|
}
|
|
|
|
nst[0] = st[0];
|
|
nst[1] = st[1];
|
|
nst[2] = st[2];
|
|
nst[dir] += nlen * i;
|
|
|
|
edgeProcContourNoInter2(ecd, nst, nlen, edgeProcEdgeMask[dir][i][4], hash, tlist, numTris, vlist, numVerts);
|
|
}
|
|
}
|
|
// printf("I am done!\n") ;
|
|
};
|
|
|
|
void Octree::processEdgeNoInter2(OctreeNode* node[4], int st[3], int len, int dir, HashMap* hash, IndexedTriangleList* tlist, int& numTris, VertexList* vlist, int& numVerts)
|
|
{
|
|
// printf("I am at a leaf edge! %d %d %d\n", st[0], st[1], st[2] ) ;
|
|
// Get minimal cell
|
|
int i, type, minht = maxDepth + 1, mini = -1;
|
|
int ind[4], sc[4], ht[4], flip = 0;
|
|
float mp[4][3];
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (node[i]->getType() == 1)
|
|
{
|
|
LeafNode* lnode = ((LeafNode*)node[i]);
|
|
ht[i] = lnode->height;
|
|
mp[i][0] = lnode->mp[0];
|
|
mp[i][1] = lnode->mp[1];
|
|
mp[i][2] = lnode->mp[2];
|
|
|
|
int ed = processEdgeMask[dir][i];
|
|
int c1 = edgevmap[ed][0];
|
|
int c2 = edgevmap[ed][1];
|
|
|
|
if (lnode->height < minht)
|
|
{
|
|
minht = lnode->height;
|
|
mini = i;
|
|
if (lnode->getSign(c1) > 0)
|
|
{
|
|
flip = 1;
|
|
}
|
|
else
|
|
{
|
|
flip = 0;
|
|
}
|
|
}
|
|
ind[i] = lnode->index;
|
|
if (ind[i] < 0)
|
|
{
|
|
// Create new index
|
|
VertexList* nv = new VertexList;
|
|
nv->vt[0] = lnode->mp[0];
|
|
nv->vt[1] = lnode->mp[1];
|
|
nv->vt[2] = lnode->mp[2];
|
|
nv->next = vlist->next;
|
|
vlist->next = nv;
|
|
ind[i] = numVerts;
|
|
lnode->index = numVerts;
|
|
numVerts++;
|
|
}
|
|
|
|
if (lnode->getSign(c1) == lnode->getSign(c2))
|
|
{
|
|
sc[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
sc[i] = 1;
|
|
}
|
|
}
|
|
else if (node[i]->getType() == 2)
|
|
{
|
|
PseudoLeafNode* pnode = ((PseudoLeafNode*)node[i]);
|
|
ht[i] = pnode->height;
|
|
mp[i][0] = pnode->mp[0];
|
|
mp[i][1] = pnode->mp[1];
|
|
mp[i][2] = pnode->mp[2];
|
|
|
|
int ed = processEdgeMask[dir][i];
|
|
int c1 = edgevmap[ed][0];
|
|
int c2 = edgevmap[ed][1];
|
|
|
|
if (pnode->height < minht)
|
|
{
|
|
minht = pnode->height;
|
|
mini = i;
|
|
if (pnode->getSign(c1) > 0)
|
|
{
|
|
flip = 1;
|
|
}
|
|
else
|
|
{
|
|
flip = 0;
|
|
}
|
|
}
|
|
ind[i] = pnode->index;
|
|
if (ind[i] < 0)
|
|
{
|
|
// Create new index
|
|
VertexList* nv = new VertexList;
|
|
nv->vt[0] = pnode->mp[0];
|
|
nv->vt[1] = pnode->mp[1];
|
|
nv->vt[2] = pnode->mp[2];
|
|
nv->next = vlist->next;
|
|
vlist->next = nv;
|
|
ind[i] = numVerts;
|
|
pnode->index = numVerts;
|
|
numVerts++;
|
|
}
|
|
|
|
if (pnode->getSign(c1) == pnode->getSign(c2))
|
|
{
|
|
sc[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
sc[i] = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Wrong!\n");
|
|
}
|
|
}
|
|
|
|
if (sc[mini] == 0)
|
|
{
|
|
// printf("I am done!\n" ) ;
|
|
return;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Performing test */
|
|
/************************************************************************/
|
|
|
|
int fverts[4];
|
|
int hasFverts[4] = { 0, 0, 0, 0 };
|
|
int evert;
|
|
int needTess = 0;
|
|
int location[4];
|
|
int nvert[4] = { 0,0,0,0 };
|
|
|
|
// First, face test
|
|
int nbr[4][2] = { {0,1},{1,3},{2,3},{0,2} };
|
|
int fdir[3][4] = {
|
|
{2,1,2,1},
|
|
{0,2,0,2},
|
|
{1,0,1,0} };
|
|
int dir3[3][4][2] = {
|
|
{{1, -1},{2, 0},{1, 0},{2, -1}},
|
|
{{2, -1},{0, 0},{2, 0},{0, -1}},
|
|
{{0, -1},{1, 0},{0, 0},{1, -1}} };
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int a = nbr[i][0];
|
|
int b = nbr[i][1];
|
|
|
|
#ifndef TESS_UNIFORM
|
|
if (ht[a] != ht[b])
|
|
#endif
|
|
{
|
|
// Different level, check if the dual edge passes through the face
|
|
if (hash->FindKey(reinterpret_cast<std::intptr_t>(node[a]), reinterpret_cast<std::intptr_t>(node[b]), fverts[i], location[i]))
|
|
{
|
|
// The vertex was found previously
|
|
founds++;
|
|
hasFverts[i] = 1;
|
|
nvert[i] = 0;
|
|
needTess = 1;
|
|
}
|
|
else
|
|
{
|
|
// Otherwise, we test it here
|
|
int sht = (ht[a] > ht[b] ? ht[b] : ht[a]);
|
|
int flen = (1 << sht);
|
|
int fst[3];
|
|
|
|
fst[fdir[dir][i]] = st[fdir[dir][i]];
|
|
fst[dir3[dir][i][0]] = st[dir3[dir][i][0]] + flen * dir3[dir][i][1];
|
|
fst[dir] = st[dir] - (st[dir] & ((1 << sht) - 1));
|
|
|
|
if (testFace(fst, flen, fdir[dir][i], mp[a], mp[b]) == 0)
|
|
{
|
|
// Dual edge does not pass face, let's make a new vertex
|
|
VertexList* nv = new VertexList;
|
|
nv->vt[0] = 0;
|
|
nv->vt[1] = 0;
|
|
nv->vt[2] = 0;
|
|
nv->next = vlist->next;
|
|
vlist->next = nv;
|
|
fverts[i] = numVerts;
|
|
location[i] = reinterpret_cast<std::intptr_t>(nv);
|
|
nvert[i] = 1;
|
|
numVerts++;
|
|
|
|
hash->InsertKey(reinterpret_cast<std::intptr_t>(node[a]), reinterpret_cast<std::intptr_t>(node[b]), fverts[i], location[i]);
|
|
|
|
hasFverts[i] = 1;
|
|
needTess = 1;
|
|
news++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Next, edge test
|
|
int diag = 1;
|
|
if (needTess == 0)
|
|
{
|
|
// Even if all dual edges pass through faces, the dual complex of an edge may not be convex
|
|
//int st2[3] = { st[0], st[1], st[2] } ;
|
|
//st2[ dir ] += len ;
|
|
|
|
diag = testEdge(st, len, dir, node, mp);
|
|
if (diag == 0)
|
|
{
|
|
// When this happens, we need to create an extra vertex on the primal edge
|
|
needTess = 1;
|
|
}
|
|
}
|
|
|
|
float cent[3];
|
|
if (needTess)
|
|
{
|
|
edgeVerts++;
|
|
makeEdgeVertex(st, len, dir, node, mp, cent);
|
|
|
|
/* Just take centroid
|
|
int num = 0 ;
|
|
evert[0] = st[0] ;
|
|
evert[1] = st[1] ;
|
|
evert[2] = st[2] ;
|
|
evert[dir] = 0 ;
|
|
for ( i = 0 ; i < 4 ; i ++ )
|
|
{
|
|
evert[dir] += mp[i][dir] ;
|
|
num ++ ;
|
|
|
|
if ( hasFverts[ i ] )
|
|
{
|
|
evert[dir] += fverts[i][dir] ;
|
|
num ++ ;
|
|
}
|
|
}
|
|
evert[dir] /= num ;
|
|
*/
|
|
|
|
/*
|
|
if ( evert[dir] < st[dir] )
|
|
{
|
|
evert[dir] = st[dir] ;
|
|
}
|
|
else if ( evert[dir] > st[dir] + len )
|
|
{
|
|
evert[dir] = st[dir] + len ;
|
|
}
|
|
*/
|
|
|
|
VertexList* nv = new VertexList;
|
|
nv->vt[0] = cent[0];
|
|
nv->vt[1] = cent[1];
|
|
nv->vt[2] = cent[2];
|
|
nv->next = vlist->next;
|
|
vlist->next = nv;
|
|
evert = numVerts;
|
|
numVerts++;
|
|
}
|
|
|
|
int flipped[3];
|
|
if (flip == 0)
|
|
{
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
flipped[i] = i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
flipped[i] = 2 - i;
|
|
}
|
|
}
|
|
|
|
// Finally, let's output triangle
|
|
if (needTess == 0)
|
|
{
|
|
// Normal splitting of quad
|
|
if (diag == 1)
|
|
{
|
|
if (node[0] != node[1] && node[1] != node[3])
|
|
{
|
|
int tind1[] = { 0,1,3 };
|
|
|
|
numTris++;
|
|
IndexedTriangleList* t1 = new IndexedTriangleList;
|
|
t1->next = tlist->next;
|
|
tlist->next = t1;
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
t1->vt[flipped[j]] = ind[tind1[j]];
|
|
}
|
|
}
|
|
|
|
if (node[3] != node[2] && node[2] != node[0])
|
|
{
|
|
int tind2[] = { 3,2,0 };
|
|
|
|
numTris++;
|
|
IndexedTriangleList* t2 = new IndexedTriangleList;
|
|
t2->next = tlist->next;
|
|
tlist->next = t2;
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
t2->vt[flipped[j]] = ind[tind2[j]];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (node[0] != node[1] && node[1] != node[2])
|
|
{
|
|
int tind1[] = { 0,1,2 };
|
|
|
|
numTris++;
|
|
IndexedTriangleList* t1 = new IndexedTriangleList;
|
|
t1->next = tlist->next;
|
|
tlist->next = t1;
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
t1->vt[flipped[j]] = ind[tind1[j]];
|
|
}
|
|
}
|
|
|
|
if (node[1] != node[3] && node[3] != node[2])
|
|
{
|
|
int tind2[] = { 1,3,2 };
|
|
|
|
numTris++;
|
|
IndexedTriangleList* t2 = new IndexedTriangleList;
|
|
t2->next = tlist->next;
|
|
tlist->next = t2;
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
t2->vt[flipped[j]] = ind[tind2[j]];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{/*
|
|
if ( flip == 1 )
|
|
{
|
|
int tempind[4]={ind[0], ind[2], ind[1], ind[3]};
|
|
OctreeNode* tempnode[4] = {node[0], node[2], node[1], node[3]};
|
|
int tempfverts[4]={fverts[3], fverts[2], fverts[1], fverts[0]};
|
|
int temphasFverts[4]={hasFverts[3], hasFverts[2], hasFverts[1], hasFverts[0]};
|
|
int templocation[4]={location[3], location[2], location[1], location[0]};
|
|
int tempnvert[4]={nvert[3], nvert[2], nvert[1], nvert[0]};
|
|
|
|
for ( i = 0 ; i < 4 ; i ++ )
|
|
{
|
|
ind[i] = tempind[i] ;
|
|
node[i] = tempnode[i] ;
|
|
fverts[i] = tempfverts[i] ;
|
|
hasFverts[i] = temphasFverts[i] ;
|
|
location[i] = templocation[i] ;
|
|
nvert[i] = tempnvert[i] ;
|
|
}
|
|
}
|
|
*/
|
|
int nnbr[4][2] = { {0,1},{1,3},{3,2},{2,0} };
|
|
|
|
// Center-splitting
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
int a = nnbr[i][0];
|
|
int b = nnbr[i][1];
|
|
|
|
if (hasFverts[i])
|
|
{
|
|
// Further split each triangle into two
|
|
numTris += 2;
|
|
|
|
IndexedTriangleList* t = new IndexedTriangleList;
|
|
t->next = tlist->next;
|
|
tlist->next = t;
|
|
t->vt[flipped[0]] = ind[a];
|
|
t->vt[flipped[1]] = fverts[i];
|
|
t->vt[flipped[2]] = evert;
|
|
|
|
t = new IndexedTriangleList;
|
|
t->next = tlist->next;
|
|
tlist->next = t;
|
|
t->vt[flipped[0]] = evert;
|
|
t->vt[flipped[1]] = fverts[i];
|
|
t->vt[flipped[2]] = ind[b];
|
|
|
|
// Update geometric location of the face vertex
|
|
VertexList* nv = ((VertexList*)location[i]);
|
|
if (nvert[i])
|
|
{
|
|
nv->vt[0] = cent[0];
|
|
nv->vt[1] = cent[1];
|
|
nv->vt[2] = cent[2];
|
|
}
|
|
else
|
|
{
|
|
nv->vt[0] = (nv->vt[0] + cent[0]) / 2;
|
|
nv->vt[1] = (nv->vt[1] + cent[1]) / 2;
|
|
nv->vt[2] = (nv->vt[2] + cent[2]) / 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// For one triangle with center vertex
|
|
if (node[a] != node[b])
|
|
{
|
|
numTris++;
|
|
IndexedTriangleList* t = new IndexedTriangleList;
|
|
t->next = tlist->next;
|
|
tlist->next = t;
|
|
t->vt[flipped[0]] = ind[a];
|
|
t->vt[flipped[1]] = ind[b];
|
|
t->vt[flipped[2]] = evert;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// printf("I am done!\n" ) ;
|
|
};
|