GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/seek/textract.c Lines: 0 1154 0.0 %
Date: 2017-05-26 Branches: 0 553 0.0 %

Line Branch Exec Source
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
}