1 |
|
|
/* |
2 |
|
|
Teem: Tools to process and visualize scientific data and images . |
3 |
|
|
Copyright (C) 2011, 2010, 2009, 2008 Thomas Schultz |
4 |
|
|
|
5 |
|
|
This library is free software; you can redistribute it and/or |
6 |
|
|
modify it under the terms of the GNU Lesser General Public License |
7 |
|
|
(LGPL) as published by the Free Software Foundation; either |
8 |
|
|
version 2.1 of the License, or (at your option) any later version. |
9 |
|
|
The terms of redistributing and/or modifying this software also |
10 |
|
|
include exceptions to the LGPL that facilitate static linking. |
11 |
|
|
|
12 |
|
|
This library is distributed in the hope that it will be useful, |
13 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 |
|
|
Lesser General Public License for more details. |
16 |
|
|
|
17 |
|
|
You should have received a copy of the GNU Lesser General Public License |
18 |
|
|
along with this library; if not, write to Free Software Foundation, Inc., |
19 |
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 |
|
|
*/ |
21 |
|
|
|
22 |
|
|
/* This file collects functions that implement extraction of crease |
23 |
|
|
* surfaces as proposed in Schultz / Theisel / Seidel, "Crease |
24 |
|
|
* Surfaces: From Theory to Extraction and Application to Diffusion |
25 |
|
|
* Tensor MRI", IEEE TVCG 16(1):109-119, 2010 */ |
26 |
|
|
|
27 |
|
|
#include "seek.h" |
28 |
|
|
#include "privateSeek.h" |
29 |
|
|
|
30 |
|
|
/* private helper routines for the T-based extraction */ |
31 |
|
|
|
32 |
|
|
/* Converts a Hessian into the transformed tensor T (cf. paper) |
33 |
|
|
* |
34 |
|
|
* T is a 9-vector representing the output |
35 |
|
|
* evals is a 3-vector (eigenvalues of the Hessian) |
36 |
|
|
* evecs is a 9-vector (eigenvectors of the Hessian) |
37 |
|
|
* evalDiffThresh is the threshold parameter theta (cf. Eq. (4) in paper) |
38 |
|
|
* ridge is non-zero if we are looking for a ridge (zero for valley) |
39 |
|
|
*/ |
40 |
|
|
void |
41 |
|
|
_seekHess2T(double *T, const double *evals, const double *evecs, |
42 |
|
|
const double evalDiffThresh, const char ridge) { |
43 |
|
|
double lambdas[3]={0.0,0.0,0.0}; |
44 |
|
|
double tmpMat[9], diag[9], evecsT[9]; |
45 |
|
|
if (ridge) { |
46 |
|
|
double diff = evals[1]-evals[2]; |
47 |
|
|
lambdas[0]=lambdas[1]=1.0; |
48 |
|
|
if (diff<evalDiffThresh) |
49 |
|
|
lambdas[2]=(1.0-diff/evalDiffThresh)*(1.0-diff/evalDiffThresh); |
50 |
|
|
} else { |
51 |
|
|
double diff = evals[0]-evals[1]; |
52 |
|
|
lambdas[1]=lambdas[2]=1.0; |
53 |
|
|
if (diff<evalDiffThresh) |
54 |
|
|
lambdas[0]=(1.0-diff/evalDiffThresh)*(1.0-diff/evalDiffThresh); |
55 |
|
|
} |
56 |
|
|
ELL_3M_ZERO_SET(diag); |
57 |
|
|
ELL_3M_DIAG_SET(diag, lambdas[0], lambdas[1], lambdas[2]); |
58 |
|
|
ELL_3M_TRANSPOSE(evecsT, evecs); |
59 |
|
|
ELL_3M_MUL(tmpMat, diag, evecs); |
60 |
|
|
ELL_3M_MUL(T, evecsT, tmpMat); |
61 |
|
|
} |
62 |
|
|
|
63 |
|
|
/* Converts a Hessian derivative into a derivative of the transformed |
64 |
|
|
* tensor field T |
65 |
|
|
* |
66 |
|
|
* Tder is a 9-vector representing the output |
67 |
|
|
* hessder is a 9-vector (Hessian derivative) |
68 |
|
|
* evals is a 3-vector (eigenvalues of the Hessian value) |
69 |
|
|
* evecs is a 9-vector (eigenvectors of the Hessian value) |
70 |
|
|
* evalDiffThresh is the threshold parameter theta (cf. Eq. (4) in the paper) |
71 |
|
|
* ridge is non-zero if we are looking for a ridge (zero for valley) |
72 |
|
|
*/ |
73 |
|
|
void |
74 |
|
|
_seekHessder2Tder(double *Tder, const double *hessder, const double *evals, |
75 |
|
|
const double *evecs, const double evalDiffThresh, |
76 |
|
|
const char ridge) { |
77 |
|
|
double evecTrans[9]; |
78 |
|
|
double hessderE[9]; /* Hessian derivative in eigenframe */ |
79 |
|
|
double tmp[9]; |
80 |
|
|
ELL_3M_TRANSPOSE(evecTrans,evecs); |
81 |
|
|
ell_3m_mul_d(tmp,hessder,evecTrans); |
82 |
|
|
ell_3m_mul_d(hessderE,evecs,tmp); |
83 |
|
|
|
84 |
|
|
if (ridge) { |
85 |
|
|
double diff=evals[1]-evals[2]; |
86 |
|
|
double l3; |
87 |
|
|
double l3der; |
88 |
|
|
if (diff<evalDiffThresh) |
89 |
|
|
l3=(1.0-diff/evalDiffThresh)*(1.0-diff/evalDiffThresh); |
90 |
|
|
else l3=0.0; |
91 |
|
|
hessderE[2]*=(1.0-l3)/(evals[0]-evals[2]); |
92 |
|
|
hessderE[6]=hessderE[2]; |
93 |
|
|
hessderE[5]*=(1.0-l3)/(evals[1]-evals[2]); |
94 |
|
|
hessderE[7]=hessderE[5]; |
95 |
|
|
|
96 |
|
|
if (diff<evalDiffThresh) |
97 |
|
|
l3der = 2/evalDiffThresh*(1-diff/evalDiffThresh)* |
98 |
|
|
(hessderE[8]-hessderE[4]); |
99 |
|
|
else |
100 |
|
|
l3der=0; |
101 |
|
|
hessderE[8]=l3der; |
102 |
|
|
hessderE[0]=hessderE[1]=hessderE[3]=hessderE[4]=0.0; |
103 |
|
|
} else { |
104 |
|
|
double diff=evals[0]-evals[1]; |
105 |
|
|
double l1; |
106 |
|
|
double l1der; |
107 |
|
|
if (diff<evalDiffThresh) |
108 |
|
|
l1=(1.0-diff/evalDiffThresh)*(1.0-diff/evalDiffThresh); |
109 |
|
|
else l1=0.0; |
110 |
|
|
hessderE[1]*=(l1-1.0)/(evals[0]-evals[1]); |
111 |
|
|
hessderE[3]=hessderE[1]; |
112 |
|
|
hessderE[2]*=(l1-1.0)/(evals[0]-evals[2]); |
113 |
|
|
hessderE[6]=hessderE[2]; |
114 |
|
|
|
115 |
|
|
if (diff<evalDiffThresh) |
116 |
|
|
l1der = 2/evalDiffThresh*(1-diff/evalDiffThresh)* |
117 |
|
|
(hessderE[4]-hessderE[0]); |
118 |
|
|
else |
119 |
|
|
l1der = 0; |
120 |
|
|
hessderE[0]=l1der; |
121 |
|
|
hessderE[4]=hessderE[5]=hessderE[7]=hessderE[8]=0.0; |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
ell_3m_mul_d(tmp,hessderE,evecs); |
125 |
|
|
ell_3m_mul_d(Tder,evecTrans,tmp); |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
static int |
129 |
|
|
findFeatureIntersection(double *results, double *Tleft, |
130 |
|
|
double *hessleft, double *gleft, |
131 |
|
|
double *Tright, double *hessright, |
132 |
|
|
double *gright, double idxleft, |
133 |
|
|
double idxright, char ridge, |
134 |
|
|
const double evalDiffThresh, |
135 |
|
|
const double dotThresh) { |
136 |
|
|
double Tdp = ELL_3V_DOT(Tleft, Tright) + ELL_3V_DOT(Tleft+3,Tright+3) + |
137 |
|
|
ELL_3V_DOT(Tleft+6,Tright+6); |
138 |
|
|
double denom_l = sqrt(ELL_3V_DOT(Tleft, Tleft) + ELL_3V_DOT(Tleft+3, Tleft+3) |
139 |
|
|
+ ELL_3V_DOT(Tleft+6, Tleft+6)), |
140 |
|
|
denom_r = sqrt(ELL_3V_DOT(Tright,Tright) + ELL_3V_DOT(Tright+3, Tright+3) |
141 |
|
|
+ ELL_3V_DOT(Tright+6, Tright+6)); |
142 |
|
|
|
143 |
|
|
if (Tdp/(denom_l*denom_r)<dotThresh && |
144 |
|
|
idxright-idxleft>0.24) { /* do a recursive step */ |
145 |
|
|
double idxcenter = 0.5*(idxleft+idxright); |
146 |
|
|
/* simply interpolate Hessian linearly */ |
147 |
|
|
double hessnew[9]; |
148 |
|
|
double evals[3],evecs[9]; |
149 |
|
|
double Tnew[9], gradnew[3]; |
150 |
|
|
int retval; |
151 |
|
|
|
152 |
|
|
ELL_3M_LERP(hessnew,0.5,hessleft,hessright); |
153 |
|
|
ell_3m_eigensolve_d(evals, evecs, hessnew, AIR_TRUE); |
154 |
|
|
|
155 |
|
|
_seekHess2T(Tnew, evals, evecs, evalDiffThresh, ridge); |
156 |
|
|
|
157 |
|
|
ELL_3V_LERP(gradnew,0.5,gleft,gright); |
158 |
|
|
retval = findFeatureIntersection(results, Tleft, hessleft, |
159 |
|
|
gleft, Tnew, hessnew, gradnew, |
160 |
|
|
idxleft, idxcenter, |
161 |
|
|
ridge, evalDiffThresh, dotThresh); |
162 |
|
|
retval += findFeatureIntersection(results+retval, Tnew, hessnew, |
163 |
|
|
gradnew, Tright, hessright, gright, |
164 |
|
|
idxcenter, idxright, |
165 |
|
|
ridge, evalDiffThresh, dotThresh); |
166 |
|
|
return retval; |
167 |
|
|
} else { |
168 |
|
|
double d1[3], d4[3]; |
169 |
|
|
ell_3mv_mul_d(d1, Tleft, gleft); |
170 |
|
|
ELL_3V_SUB(d1,d1,gleft); |
171 |
|
|
ell_3mv_mul_d(d4, Tright, gright); |
172 |
|
|
ELL_3V_SUB(d4,d4,gright); |
173 |
|
|
|
174 |
|
|
if (ELL_3V_DOT(d1,d4)<0) { /* mark edge as crossed */ |
175 |
|
|
/* find assumed intersection point */ |
176 |
|
|
double diff[3], dlen, alpha; |
177 |
|
|
ELL_3V_SUB(diff,d4,d1); |
178 |
|
|
dlen=ELL_3V_LEN(diff); |
179 |
|
|
if (dlen>1e-5) { |
180 |
|
|
double ap=-ELL_3V_DOT(d1,diff)/dlen; |
181 |
|
|
alpha = ap/dlen; |
182 |
|
|
} else |
183 |
|
|
alpha = 0.5; |
184 |
|
|
|
185 |
|
|
*results = (1-alpha)*idxleft+alpha*idxright; |
186 |
|
|
return 1; |
187 |
|
|
} |
188 |
|
|
} |
189 |
|
|
return 0; |
190 |
|
|
} |
191 |
|
|
|
192 |
|
|
/* Assuming (simplistic) linearly interpolated Hessians and gradients, |
193 |
|
|
* computes the analytical normal of the crease surface. |
194 |
|
|
* The result is _not_ normalized. */ |
195 |
|
|
static void |
196 |
|
|
computeGradientLin(double *result, double *T, double *g, |
197 |
|
|
double *Txm, double *gxm, double *Txp, double *gxp, |
198 |
|
|
double *Tym, double *gym, double *Typ, double *gyp, |
199 |
|
|
double *Tzm, double *gzm, double *Tzp, double *gzp) { |
200 |
|
|
double Tder[9]; |
201 |
|
|
double gder[3]; |
202 |
|
|
double tmp[3], tmp1[3], tmp2[3]; |
203 |
|
|
double derxv[3], deryv[3], derzv[3]; |
204 |
|
|
ELL_3M_SUB(Tder,Txp,Txm); |
205 |
|
|
ELL_3V_SUB(gder,gxp,gxm); |
206 |
|
|
ell_3mv_mul_d(tmp,T,gder); |
207 |
|
|
ELL_3V_SUB(tmp,tmp,gder); |
208 |
|
|
ell_3mv_mul_d(derxv,Tder,g); |
209 |
|
|
ELL_3V_ADD2(derxv,derxv,tmp); |
210 |
|
|
|
211 |
|
|
ELL_3M_SUB(Tder,Typ,Tym); |
212 |
|
|
ELL_3V_SUB(gder,gyp,gym); |
213 |
|
|
ell_3mv_mul_d(tmp,T,gder); |
214 |
|
|
ELL_3V_SUB(tmp,tmp,gder); |
215 |
|
|
ell_3mv_mul_d(deryv,Tder,g); |
216 |
|
|
ELL_3V_ADD2(deryv,deryv,tmp); |
217 |
|
|
|
218 |
|
|
ELL_3M_SUB(Tder,Tzp,Tzm); |
219 |
|
|
ELL_3V_SUB(gder,gzp,gzm); |
220 |
|
|
ell_3mv_mul_d(tmp,T,gder); |
221 |
|
|
ELL_3V_SUB(tmp,tmp,gder); |
222 |
|
|
ell_3mv_mul_d(derzv,Tder,g); |
223 |
|
|
ELL_3V_ADD2(derzv,derzv,tmp); |
224 |
|
|
|
225 |
|
|
/* accumulate a gradient */ |
226 |
|
|
tmp1[0]=derxv[0]; tmp1[1]=deryv[0]; tmp1[2]=derzv[0]; |
227 |
|
|
tmp2[0]=derxv[1]; tmp2[1]=deryv[1]; tmp2[2]=derzv[1]; |
228 |
|
|
if (ELL_3V_DOT(tmp1,tmp2)<0) |
229 |
|
|
ELL_3V_SCALE(tmp2,-1.0,tmp2); |
230 |
|
|
ELL_3V_ADD2(tmp1,tmp1,tmp2); |
231 |
|
|
tmp2[0]=derxv[2]; tmp2[1]=deryv[2]; tmp2[2]=derzv[2]; |
232 |
|
|
if (ELL_3V_DOT(tmp1,tmp2)<0) |
233 |
|
|
ELL_3V_SCALE(tmp2,-1.0,tmp2); |
234 |
|
|
ELL_3V_ADD2(result,tmp1,tmp2); |
235 |
|
|
} |
236 |
|
|
|
237 |
|
|
/* Given a unique edge ID and an intersection point given by some value |
238 |
|
|
* alpha \in [0,1], compute the crease surface normal at that point */ |
239 |
|
|
static void |
240 |
|
|
computeEdgeGradient(seekContext *sctx, baggage *bag, double *res, |
241 |
|
|
unsigned int xi, unsigned int yi, char edgeid, double alpha) |
242 |
|
|
{ |
243 |
|
|
double Txm[9], Txp[9], Tym[9], Typ[9], Tzm[9], Tzp[9], T[9], |
244 |
|
|
gxm[3], gxp[3], gym[3], gyp[3], gzm[3], gzp[3], g[3]; |
245 |
|
|
|
246 |
|
|
unsigned int sx = AIR_CAST(unsigned int, sctx->sx); |
247 |
|
|
unsigned int sy = AIR_CAST(unsigned int, sctx->sy); |
248 |
|
|
unsigned int sz = AIR_CAST(unsigned int, sctx->sz); |
249 |
|
|
unsigned int si = xi + sx*yi; |
250 |
|
|
unsigned int six = xi + 1 + sx*yi, siX = xi - 1 + sx*yi; |
251 |
|
|
unsigned int siy = xi + sx*(yi+1), siY = xi + sx*(yi-1); |
252 |
|
|
unsigned int sixy = xi + 1 + sx*(yi+1), |
253 |
|
|
sixY = xi + 1 + sx*(yi-1), |
254 |
|
|
siXy = xi - 1 + sx*(yi+1); |
255 |
|
|
/* many special cases needed to fill Txm, gxm, etc. :-( */ |
256 |
|
|
switch (edgeid) { |
257 |
|
|
case 0: |
258 |
|
|
ELL_3M_LERP(T, alpha, sctx->t + 9*(0+2*si), sctx->t + 9*(0+2*six)); |
259 |
|
|
ELL_3V_LERP(g, alpha, sctx->grad + 3*(0+2*si), sctx->grad + 3*(0+2*six)); |
260 |
|
|
ELL_3M_LERP(Tzp, alpha, sctx->t + 9*(1+2*si), sctx->t + 9*(1+2*six)); |
261 |
|
|
ELL_3V_LERP(gzp, alpha, sctx->grad + 3*(1+2*si), sctx->grad + 3*(1+2*six)); |
262 |
|
|
if (bag->zi==0) { |
263 |
|
|
ELL_3M_COPY(Tzm, T); ELL_3V_COPY(gzm, g); |
264 |
|
|
} else { |
265 |
|
|
ELL_3M_LERP(Tzm, alpha, sctx->tcontext + 9*(0+2*si), |
266 |
|
|
sctx->tcontext + 9*(0+2*six)); |
267 |
|
|
ELL_3V_LERP(gzm, alpha, sctx->gradcontext + 3*(0+2*si), |
268 |
|
|
sctx->gradcontext + 3*(0+2*six)); |
269 |
|
|
ELL_3M_SCALE(Tzm, 0.5, Tzm); ELL_3M_SCALE(Tzp, 0.5, Tzp); |
270 |
|
|
ELL_3V_SCALE(gzm, 0.5, gzm); ELL_3V_SCALE(gzp, 0.5, gzp); |
271 |
|
|
} |
272 |
|
|
if (yi==0) { |
273 |
|
|
ELL_3M_COPY(Tym, T); ELL_3V_COPY(gym, g); |
274 |
|
|
} else { |
275 |
|
|
ELL_3M_LERP(Tym, alpha, sctx->t + 9*(0+2*siY), sctx->t + 9*(0+2*sixY)); |
276 |
|
|
ELL_3V_LERP(gym, alpha, sctx->grad + 3*(0+2*siY), |
277 |
|
|
sctx->grad + 3*(0+2*sixY)); |
278 |
|
|
} |
279 |
|
|
if (yi==sy-1) { |
280 |
|
|
ELL_3M_COPY(Typ, T); ELL_3V_COPY(gyp, g); |
281 |
|
|
} else { |
282 |
|
|
ELL_3M_LERP(Typ, alpha, sctx->t + 9*(0+2*siy), sctx->t + 9*(0+2*sixy)); |
283 |
|
|
ELL_3V_LERP(gyp, alpha, sctx->grad + 3*(0+2*siy), |
284 |
|
|
sctx->grad + 3*(0+2*sixy)); |
285 |
|
|
} |
286 |
|
|
if (yi!=0 && yi!=sy-1) { |
287 |
|
|
ELL_3M_SCALE(Tym, 0.5, Tym); ELL_3M_SCALE(Typ, 0.5, Typ); |
288 |
|
|
ELL_3V_SCALE(gym, 0.5, gym); ELL_3V_SCALE(gyp, 0.5, gyp); |
289 |
|
|
} |
290 |
|
|
computeGradientLin(res, T, g, |
291 |
|
|
sctx->t + 9*(0+2*si), sctx->grad + 3*(0+2*si), |
292 |
|
|
sctx->t + 9*(0+2*six), sctx->grad + 3*(0+2*six), |
293 |
|
|
Tym, gym, Typ, gyp, |
294 |
|
|
Tzm, gzm, Tzp, gzp); |
295 |
|
|
break; |
296 |
|
|
case 1: |
297 |
|
|
ELL_3M_LERP(T, alpha, sctx->t + 9*(0+2*si), sctx->t + 9*(0+2*siy)); |
298 |
|
|
ELL_3V_LERP(g, alpha, sctx->grad + 3*(0+2*si), sctx->grad + 3*(0+2*siy)); |
299 |
|
|
ELL_3M_LERP(Tzp, alpha, sctx->t + 9*(1+2*si), sctx->t + 9*(1+2*siy)); |
300 |
|
|
ELL_3V_LERP(gzp, alpha, sctx->grad + 3*(1+2*si), sctx->grad + 3*(1+2*siy)); |
301 |
|
|
if (bag->zi==0) { |
302 |
|
|
ELL_3M_COPY(Tzm, T); ELL_3V_COPY(gzm, g); |
303 |
|
|
} else { |
304 |
|
|
ELL_3M_LERP(Tzm, alpha, sctx->tcontext + 9*(0+2*si), |
305 |
|
|
sctx->tcontext + 9*(0+2*siy)); |
306 |
|
|
ELL_3V_LERP(gzm, alpha, sctx->gradcontext + 3*(0+2*si), |
307 |
|
|
sctx->gradcontext + 3*(0+2*siy)); |
308 |
|
|
ELL_3M_SCALE(Tzm, 0.5, Tzm); ELL_3M_SCALE(Tzp, 0.5, Tzp); |
309 |
|
|
ELL_3V_SCALE(gzm, 0.5, gzm); ELL_3V_SCALE(gzp, 0.5, gzp); |
310 |
|
|
} |
311 |
|
|
if (xi==0) { |
312 |
|
|
ELL_3M_COPY(Txm, T); ELL_3V_COPY(gxm, g); |
313 |
|
|
} else { |
314 |
|
|
ELL_3M_LERP(Txm, alpha, sctx->t + 9*(0+2*siX), sctx->t + 9*(0+2*siXy)); |
315 |
|
|
ELL_3V_LERP(gxm, alpha, sctx->grad + 3*(0+2*siX), |
316 |
|
|
sctx->grad + 3*(0+2*siXy)); |
317 |
|
|
} |
318 |
|
|
if (xi==sx-1) { |
319 |
|
|
ELL_3M_COPY(Txp, T); ELL_3V_COPY(gxm, g); |
320 |
|
|
} else { |
321 |
|
|
ELL_3M_LERP(Txp, alpha, sctx->t + 9*(0+2*six), sctx->t + 9*(0+2*sixy)); |
322 |
|
|
ELL_3V_LERP(gxp, alpha, sctx->grad + 3*(0+2*six), |
323 |
|
|
sctx->grad + 3*(0+2*sixy)); |
324 |
|
|
} |
325 |
|
|
if (xi!=0 && xi!=sx-1) { |
326 |
|
|
ELL_3M_SCALE(Txm, 0.5, Txm); ELL_3M_SCALE(Txp, 0.5, Txp); |
327 |
|
|
ELL_3V_SCALE(gxm, 0.5, gxm); ELL_3V_SCALE(gxp, 0.5, gxp); |
328 |
|
|
} |
329 |
|
|
computeGradientLin(res, T, g, |
330 |
|
|
Txm, gxm, Txp, gxp, |
331 |
|
|
sctx->t + 9*(0+2*si), sctx->grad + 3*(0+2*si), |
332 |
|
|
sctx->t + 9*(0+2*siy), sctx->grad + 3*(0+2*siy), |
333 |
|
|
T, g, Tzp, gzp); |
334 |
|
|
break; |
335 |
|
|
case 2: |
336 |
|
|
ELL_3M_LERP(T, alpha, sctx->t + 9*(0+2*si), sctx->t + 9*(1+2*si)); |
337 |
|
|
ELL_3V_LERP(g, alpha, sctx->grad + 3*(0+2*si), sctx->grad + 3*(1+2*si)); |
338 |
|
|
if (xi==0) { |
339 |
|
|
ELL_3M_COPY(Txm, T); ELL_3V_COPY(gxm, g); |
340 |
|
|
} else { |
341 |
|
|
ELL_3M_LERP(Txm, alpha, sctx->t + 9*(0+2*siX), sctx->t + 9*(1+2*siX)); |
342 |
|
|
ELL_3V_LERP(gxm, alpha, sctx->grad + 3*(0+2*siX), |
343 |
|
|
sctx->grad + 3*(1+2*siX)); |
344 |
|
|
} |
345 |
|
|
if (xi==sx-1) { |
346 |
|
|
ELL_3M_COPY(Txp, T); ELL_3V_COPY(gxp, g); |
347 |
|
|
} else { |
348 |
|
|
ELL_3M_LERP(Txp, alpha, sctx->t + 9*(0+2*six), sctx->t + 9*(1+2*six)); |
349 |
|
|
ELL_3V_LERP(gxp, alpha, sctx->grad + 3*(0+2*six), |
350 |
|
|
sctx->grad + 3*(1+2*six)); |
351 |
|
|
} |
352 |
|
|
if (xi!=0 && xi!=sx-1) { |
353 |
|
|
ELL_3M_SCALE(Txm, 0.5, Txm); ELL_3M_SCALE(Txp, 0.5, Txp); |
354 |
|
|
ELL_3V_SCALE(gxm, 0.5, gxm); ELL_3V_SCALE(gxp, 0.5, gxp); |
355 |
|
|
} |
356 |
|
|
if (yi==0) { |
357 |
|
|
ELL_3M_COPY(Tym, T); ELL_3V_COPY(gym, g); |
358 |
|
|
} else { |
359 |
|
|
ELL_3M_LERP(Tym, alpha, sctx->t + 9*(0+2*siY), sctx->t + 9*(1+2*siY)); |
360 |
|
|
ELL_3V_LERP(gym, alpha, sctx->grad + 3*(0+2*siY), |
361 |
|
|
sctx->grad + 3*(1+2*siY)); |
362 |
|
|
} |
363 |
|
|
if (yi==sy-1) { |
364 |
|
|
ELL_3M_COPY(Typ, T); ELL_3V_COPY(gyp, g); |
365 |
|
|
} else { |
366 |
|
|
ELL_3M_LERP(Typ, alpha, sctx->t + 9*(0+2*siy), sctx->t + 9*(1+2*siy)); |
367 |
|
|
ELL_3V_LERP(gyp, alpha, sctx->grad + 3*(0+2*siy), |
368 |
|
|
sctx->grad + 3*(1+2*siy)); |
369 |
|
|
} |
370 |
|
|
if (yi!=0 && yi!=sy-1) { |
371 |
|
|
ELL_3M_SCALE(Tym, 0.5, Tym); ELL_3M_SCALE(Typ, 0.5, Typ); |
372 |
|
|
ELL_3V_SCALE(gym, 0.5, gym); ELL_3V_SCALE(gyp, 0.5, gyp); |
373 |
|
|
} |
374 |
|
|
if (bag->zi>0 && bag->zi<sz-2) { |
375 |
|
|
ELL_3M_LERP(Tzm, alpha, sctx->tcontext + 9*(0+2*si), |
376 |
|
|
sctx->t + 9*(0+2*si)); |
377 |
|
|
ELL_3V_LERP(gzm, alpha, sctx->gradcontext + 3*(0+2*si), |
378 |
|
|
sctx->grad + 3*(0+2*si)); |
379 |
|
|
ELL_3M_LERP(Tzp, alpha, sctx->t + 9*(1+2*si), |
380 |
|
|
sctx->tcontext + 9*(1+2*si)); |
381 |
|
|
ELL_3V_LERP(gzp, alpha, sctx->grad + 3*(1+2*si), |
382 |
|
|
sctx->gradcontext + 3*(1+2*si)); |
383 |
|
|
ELL_3M_SCALE(Tzm, 0.5, Tzm); ELL_3M_SCALE(Tzp, 0.5, Tzp); |
384 |
|
|
ELL_3V_SCALE(gzm, 0.5, gzm); ELL_3V_SCALE(gzp, 0.5, gzp); |
385 |
|
|
} else { |
386 |
|
|
ELL_3M_COPY(Tzm, sctx->t + 9*(0+2*si)); |
387 |
|
|
ELL_3V_COPY(gzm, sctx->grad + 3*(0+2*si)); |
388 |
|
|
ELL_3M_COPY(Tzp, sctx->t + 9*(1+2*si)); |
389 |
|
|
ELL_3V_COPY(gzp, sctx->grad + 3*(1+2*si)); |
390 |
|
|
} |
391 |
|
|
computeGradientLin(res, T, g, |
392 |
|
|
Txm, gxm, Txp, gxp, |
393 |
|
|
Tym, gym, Typ, gyp, |
394 |
|
|
Tzm, gzm, Tzp, gzp); |
395 |
|
|
break; |
396 |
|
|
case 3: |
397 |
|
|
ELL_3M_LERP(T, alpha, sctx->t + 9*(1+2*si), sctx->t + 9*(1+2*six)); |
398 |
|
|
ELL_3V_LERP(g, alpha, sctx->grad + 3*(1+2*si), sctx->grad + 3*(1+2*six)); |
399 |
|
|
ELL_3M_LERP(Tzm, alpha, sctx->t + 9*(0+2*si), sctx->t + 9*(0+2*six)); |
400 |
|
|
ELL_3V_LERP(gzm, alpha, sctx->grad + 3*(0+2*si), sctx->grad + 3*(0+2*six)); |
401 |
|
|
if (bag->zi==sz-2) { |
402 |
|
|
ELL_3M_COPY(Tzp, T); ELL_3V_COPY(gzp, g); |
403 |
|
|
} else { |
404 |
|
|
ELL_3M_LERP(Tzp, alpha, sctx->tcontext + 9*(1+2*si), |
405 |
|
|
sctx->tcontext + 9*(1+2*six)); |
406 |
|
|
ELL_3V_LERP(gzp, alpha, sctx->gradcontext + 3*(1+2*si), |
407 |
|
|
sctx->gradcontext + 3*(1+2*six)); |
408 |
|
|
ELL_3M_SCALE(Tzm, 0.5, Tzm); ELL_3M_SCALE(Tzp, 0.5, Tzp); |
409 |
|
|
ELL_3V_SCALE(gzm, 0.5, gzm); ELL_3V_SCALE(gzp, 0.5, gzp); |
410 |
|
|
} |
411 |
|
|
if (xi>0 && xi<sx-2) { |
412 |
|
|
unsigned int sixx = xi + 2 + sx*yi; |
413 |
|
|
ELL_3M_LERP(Txm, alpha, sctx->t + 9*(1+2*siX), sctx->t + 9*(1+2*si)); |
414 |
|
|
ELL_3V_LERP(gxm, alpha, sctx->grad + 3*(1+2*siX), |
415 |
|
|
sctx->grad + 3*(1+2*si)); |
416 |
|
|
ELL_3M_LERP(Txp, alpha, sctx->t + 9*(1+2*six), sctx->t + 9*(1+2*sixx)); |
417 |
|
|
ELL_3V_LERP(gxp, alpha, sctx->grad + 3*(1+2*six), |
418 |
|
|
sctx->grad + 3*(1+2*sixx)); |
419 |
|
|
ELL_3M_SCALE(Txm, 0.5, Txm); ELL_3M_SCALE(Txp, 0.5, Txp); |
420 |
|
|
ELL_3V_SCALE(gxm, 0.5, gxm); ELL_3V_SCALE(gxp, 0.5, gxp); |
421 |
|
|
} else { |
422 |
|
|
ELL_3M_COPY(Txm, sctx->t + 9*(1+2*si)); |
423 |
|
|
ELL_3V_COPY(gxm, sctx->grad + 3*(1+2*si)); |
424 |
|
|
ELL_3M_COPY(Txp, sctx->t + 9*(1+2*six)); |
425 |
|
|
ELL_3V_COPY(gxp, sctx->grad + 3*(1+2*six)); |
426 |
|
|
} |
427 |
|
|
if (yi==0) { |
428 |
|
|
ELL_3M_COPY(Tym, T); ELL_3V_COPY(gym, g); |
429 |
|
|
} else { |
430 |
|
|
ELL_3M_LERP(Tym, alpha, sctx->t + 9*(1+2*siY), sctx->t + 9*(1+2*sixY)); |
431 |
|
|
ELL_3V_LERP(gym, alpha, sctx->grad + 3*(1+2*siY), |
432 |
|
|
sctx->grad + 3*(1+2*sixY)); |
433 |
|
|
} |
434 |
|
|
if (yi==sy-1) { |
435 |
|
|
ELL_3M_COPY(Typ, T); ELL_3V_COPY(gyp, g); |
436 |
|
|
} else { |
437 |
|
|
ELL_3M_LERP(Typ, alpha, sctx->t + 9*(1+2*siy), sctx->t + 9*(1+2*sixy)); |
438 |
|
|
ELL_3V_LERP(gyp, alpha, sctx->grad + 3*(1+2*siy), |
439 |
|
|
sctx->grad + 3*(1+2*sixy)); |
440 |
|
|
} |
441 |
|
|
if (yi!=0 && yi!=sy-1) { |
442 |
|
|
ELL_3M_SCALE(Tym, 0.5, Tym); ELL_3M_SCALE(Typ, 0.5, Typ); |
443 |
|
|
ELL_3V_SCALE(gym, 0.5, gym); ELL_3V_SCALE(gyp, 0.5, gyp); |
444 |
|
|
} |
445 |
|
|
computeGradientLin(res, T, g, |
446 |
|
|
Txm, gxm, Txp, gxp, |
447 |
|
|
Tym, gym, Typ, gyp, |
448 |
|
|
Tzm, gzm, Tzp, gzp); |
449 |
|
|
break; |
450 |
|
|
case 4: |
451 |
|
|
ELL_3M_LERP(T, alpha, sctx->t + 9*(1+2*si), sctx->t + 9*(1+2*siy)); |
452 |
|
|
ELL_3V_LERP(g, alpha, sctx->grad + 3*(1+2*si), sctx->grad + 3*(1+2*siy)); |
453 |
|
|
ELL_3M_LERP(Tzm, alpha, sctx->t + 9*(0+2*si), sctx->t + 9*(0+2*siy)); |
454 |
|
|
ELL_3V_LERP(gzm, alpha, sctx->grad + 3*(0+2*si), sctx->grad + 3*(0+2*siy)); |
455 |
|
|
if (bag->zi==sz-2) { |
456 |
|
|
ELL_3M_COPY(Tzp, T); ELL_3V_COPY(gzp, g); |
457 |
|
|
} else { |
458 |
|
|
ELL_3M_LERP(Tzp, alpha, sctx->tcontext + 9*(1+2*si), |
459 |
|
|
sctx->tcontext + 9*(1+2*siy)); |
460 |
|
|
ELL_3V_LERP(gzp, alpha, sctx->gradcontext + 3*(1+2*si), |
461 |
|
|
sctx->gradcontext + 3*(1+2*siy)); |
462 |
|
|
ELL_3M_SCALE(Tzm, 0.5, Tzm); ELL_3M_SCALE(Tzp, 0.5, Tzp); |
463 |
|
|
ELL_3V_SCALE(gzm, 0.5, gzm); ELL_3V_SCALE(gzp, 0.5, gzp); |
464 |
|
|
} |
465 |
|
|
if (xi==0) { |
466 |
|
|
ELL_3M_COPY(Txm, T); ELL_3V_COPY(gxm, g); |
467 |
|
|
} else { |
468 |
|
|
ELL_3M_LERP(Txm, alpha, sctx->t + 9*(1+2*siX), sctx->t + 9*(1+2*siXy)); |
469 |
|
|
ELL_3V_LERP(gxm, alpha, sctx->grad + 3*(1+2*siX), |
470 |
|
|
sctx->grad + 3*(1+2*siXy)); |
471 |
|
|
} |
472 |
|
|
if (xi==sx-1) { |
473 |
|
|
ELL_3M_COPY(Txp, T); ELL_3V_COPY(gxp, g); |
474 |
|
|
} else { |
475 |
|
|
ELL_3M_LERP(Txp, alpha, sctx->t + 9*(1+2*six), sctx->t + 9*(1+2*sixy)); |
476 |
|
|
ELL_3V_LERP(gxp, alpha, sctx->grad + 3*(1+2*six), |
477 |
|
|
sctx->grad + 3*(1+2*sixy)); |
478 |
|
|
} |
479 |
|
|
if (xi!=0 && xi!=sx-1) { |
480 |
|
|
ELL_3M_SCALE(Txm, 0.5, Txm); ELL_3M_SCALE(Txp, 0.5, Txp); |
481 |
|
|
ELL_3V_SCALE(gxm, 0.5, gxm); ELL_3V_SCALE(gxp, 0.5, gxp); |
482 |
|
|
} |
483 |
|
|
if (yi>0 && yi<sy-2) { |
484 |
|
|
unsigned int siyy = xi + sx*(yi+2); |
485 |
|
|
ELL_3M_LERP(Tym, alpha, sctx->t + 9*(1+2*siY), sctx->t + 9*(1+2*si)); |
486 |
|
|
ELL_3V_LERP(gym, alpha, sctx->grad + 3*(1+2*siY), |
487 |
|
|
sctx->grad + 3*(1+2*si)); |
488 |
|
|
ELL_3M_LERP(Typ, alpha, sctx->t + 9*(1+2*siy), sctx->t + 9*(1+2*siyy)); |
489 |
|
|
ELL_3V_LERP(gyp, alpha, sctx->grad + 3*(1+2*siy), |
490 |
|
|
sctx->grad + 3*(1+2*siyy)); |
491 |
|
|
ELL_3M_SCALE(Tym, 0.5, Tym); ELL_3M_SCALE(Typ, 0.5, Typ); |
492 |
|
|
ELL_3V_SCALE(gym, 0.5, gym); ELL_3V_SCALE(gyp, 0.5, gyp); |
493 |
|
|
} else { |
494 |
|
|
ELL_3M_COPY(Tym, sctx->t + 9*(1+2*si)); |
495 |
|
|
ELL_3V_COPY(gym, sctx->grad + 3*(1+2*si)); |
496 |
|
|
ELL_3M_COPY(Typ, sctx->t + 9*(1+2*six)); |
497 |
|
|
ELL_3V_COPY(gyp, sctx->grad + 3*(1+2*six)); |
498 |
|
|
} |
499 |
|
|
computeGradientLin(res, T, g, |
500 |
|
|
Txm, gxm, Txp, gxp, |
501 |
|
|
Tym, gym, Typ, gyp, |
502 |
|
|
Tzm, gzm, Tzp, gzp); |
503 |
|
|
break; |
504 |
|
|
} |
505 |
|
|
} |
506 |
|
|
|
507 |
|
|
/* Given a unique face ID and coordinates, compute the crease surface |
508 |
|
|
* normal at the specified degenerate point */ |
509 |
|
|
static void |
510 |
|
|
computeFaceGradient(seekContext *sctx, double *res, |
511 |
|
|
unsigned int xi, unsigned int yi, |
512 |
|
|
char faceid, double *coords) { |
513 |
|
|
double T[9], Txm[9], Txp[9], Tym[9], Typ[9], Tzm[9], Tzp[9], |
514 |
|
|
g[3], gxm[3], gxp[3], gym[3], gyp[3], gzm[3], gzp[3]; |
515 |
|
|
unsigned int sx = AIR_CAST(unsigned int, sctx->sx); |
516 |
|
|
unsigned int sy = AIR_CAST(unsigned int, sctx->sy); |
517 |
|
|
unsigned int si = xi + sx*yi; |
518 |
|
|
unsigned int six = xi + 1 + sx*yi, siX = xi - 1 + sx*yi; |
519 |
|
|
unsigned int siy = xi + sx*(yi+1), siY = xi + sx*(yi-1); |
520 |
|
|
unsigned int sixy = xi + 1 + sx*(yi+1), sixY = xi + 1 + sx*(yi-1), |
521 |
|
|
siXy = xi - 1 + sx*(yi+1); |
522 |
|
|
|
523 |
|
|
/* Again, lots of special cases to fill Txm, gxm, etc. */ |
524 |
|
|
switch (faceid) { |
525 |
|
|
case 0: |
526 |
|
|
/* bilinearly interpolate Tzp/gzp first */ |
527 |
|
|
ELL_3M_LERP(Txm, coords[1], sctx->t + 9*(1+2*si), sctx->t + 9*(1+2*siy)); |
528 |
|
|
ELL_3V_LERP(gxm, coords[1], sctx->grad + 3*(1+2*si), |
529 |
|
|
sctx->grad + 3*(1+2*siy)); |
530 |
|
|
ELL_3M_LERP(Txp, coords[1], sctx->t + 9*(1+2*six), sctx->t + 9*(1+2*sixy)); |
531 |
|
|
ELL_3V_LERP(gxp, coords[1], sctx->grad + 3*(1+2*six), |
532 |
|
|
sctx->grad + 3*(1+2*sixy)); |
533 |
|
|
ELL_3M_LERP(Tzp, coords[0], Txm, Txp); |
534 |
|
|
ELL_3V_LERP(gzp, coords[0], gxm, gxp); |
535 |
|
|
/* now, compute all required points on the bottom face */ |
536 |
|
|
ELL_3M_LERP(Txm, coords[1], sctx->t + 9*(0+2*si), sctx->t + 9*(0+2*siy)); |
537 |
|
|
ELL_3V_LERP(gxm, coords[1], sctx->grad + 3*(0+2*si), |
538 |
|
|
sctx->grad + 3*(0+2*siy)); |
539 |
|
|
ELL_3M_LERP(Txp, coords[1], sctx->t + 9*(0+2*six), sctx->t + 9*(0+2*sixy)); |
540 |
|
|
ELL_3V_LERP(gxp, coords[1], sctx->grad + 3*(0+2*six), |
541 |
|
|
sctx->grad + 3*(0+2*sixy)); |
542 |
|
|
|
543 |
|
|
ELL_3M_LERP(Tym, coords[0], sctx->t + 9*(0+2*si), sctx->t + 9*(0+2*six)); |
544 |
|
|
ELL_3V_LERP(gym, coords[0], sctx->grad + 3*(0+2*si), |
545 |
|
|
sctx->grad + 3*(0+2*six)); |
546 |
|
|
ELL_3M_LERP(Typ, coords[0], sctx->t + 9*(0+2*siy), sctx->t + 9*(0+2*sixy)); |
547 |
|
|
ELL_3V_LERP(gyp, coords[0], sctx->grad + 3*(0+2*siy), |
548 |
|
|
sctx->grad + 3*(0+2*sixy)); |
549 |
|
|
|
550 |
|
|
ELL_3M_LERP(T, coords[0], Txm, Txp); |
551 |
|
|
ELL_3V_LERP(g, coords[0], gxm, gxp); |
552 |
|
|
|
553 |
|
|
computeGradientLin(sctx->facenorm+3*(faceid+4*si), T, g, |
554 |
|
|
Txm, gxm, Txp, gxp, |
555 |
|
|
Tym, gym, Typ, gyp, |
556 |
|
|
T, g, Tzp, gzp); |
557 |
|
|
break; |
558 |
|
|
case 1: |
559 |
|
|
/* bilinearly interpolate Typ/gyp first */ |
560 |
|
|
if (yi!=sy-1) { |
561 |
|
|
ELL_3M_LERP(Txm, coords[1], sctx->t + 9*(0+2*siy), sctx->t + 9*(1+2*siy)); |
562 |
|
|
ELL_3V_LERP(gxm, coords[1], sctx->grad + 3*(0+2*siy), |
563 |
|
|
sctx->grad + 3*(1+2*siy)); |
564 |
|
|
ELL_3M_LERP(Txp, coords[1], sctx->t + 9*(0+2*sixy), |
565 |
|
|
sctx->t + 9*(1+2*sixy)); |
566 |
|
|
ELL_3V_LERP(gxp, coords[1], sctx->grad + 3*(0+2*sixy), |
567 |
|
|
sctx->grad + 3*(1+2*sixy)); |
568 |
|
|
ELL_3M_LERP(Typ, coords[0], Txm, Txp); |
569 |
|
|
ELL_3V_LERP(gyp, coords[0], gxm, gxp); |
570 |
|
|
} else { |
571 |
|
|
ELL_3M_LERP(Txm, coords[1], sctx->t + 9*(0+2*siY), sctx->t + 9*(1+2*siY)); |
572 |
|
|
ELL_3V_LERP(gxm, coords[1], sctx->grad + 3*(0+2*siY), |
573 |
|
|
sctx->grad + 3*(1+2*siY)); |
574 |
|
|
ELL_3M_LERP(Txp, coords[1], sctx->t + 9*(0+2*sixY), |
575 |
|
|
sctx->t + 9*(1+2*sixY)); |
576 |
|
|
ELL_3V_LERP(gxp, coords[1], sctx->grad + 3*(0+2*sixY), |
577 |
|
|
sctx->grad + 3*(1+2*sixY)); |
578 |
|
|
ELL_3M_LERP(Tym, coords[0], Txm, Txp); |
579 |
|
|
ELL_3V_LERP(gym, coords[0], gxm, gxp); |
580 |
|
|
} |
581 |
|
|
/* now, compute remaining points */ |
582 |
|
|
ELL_3M_LERP(Txm, coords[1], sctx->t + 9*(0+2*si), sctx->t + 9*(1+2*si)); |
583 |
|
|
ELL_3V_LERP(gxm, coords[1], sctx->grad + 3*(0+2*si), |
584 |
|
|
sctx->grad + 3*(1+2*si)); |
585 |
|
|
ELL_3M_LERP(Txp, coords[1], sctx->t + 9*(0+2*six), sctx->t + 9*(1+2*six)); |
586 |
|
|
ELL_3V_LERP(gxp, coords[1], sctx->grad + 3*(0+2*six), |
587 |
|
|
sctx->grad + 3*(1+2*six)); |
588 |
|
|
|
589 |
|
|
ELL_3M_LERP(Tzm, coords[0], sctx->t + 9*(0+2*si), sctx->t + 9*(0+2*six)); |
590 |
|
|
ELL_3V_LERP(gzm, coords[0], sctx->grad + 3*(0+2*si), |
591 |
|
|
sctx->grad + 3*(0+2*six)); |
592 |
|
|
ELL_3M_LERP(Tzp, coords[0], sctx->t + 9*(1+2*si), sctx->t + 9*(1+2*six)); |
593 |
|
|
ELL_3V_LERP(gzp, coords[0], sctx->grad + 3*(1+2*si), |
594 |
|
|
sctx->grad + 3*(1+2*six)); |
595 |
|
|
|
596 |
|
|
ELL_3M_LERP(T, coords[0], Txm, Txp); |
597 |
|
|
ELL_3V_LERP(g, coords[0], gxm, gxp); |
598 |
|
|
|
599 |
|
|
if (yi!=sy-1) { |
600 |
|
|
computeGradientLin(sctx->facenorm+3*(faceid+4*si), T, g, |
601 |
|
|
Txm, gxm, Txp, gxp, |
602 |
|
|
T, g, Typ, gyp, |
603 |
|
|
Tzm, gzm, Tzp, gzp); |
604 |
|
|
} else { |
605 |
|
|
computeGradientLin(sctx->facenorm+3*(faceid+4*si), T, g, |
606 |
|
|
Txm, gxm, Txp, gxp, |
607 |
|
|
Tym, gym, T, g, |
608 |
|
|
Tzm, gzm, Tzp, gzp); |
609 |
|
|
} |
610 |
|
|
break; |
611 |
|
|
case 2: |
612 |
|
|
/* bilinearly interpolate Txp/gxp first */ |
613 |
|
|
if (xi!=sx-1) { |
614 |
|
|
ELL_3M_LERP(Tym, coords[1], sctx->t + 9*(0+2*six), sctx->t + 9*(1+2*six)); |
615 |
|
|
ELL_3V_LERP(gym, coords[1], sctx->grad + 3*(0+2*six), |
616 |
|
|
sctx->grad + 3*(1+2*six)); |
617 |
|
|
ELL_3M_LERP(Typ, coords[1], sctx->t + 9*(0+2*sixy), |
618 |
|
|
sctx->t + 9*(1+2*sixy)); |
619 |
|
|
ELL_3V_LERP(gyp, coords[1], sctx->grad + 3*(0+2*sixy), |
620 |
|
|
sctx->grad + 3*(1+2*sixy)); |
621 |
|
|
ELL_3M_LERP(Txp, coords[0], Tym, Typ); |
622 |
|
|
ELL_3V_LERP(gxp, coords[0], gym, gyp); |
623 |
|
|
} else { |
624 |
|
|
ELL_3M_LERP(Tym, coords[1], sctx->t + 9*(0+2*siX), sctx->t + 9*(1+2*siX)); |
625 |
|
|
ELL_3V_LERP(gym, coords[1], sctx->grad + 3*(0+2*siX), |
626 |
|
|
sctx->grad + 3*(1+2*siX)); |
627 |
|
|
ELL_3M_LERP(Typ, coords[1], sctx->t + 9*(0+2*siXy), |
628 |
|
|
sctx->t + 9*(1+2*siXy)); |
629 |
|
|
ELL_3V_LERP(gyp, coords[1], sctx->grad + 3*(0+2*siXy), |
630 |
|
|
sctx->grad + 3*(1+2*siXy)); |
631 |
|
|
ELL_3M_LERP(Txm, coords[0], Tym, Typ); |
632 |
|
|
ELL_3V_LERP(gxm, coords[0], gym, gyp); |
633 |
|
|
} |
634 |
|
|
/* now, compute remaining points */ |
635 |
|
|
ELL_3M_LERP(Tym, coords[1], sctx->t + 9*(0+2*si), sctx->t + 9*(1+2*si)); |
636 |
|
|
ELL_3V_LERP(gym, coords[1], sctx->grad + 3*(0+2*si), |
637 |
|
|
sctx->grad + 3*(1+2*si)); |
638 |
|
|
ELL_3M_LERP(Typ, coords[1], sctx->t + 9*(0+2*siy), sctx->t + 9*(1+2*siy)); |
639 |
|
|
ELL_3V_LERP(gyp, coords[1], sctx->grad + 3*(0+2*siy), |
640 |
|
|
sctx->grad + 3*(1+2*siy)); |
641 |
|
|
|
642 |
|
|
ELL_3M_LERP(Tzm, coords[0], sctx->t + 9*(0+2*si), sctx->t + 9*(0+2*siy)); |
643 |
|
|
ELL_3V_LERP(gzm, coords[0], sctx->grad + 3*(0+2*si), |
644 |
|
|
sctx->grad + 3*(0+2*siy)); |
645 |
|
|
ELL_3M_LERP(Tzp, coords[0], sctx->t + 9*(1+2*si), sctx->t + 9*(1+2*siy)); |
646 |
|
|
ELL_3V_LERP(gzp, coords[0], sctx->grad + 3*(1+2*si), |
647 |
|
|
sctx->grad + 3*(1+2*siy)); |
648 |
|
|
|
649 |
|
|
ELL_3M_LERP(T, coords[0], Tym, Typ); |
650 |
|
|
ELL_3V_LERP(g, coords[0], gym, gyp); |
651 |
|
|
|
652 |
|
|
if (xi!=sx-1) { |
653 |
|
|
computeGradientLin(sctx->facenorm+3*(faceid+4*si), T, g, |
654 |
|
|
T, g, Txp, gxp, |
655 |
|
|
Tym, gym, Typ, gyp, |
656 |
|
|
Tzm, gzm, Tzp, gzp); |
657 |
|
|
} else { |
658 |
|
|
computeGradientLin(sctx->facenorm+3*(faceid+4*si), T, g, |
659 |
|
|
Txm, gxm, T, g, |
660 |
|
|
Tym, gym, Typ, gyp, |
661 |
|
|
Tzm, gzm, Tzp, gzp); |
662 |
|
|
} |
663 |
|
|
break; |
664 |
|
|
case 3: |
665 |
|
|
/* bilinearly interpolate Tzm/gzm first */ |
666 |
|
|
ELL_3M_LERP(Txm, coords[1], sctx->t + 9*(0+2*si), sctx->t + 9*(0+2*siy)); |
667 |
|
|
ELL_3V_LERP(gxm, coords[1], sctx->grad + 3*(0+2*si), |
668 |
|
|
sctx->grad + 3*(0+2*siy)); |
669 |
|
|
ELL_3M_LERP(Txp, coords[1], sctx->t + 9*(0+2*six), sctx->t + 9*(0+2*sixy)); |
670 |
|
|
ELL_3V_LERP(gxp, coords[1], sctx->grad + 3*(0+2*six), |
671 |
|
|
sctx->grad + 3*(0+2*sixy)); |
672 |
|
|
ELL_3M_LERP(Tzm, coords[0], Txm, Txp); |
673 |
|
|
ELL_3V_LERP(gzm, coords[0], gxm, gxp); |
674 |
|
|
/* now, compute all required points on the top face */ |
675 |
|
|
ELL_3M_LERP(Txm, coords[1], sctx->t + 9*(1+2*si), sctx->t + 9*(1+2*siy)); |
676 |
|
|
ELL_3V_LERP(gxm, coords[1], sctx->grad + 3*(1+2*si), |
677 |
|
|
sctx->grad + 3*(1+2*siy)); |
678 |
|
|
ELL_3M_LERP(Txp, coords[1], sctx->t + 9*(1+2*six), sctx->t + 9*(1+2*sixy)); |
679 |
|
|
ELL_3V_LERP(gxp, coords[1], sctx->grad + 3*(1+2*six), |
680 |
|
|
sctx->grad + 3*(1+2*sixy)); |
681 |
|
|
|
682 |
|
|
ELL_3M_LERP(Tym, coords[0], sctx->t + 9*(1+2*si), sctx->t + 9*(1+2*six)); |
683 |
|
|
ELL_3V_LERP(gym, coords[0], sctx->grad + 3*(1+2*si), |
684 |
|
|
sctx->grad + 3*(1+2*six)); |
685 |
|
|
ELL_3M_LERP(Typ, coords[0], sctx->t + 9*(1+2*siy), sctx->t + 9*(1+2*sixy)); |
686 |
|
|
ELL_3V_LERP(gyp, coords[0], sctx->grad + 3*(1+2*siy), |
687 |
|
|
sctx->grad + 3*(1+2*sixy)); |
688 |
|
|
|
689 |
|
|
ELL_3M_LERP(T, coords[0], Txm, Txp); |
690 |
|
|
ELL_3V_LERP(g, coords[0], gxm, gxp); |
691 |
|
|
|
692 |
|
|
computeGradientLin(sctx->facenorm+3*(faceid+4*si), T, g, |
693 |
|
|
Txm, gxm, Txp, gxp, |
694 |
|
|
Tym, gym, Typ, gyp, |
695 |
|
|
Tzm, gzm, T, g); |
696 |
|
|
break; |
697 |
|
|
} |
698 |
|
|
ELL_3V_COPY(res, sctx->facenorm+3*(faceid+4*si)); |
699 |
|
|
} |
700 |
|
|
|
701 |
|
|
/* small helper routines: intersection tests */ |
702 |
|
|
|
703 |
|
|
/* check if a given 2D triangle is oriented clockwise (-1) |
704 |
|
|
* or counter-clockwise (1). |
705 |
|
|
* returns 0 if given points are collinear */ |
706 |
|
|
static int |
707 |
|
|
checkTriOrientation (double *p1, double *p2, double *p3) { |
708 |
|
|
double test = (((p2[0]-p1[0])*(p3[1]-p1[1])) - ((p3[0]-p1[0])*(p2[1]-p1[1]))); |
709 |
|
|
if (test > 0) return 1; |
710 |
|
|
else if (test < 0) return -1; |
711 |
|
|
else return 0; |
712 |
|
|
} |
713 |
|
|
|
714 |
|
|
/* check if two given 2D lines intersect */ |
715 |
|
|
static int |
716 |
|
|
lineIntersectionTest (double *l1p1, double *l1p2, double *l2p1, double *l2p2) { |
717 |
|
|
int or1 = checkTriOrientation(l1p1, l1p2, l2p1); |
718 |
|
|
int or2 = checkTriOrientation(l1p1, l1p2, l2p2); |
719 |
|
|
if (or1 != or2) { |
720 |
|
|
or1 = checkTriOrientation(l2p1, l2p2, l1p1); |
721 |
|
|
or2 = checkTriOrientation(l2p1, l2p2, l1p2); |
722 |
|
|
if (or1 != or2) |
723 |
|
|
return 1; |
724 |
|
|
} |
725 |
|
|
return 0; |
726 |
|
|
} |
727 |
|
|
|
728 |
|
|
/* check if two given 3D triangles intersect */ |
729 |
|
|
static int |
730 |
|
|
triIntersectionTest (double *t1v1, double *t1v2, double *t1v3, |
731 |
|
|
double *t2v1, double *t2v2, double *t2v3) { |
732 |
|
|
double n1[3], n2[3], d1, d2; |
733 |
|
|
double diff1[3], diff2[3]; |
734 |
|
|
double t2sd1, t2sd2, t2sd3; |
735 |
|
|
ELL_3V_SUB(diff1, t1v2, t1v1); |
736 |
|
|
ELL_3V_SUB(diff2, t1v3, t1v1); |
737 |
|
|
ELL_3V_CROSS(n1,diff1,diff2); |
738 |
|
|
d1=-ELL_3V_DOT(n1,t1v1); |
739 |
|
|
|
740 |
|
|
/* compute scaled signed distances of t2 to plane of t1 */ |
741 |
|
|
t2sd1 = ELL_3V_DOT(n1, t2v1)+d1; |
742 |
|
|
t2sd2 = ELL_3V_DOT(n1, t2v2)+d1; |
743 |
|
|
t2sd3 = ELL_3V_DOT(n1, t2v3)+d1; |
744 |
|
|
|
745 |
|
|
if (t2sd1==0 && t2sd2==0 && t2sd3==0) { |
746 |
|
|
/* coplanar case: handle in 2D */ |
747 |
|
|
double t1v12d[2], t1v22d[2], t1v32d[2], t2v12d[2], t2v22d[2], t2v32d[2]; |
748 |
|
|
if (fabs(n1[0])>=fabs(n1[1]) && fabs(n1[0])>=fabs(n1[2])) { |
749 |
|
|
t1v12d[0]=t1v1[1]; t1v12d[1]=t1v1[2]; |
750 |
|
|
t1v22d[0]=t1v2[1]; t1v22d[1]=t1v2[2]; |
751 |
|
|
t1v32d[0]=t1v3[1]; t1v32d[1]=t1v3[2]; |
752 |
|
|
t2v12d[0]=t2v1[1]; t2v12d[1]=t2v1[2]; |
753 |
|
|
t2v22d[0]=t2v2[1]; t2v22d[1]=t2v2[2]; |
754 |
|
|
t2v32d[0]=t2v3[1]; t2v32d[1]=t2v3[2]; |
755 |
|
|
} else if (fabs(n1[1])>=fabs(n1[0]) && fabs(n1[1])>=fabs(n1[2])) { |
756 |
|
|
t1v12d[0]=t1v1[0]; t1v12d[1]=t1v1[2]; |
757 |
|
|
t1v22d[0]=t1v2[0]; t1v22d[1]=t1v2[2]; |
758 |
|
|
t1v32d[0]=t1v3[0]; t1v32d[1]=t1v3[2]; |
759 |
|
|
t2v12d[0]=t2v1[0]; t2v12d[1]=t2v1[2]; |
760 |
|
|
t2v22d[0]=t2v2[0]; t2v22d[1]=t2v2[2]; |
761 |
|
|
t2v32d[0]=t2v3[0]; t2v32d[1]=t2v3[2]; |
762 |
|
|
} else { |
763 |
|
|
t1v12d[0]=t1v1[0]; t1v12d[1]=t1v1[1]; |
764 |
|
|
t1v22d[0]=t1v2[0]; t1v22d[1]=t1v2[1]; |
765 |
|
|
t1v32d[0]=t1v3[0]; t1v32d[1]=t1v3[1]; |
766 |
|
|
t2v12d[0]=t2v1[0]; t2v12d[1]=t2v1[1]; |
767 |
|
|
t2v22d[0]=t2v2[0]; t2v22d[1]=t2v2[1]; |
768 |
|
|
t2v32d[0]=t2v3[0]; t2v32d[1]=t2v3[1]; |
769 |
|
|
} |
770 |
|
|
/* we may assume that none of the triangles is fully contained |
771 |
|
|
* within the other. Thus, it suffices to do a lot of 2D line-line |
772 |
|
|
* intersections */ |
773 |
|
|
if (lineIntersectionTest(t1v12d, t1v22d, t2v12d, t2v22d) || |
774 |
|
|
lineIntersectionTest(t1v22d, t1v32d, t2v12d, t2v22d) || |
775 |
|
|
lineIntersectionTest(t1v32d, t1v12d, t2v12d, t2v22d) || |
776 |
|
|
lineIntersectionTest(t1v12d, t1v22d, t2v22d, t2v32d) || |
777 |
|
|
lineIntersectionTest(t1v22d, t1v32d, t2v22d, t2v32d) || |
778 |
|
|
lineIntersectionTest(t1v32d, t1v12d, t2v22d, t2v32d) || |
779 |
|
|
lineIntersectionTest(t1v12d, t1v22d, t2v32d, t2v12d) || |
780 |
|
|
lineIntersectionTest(t1v22d, t1v32d, t2v32d, t2v12d) || |
781 |
|
|
lineIntersectionTest(t1v32d, t1v12d, t2v32d, t2v12d)) |
782 |
|
|
return 1; |
783 |
|
|
return 0; |
784 |
|
|
} else { |
785 |
|
|
/* pointers to the vertices on the same side / opposite side of plane */ |
786 |
|
|
double *t2s11, *t2s12, *t2s2, t2s11sd, t2s12sd, t2s2sd; |
787 |
|
|
double t1sd1, t1sd2, t1sd3; |
788 |
|
|
double *t1s11, *t1s12, *t1s2, t1s11sd, t1s12sd, t1s2sd; |
789 |
|
|
double t1p11, t1p12, t1p2, t2p11, t2p12, t2p2; |
790 |
|
|
double D[3]; /* direction vector of line */ |
791 |
|
|
double t1t1, t1t2, t2t1, t2t2; |
792 |
|
|
if (t2sd1*t2sd2>=0 && t2sd1*t2sd3<=0) { |
793 |
|
|
t2s11=t2v1; t2s12=t2v2; t2s2=t2v3; t2s11sd=t2sd1; |
794 |
|
|
t2s12sd=t2sd2; t2s2sd=t2sd3; |
795 |
|
|
} else if (t2sd1*t2sd3>=0 && t2sd1*t2sd2<=0) { |
796 |
|
|
t2s11=t2v1; t2s12=t2v3; t2s2=t2v2; t2s11sd=t2sd1; |
797 |
|
|
t2s12sd=t2sd3; t2s2sd=t2sd2; |
798 |
|
|
} else if (t2sd2*t2sd3>=0 && t2sd1*t2sd2<=0) { |
799 |
|
|
t2s11=t2v2; t2s12=t2v3; t2s2=t2v1; t2s11sd=t2sd2; |
800 |
|
|
t2s12sd=t2sd3; t2s2sd=t2sd1; |
801 |
|
|
} else |
802 |
|
|
return 0; /* all on the same side; no intersection */ |
803 |
|
|
|
804 |
|
|
/* same game for triangle 2 */ |
805 |
|
|
ELL_3V_SUB(diff1, t2v2, t2v1); |
806 |
|
|
ELL_3V_SUB(diff2, t2v3, t2v1); |
807 |
|
|
ELL_3V_CROSS(n2, diff1, diff2); |
808 |
|
|
d2=-ELL_3V_DOT(n2,t2v1); |
809 |
|
|
t1sd1 = ELL_3V_DOT(n2, t1v1)+d2; |
810 |
|
|
t1sd2 = ELL_3V_DOT(n2, t1v2)+d2; |
811 |
|
|
t1sd3 = ELL_3V_DOT(n2, t1v3)+d2; |
812 |
|
|
if (t1sd1*t1sd2>=0 && t1sd1*t1sd3<=0) { |
813 |
|
|
t1s11=t1v1; t1s12=t1v2; t1s2=t1v3; t1s11sd=t1sd1; |
814 |
|
|
t1s12sd=t1sd2; t1s2sd=t1sd3; |
815 |
|
|
} else if (t1sd1*t1sd3>=0 && t1sd1*t1sd2<=0) { |
816 |
|
|
t1s11=t1v1; t1s12=t1v3; t1s2=t1v2; t1s11sd=t1sd1; |
817 |
|
|
t1s12sd=t1sd3; t1s2sd=t1sd2; |
818 |
|
|
} else if (t1sd2*t1sd3>=0 && t1sd1*t1sd2<=0) { |
819 |
|
|
t1s11=t1v2; t1s12=t1v3; t1s2=t1v1; t1s11sd=t1sd2; |
820 |
|
|
t1s12sd=t1sd3; t1s2sd=t1sd1; |
821 |
|
|
} else |
822 |
|
|
return 0; /* all on the same side; no intersection */ |
823 |
|
|
|
824 |
|
|
/* both planes intersect in a line; check if the intervals on that |
825 |
|
|
* line intersect */ |
826 |
|
|
ELL_3V_CROSS(D,n1,n2); |
827 |
|
|
/* we are only interested in component magnitudes */ |
828 |
|
|
D[0]=fabs(D[0]); D[1]=fabs(D[1]); D[2]=fabs(D[2]); |
829 |
|
|
if (D[0]>=D[1] && D[0]>=D[2]) { |
830 |
|
|
t1p11=t1s11[0]; t1p12=t1s12[0]; t1p2=t1s2[0]; |
831 |
|
|
t2p11=t2s11[0]; t2p12=t2s12[0]; t2p2=t2s2[0]; |
832 |
|
|
} else if (D[1]>=D[0] && D[1]>=D[2]) { |
833 |
|
|
t1p11=t1s11[1]; t1p12=t1s12[1]; t1p2=t1s2[1]; |
834 |
|
|
t2p11=t2s11[1]; t2p12=t2s12[1]; t2p2=t2s2[1]; |
835 |
|
|
} else { |
836 |
|
|
t1p11=t1s11[2]; t1p12=t1s12[2]; t1p2=t1s2[2]; |
837 |
|
|
t2p11=t2s11[2]; t2p12=t2s12[2]; t2p2=t2s2[2]; |
838 |
|
|
} |
839 |
|
|
/* compute interval boundaries */ |
840 |
|
|
t1t1=t1p11+(t1p2-t1p11)*t1s11sd/(t1s11sd-t1s2sd); |
841 |
|
|
t1t2=t1p12+(t1p2-t1p12)*t1s12sd/(t1s12sd-t1s2sd); |
842 |
|
|
if (t1t1>t1t2) { |
843 |
|
|
double help=t1t1; |
844 |
|
|
t1t1=t1t2; |
845 |
|
|
t1t2=help; |
846 |
|
|
} |
847 |
|
|
t2t1=t2p11+(t2p2-t2p11)*t2s11sd/(t2s11sd-t2s2sd); |
848 |
|
|
t2t2=t2p12+(t2p2-t2p12)*t2s12sd/(t2s12sd-t2s2sd); |
849 |
|
|
if (t2t1>t2t2) { |
850 |
|
|
double help=t2t1; |
851 |
|
|
t2t1=t2t2; |
852 |
|
|
t2t2=help; |
853 |
|
|
} |
854 |
|
|
/* test for interval intersection */ |
855 |
|
|
if (t2t1>t1t2 || t1t1>t2t2) return 0; |
856 |
|
|
return 1; |
857 |
|
|
} |
858 |
|
|
} |
859 |
|
|
|
860 |
|
|
/* Score possible local topologies based on the agreement of |
861 |
|
|
* connecting lines with normal directions. Lower scores are |
862 |
|
|
* better. */ |
863 |
|
|
|
864 |
|
|
/* Connections between degenerate points on cell faces; if only four |
865 |
|
|
* degenerate points are present, set p31 to NULL */ |
866 |
|
|
static double |
867 |
|
|
evaluateDegConnection(double *p11, double *p12, double *p13, double *p14, |
868 |
|
|
double *p21, double *p22, double *p23, double *p24, |
869 |
|
|
double *p31, double *p32, double *p33, double *p34, |
870 |
|
|
double *n12, double *n13, double *n22, double *n23, |
871 |
|
|
double *n32, double *n33) { |
872 |
|
|
double diff1[3], diff2[3], diff3[3], ret; |
873 |
|
|
/* first, perform intersection testing */ |
874 |
|
|
if (triIntersectionTest(p11, p12, p13, p21, p22, p23) || |
875 |
|
|
triIntersectionTest(p13, p14, p11, p21, p22, p23) || |
876 |
|
|
triIntersectionTest(p11, p12, p13, p23, p24, p21) || |
877 |
|
|
triIntersectionTest(p13, p14, p11, p23, p24, p21)) |
878 |
|
|
return 1e20; |
879 |
|
|
if (p31 != NULL) { /* three pairs - some more to do */ |
880 |
|
|
if (triIntersectionTest(p11, p12, p13, p31, p32, p33) || |
881 |
|
|
triIntersectionTest(p11, p12, p13, p33, p34, p31) || |
882 |
|
|
triIntersectionTest(p13, p14, p11, p31, p32, p33) || |
883 |
|
|
triIntersectionTest(p13, p14, p11, p33, p34, p31) || |
884 |
|
|
triIntersectionTest(p21, p22, p23, p31, p32, p33) || |
885 |
|
|
triIntersectionTest(p21, p22, p23, p33, p34, p31) || |
886 |
|
|
triIntersectionTest(p23, p24, p21, p31, p32, p33) || |
887 |
|
|
triIntersectionTest(p23, p24, p21, p33, p34, p31)) |
888 |
|
|
return 1e20; |
889 |
|
|
} |
890 |
|
|
ELL_3V_SUB(diff1,p13,p12); |
891 |
|
|
ELL_3V_SUB(diff2,p23,p22); |
892 |
|
|
ret=fabs(ELL_3V_DOT(diff1,n12))+fabs(ELL_3V_DOT(diff1,n13))+ |
893 |
|
|
fabs(ELL_3V_DOT(diff2,n22))+fabs(ELL_3V_DOT(diff2,n23)); |
894 |
|
|
if (p31 != NULL) { |
895 |
|
|
ELL_3V_SUB(diff3,p33,p32); |
896 |
|
|
ret+=fabs(ELL_3V_DOT(diff3,n32))+fabs(ELL_3V_DOT(diff3,n33)); |
897 |
|
|
} |
898 |
|
|
return ret; |
899 |
|
|
} |
900 |
|
|
|
901 |
|
|
/* suggests a connectivity for a non-trivial combination of |
902 |
|
|
* intersection points in the plane. |
903 |
|
|
* pairs is output (permutation of idcs) |
904 |
|
|
* bestval is input/output (best value so far, start with something big) |
905 |
|
|
* ct is the number of points (currently assumed even) |
906 |
|
|
* idcs is input (idcs that still need to be permuted) |
907 |
|
|
* fixedct is input (number of idcs that are already fixed at this depth) |
908 |
|
|
* coords is an array of 2D coordinates |
909 |
|
|
* norms is an array of 2D vectors */ |
910 |
|
|
static void |
911 |
|
|
findConnectivity(signed char *pairs, double *bestval, int ct, char *idcs, |
912 |
|
|
int fixedct, double *coords, double *norms) { |
913 |
|
|
int i,j; |
914 |
|
|
if (fixedct==ct) { |
915 |
|
|
double weight=0; |
916 |
|
|
for (i=0; i<ct-1; i+=2) { |
917 |
|
|
double diff[2]; |
918 |
|
|
ELL_2V_SUB(diff,coords+2*idcs[i],coords+2*idcs[i+1]); |
919 |
|
|
weight+=fabs(ELL_2V_DOT(diff,norms+2*idcs[i]))+ |
920 |
|
|
fabs(ELL_2V_DOT(diff,norms+2*idcs[i+1])); |
921 |
|
|
} |
922 |
|
|
if (weight<*bestval) { |
923 |
|
|
*bestval=weight; |
924 |
|
|
memcpy(pairs,idcs,sizeof(char)*ct); |
925 |
|
|
} |
926 |
|
|
return; |
927 |
|
|
} |
928 |
|
|
/* else: we need a recursion */ |
929 |
|
|
for (i=fixedct+1; i<ct; i++) { |
930 |
|
|
int intersect=0; |
931 |
|
|
char *idxnew; |
932 |
|
|
if (NULL == (idxnew = (char*) malloc (sizeof(char)*ct))) |
933 |
|
|
return; |
934 |
|
|
memcpy(idxnew,idcs,sizeof(char)*ct); |
935 |
|
|
/* try any of the remaining indices as a pair */ |
936 |
|
|
idxnew[fixedct+1]=idcs[i]; |
937 |
|
|
idxnew[i]=idcs[fixedct+1]; |
938 |
|
|
/* check if the resulting line causes an intersection */ |
939 |
|
|
for (j=0;j<fixedct;j+=2) { |
940 |
|
|
if (lineIntersectionTest(coords+2*idxnew[fixedct], |
941 |
|
|
coords+2*idxnew[fixedct+1], |
942 |
|
|
coords+2*idxnew[j],coords+2*idxnew[j+1])) { |
943 |
|
|
intersect=1; |
944 |
|
|
break; |
945 |
|
|
} |
946 |
|
|
} |
947 |
|
|
if (!intersect) { |
948 |
|
|
findConnectivity(pairs, bestval, ct, idxnew, fixedct+2, coords, norms); |
949 |
|
|
} |
950 |
|
|
free(idxnew); |
951 |
|
|
} |
952 |
|
|
} |
953 |
|
|
|
954 |
|
|
#define _SEEK_TREATED_REQUEST 0x01 /* this voxel has to be treated */ |
955 |
|
|
#define _SEEK_TREATED_EDGE0 0x02 /* unique edge 0 has been treated */ |
956 |
|
|
#define _SEEK_TREATED_EDGE1 0x04 /* unique edge 1 has been treated */ |
957 |
|
|
#define _SEEK_TREATED_EDGE2 0x08 /* unique edge 2 has been treated */ |
958 |
|
|
#define _SEEK_TREATED_EDGE3 0x10 /* unique edge 3 has been treated */ |
959 |
|
|
#define _SEEK_TREATED_EDGE4 0x20 /* unique edge 4 has been treated */ |
960 |
|
|
#define _SEEK_TREATED_FACE3 0x40 /* unique face 3 has been treated */ |
961 |
|
|
|
962 |
|
|
/* find deg. points, normals, and connectivity on a given (unique) face |
963 |
|
|
* now refines the search if it couldn't find a degenerate point */ |
964 |
|
|
static void |
965 |
|
|
connectFace(seekContext *sctx, baggage *bag, |
966 |
|
|
unsigned int xi, unsigned int yi, unsigned char faceid) { |
967 |
|
|
int edgeid[4][4]={{0, 2, 3, 1}, /* which edges belong to which unique face? */ |
968 |
|
|
{0, 5, 8, 4}, |
969 |
|
|
{1, 6, 9, 4}, |
970 |
|
|
{8,10,11, 9}}; |
971 |
|
|
unsigned int sx = AIR_CAST(unsigned int, sctx->sx); |
972 |
|
|
unsigned int si = xi + sx*yi; |
973 |
|
|
unsigned int six = xi + 1 + sx*yi; |
974 |
|
|
unsigned int siy = xi + sx*(yi+1); |
975 |
|
|
unsigned int sixy = xi + 1 + sx*(yi+1); |
976 |
|
|
char inter[12]; /* indices of intersections */ |
977 |
|
|
int pass; /* allow multiple refined passes */ |
978 |
|
|
int i; |
979 |
|
|
/* voxel in which treated information is stored for local edge i */ |
980 |
|
|
/* which vertices form which unique face? */ |
981 |
|
|
int verti[4][4]; |
982 |
|
|
int voxel[4][4]; |
983 |
|
|
/* mask for treated information in the above voxel */ |
984 |
|
|
char mask[4][4]={{_SEEK_TREATED_EDGE0, _SEEK_TREATED_EDGE1, |
985 |
|
|
_SEEK_TREATED_EDGE0, _SEEK_TREATED_EDGE1}, |
986 |
|
|
{_SEEK_TREATED_EDGE0, _SEEK_TREATED_EDGE2, |
987 |
|
|
_SEEK_TREATED_EDGE3, _SEEK_TREATED_EDGE2}, |
988 |
|
|
{_SEEK_TREATED_EDGE1, _SEEK_TREATED_EDGE2, |
989 |
|
|
_SEEK_TREATED_EDGE4, _SEEK_TREATED_EDGE2}, |
990 |
|
|
{_SEEK_TREATED_EDGE3, _SEEK_TREATED_EDGE4, |
991 |
|
|
_SEEK_TREATED_EDGE3, _SEEK_TREATED_EDGE4}}; |
992 |
|
|
/* start- and endpoints of the edges */ |
993 |
|
|
int verts[4][4], verte[4][4]; |
994 |
|
|
char treat[4]={0,0,0,0}; |
995 |
|
|
double dpthresh[3]={0.7,0.8,0.9}; |
996 |
|
|
/* candidates for degenerate points */ |
997 |
|
|
double candidates[18]={0.5,0.5, 0.25,0.25, 0.25,0.75, |
998 |
|
|
0.75,0.25, 0.75,0.75, 0.5,0.25, |
999 |
|
|
0.25,0.5, 0.75,0.5, 0.6,0.75}; |
1000 |
|
|
int cand_idx[4]={0, 1, 5, 9}; |
1001 |
|
|
int interct; |
1002 |
|
|
|
1003 |
|
|
/* apparently, some C compilers cannot make these initializations in-place */ |
1004 |
|
|
ELL_4V_SET(verti[0], 0+2*si, 0+2*six, 0+2*siy, 0+2*sixy); |
1005 |
|
|
ELL_4V_SET(verti[1], 0+2*si, 0+2*six, 1+2*si, 1+2*six); |
1006 |
|
|
ELL_4V_SET(verti[2], 0+2*si, 0+2*siy, 1+2*si, 1+2*siy); |
1007 |
|
|
ELL_4V_SET(verti[3], 1+2*si, 1+2*six, 1+2*siy, 1+2*sixy); |
1008 |
|
|
ELL_4V_SET(voxel[0], si, six, siy, si); |
1009 |
|
|
ELL_4V_SET(voxel[1], si, six, si, si); |
1010 |
|
|
ELL_4V_SET(voxel[2], si, siy, si, si); |
1011 |
|
|
ELL_4V_SET(voxel[3], si, six, siy, si); |
1012 |
|
|
ELL_4V_SET(verts[0], 0+2*si, 0+2*six, 0+2*siy, 0+2*si); |
1013 |
|
|
ELL_4V_SET(verts[1], 0+2*si, 0+2*six, 1+2*si, 0+2*si); |
1014 |
|
|
ELL_4V_SET(verts[2], 0+2*si, 0+2*siy, 1+2*si, 0+2*si); |
1015 |
|
|
ELL_4V_SET(verts[3], 1+2*si, 1+2*six, 1+2*siy, 1+2*si); |
1016 |
|
|
ELL_4V_SET(verte[0], 0+2*six, 0+2*sixy, 0+2*sixy, 0+2*siy); |
1017 |
|
|
ELL_4V_SET(verte[1], 0+2*six, 1+2*six, 1+2*six, 1+2*si); |
1018 |
|
|
ELL_4V_SET(verte[2], 0+2*siy, 1+2*siy, 1+2*siy, 1+2*si); |
1019 |
|
|
ELL_4V_SET(verte[3], 1+2*six, 1+2*sixy, 1+2*sixy, 1+2*siy); |
1020 |
|
|
|
1021 |
|
|
/* find out which edges have not yet been treated */ |
1022 |
|
|
for (i=0; i<4; i++) { |
1023 |
|
|
if (!(sctx->treated[voxel[faceid][i]]&mask[faceid][i])) { |
1024 |
|
|
treat[i]=1; /* we need to treat this */ |
1025 |
|
|
sctx->treated[voxel[faceid][i]] |= mask[faceid][i]; |
1026 |
|
|
} |
1027 |
|
|
} |
1028 |
|
|
|
1029 |
|
|
for (pass=0; pass<3; pass++) { |
1030 |
|
|
/* first, find intersections for edges that need treatment */ |
1031 |
|
|
int j; |
1032 |
|
|
for (j=0; j<4; j++) { |
1033 |
|
|
double interpos[8]; |
1034 |
|
|
if (!treat[j]) continue; |
1035 |
|
|
interct=findFeatureIntersection(interpos, |
1036 |
|
|
sctx->t + 9*verts[faceid][j], |
1037 |
|
|
sctx->hess + 9*verts[faceid][j], |
1038 |
|
|
sctx->grad + 3*verts[faceid][j], |
1039 |
|
|
sctx->t + 9*verte[faceid][j], |
1040 |
|
|
sctx->hess + 9*verte[faceid][j], |
1041 |
|
|
sctx->grad + 3*verte[faceid][j], |
1042 |
|
|
0.0, 1.0, bag->esIdx==2, |
1043 |
|
|
sctx->evalDiffThresh, |
1044 |
|
|
dpthresh[pass]); |
1045 |
|
|
if (interct>3) interct=3; |
1046 |
|
|
for (i=0; i<interct; i++) { |
1047 |
|
|
double x=0, y=0, z=0; unsigned int xb=0, yb=0, idb=0; |
1048 |
|
|
sctx->edgealpha[3*(bag->evti[edgeid[faceid][j]]+5*si)+i] = interpos[i]; |
1049 |
|
|
switch (edgeid[faceid][j]) { |
1050 |
|
|
case 0: x=xi+interpos[i]; y=yi; z=bag->zi; |
1051 |
|
|
xb=xi; yb=yi; idb=0; break; |
1052 |
|
|
case 1: x=xi; y=yi+interpos[i]; z=bag->zi; |
1053 |
|
|
xb=xi; yb=yi; idb=1; break; |
1054 |
|
|
case 2: x=xi+1; y=yi+interpos[i]; z=bag->zi; |
1055 |
|
|
xb=xi+1; yb=yi; idb=1; break; |
1056 |
|
|
case 3: x=xi+interpos[i]; y=yi+1; z=bag->zi; |
1057 |
|
|
xb=xi; yb=yi+1; idb=0; break; |
1058 |
|
|
case 4: x=xi; y=yi; z=bag->zi+interpos[i]; |
1059 |
|
|
xb=xi; yb=yi; idb=2; break; |
1060 |
|
|
case 5: x=xi+1; y=yi; z=bag->zi+interpos[i]; |
1061 |
|
|
xb=xi+1; yb=yi; idb=2; break; |
1062 |
|
|
case 6: x=xi; y=yi+1; z=bag->zi+interpos[i]; |
1063 |
|
|
xb=xi; yb=yi+1; idb=2; break; |
1064 |
|
|
case 7: x=xi+1; y=yi+1; z=bag->zi+interpos[i]; |
1065 |
|
|
xb=xi+1; yb=yi+1; idb=2; break; |
1066 |
|
|
case 8: x=xi+interpos[i]; y=yi; z=bag->zi+1; |
1067 |
|
|
xb=xi; yb=yi; idb=3; break; |
1068 |
|
|
case 9: x=xi; y=yi+interpos[i]; z=bag->zi+1; |
1069 |
|
|
xb=xi; yb=yi; idb=4; break; |
1070 |
|
|
case 10: x=xi+1; y=yi+interpos[i]; z=bag->zi+1; |
1071 |
|
|
xb=xi+1; yb=yi; idb=4; break; |
1072 |
|
|
case 11: x=xi+interpos[i]; y=yi+1; z=bag->zi+1; |
1073 |
|
|
xb=xi; yb=yi+1; idb=3; break; |
1074 |
|
|
} |
1075 |
|
|
ELL_3V_SET(sctx->edgeicoord+9*(bag->evti[edgeid[faceid][j]]+5*si)+3*i, |
1076 |
|
|
x, y, z); |
1077 |
|
|
computeEdgeGradient(sctx, bag, sctx->edgenorm+ |
1078 |
|
|
9*(bag->evti[edgeid[faceid][j]]+5*si)+3*i, |
1079 |
|
|
xb, yb, idb, interpos[i]); |
1080 |
|
|
} |
1081 |
|
|
} |
1082 |
|
|
|
1083 |
|
|
interct=0; /* number of feature intersections */ |
1084 |
|
|
for (i=0; i<3; i++) { |
1085 |
|
|
if (sctx->edgealpha[3*(bag->evti[edgeid[faceid][0]]+5*si)+i]>=0) |
1086 |
|
|
inter[interct++]=i; /* numbering is local w.r.t. face */ |
1087 |
|
|
if (sctx->edgealpha[3*(bag->evti[edgeid[faceid][1]]+5*si)+i]>=0) |
1088 |
|
|
inter[interct++]=3+i; |
1089 |
|
|
if (sctx->edgealpha[3*(bag->evti[edgeid[faceid][2]]+5*si)+i]>=0) |
1090 |
|
|
inter[interct++]=6+i; |
1091 |
|
|
if (sctx->edgealpha[3*(bag->evti[edgeid[faceid][3]]+5*si)+i]>=0) |
1092 |
|
|
inter[interct++]=9+i; |
1093 |
|
|
} |
1094 |
|
|
if (interct%2==1) { /* we need to look for a degeneracy */ |
1095 |
|
|
int k; |
1096 |
|
|
for (k=cand_idx[pass]; k<cand_idx[pass+1]; k++) { |
1097 |
|
|
ELL_2V_SET(sctx->facecoord+2*(faceid+4*si), |
1098 |
|
|
candidates[2*k], candidates[2*k+1]); |
1099 |
|
|
if (!seekDescendToDeg(sctx->facecoord+2*(faceid+4*si), |
1100 |
|
|
sctx->hess + 9*verti[faceid][0], |
1101 |
|
|
sctx->hess + 9*verti[faceid][1], |
1102 |
|
|
sctx->hess + 9*verti[faceid][2], |
1103 |
|
|
sctx->hess + 9*verti[faceid][3], |
1104 |
|
|
50, 1e-9, (bag->esIdx==2)?'l':'p')) { |
1105 |
|
|
inter[interct++]=12; /* 12 means "deg. point on this face */ |
1106 |
|
|
break; |
1107 |
|
|
} |
1108 |
|
|
} |
1109 |
|
|
if ((pass==2) && (inter[interct-1]!=12)) { |
1110 |
|
|
/* nothing helped, so insert a dummy vertex */ |
1111 |
|
|
ELL_2V_SET(sctx->facecoord+2*(faceid+4*si), 0.5, 0.5); |
1112 |
|
|
inter[interct++]=12; |
1113 |
|
|
} |
1114 |
|
|
if (inter[interct-1]==12) { |
1115 |
|
|
computeFaceGradient(sctx, sctx->facenorm+3*(faceid+4*si), |
1116 |
|
|
xi, yi, faceid, sctx->facecoord+2*(faceid+4*si)); |
1117 |
|
|
switch (faceid) { |
1118 |
|
|
case 0: ELL_3V_SET(sctx->faceicoord+3*(faceid+4*si), |
1119 |
|
|
xi+sctx->facecoord[2*(faceid+4*si)], |
1120 |
|
|
yi+sctx->facecoord[2*(faceid+4*si)+1], bag->zi); |
1121 |
|
|
break; |
1122 |
|
|
case 1: ELL_3V_SET(sctx->faceicoord+3*(faceid+4*si), |
1123 |
|
|
xi+sctx->facecoord[2*(faceid+4*si)], yi, |
1124 |
|
|
bag->zi+sctx->facecoord[2*(faceid+4*si)+1]); |
1125 |
|
|
break; |
1126 |
|
|
case 2: ELL_3V_SET(sctx->faceicoord+3*(faceid+4*si), xi, |
1127 |
|
|
yi+sctx->facecoord[2*(faceid+4*si)], |
1128 |
|
|
bag->zi+sctx->facecoord[2*(faceid+4*si)+1]); |
1129 |
|
|
break; |
1130 |
|
|
case 3: ELL_3V_SET(sctx->faceicoord+3*(faceid+4*si), |
1131 |
|
|
xi+sctx->facecoord[2*(faceid+4*si)], |
1132 |
|
|
yi+sctx->facecoord[2*(faceid+4*si)+1], bag->zi+1); |
1133 |
|
|
break; |
1134 |
|
|
} |
1135 |
|
|
} |
1136 |
|
|
} |
1137 |
|
|
if (interct%2==0) { /* we can break out */ |
1138 |
|
|
break; |
1139 |
|
|
} |
1140 |
|
|
} |
1141 |
|
|
|
1142 |
|
|
if (interct<=1) { /* there is no connectivity on this face */ |
1143 |
|
|
ELL_4V_SET(sctx->pairs+12*(faceid+4*si),-1,-1,-1,-1); |
1144 |
|
|
} else if (interct==2) { /* connectivity is straightforward */ |
1145 |
|
|
ELL_4V_SET(sctx->pairs+12*(faceid+4*si),inter[0],inter[1],-1,-1); |
1146 |
|
|
} else { /* we need gradients and coordinates to make a decision */ |
1147 |
|
|
double interc[24]; /* 2D coordinates of intersection points */ |
1148 |
|
|
double intern[24]; /* 2D normals at intersection points */ |
1149 |
|
|
/* used to find the best pairing without self-intersection */ |
1150 |
|
|
double bestscore=1e20; |
1151 |
|
|
char idcs[12]; /* consider if we need to restrict this */ |
1152 |
|
|
for (i=0; i<interct; i++) { |
1153 |
|
|
if (inter[i]<12) { /* edge feature */ |
1154 |
|
|
int resolved=edgeid[faceid][inter[i]/3]; |
1155 |
|
|
int offset=inter[i]%3; |
1156 |
|
|
switch (faceid) { |
1157 |
|
|
case 0: case 3: |
1158 |
|
|
ELL_2V_SET(interc+2*i, |
1159 |
|
|
sctx->edgeicoord[9*(bag->evti[resolved]+5*si)+3*offset], |
1160 |
|
|
sctx->edgeicoord[9*(bag->evti[resolved]+5*si)+3*offset+1]); |
1161 |
|
|
ELL_2V_SET(intern+2*i, |
1162 |
|
|
sctx->edgenorm[9*(bag->evti[resolved]+5*si)+3*offset], |
1163 |
|
|
sctx->edgenorm[9*(bag->evti[resolved]+5*si)+3*offset+1]); |
1164 |
|
|
break; |
1165 |
|
|
case 1: |
1166 |
|
|
ELL_2V_SET(interc+2*i, |
1167 |
|
|
sctx->edgeicoord[9*(bag->evti[resolved]+5*si)+3*offset], |
1168 |
|
|
sctx->edgeicoord[9*(bag->evti[resolved]+5*si)+3*offset+2]); |
1169 |
|
|
ELL_2V_SET(intern+2*i, |
1170 |
|
|
sctx->edgenorm[9*(bag->evti[resolved]+5*si)+3*offset], |
1171 |
|
|
sctx->edgenorm[9*(bag->evti[resolved]+5*si)+3*offset+2]); |
1172 |
|
|
break; |
1173 |
|
|
case 2: |
1174 |
|
|
ELL_2V_SET(interc+2*i, |
1175 |
|
|
sctx->edgeicoord[9*(bag->evti[resolved]+5*si)+3*offset+1], |
1176 |
|
|
sctx->edgeicoord[9*(bag->evti[resolved]+5*si)+3*offset+2]); |
1177 |
|
|
ELL_2V_SET(intern+2*i, |
1178 |
|
|
sctx->edgenorm[9*(bag->evti[resolved]+5*si)+3*offset+1], |
1179 |
|
|
sctx->edgenorm[9*(bag->evti[resolved]+5*si)+3*offset+2]); |
1180 |
|
|
break; |
1181 |
|
|
} |
1182 |
|
|
} else { /* face feature */ |
1183 |
|
|
switch (faceid) { |
1184 |
|
|
case 0: case 3: |
1185 |
|
|
ELL_2V_SET(interc+2*i, sctx->faceicoord[3*(faceid+4*si)], |
1186 |
|
|
sctx->faceicoord[3*(faceid+4*si)+1]); |
1187 |
|
|
ELL_2V_SET(intern+2*i, sctx->facenorm[3*(faceid+4*si)], |
1188 |
|
|
sctx->facenorm[3*(faceid+4*si)+1]); |
1189 |
|
|
break; |
1190 |
|
|
case 1: |
1191 |
|
|
ELL_2V_SET(interc+2*i, sctx->faceicoord[3*(faceid+4*si)], |
1192 |
|
|
sctx->faceicoord[3*(faceid+4*si)+2]); |
1193 |
|
|
ELL_2V_SET(intern+2*i, sctx->facenorm[3*(faceid+4*si)], |
1194 |
|
|
sctx->facenorm[3*(faceid+4*si)+2]); |
1195 |
|
|
break; |
1196 |
|
|
case 2: |
1197 |
|
|
ELL_2V_SET(interc+2*i, sctx->faceicoord[3*(faceid+4*si)+1], |
1198 |
|
|
sctx->faceicoord[3*(faceid+4*si)+2]); |
1199 |
|
|
ELL_2V_SET(intern+2*i, sctx->facenorm[3*(faceid+4*si)+1], |
1200 |
|
|
sctx->facenorm[3*(faceid+4*si)+2]); |
1201 |
|
|
break; |
1202 |
|
|
} |
1203 |
|
|
} |
1204 |
|
|
} |
1205 |
|
|
for (i=0; i<interct; i++) { |
1206 |
|
|
sctx->pairs[12*(faceid+4*si)+i]=i; |
1207 |
|
|
idcs[i]=i; |
1208 |
|
|
} |
1209 |
|
|
findConnectivity(sctx->pairs+12*(faceid+4*si), &bestscore, interct, |
1210 |
|
|
idcs, 0, interc, intern); |
1211 |
|
|
for (i=0; i<interct; i++) |
1212 |
|
|
sctx->pairs[12*(faceid+4*si)+i]=inter[sctx->pairs[12*(faceid+4*si)+i]]; |
1213 |
|
|
for (i=interct; i<12; i++) |
1214 |
|
|
sctx->pairs[12*(faceid+4*si)+i]=-1; |
1215 |
|
|
} |
1216 |
|
|
} |
1217 |
|
|
|
1218 |
|
|
static void |
1219 |
|
|
intersectionShuffleProbe(seekContext *sctx, baggage *bag) { |
1220 |
|
|
unsigned int xi, yi, sx, sy, si; |
1221 |
|
|
int i; |
1222 |
|
|
|
1223 |
|
|
sx = AIR_CAST(unsigned int, sctx->sx); |
1224 |
|
|
sy = AIR_CAST(unsigned int, sctx->sy); |
1225 |
|
|
|
1226 |
|
|
for (yi=0; yi<sy; yi++) { |
1227 |
|
|
for (xi=0; xi<sx; xi++) { |
1228 |
|
|
si = xi + sx*yi; |
1229 |
|
|
/* take care of facevidx array */ |
1230 |
|
|
if (!bag->zi) { /* initialize, else copy over */ |
1231 |
|
|
sctx->facevidx[0 + 4*si] = -1; |
1232 |
|
|
} else { |
1233 |
|
|
sctx->facevidx[0 + 4*si] = sctx->facevidx[3 + 4*si]; |
1234 |
|
|
} |
1235 |
|
|
sctx->facevidx[1 + 4*si] = sctx->facevidx[2 + 4*si] = |
1236 |
|
|
sctx->facevidx[3 + 4*si] = -1; |
1237 |
|
|
|
1238 |
|
|
/* copy or reset data on the 5 unique edges */ |
1239 |
|
|
|
1240 |
|
|
if (sctx->treated[si]&_SEEK_TREATED_EDGE3) { |
1241 |
|
|
/* has been treated, just copy results */ |
1242 |
|
|
ELL_3V_COPY(sctx->edgealpha+3*(0+5*si), sctx->edgealpha+3*(3+5*si)); |
1243 |
|
|
ELL_3M_COPY(sctx->edgenorm+9*(0+5*si), sctx->edgenorm+9*(3+5*si)); |
1244 |
|
|
ELL_3M_COPY(sctx->edgeicoord+9*(0+5*si), sctx->edgeicoord+9*(3+5*si)); |
1245 |
|
|
sctx->treated[si]|=_SEEK_TREATED_EDGE0; |
1246 |
|
|
} else if (xi!=sx-1) { |
1247 |
|
|
ELL_3V_SET(sctx->edgealpha+3*(0+5*si),-1,-1,-1); |
1248 |
|
|
sctx->treated[si]&=0xFF^_SEEK_TREATED_EDGE0; |
1249 |
|
|
} |
1250 |
|
|
|
1251 |
|
|
if (sctx->treated[si]&_SEEK_TREATED_EDGE4) { |
1252 |
|
|
/* has been treated, just copy results */ |
1253 |
|
|
ELL_3V_COPY(sctx->edgealpha+3*(1+5*si), sctx->edgealpha+3*(4+5*si)); |
1254 |
|
|
ELL_3M_COPY(sctx->edgenorm+9*(1+5*si), sctx->edgenorm+9*(4+5*si)); |
1255 |
|
|
ELL_3M_COPY(sctx->edgeicoord+9*(1+5*si), sctx->edgeicoord+9*(4+5*si)); |
1256 |
|
|
sctx->treated[si]|=_SEEK_TREATED_EDGE1; |
1257 |
|
|
} else if (yi!=sy-1) { |
1258 |
|
|
ELL_3V_SET(sctx->edgealpha+3*(1+5*si),-1,-1,-1); |
1259 |
|
|
sctx->treated[si]&=0xFF^_SEEK_TREATED_EDGE1; |
1260 |
|
|
} |
1261 |
|
|
|
1262 |
|
|
/* edges within and at top of the slab are new */ |
1263 |
|
|
ELL_3V_SET(sctx->edgealpha+3*(2+5*si),-1,-1,-1); |
1264 |
|
|
sctx->treated[si]&=0xFF^_SEEK_TREATED_EDGE2; |
1265 |
|
|
|
1266 |
|
|
ELL_3V_SET(sctx->edgealpha+3*(3+5*si),-1,-1,-1); |
1267 |
|
|
sctx->treated[si]&=0xFF^_SEEK_TREATED_EDGE3; |
1268 |
|
|
|
1269 |
|
|
ELL_3V_SET(sctx->edgealpha+3*(4+5*si),-1,-1,-1); |
1270 |
|
|
sctx->treated[si]&=0xFF^_SEEK_TREATED_EDGE4; |
1271 |
|
|
} |
1272 |
|
|
} |
1273 |
|
|
|
1274 |
|
|
/* find missing deg. points, edge intersections, normals, and |
1275 |
|
|
* connectivity on the four unique faces |
1276 |
|
|
* this is done in a separate pass to make sure that all edge information |
1277 |
|
|
* has been updated */ |
1278 |
|
|
for (yi=0; yi<sy; yi++) { |
1279 |
|
|
for (xi=0; xi<sx; xi++) { |
1280 |
|
|
si = xi + sx*yi; |
1281 |
|
|
if (sctx->treated[si]&_SEEK_TREATED_FACE3) { |
1282 |
|
|
/* we can copy previous results */ |
1283 |
|
|
ELL_2V_COPY(sctx->facecoord+2*(0+4*si), sctx->facecoord+2*(3+4*si)); |
1284 |
|
|
ELL_3V_COPY(sctx->faceicoord+3*(0+4*si), sctx->faceicoord+3*(3+4*si)); |
1285 |
|
|
ELL_3V_COPY(sctx->facenorm+3*(0+4*si), sctx->facenorm+3*(3+4*si)); |
1286 |
|
|
for (i=0; i<3; i++) |
1287 |
|
|
ELL_4V_COPY(sctx->pairs+12*(0+4*si)+4*i, sctx->pairs+12*(3+4*si)+4*i); |
1288 |
|
|
} else if (xi!=sx-1 && yi!=sy-1) { |
1289 |
|
|
if (sctx->treated[si]&_SEEK_TREATED_REQUEST) |
1290 |
|
|
connectFace(sctx, bag, xi, yi, 0); |
1291 |
|
|
else |
1292 |
|
|
ELL_4V_SET(sctx->pairs+12*(0+4*si),-1,-1,-1,-1); |
1293 |
|
|
} |
1294 |
|
|
if (xi!=sx-1) { |
1295 |
|
|
if (sctx->treated[si]&_SEEK_TREATED_REQUEST || |
1296 |
|
|
(yi!=0 && sctx->treated[xi+sx*(yi-1)]&_SEEK_TREATED_REQUEST)) |
1297 |
|
|
connectFace(sctx, bag, xi, yi, 1); |
1298 |
|
|
else ELL_4V_SET(sctx->pairs+12*(1+4*si),-1,-1,-1,-1); |
1299 |
|
|
} |
1300 |
|
|
if (yi!=sy-1) { |
1301 |
|
|
if (sctx->treated[si]&_SEEK_TREATED_REQUEST || |
1302 |
|
|
(xi!=0 && sctx->treated[xi-1+sx*yi]&_SEEK_TREATED_REQUEST)) |
1303 |
|
|
connectFace(sctx, bag, xi, yi, 2); |
1304 |
|
|
else ELL_4V_SET(sctx->pairs+12*(2+4*si),-1,-1,-1,-1); |
1305 |
|
|
if (xi!=sx-1) { |
1306 |
|
|
if (sctx->treated[si]&_SEEK_TREATED_REQUEST) { |
1307 |
|
|
connectFace(sctx, bag, xi, yi, 3); |
1308 |
|
|
sctx->treated[si]|=_SEEK_TREATED_FACE3; |
1309 |
|
|
} else { |
1310 |
|
|
ELL_4V_SET(sctx->pairs+12*(3+4*si),-1,-1,-1,-1); |
1311 |
|
|
sctx->treated[si]&=0xFF^_SEEK_TREATED_FACE3; |
1312 |
|
|
} |
1313 |
|
|
} |
1314 |
|
|
} |
1315 |
|
|
} |
1316 |
|
|
} |
1317 |
|
|
} |
1318 |
|
|
|
1319 |
|
|
/* special triangulation routine for use with T-based extraction */ |
1320 |
|
|
int |
1321 |
|
|
_seekTriangulateT(seekContext *sctx, baggage *bag, limnPolyData *lpld) { |
1322 |
|
|
unsigned xi, yi, sx, sy, si, i; |
1323 |
|
|
|
1324 |
|
|
/* map edge indices w.r.t. faces (as used in sctx->pairs) back to |
1325 |
|
|
* edge indices w.r.t. voxel */ |
1326 |
|
|
char edges[6][5]={{0, 2, 3, 1,12}, |
1327 |
|
|
{0, 5, 8, 4,13}, |
1328 |
|
|
{2, 7,10, 5,14}, |
1329 |
|
|
{3, 7,11, 6,15}, |
1330 |
|
|
{1, 6, 9, 4,16}, |
1331 |
|
|
{8,10,11, 9,17}}; |
1332 |
|
|
|
1333 |
|
|
sx = AIR_CAST(unsigned int, sctx->sx); |
1334 |
|
|
sy = AIR_CAST(unsigned int, sctx->sy); |
1335 |
|
|
|
1336 |
|
|
for (yi=0; yi<sy-1; yi++) { |
1337 |
|
|
for (xi=0; xi<sx-1; xi++) { |
1338 |
|
|
int fvti[6]; /* indices into unique face array */ |
1339 |
|
|
char connections[84];/* (12 edges * 3 possible intersections+6 faces)*2 */ |
1340 |
|
|
char degeneracies[6]; |
1341 |
|
|
int degct=0; |
1342 |
|
|
|
1343 |
|
|
unsigned int face; |
1344 |
|
|
|
1345 |
|
|
if (sctx->strengthUse && sctx->stng[0+2*(xi+sx*yi)] < sctx->strength && |
1346 |
|
|
sctx->stng[1+2*(xi+sx*yi)] < sctx->strength && |
1347 |
|
|
sctx->stng[0+2*(xi+1+sx*yi)] < sctx->strength && |
1348 |
|
|
sctx->stng[1+2*(xi+1+sx*yi)] < sctx->strength && |
1349 |
|
|
sctx->stng[0+2*(xi+sx*(yi+1))] < sctx->strength && |
1350 |
|
|
sctx->stng[1+2*(xi+sx*(yi+1))] < sctx->strength && |
1351 |
|
|
sctx->stng[0+2*(xi+1+sx*(yi+1))] < sctx->strength && |
1352 |
|
|
sctx->stng[1+2*(xi+1+sx*(yi+1))] < sctx->strength) |
1353 |
|
|
continue;/* all vertices below strength limit, do not create geometry */ |
1354 |
|
|
|
1355 |
|
|
si = xi + sx*yi; |
1356 |
|
|
ELL_3V_SET(fvti, 0 + 4*si, 1 + 4*si, 2 + 4*(xi+1 + sx*yi)); |
1357 |
|
|
ELL_3V_SET(fvti+3, 1 + 4*(xi + sx*(yi+1)), 2 + 4*si, 3 + 4*si); |
1358 |
|
|
|
1359 |
|
|
/* collect all intersection + connectivity info for this voxel */ |
1360 |
|
|
memset(connections,-1,sizeof(connections)); |
1361 |
|
|
for (face=0; face<6; face++) { |
1362 |
|
|
for (i=0; i<6; i++) { |
1363 |
|
|
int idx1, offset1, idx2, offset2, idxmap1, idxmap2; |
1364 |
|
|
if (sctx->pairs[12*fvti[face]+2*i]==-1) break; |
1365 |
|
|
idx1=edges[face][sctx->pairs[12*fvti[face]+2*i]/3]; |
1366 |
|
|
offset1=sctx->pairs[12*fvti[face]+2*i]%3; |
1367 |
|
|
idx2=edges[face][sctx->pairs[12*fvti[face]+2*i+1]/3]; |
1368 |
|
|
offset2=sctx->pairs[12*fvti[face]+2*i+1]%3; |
1369 |
|
|
idxmap1=3*idx1+offset1; |
1370 |
|
|
idxmap2=3*idx2+offset2; |
1371 |
|
|
if (idx1>11) { |
1372 |
|
|
idxmap1=idx1+24; /* +36-12 */ |
1373 |
|
|
degeneracies[degct++] = idxmap1; |
1374 |
|
|
} |
1375 |
|
|
if (idx2>11) { |
1376 |
|
|
idxmap2=idx2+24; |
1377 |
|
|
degeneracies[degct++] = idxmap2; |
1378 |
|
|
} |
1379 |
|
|
|
1380 |
|
|
if (connections[2*idxmap1]==-1) |
1381 |
|
|
connections[2*idxmap1]=idxmap2; |
1382 |
|
|
else |
1383 |
|
|
connections[2*idxmap1+1]=idxmap2; |
1384 |
|
|
if (connections[2*idxmap2]==-1) |
1385 |
|
|
connections[2*idxmap2]=idxmap1; |
1386 |
|
|
else |
1387 |
|
|
connections[2*idxmap2+1]=idxmap1; |
1388 |
|
|
} |
1389 |
|
|
} |
1390 |
|
|
|
1391 |
|
|
/* connect the degenerate points */ |
1392 |
|
|
if (degct==2) { |
1393 |
|
|
connections[2*degeneracies[0]+1]=degeneracies[1]; |
1394 |
|
|
connections[2*degeneracies[1]+1]=degeneracies[0]; |
1395 |
|
|
} else if (degct==4) { |
1396 |
|
|
int bestchoice=0; |
1397 |
|
|
int eidcs[4], fidcs[4]; |
1398 |
|
|
int k; |
1399 |
|
|
double bestscore, score; |
1400 |
|
|
for (k=0; k<4; ++k) { |
1401 |
|
|
eidcs[k]=3*(bag->evti[connections[2*degeneracies[k]]/3]+5*si)+ |
1402 |
|
|
connections[2*degeneracies[k]]%3; |
1403 |
|
|
fidcs[k]=fvti[degeneracies[k]-36]; |
1404 |
|
|
} |
1405 |
|
|
bestscore=evaluateDegConnection(sctx->edgeicoord+3*eidcs[0], |
1406 |
|
|
sctx->faceicoord+3*fidcs[0], |
1407 |
|
|
sctx->faceicoord+3*fidcs[1], |
1408 |
|
|
sctx->edgeicoord+3*eidcs[1], |
1409 |
|
|
sctx->edgeicoord+3*eidcs[2], |
1410 |
|
|
sctx->faceicoord+3*fidcs[2], |
1411 |
|
|
sctx->faceicoord+3*fidcs[3], |
1412 |
|
|
sctx->edgeicoord+3*eidcs[3], |
1413 |
|
|
NULL, NULL, NULL, NULL, |
1414 |
|
|
sctx->facenorm+3*fidcs[0], |
1415 |
|
|
sctx->facenorm+3*fidcs[1], |
1416 |
|
|
sctx->facenorm+3*fidcs[2], |
1417 |
|
|
sctx->facenorm+3*fidcs[3], |
1418 |
|
|
NULL, NULL); |
1419 |
|
|
score=evaluateDegConnection(sctx->edgeicoord+3*eidcs[0], |
1420 |
|
|
sctx->faceicoord+3*fidcs[0], |
1421 |
|
|
sctx->faceicoord+3*fidcs[2], |
1422 |
|
|
sctx->edgeicoord+3*eidcs[2], |
1423 |
|
|
sctx->edgeicoord+3*eidcs[1], |
1424 |
|
|
sctx->faceicoord+3*fidcs[1], |
1425 |
|
|
sctx->faceicoord+3*fidcs[3], |
1426 |
|
|
sctx->edgeicoord+3*eidcs[3], |
1427 |
|
|
NULL, NULL, NULL, NULL, |
1428 |
|
|
sctx->facenorm+3*fidcs[0], |
1429 |
|
|
sctx->facenorm+3*fidcs[2], |
1430 |
|
|
sctx->facenorm+3*fidcs[1], |
1431 |
|
|
sctx->facenorm+3*fidcs[3], |
1432 |
|
|
NULL, NULL); |
1433 |
|
|
if (score<bestscore) { |
1434 |
|
|
bestscore=score; |
1435 |
|
|
bestchoice=1; |
1436 |
|
|
} |
1437 |
|
|
score=evaluateDegConnection(sctx->edgeicoord+3*eidcs[0], |
1438 |
|
|
sctx->faceicoord+3*fidcs[0], |
1439 |
|
|
sctx->faceicoord+3*fidcs[3], |
1440 |
|
|
sctx->edgeicoord+3*eidcs[3], |
1441 |
|
|
sctx->edgeicoord+3*eidcs[1], |
1442 |
|
|
sctx->faceicoord+3*fidcs[1], |
1443 |
|
|
sctx->faceicoord+3*fidcs[2], |
1444 |
|
|
sctx->edgeicoord+3*eidcs[2], |
1445 |
|
|
NULL, NULL, NULL, NULL, |
1446 |
|
|
sctx->facenorm+3*fidcs[0], |
1447 |
|
|
sctx->facenorm+3*fidcs[3], |
1448 |
|
|
sctx->facenorm+3*fidcs[1], |
1449 |
|
|
sctx->facenorm+3*fidcs[2], |
1450 |
|
|
NULL, NULL); |
1451 |
|
|
if (score<bestscore) { |
1452 |
|
|
bestscore=score; |
1453 |
|
|
bestchoice=2; |
1454 |
|
|
} |
1455 |
|
|
switch (bestchoice) { |
1456 |
|
|
case 0: connections[2*degeneracies[0]+1]=degeneracies[1]; |
1457 |
|
|
connections[2*degeneracies[1]+1]=degeneracies[0]; |
1458 |
|
|
connections[2*degeneracies[2]+1]=degeneracies[3]; |
1459 |
|
|
connections[2*degeneracies[3]+1]=degeneracies[2]; |
1460 |
|
|
break; |
1461 |
|
|
case 1: connections[2*degeneracies[0]+1]=degeneracies[2]; |
1462 |
|
|
connections[2*degeneracies[2]+1]=degeneracies[0]; |
1463 |
|
|
connections[2*degeneracies[1]+1]=degeneracies[3]; |
1464 |
|
|
connections[2*degeneracies[3]+1]=degeneracies[1]; |
1465 |
|
|
break; |
1466 |
|
|
case 2: connections[2*degeneracies[0]+1]=degeneracies[3]; |
1467 |
|
|
connections[2*degeneracies[3]+1]=degeneracies[0]; |
1468 |
|
|
connections[2*degeneracies[1]+1]=degeneracies[2]; |
1469 |
|
|
connections[2*degeneracies[2]+1]=degeneracies[1]; |
1470 |
|
|
break; |
1471 |
|
|
} |
1472 |
|
|
} else if (degct==6) { |
1473 |
|
|
int bestchoice=0; |
1474 |
|
|
int eidcs[6], fidcs[6]; |
1475 |
|
|
int k; |
1476 |
|
|
double bestscore; |
1477 |
|
|
int pairings[15][6]={{0,1,2,3,4,5},{0,1,2,4,3,5},{0,1,2,5,3,4}, |
1478 |
|
|
{0,2,1,3,4,5},{0,2,1,4,3,5},{0,2,1,5,3,4}, |
1479 |
|
|
{0,3,1,2,4,5},{0,3,1,4,2,5},{0,3,1,5,2,4}, |
1480 |
|
|
{0,4,1,2,3,5},{0,4,1,3,2,5},{0,4,1,5,2,3}, |
1481 |
|
|
{0,5,1,2,3,4},{0,5,1,3,2,4},{0,5,1,4,2,3}}; |
1482 |
|
|
for (k=0; k<6; ++k) { |
1483 |
|
|
eidcs[k]=3*(bag->evti[connections[2*degeneracies[k]]/3]+5*si)+ |
1484 |
|
|
connections[2*degeneracies[k]]%3; |
1485 |
|
|
fidcs[k]=fvti[degeneracies[k]-36]; |
1486 |
|
|
} |
1487 |
|
|
bestscore=evaluateDegConnection(sctx->edgeicoord+3*eidcs[0], |
1488 |
|
|
sctx->faceicoord+3*fidcs[0], |
1489 |
|
|
sctx->faceicoord+3*fidcs[1], |
1490 |
|
|
sctx->edgeicoord+3*eidcs[1], |
1491 |
|
|
sctx->edgeicoord+3*eidcs[2], |
1492 |
|
|
sctx->faceicoord+3*fidcs[2], |
1493 |
|
|
sctx->faceicoord+3*fidcs[3], |
1494 |
|
|
sctx->edgeicoord+3*eidcs[3], |
1495 |
|
|
sctx->edgeicoord+3*eidcs[4], |
1496 |
|
|
sctx->faceicoord+3*fidcs[4], |
1497 |
|
|
sctx->faceicoord+3*fidcs[5], |
1498 |
|
|
sctx->edgeicoord+3*eidcs[5], |
1499 |
|
|
sctx->facenorm+3*fidcs[0], |
1500 |
|
|
sctx->facenorm+3*fidcs[1], |
1501 |
|
|
sctx->facenorm+3*fidcs[2], |
1502 |
|
|
sctx->facenorm+3*fidcs[3], |
1503 |
|
|
sctx->facenorm+3*fidcs[4], |
1504 |
|
|
sctx->facenorm+3*fidcs[5]); |
1505 |
|
|
for (k=1; k<15; ++k) { |
1506 |
|
|
double score=evaluateDegConnection |
1507 |
|
|
(sctx->edgeicoord+3*eidcs[pairings[k][0]], |
1508 |
|
|
sctx->faceicoord+3*fidcs[pairings[k][0]], |
1509 |
|
|
sctx->faceicoord+3*fidcs[pairings[k][1]], |
1510 |
|
|
sctx->edgeicoord+3*eidcs[pairings[k][1]], |
1511 |
|
|
sctx->edgeicoord+3*eidcs[pairings[k][2]], |
1512 |
|
|
sctx->faceicoord+3*fidcs[pairings[k][2]], |
1513 |
|
|
sctx->faceicoord+3*fidcs[pairings[k][3]], |
1514 |
|
|
sctx->edgeicoord+3*eidcs[pairings[k][3]], |
1515 |
|
|
sctx->edgeicoord+3*eidcs[pairings[k][4]], |
1516 |
|
|
sctx->faceicoord+3*fidcs[pairings[k][4]], |
1517 |
|
|
sctx->faceicoord+3*fidcs[pairings[k][5]], |
1518 |
|
|
sctx->edgeicoord+3*eidcs[pairings[k][5]], |
1519 |
|
|
sctx->facenorm+3*fidcs[pairings[k][0]], |
1520 |
|
|
sctx->facenorm+3*fidcs[pairings[k][1]], |
1521 |
|
|
sctx->facenorm+3*fidcs[pairings[k][2]], |
1522 |
|
|
sctx->facenorm+3*fidcs[pairings[k][3]], |
1523 |
|
|
sctx->facenorm+3*fidcs[pairings[k][4]], |
1524 |
|
|
sctx->facenorm+3*fidcs[pairings[k][5]]); |
1525 |
|
|
if (score<bestscore) { |
1526 |
|
|
bestscore=score; bestchoice=k; |
1527 |
|
|
} |
1528 |
|
|
} |
1529 |
|
|
connections[2*degeneracies[pairings[bestchoice][0]]+1]= |
1530 |
|
|
degeneracies[pairings[bestchoice][1]]; |
1531 |
|
|
connections[2*degeneracies[pairings[bestchoice][1]]+1]= |
1532 |
|
|
degeneracies[pairings[bestchoice][0]]; |
1533 |
|
|
connections[2*degeneracies[pairings[bestchoice][2]]+1]= |
1534 |
|
|
degeneracies[pairings[bestchoice][3]]; |
1535 |
|
|
connections[2*degeneracies[pairings[bestchoice][3]]+1]= |
1536 |
|
|
degeneracies[pairings[bestchoice][2]]; |
1537 |
|
|
connections[2*degeneracies[pairings[bestchoice][4]]+1]= |
1538 |
|
|
degeneracies[pairings[bestchoice][5]]; |
1539 |
|
|
connections[2*degeneracies[pairings[bestchoice][5]]+1]= |
1540 |
|
|
degeneracies[pairings[bestchoice][4]]; |
1541 |
|
|
} |
1542 |
|
|
|
1543 |
|
|
/* sufficient to run to 36: each polygon will contain at least |
1544 |
|
|
* one edge vertex */ |
1545 |
|
|
for (i=0; i<36; i++) { |
1546 |
|
|
if (connections[2*i]!=-1) { |
1547 |
|
|
/* extract polygon from connections array */ |
1548 |
|
|
signed char polygon[42]; |
1549 |
|
|
unsigned char polyct=0; |
1550 |
|
|
char thiz=i; |
1551 |
|
|
char next=connections[2*i]; |
1552 |
|
|
polygon[polyct++]=i; |
1553 |
|
|
connections[2*i]=-1; |
1554 |
|
|
while (next!=-1) { |
1555 |
|
|
char helpnext; |
1556 |
|
|
polygon[polyct++]=next; |
1557 |
|
|
if (connections[2*next]==thiz) { |
1558 |
|
|
helpnext=connections[2*next+1]; |
1559 |
|
|
} else { |
1560 |
|
|
helpnext=connections[2*next]; |
1561 |
|
|
} |
1562 |
|
|
connections[2*next]=connections[2*next+1]=-1; |
1563 |
|
|
thiz = next; next = helpnext; |
1564 |
|
|
if (next==polygon[0]) |
1565 |
|
|
break; /* polygon is closed */ |
1566 |
|
|
} |
1567 |
|
|
if (next!=-1) { /* else: discard unclosed polygon */ |
1568 |
|
|
/* make sure all required vertices are there */ |
1569 |
|
|
int j; |
1570 |
|
|
for (j=0; j<polyct; ++j) { |
1571 |
|
|
double tvertA[4], tvertB[4]; |
1572 |
|
|
if (polygon[j]<36) { /* we may need to insert an edge vertex */ |
1573 |
|
|
int eidx=3*(bag->evti[polygon[j]/3] + 5*si)+polygon[j]%3; |
1574 |
|
|
if (-1 == sctx->vidx[eidx]) { |
1575 |
|
|
int ovi; |
1576 |
|
|
ELL_3V_COPY(tvertA, sctx->edgeicoord+3*eidx); |
1577 |
|
|
tvertA[3]=1.0; |
1578 |
|
|
|
1579 |
|
|
/* tvertB in input index space */ |
1580 |
|
|
ELL_4MV_MUL(tvertB, sctx->txfIdx, tvertA); |
1581 |
|
|
/* tvertA in world space */ |
1582 |
|
|
ELL_4MV_MUL(tvertA, sctx->shape->ItoW, tvertB); |
1583 |
|
|
ELL_4V_HOMOG(tvertA, tvertA); |
1584 |
|
|
|
1585 |
|
|
ovi = sctx->vidx[eidx] = |
1586 |
|
|
airArrayLenIncr(bag->xyzwArr, 1); |
1587 |
|
|
ELL_4V_SET_TT(lpld->xyzw + 4*ovi, float, |
1588 |
|
|
tvertA[0], tvertA[1], tvertA[2], 1.0); |
1589 |
|
|
|
1590 |
|
|
if (sctx->normalsFind) { |
1591 |
|
|
double len=ELL_3V_LEN(sctx->edgenorm+3*eidx); |
1592 |
|
|
airArrayLenIncr(bag->normArr, 1); |
1593 |
|
|
ELL_3V_SCALE_TT(lpld->norm + 3*ovi, float, 1.0/len, |
1594 |
|
|
sctx->edgenorm+3*eidx); |
1595 |
|
|
} |
1596 |
|
|
|
1597 |
|
|
sctx->vertNum++; |
1598 |
|
|
} |
1599 |
|
|
} else { /* we may need to insert a face vertex */ |
1600 |
|
|
int fidx=fvti[polygon[j]-36]; |
1601 |
|
|
if (-1 == sctx->facevidx[fidx]) { |
1602 |
|
|
int ovi; |
1603 |
|
|
ELL_3V_COPY(tvertA, sctx->faceicoord+3*fidx); |
1604 |
|
|
tvertA[3]=1.0; |
1605 |
|
|
/* tvertB in input index space */ |
1606 |
|
|
ELL_4MV_MUL(tvertB, sctx->txfIdx, tvertA); |
1607 |
|
|
/* tvertA in world space */ |
1608 |
|
|
ELL_4MV_MUL(tvertA, sctx->shape->ItoW, tvertB); |
1609 |
|
|
ELL_4V_HOMOG(tvertA, tvertA); |
1610 |
|
|
|
1611 |
|
|
ovi = sctx->facevidx[fidx] = |
1612 |
|
|
airArrayLenIncr(bag->xyzwArr, 1); |
1613 |
|
|
ELL_4V_SET_TT(lpld->xyzw + 4*ovi, float, |
1614 |
|
|
tvertA[0], tvertA[1], tvertA[2], 1.0); |
1615 |
|
|
|
1616 |
|
|
if (sctx->normalsFind) { |
1617 |
|
|
double len=ELL_3V_LEN(sctx->facenorm+3*fidx); |
1618 |
|
|
airArrayLenIncr(bag->normArr, 1); |
1619 |
|
|
ELL_3V_SCALE_TT(lpld->norm + 3*ovi, float, 1.0/len, |
1620 |
|
|
sctx->facenorm+3*fidx); |
1621 |
|
|
} |
1622 |
|
|
|
1623 |
|
|
sctx->vertNum++; |
1624 |
|
|
} |
1625 |
|
|
} |
1626 |
|
|
} |
1627 |
|
|
if (polyct>4) { /* we need to insert a helper vertex */ |
1628 |
|
|
double tvertA[4], tvertB[4], tvertAsum[4]={0,0,0,0}, |
1629 |
|
|
normsum[3]={0,0,0}; |
1630 |
|
|
int ovi; |
1631 |
|
|
unsigned int vii[3]; |
1632 |
|
|
|
1633 |
|
|
for (j=0; j<polyct; j++) { |
1634 |
|
|
if (polygon[j]<36) { |
1635 |
|
|
int eidx=3*(bag->evti[polygon[j]/3] + 5*si)+polygon[j]%3; |
1636 |
|
|
ELL_3V_COPY(tvertA, sctx->edgeicoord+3*eidx); |
1637 |
|
|
tvertA[3]=1.0; |
1638 |
|
|
ELL_4V_INCR(tvertAsum,tvertA); |
1639 |
|
|
if (ELL_3V_DOT(normsum,sctx->edgenorm+3*eidx)<0) |
1640 |
|
|
ELL_3V_SUB(normsum,normsum,sctx->edgenorm+3*eidx); |
1641 |
|
|
else |
1642 |
|
|
ELL_3V_INCR(normsum,sctx->edgenorm+3*eidx); |
1643 |
|
|
} else { |
1644 |
|
|
int fidx=fvti[polygon[j]-36]; |
1645 |
|
|
ELL_3V_COPY(tvertA, sctx->faceicoord+3*fidx); |
1646 |
|
|
tvertA[3]=1.0; |
1647 |
|
|
ELL_4V_INCR(tvertAsum,tvertA); |
1648 |
|
|
if (ELL_3V_DOT(normsum,sctx->facenorm+3*fidx)<0) |
1649 |
|
|
ELL_3V_SUB(normsum,normsum,sctx->facenorm+3*fidx); |
1650 |
|
|
else |
1651 |
|
|
ELL_3V_INCR(normsum,sctx->facenorm+3*fidx); |
1652 |
|
|
} |
1653 |
|
|
} |
1654 |
|
|
/* tvertB in input index space */ |
1655 |
|
|
ELL_4MV_MUL(tvertB, sctx->txfIdx, tvertAsum); |
1656 |
|
|
/* tvertA in world space */ |
1657 |
|
|
ELL_4MV_MUL(tvertA, sctx->shape->ItoW, tvertB); |
1658 |
|
|
ELL_4V_HOMOG(tvertA, tvertA); |
1659 |
|
|
|
1660 |
|
|
ovi = airArrayLenIncr(bag->xyzwArr, 1); |
1661 |
|
|
ELL_4V_SET_TT(lpld->xyzw + 4*ovi, float, |
1662 |
|
|
tvertA[0], tvertA[1], tvertA[2], 1.0); |
1663 |
|
|
if (sctx->normalsFind) { |
1664 |
|
|
double len=ELL_3V_LEN(normsum); |
1665 |
|
|
airArrayLenIncr(bag->normArr, 1); |
1666 |
|
|
ELL_3V_SCALE_TT(lpld->norm + 3*ovi, float, 1.0/len, normsum); |
1667 |
|
|
} |
1668 |
|
|
sctx->vertNum++; |
1669 |
|
|
|
1670 |
|
|
vii[0]=ovi; |
1671 |
|
|
vii[1]=sctx->vidx[3*(bag->evti[polygon[0]/3]+5*si)+polygon[0]%3]; |
1672 |
|
|
for (j=0; j<polyct; ++j) { |
1673 |
|
|
double edgeA[3], edgeB[3]; |
1674 |
|
|
double norm[3]; |
1675 |
|
|
vii[2]=vii[1]; |
1676 |
|
|
if (j==polyct-1) { |
1677 |
|
|
if (polygon[0]<36) |
1678 |
|
|
vii[1]=sctx->vidx[3*(bag->evti[polygon[0]/3] + 5*si)+ |
1679 |
|
|
polygon[0]%3]; |
1680 |
|
|
else vii[1]=sctx->facevidx[fvti[polygon[0]-36]]; |
1681 |
|
|
} else { |
1682 |
|
|
if (polygon[j+1]<36) |
1683 |
|
|
vii[1]=sctx->vidx[3*(bag->evti[polygon[j+1]/3] + 5*si)+ |
1684 |
|
|
polygon[j+1]%3]; |
1685 |
|
|
else vii[1]=sctx->facevidx[fvti[polygon[j+1]-36]]; |
1686 |
|
|
} |
1687 |
|
|
|
1688 |
|
|
/* check for degenerate tris */ |
1689 |
|
|
ELL_3V_SUB(edgeA, lpld->xyzw+4*vii[1], lpld->xyzw+4*vii[0]); |
1690 |
|
|
ELL_3V_SUB(edgeB, lpld->xyzw+4*vii[2], lpld->xyzw+4*vii[0]); |
1691 |
|
|
ELL_3V_CROSS(norm, edgeA, edgeB); |
1692 |
|
|
if (ELL_3V_DOT(norm,norm)!=0) { |
1693 |
|
|
unsigned iii = airArrayLenIncr(bag->indxArr, 3); |
1694 |
|
|
ELL_3V_COPY(lpld->indx + iii, vii); |
1695 |
|
|
lpld->icnt[0] += 3; |
1696 |
|
|
sctx->faceNum++; |
1697 |
|
|
} |
1698 |
|
|
/* else: degeneracies are caused by intersections that |
1699 |
|
|
* more or less coincide with a grid vertex. They |
1700 |
|
|
* should be harmless, so just don't create |
1701 |
|
|
* deg. triangles in this case */ |
1702 |
|
|
} |
1703 |
|
|
} else if (polyct>2) { |
1704 |
|
|
/* insert the actual triangles */ |
1705 |
|
|
unsigned int vii[3], iii; |
1706 |
|
|
if (polygon[0]<36) |
1707 |
|
|
vii[0]=sctx->vidx[3*(bag->evti[polygon[0]/3] + 5*si)+ |
1708 |
|
|
polygon[0]%3]; |
1709 |
|
|
else vii[0]=sctx->facevidx[fvti[polygon[0]-36]]; |
1710 |
|
|
if (polygon[1]<36) |
1711 |
|
|
vii[1]=sctx->vidx[3*(bag->evti[polygon[1]/3] + 5*si)+ |
1712 |
|
|
polygon[1]%3]; |
1713 |
|
|
else vii[1]=sctx->facevidx[fvti[polygon[1]-36]]; |
1714 |
|
|
if (polygon[2]<36) |
1715 |
|
|
vii[2]=sctx->vidx[3*(bag->evti[polygon[2]/3] + 5*si)+ |
1716 |
|
|
polygon[2]%3]; |
1717 |
|
|
else vii[2]=sctx->facevidx[fvti[polygon[2]-36]]; |
1718 |
|
|
iii = airArrayLenIncr(bag->indxArr, 3); |
1719 |
|
|
ELL_3V_COPY(lpld->indx + iii, vii); |
1720 |
|
|
lpld->icnt[0] += 3; |
1721 |
|
|
sctx->faceNum++; |
1722 |
|
|
|
1723 |
|
|
if (polyct==4) { |
1724 |
|
|
vii[1]=vii[2]; |
1725 |
|
|
if (polygon[3]<36) |
1726 |
|
|
vii[2]=sctx->vidx[3*(bag->evti[polygon[3]/3] + 5*si)+ |
1727 |
|
|
polygon[3]%3]; |
1728 |
|
|
else vii[2]=sctx->facevidx[fvti[polygon[3]-36]]; |
1729 |
|
|
iii = airArrayLenIncr(bag->indxArr, 3); |
1730 |
|
|
ELL_3V_COPY(lpld->indx + iii, vii); |
1731 |
|
|
lpld->icnt[0] += 3; |
1732 |
|
|
sctx->faceNum++; |
1733 |
|
|
} |
1734 |
|
|
} |
1735 |
|
|
} |
1736 |
|
|
} |
1737 |
|
|
} |
1738 |
|
|
} |
1739 |
|
|
} |
1740 |
|
|
return 0; |
1741 |
|
|
} |
1742 |
|
|
|
1743 |
|
|
static void |
1744 |
|
|
shuffleT(seekContext *sctx, baggage *bag) { |
1745 |
|
|
unsigned int xi, yi, sx, sy, si; |
1746 |
|
|
|
1747 |
|
|
sx = AIR_CAST(unsigned int, sctx->sx); |
1748 |
|
|
sy = AIR_CAST(unsigned int, sctx->sy); |
1749 |
|
|
|
1750 |
|
|
if (sctx->strengthUse) { /* requests need to be cleared initially */ |
1751 |
|
|
for (yi=0; yi<sy; yi++) { |
1752 |
|
|
for (xi=0; xi<sx; xi++) { |
1753 |
|
|
sctx->treated[xi+sx*yi] &= 0xFF^_SEEK_TREATED_REQUEST; |
1754 |
|
|
} |
1755 |
|
|
} |
1756 |
|
|
} /* else, the request bits are always on */ |
1757 |
|
|
|
1758 |
|
|
for (yi=0; yi<sy; yi++) { |
1759 |
|
|
for (xi=0; xi<sx; xi++) { |
1760 |
|
|
si = xi + sx*yi; |
1761 |
|
|
|
1762 |
|
|
/* vidx neither needs past nor future context */ |
1763 |
|
|
if (!bag->zi) { |
1764 |
|
|
ELL_3V_SET(sctx->vidx+3*(0+5*si), -1, -1, -1); |
1765 |
|
|
ELL_3V_SET(sctx->vidx+3*(1+5*si), -1, -1, -1); |
1766 |
|
|
} else { |
1767 |
|
|
ELL_3V_COPY(sctx->vidx+3*(0+5*si), sctx->vidx+3*(3+5*si)); |
1768 |
|
|
ELL_3V_COPY(sctx->vidx+3*(1+5*si), sctx->vidx+3*(4+5*si)); |
1769 |
|
|
} |
1770 |
|
|
ELL_3V_SET(sctx->vidx+3*(2+5*si),-1,-1,-1); |
1771 |
|
|
ELL_3V_SET(sctx->vidx+3*(3+5*si),-1,-1,-1); |
1772 |
|
|
ELL_3V_SET(sctx->vidx+3*(4+5*si),-1,-1,-1); |
1773 |
|
|
|
1774 |
|
|
/* strength only has future context */ |
1775 |
|
|
if (sctx->strengthUse) { |
1776 |
|
|
sctx->stng[0 + 2*si] = sctx->stng[1 + 2*si]; |
1777 |
|
|
sctx->stng[1 + 2*si] = sctx->stngcontext[si]; |
1778 |
|
|
if (sctx->stng[0+2*si]>sctx->strength || |
1779 |
|
|
sctx->stng[1+2*si]>sctx->strength) { |
1780 |
|
|
/* set up to four request bits */ |
1781 |
|
|
sctx->treated[si] |= _SEEK_TREATED_REQUEST; |
1782 |
|
|
if (xi!=0) sctx->treated[xi-1+sx*yi] |= _SEEK_TREATED_REQUEST; |
1783 |
|
|
if (yi!=0) sctx->treated[xi+sx*(yi-1)] |= _SEEK_TREATED_REQUEST; |
1784 |
|
|
if (xi!=0 && yi!=0) |
1785 |
|
|
sctx->treated[xi-1+sx*(yi-1)] |= _SEEK_TREATED_REQUEST; |
1786 |
|
|
} |
1787 |
|
|
} |
1788 |
|
|
|
1789 |
|
|
/* shuffle grad, hess and t in three steps: move to past context, |
1790 |
|
|
* shuffle in slab itself, move from future context */ |
1791 |
|
|
|
1792 |
|
|
ELL_3V_COPY(sctx->gradcontext + 3*(0+2*si), sctx->grad + 3*(0+2*si)); |
1793 |
|
|
ELL_3V_COPY(sctx->grad + 3*(0+2*si), sctx->grad + 3*(1+2*si)); |
1794 |
|
|
ELL_3V_COPY(sctx->grad + 3*(1+2*si), sctx->gradcontext + 3*(1+2*si)); |
1795 |
|
|
|
1796 |
|
|
ELL_3M_COPY(sctx->hesscontext + 9*(0+2*si), sctx->hess + 9*(0+2*si)); |
1797 |
|
|
ELL_3M_COPY(sctx->hess + 9*(0+2*si), sctx->hess + 9*(1+2*si)); |
1798 |
|
|
ELL_3M_COPY(sctx->hess + 9*(1+2*si), sctx->hesscontext + 9*(1+2*si)); |
1799 |
|
|
|
1800 |
|
|
ELL_3M_COPY(sctx->tcontext + 9*(0+2*si), sctx->t + 9*(0+2*si)); |
1801 |
|
|
ELL_3M_COPY(sctx->t + 9*(0+2*si), sctx->t + 9*(1+2*si)); |
1802 |
|
|
ELL_3M_COPY(sctx->t + 9*(1+2*si), sctx->tcontext + 9*(1+2*si)); |
1803 |
|
|
} |
1804 |
|
|
} |
1805 |
|
|
} |
1806 |
|
|
|
1807 |
|
|
static void |
1808 |
|
|
probeT(seekContext *sctx, baggage *bag, double zi) { |
1809 |
|
|
unsigned int xi, yi, sx, sy, si; |
1810 |
|
|
|
1811 |
|
|
sx = AIR_CAST(unsigned int, sctx->sx); |
1812 |
|
|
sy = AIR_CAST(unsigned int, sctx->sy); |
1813 |
|
|
|
1814 |
|
|
for (yi=0; yi<sy; yi++) { |
1815 |
|
|
for (xi=0; xi<sx; xi++) { |
1816 |
|
|
si = xi + sx*yi; |
1817 |
|
|
|
1818 |
|
|
if (sctx->gctx) { /* HEY: need this check, what's the right way? */ |
1819 |
|
|
_seekIdxProbe(sctx, bag, xi, yi, zi); |
1820 |
|
|
} |
1821 |
|
|
if (sctx->strengthUse) { |
1822 |
|
|
sctx->stngcontext[si] = sctx->strengthSign*sctx->stngAns[0]; |
1823 |
|
|
if (sctx->strengthSeenMax==AIR_NAN) { |
1824 |
|
|
sctx->strengthSeenMax = sctx->stngcontext[si]; |
1825 |
|
|
} |
1826 |
|
|
sctx->strengthSeenMax = AIR_MAX(sctx->strengthSeenMax, |
1827 |
|
|
sctx->stngcontext[si]); |
1828 |
|
|
} |
1829 |
|
|
ELL_3V_COPY(sctx->gradcontext + 3*(1 + 2*si), sctx->gradAns); |
1830 |
|
|
ELL_3M_COPY(sctx->hesscontext + 9*(1 + 2*si), sctx->hessAns); |
1831 |
|
|
_seekHess2T(sctx->tcontext + 9*(1 + 2*si), sctx->evalAns, sctx->evecAns, |
1832 |
|
|
sctx->evalDiffThresh, (sctx->type==seekTypeRidgeSurfaceT)); |
1833 |
|
|
} |
1834 |
|
|
} |
1835 |
|
|
} |
1836 |
|
|
|
1837 |
|
|
/* it has now become much easier to make this its own routine |
1838 |
|
|
* (vs. adding many more case distinctions to shuffleProbe) |
1839 |
|
|
* this only duplicates little (and trivial) code */ |
1840 |
|
|
int |
1841 |
|
|
_seekShuffleProbeT(seekContext *sctx, baggage *bag) { |
1842 |
|
|
/* for high-quality normal estimation, we need two slices of data |
1843 |
|
|
* context; to keep the code simple, separate shuffle and probe |
1844 |
|
|
* operations - let's hope this doesn't destroy cache performance */ |
1845 |
|
|
|
1846 |
|
|
if (!bag->zi) { |
1847 |
|
|
if (sctx->strengthUse) |
1848 |
|
|
/* before the first round, initialize treated to zero */ |
1849 |
|
|
memset(sctx->treated, 0, sizeof(char)*sctx->sx*sctx->sy); |
1850 |
|
|
else /* request all edges */ |
1851 |
|
|
memset(sctx->treated, _SEEK_TREATED_REQUEST, |
1852 |
|
|
sizeof(char)*sctx->sx*sctx->sy); |
1853 |
|
|
probeT(sctx, bag, 0); |
1854 |
|
|
shuffleT(sctx, bag); |
1855 |
|
|
probeT(sctx, bag, 1); |
1856 |
|
|
} |
1857 |
|
|
shuffleT(sctx, bag); |
1858 |
|
|
if (bag->zi!=sctx->sz-2) |
1859 |
|
|
probeT(sctx, bag, bag->zi+2); |
1860 |
|
|
|
1861 |
|
|
intersectionShuffleProbe(sctx, bag); |
1862 |
|
|
|
1863 |
|
|
return 0; |
1864 |
|
|
} |
1865 |
|
|
|
1866 |
|
|
/* For all vertices in pld, use sctx to probe the strength measure, |
1867 |
|
|
* and return the answer (times strengthSign) in nval. The intended |
1868 |
|
|
* use is postfiltering (with limnPolyDataClip), which is obligatory |
1869 |
|
|
* when using seekType*SurfaceT |
1870 |
|
|
* |
1871 |
|
|
* Returns 1 and adds a message to biff upon error |
1872 |
|
|
* Returns 0 on success, -n when probing n vertices failed (strength |
1873 |
|
|
* is set to AIR_NAN for those); note that positions outside the field |
1874 |
|
|
* are clamped to lie on its boundary. |
1875 |
|
|
* |
1876 |
|
|
* This routine assumes that a strength has been set in sctx and |
1877 |
|
|
* seekUpdate() has been run. |
1878 |
|
|
* This routine does not modify sctx->strengthSeenMax. |
1879 |
|
|
*/ |
1880 |
|
|
int |
1881 |
|
|
seekVertexStrength(Nrrd *nval, seekContext *sctx, limnPolyData *pld) { |
1882 |
|
|
static const char me[]="seekVertexStrength"; |
1883 |
|
|
unsigned int i; |
1884 |
|
|
double *data; |
1885 |
|
|
int E=0; |
1886 |
|
|
|
1887 |
|
|
if (!(nval && sctx && pld)) { |
1888 |
|
|
biffAddf(SEEK, "%s: got NULL pointer", me); |
1889 |
|
|
return 1; |
1890 |
|
|
} |
1891 |
|
|
if (!(sctx->gctx && sctx->pvl)) { |
1892 |
|
|
biffAddf(SEEK, "%s: need sctx with attached gageContext", me); |
1893 |
|
|
return 1; |
1894 |
|
|
} |
1895 |
|
|
if (!sctx->stngAns) { |
1896 |
|
|
biffAddf(SEEK, "%s: no strength item found. Did you enable strengthUse?", |
1897 |
|
|
me); |
1898 |
|
|
return 1; |
1899 |
|
|
} |
1900 |
|
|
if (nrrdAlloc_va(nval, nrrdTypeDouble, 1, (size_t) pld->xyzwNum)) { |
1901 |
|
|
biffAddf(SEEK, "%s: could not allocate output", me); |
1902 |
|
|
return 1; |
1903 |
|
|
} |
1904 |
|
|
|
1905 |
|
|
data = (double*) nval->data; |
1906 |
|
|
for (i=0; i<pld->xyzwNum; i++) { |
1907 |
|
|
float homog[4]; |
1908 |
|
|
ELL_4V_HOMOG(homog, pld->xyzw+4*i); |
1909 |
|
|
if (!gageProbeSpace(sctx->gctx,homog[0],homog[1],homog[2],0,1)) { |
1910 |
|
|
*(data++)=*(sctx->stngAns)*sctx->strengthSign; |
1911 |
|
|
} else { |
1912 |
|
|
*(data++)=AIR_NAN; |
1913 |
|
|
E--; |
1914 |
|
|
} |
1915 |
|
|
} |
1916 |
|
|
return E; |
1917 |
|
|
} |