layer0/Triangle.cpp (2,107 lines of code) (raw):
/*
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* Copyright (c) Schrodinger, LLC.
D* -------------------------------------------------------------------
E* It is unlawful to modify or remove this copyright notice.
F* -------------------------------------------------------------------
G* Please see the accompanying LICENSE file for further information.
H* -------------------------------------------------------------------
I* Additional authors of this source file include:
-*
-*
-*
Z* -------------------------------------------------------------------
*/
/* glossary:
active edge = an edge with one triangle
closed edge = an edge with two triangles
closed vertex = one which is surrounded by a cycle of triangles
active vertex = (opposite of closed)
*/
#include"os_python.h"
#include"os_predef.h"
#include"os_std.h"
#include"Base.h"
#include"Triangle.h"
#include"Map.h"
#include"MemoryDebug.h"
#include"Err.h"
#include"Setting.h"
#include"Ortho.h"
#include"Feedback.h"
#include"Util.h"
typedef struct {
int index;
int value;
int next;
} LinkType;
typedef struct {
int vert3, tri1;
int vert4, tri2;
} EdgeRec;
typedef struct {
PyMOLGlobals *G;
int *activeEdge; /* active edges */
int nActive;
int *edgeStatus;
int *vertActive;
int *vertWeight;
int *tri;
int nTri;
float *vNormal; /* normal vector for first triangle of an active edge */
EdgeRec *edge;
int nEdge;
MapType *map;
MapCache map_cache;
LinkType *link;
int nLink;
int N;
float maxEdgeLenSq;
} TriangleSurfaceRec;
int TriangleDegenerate(float *v1, float *n1, float *v2, float *n2, float *v3, float *n3)
{
float axis1[3];
float axis2[3];
float axis3[3];
float norm[3];
float dot[3];
add3f(n1, n2, norm);
add3f(n3, norm, norm);
subtract3f(v1, v2, axis1);
subtract3f(v3, v2, axis2);
cross_product3f(axis1, axis2, axis3);
dot[0] = dot_product3f(axis3, n1);
dot[1] = dot_product3f(axis3, n2);
dot[2] = dot_product3f(axis3, n3);
return (!(((dot[0] > 0.0F) && (dot[1] > 0.0F) && (dot[2] > 0.0F)) ||
((dot[0] < 0.0F) && (dot[1] < 0.0F) && (dot[2] < 0.0F))
));
}
static int TriangleEdgeStatus(TriangleSurfaceRec * II, int i1, int i2)
{
TriangleSurfaceRec *I = II;
int l, low, high;
low = (i1 > i2 ? i2 : i1);
high = (i1 > i2 ? i1 : i2);
l = I->edgeStatus[low];
while(l) {
if(I->link[l].index == high)
return (I->link[l].value); /* <0 closed, 0 open, >0 then has index for blocking vector */
l = I->link[l].next;
}
return (0);
}
static int *TriangleMakeStripVLA(TriangleSurfaceRec * II, float *v, float *vn, int n)
{
TriangleSurfaceRec *I = II;
int *tFlag, tmp_int;
int c, a, cc = 0;
int *s, *sc, *strip;
int state, s01, i0, i1, i2, tc, t0 = 0;
int *t;
int done;
int dir, dcnt;
int flag;
float *v0, *v1, *v2, vt1[3], vt2[3], *tn0, *tn1, *tn2, tn[3], xtn[3];
strip = VLAlloc(int, I->nTri * 4); /* strip VLA is count,vert,vert,...count,vert,vert...zero */
tFlag = Alloc(int, I->nTri);
for(a = 0; a < I->nTri; a++)
tFlag[a] = 0;
s = strip;
done = false;
while(!done) {
done = true;
t = I->tri;
dir = 0;
for(a = 0; a < I->nTri; a++) {
if(!tFlag[a]) {
tc = a;
flag = false;
dcnt = 0;
while(dcnt < 3) {
i0 = *(t + 3 * tc + (dir % 3));
i1 = *(t + 3 * tc + ((dir + 1) % 3));
state = TriangleEdgeStatus(I, i0, i1);
if(state) {
s01 = abs(state);
t0 = I->edge[s01].tri1;
if(!tFlag[t0])
flag = true;
else if(state < 0) {
t0 = I->edge[s01].tri2;
if(!tFlag[t0])
flag = true;
}
}
if(!flag) {
dir++;
dcnt++;
} else {
c = 0;
sc = s++;
*(s++) = i0;
*(s++) = i1;
while(1) {
state = TriangleEdgeStatus(I, s[-2], s[-1]);
if(!state)
break;
s01 = abs(state);
/* printf("a: %i %i %i\n",a,I->edge[s01].tri1,I->edge[s01].tri2); */
t0 = I->edge[s01].tri1;
if(!tFlag[t0])
i2 = I->edge[s01].vert3;
else {
if(state >= 0)
break;
t0 = I->edge[s01].tri2;
i2 = I->edge[s01].vert4;
/* printf("second to %i i2 %i [t0] %i \n",t0,i2,tFlag[t0]); */
}
if(tFlag[t0])
break;
*(s++) = i2;
tFlag[t0] = true;
c++;
done = false;
if((c == 1) || (c == 2)) { /* make sure vertices follow standard convention */
/* sum normal */
tn0 = vn + (*(s - 3)) * 3;
tn1 = vn + (*(s - 2)) * 3;
tn2 = vn + (*(s - 1)) * 3;
add3f(tn0, tn1, tn);
add3f(tn2, tn, tn);
/* compute right-hand vector */
v0 = v + (*(s - 3)) * 3;
v1 = v + (*(s - 2)) * 3;
v2 = v + (*(s - 1)) * 3;
subtract3f(v0, v1, vt1);
subtract3f(v0, v2, vt2);
cross_product3f(vt1, vt2, xtn);
if(c & 0x1) {
/* reorder triangle if necessary */
if(dot_product3f(xtn, tn) < 0.0) {
tmp_int = *(s - 3);
*(s - 3) = *(s - 2);
*(s - 2) = tmp_int;
}
} else {
if(dot_product3f(xtn, tn) > 0.0) { /* if we're blowing the right hand rule
on the second triangle, then
terminate this strip and try again */
tFlag[t0] = false;
c--;
s--;
break;
}
}
} else { /* continue proofreading handedness... */
float dp;
/* sum normal */
tn0 = vn + (*(s - 3)) * 3;
tn1 = vn + (*(s - 2)) * 3;
tn2 = vn + (*(s - 1)) * 3;
add3f(tn0, tn1, tn);
add3f(tn2, tn, tn);
/* compute right-hand vector */
v0 = v + (*(s - 3)) * 3;
v1 = v + (*(s - 2)) * 3;
v2 = v + (*(s - 1)) * 3;
subtract3f(v0, v1, vt1);
subtract3f(v0, v2, vt2);
cross_product3f(vt1, vt2, xtn);
dp = dot_product3f(xtn, tn);
if(((c & 0x1) && (dp < 0.0)) || ((!(c & 0x1)) && (dp > 0.0))) {
/* truncate if right hand rule has been lost */
tFlag[t0] = false;
c--;
s--;
break;
}
}
}
if(!c)
s = sc;
else {
*sc = c;
cc += c;
}
/* if(c>1) printf("strip %i %i\n",c,cc); */
dcnt = 0;
tc = t0;
flag = false;
}
}
}
}
/* fail-safe check in case of bad connectivity... */
for(a = 0; a < I->nTri; a++) {
if(!tFlag[a]) {
/* printf("missed %i %i %i\n",*(I->tri+3*a),*(I->tri+3*a+1), *(I->tri+3*a+2)); */
*(s++) = 1;
*(s++) = *(I->tri + 3 * a);
*(s++) = *(I->tri + 3 * a + 1);
*(s++) = *(I->tri + 3 * a + 2);
/* make sure vertices follow standard convention */
/* sum normal */
tn0 = vn + (*(s - 3)) * 3;
tn1 = vn + (*(s - 2)) * 3;
tn2 = vn + (*(s - 1)) * 3;
add3f(tn0, tn1, tn);
add3f(tn2, tn, tn);
/* compute right-hand vector */
v0 = v + (*(s - 3)) * 3;
v1 = v + (*(s - 2)) * 3;
v2 = v + (*(s - 1)) * 3;
subtract3f(v0, v1, vt1);
subtract3f(v0, v2, vt2);
cross_product3f(vt1, vt2, xtn);
/* reorder triangle if necessary */
if(dot_product3f(xtn, tn) < 0.0) {
tmp_int = *(s - 3);
*(s - 3) = *(s - 2);
*(s - 2) = tmp_int;
}
}
}
*s = 0; /* terminate strip list */
}
FreeP(tFlag);
/* shrink strip */
return (strip);
}
static int TriangleAdjustNormals(TriangleSurfaceRec * II, float *v, float *vn, int n,
int final_pass)
{
TriangleSurfaceRec *I = II;
int ok = true;
/* points all normals to the average of the intersecting triangles in order to maximum surface smoothness */
float *tNorm = NULL, *tWght;
int *vFlag = NULL;
float *v0, *v1, *v2, *tn, vt1[3], vt2[3], *vn0, *tn0, *tn1, *tn2, *tw;
int a, *t, i0, i1, i2;
float tmp[3];
tNorm = Alloc(float, 3 * I->nTri);
tWght = Alloc(float, I->nTri);
vFlag = Alloc(int, n);
for(a = 0; a < n; a++) {
vFlag[a] = 0;
}
/* first, calculate and store all triangle normals & weights */
t = I->tri;
tn = tNorm;
tw = tWght;
for(a = 0; a < I->nTri; a++) {
vFlag[t[0]] = 1;
vFlag[t[1]] = 1;
vFlag[t[2]] = 1;
v0 = v + (*(t++)) * 3;
v1 = v + (*(t++)) * 3;
v2 = v + (*(t++)) * 3;
subtract3f(v1, v0, vt1);
subtract3f(v2, v0, vt2);
cross_product3f(vt1, vt2, tn);
*(tw++) = (float) length3f(tn); /* store weight */
normalize3f(tn);
tn += 3;
}
/* clear normals */
vn0 = vn;
for(a = 0; a < n; a++)
if(vFlag[a]) {
*(vn0++) = 0.0;
*(vn0++) = 0.0;
*(vn0++) = 0.0;
} else
vn0 += 3;
/* sum */
tn = tNorm;
tw = tWght;
t = I->tri;
for(a = 0; a < I->nTri; a++) {
i0 = *(t++);
i1 = *(t++);
i2 = *(t++);
scale3f(tn, *tw, tmp);
tn0 = vn + i0 * 3;
tn1 = vn + i1 * 3;
tn2 = vn + i2 * 3;
add3f(tmp, tn0, tn0);
add3f(tmp, tn1, tn1);
add3f(tmp, tn2, tn2);
tn += 3;
tw++;
}
/* normalize */
vn0 = vn;
for(a = 0; a < n; a++) {
if(vFlag[a])
normalize3f(vn0);
vn0 += 3;
}
/* now ensure that no normal is allowed to point behind a triangle... */
if(final_pass) {
int repeat = true;
int max_cyc = 5;
float *va = Alloc(float, 3 * n), *va0, *va1, *va2;
float vt[3];
while(repeat && max_cyc) {
repeat = false;
va0 = va;
for(a = 0; a < n; a++) {
vFlag[a] = 0;
*(va0++) = 0.0F;
*(va0++) = 0.0F;
*(va0++) = 0.0F;
}
max_cyc--;
t = I->tri;
tn = tNorm;
for(a = 0; a < I->nTri; a++) {
i0 = *(t++);
i1 = *(t++);
i2 = *(t++);
tn0 = vn + i0 * 3; /* triangle normal */
tn1 = vn + i1 * 3;
tn2 = vn + i2 * 3;
va0 = va + i0 * 3; /* adjustment */
va1 = va + i1 * 3;
va2 = va + i2 * 3;
if(dot_product3f(tn0, tn) < 0.0F) {
remove_component3f(tn0, tn, vt);
normalize3f(vt);
add3f(vt, va0, va0);
vFlag[i0] = true;
repeat = true;
}
if(dot_product3f(tn1, tn) < 0.0F) {
remove_component3f(tn1, tn, vt);
normalize3f(vt);
add3f(vt, va1, va1);
vFlag[i1] = true;
repeat = true;
}
if(dot_product3f(tn2, tn) < 0.0F) {
remove_component3f(tn2, tn, vt);
normalize3f(vt);
add3f(vt, va2, va2);
vFlag[i2] = true;
repeat = true;
}
tn += 3;
}
vn0 = vn;
va0 = va;
for(a = 0; a < n; a++) {
if(vFlag[a]) {
normalize23f(va0, vn0);
}
vn0 += 3;
va0 += 3;
}
}
FreeP(va);
}
FreeP(vFlag);
FreeP(tWght);
FreeP(tNorm);
if(I->G->Interrupt)
ok = false;
return ok;
}
static int TriangleActivateEdges(TriangleSurfaceRec * II, int low)
{
TriangleSurfaceRec *I = II;
int l;
l = I->edgeStatus[low];
while(l) {
if(I->link[l].value > 0) {
VLACheck(I->activeEdge, int, I->nActive * 2 + 1);
I->activeEdge[I->nActive * 2] = low;
I->activeEdge[I->nActive * 2 + 1] = I->link[l].index;
I->nActive++;
}
l = I->link[l].next;
}
return (0);
}
static void TriangleDeleteEdge(TriangleSurfaceRec * II, int i1, int i2)
{
TriangleSurfaceRec *I = II;
int l, low, high;
int prev = 0;
low = (i1 > i2 ? i2 : i1);
high = (i1 > i2 ? i1 : i2);
/* printf("set: %i %i %i\n",i1,i2,value); */
l = I->edgeStatus[low];
while(l) {
if(I->link[l].index == high) {
if(prev) {
I->link[prev].next = I->link[l].next; /* leaks, but that's no big deal */
return;
} else {
I->edgeStatus[low] = I->link[l].next; /* leaks, but that's no big deal */
}
}
prev = l;
l = I->link[l].next;
}
return;
}
static void TriangleEdgeSetStatus(TriangleSurfaceRec * II, int i1, int i2, int value)
{
TriangleSurfaceRec *I = II;
int l, low, high;
low = (i1 > i2 ? i2 : i1);
high = (i1 > i2 ? i1 : i2);
/* printf("set: %i %i %i\n",i1,i2,value); */
l = I->edgeStatus[low];
while(l) {
if(I->link[l].index == high) {
I->link[l].value = value;
return;
}
l = I->link[l].next;
}
if(!l) {
VLACheck(I->link, LinkType, I->nLink);
I->link[I->nLink].next = I->edgeStatus[low];
I->edgeStatus[low] = I->nLink;
/* printf("offset %i value %i index %i\n",I->nLink,value,high); */
I->link[I->nLink].index = high;
I->link[I->nLink].value = value;
I->nLink++;
}
}
static void TriangleMove(TriangleSurfaceRec * II, int from, int to)
{
TriangleSurfaceRec *I = II;
int i0, i1, i2, s01, s02, s12;
i0 = I->tri[from * 3];
i1 = I->tri[from * 3 + 1];
i2 = I->tri[from * 3 + 2];
s01 = TriangleEdgeStatus(I, i0, i1);
s02 = TriangleEdgeStatus(I, i0, i2);
s12 = TriangleEdgeStatus(I, i1, i2);
#define TMoveMacro(x) {\
if(x>0) { \
if(I->edge[x].tri1==from) \
I->edge[x].tri1=to; \
else if(I->edge[x].tri2==from) \
I->edge[x].tri2=to; \
} else if(x<0) { \
x=-x; \
if(I->edge[x].tri1==from) \
I->edge[x].tri1=to; \
else if(I->edge[x].tri2==from) \
I->edge[x].tri2=to; \
}}\
TMoveMacro(s01)
TMoveMacro(s02)
TMoveMacro(s12)
I->tri[to * 3] = i0;
I->tri[to * 3 + 1] = i1;
I->tri[to * 3 + 2] = i2;
}
#define max_edge_len 2.5
static void TriangleRectify(TriangleSurfaceRec * I, int t, float *v, float *vn)
{
int i0 = I->tri[t * 3 + 0];
int i1 = I->tri[t * 3 + 1];
int i2 = I->tri[t * 3 + 2], it;
float *n0 = vn + 3 * i0, *n1 = vn + 3 * i1, *n2 = vn + 3 * i2;
float *v0 = v + 3 * i0, *v1 = v + 3 * i1, *v2 = v + 3 * i2;
float tNorm[3], vt1[3], vt2[3], vt[3];
add3f(n0, n1, tNorm);
add3f(n2, tNorm, tNorm);
subtract3f(v1, v0, vt1);
subtract3f(v2, v0, vt2);
cross_product3f(vt1, vt2, vt);
if(dot_product3f(vt, tNorm) < 0.0) { /* if wrong, then interchange */
it = i1;
i1 = i2;
i2 = it;
I->tri[t * 3 + 1] = i1;
I->tri[t * 3 + 2] = i2;
}
}
static void AddActive(TriangleSurfaceRec * II, int i1, int i2)
{
int t;
TriangleSurfaceRec *I = II;
if(i1 > i2) {
t = i1;
i1 = i2;
i2 = t;
}
VLACheck(I->activeEdge, int, I->nActive * 2 + 1);
I->activeEdge[I->nActive * 2] = i1;
I->activeEdge[I->nActive * 2 + 1] = i2;
I->nActive++;
if(I->vertActive[i1] < 0)
I->vertActive[i1] = 0;
I->vertActive[i1]++;
if(I->vertActive[i2] < 0)
I->vertActive[i2] = 0;
I->vertActive[i2]++;
}
static void TriangleAdd(TriangleSurfaceRec * II, int i0, int i1, int i2, float *tNorm,
float *v, float *vn)
{
TriangleSurfaceRec *I = II;
int s01, s12, s02, it;
float *v0, *v1, *v2, *n0, *n1, *n2, *ft;
float vt[3], vt1[3], vt2[3], vt3[3];
int e1, e2, e3, h, j, k, l;
MapType *map = I->map;
MapCache *cache = &I->map_cache;
v0 = v + 3 * i0;
v1 = v + 3 * i1;
v2 = v + 3 * i2;
n0 = vn + 3 * i0;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
/* mark this quadrant as visited so that further activity in this
quadrant won't prolong the rendering process indefinitely */
MapLocus(map, v0, &h, &k, &l);
e1 = *(MapEStart(map, h, k, l));
if(e1) {
j = map->EList[e1];
MapCache(cache, j);
}
MapLocus(map, v1, &h, &k, &l);
e2 = *(MapEStart(map, h, k, l));
if(e2 && (e1 != e2)) {
j = map->EList[e2];
MapCache(cache, j);
}
MapLocus(map, v2, &h, &k, &l);
e3 = *(MapEStart(map, h, k, l));
if(e3 && (e3 != e2) && (e3 != e1)) {
j = map->EList[e3];
MapCache(cache, j);
}
/* make sure the triangle obeys the right hand rule */
subtract3f(v1, v0, vt1);
subtract3f(v2, v0, vt2);
cross_product3f(vt1, vt2, vt);
if(dot_product3f(vt, tNorm) < 0.0) { /* if wrong, then interchange */
it = i1;
i1 = i2;
i2 = it;
ft = v1;
v1 = v2;
v2 = ft;
ft = n1;
n1 = n2;
n2 = ft;
}
/* now, bend the normals a bit so that they line up better with the
actual triangles drawn */
add3f(n0, n1, vt3);
add3f(n2, vt3, vt3);
I->vertWeight[i0]++;
scale3f(n0, I->vertWeight[i0], n0);
add3f(tNorm, n0, n0);
normalize3f(n0);
I->vertWeight[i1]++;
scale3f(n1, I->vertWeight[i1], n1);
add3f(tNorm, n1, n1);
normalize3f(n1);
I->vertWeight[i2]++;
scale3f(n2, I->vertWeight[i2], n2);
add3f(tNorm, n2, n2);
normalize3f(n2);
s01 = TriangleEdgeStatus(I, i0, i1);
s02 = TriangleEdgeStatus(I, i0, i2);
s12 = TriangleEdgeStatus(I, i1, i2);
/* create a new triangle */
VLACheck(I->tri, int, (I->nTri * 3) + 2);
I->tri[I->nTri * 3] = i0;
I->tri[I->nTri * 3 + 1] = i1;
I->tri[I->nTri * 3 + 2] = i2;
/* printf("creating %i %i %i\n",i0,i1,i2); */
if(s01) {
if(s01 > 0) {
I->edge[s01].vert4 = i2;
I->edge[s01].tri2 = I->nTri;
TriangleEdgeSetStatus(I, i0, i1, -s01);
I->vertActive[i0]--; /* deactivate when all active edges are closed */
I->vertActive[i1]--;
} /*else {
ErrFatal(I->G,"TriangleAdd","Invalid triangle - s01 negative");
} */
} else {
VLACheck(I->edge, EdgeRec, I->nEdge);
I->edge[I->nEdge].vert3 = i2;
I->edge[I->nEdge].tri1 = I->nTri;
VLACheck(I->vNormal, float, (I->nEdge * 3) + 2);
copy3f(tNorm, I->vNormal + I->nEdge * 3);
TriangleEdgeSetStatus(I, i0, i1, I->nEdge);
I->nEdge++;
AddActive(I, i0, i1);
}
if(s02) {
if(s02 > 0) {
I->edge[s02].vert4 = i1;
I->edge[s02].tri2 = I->nTri;
TriangleEdgeSetStatus(I, i0, i2, -s02);
I->vertActive[i0]--; /* deactivate when all active edges are closed */
I->vertActive[i2]--;
} /*else {
ErrFatal(I->G,"TriangleAdd","Invalid triangle - s02 negative");
} */
} else {
VLACheck(I->edge, EdgeRec, I->nEdge);
I->edge[I->nEdge].vert3 = i1;
I->edge[I->nEdge].tri1 = I->nTri;
VLACheck(I->vNormal, float, (I->nEdge * 3) + 2);
copy3f(tNorm, I->vNormal + I->nEdge * 3);
TriangleEdgeSetStatus(I, i0, i2, I->nEdge);
I->nEdge++;
AddActive(I, i0, i2);
}
if(s12) {
if(s12 > 0) {
I->edge[s12].vert4 = i0;
I->edge[s12].tri2 = I->nTri;
TriangleEdgeSetStatus(I, i1, i2, -s12);
I->vertActive[i1]--; /* deactivate when all active edges are closed */
I->vertActive[i2]--;
} /*else {
ErrFatal(I->G,"TriangleAdd","Invalid triangle - s12 negative");
} */
} else {
VLACheck(I->edge, EdgeRec, I->nEdge);
I->edge[I->nEdge].vert3 = i0;
I->edge[I->nEdge].tri1 = I->nTri;
VLACheck(I->vNormal, float, (I->nEdge * 3) + 2);
copy3f(tNorm, I->vNormal + I->nEdge * 3);
TriangleEdgeSetStatus(I, i1, i2, I->nEdge);
I->nEdge++;
AddActive(I, i1, i2);
}
I->nTri++;
}
static int TriangleBuildObvious(TriangleSurfaceRec * II, int i1, int i2, float *v,
float *vn, int n)
{
/* this routine builds obvious, easy triagles where the closest point
* to the edge is always tried */
TriangleSurfaceRec *I = II;
MapType *map;
int ok = true;
float *v1, *v2, *v0, *v4, vt[3], vt1[3], vt2[3], vt3[3], vt4[3], *n0, *n1, *n2,
tNorm[3];
int i0, s01 = 0, s02 = 0, s12, i, j, h, k, l, i4;
float dp;
int flag;
int used = -1;
float maxDot, dot, dot1, dot2;
const float _plus = R_SMALL4, _0 = 0.0F;
const float _25 = 0.25F;
/* PRINTFD(I->G,FB_Triangle)
" TriangleBuildObvious-Debug: entered: i1=%d i2=%d n=%d\n",i1,i2,n
ENDFD; */
map = I->map;
s12 = TriangleEdgeStatus(I, i1, i2);
/* PRINTFD(I->G,FB_Triangle)
" TriangleBuildObvious-Debug: edge status=%d\n",s12
ENDFD;
*/
if(s12 > 0)
used = I->edge[s12].vert3;
if(s12 >= 0) {
float minDist2 = MAXFLOAT;
maxDot = _plus;
i0 = -1;
v1 = v + i1 * 3;
v2 = v + i2 * 3;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
MapLocus(map, v1, &h, &k, &l);
i = *(MapEStart(map, h, k, l));
if(i) {
j = map->EList[i++];
while(j >= 0) {
if((j != i1) && (j != i2) && (j != used)) {
v0 = v + 3 * j;
{
float d1 = diffsq3f(v0, v1);
float d2 = diffsq3f(v0, v2);
float dif2 = (d2 > d1 ? d2 : d1);
if(dif2 < minDist2) {
n0 = vn + 3 * j;
dot1 = dot_product3f(n0, n1);
dot2 = dot_product3f(n0, n2);
dot = dot1 + dot2;
if((dif2 / minDist2) < _25) {
minDist2 = dif2;
maxDot = dot;
i0 = j;
} else if((dot > _0) && (dot1 > _0) && (dot2 > _0)) {
if((i0 < 0) || (dot > maxDot)) {
minDist2 = dif2;
maxDot = dot;
i0 = j;
} else if((dif2 / minDist2) < powf(2 * (dot / maxDot), 2.0f)) {
minDist2 = dif2;
maxDot = dot;
i0 = j;
}
}
}
}
}
j = map->EList[i++];
}
/* PRINTFD(I->G,FB_Triangle)
" TriangleBuildObvious-Debug: i0=%d\n",i0
ENDFD; */
if(i0 >= 0) {
s01 = TriangleEdgeStatus(I, i0, i1);
s02 = TriangleEdgeStatus(I, i0, i2);
if(I->vertActive[i0] > 0) {
if(!((s01 > 0) || (s02 > 0)))
i0 = -1; /* don't allow non-adjacent joins to active vertices */
}
}
/* PRINTFD(I->G,FB_Triangle)
" TriangleBuildObvious-Debug: i0=%d s01=%d s02=%d\n",i0,s01,s02
ENDFD; */
if(i0 >= 0) {
v0 = v + 3 * i0;
flag = false;
if(I->vertActive[i0]) {
if((s01 >= 0) && (s02 >= 0))
flag = true;
if(flag) { /* are all normals pointing in generally the same direction? */
n0 = vn + 3 * i0;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
add3f(n0, n1, vt1);
add3f(n2, vt1, vt2);
normalize3f(vt2);
/* if(Feedback(I->G,FB_Triangle,FB_Debugging)) {
dump3f(n0,"n0");
dump3f(n1,"n1");
dump3f(n2,"n2");
dump3f(vt2,"vt2");
PRINTF " n0.vt2 = %8.3f\n",dot_product3f(n0,vt2) ENDF(I->G);
PRINTF " n1.vt2 = %8.3f\n",dot_product3f(n1,vt2) ENDF(I->G);
PRINTF " n2.vt2 = %8.3f\n",dot_product3f(n2,vt2) ENDF(I->G);
PRINTF " n0.vt2<0.1 %d\n",dot_product3f(n0,vt2)<0.1 ENDF(I->G);
PRINTF " n1.vt2<0.1 %d\n",dot_product3f(n1,vt2)<0.1 ENDF(I->G);
PRINTF " n2.vt2<0.1 %d\n",dot_product3f(n2,vt2)<0.1 ENDF(I->G);
fflush(stdout);
} */
if(((dot_product3f(n0, vt2)) < 0.1) ||
((dot_product3f(n1, vt2)) < 0.1) || ((dot_product3f(n2, vt2)) < 0.1))
flag = false;
/* modified 010916 to effect workaround of apparent bug in GCC's optimizer */
}
/* PRINTFD(I->G,FB_Triangle)
" TriangleBuildObvious-Debug: past normal sums, flag= %d\n",flag
ENDFD; */
if(flag) { /* does the sum of the normals point in the same direction as the triangle? */
subtract3f(v1, v0, vt3);
subtract3f(v2, v0, vt4);
cross_product3f(vt3, vt4, tNorm);
normalize3f(tNorm);
dp = dot_product3f(vt2, tNorm);
if(dp < 0)
scale3f(tNorm, -1.0F, tNorm);
if(fabs(dp) < 0.1)
flag = false;
}
/* PRINTFD(I->G,FB_Triangle)
" TriangleBuildObvious-Debug: past tNorm, flag= %d\n",flag
ENDFD; */
if(flag) {
if(s12 > 0)
if(dot_product3f(I->vNormal + s12 * 3, tNorm) < 0.1)
flag = false;
if(s01 > 0)
if(dot_product3f(I->vNormal + s01 * 3, tNorm) < 0.1)
flag = false;
if(s02 > 0)
if(dot_product3f(I->vNormal + s02 * 3, tNorm) < 0.1)
flag = false;
}
/* PRINTFD(I->G,FB_Triangle)
" TriangleBuildObvious-Debug: past compare tNorm, flag= %d\n",flag
ENDFD; */
if(flag) { /* are all the Blocking vectors pointing outward, and are the triangle normals consistent? */
if(s12 > 0) {
i4 = I->edge[s12].vert3;
v4 = v + i4 * 3;
subtract3f(v0, v1, vt1);
subtract3f(v4, v1, vt2);
subtract3f(v1, v2, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if((dot_product3f(vt3, vt4)) > 0.0)
flag = false;
}
if(s01 > 0) {
i4 = I->edge[s01].vert3;
v4 = v + i4 * 3;
subtract3f(v2, v0, vt1);
subtract3f(v4, v0, vt2);
subtract3f(v0, v1, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if((dot_product3f(vt3, vt4)) > 0.0)
flag = false;
}
if(s02 > 0) {
i4 = I->edge[s02].vert3;
v4 = v + i4 * 3;
subtract3f(v1, v0, vt1);
subtract3f(v4, v0, vt2);
subtract3f(v0, v2, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if((dot_product3f(vt3, vt4)) > 0.0)
flag = false;
}
}
/* PRINTFD(I->G,FB_Triangle)
" TriangleBuildObvious-Debug: past blocking, flag= %d\n",flag
ENDFD; */
}
if(flag)
TriangleAdd(I, i0, i1, i2, tNorm, v, vn);
}
}
}
if(I->G->Interrupt)
ok = false;
return ok;
}
static int TriangleBuildSecondPass(TriangleSurfaceRec * II, int i1, int i2, float *v,
float *vn, int n)
{
/* in this version, the closest active point is tried. Closed points
are skipped. */
TriangleSurfaceRec *I = II;
int ok = true;
MapType *map;
float *v1, *v2, *v0, *v4, vt[3], vt1[3], vt2[3], vt3[3], vt4[3], *n0, *n1, *n2,
tNorm[3];
int i0, s01 = 0, s02 = 0, s12, i, j, h, k, l, i4;
float minDist2, dp;
int flag;
int used = -1;
float dot, dot1, dot2, maxDot;
const float _plus = R_SMALL4, _0 = 0.0F;
const float _25 = 0.25F;
map = I->map;
s12 = TriangleEdgeStatus(I, i1, i2);
if(s12 > 0)
used = I->edge[s12].vert3;
if(s12 >= 0) {
minDist2 = I->maxEdgeLenSq;
maxDot = _plus;
i0 = -1;
v1 = v + i1 * 3;
v2 = v + i2 * 3;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
MapLocus(map, v1, &h, &k, &l);
i = *(MapEStart(map, h, k, l));
if(i) {
j = map->EList[i++];
while(j >= 0) {
if((j != i1) && (j != i2) && (j != used) && (I->vertActive[j])) {
/* eliminate closed vertices from consideration - where vertactive is 0 */
v0 = v + 3 * j;
n0 = vn + 3 * j;
{
float d1 = diffsq3f(v0, v1);
float d2 = diffsq3f(v0, v2);
float dif2 = (d2 > d1 ? d2 : d1);
if(dif2 < minDist2) {
dot1 = dot_product3f(n0, n1);
dot2 = dot_product3f(n0, n2);
dot = dot1 + dot2;
if((dif2 / minDist2) < _25) {
minDist2 = dif2;
maxDot = dot;
i0 = j;
} else if((dot > _0) && (dot1 > _0) && (dot2 > _0)) {
if((i0 < 0) || (dot > maxDot)) {
minDist2 = dif2;
maxDot = dot;
i0 = j;
} else if((dif2 / minDist2) < powf(2 * (dot / maxDot), 2.0f)) {
maxDot = dot;
minDist2 = dif2;
i0 = j;
}
}
}
}
}
j = map->EList[i++];
}
if(i0 >= 0) {
s01 = TriangleEdgeStatus(I, i0, i1);
s02 = TriangleEdgeStatus(I, i0, i2);
if(I->vertActive[i0] > 0) {
if(!((s01 > 0) || (s02 > 0)))
i0 = -1; /* don't allow non-adjacent joins to active vertices */
}
}
if(i0 >= 0) {
v0 = v + 3 * i0;
flag = false;
if(I->vertActive[i0]) {
if((s01 >= 0) && (s02 >= 0))
flag = true;
if(flag) { /* are all normals pointing in generally the same direction? */
n0 = vn + 3 * i0;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
add3f(n0, n1, vt1);
add3f(n2, vt1, vt2);
normalize3f(vt2);
if(((dot_product3f(n0, vt2)) < 0.1) ||
((dot_product3f(n1, vt2)) < 0.1) || ((dot_product3f(n2, vt2)) < 0.1))
flag = false;
/* modified 010916 to effect workaround of apparent bug in GCC's optimizer */
} /*printf("pass normal sums %i\n",flag); */
if(flag) { /* does the sum of the normals point in the same direction as the triangle? */
subtract3f(v1, v0, vt3);
subtract3f(v2, v0, vt4);
cross_product3f(vt3, vt4, tNorm);
normalize3f(tNorm);
dp = dot_product3f(vt2, tNorm);
if(dp < 0)
scale3f(tNorm, -1.0F, tNorm);
if(fabs(dp) < 0.1)
flag = false;
}
/*printf("pass tNorm %i\n",flag); */
if(flag) {
if(s12 > 0)
if(dot_product3f(I->vNormal + s12 * 3, tNorm) < 0.1)
flag = false;
if(s01 > 0)
if(dot_product3f(I->vNormal + s01 * 3, tNorm) < 0.1)
flag = false;
if(s02 > 0)
if(dot_product3f(I->vNormal + s02 * 3, tNorm) < 0.1)
flag = false;
} /*printf("pass compare tNorm %i\n",flag); */
if(flag) { /* are all the Blocking vectors pointing outward, and are the triangle normals consistent? */
if(s12 > 0) {
i4 = I->edge[s12].vert3;
v4 = v + i4 * 3;
subtract3f(v0, v1, vt1);
subtract3f(v4, v1, vt2);
subtract3f(v1, v2, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if(dot_product3f(vt3, vt4) > 0.0)
flag = false;
}
if(s01 > 0) {
i4 = I->edge[s01].vert3;
v4 = v + i4 * 3;
subtract3f(v2, v0, vt1);
subtract3f(v4, v0, vt2);
subtract3f(v0, v1, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if(dot_product3f(vt3, vt4) > 0.0)
flag = false;
}
if(s02 > 0) {
i4 = I->edge[s02].vert3;
v4 = v + i4 * 3;
subtract3f(v1, v0, vt1);
subtract3f(v4, v0, vt2);
subtract3f(v0, v2, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if(dot_product3f(vt3, vt4) > 0.0)
flag = false;
}
} /*printf("pass blocking %i\n",flag); */
}
if(flag)
TriangleAdd(I, i0, i1, i2, tNorm, v, vn);
}
}
}
if(I->G->Interrupt)
ok = false;
return ok;
}
static int TriangleBuildSecondSecondPass(TriangleSurfaceRec * II, int i1, int i2,
float *v, float *vn, int n, float cutoff)
{
/* in this version, the closest active point is tried. Closed points
are skipped. */
TriangleSurfaceRec *I = II;
int ok = true;
MapType *map;
float *v1, *v2, *v0, *v4, vt[3], vt1[3], vt2[3], vt3[3], vt4[3], *n0, *n1, *n2,
tNorm[3];
int i0, s01 = 0, s02 = 0, s12, i, j, h, k, l, i4;
float minDist2, dp;
int flag;
int used = -1;
float dot;
const float _25 = 0.25;
map = I->map;
s12 = TriangleEdgeStatus(I, i1, i2);
if(s12 > 0)
used = I->edge[s12].vert3;
if(s12 >= 0) {
minDist2 = I->maxEdgeLenSq;
i0 = -1;
v1 = v + i1 * 3;
v2 = v + i2 * 3;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
MapLocus(map, v1, &h, &k, &l);
i = *(MapEStart(map, h, k, l));
if(i) {
j = map->EList[i++];
while(j >= 0) {
if((j != i1) && (j != i2) && (j != used) && (I->vertActive[j])) {
/* eliminate closed vertices from consideration - where vertactive is 0 */
v0 = v + 3 * j;
n0 = vn + 3 * j;
{
float d1 = diffsq3f(v0, v1);
float d2 = diffsq3f(v0, v2);
float dif2 = (d2 > d1 ? d2 : d1);
if(dif2 < minDist2) {
dot = dot_product3f(n0, n1) + dot_product3f(n0, n2);
if((dot > cutoff) || ((dif2 / minDist2) < _25)) {
minDist2 = dif2;
i0 = j;
}
}
}
}
j = map->EList[i++];
}
if(i0 >= 0) {
s01 = TriangleEdgeStatus(I, i0, i1);
s02 = TriangleEdgeStatus(I, i0, i2);
if(I->vertActive[i0] > 0) {
if(!((s01 > 0) || (s02 > 0)))
i0 = -1; /* don't allow non-adjacent joins to active vertices */
}
}
if(i0 >= 0) {
v0 = v + 3 * i0;
flag = false;
if(I->vertActive[i0]) {
if((s01 >= 0) && (s02 >= 0))
flag = true;
if(flag) { /* are all normals pointing in generally the same direction? */
n0 = vn + 3 * i0;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
add3f(n0, n1, vt1);
add3f(n2, vt1, vt2);
normalize3f(vt2);
if(((dot_product3f(n0, vt2)) < 0.1) ||
((dot_product3f(n1, vt2)) < 0.1) || ((dot_product3f(n2, vt2)) < 0.1))
flag = false;
/* modified 010916 to effect workaround of apparent bug in GCC's optimizer */
} /*printf("pass normal sums %i\n",flag); */
if(flag) { /* does the sum of the normals point in the same direction as the triangle? */
subtract3f(v1, v0, vt3);
subtract3f(v2, v0, vt4);
cross_product3f(vt3, vt4, tNorm);
normalize3f(tNorm);
dp = dot_product3f(vt2, tNorm);
if(dp < 0)
scale3f(tNorm, -1.0F, tNorm);
if(fabs(dp) < 0.1)
flag = false;
} /*printf("pass tNorm %i\n",flag); */
if(flag) {
if(s12 > 0)
if(dot_product3f(I->vNormal + s12 * 3, tNorm) < 0.1)
flag = false;
if(s01 > 0)
if(dot_product3f(I->vNormal + s01 * 3, tNorm) < 0.1)
flag = false;
if(s02 > 0)
if(dot_product3f(I->vNormal + s02 * 3, tNorm) < 0.1)
flag = false;
} /*printf("pass compare tNorm %i\n",flag); */
if(flag) { /* are all the Blocking vectors pointing outward, and are the triangle normals consistent? */
if(s12 > 0) {
i4 = I->edge[s12].vert3;
v4 = v + i4 * 3;
subtract3f(v0, v1, vt1);
subtract3f(v4, v1, vt2);
subtract3f(v1, v2, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if(dot_product3f(vt3, vt4) > 0.0)
flag = false;
}
if(s01 > 0) {
i4 = I->edge[s01].vert3;
v4 = v + i4 * 3;
subtract3f(v2, v0, vt1);
subtract3f(v4, v0, vt2);
subtract3f(v0, v1, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if(dot_product3f(vt3, vt4) > 0.0)
flag = false;
}
if(s02 > 0) {
i4 = I->edge[s02].vert3;
v4 = v + i4 * 3;
subtract3f(v1, v0, vt1);
subtract3f(v4, v0, vt2);
subtract3f(v0, v2, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if(dot_product3f(vt3, vt4) > 0.0)
flag = false;
}
} /*printf("pass blocking %i\n",flag); */
}
if(flag)
TriangleAdd(I, i0, i1, i2, tNorm, v, vn);
}
}
}
if(I->G->Interrupt)
ok = false;
return ok;
}
static void TriangleBuildSingle(TriangleSurfaceRec * II, int i1, int i2, float *v,
float *vn, int n)
{
TriangleSurfaceRec *I = II;
MapType *map;
float *v1, *v2, *v0, *v4, vt[3], vt1[3], vt2[3], vt3[3], vt4[3], *n0, *n1, *n2,
tNorm[3];
int i0, s01 = 0, s02 = 0, s12, i, j, h, k, l, i4;
float minDist2, dp;
int flag;
int used = -1;
map = I->map;
s12 = TriangleEdgeStatus(I, i1, i2);
if(s12 > 0)
used = I->edge[s12].vert3;
if(s12 >= 0) {
minDist2 = I->maxEdgeLenSq;
i0 = -1;
v1 = v + i1 * 3;
v2 = v + i2 * 3;
MapLocus(map, v1, &h, &k, &l);
i = *(MapEStart(map, h, k, l));
if(i) {
j = map->EList[i++];
while(j >= 0) {
if((j != i1) && (j != i2) && (j != used) && (I->vertActive[j])) {
v0 = v + 3 * j;
{
float d1 = diffsq3f(v0, v1);
float d2 = diffsq3f(v0, v2);
float dif2 = (d2 > d1 ? d2 : d1);
if(dif2 < minDist2) {
minDist2 = dif2;
i0 = j;
}
}
}
j = map->EList[i++];
}
if(i0 >= 0) {
v0 = v + 3 * i0;
flag = false;
s01 = TriangleEdgeStatus(I, i0, i1);
s02 = TriangleEdgeStatus(I, i0, i2);
if(I->vertActive[i0]) {
if((s01 >= 0) && (s02 >= 0))
flag = true;
if(flag) { /* are all normals pointing in generally the same direction? */
n0 = vn + 3 * i0;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
add3f(n0, n1, vt1);
add3f(n2, vt1, vt2);
normalize3f(vt2);
if(((dot_product3f(n0, vt2)) < 0.1) ||
((dot_product3f(n1, vt2)) < 0.1) || ((dot_product3f(n2, vt2)) < 0.1))
flag = false;
/* modified 010916 to effect workaround of apparent bug in GCC's optimizer */
} /*printf("pass normal sums %i\n",flag); */
if(flag) { /* does the sum of the normals point in the same direction as the triangle? */
subtract3f(v1, v0, vt3);
subtract3f(v2, v0, vt4);
cross_product3f(vt3, vt4, tNorm);
normalize3f(tNorm);
dp = dot_product3f(vt2, tNorm);
if(dp < 0)
scale3f(tNorm, -1.0F, tNorm);
if(fabs(dp) < 0.1)
flag = false;
} /*printf("pass tNorm %i\n",flag); */
if(flag) {
if(s12 > 0)
if(dot_product3f(I->vNormal + s12 * 3, tNorm) < 0.1)
flag = false;
if(s01 > 0)
if(dot_product3f(I->vNormal + s01 * 3, tNorm) < 0.1)
flag = false;
if(s02 > 0)
if(dot_product3f(I->vNormal + s02 * 3, tNorm) < 0.1)
flag = false;
} /*printf("pass compare tNorm %i\n",flag); */
if(flag) { /* are all the Blocking vectors pointing outward, and are the triangle normals consistent? */
if(s12 > 0) {
i4 = I->edge[s12].vert3;
v4 = v + i4 * 3;
subtract3f(v0, v1, vt1);
subtract3f(v4, v1, vt2);
subtract3f(v1, v2, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if(dot_product3f(vt3, vt4) > 0.0)
flag = false;
}
if(s01 > 0) {
i4 = I->edge[s01].vert3;
v4 = v + i4 * 3;
subtract3f(v2, v0, vt1);
subtract3f(v4, v0, vt2);
subtract3f(v0, v1, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if(dot_product3f(vt3, vt4) > 0.0)
flag = false;
}
if(s02 > 0) {
i4 = I->edge[s02].vert3;
v4 = v + i4 * 3;
subtract3f(v1, v0, vt1);
subtract3f(v4, v0, vt2);
subtract3f(v0, v2, vt);
normalize3f(vt);
remove_component3f(vt1, vt, vt3);
remove_component3f(vt2, vt, vt4);
normalize3f(vt3);
normalize3f(vt4);
if(dot_product3f(vt3, vt4) > 0.0)
flag = false;
}
} /*printf("pass blocking %i\n",flag); */
}
if(flag)
TriangleAdd(I, i0, i1, i2, tNorm, v, vn);
}
}
}
}
static int TriangleBuildThirdPass(TriangleSurfaceRec * II, int i1, int i2, float *v,
float *vn, int n)
{
/* This routine fills in triangles surrounded by three active edges */
TriangleSurfaceRec *I = II;
int ok = true;
MapType *map;
float *v1, *v2, *v0, vt1[3], vt2[3], vt3[3], vt4[3], *n0, *n1, *n2, tNorm[3];
int i0, s01, s02, s12, i, j, h, k, l;
float minDist2, dp;
int used = -1;
map = I->map;
s12 = TriangleEdgeStatus(I, i1, i2);
if(s12 > 0)
used = I->edge[s12].vert3;
if(s12 >= 0) {
minDist2 = I->maxEdgeLenSq;
i0 = -1;
v1 = v + i1 * 3;
v2 = v + i2 * 3;
MapLocus(map, v1, &h, &k, &l);
i = *(MapEStart(map, h, k, l));
if(i) {
j = map->EList[i++];
while(j >= 0) {
if((j != i1) && (j != i2) && (j != used) && (I->vertActive[j])) {
v0 = v + 3 * j;
{
float d1 = diffsq3f(v0, v1);
float d2 = diffsq3f(v0, v2);
float dif2 = (d2 > d1 ? d2 : d1);
if(dif2 < minDist2) {
minDist2 = dif2;
i0 = j;
}
}
}
j = map->EList[i++];
}
if(i0 >= 0) {
v0 = v + 3 * i0;
s01 = TriangleEdgeStatus(I, i0, i1);
s02 = TriangleEdgeStatus(I, i0, i2);
/* if all three edges are active */
if((s12 > 0) && (s01 > 0) && (s02 > 0)) {
n0 = vn + 3 * i0;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
add3f(n0, n1, vt1);
add3f(n2, vt1, vt2);
subtract3f(v1, v0, vt3);
subtract3f(v2, v0, vt4);
cross_product3f(vt3, vt4, tNorm);
normalize3f(tNorm);
dp = dot_product3f(vt2, tNorm);
if(dp < 0)
scale3f(tNorm, -1.0F, tNorm);
TriangleAdd(I, i0, i1, i2, tNorm, v, vn);
}
}
}
}
if(I->G->Interrupt)
ok = false;
return ok;
}
static int TriangleBuildLast(TriangleSurfaceRec * II, int i1, int i2, float *v, float *vn,
int n)
{
/* this routine is a hack to fill in the odd-ball situations */
TriangleSurfaceRec *I = II;
int ok = true;
MapType *map;
float *v1, *v2, *v0, vt1[3], vt2[3], vt3[3], vt4[3], *n0, *n1, *n2, tNorm[3];
int i0, s01, s02, s12, i, j, h, k, l;
float minDist2, dp;
int used = -1;
map = I->map;
s12 = TriangleEdgeStatus(I, i1, i2);
if(s12 > 0)
used = I->edge[s12].vert3;
if(s12 >= 0) {
minDist2 = I->maxEdgeLenSq;
i0 = -1;
v1 = v + i1 * 3;
v2 = v + i2 * 3;
MapLocus(map, v1, &h, &k, &l);
i = *(MapEStart(map, h, k, l));
if(i) {
j = map->EList[i++];
while(j >= 0) {
if((j != i1) && (j != i2) && (j != used) && (I->vertActive[j] > 0)) {
v0 = v + 3 * j;
{
float d1 = diffsq3f(v0, v1);
float d2 = diffsq3f(v0, v2);
float dif2 = (d2 > d1 ? d2 : d1);
if(dif2 < minDist2) {
minDist2 = dif2;
i0 = j;
}
}
}
j = map->EList[i++];
}
if(i0 >= 0) {
v0 = v + 3 * i0;
s01 = TriangleEdgeStatus(I, i0, i1);
s02 = TriangleEdgeStatus(I, i0, i2);
/* if all three edges are active */
if(((s12 > 0) && (((s01 > 0) && (s02 >= 0)) || ((s01 >= 0) && (s02 > 0)))) ||
((s01 > 0) && (s02 > 0))) {
n0 = vn + 3 * i0;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
add3f(n0, n1, vt1);
add3f(n2, vt1, vt2);
subtract3f(v1, v0, vt3);
subtract3f(v2, v0, vt4);
cross_product3f(vt3, vt4, tNorm);
normalize3f(tNorm);
dp = dot_product3f(vt2, tNorm);
if(dp < 0)
scale3f(tNorm, -1.0F, tNorm);
TriangleAdd(I, i0, i1, i2, tNorm, v, vn);
}
}
}
}
if(I->G->Interrupt)
ok = false;
return ok;
}
static int FollowActives(TriangleSurfaceRec * II, float *v, float *vn, int n, int mode)
{
TriangleSurfaceRec *I = II;
int ok = true;
int i1, i2;
PRINTFD(I->G, FB_Triangle)
" TriangleFollowActives-Debug: entered: n=%6d mode=%d\n TriangleFollowActives-Debug: nTri=%6d nActive=%6d\n",
n, mode, I->nTri, I->nActive ENDFD;
OrthoBusyFast(I->G, (I->N * 3) + I->nTri, I->N * 5); /* 3/5 to 4/5 */
while(I->nActive) {
I->nActive--;
i1 = I->activeEdge[I->nActive * 2];
i2 = I->activeEdge[I->nActive * 2 + 1];
switch (mode) {
case 0:
TriangleBuildObvious(I, i1, i2, v, vn, n);
break;
case 1:
TriangleBuildSecondPass(I, i1, i2, v, vn, n);
break;
case 2:
TriangleBuildSecondSecondPass(I, i1, i2, v, vn, n, 0.0F);
break;
case 4:
TriangleBuildThirdPass(I, i1, i2, v, vn, n);
break;
case 5:
TriangleBuildLast(I, i1, i2, v, vn, n);
break;
}
}
PRINTFD(I->G, FB_Triangle)
" TriangleFollowActives-Debug: exiting: nTri=%6d nActive=%6d\n",
I->nTri, I->nActive ENDFD;
if(I->G->Interrupt)
ok = false;
return ok;
}
static int TriangleFill(TriangleSurfaceRec * II, float *v, float *vn, int n,
int first_time)
{
TriangleSurfaceRec *I = II;
int ok = true;
int lastTri, lastTri2, lastTri3;
int a, i, j, h, k, l;
float minDist2, *v0, *n0, *n1;
int i1, i2 = 0;
int n_pass = 0;
int first_vert = 0, first_vert_used = 0;
MapType *map;
MapCache *cache;
PRINTFD(I->G, FB_Triangle)
" TriangleFill-Debug: entered: n=%d\n", n ENDFD;
map = I->map;
cache = &I->map_cache;
lastTri3 = -1;
while(ok && (lastTri3 != I->nTri)) {
lastTri3 = I->nTri;
n_pass++;
if(n_pass > SettingGetGlobal_i(I->G, cSetting_triangle_max_passes))
break;
I->nActive = 0;
while(ok && (!I->nActive) && (I->nTri == lastTri3)) {
i1 = -1;
minDist2 = I->maxEdgeLenSq;
for(a = 0; a < n; a++) {
if(!I->edgeStatus[a]) {
v0 = v + a * 3;
n0 = vn + 3 * a;
MapLocus(map, v0, &h, &k, &l);
i = *(MapEStart(map, h, k, l));
if(i) {
j = map->EList[i++];
first_vert = j;
while(j >= 0) {
if(j != a) {
float dif2 = diffsq3f(v + 3 * j, v0);
if(dif2 < minDist2)
if(I->vertActive[a] == -1)
if(TriangleEdgeStatus(I, a, j) >= 0) { /* can we put a triangle here? */
n1 = vn + 3 * j;
if(dot_product3f(n0, n1) > 0.5) { /* start with vertices pointing the same way */
minDist2 = dif2;
i1 = a;
i2 = j;
first_vert_used = first_vert;
}
}
}
j = map->EList[i++];
}
}
}
}
if(i1 >= 0) {
if(!MapCached(cache, first_vert_used)) {
MapCache(cache, first_vert_used);
if(first_time) {
n_pass = n_pass / 2;
/* if we've entered a new map quadrant then half the effective number of passes */
/* this is a very non-obvious way of making sure that we
don't prematurely terminate when surfacing
discontinuous surfaces that will always require many passes */
}
}
if(I->vertActive[i1] < 0)
I->vertActive[i1]--;
VLACheck(I->activeEdge, int, I->nActive * 2 + 1);
I->activeEdge[I->nActive * 2] = i1;
I->activeEdge[I->nActive * 2 + 1] = i2;
I->nActive = 1;
lastTri = I->nTri;
ok = FollowActives(I, v, vn, n, 0);
while(ok && (lastTri != I->nTri)) {
lastTri = I->nTri;
for(a = 0; a < n; a++)
if(I->vertActive[a])
TriangleActivateEdges(I, a);
ok = FollowActives(I, v, vn, n, 0);
}
} else
break;
if(I->G->Interrupt)
ok = false;
if(!ok)
break;
}
PRINTFD(I->G, FB_Triangle)
" TriangleFill-Debug: Follow actives 1 nTri=%d\n", I->nTri ENDFD;
lastTri = I->nTri - 1;
while(ok && (lastTri != I->nTri)) {
lastTri = I->nTri;
for(a = 0; a < n; a++)
if(I->vertActive[a])
TriangleActivateEdges(I, a);
ok = FollowActives(I, v, vn, n, 1);
}
lastTri2 = I->nTri - 1;
while(ok && (lastTri2 != I->nTri)) {
lastTri2 = I->nTri;
for(a = 0; a < n; a++) {
if(I->vertActive[a]) {
TriangleActivateEdges(I, a);
if(I->nActive) {
PRINTFD(I->G, FB_Triangle)
" TriangleFill-Debug: build single: nTri=%d nActive=%d\n", I->nTri,
I->nActive ENDFD;
I->nActive--;
i1 = I->activeEdge[I->nActive * 2];
i2 = I->activeEdge[I->nActive * 2 + 1];
TriangleBuildSingle(I, i1, i2, v, vn, n);
PRINTFD(I->G, FB_Triangle)
" TriangleFill-Debug: follow actives 1: nTri=%d nActive=%d\n", I->nTri,
I->nActive ENDFD;
ok = FollowActives(I, v, vn, n, 1);
}
}
if(!ok)
break;
}
}
PRINTFD(I->G, FB_Triangle)
" TriangleFill-Debug: Follow actives 1 nTri=%d\n", I->nTri ENDFD;
lastTri = I->nTri - 1;
while(ok && (lastTri != I->nTri)) {
lastTri = I->nTri;
for(a = 0; a < n; a++)
if(I->vertActive[a])
TriangleActivateEdges(I, a);
ok = FollowActives(I, v, vn, n, 2);
}
lastTri2 = I->nTri - 1;
while(ok && (lastTri2 != I->nTri)) {
lastTri2 = I->nTri;
for(a = 0; a < n; a++) {
if(I->vertActive[a]) {
TriangleActivateEdges(I, a);
if(I->nActive) {
PRINTFD(I->G, FB_Triangle)
" TriangleFill-Debug: build single: nTri=%d nActive=%d\n", I->nTri,
I->nActive ENDFD;
I->nActive--;
i1 = I->activeEdge[I->nActive * 2];
i2 = I->activeEdge[I->nActive * 2 + 1];
TriangleBuildSingle(I, i1, i2, v, vn, n);
PRINTFD(I->G, FB_Triangle)
" TriangleFill-Debug: follow actives 2: nTri=%d nActive=%d\n", I->nTri,
I->nActive ENDFD;
ok = FollowActives(I, v, vn, n, 2);
}
}
if(!ok)
break;
}
}
PRINTFD(I->G, FB_Triangle)
" TriangleFill-Debug: follow actives 4: nTri=%d nActive=%d\n", I->nTri, I->nActive
ENDFD;
for(a = 0; a < n; a++)
if(I->vertActive[a])
TriangleActivateEdges(I, a);
ok = FollowActives(I, v, vn, n, 4);
PRINTFD(I->G, FB_Triangle)
" TriangleFill-Debug: follow actives 5: nTri=%d nActive=%d\n", I->nTri, I->nActive
ENDFD;
lastTri = I->nTri - 1;
while(ok && (lastTri != I->nTri)) {
lastTri = I->nTri;
for(a = 0; a < n; a++)
if(I->vertActive[a])
TriangleActivateEdges(I, a);
ok = FollowActives(I, v, vn, n, 5); /* this is a sloppy, forcing tesselation */
}
}
PRINTFD(I->G, FB_Triangle)
" TriangleFill: leaving... nTri=%d nActive=%d\n", I->nTri, I->nActive ENDFD;
if(I->G->Interrupt)
ok = false;
return ok;
}
static int TriangleTxfFolds(TriangleSurfaceRec * II, float *v, float *vn, int n)
{
TriangleSurfaceRec *I = II;
int ok = true;
int a, b, c, d, l, s01, s02, t1, t2;
float *v0, *v1, *v2, *v3, d10[3], n10[3], d20[3], d30[3], d21[3], d31[3], d32[3];
float x1020[3], x1030[3], x2132[3], x2032[3], s2[3], s3[3], nt[3];
float old_dp, new_dp, old_conv, new_conv;
for(a = 0; a < n; a++) { /* first vertex */
l = I->edgeStatus[a];
while(l) {
if((s01 = I->link[l].value) < 0) { /* closed edge */
s01 = -s01;
b = I->link[l].index; /* second vertex */
v0 = v + a * 3;
v1 = v + b * 3;
c = I->edge[s01].vert3;
d = I->edge[s01].vert4;
v2 = v + c * 3;
v3 = v + d * 3;
subtract3f(v1, v0, d10);
subtract3f(v2, v0, d20);
subtract3f(v3, v0, d30);
cross_product3f(d10, d20, x1020);
cross_product3f(d10, d30, x1030);
normalize3f(x1020);
normalize3f(x1030);
if((old_dp = dot_product3f(x1020, x1030)) > 0.5F) { /* triangles are nearly opposing one another */
/*
CGOLinewidth(I->G->DebugCGO,5.0);
CGOBegin(I->G->DebugCGO,GL_LINES);
CGOVertexv(I->G->DebugCGO,v0);
CGOVertexv(I->G->DebugCGO,v1);
CGOEnd(I->G->DebugCGO);
CGOLinewidth(I->G->DebugCGO,3.0);
CGOBegin(I->G->DebugCGO,GL_LINES);
CGOVertexv(I->G->DebugCGO,v2);
CGOVertexv(I->G->DebugCGO,v3);
CGOEnd(I->G->DebugCGO);
*/
normalize23f(d10, n10);
subtract3f(v2, v1, d21);
subtract3f(v3, v1, d31);
add3f(d21, d20, s2);
add3f(d31, d30, s3);
remove_component3f(s2, n10, s2);
remove_component3f(s3, n10, s3);
normalize3f(s2);
normalize3f(s3);
if(dot_product3f(s2, s3) > 0.5F) {
/* 2 & 3 on same side of 01 */
subtract3f(v3, v2, d32);
cross_product3f(d21, d32, x2132);
cross_product3f(d20, d32, x2032);
normalize3f(x2132);
normalize3f(x2032);
if((new_dp = dot_product3f(x2132, x2032)) < old_dp) {
int legal = true;
s02 = TriangleEdgeStatus(I, a, d);
if(s02 < 0) {
s02 = -s02;
if((I->edge[s02].vert3 == c) || (I->edge[s02].vert4 == c))
legal = false;
}
s02 = TriangleEdgeStatus(I, b, d);
if(s02 < 0) {
s02 = -s02;
if((I->edge[s02].vert3 == c) || (I->edge[s02].vert4 == c))
legal = false;
}
s02 = TriangleEdgeStatus(I, a, c);
if(s02 < 0) {
s02 = -s02;
if((I->edge[s02].vert3 == d) || (I->edge[s02].vert4 == d))
legal = false;
}
s02 = TriangleEdgeStatus(I, b, c);
if(s02 < 0) {
s02 = -s02;
if((I->edge[s02].vert3 == d) || (I->edge[s02].vert4 == d))
legal = false;
}
if(legal) {
/* how consistent are the normals (old versus new) ? */
copy3f(vn + a * 3, nt);
add3f(vn + b * 3, nt, nt);
add3f(vn + c * 3, nt, nt);
old_conv = dot_product3f(x1020, nt);
copy3f(vn + a * 3, nt);
add3f(vn + b * 3, nt, nt);
add3f(vn + d * 3, nt, nt);
old_conv += -dot_product3f(x1030, nt);
old_conv = (float) fabs(old_conv);
copy3f(vn + a * 3, nt);
add3f(vn + c * 3, nt, nt);
add3f(vn + d * 3, nt, nt);
new_conv = dot_product3f(x2032, nt);
copy3f(vn + b * 3, nt);
add3f(vn + c * 3, nt, nt);
add3f(vn + d * 3, nt, nt);
new_conv += -dot_product3f(x2132, nt);
new_conv = (float) fabs(new_conv);
if((old_conv < new_conv)) {
/* switch the edges and triangles around */
TriangleDeleteEdge(I, a, b);
TriangleEdgeSetStatus(I, c, d, -s01);
I->edge[s01].vert3 = a;
I->edge[s01].vert4 = b;
t1 = I->edge[s01].tri1;
t2 = I->edge[s01].tri2;
{
int i;
for(i = 0; i < 3; i++) {
if(I->tri[3 * t1 + i] == b) { /* a b c -> a c d */
I->tri[3 * t1 + i] = d;
}
if(I->tri[3 * t2 + i] == a) { /* a b d -> c b d */
I->tri[3 * t2 + i] = c;
}
}
TriangleRectify(I, t1, v, vn);
TriangleRectify(I, t2, v, vn);
}
s01 = TriangleEdgeStatus(I, a, d);
if(s01 < 0) {
s01 = -s01;
if(I->edge[s01].vert3 == b) {
I->edge[s01].vert3 = c;
I->edge[s01].tri1 = t1;
} else if(I->edge[s01].vert4 == b) {
I->edge[s01].vert4 = c;
I->edge[s01].tri2 = t1;
}
}
s01 = TriangleEdgeStatus(I, a, c);
if(s01 < 0) {
s01 = -s01;
if(I->edge[s01].vert3 == b) {
I->edge[s01].vert3 = d;
I->edge[s01].tri1 = t1;
} else if(I->edge[s01].vert4 == b) {
I->edge[s01].vert4 = d;
I->edge[s01].tri2 = t1;
}
}
s01 = TriangleEdgeStatus(I, b, c);
if(s01 < 0) {
s01 = -s01;
if(I->edge[s01].vert3 == a) {
I->edge[s01].vert3 = d;
I->edge[s01].tri1 = t2;
} else if(I->edge[s01].vert4 == a) {
I->edge[s01].vert4 = d;
I->edge[s01].tri2 = t2;
}
}
s01 = TriangleEdgeStatus(I, b, d);
if(s01 < 0) {
s01 = -s01;
if(I->edge[s01].vert3 == a) {
I->edge[s01].vert3 = c;
I->edge[s01].tri1 = t2;
} else if(I->edge[s01].vert4 == a) {
I->edge[s01].vert4 = c;
I->edge[s01].tri2 = t2;
}
}
l = I->edgeStatus[a]; /* start vertex over since we've messed with its edges */
}
}
}
}
}
}
l = I->link[l].next;
}
}
if(I->G->Interrupt)
ok = false;
return ok;
/* CGOStop(I->G->DebugCGO); */
}
static int TriangleFixProblems(TriangleSurfaceRec * II, float *v, float *vn, int n)
{
TriangleSurfaceRec *I = II;
int ok = true;
int problemFlag;
int a, l, e;
int i0, i1, i2, s01 = 0, s02 = 0, s12;
int *pFlag = NULL;
int *vFlag = NULL;
problemFlag = false;
pFlag = Alloc(int, n);
vFlag = Alloc(int, n);
for(a = 0; a < n; a++) {
vFlag[a] = 0;
if(I->vertActive[a]) {
pFlag[a] = 1;
problemFlag = true;
} else {
pFlag[a] = 0;
}
}
if(I->G->Interrupt)
ok = false;
if(ok && problemFlag) {
a = 0;
while(ok && (a < I->nTri)) {
if(((pFlag[I->tri[a * 3]] && (pFlag[I->tri[a * 3 + 1]])) ||
(pFlag[I->tri[a * 3 + 1]] && (pFlag[I->tri[a * 3 + 2]])) ||
(pFlag[I->tri[a * 3]] && (pFlag[I->tri[a * 3 + 2]])))) {
i0 = I->tri[a * 3];
i1 = I->tri[a * 3 + 1];
i2 = I->tri[a * 3 + 2];
s01 = TriangleEdgeStatus(I, i0, i1);
if(s01 < 0) {
s01 = -s01;
if(I->edge[s01].tri2 != a) {
I->edge[s01].tri1 = I->edge[s01].tri2;
I->edge[s01].vert3 = I->edge[s01].vert4;
}
} else
s01 = 0;
TriangleEdgeSetStatus(I, i0, i1, s01);
s02 = TriangleEdgeStatus(I, i0, i2);
if(s02 < 0) {
s02 = -s02;
if(I->edge[s02].tri2 != a) {
I->edge[s02].tri1 = I->edge[s02].tri2;
I->edge[s02].vert3 = I->edge[s02].vert4;
}
} else
s02 = 0;
TriangleEdgeSetStatus(I, i0, i2, s02);
s12 = TriangleEdgeStatus(I, i1, i2);
if(s12 < 0) {
s12 = -s12;
if(I->edge[s12].tri2 != a) {
I->edge[s12].tri1 = I->edge[s12].tri2;
I->edge[s12].vert3 = I->edge[s12].vert4;
}
} else
s12 = 0;
TriangleEdgeSetStatus(I, i1, i2, s12);
I->nTri--;
TriangleMove(I, I->nTri, a);
vFlag[i0] = true;
vFlag[i1] = true;
vFlag[i2] = true;
}
a++;
if(I->G->Interrupt)
ok = false;
}
/* now go through the complicated step of resetting vertex activities */
if(ok) {
for(a = 0; a < n; a++)
if(vFlag[a])
I->vertActive[a] = -1;
}
if(ok) {
for(a = 0; a < n; a++) {
l = I->edgeStatus[a];
while(l) {
if(I->link[l].value > 0) {
if(vFlag[a]) {
e = a;
if(I->vertActive[e] < 0)
I->vertActive[e] = 0;
I->vertActive[e]++;
}
if(vFlag[I->link[l].index]) {
e = I->link[l].index;
if(I->vertActive[e] < 0)
I->vertActive[e] = 0;
I->vertActive[e]++;
}
}
if(I->link[l].value < 0) {
if(vFlag[a]) {
e = a;
if(I->vertActive[e] < 0)
I->vertActive[e] = 0;
}
if(vFlag[I->link[l].index]) {
e = I->link[l].index;
if(I->vertActive[e] < 0)
I->vertActive[e] = 0;
}
}
l = I->link[l].next;
}
if(I->G->Interrupt) {
ok = false;
break;
}
}
if(ok)
ok = TriangleAdjustNormals(I, v, vn, n, false);
if(ok)
ok = TriangleFill(I, v, vn, n, false);
}
}
FreeP(vFlag);
FreeP(pFlag);
if(I->G->Interrupt)
ok = false;
return ok;
}
static int TriangleBruteForceClosure(TriangleSurfaceRec * II, float *v, float *vn, int n,
float cutoff)
{
TriangleSurfaceRec *I = II;
int ok = true;
int a, b, c, d;
int i0, i1, i2;
float *v1, *v2, *v0, vt1[3], vt2[3], vt3[3], vt4[3], *n0, *n1, *n2, tNorm[3];
int *pFlag = NULL;
int *pair = NULL;
int pc;
int *active = NULL;
int ac;
int hits;
int p1, p2;
float dp;
active = Alloc(int, n);
ac = 0;
pair = Alloc(int, n * 2);
pc = 0;
pFlag = Alloc(int, n);
for(a = 0; a < n; a++) {
if(I->vertActive[a]) {
pFlag[a] = 1;
active[ac] = a;
ac++;
} else {
pFlag[a] = 0;
}
}
if(ac < 80) { /* there is a limit to how much we can brute force... */
a = 0;
while(ok && (a < I->nTri) && (pc < n)) {
i0 = I->tri[a * 3];
i1 = I->tri[a * 3 + 1];
i2 = I->tri[a * 3 + 2];
if(pFlag[i0] && pFlag[i1]) {
if(i0 < i1) {
pair[pc * 2] = i0;
pair[pc * 2 + 1] = i1;
} else {
pair[pc * 2] = i1;
pair[pc * 2 + 1] = i0;
}
pc++;
}
if(pFlag[i1] && pFlag[i2]) {
if(i1 < i2) {
pair[pc * 2] = i1;
pair[pc * 2 + 1] = i2;
} else {
pair[pc * 2] = i2;
pair[pc * 2 + 1] = i1;
}
pc++;
}
if(pFlag[i2] && pFlag[i0]) {
if(i2 < i0) {
pair[pc * 2] = i2;
pair[pc * 2 + 1] = i0;
} else {
pair[pc * 2] = i0;
pair[pc * 2 + 1] = i2;
}
pc++;
}
a++;
if(I->G->Interrupt) {
ok = false;
break;
}
}
PRINTFD(I->G, FB_Triangle)
" Triangle-BFS: ac %d pc %d\n", ac, pc ENDFD;
if(ok) {
for(a = 0; a < ac; a++) {
i0 = active[a];
for(b = a + 1; b < ac; b++) {
i1 = active[b];
for(c = b + 1; c < ac; c++) { /* consider all three-way possibilities */
i2 = active[c];
hits = 0;
for(d = 0; d < pc; d++) {
p1 = *(pair + d * 2);
p2 = *(pair + d * 2 + 1);
if((p1 == i0) && (p2 == i1))
hits++;
else if((p1 == i1) && (p2 == i2))
hits++;
else if((p1 == i0) && (p2 == i2))
hits++;
}
if(hits >= 3) {
v0 = v + i0 * 3;
v1 = v + i1 * 3;
v2 = v + i2 * 3;
if(within3f(v0, v1, cutoff) &&
within3f(v1, v2, cutoff) &&
within3f(v0, v2, cutoff)) {
n0 = vn + 3 * i0;
n1 = vn + 3 * i1;
n2 = vn + 3 * i2;
add3f(n0, n1, vt1);
add3f(n2, vt1, vt2);
subtract3f(v1, v0, vt3);
subtract3f(v2, v0, vt4);
cross_product3f(vt3, vt4, tNorm);
normalize3f(tNorm);
dp = dot_product3f(vt2, tNorm);
if(dp < 0)
scale3f(tNorm, -1.0F, tNorm);
TriangleAdd(I, i0, i1, i2, tNorm, v, vn);
}
}
}
}
if(I->G->Interrupt) {
ok = false;
break;
}
}
}
}
FreeP(active);
FreeP(pair);
FreeP(pFlag);
if(I->G->Interrupt)
ok = false;
return ok;
}
int *TrianglePointsToSurface(PyMOLGlobals * G, float *v, float *vn, int n,
float cutoff, int *nTriPtr, int **stripPtr,
float *extent, int cavity_mode)
{
TriangleSurfaceRec *I = NULL;
int ok = true;
int *result = NULL;
MapType *map;
int a;
if(n >= 3) {
I = Alloc(TriangleSurfaceRec, 1);
if(I) {
float maxEdgeLen = 0.0F;
I->G = G;
I->N = n;
I->nActive = 0;
I->activeEdge = VLAlloc(int, 1000);
I->link = VLAlloc(LinkType, n * 2);
UtilZeroMem(I->link, sizeof(LinkType));
I->nLink = 1;
I->vNormal = VLAlloc(float, n * 2);
I->edge = VLAlloc(EdgeRec, n * 2);
UtilZeroMem(I->edge, sizeof(EdgeRec));
I->nEdge = 1;
I->tri = VLAlloc(int, n);
I->nTri = 0;
if(cavity_mode) {
maxEdgeLen = (cutoff*1.414F);
I->maxEdgeLenSq = maxEdgeLen * maxEdgeLen;
} else {
I->maxEdgeLenSq = MAXFLOAT;
}
I->map = MapNew(I->G, cutoff, v, n, extent);
MapSetupExpress(I->map);
map = I->map;
MapCacheInit(&I->map_cache, map, 0, 0);
if(G->Interrupt)
ok = false;
if(ok) {
I->edgeStatus = Alloc(int, n);
for(a = 0; a < n; a++) {
I->edgeStatus[a] = 0;
}
I->vertActive = Alloc(int, n);
for(a = 0; a < n; a++) {
I->vertActive[a] = -1;
}
I->vertWeight = Alloc(int, n);
for(a = 0; a < n; a++) {
I->vertWeight[a] = 2;
}
}
if(ok) {
ok = TriangleFill(I, v, vn, n, true);
}
if(ok) {
if(Feedback(G, FB_Triangle, FB_Debugging)) {
for(a = 0; a < n; a++)
if(I->vertActive[a])
printf(" TrianglePTS-DEBUG: before fix %i %i\n", a, I->vertActive[a]);
}
}
if(ok)
ok = TriangleTxfFolds(I, v, vn, n);
if(ok)
ok = TriangleFixProblems(I, v, vn, n);
if(Feedback(G, FB_Triangle, FB_Debugging)) {
for(a = 0; a < n; a++)
if(I->vertActive[a])
printf(" TrianglePTS-DEBUG: after fix %i %i\n", a, I->vertActive[a]);
}
if(ok) {
if(cavity_mode) {
ok = TriangleBruteForceClosure(I, v, vn, n, maxEdgeLen);
} else {
ok = TriangleBruteForceClosure(I, v, vn, n, cutoff * 3);
}
}
/* abandon algorithm, just CLOSE THOSE GAPS! */
if(ok)
ok = TriangleAdjustNormals(I, v, vn, n, true);
if(ok) {
*(stripPtr) = TriangleMakeStripVLA(I, v, vn, n);
}
(*nTriPtr) = I->nTri;
VLAFreeP(I->activeEdge);
VLAFreeP(I->link);
VLAFreeP(I->vNormal);
VLAFreeP(I->edge);
FreeP(I->edgeStatus);
FreeP(I->vertActive);
FreeP(I->vertWeight);
MapCacheFree(&I->map_cache, 0, 0);
MapFree(map);
result = I->tri;
}
FreeP(I);
}
if(!ok) {
VLAFreeP(result);
}
return (result);
}
void CalculateTriangleNormal(float *p1, float *p2, float *p3, float *n){
float v1[3], v2[3];
subtract3f(p2, p1, v1);
subtract3f(p3, p1, v2);
cross_product3f(v1, v2, n);
}