#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 */