src/parabola.h

    #include "utils.h"
    
    #define PARABOLA_FIT_CENTER_WEIGHT .1
    
    // Define this to use a x^iy^j polynomial with i = 0...NP-1, j = 0...NP-1
    // #define NP 3
    
    typedef struct {
      coord o;
    #if dimension == 2 /* y = a[0]*x^2 + a[1]*x + a[2] */
      coord m;
      double ** M, rhs[3], a[3];
    #else /* 3D z = a[0]*x^2 + a[1]*y^2 + a[2]*x*y + a[3]*x + a[4]*y + a[5] */
      double t[3][3];
    # ifdef NP
      double ** M, rhs[NP*NP], a[NP*NP];
    # else
      double ** M, rhs[6], a[6];
    # endif
    #endif /* 3D */
    } ParabolaFit;
    
    static void parabola_fit_init (ParabolaFit * p, coord o, coord m)
    {
      foreach_dimension()
        p->o.x = o.x;
    #if dimension == 2
      foreach_dimension()
        p->m.x = m.x;
      normalize (&p->m);
      int n = 3;
    #else /* 3D */
      double max;
      coord nx = {0., 0., 0.}, ny, nz;
      int d = 0;
    
      foreach_dimension()
        nz.x = m.x;
      normalize (&nz);
      max = sq(nz.x);
      /* build a vector orthogonal to nz */
      if (sq(nz.y) > max) { max = sq(nz.y); d = 1; }
      if (sq(nz.z) > max) d = 2;
      switch (d) {
      case 0: nx.x = - nz.z/nz.x; nx.z = 1.0; break;
      case 1: nx.y = - nz.z/nz.y; nx.z = 1.0; break;
      case 2: nx.z = - nz.x/nz.z; nx.x = 1.0; break;
      }
      normalize (&nx);
    
      /* build a second vector orthogonal to nx and nz */
      foreach_dimension()
        ny.x = nz.y*nx.z - nz.z*nx.y;
    
      /* transformation matrix from (i,j,k) to (nx, ny, nz) */
      p->t[0][0] = nx.x; p->t[0][1] = nx.y; p->t[0][2] = nx.z;
      p->t[1][0] = ny.x; p->t[1][1] = ny.y; p->t[1][2] = ny.z;
      p->t[2][0] = nz.x; p->t[2][1] = nz.y; p->t[2][2] = nz.z;
    # ifdef NP
      int n = NP*NP;
    # else
      int n = 6;
    # endif
    #endif /* 3D */
      p->M = (double **) matrix_new (n, n, sizeof(double));  
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++)
          p->M[i][j] = 0.;
        p->rhs[i] = 0.;
      }
    }
    
    static void parabola_fit_add (ParabolaFit * p, coord m, double w)
    {
    #if dimension == 2
      double x1 = m.x - p->o.x, y1 = m.y - p->o.y;
      double x = p->m.y*x1 - p->m.x*y1;
      double y = p->m.x*x1 + p->m.y*y1;
      double x2 = w*x*x, x3 = x2*x, x4 = x3*x;
      p->M[0][0] += x4;
      p->M[1][0] += x3; p->M[1][1] += x2;
      p->M[2][1] += w*x; p->M[2][2] += w;
      p->rhs[0] += x2*y; p->rhs[1] += w*x*y; p->rhs[2] += w*y;
    #else /* 3D */
      double x1 = m.x - p->o.x, y1 = m.y - p->o.y, z1 = m.z - p->o.z;
      double x = p->t[0][0]*x1 + p->t[0][1]*y1 + p->t[0][2]*z1;
      double y = p->t[1][0]*x1 + p->t[1][1]*y1 + p->t[1][2]*z1;
      double z = p->t[2][0]*x1 + p->t[2][1]*y1 + p->t[2][2]*z1;
    # ifdef NP
      for (int i = 0; i < NP; i++)
        for (int j = 0; j < NP; j++) {
          for (int k = 0; k < NP; k++)
    	for (int l = 0; l < NP; l++)
    	  p->M[i*NP + j][k*NP + l] += w*pow(x, i + k)*pow(y, j + l);
          p->rhs[i*NP + j] += w*z*pow(x, i)*pow(y, j);
        }
    # else // !NP 
      double x2 = x*x, x3 = x2*x, x4 = x3*x;
      double y2 = y*y, y3 = y2*y, y4 = y3*y;
      p->M[0][0] += w*x4; p->M[1][1] += w*y4; p->M[2][2] += w*x2*y2; 
      p->M[3][3] += w*x2; p->M[4][4] += w*y2; p->M[5][5] += w;
      p->M[0][2] += w*x3*y; p->M[0][3] += w*x3; p->M[0][4] += w*x2*y;
      p->M[1][2] += w*x*y3; p->M[1][3] += w*x*y2; p->M[1][4] += w*y3;
      p->M[2][5] += w*x*y;
      p->M[3][5] += w*x;
      p->M[4][5] += w*y;
      p->rhs[0] += w*x2*z; p->rhs[1] += w*y2*z; p->rhs[2] += w*x*y*z;
      p->rhs[3] += w*x*z; p->rhs[4] += w*y*z; p->rhs[5] += w*z;
    # endif // !NP
    #endif /* 3D */
    }
    
    static double parabola_fit_solve (ParabolaFit * p)
    {
    #if dimension == 2
      p->M[0][1] = p->M[1][0];
      p->M[0][2] = p->M[2][0] = p->M[1][1];
      p->M[1][2] = p->M[2][1];
      double pivmin = matrix_inverse (p->M, 3, 1e-10);
      if (pivmin) {
        p->a[0] = p->M[0][0]*p->rhs[0] + p->M[0][1]*p->rhs[1] + p->M[0][2]*p->rhs[2];
        p->a[1] = p->M[1][0]*p->rhs[0] + p->M[1][1]*p->rhs[1] + p->M[1][2]*p->rhs[2];
      }
      else /* this may be a degenerate/isolated interface fragment */
        p->a[0] = p->a[1] = 0.;
    #else /* 3D */
    # ifdef NP
      double pivmin = matrix_inverse (p->M, NP*NP, 1e-10);
      if (pivmin)
        for (int i = 0; i < NP*NP; i++) {
          p->a[i] = 0.;
          for (int j = 0; j < NP*NP; j++)
    	p->a[i] += p->M[i][j]*p->rhs[j];
        }
      else /* this may be a degenerate/isolated interface fragment */
        for (int i = 0; i < NP*NP; i++)
          p->a[i] = 0.;
    # else // !NP
      p->M[0][1] = p->M[2][2]; p->M[0][5] = p->M[3][3];
      p->M[1][5] = p->M[4][4];
      p->M[2][3] = p->M[0][4]; p->M[2][4] = p->M[1][3];
      p->M[3][4] = p->M[2][5];
      for (int i = 1; i < 6; i++)
        for (int j = 0; j < i; j++)
          p->M[i][j] = p->M[j][i];
      double pivmin = matrix_inverse (p->M, 6, 1e-10);
      if (pivmin)
        for (int i = 0; i < 6; i++) {
          p->a[i] = 0.;
          for (int j = 0; j < 6; j++)
    	p->a[i] += p->M[i][j]*p->rhs[j];
        }
      else /* this may be a degenerate/isolated interface fragment */
        for (int i = 0; i < 6; i++)
          p->a[i] = 0.;
    # endif // !NP
    #endif /* 3D */  
      matrix_free (p->M);
      return pivmin;
    }
    
    static double parabola_fit_curvature (ParabolaFit * p,
    				      double kappamax, double * kmax)
    {
      double kappa;
    #if dimension == 2
      double dnm = 1.[0] + sq(p->a[1]);
      kappa = - 2.*p->a[0]/pow(dnm, 3/2.);
      if (kmax)
        *kmax = fabs (kappa);
    #else /* 3D */
    # ifdef NP
      double hxx = 2.*p->a[2*NP], hyy = 2.*p->a[2], hxy = p->a[NP + 1];
      double hx = p->a[NP], hy = p->a[1];
    # else
      double hxx = 2.*p->a[0], hyy = 2.*p->a[1], hxy = p->a[2];
      double hx = p->a[3], hy = p->a[4];
    # endif
      double dnm = 1. + sq(hx) + sq(hy);
      kappa = - (hxx*(1. + sq(hy)) + hyy*(1. + sq(hx)) - 2.*hxy*hx*hy)
        /sqrt (dnm*dnm*dnm);
      if (kmax) {
        double kg = (hxx*hyy - hxy*hxy)/(dnm*dnm);
        double a = kappa*kappa/4. - kg;
        *kmax = fabs (kappa/2.);
        if (a >= 0.)
          *kmax += sqrt (a);
      }
    #endif /* 3D */
      if (fabs (kappa) > kappamax) {
        if (kmax)
          *kmax = kappamax;
        return kappa > 0. ? kappamax : - kappamax;
      }
      return kappa;
    }
    
    #if AXI
    static void parabola_fit_axi_curvature (const ParabolaFit * p,
    					double r, double h,
    					double * kappa, double * kmax)
    {
      double nr = (p->m.x*p->a[1] + p->m.y)/sqrt (1. + sq(p->a[1]));
      /* limit the minimum radius to half the grid size */
      double kaxi = nr/max(r, h/2.);
      *kappa += kaxi;
      if (kmax)
        *kmax = max (*kmax, fabs (kaxi));
    }
    #endif /* 2D */