diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp
index de581d894b8e21375ebc3ae8703c1f67710405cf..84af3697cd345e433f1950d7ab3c25a74a49a42c 100644
--- a/Mesh/qualityMeasures.cpp
+++ b/Mesh/qualityMeasures.cpp
@@ -333,3 +333,313 @@ double qmQuadrangleAngles (MQuadrangle *e) {
 
 }
 
+
+namespace {
+
+
+// Compute unit vector
+inline void unitVec(const double &x0, const double &y0, const double &z0,
+                    const double &x1, const double &y1, const double &z1,
+                    double &x01n, double &y01n, double &z01n)
+{
+  const double x01 = x1-x0, y01 = y1-y0, z01 = z1-z0;
+  const double invL01 = 1./sqrt(x01*x01 + y01*y01 + z01*z01);
+  x01n = x01*invL01; y01n = y01*invL01; z01n = z01*invL01;
+}
+
+
+// Compute unit vector and gradients w.r.t. x0, y0, z0, x1, y1, z1
+inline void unitVecAndGrad(const double &x0, const double &y0, const double &z0,
+                           const double &x1, const double &y1, const double &z1,
+                           fullMatrix<double> &res)
+{
+  const double x01 = x1-x0, y01 = y1-y0, z01 = z1-z0;
+  const double x01Sq = x01*x01, y01Sq = y01*y01, z01Sq = z01*z01;
+  const double invL01Sq = 1./(x01Sq+y01Sq+z01Sq), invL01 = sqrt(invL01Sq);
+  const double invL01Cu = invL01Sq*invL01;
+
+  double &dx01ndx0 = res(0, 0), &dx01ndy0 = res(0, 1), &dx01ndz0 = res(0, 2),
+          &dx01ndx1 = res(0, 3), &dx01ndy1 = res(0, 4), &dx01ndz1 = res(0, 5), &x01n = res(0, 6);
+  double &dy01ndx0 = res(1, 0), &dy01ndy0 = res(1, 1), &dy01ndz0 = res(1, 2),
+          &dy01ndx1 = res(1, 3), &dy01ndy1 = res(1, 4), &dy01ndz1 = res(1, 5), &y01n = res(1, 6);
+  double &dz01ndx0 = res(2, 0), &dz01ndy0 = res(2, 1), &dz01ndz0 = res(2, 2),
+          &dz01ndx1 = res(2, 3), &dz01ndy1 = res(2, 4), &dz01ndz1 = res(2, 5), &z01n = res(2, 6);
+
+  dx01ndx0 = x01Sq*invL01Cu-invL01;
+  dx01ndy0 = x01*y01*invL01Cu;
+  dx01ndz0 = x01*z01*invL01Cu;
+  dx01ndx1 = -dx01ndx0;
+  dx01ndy1 = -dx01ndy0;
+  dx01ndz1 = -dx01ndz0;
+  x01n = x01*invL01;
+
+  dy01ndx0 = dx01ndy0;
+  dy01ndy0 = y01Sq*invL01Cu-invL01;
+  dy01ndz0 = y01*z01*invL01Cu;
+  dy01ndx1 = -dy01ndx0;
+  dy01ndy1 = -dy01ndy0;
+  dy01ndz1 = -dy01ndz0;
+  y01n = y01*invL01;
+
+  dz01ndx0 = dx01ndz0;
+  dz01ndy0 = dy01ndz0;
+  dz01ndz0 = z01Sq*invL01Cu-invL01;
+  dz01ndx1 = -dx01ndz0;
+  dz01ndy1 = -dz01ndy0;
+  dz01ndz1 = -dz01ndz0;
+  z01n = z01*invL01;
+}
+
+
+// Given vectors a and b, compute area of triangle defined by both vectors (times a factor)
+inline double triArea(const double fact,
+                      const double &xa, const double &ya, const double &za,
+                      const double &xb, const double &yb, const double &zb)
+{
+  const double zn = xa*yb - xb*ya, yn = za*xb - xa*zb, xn = ya*zb - za*yb;
+  return fact * sqrt(xn*xn + yn*yn + zn*zn);
+}
+
+
+// Given vectors (0, 1) and (0, 2) and their gradients, compute area of triangle
+// defined by both vectors and grad. w.r.t. x0, y0, z0, x1, y1, z1, x2, y2, z2 (times a factor)
+inline void triAreaAndGrad(const double fact, const fullMatrix<double> &vga,
+                           const fullMatrix<double> &vgb, fullVector<double> &res)
+{
+  const double &dxadx0 = vga(0, 0), &dxady0 = vga(0, 1), &dxadz0 = vga(0, 2),
+                &dxadx1 = vga(0, 3), &dxady1 = vga(0, 4), &dxadz1 = vga(0, 5), &xa = vga(0, 6);
+  const double &dyadx0 = vga(1, 0), &dyady0 = vga(1, 1), &dyadz0 = vga(1, 2),
+                &dyadx1 = vga(1, 3), &dyady1 = vga(1, 4), &dyadz1 = vga(1, 5), &ya = vga(1, 6);
+  const double &dzadx0 = vga(2, 0), &dzady0 = vga(2, 1), &dzadz0 = vga(2, 2),
+                &dzadx1 = vga(2, 3), &dzady1 = vga(2, 4), &dzadz1 = vga(2, 5), &za = vga(2, 6);
+
+  const double &dxbdx0 = vgb(0, 0), &dxbdy0 = vgb(0, 1), &dxbdz0 = vgb(0, 2),
+                &dxbdx2 = vgb(0, 3), &dxbdy2 = vgb(0, 4), &dxbdz2 = vgb(0, 5), &xb = vgb(0, 6);
+  const double &dybdx0 = vgb(1, 0), &dybdy0 = vgb(1, 1), &dybdz0 = vgb(1, 2),
+                &dybdx2 = vgb(1, 3), &dybdy2 = vgb(1, 4), &dybdz2 = vgb(1, 5), &yb = vgb(1, 6);
+  const double &dzbdx0 = vgb(2, 0), &dzbdy0 = vgb(2, 1), &dzbdz0 = vgb(2, 2),
+                &dzbdx2 = vgb(2, 3), &dzbdy2 = vgb(2, 4), &dzbdz2 = vgb(2, 5), &zb = vgb(2, 6);
+
+  const double xn = ya*zb - za*yb;
+  const double dxndx0 = ya*dzbdx0 + dyadx0*zb - yb*dzadx0 - dybdx0*za;
+  const double dxndy0 = ya*dzbdy0 + dyady0*zb - yb*dzady0 - dybdy0*za;
+  const double dxndz0 = ya*dzbdz0 + dyadz0*zb - yb*dzadz0 - dybdz0*za;
+  const double dxndx1 = dyadx1*zb - yb*dzadx1;
+  const double dxndy1 = dyady1*zb - yb*dzady1;
+  const double dxndz1 = dyadz1*zb - yb*dzadz1;
+  const double dxndx2 = ya*dzbdx2 - dybdx2*za;
+  const double dxndy2 = ya*dzbdy2 - dybdy2*za;
+  const double dxndz2 = ya*dzbdz2 - dybdz2*za;
+
+  const double yn = za*xb - xa*zb;
+  const double dyndx0 = -xa*dzbdx0 - dxadx0*zb + xb*dzadx0 + dxbdx0*za;
+  const double dyndy0 = -xa*dzbdy0 - dxady0*zb + xb*dzady0 + dxbdy0*za;
+  const double dyndz0 = -xa*dzbdz0 - dxadz0*zb + xb*dzadz0 + dxbdz0*za;
+  const double dyndx1 = xb*dzadx1 - dxadx1*zb;
+  const double dyndy1 = xb*dzady1 - dxady1*zb;
+  const double dyndz1 = xb*dzadz1 - dxadz1*zb;
+  const double dyndx2 = dxbdx2*za - xa*dzbdx2;
+  const double dyndy2 = dxbdy2*za - xa*dzbdy2;
+  const double dyndz2 = dxbdz2*za - xa*dzbdz2;
+
+  const double zn = xa*yb - xb*ya;
+  const double dzndx0 = xa*dybdx0 + dxadx0*yb - xb*dyadx0 - dxbdx0*ya;
+  const double dzndy0 = xa*dybdy0 + dxady0*yb - xb*dyady0 - dxbdy0*ya;
+  const double dzndz0 = xa*dybdz0 + dxadz0*yb - xb*dyadz0 - dxbdz0*ya;
+  const double dzndx1 = dxadx1*yb - xb*dyadx1;
+  const double dzndy1 = dxady1*yb - xb*dyady1;
+  const double dzndz1 = dxadz1*yb - xb*dyadz1;
+  const double dzndx2 = xa*dybdx2 - dxbdx2*ya;
+  const double dzndy2 = xa*dybdy2 - dxbdy2*ya;
+  const double dzndz2 = xa*dybdz2 - dxbdz2*ya;
+
+  double &dNCJdx0 = res(0), &dNCJdy0 = res(1), &dNCJdz0 = res(2),
+          &dNCJdx1 = res(3), &dNCJdy1 = res(4), &dNCJdz1 = res(5),
+          &dNCJdx2 = res(6), &dNCJdy2 = res(7), &dNCJdz2 = res(8), &NCJ = res(9);
+
+  const double n = sqrt(xn*xn + yn*yn + zn*zn), invN = 1./n, fact2 = fact*invN;
+  dNCJdx0 = (dxndx0*xn + dyndx0*yn + dzndx0*zn) * fact2;
+  dNCJdy0 = (dxndy0*xn + dyndy0*yn + dzndy0*zn) * fact2;
+  dNCJdz0 = (dxndz0*xn + dyndz0*yn + dzndz0*zn) * fact2;
+  dNCJdx1 = (dxndx1*xn + dyndx1*yn + dzndx1*zn) * fact2;
+  dNCJdy1 = (dxndy1*xn + dyndy1*yn + dzndy1*zn) * fact2;
+  dNCJdz1 = (dxndz1*xn + dyndz1*yn + dzndz1*zn) * fact2;
+  dNCJdx2 = (dxndx2*xn + dyndx2*yn + dzndx2*zn) * fact2;
+  dNCJdy2 = (dxndy2*xn + dyndy2*yn + dzndy2*zn) * fact2;
+  dNCJdz2 = (dxndz2*xn + dyndz2*yn + dzndz2*zn) * fact2;
+  NCJ = fact * n;
+}
+
+
+inline void revertVG(const fullMatrix<double> &vg, fullMatrix<double> &res)
+{
+  res(0, 0) = -vg(0, 3); res(0, 1) = -vg(0, 4); res(0, 2) = -vg(0, 5); res(0, 6) = -vg(0, 6);
+  res(1, 0) = -vg(1, 3); res(1, 1) = -vg(1, 4); res(1, 2) = -vg(1, 5); res(1, 6) = -vg(1, 6);
+  res(2, 0) = -vg(2, 3); res(2, 1) = -vg(2, 4); res(2, 2) = -vg(2, 5); res(2, 6) = -vg(2, 6);
+}
+
+
+}
+
+
+void measuresTriangle::getNCJ(const double &x0, const double &y0, const double &z0,
+                              const double &x1, const double &y1, const double &z1,
+                              const double &x2, const double &y2, const double &z2,
+                              fullVector<double> &ncj)
+{
+  // Compute unit vectors for each edge
+  double x01n, y01n, z01n, x12n, y12n, z12n, x20n, y20n, z20n;
+  unitVec(x0, y0, z0, x1, y1, z1, x01n, y01n, z01n);
+  unitVec(x1, y1, z1, x2, y2, z2, x12n, y12n, z12n);
+  unitVec(x2, y2, z2, x0, y0, z0, x20n, y20n, z20n);
+
+  // Compute NCJ at vertex from unit vectors a and b as 0.5*||a^b||/A_equilateral
+  // Factor = 2./sqrt(3.) = 0.5/A_equilateral
+  static const double fact = 1.1547005383792517;
+  ncj(0) = triArea(fact, x01n, y01n, z01n, -x20n, -y20n, -z20n);
+  ncj(1) = triArea(fact, x12n, y12n, z12n, -x01n, -y01n, -z01n);
+  ncj(2) = triArea(fact, x20n, y20n, z20n, -x12n, -y12n, -z12n);
+}
+
+
+void measuresTriangle::getNCJAndGradients(const double &x0, const double &y0, const double &z0,
+                                          const double &x1, const double &y1, const double &z1,
+                                          const double &x2, const double &y2, const double &z2,
+                                          fullMatrix<double> &res)
+{
+  // Factor = 2./sqrt(3.) = 0.5/A_equilateral
+  static const double fact = 1.1547005383792517;
+
+  // Compute unit vector and its gradients for each edge
+  fullMatrix<double> vg01(3,7);
+  unitVecAndGrad(x0, y0, z0, x1, y1, z1, vg01);
+  fullMatrix<double> vg12(3,7);
+  unitVecAndGrad(x1, y1, z1, x2, y2, z2, vg12);
+  fullMatrix<double> vg20(3,7);
+  unitVecAndGrad(x2, y2, z2, x0, y0, z0, vg20);
+  fullMatrix<double> vg10(3,7);
+  revertVG(vg01, vg10);
+  fullMatrix<double> vg21(3,7);
+  revertVG(vg12, vg21);
+  fullMatrix<double> vg02(3,7);
+  revertVG(vg20, vg02);
+
+  // Compute NCJ at vertex 0 as 0.5*||u01^u02||/A_triEqui
+  // and gradients w.r.t. x0, y0, z0, x1, y1, z1, x2, y2, z2
+  fullVector<double> res0(10);
+  triAreaAndGrad(fact, vg01, vg02, res0);
+  res(0, 0) = res0(0); res(0, 1) = res0(1); res(0, 2) = res0(2);
+  res(0, 3) = res0(3); res(0, 4) = res0(4); res(0, 5) = res0(5);
+  res(0, 6) = res0(6); res(0, 7) = res0(7); res(0, 8) = res0(8);
+  res(0, 9) = res0(9);
+
+  // Compute NCJ at vertex 1 as 0.5*||u12^u10||/A_triEqui
+  // and gradients w.r.t. x1, y1, z1, x2, y2, z2, x0, y0, z0
+  fullVector<double> res1(10);
+  triAreaAndGrad(fact, vg12, vg10, res1);
+  res(1, 0) = res1(6); res(1, 1) = res1(7); res(1, 2) = res1(8);
+  res(1, 3) = res1(0); res(1, 4) = res1(1); res(1, 5) = res1(2);
+  res(1, 6) = res1(3); res(1, 7) = res1(4); res(1, 8) = res1(5);
+  res(1, 9) = res1(9);
+
+  // Compute NCJ at vertex 2 as 0.5*||u20^u21||/A_triEqui
+  // Compute NCJ at vertex 2 and gradients w.r.t. x2, y2, z2, x0, y0, z0, x1, y1, z1
+  fullVector<double> res2(10);
+  triAreaAndGrad(fact, vg20, vg21, res2);
+  res(2, 0) = res2(3); res(2, 1) = res2(4); res(2, 2) = res2(5);
+  res(2, 3) = res2(6); res(2, 4) = res2(7); res(2, 5) = res2(8);
+  res(2, 6) = res2(0); res(2, 7) = res2(1); res(2, 8) = res2(2);
+  res(2, 9) = res2(9);
+}
+
+
+void measuresQuadrangle::getNCJ(const double &x0, const double &y0, const double &z0,
+                                const double &x1, const double &y1, const double &z1,
+                                const double &x2, const double &y2, const double &z2,
+                                const double &x3, const double &y3, const double &z3,
+                                fullVector<double> &ncj)
+{
+  // Compute unit vectors for each edge
+  double x01n, y01n, z01n, x12n, y12n, z12n, x23n, y23n, z23n, x30n, y30n, z30n;
+  unitVec(x0, y0, z0, x1, y1, z1, x01n, y01n, z01n);
+  unitVec(x1, y1, z1, x2, y2, z2, x12n, y12n, z12n);
+  unitVec(x2, y2, z2, x3, y3, z3, x23n, y23n, z23n);
+  unitVec(x3, y3, z3, x0, y0, z0, x30n, y30n, z30n);
+
+  // Compute NCJ at vertex from unit vectors a and b as 0.5*||a^b||/A_triRect
+  // Factor = 1. = 0.5/A_triRect
+  static const double fact = 1.;
+  ncj(0) = triArea(fact, x01n, y01n, z01n, -x30n, -y30n, -z30n);
+  ncj(1) = triArea(fact, x12n, y12n, z12n, -x01n, -y01n, -z01n);
+  ncj(2) = triArea(fact, x23n, y23n, z23n, -x12n, -y12n, -z12n);
+  ncj(3) = triArea(fact, x30n, y30n, z30n, -x23n, -y23n, -z23n);
+}
+
+
+void measuresQuadrangle::getNCJAndGradients(const double &x0, const double &y0, const double &z0,
+                                            const double &x1, const double &y1, const double &z1,
+                                            const double &x2, const double &y2, const double &z2,
+                                            const double &x3, const double &y3, const double &z3,
+                                            fullMatrix<double> &res)
+{
+  // Factor = 1. = 0.5/A_triRect
+  static const double fact = 1.;
+
+  // Compute unit vector and its gradients for each edge
+  fullMatrix<double> vg01(3,7);
+  unitVecAndGrad(x0, y0, z0, x1, y1, z1, vg01);
+  fullMatrix<double> vg12(3,7);
+  unitVecAndGrad(x1, y1, z1, x2, y2, z2, vg12);
+  fullMatrix<double> vg23(3,7);
+  unitVecAndGrad(x2, y2, z2, x3, y3, z3, vg23);
+  fullMatrix<double> vg30(3,7);
+  unitVecAndGrad(x3, y3, z3, x0, y0, z0, vg30);
+  fullMatrix<double> vg10(3,7);
+  revertVG(vg01, vg10);
+  fullMatrix<double> vg21(3,7);
+  revertVG(vg12, vg21);
+  fullMatrix<double> vg32(3,7);
+  revertVG(vg23, vg32);
+  fullMatrix<double> vg03(3,7);
+  revertVG(vg30, vg03);
+
+  // Compute NCJ at vertex 0 as 0.5*||u01^u03||/A_triRect
+  // and gradients w.r.t. x0, y0, z0, x1, y1, z1, x3, y3, z3
+  fullVector<double> res0(10);
+  triAreaAndGrad(fact, vg01, vg03, res0);
+  res(0, 0) = res0(0); res(0, 1) =  res0(1); res(0, 2) =  res0(2);
+  res(0, 3) = res0(3); res(0, 4) =  res0(4); res(0, 5) =  res0(5);
+  res(0, 6) =      0.; res(0, 7) =       0.; res(0, 8) =       0.;
+  res(0, 9) = res0(6); res(0, 10) = res0(7); res(0, 11) = res0(8);
+  res(0, 12) = res0(9);
+
+  // Compute NCJ at vertex 1 as 0.5*||u12^u10||/A_triRect
+  // and gradients w.r.t. x1, y1, z1, x2, y2, z2, x0, y0, z0
+  fullVector<double> res1(10);
+  triAreaAndGrad(fact, vg12, vg10, res1);
+  res(1, 0) = res1(6); res(1, 1) = res1(7); res(1, 2) = res1(8);
+  res(1, 3) = res1(0); res(1, 4) = res1(1); res(1, 5) = res1(2);
+  res(1, 6) = res1(3); res(1, 7) = res1(4); res(1, 8) = res1(5);
+  res(1, 9) =      0.; res(1, 10) =     0.; res(1, 11) =     0.;
+  res(1, 12) = res1(9);
+
+  // Compute NCJ at vertex 2 as 0.5*||u23^u21||/A_triRect
+  // and gradients w.r.t. x2, y2, z2, x3, y3, z3, x1, y1, z1
+  fullVector<double> res2(10);
+  triAreaAndGrad(fact, vg23, vg21, res2);
+  res(2, 0) =      0.; res(2, 1) =       0.; res(2, 2) =       0.;
+  res(2, 3) = res2(6); res(2, 4) =  res2(7); res(2, 5) =  res2(8);
+  res(2, 6) = res2(0); res(2, 7) =  res2(1); res(2, 8) =  res2(2);
+  res(2, 9) = res2(3); res(2, 10) = res2(4); res(2, 11) = res2(5);
+  res(2, 12) = res2(9);
+
+  // Compute NCJ at vertex 3 as 0.5*||u30^u32||/A_triRect
+  // and gradients w.r.t. x3, y3, z3, x0, y0, z0, x2, y2, z2
+  fullVector<double> res3(10);
+  triAreaAndGrad(fact, vg23, vg21, res3);
+  res(3, 0) = res3(3); res(3, 1) =  res3(4); res(3, 2) =  res3(5);
+  res(3, 3) =      0.; res(3, 4) =       0.; res(3, 5) =       0.;
+  res(3, 6) = res3(6); res(3, 7) =  res3(7); res(3, 8) =  res3(8);
+  res(3, 9) = res3(0); res(3, 10) = res3(1); res(3, 11) = res3(2);
+  res(3, 12) = res3(9);
+}
diff --git a/Mesh/qualityMeasures.h b/Mesh/qualityMeasures.h
index f2fc96876ea6e9eeb920de66f8ca641a2916bd35..9637e25057be7394216ffcd0831dbad0a4c78689 100644
--- a/Mesh/qualityMeasures.h
+++ b/Mesh/qualityMeasures.h
@@ -6,6 +6,8 @@
 #ifndef _QUALITY_MEASURES_H_
 #define _QUALITY_MEASURES_H_
 
+#include "fullMatrix.h"
+
 class BDS_Point;
 class BDS_Face;
 class MVertex;
@@ -41,4 +43,32 @@ double qmTet(const double &x1, const double &y1, const double &z1,
              const double &x4, const double &y4, const double &z4, 
              const qualityMeasure4Tet &cr, double *volume = 0);
 
+class measuresTriangle
+{
+public:
+  static void getNCJ(const double &x0, const double &y0, const double &z0,
+                     const double &x1, const double &y1, const double &z1,
+                     const double &x2, const double &y2, const double &z2,
+                     fullVector<double> &ncj);
+  static void getNCJAndGradients(const double &x0, const double &y0, const double &z0,
+                                 const double &x1, const double &y1, const double &z1,
+                                 const double &x2, const double &y2, const double &z2,
+                                 fullMatrix<double> &ncj);
+};
+
+class measuresQuadrangle
+{
+public:
+  static void getNCJ(const double &x0, const double &y0, const double &z0,
+                     const double &x1, const double &y1, const double &z1,
+                     const double &x2, const double &y2, const double &z2,
+                     const double &x3, const double &y3, const double &z3,
+                     fullVector<double> &ncj);
+  static void getNCJAndGradients(const double &x0, const double &y0, const double &z0,
+                                 const double &x1, const double &y1, const double &z1,
+                                 const double &x2, const double &y2, const double &z2,
+                                 const double &x3, const double &y3, const double &z3,
+                                 fullMatrix<double> &ncj);
+};
+
 #endif