diff --git a/CMakeLists.txt b/CMakeLists.txt
index cb478406c11f61f9d6a1cb0d78591d908c9da4a9..ff4521c23cbe464a9306a9858cb313a46cf4dccd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -154,8 +154,10 @@ set(GMSH_API
   contrib/MeshOptimizer/MeshOptPatch.h contrib/MeshOptimizer/MeshOpt.h
   contrib/MeshOptimizer/MeshOptCommon.h contrib/MeshOptimizer/MeshOptimizer.h
   contrib/MeshOptimizer/MeshOptObjContribFunc.h contrib/MeshOptimizer/MeshOptObjContrib.h
+  contrib/MeshOptimizer/MeshOptObjContribScaledNodeDispSq.h
   contrib/MeshOptimizer/MeshOptObjectiveFunction.h contrib/MeshOptimizer/MeshOptVertexCoord.h 
-  contrib/MeshQualityOptimizer/MeshQualityObjContribNCJ.h
+  contrib/MeshQualityOptimizer/MeshQualityObjContribIdealJac.h
+  contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h
   contrib/MeshQualityOptimizer/MeshQualityOptimizer.h
   contrib/MathEx/mathex.h)
 
diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
index 94b970e882ace3609b6a80c130ee0546d4cdf2c5..0417c6ba336157cc33e970d9d8150d694b9cc3ad 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
@@ -753,12 +753,14 @@ void HighOrderMeshOptimizer(GModel *gm, OptHomParameters &p)
 #include "MeshOptimizer.h"
 
 
-struct HOPatchDefParameters : public MeshOptParameters::PatchDefParameters
+struct HOPatchDefParameters : public MeshOptPatchDef
 {
   HOPatchDefParameters(const OptHomParameters &p);
   virtual ~HOPatchDefParameters() {}
-  virtual double elBadness(MElement *el);
-  virtual double maxDistance(MElement *el);
+  virtual double elBadness(MElement *el) const;
+  virtual double maxDistance(MElement *el) const;
+  virtual int inPatch(const SPoint3 &badBary,
+                      double limDist, MElement *el) const;
 private:
   double jacMin, jacMax;
   double distanceFactor;
@@ -790,7 +792,8 @@ HOPatchDefParameters::HOPatchDefParameters(const OptHomParameters &p)
 }
 
 
-double HOPatchDefParameters::elBadness(MElement *el) {
+double HOPatchDefParameters::elBadness(MElement *el) const
+{
   double jmin, jmax;
   el->scaledJacRange(jmin, jmax);
   double badness = std::min(jmin-jacMin, 0.) + std::min(jacMax-jmax, 0.);
@@ -802,11 +805,19 @@ double HOPatchDefParameters::elBadness(MElement *el) {
 }
 
 
-double HOPatchDefParameters::maxDistance(MElement *el) {
+double HOPatchDefParameters::maxDistance(MElement *el) const
+{
   return distanceFactor * el->maxDistToStraight();
 }
 
 
+int HOPatchDefParameters::inPatch(const SPoint3 &badBary,
+                                  double limDist, MElement *el) const
+{
+  return testElInDist(badBary, limDist, el) ? 1 : 0;
+}
+
+
 void HighOrderMeshOptimizerNew(GModel *gm, OptHomParameters &p)
 {
   Msg::StatusBar(true, "Optimizing high order mesh...");
@@ -820,7 +831,8 @@ void HighOrderMeshOptimizerNew(GModel *gm, OptHomParameters &p)
   par.optDisplay = 30;
   par.verbose = 4;
 
-  ObjContribScaledNodeDispSq<ObjContribFuncSimple> nodeDistFunc(p.weightFixed, p.weightFree);
+  ObjContribScaledNodeDispSq<ObjContribFuncSimple> nodeDistFunc(p.weightFixed, p.weightFree,
+                                                                Patch::LS_MAXNODEDIST);
   ObjContribScaledJac<ObjContribFuncBarrierMovMin> minJacBarFunc(1.);
   minJacBarFunc.setTarget(p.BARRIER_MIN, 1.);
   ObjContribScaledJac<ObjContribFuncBarrierFixMinMovMax> minMaxJacBarFunc(1.);
@@ -828,7 +840,7 @@ void HighOrderMeshOptimizerNew(GModel *gm, OptHomParameters &p)
   ObjContribCADDist<ObjContribFuncSimpleTargetMax> CADDistFunc(p.optCADWeight, p.discrTolerance);
   CADDistFunc.setTarget(p.optCADDistMax);
 
-  MeshOptParameters::PassParameters minJacPass;
+  MeshOptPass minJacPass;
   minJacPass.barrierIterMax = p.optPassMax;
   minJacPass.optIterMax = p.itMax;
   minJacPass.contrib.push_back(&nodeDistFunc);
@@ -837,7 +849,7 @@ void HighOrderMeshOptimizerNew(GModel *gm, OptHomParameters &p)
   par.pass.push_back(minJacPass);
 
   if (p.BARRIER_MAX > 0.) {
-    MeshOptParameters::PassParameters minMaxJacPass;
+    MeshOptPass minMaxJacPass;
     minMaxJacPass.barrierIterMax = p.optPassMax;
     minMaxJacPass.optIterMax = p.itMax;
     minMaxJacPass.contrib.push_back(&nodeDistFunc);
diff --git a/contrib/MeshOptimizer/CMakeLists.txt b/contrib/MeshOptimizer/CMakeLists.txt
index 525303ecd0a77e2f925e492e83c36a9f38cfa5db..1cee09e2ed669fee3713f2644b0c665c5aded625 100644
--- a/contrib/MeshOptimizer/CMakeLists.txt
+++ b/contrib/MeshOptimizer/CMakeLists.txt
@@ -5,6 +5,7 @@
 
 set(SRC
   MeshOpt.cpp
+  MeshOptCommon.cpp
   MeshOptimizer.cpp
   MeshOptPatch.cpp
   MeshOptObjectiveFunction.cpp
diff --git a/contrib/MeshOptimizer/MeshOptCommon.cpp b/contrib/MeshOptimizer/MeshOptCommon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d32a9528fb6e99e92d3822755f843c505256b598
--- /dev/null
+++ b/contrib/MeshOptimizer/MeshOptCommon.cpp
@@ -0,0 +1,136 @@
+// Copyright (C) 2013 ULg-UCL
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, and/or sell copies of the
+// Software, and to permit persons to whom the Software is furnished
+// to do so, provided that the above copyright notice(s) and this
+// permission notice appear in all copies of the Software and that
+// both the above copyright notice(s) and this permission notice
+// appear in supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
+// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
+// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+// OF THIS SOFTWARE.
+//
+// Please report all bugs and problems to the public mailing list
+// <gmsh@geuz.org>.
+//
+// Contributors: Thomas Toulorge, Jonathan Lambrechts
+
+#include "MElement.h"
+#include "MeshOptCommon.h"
+
+
+namespace {
+
+
+// Test intersection between sphere and segment
+bool testSegSphereIntersect(SPoint3 A, SPoint3 B, const SPoint3& P, const double rr)
+{
+  // Test if separating plane between sphere and segment vertices
+  // For each vertex, separation if vertex is outside sphere and P on opposite side
+  // to other seg. vertex w.r.t plane of normal (vertex-P) through vertex
+  const SVector3 PA(P, A), PB(P, B);
+  const double aa = dot(PA, PA), ab = dot(PA, PB);
+  if ((aa > rr) & (ab > aa)) return false;
+  const double  bb = dot(PB, PB);
+  if ((bb > rr) & (ab > bb)) return false;
+
+  // Test if separating plane between sphere and line
+  // For A, separation if projection Q of P on (AB) lies outside the sphere
+  const SVector3 AB(A, B);
+  const double d = ab - aa, e = dot(AB, AB);
+  const  SVector3 PQ = PA * e - d * AB;
+  if (dot(PQ, PQ) > rr * e * e) return false;
+
+  // Return true (intersection) if no separation at all
+  return true;
+}
+
+
+// Test intersection between sphere and triangle
+// Inspired by Christer Ericson, http://realtimecollisiondetection.net/blog/?p=103
+bool testTriSphereIntersect(SPoint3 A, SPoint3 B, SPoint3 C, const SPoint3& P, const double rr)
+{
+  // Test if separating plane between sphere and triangle plane
+  const SVector3 PA(P, A), AB(A, B), AC(A, C);
+  const SVector3 V = crossprod(AB, AC);                               // Normal to triangle plane
+  const double d = dot(PA, V);                                         // Dist. from P to triangle plane times norm of V
+  const double e = dot(V, V);                                         // Norm of V
+  if (d * d > rr * e) return false;                                   // Test if separating plane between sphere and triangle plane
+
+  // Test if separating plane between sphere and triangle vertices
+  const SVector3 PB(P, B), PC(P, B);
+  const double aa = dot(PA, PA), ab = dot(PA, PB), ac = dot(PA, PC);
+  const double bb = dot(PB, PB), bc = dot(PB, PC), cc = dot(PC, PC);
+  if ((aa > rr) & (ab > aa) & (ac > aa)) return false;                    // For each triangle vertex, separation if vertex is outside sphere
+  if ((bb > rr) & (ab > bb) & (bc > bb)) return false;                    // and P on opposite side to other two triangle vertices w.r.t
+  if ((cc > rr) & (ac > cc) & (bc > cc)) return false;                    // plane of normal (vertex-P) through vertex
+
+  // Test if separating plane between sphere and triangle edges
+  const SVector3 BC(B, C);
+  const double d1 = ab - aa, d2 = bc - bb, d3 = ac - cc;
+  const double e1 = dot(AB, AB), e2 = dot(BC, BC), e3 = dot(AC, AC);
+  const  SVector3 PQ1 = PA * e1 - d1 * AB;                                // Q1 projection of P on line (AB)
+  const  SVector3 PQ2 = PB * e2 - d2 * BC;                                // Q2 projection of P on line (BC)
+  const  SVector3 PQ3 = PC * e3 + d3 * AC;                                // Q3 projection of P on line (AC)
+  const  SVector3 PQC = PC * e1 - PQ1;
+  const  SVector3 PQA = PA * e2 - PQ2;
+  const  SVector3 PQB = PB * e3 - PQ3;
+  if ((dot(PQ1, PQ1) > rr * e1 * e1) & (dot(PQ1, PQC) > 0)) return false; // For A, separation if Q lies outside the sphere and if P and C
+  if ((dot(PQ2, PQ2) > rr * e2 * e2) & (dot(PQ2, PQA) > 0)) return false; // are on opposite sides of plane through AB with normal PQ
+  if ((dot(PQ3, PQ3) > rr * e3 * e3) & (dot(PQ3, PQB) > 0)) return false; // Same for other two vertices
+
+  // Return true (intersection) if no separation at all
+  return true;
+}
+
+
+}
+
+
+// Test of intersection element with circle/sphere
+bool MeshOptPatchDef::testElInDist(const SPoint3 &P, double limDist,
+                                   MElement *el) const
+{
+  const double sampleLen = 0.5*limDist;                                   // Distance between sample points
+  const double limDistSq = limDist*limDist;
+
+  if (el->getDim() == 2) {                                                // 2D?
+    for (int iEd = 0; iEd < el->getNumEdges(); iEd++) {                   // Loop over edges of element
+      MEdge ed = el->getEdge(iEd);
+      const SPoint3 A = ed.getVertex(0)->point();
+      const SPoint3 B = ed.getVertex(1)->point();
+      if (testSegSphereIntersect(A, B, P, limDistSq)) {
+        return true;
+      }
+    }
+  }
+  else {                                                                  // 3D
+    for (int iFace = 0; iFace < el->getNumFaces(); iFace++) {             // Loop over faces of element
+      MFace face = el->getFace(iFace);
+      const SPoint3 A = face.getVertex(0)->point();
+      const SPoint3 B = face.getVertex(1)->point();
+      const SPoint3 C = face.getVertex(2)->point();
+      if (face.getNumVertices() == 3)
+        return testTriSphereIntersect(A, B, C, P, limDistSq);
+      else {
+        const SPoint3 D = face.getVertex(3)->point();
+        return (testTriSphereIntersect(A, B, C, P, limDistSq) ||
+                    testTriSphereIntersect(A, C, D, P, limDistSq));
+      }
+    }
+  }
+
+  return false;
+}
diff --git a/contrib/MeshOptimizer/MeshOptCommon.h b/contrib/MeshOptimizer/MeshOptCommon.h
index 9f895e84f9c5ede16ae4f6847aa42dbcae194a1e..189c7689d5030a4d4c009f794c3ebe208a2ebfce 100644
--- a/contrib/MeshOptimizer/MeshOptCommon.h
+++ b/contrib/MeshOptimizer/MeshOptCommon.h
@@ -34,35 +34,48 @@
 
 
 class MElement;
+class SPoint3;
 class ObjContrib;
 
 
-struct MeshOptParameters {                             // Parameters controlling the strategy
-  enum { STRAT_CONNECTED, STRAT_ONEBYONE };
-  struct PassParameters {                              // Parameters controlling the optimization procedure in each pass
-    std::vector<ObjContrib*> contrib;                  // Indices of contributions to objective function
-    int optIterMax;                                    // Max. number of opt. iterations each time the barrier is moved
-    int barrierIterMax;                                // Max. number of times the barrier is moved
-  };
-  struct PatchDefParameters {
-    int strategy;                                      // Strategy: connected patches or adaptive one-by-one
-    int minLayers, maxLayers;                          // Min. and max. nb. of layers around a bad element in patch
-    union {
-      struct {                                         // If adaptive strategy:
-        int maxAdaptPatch;                             // Max. nb. of adaptation iterations
-        int maxLayersAdaptFact;                        // Growth rate in number of layers around a bad element
-        double distanceAdaptFact;                      // Growth rate in max. distance from bad element
-      };
-      bool weakMerge;                                   // If connected strategy: weak or strong merging of patches
+class MeshOptPatchDef {
+public:
+  int strategy;                                         // Strategy: connected patches or adaptive one-by-one
+  int minLayers, maxLayers;                             // Min. and max. nb. of layers around a bad element in patch
+  union {
+    struct {                                            // If adaptive strategy:
+      int maxAdaptPatch;                                // Max. nb. of adaptation iterations
+      int maxLayersAdaptFact;                           // Growth rate in number of layers around a bad element
+      double distanceAdaptFact;                         // Growth rate in max. distance from bad element
     };
-    virtual double elBadness(MElement *el) = 0;         // Pointer to function returning "badness" of element (for patch creation)
-    virtual double maxDistance(MElement *el) = 0; // Pointer to function checking the patch distance criterion for a given bad element
+    bool weakMerge;                                     // If connected strategy: weak or strong merging of patches
   };
+  virtual ~MeshOptPatchDef() {}
+  virtual double elBadness(MElement *el) const = 0;     // Determine "badness" of a given element (for patch creation)
+  virtual double maxDistance(MElement *el) const = 0;   // Compute max. distance to a given bad element for elements in patch
+  virtual int inPatch(const SPoint3 &badBary,           // Determine whether a given element should be included in the patch around a...
+                      double limDist,                   // ... given bad element barycenter, with a limit distance if needed. Output: ...
+                      MElement *el) const = 0;          // ... -1 = excluded, 0 = included only up to minLayers, 1 = included up to maxLayers
+protected:
+  bool testElInDist(const SPoint3 &P, double limDist,   // Test whether an element is within a certain distance from a point
+                    MElement *el) const;
+};
+
+
+struct MeshOptPass {                                    // Parameters controlling the optimization procedure in each pass
+  std::vector<ObjContrib*> contrib;                     // Indices of contributions to objective function
+  int optIterMax;                                       // Max. number of opt. iterations each time the barrier is moved
+  int barrierIterMax;                                   // Max. number of times the barrier is moved
+};
+
+
+struct MeshOptParameters {                              // Parameters controlling the strategy
+  enum { STRAT_CONNECTED, STRAT_ONEBYONE };
   int dim ;                                             // Which dimension to optimize
   bool onlyVisible ;                                    // Apply optimization to visible entities ONLY
   bool fixBndNodes;                                     // If points can move on boundaries
-  PatchDefParameters *patchDef;
-  std::vector<PassParameters> pass;
+  MeshOptPatchDef *patchDef;
+  std::vector<MeshOptPass> pass;
   int optDisplay;                                       // Sampling rate in opt. iterations for display
   int verbose;                                          // Level of information displayed and written to disk
   int success;                                          // Success flag: -1 = fail, 0 = partial fail (target not reached), 1 = success
diff --git a/contrib/MeshOptimizer/MeshOptObjContribFunc.cpp b/contrib/MeshOptimizer/MeshOptObjContribFunc.cpp
index 8be99a8567af2d97a16df53205f7f2fc493edd44..cd5757325c612de14504b348183341504b061d07 100644
--- a/contrib/MeshOptimizer/MeshOptObjContribFunc.cpp
+++ b/contrib/MeshOptimizer/MeshOptObjContribFunc.cpp
@@ -1,6 +1,7 @@
 // TODO: Copyright
 
 #include <cmath>
+#include "GmshMessage.h"
 #include "MeshOptObjContribFunc.h"
 
 
@@ -31,28 +32,37 @@ bool ObjContribFuncSimpleTargetMax::stagnated(double vMin, double vMax)
 }
 
 
-const double ObjContribFuncBarrier::LOWMARGINMULT = 0.9;
-const double ObjContribFuncBarrier::UPMARGINMULT = 1.1;
+const double ObjContribFuncBarrier::MARGINCOEFF = 0.1;
 const double ObjContribFuncBarrier::STAGTHRESHOLD = 0.01;
 
 
 ObjContribFuncBarrier::ObjContribFuncBarrier() :
-    _target(0.), _barrier(0.), _init(0.), _opt(0.)
+    _target(0.), _barrier(0.), _init(0.), _opt(0.), _defaultMargin(0.)
 {
 }
 
 
-void ObjContribFuncBarrier::setTarget(double target, double opt)
+void ObjContribFuncBarrier::setTarget(double target, double opt, double defaultMargin)
 {
   _target = target;
   _opt = opt;
+  _defaultMargin = defaultMargin;
+  if (_defaultMargin == 0.) {
+    if (opt != 0.)
+      _defaultMargin = MARGINCOEFF*fabs(opt);
+    else if (target != 0.)
+      _defaultMargin = MARGINCOEFF*fabs(target);
+    else
+      Msg::Warning("Could not find value to define a scale for default barrier margin");
+  }
 }
 
 
 void ObjContribFuncBarrierMovMin::updateParameters(double vMin, double vMax)
 {
   _init = vMin;
-  _barrier = vMin > 0. ? LOWMARGINMULT*vMin : UPMARGINMULT*vMin;
+  const double margin = (vMin == 0.) ? _defaultMargin : MARGINCOEFF*fabs(vMin);
+  _barrier = vMin - margin;
 }
 
 
@@ -65,7 +75,8 @@ bool ObjContribFuncBarrierMovMin::stagnated(double vMin, double vMax)
 void ObjContribFuncBarrierMovMax::updateParameters(double vMin, double vMax)
 {
   _init = vMax;
-  _barrier = vMax > 0. ? UPMARGINMULT*vMax : LOWMARGINMULT*vMax;
+  const double margin = (vMax == 0.) ? _defaultMargin : MARGINCOEFF*fabs(vMax);
+  _barrier = vMax + margin;
 }
 
 
@@ -78,5 +89,6 @@ bool ObjContribFuncBarrierMovMax::stagnated(double vMin, double vMax)
 void ObjContribFuncBarrierFixMinMovMax::initialize(double vMin, double vMax)
 {
   ObjContribFuncBarrierMovMax::initialize(vMin, vMax);
-  _fixedMinBarrier = vMin > 0. ? LOWMARGINMULT*vMin : UPMARGINMULT*vMin;
+  const double margin = (vMin == 0.) ? _defaultMargin : MARGINCOEFF*fabs(vMin);
+  _fixedMinBarrier = vMin - margin;
 }
diff --git a/contrib/MeshOptimizer/MeshOptObjContribFunc.h b/contrib/MeshOptimizer/MeshOptObjContribFunc.h
index 04c7aef64f5185f541b09f629c2aba6c60153188..ec12b3fde04ff8bf572bb51e208c19364f541c0f 100644
--- a/contrib/MeshOptimizer/MeshOptObjContribFunc.h
+++ b/contrib/MeshOptimizer/MeshOptObjContribFunc.h
@@ -38,13 +38,16 @@ class ObjContribFuncBarrier
 {
 public:
   ObjContribFuncBarrier();
-  void setTarget(double target, double opt=1.);
+  void setTarget(double target, double opt=1.,
+                 double defaultMargin=0.);
 
 protected:
-  static const double LOWMARGINMULT, UPMARGINMULT;                                // Upper and lower margins w.r.t. min. & max. to set barrier
+  static const double MARGINCOEFF;                                                // Margin coefficient w.r.t. min. & max. to set barrier
   static const double STAGTHRESHOLD;                                              // Threshold to consider that measures stagnates
   double _opt;                                                                    // Optimal value of measure in barrier function
-  double _barrier, _target, _init;                                                // Current barrier, target and initial values of min./max. of measure
+  double _defaultMargin;                                                          // Default margin value to set barrier w.r.t. of min./max. of measure
+  double _barrier, _target;                                                       // Current barrier and target of min./max. of measure
+  double _init;                                                                   // Initial value of min./max. of measure
   static double logBarrier(double v, double barrier, double opt);
   static double diffLogBarrier(double v, double barrier, double opt);
 };
diff --git a/contrib/MeshOptimizer/MeshOptObjContribScaledNodeDispSq.h b/contrib/MeshOptimizer/MeshOptObjContribScaledNodeDispSq.h
index 070d744447e3df5d5f24a871a6d109aea12ac8af..6aa3c7ec05f6caacf82e4975732f073dcd2ea2f3 100644
--- a/contrib/MeshOptimizer/MeshOptObjContribScaledNodeDispSq.h
+++ b/contrib/MeshOptimizer/MeshOptObjContribScaledNodeDispSq.h
@@ -11,7 +11,8 @@ template<class FuncType>
 class ObjContribScaledNodeDispSq : public ObjContrib, public FuncType
 {
 public:
-  ObjContribScaledNodeDispSq(double weightFixed, double weightFree);
+  ObjContribScaledNodeDispSq(double weightFixed, double weightFree,
+                             Patch::LengthScaling scaling);
   virtual ~ObjContribScaledNodeDispSq() {}
   virtual ObjContrib *copy() const;
   virtual void initialize(Patch *mesh);
@@ -25,15 +26,16 @@ public:
 protected:
   Patch *_mesh;
   double _weightFixed, _weightFree;
-
+  Patch::LengthScaling _scaling;
 };
 
 
 template<class FuncType>
 ObjContribScaledNodeDispSq<FuncType>::ObjContribScaledNodeDispSq(double weightFixed,
-                                                                    double weightFree) :
+                                                                 double weightFree,
+                                                                 Patch::LengthScaling scaling) :
   ObjContrib("ScaledNodeDispSq", FuncType::getNamePrefix()+"ScaledNodeDispSq"),
-  _mesh(0), _weightFixed(weightFixed), _weightFree(weightFree)
+  _mesh(0), _weightFixed(weightFixed), _weightFree(weightFree), _scaling(scaling)
 {
 }
 
@@ -49,7 +51,7 @@ template<class FuncType>
 void ObjContribScaledNodeDispSq<FuncType>::initialize(Patch *mesh)
 {
   _mesh = mesh;
-  _mesh->initScaledNodeDispSq();
+  _mesh->initScaledNodeDispSq(_scaling);
   updateMinMax();
   FuncType::initialize(_min, _max);
 }
diff --git a/contrib/MeshOptimizer/MeshOptPatch.cpp b/contrib/MeshOptimizer/MeshOptPatch.cpp
index c4f71eb0620b6abce8c24e29c8b36c2683e52430..0debf3111a64cd336ddb187dd8e0060f04a80bee 100644
--- a/contrib/MeshOptimizer/MeshOptPatch.cpp
+++ b/contrib/MeshOptimizer/MeshOptPatch.cpp
@@ -41,7 +41,8 @@
 
 Patch::Patch(const std::map<MElement*,GEntity*> &element2entity,
            const std::set<MElement*> &els, std::set<MVertex*> &toFix,
-           bool fixBndNodes)
+           bool fixBndNodes) :
+  _typeLengthScale(LS_NONE), _invLengthScaleSq(0.)
 {
 
   _dim = (*els.begin())->getDim();
@@ -212,24 +213,36 @@ void Patch::writeMSH(const char *filename)
   fclose(f);
 }
 
-// TODO: allow user to choose type of scaling length
-void Patch::initScaledNodeDispSq()
+
+void Patch::initScaledNodeDispSq(LengthScaling scaling)
 {
-  if (_invLengthScaleSq == 0.) {
+  if ((_invLengthScaleSq == 0.) || _typeLengthScale != scaling) {
+    _typeLengthScale = scaling;
     double maxDSq = 0.;
-    for (int iEl = 0; iEl < nEl(); iEl++) {
-      const double d = el(iEl)->maxDistToStraight(), dd = d*d;
-      if (dd > maxDSq) maxDSq = dd;
-    }
-    if (maxDSq < 1.e-10) {
-      double maxSSq = 0.;
-      for (int iEl = 0; iEl < nEl(); iEl++) {
-        const double s = el(iEl)->getOuterRadius(), ss = s*s;
-        if (ss > maxSSq) maxSSq = ss;
+    switch(scaling) {
+      case LS_MAXNODEDIST : {
+        for (int iEl = 0; iEl < nEl(); iEl++) {
+          const double d = el(iEl)->maxDistToStraight(), dd = d*d;
+          if (dd > maxDSq) maxDSq = dd;
+        }
+        break;
+      }
+      case LS_MAXOUTERRADIUS : {
+        for (int iEl = 0; iEl < nEl(); iEl++) {
+          const double d = el(iEl)->getOuterRadius(), dd = d*d;
+          if (dd > maxDSq) maxDSq = dd;
+        }
+        break;
+      }
+      case LS_MINEDGELENGTH : {
+        for (int iEl = 0; iEl < nEl(); iEl++) {
+          const double d = el(iEl)->minEdge(), dd = d*d;
+          if (dd > maxDSq) maxDSq = dd;
+        }
+        break;
       }
-      _invLengthScaleSq = 1./maxSSq;
     }
-    else _invLengthScaleSq = 1./maxDSq;
+    _invLengthScaleSq = 1./maxDSq;
   }
 }
 
@@ -266,13 +279,14 @@ void Patch::initScaledJac()
 
   // Set normals to 2D elements (with magnitude of inverse Jacobian) or initial
   // Jacobians of 3D elements
-  if ((_dim == 2) && _scaledNormEl.empty()) {
-    _scaledNormEl.resize(nEl());
+  if ((_dim == 2) && _JacNormEl.empty()) {
+    _JacNormEl.resize(nEl());
 //    for (int iEl = 0; iEl < nEl(); iEl++) calcScaledNormalEl2D(element2entity,iEl);
-    for (int iEl = 0; iEl < nEl(); iEl++) calcNormalEl2D(iEl, NS_INVNORM);
+    for (int iEl = 0; iEl < nEl(); iEl++)
+      calcNormalEl2D(iEl, NS_INVNORM, _JacNormEl[iEl], false);
   }
   else if (_invStraightJac.empty()) {
-    _invStraightJac.resize(nEl(),1.);
+    _invStraightJac.resize(nEl(), 1.);
     double dumJac[3][3];
     for (int iEl = 0; iEl < nEl(); iEl++)
       _invStraightJac[iEl] = 1. / fabs(_el[iEl]->getPrimaryJacobian(0.,0.,0.,dumJac));
@@ -293,7 +307,8 @@ void Patch::initMetricMin()
 
 // TODO: Re-introduce normal to geometry?
 //void Mesh::calcScaledNormalEl2D(const std::map<MElement*,GEntity*> &element2entity, int iEl)
-void Patch::calcNormalEl2D(int iEl, NORMALSCALING scaling)
+void Patch::calcNormalEl2D(int iEl, NormalScaling scaling,
+                           fullMatrix<double> &elNorm, bool ideal)
 {
   const JacobianBasis *jac = _el[iEl]->getJacobianFuncSpace();
 
@@ -319,21 +334,25 @@ void Patch::calcNormalEl2D(int iEl, NORMALSCALING scaling)
 //    geoNorm = ((GFace*)ge)->normal(param);
 //  }
 
-  fullMatrix<double> uElNorm(1, 3);
-  fullMatrix<double> &elNorm = (scaling == NS_INVNORM) ? _scaledNormEl[iEl] :
-                                ((scaling == NS_UNIT) ? uElNorm : _metricNormEl[iEl]);
   elNorm.resize(1, 3);
-  const double norm = jac->getPrimNormal2D(primNodesXYZ, elNorm);
-  if (scaling != 0) {
-    double factor = (scaling == NS_SQRTNORM) ? 1./norm : sqrt(norm);
-//    if (hasGeoNorm) {
-//      const double scal = geoNorm(0)*elNorm(0,0)+geoNorm(1)*elNorm(0,1)+geoNorm(2)*elNorm(0,2);
-//      if (scal < 0.) factor = -factor;
-//    }
-    elNorm.scale(factor);   // Re-scaling normal here is faster than an extra scaling operation on the Jacobian
-  }
-  else
-    _unitNormEl[iEl] = SVector3(uElNorm(0, 0), uElNorm(0, 1), uElNorm(0, 2));
+  const double norm = jac->getPrimNormal2D(primNodesXYZ, elNorm, ideal);
+  double factor;
+  switch (scaling) {
+    case NS_UNIT:
+      factor = 1.;
+      break;
+    case NS_INVNORM:
+      factor = 1./norm;
+      break;
+    case NS_SQRTNORM:
+      factor = sqrt(norm);
+      break;
+  }
+//  if (hasGeoNorm) {
+//    const double scal = geoNorm(0)*elNorm(0,0)+geoNorm(1)*elNorm(0,1)+geoNorm(2)*elNorm(0,2);
+//    if (scal < 0.) factor = -factor;
+//  }
+  elNorm.scale(factor);   // Re-scaling normal here is faster than an extra scaling operation on the Jacobian
 }
 
 
@@ -356,7 +375,7 @@ void Patch::scaledJacAndGradients(int iEl, std::vector<double> &sJ,
 
   // Calculate Jacobian and gradients, scale if 3D (already scaled by
   // regularization normals in 2D)
-  jacBasis->getSignedJacAndGradients(nodesXYZ,_scaledNormEl[iEl],JDJ);
+  jacBasis->getSignedJacAndGradients(nodesXYZ,_JacNormEl[iEl],JDJ);
   if (_dim == 3) JDJ.scale(_invStraightJac[iEl]);
 
   // Transform Jacobian and gradients from Lagrangian to Bezier basis
@@ -504,89 +523,90 @@ bool Patch::bndDistAndGradients(int iEl, double &f, std::vector<double> &gradF,
 }
 
 
-void Patch::initNCJ()
+void Patch::initIdealJac()
 {
   // Initialize _nBezEl
-  if (_nNCJEl.empty()) {
-    _nNCJEl.resize(nEl());
+  if (_nIJacEl.empty()) {
+    _nIJacEl.resize(nEl());
     for (int iEl=0; iEl<nEl(); iEl++)
-      switch(_el[iEl]->getType()) {                                             // TODO: Complete with other types?
-      case TYPE_TRI: _nNCJEl[iEl] = qmTriangle::numNCJVal(); break;
-      case TYPE_QUA: _nNCJEl[iEl] = qmQuadrangle::numNCJVal(); break;
-      }
+      _nIJacEl[iEl] = _el[iEl]->getJacobianFuncSpace()->getNumJacNodes();
   }
 
   // Set normals to 2D elements (with magnitude of inverse Jacobian) or initial
   // Jacobians of 3D elements
-  if ((_dim == 2) && _unitNormEl.empty()) {
-    _unitNormEl.resize(nEl());
+  if ((_dim == 2) && _IJacNormEl.empty()) {
+    _IJacNormEl.resize(nEl());
 //    for (int iEl = 0; iEl < nEl(); iEl++) calcScaledNormalEl2D(element2entity,iEl);
-    for (int iEl = 0; iEl < nEl(); iEl++) calcNormalEl2D(iEl, NS_UNIT);
+    for (int iEl = 0; iEl < nEl(); iEl++)
+      calcNormalEl2D(iEl, NS_INVNORM, _IJacNormEl[iEl], true);
+  }
+  else if (_invStraightJac.empty()) {
+    _invIJac.resize(nEl(), 1.);
+    for (int iEl = 0; iEl < nEl(); iEl++) {
+      int nEd = _el[iEl]->getNumEdges();
+      double sumEdLength = 0.;
+      for(int iEd = 0; iEd < nEd; iEd++)
+        sumEdLength += _el[iEl]->getEdge(iEd).length();
+      const double invMeanEdLength = double(nEd)/sumEdLength;
+      _invIJac[iEl] = invMeanEdLength*invMeanEdLength*invMeanEdLength;
+    }
   }
 }
 
 
-void Patch::NCJ(int iEl, std::vector<double> &NCJ)
+void Patch::idealJacAndGradients(int iEl, std::vector<double> &iJ, std::vector<double> &gIJ)
 {
-  const int &numNCJVal = _nNCJEl[iEl];
-  const int &numNodes = _nNodEl[iEl];
-
-  std::vector<int> &iVEl = _el2V[iEl];
-  switch(_el[iEl]->getType()) {                                                 // TODO: Complete with other types?
-  case TYPE_TRI: {
-    const int &iV0 = _el2V[iEl][0], &iV1 = _el2V[iEl][1], &iV2 = _el2V[iEl][2];
-    qmTriangle::NCJ(_xyz[iV0], _xyz[iV1], _xyz[iV2], _unitNormEl[iEl], NCJ);
-    break;
-  }
-  case TYPE_QUA: {
-    const int &iV0 = _el2V[iEl][0], &iV1 = _el2V[iEl][1],
-              &iV2 = _el2V[iEl][2], &iV3 = _el2V[iEl][3];
-    qmQuadrangle::NCJ(_xyz[iV0], _xyz[iV1], _xyz[iV2], _xyz[iV3], _unitNormEl[iEl], NCJ);
-    break;
-  }
+  const JacobianBasis *jacBasis = _el[iEl]->getJacobianFuncSpace();
+  const int &numJacNodes = _nIJacEl[iEl];
+  const int &numMapNodes = _nNodEl[iEl];
+  fullMatrix<double> JDJ(numJacNodes,3*numMapNodes+1), BDB(numJacNodes,3*numMapNodes+1);
+
+  // Coordinates of nodes
+  fullMatrix<double> nodesXYZ(numMapNodes,3), normals(_dim,3);
+  for (int i = 0; i < numMapNodes; i++) {
+    int &iVi = _el2V[iEl][i];
+    nodesXYZ(i,0) = _xyz[iVi].x();
+    nodesXYZ(i,1) = _xyz[iVi].y();
+    nodesXYZ(i,2) = _xyz[iVi].z();
   }
-}
 
+  // Calculate Jacobian and gradients, scale if 3D (already scaled by
+  // regularization normals in 2D)
+  jacBasis->getSignedIdealJacAndGradients(nodesXYZ,_IJacNormEl[iEl],JDJ);
+  if (_dim == 3) JDJ.scale(_invIJac[iEl]);
+//  if (_el[iEl]->getNum() == 90370) {
+//    std::cout << "DBGTT: bad el.: " << _el[iEl]->getNum() << "\n";
+//    for (int i = 0; i < numMapNodes; i++)
+//      std::cout << "DBGTT: {x,y,z}" << i << " = (" << nodesXYZ(i,0)
+//                << ", " << nodesXYZ(i,1) << ", " << nodesXYZ(i,2) << ")\n";
+//   for (int l = 0; l < numJacNodes; l++) {
+//      for (int i = 0; i < numMapNodes; i++)
+//        std::cout << "DBGTT: dJ" << l << "d{x,y,z}" << i << " = (" << JDJ(l, i)
+//                  << ", " << JDJ(l, i+numMapNodes) << ", " << JDJ(l, i+2*numMapNodes)<< ")\n";
+//      std::cout << "DBGTT: J" << l << " = " << JDJ(l, 3*numMapNodes)<< "\n";
+//    }
+//  }
 
-void Patch::NCJAndGradients(int iEl, std::vector<double> &NCJ, std::vector<double> &gNCJ)
-{
-  const int &numNCJVal = _nNCJEl[iEl];
-  const int &numNodes = _nNodEl[iEl];
-
-  std::vector<int> &iVEl = _el2V[iEl];
-  std::vector<double> dNCJ(numNCJVal*3*numNodes);
-  switch(_el[iEl]->getType()) {                                                 // TODO: Complete with other types?
-  case TYPE_TRI: {
-    const int &iV0 = _el2V[iEl][0], &iV1 = _el2V[iEl][1], &iV2 = _el2V[iEl][2];
-    qmTriangle::NCJAndGradients(_xyz[iV0], _xyz[iV1], _xyz[iV2],
-                                _unitNormEl[iEl], NCJ, dNCJ);
-    break;
-  }
-  case TYPE_QUA: {
-    const int &iV0 = _el2V[iEl][0], &iV1 = _el2V[iEl][1],
-              &iV2 = _el2V[iEl][2], &iV3 = _el2V[iEl][3];
-    qmQuadrangle::NCJAndGradients(_xyz[iV0], _xyz[iV1], _xyz[iV2], _xyz[iV3],
-                                  _unitNormEl[iEl], NCJ, dNCJ);
-    break;
-  }
-  }
+  // Transform Jacobian and gradients from Lagrangian to Bezier basis
+  jacBasis->lag2Bez(JDJ,BDB);
+
+  // Scaled jacobian
+  for (int l = 0; l < numJacNodes; l++) iJ [l] = BDB (l,3*numMapNodes);
 
-  // Gradients of the NCJ
+  // Gradients of the scaled jacobian
   int iPC = 0;
-  std::vector<SPoint3> gXyzV(numNCJVal);
-  std::vector<SPoint3> gUvwV(numNCJVal);
-  for (int i = 0; i < numNodes; i++) {
+  std::vector<SPoint3> gXyzV(numJacNodes);
+  std::vector<SPoint3> gUvwV(numJacNodes);
+  for (int i = 0; i < numMapNodes; i++) {
     int &iFVi = _el2FV[iEl][i];
     if (iFVi >= 0) {
-      for (int l = 0; l < numNCJVal; l++) {
-        int ind = (l*numNodes+i)*3;
-        gXyzV[l] = SPoint3(dNCJ[ind], dNCJ[ind+1], dNCJ[ind+2]);
-      }
-      _coordFV[iFVi]->gXyz2gUvw(_uvw[iFVi], gXyzV, gUvwV);
-      for (int l = 0; l < numNCJVal; l++) {
-        gNCJ[indGNCJ(iEl, l, iPC)] = gUvwV[l][0];
-        if (_nPCFV[iFVi] >= 2) gNCJ[indGNCJ(iEl, l, iPC+1)] = gUvwV[l][1];
-        if (_nPCFV[iFVi] == 3) gNCJ[indGNCJ(iEl, l, iPC+2)] = gUvwV[l][2];
+      for (int l = 0; l < numJacNodes; l++)
+        gXyzV [l] = SPoint3(BDB(l,i), BDB(l,i+numMapNodes), BDB(l,i+2*numMapNodes));
+      _coordFV[iFVi]->gXyz2gUvw(_uvw[iFVi],gXyzV,gUvwV);
+      for (int l = 0; l < numJacNodes; l++) {
+        gIJ[indGIJac(iEl,l,iPC)] = gUvwV[l][0];
+        if (_nPCFV[iFVi] >= 2) gIJ[indGIJac(iEl,l,iPC+1)] = gUvwV[l][1];
+        if (_nPCFV[iFVi] == 3) gIJ[indGIJac(iEl,l,iPC+2)] = gUvwV[l][2];
       }
       iPC += _nPCFV[iFVi];
     }
@@ -594,7 +614,7 @@ void Patch::NCJAndGradients(int iEl, std::vector<double> &NCJ, std::vector<doubl
 }
 
 
-void Patch::initInvCond()
+void Patch::initCondNum()
 {
   // Initialize _nBezEl
   if (_nBezEl.empty()) {
@@ -605,16 +625,17 @@ void Patch::initInvCond()
 
   // Set normals to 2D elements (with magnitude of inverse Jacobian) or initial
   // Jacobians of 3D elements
-  if ((_dim == 2) && _metricNormEl.empty()) {
-    _metricNormEl.resize(nEl());
+  if ((_dim == 2) && _condNormEl.empty()) {
+    _condNormEl.resize(nEl());
 //    for (int iEl = 0; iEl < nEl(); iEl++) calcScaledNormalEl2D(element2entity,iEl);
-    for (int iEl = 0; iEl < nEl(); iEl++) calcNormalEl2D(iEl, NS_SQRTNORM);
+    for (int iEl = 0; iEl < nEl(); iEl++)
+      calcNormalEl2D(iEl, NS_SQRTNORM, _condNormEl[iEl], true);
   }
 }
 
 
-void Patch::invCondAndGradients(int iEl, std::vector<double> &invCond,
-                                std::vector<double> &gInvCond)
+void Patch::condNumAndGradients(int iEl, std::vector<double> &condNum,
+                                std::vector<double> &gCondNum)
 {
   const JacobianBasis *jacBasis = _el[iEl]->getJacobianFuncSpace();
   const int &numJacNodes = _nBezEl[iEl];
@@ -632,10 +653,10 @@ void Patch::invCondAndGradients(int iEl, std::vector<double> &invCond,
 
   // Calculate Jacobian and gradients, scale if 3D (already scaled by
   // regularization normals in 2D)
-  jacBasis->getInvCondAndGradients(nodesXYZ, _metricNormEl[iEl], IDI);
+  jacBasis->getCondNumAndGradients(nodesXYZ, _condNormEl[iEl], IDI);
 
   // Inverse condition number
-  for (int l = 0; l < numJacNodes; l++) invCond[l] = IDI(l, 3*numMapNodes);
+  for (int l = 0; l < numJacNodes; l++) condNum[l] = IDI(l, 3*numMapNodes);
 
   // Gradients of the inverse condition number
   int iPC = 0;
@@ -649,9 +670,9 @@ void Patch::invCondAndGradients(int iEl, std::vector<double> &invCond,
                             IDI(l, i+2*numMapNodes));
       _coordFV[iFVi]->gXyz2gUvw(_uvw[iFVi],gXyzV,gUvwV);
       for (int l = 0; l < numJacNodes; l++) {
-        gInvCond[indGSJ(iEl,l,iPC)] = gUvwV[l][0];
-        if (_nPCFV[iFVi] >= 2) gInvCond[indGSJ(iEl,l,iPC+1)] = gUvwV[l][1];
-        if (_nPCFV[iFVi] == 3) gInvCond[indGSJ(iEl,l,iPC+2)] = gUvwV[l][2];
+        gCondNum[indGSJ(iEl,l,iPC)] = gUvwV[l][0];
+        if (_nPCFV[iFVi] >= 2) gCondNum[indGSJ(iEl,l,iPC+1)] = gUvwV[l][1];
+        if (_nPCFV[iFVi] == 3) gCondNum[indGSJ(iEl,l,iPC+2)] = gUvwV[l][2];
       }
       iPC += _nPCFV[iFVi];
     }
diff --git a/contrib/MeshOptimizer/MeshOptPatch.h b/contrib/MeshOptimizer/MeshOptPatch.h
index 4269ba833d02510802bea41b289f0f77d8f86a5b..d9b477f27770d51e26f370937b0cfb4ba3c9ef7b 100644
--- a/contrib/MeshOptimizer/MeshOptPatch.h
+++ b/contrib/MeshOptimizer/MeshOptPatch.h
@@ -78,7 +78,8 @@ public:
   void writeMSH(const char *filename);
 
   // Node distance measure
-  void initScaledNodeDispSq();
+  enum LengthScaling { LS_NONE, LS_MAXNODEDIST, LS_MAXOUTERRADIUS, LS_MINEDGELENGTH };
+  void initScaledNodeDispSq(LengthScaling scaling);
   inline double invLengthScaleSq() { return _invLengthScaleSq; }
   double scaledNodeDispSq(int iFV);
   void gradScaledNodeDispSq(int iFV, std::vector<double> &gDSq);
@@ -93,18 +94,15 @@ public:
   bool bndDistAndGradients(int iEl, double &f , std::vector<double> &gradF, double eps);
 
   // Mesh quality
-  inline const int &nNCJEl(int iEl) { return _nNCJEl[iEl]; }
-  inline int indGNCJ(int iEl, int l, int iPC) { return iPC*_nNCJEl[iEl]+l; }
-  void initNCJ();
-  void NCJ(int iEl, std::vector<double> &NCJ);
-  void NCJAndGradients(int iEl, std::vector<double> &NCJ, std::vector<double> &gNCJ);
-  void initInvCond();
-  void invCondAndGradients(int iEl, std::vector<double> &invCond, std::vector<double> &ginvCond);
+  inline const int &nIJacEl(int iEl) { return _nIJacEl[iEl]; }
+  inline int indGIJac(int iEl, int l, int iPC) { return iPC*_nIJacEl[iEl]+l; }
+  void initIdealJac();
+  void idealJacAndGradients(int iEl, std::vector<double> &NCJ, std::vector<double> &gNCJ);
+  void initCondNum();
+  void condNumAndGradients(int iEl, std::vector<double> &condNum, std::vector<double> &gCondNum);
 
 private:
 
-  enum NORMALSCALING { NS_UNIT, NS_INVNORM, NS_SQRTNORM };
-
   // Mesh entities and variables
   int _dim;
   int _nPC;                                         // Total nb. of parametric coordinates
@@ -141,19 +139,23 @@ private:
   }
 
   // Node displacement
-  double _invLengthScaleSq;                             // Square inverse of a length for node displacement scaling
+  LengthScaling _typeLengthScale;
+  double _invLengthScaleSq;                                     // Square inverse of a length for node displacement scaling
 
   // High-order: scaled Jacobian and metric measures
-  std::vector<int> _nBezEl;                             // Number of Bezier poly. for an el.
-  std::vector<fullMatrix<double> > _scaledNormEl;       // Normals to 2D elements for Jacobian regularization and scaling
-  std::vector<double> _invStraightJac;                  // Initial Jacobians for 3D elements
+  enum NormalScaling { NS_UNIT, NS_INVNORM, NS_SQRTNORM };
+  std::vector<int> _nBezEl;                                     // Number of Bezier poly. for an el.
+  std::vector<fullMatrix<double> > _JacNormEl;                  // Normals to 2D elements for Jacobian regularization and scaling
+  std::vector<double> _invStraightJac;                          // Initial Jacobians for 3D elements
 //  void calcScaledNormalEl2D(const std::map<MElement*,GEntity*> &element2entity, int iEl);
-  void calcNormalEl2D(int iEl, NORMALSCALING scaling);
+  void calcNormalEl2D(int iEl, NormalScaling scaling,
+                      fullMatrix<double> &elNorm, bool ideal);
 
   // Mesh quality
-  std::vector<int> _nNCJEl;                             // Number of NCJ values for an el.
-  std::vector<SVector3> _unitNormEl;                    // Normals to 2D elements for NCJ regularization
-  std::vector<fullMatrix<double> > _metricNormEl;       // Normals to 2D elements for inverse conditioning computation
+  std::vector<int> _nIJacEl;                                    // Number of NCJ values for an el
+  std::vector<fullMatrix<double> > _IJacNormEl;                 // Normals to 2D elements for Jacobian regularization and scaling
+  std::vector<double> _invIJac;                                 // Initial Jacobians for 3D elements
+  std::vector<fullMatrix<double> > _condNormEl;                 // Normals to 2D elements for inverse conditioning computation
 };
 
 
diff --git a/contrib/MeshOptimizer/MeshOptimizer.cpp b/contrib/MeshOptimizer/MeshOptimizer.cpp
index 4cf44f2d1acb7a1db9e317c82b7f8558d5e51a77..ac1a3e0f799797cc309c9f3681bac5ac4584ebca 100644
--- a/contrib/MeshOptimizer/MeshOptimizer.cpp
+++ b/contrib/MeshOptimizer/MeshOptimizer.cpp
@@ -71,109 +71,10 @@ static std::set<MVertex *> getAllBndVertices
 }
 
 
-// Test intersection between sphere and segment
-static bool testSegSphereIntersect(SPoint3 A, SPoint3 B, const SPoint3& P, const double rr)
-{
-  // Test if separating plane between sphere and segment vertices
-  // For each vertex, separation if vertex is outside sphere and P on opposite side
-  // to other seg. vertex w.r.t plane of normal (vertex-P) through vertex
-  const SVector3 PA(P, A), PB(P, B);
-  const double aa = dot(PA, PA), ab = dot(PA, PB);
-  if ((aa > rr) & (ab > aa)) return false;
-  const double  bb = dot(PB, PB);
-  if ((bb > rr) & (ab > bb)) return false;
-
-  // Test if separating plane between sphere and line
-  // For A, separation if projection Q of P on (AB) lies outside the sphere
-  const SVector3 AB(A, B);
-  const double d = ab - aa, e = dot(AB, AB);
-  const  SVector3 PQ = PA * e - d * AB;
-  if (dot(PQ, PQ) > rr * e * e) return false;
-
-  // Return true (intersection) if no separation at all
-  return true;
-}
-
-
-// Test intersection between sphere and triangle
-// Inspired by Christer Ericson, http://realtimecollisiondetection.net/blog/?p=103
-static bool testTriSphereIntersect(SPoint3 A, SPoint3 B, SPoint3 C, const SPoint3& P, const double rr)
-{
-  // Test if separating plane between sphere and triangle plane
-  const SVector3 PA(P, A), AB(A, B), AC(A, C);
-  const SVector3 V = crossprod(AB, AC);                               // Normal to triangle plane
-  const double d = dot(PA, V);                                         // Dist. from P to triangle plane times norm of V
-  const double e = dot(V, V);                                         // Norm of V
-  if (d * d > rr * e) return false;                                   // Test if separating plane between sphere and triangle plane
-
-  // Test if separating plane between sphere and triangle vertices
-  const SVector3 PB(P, B), PC(P, B);
-  const double aa = dot(PA, PA), ab = dot(PA, PB), ac = dot(PA, PC);
-  const double bb = dot(PB, PB), bc = dot(PB, PC), cc = dot(PC, PC);
-  if ((aa > rr) & (ab > aa) & (ac > aa)) return false;                    // For each triangle vertex, separation if vertex is outside sphere
-  if ((bb > rr) & (ab > bb) & (bc > bb)) return false;                    // and P on opposite side to other two triangle vertices w.r.t
-  if ((cc > rr) & (ac > cc) & (bc > cc)) return false;                    // plane of normal (vertex-P) through vertex
-
-  // Test if separating plane between sphere and triangle edges
-  const SVector3 BC(B, C);
-  const double d1 = ab - aa, d2 = bc - bb, d3 = ac - cc;
-  const double e1 = dot(AB, AB), e2 = dot(BC, BC), e3 = dot(AC, AC);
-  const  SVector3 PQ1 = PA * e1 - d1 * AB;                                // Q1 projection of P on line (AB)
-  const  SVector3 PQ2 = PB * e2 - d2 * BC;                                // Q2 projection of P on line (BC)
-  const  SVector3 PQ3 = PC * e3 + d3 * AC;                                // Q3 projection of P on line (AC)
-  const  SVector3 PQC = PC * e1 - PQ1;
-  const  SVector3 PQA = PA * e2 - PQ2;
-  const  SVector3 PQB = PB * e3 - PQ3;
-  if ((dot(PQ1, PQ1) > rr * e1 * e1) & (dot(PQ1, PQC) > 0)) return false; // For A, separation if Q lies outside the sphere and if P and C
-  if ((dot(PQ2, PQ2) > rr * e2 * e2) & (dot(PQ2, PQA) > 0)) return false; // are on opposite sides of plane through AB with normal PQ
-  if ((dot(PQ3, PQ3) > rr * e3 * e3) & (dot(PQ3, PQB) > 0)) return false; // Same for other two vertices
-
-  // Return true (intersection) if no separation at all
-  return true;
-}
-
-
-// Approximate test of intersection element with circle/sphere by sampling
-static bool testElInDist(const SPoint3 P, double limDist, MElement *el)
-{
-  const double sampleLen = 0.5*limDist;                                   // Distance between sample points
-  const double limDistSq = limDist*limDist;
-
-  if (el->getDim() == 2) {                                                // 2D?
-    for (int iEd = 0; iEd < el->getNumEdges(); iEd++) {                   // Loop over edges of element
-      MEdge ed = el->getEdge(iEd);
-      const SPoint3 A = ed.getVertex(0)->point();
-      const SPoint3 B = ed.getVertex(1)->point();
-      if (testSegSphereIntersect(A, B, P, limDistSq)) {
-        return true;
-      }
-    }
-  }
-  else {                                                                  // 3D
-    for (int iFace = 0; iFace < el->getNumFaces(); iFace++) {             // Loop over faces of element
-      MFace face = el->getFace(iFace);
-      const SPoint3 A = face.getVertex(0)->point();
-      const SPoint3 B = face.getVertex(1)->point();
-      const SPoint3 C = face.getVertex(2)->point();
-      if (face.getNumVertices() == 3)
-        return testTriSphereIntersect(A, B, C, P, limDistSq);
-      else {
-        const SPoint3 D = face.getVertex(3)->point();
-        return (testTriSphereIntersect(A, B, C, P, limDistSq) ||
-                    testTriSphereIntersect(A, C, D, P, limDistSq));
-      }
-    }
-  }
-
-  return false;
-}
-
-
-static std::set<MElement*> getSurroundingPatch(MElement *el, int minLayers,
-                            int maxLayers, double limDist,
+static std::set<MElement*> getSurroundingPatch(MElement *el, const MeshOptPatchDef *patchDef,
+                            double limDist, int maxLayers,
                             const std::map<MVertex*, std::vector<MElement*> > &vertex2elements)
 {
-
   const SPoint3 pnt = el->barycenter(true);
 
   std::set<MElement*> patch;
@@ -190,9 +91,11 @@ static std::set<MElement*> getSurroundingPatch(MElement *el, int minLayers,
           ((*it)->getVertex(i))->second;
         for (std::vector<MElement*>::const_iterator itN = neighbours.begin();
              itN != neighbours.end(); ++itN) {
-          if ((patch.find(*itN) == patch.end()) &&
-              ((d < minLayers) || testElInDist(pnt, limDist, *itN)))
-            if (patch.insert(*itN).second) currentLayer.push_back(*itN);      // Assume that if an el is too far, its neighbours are too far as well
+          if (patch.find(*itN) == patch.end()) {
+            const int elIn = patchDef->inPatch(pnt, limDist, *itN);
+            if ((elIn > 0) || ((d < patchDef->minLayers) && (elIn == 0)))
+              if (patch.insert(*itN).second) currentLayer.push_back(*itN);      // Assume that if an el is too far, its neighbours are too far as well
+          }
         }
       }
     }
@@ -251,8 +154,8 @@ static std::vector<std::pair<std::set<MElement*>, std::set<MVertex*> > > getConn
   primPatches.reserve(badElements.size());
   for (std::set<MElement*>::const_iterator it = badElements.begin(); it != badElements.end(); ++it) {
     const double limDist = par.patchDef->maxDistance(*it);
-    primPatches.push_back(getSurroundingPatch(*it, par.patchDef->minLayers,
-                            par.patchDef->maxLayers, limDist, vertex2elements));
+    primPatches.push_back(getSurroundingPatch(*it, par.patchDef, limDist,
+                                par.patchDef->maxLayers, vertex2elements));
   }
 
   // Compute patch connectivity
@@ -404,8 +307,8 @@ static void optimizeOneByOne
 
       // Set up patch
       const double limDist = par.patchDef->maxDistance(worstEl);
-      std::set<MElement*> toOptimizePrim = getSurroundingPatch(worstEl, par.patchDef->minLayers,
-                                                          maxLayers, limDist, vertex2elements);
+      std::set<MElement*> toOptimizePrim = getSurroundingPatch(worstEl, par.patchDef, limDist,
+                                                                    maxLayers, vertex2elements);
       std::set<MVertex*> toFix = getAllBndVertices(toOptimizePrim, vertex2elements);
       std::set<MElement*> toOptimize;
       std::set_difference(toOptimizePrim.begin(),toOptimizePrim.end(),
diff --git a/contrib/MeshQualityOptimizer/MeshQualityObjContribIdealJac.h b/contrib/MeshQualityOptimizer/MeshQualityObjContribIdealJac.h
new file mode 100644
index 0000000000000000000000000000000000000000..3f2245f0813697dbeff70027aa1942fd1a077d47
--- /dev/null
+++ b/contrib/MeshQualityOptimizer/MeshQualityObjContribIdealJac.h
@@ -0,0 +1,98 @@
+// TODO: Copyright
+
+#ifndef _MESHQUALITYOBJCONTRIBIDEALJAC_H_
+#define _MESHQUALITYOBJCONTRIBIDEALJAC_H_
+
+#include "MeshOptPatch.h"
+#include "MeshOptObjContrib.h"
+
+
+template<class FuncType>
+class ObjContribIdealJac : public ObjContrib, public FuncType
+{
+public:
+  ObjContribIdealJac(double weight);
+  virtual ~ObjContribIdealJac() {}
+  virtual ObjContrib *copy() const;
+  virtual void initialize(Patch *mesh);
+  virtual bool fail() { return _min <= 0.; }
+  virtual bool addContrib(double &Obj, alglib::real_1d_array &gradObj);
+  virtual void updateParameters() { FuncType::updateParameters(_min, _max); }
+  virtual bool targetReached() { return FuncType::targetReached(_min, _max); }
+  virtual bool stagnated() { return FuncType::stagnated(_min, _max); }
+  virtual void updateMinMax();
+
+protected:
+  Patch *_mesh;
+  double _weight;
+};
+
+
+template<class FuncType>
+ObjContribIdealJac<FuncType>::ObjContribIdealJac(double weight) :
+  ObjContrib("IdealJac", FuncType::getNamePrefix()+"IdealJac"),
+  _mesh(0), _weight(weight)
+{
+}
+
+
+template<class FuncType>
+ObjContrib *ObjContribIdealJac<FuncType>::copy() const
+{
+  return new ObjContribIdealJac<FuncType>(*this);
+}
+
+
+template<class FuncType>
+void ObjContribIdealJac<FuncType>::initialize(Patch *mesh)
+{
+  _mesh = mesh;
+  _mesh->initIdealJac();
+  updateMinMax();
+  FuncType::initialize(_min, _max);
+}
+
+
+template<class FuncType>
+bool ObjContribIdealJac<FuncType>::addContrib(double &Obj, alglib::real_1d_array &gradObj)
+{
+  _min = BIGVAL;
+  _max = -BIGVAL;
+
+  for (int iEl = 0; iEl < _mesh->nEl(); iEl++) {
+    std::vector<double> iJ(_mesh->nIJacEl(iEl));                                       // Scaled Jacobians
+    std::vector<double> gIJ(_mesh->nIJacEl(iEl)*_mesh->nPCEl(iEl));                    // Gradients of scaled Jacobians
+    _mesh->idealJacAndGradients(iEl, iJ, gIJ);
+    for (int l = 0; l < _mesh->nIJacEl(iEl); l++) {                                    // Add contribution for each Bezier coeff.
+      Obj += _weight * FuncType::compute(iJ[l]);
+      const double dfact = _weight * FuncType::computeDiff(iJ[l]);
+      for (int iPC = 0; iPC < _mesh->nPCEl(iEl); iPC++)
+        gradObj[_mesh->indPCEl(iEl, iPC)] += dfact * gIJ[_mesh->indGIJac(iEl, l, iPC)];
+      _min = std::min(_min, iJ[l]);
+      _max = std::max(_max, iJ[l]);
+    }
+  }
+
+  return true;
+}
+
+
+template<class FuncType>
+void ObjContribIdealJac<FuncType>::updateMinMax()
+{
+  _min = BIGVAL;
+  _max = -BIGVAL;
+
+  for (int iEl = 0; iEl < _mesh->nEl(); iEl++) {
+    std::vector<double> iJ(_mesh->nIJacEl(iEl));                         // Scaled Jacobians
+    std::vector<double> dumGIJ(_mesh->nIJacEl(iEl)*_mesh->nPCEl(iEl));   // Gradients of scaled Jacobians
+    _mesh->idealJacAndGradients(iEl, iJ, dumGIJ);
+    for (int l = 0; l < _mesh->nIJacEl(iEl); l++) {                      // Check each Bezier coeff.
+      _min = std::min(_min, iJ[l]);
+      _max = std::max(_max, iJ[l]);
+    }
+  }
+}
+
+
+#endif /* _MESHQUALITYOBJCONTRIBIDEALJAC_H_ */
diff --git a/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h b/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h
index ccdac14fcf1f1566c0a5f46dbca406dbdb12c807..65b758fb3f0d91c9f8e5daa85bea529845d39a6d 100644
--- a/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h
+++ b/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h
@@ -47,7 +47,7 @@ template<class FuncType>
 void ObjContribInvCond<FuncType>::initialize(Patch *mesh)
 {
   _mesh = mesh;
-  _mesh->initInvCond();
+  _mesh->initCondNum();
   updateMinMax();
   FuncType::initialize(_min, _max);
 }
@@ -62,7 +62,7 @@ bool ObjContribInvCond<FuncType>::addContrib(double &Obj, alglib::real_1d_array
   for (int iEl = 0; iEl < _mesh->nEl(); iEl++) {
     std::vector<double> invCond(_mesh->nBezEl(iEl));                                      // Min. of Metric
     std::vector<double> gInvCond(_mesh->nBezEl(iEl)*_mesh->nPCEl(iEl));                   // Dummy gradients of metric min.
-    _mesh->invCondAndGradients(iEl, invCond, gInvCond);
+    _mesh->condNumAndGradients(iEl, invCond, gInvCond);
     for (int l = 0; l < _mesh->nBezEl(iEl); l++) {                                        // Add contribution for each Bezier coeff.
       Obj += _weight * FuncType::compute(invCond[l]);
       const double dfact = _weight * FuncType::computeDiff(invCond[l]);
@@ -86,7 +86,7 @@ void ObjContribInvCond<FuncType>::updateMinMax()
   for (int iEl = 0; iEl < _mesh->nEl(); iEl++) {
     std::vector<double> invCond(_mesh->nBezEl(iEl));                                      // Min. of Metric
     std::vector<double> dumGInvCond(_mesh->nBezEl(iEl)*_mesh->nPCEl(iEl));                // Dummy gradients of metric min.
-    _mesh->invCondAndGradients(iEl, invCond, dumGInvCond);
+    _mesh->condNumAndGradients(iEl, invCond, dumGInvCond);
     for (int l = 0; l < _mesh->nBezEl(iEl); l++) {                                        // Add contribution for each Bezier coeff.
       _min = std::min(_min, invCond[l]);
       _max = std::max(_max, invCond[l]);
diff --git a/contrib/MeshQualityOptimizer/MeshQualityObjContribNCJ.h b/contrib/MeshQualityOptimizer/MeshQualityObjContribNCJ.h
deleted file mode 100644
index 0673a2812825d938ca7baa0adbd1cda6021cfd81..0000000000000000000000000000000000000000
--- a/contrib/MeshQualityOptimizer/MeshQualityObjContribNCJ.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// TODO: Copyright
-
-#ifndef _MESHQUALITYCONTRIBNCJ_H_
-#define _MESHQUALITYCONTRIBNCJ_H_
-
-#include "MeshOptPatch.h"
-#include "MeshOptObjContrib.h"
-
-
-template<class FuncType>
-class ObjContribNCJ : public ObjContrib, public FuncType
-{
-public:
-  ObjContribNCJ(double weight);
-  virtual ~ObjContribNCJ() {}
-  virtual ObjContrib *copy() const;
-  virtual void initialize(Patch *mesh);
-  virtual bool fail() { return _min <= 0.; }
-  virtual bool addContrib(double &Obj, alglib::real_1d_array &gradObj);
-  virtual void updateParameters() { FuncType::updateParameters(_min, _max); }
-  virtual bool targetReached() { return FuncType::targetReached(_min, _max); }
-  virtual bool stagnated() { return FuncType::stagnated(_min, _max); }
-  virtual void updateMinMax();
-
-protected:
-  Patch *_mesh;
-  double _weight;
-};
-
-
-template<class FuncType>
-ObjContribNCJ<FuncType>::ObjContribNCJ(double weight) :
-  ObjContrib("NCJ", FuncType::getNamePrefix()+"NCJ"),
-  _mesh(0), _weight(weight)
-{
-}
-
-
-template<class FuncType>
-ObjContrib *ObjContribNCJ<FuncType>::copy() const
-{
-  return new ObjContribNCJ<FuncType>(*this);
-}
-
-
-template<class FuncType>
-void ObjContribNCJ<FuncType>::initialize(Patch *mesh)
-{
-  _mesh = mesh;
-  _mesh->initNCJ();
-  updateMinMax();
-  FuncType::initialize(_min, _max);
-}
-
-
-template<class FuncType>
-bool ObjContribNCJ<FuncType>::addContrib(double &Obj, alglib::real_1d_array &gradObj)
-{
-  _min = BIGVAL;
-  _max = -BIGVAL;
-
-  for (int iEl = 0; iEl < _mesh->nEl(); iEl++) {
-    std::vector<double> NCJ(_mesh->nNCJEl(iEl));                                        // Scaled Jacobians
-    std::vector<double> gNCJ(_mesh->nNCJEl(iEl)*_mesh->nPCEl(iEl));                     // Gradients of scaled Jacobians
-    _mesh->NCJAndGradients(iEl, NCJ, gNCJ);
-    for (int l = 0; l < _mesh->nNCJEl(iEl); l++) {                                      // Add contribution for each Bezier coeff.
-      Obj += _weight * FuncType::compute(NCJ[l]);
-      const double dfact = _weight * FuncType::computeDiff(NCJ[l]);
-      for (int iPC = 0; iPC < _mesh->nPCEl(iEl); iPC++)
-        gradObj[_mesh->indPCEl(iEl, iPC)] += dfact * gNCJ[_mesh->indGNCJ(iEl, l, iPC)];
-      _min = std::min(_min, NCJ[l]);
-      _max = std::max(_max, NCJ[l]);
-    }
-  }
-
-  return true;
-}
-
-
-template<class FuncType>
-void ObjContribNCJ<FuncType>::updateMinMax()
-{
-  _min = BIGVAL;
-  _max = -BIGVAL;
-
-  for (int iEl = 0; iEl < _mesh->nEl(); iEl++) {
-    std::vector<double> NCJ(_mesh->nNCJEl(iEl));                         // Scaled Jacobians
-    _mesh->NCJ(iEl, NCJ);
-    for (int l = 0; l < _mesh->nNCJEl(iEl); l++) {                      // Check each Bezier coeff.
-      _min = std::min(_min, NCJ[l]);
-      _max = std::max(_max, NCJ[l]);
-    }
-  }
-}
-
-
-#endif /* _MESHQUALITYCONTRIBNCJ_H_ */
diff --git a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp
index c50d513767ae7ea9c2726e4501a221036e21a95f..db96312c383c825b9d9800d987aaa2737a6c4934 100644
--- a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp
+++ b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp
@@ -10,35 +10,37 @@
 #include "MeshOptObjContribFunc.h"
 #include "MeshOptObjContrib.h"
 #include "MeshOptObjContribScaledNodeDispSq.h"
-#include "MeshQualityObjContribNCJ.h"
+#include "MeshQualityObjContribIdealJac.h"
 #include "MeshQualityObjContribInvCond.h"
 #include "MeshOptimizer.h"
 #include "MeshQualityOptimizer.h"
 
 
-struct QualPatchDefParameters : public MeshOptParameters::PatchDefParameters
+struct QualPatchDefParameters : public MeshOptPatchDef
 {
   QualPatchDefParameters(const MeshQualOptParameters &p);
   virtual ~QualPatchDefParameters() {}
-  virtual double elBadness(MElement *el);
-  virtual double maxDistance(MElement *el);
+  virtual double elBadness(MElement *el) const;
+  virtual double maxDistance(MElement *el) const;
+  virtual int inPatch(const SPoint3 &badBary,
+                      double limDist, MElement *el) const;
 private:
-//  double NCJMin, NCJMax;
-  double invCondMin;
-  double distanceFactor;
+  bool _excludeHex, _excludePrism;
+  double _idealJacMin;
+  double _distanceFactor;
 };
 
 
 QualPatchDefParameters::QualPatchDefParameters(const MeshQualOptParameters &p)
 {
-//  NCJMin = p.minTargetNCJ;
-//  NCJMax = (p.maxTargetNCJ > 0.) ? p.maxTargetNCJ : 1.e300;
-  invCondMin = p.minTargetInvCond;
+  _excludeHex = p.excludeHex;
+  _excludePrism = p.excludePrism;
+  _idealJacMin = p.minTargetIdealJac;
   strategy = (p.strategy == 1) ? MeshOptParameters::STRAT_ONEBYONE :
                                         MeshOptParameters::STRAT_CONNECTED;
   minLayers = (p.dim == 3) ? 1 : 0;
   maxLayers = p.nbLayers;
-  distanceFactor = p.distanceFactor;
+  _distanceFactor = p.distanceFactor;
   if (strategy == MeshOptParameters::STRAT_CONNECTED)
     weakMerge = (p.strategy == 2);
   else {
@@ -49,32 +51,29 @@ QualPatchDefParameters::QualPatchDefParameters(const MeshQualOptParameters &p)
 }
 
 
-double QualPatchDefParameters::elBadness(MElement *el) {
-//  double valMin, valMax;
-//  switch(el->getType()) {                                                 // TODO: Complete with other types?
-//  case TYPE_TRI: {
-//     qmTriangle::NCJRange(static_cast<MTriangle*>(el), valMin, valMax);
-//    break;
-//  }
-//  case TYPE_QUA: {
-//    qmQuadrangle::NCJRange(static_cast<MQuadrangle*>(el), valMin, valMax);
-//    break;
-//  }
-//  }
-  const JacobianBasis *jac = el->getJacobianFuncSpace();
-  fullMatrix<double> nodesXYZ(el->getNumShapeFunctions(), 3);
-  el->getNodesCoord(nodesXYZ);
-  fullVector<double> invCond(jac->getNumJacNodes());
-  jac->getInvCond(nodesXYZ, invCond);
-  const double valMin = *std::min_element(invCond.getDataPtr(),
-                          invCond.getDataPtr()+jac->getNumJacNodes());
-  double badness = std::min(valMin-invCondMin, 0.);
-  return badness;
+double QualPatchDefParameters::elBadness(MElement *el) const
+{
+  const int typ = el->getType();
+  if (_excludeHex && (typ == TYPE_HEX)) return 1.;
+  if (_excludePrism && (typ == TYPE_PRI)) return 1.;
+  double jMin, jMax;
+  el->idealJacRange(jMin, jMax);
+  return jMin-_idealJacMin;
+}
+
+
+double QualPatchDefParameters::maxDistance(MElement *el) const
+{
+  return _distanceFactor * el->maxEdge();
 }
 
 
-double QualPatchDefParameters::maxDistance(MElement *el) {
-  return distanceFactor * el->getOuterRadius();
+int QualPatchDefParameters::inPatch(const SPoint3 &badBary,
+                                    double limDist, MElement *el) const
+{
+  const int typ = el->getType();
+  if ((typ == TYPE_HEX) || (typ == TYPE_PRI)) return -1;
+  return testElInDist(badBary, limDist, el) ? 1 : 0;
 }
 
 
@@ -88,42 +87,24 @@ void MeshQualityOptimizer(GModel *gm, MeshQualOptParameters &p)
   par.fixBndNodes = p.fixBndNodes;
   QualPatchDefParameters patchDef(p);
   par.patchDef = &patchDef;
-  par.optDisplay = 30;
+  par.optDisplay = 20;
   par.verbose = 4;
 
-  ObjContribScaledNodeDispSq<ObjContribFuncSimple> nodeDistFunc(p.weightFixed, p.weightFree);
-//  ObjContribNCJ<ObjContribFuncBarrierMovMin> minNCJBarFunc(1.);
-//  minNCJBarFunc.setTarget(p.minTargetNCJ, 1.);
-////  minNCJBarFunc.setTarget(p.minTargetNCJ, 0.866025404);
-//  ObjContribNCJ<ObjContribFuncBarrierFixMinMovMax> minMaxNCJBarFunc(1.);
-//  minMaxNCJBarFunc.setTarget(p.maxTargetNCJ, 1.);
-  ObjContribInvCond<ObjContribFuncBarrierMovMin> minInvCondBarFunc(1.);
-  minInvCondBarFunc.setTarget(p.minTargetInvCond, 1.);
+  ObjContribScaledNodeDispSq<ObjContribFuncSimple> nodeDistFunc(p.weightFixed, p.weightFree,
+                                                                Patch::LS_MINEDGELENGTH);
+  ObjContribIdealJac<ObjContribFuncBarrierMovMin> minIdealJacBarFunc(1.);
+  minIdealJacBarFunc.setTarget(p.minTargetIdealJac, 1.);
 
-  MeshOptParameters::PassParameters minJacPass;
+  MeshOptPass minJacPass;
   minJacPass.barrierIterMax = p.optPassMax;
   minJacPass.optIterMax = p.itMax;
   minJacPass.contrib.push_back(&nodeDistFunc);
-//  minJacPass.contrib.push_back(&minNCJBarFunc);
-  minJacPass.contrib.push_back(&minInvCondBarFunc);
+  minJacPass.contrib.push_back(&minIdealJacBarFunc);
   par.pass.push_back(minJacPass);
 
-//  if (p.maxTargetNCJ > 0.) {
-//    MeshOptParameters::PassParameters minMaxJacPass;
-//    minMaxJacPass.barrierIterMax = p.optPassMax;
-//    minMaxJacPass.optIterMax = p.itMax;
-//    minMaxJacPass.contrib.push_back(&nodeDistFunc);
-//    minMaxJacPass.contrib.push_back(&minMaxNCJBarFunc);
-//    par.pass.push_back(minMaxJacPass);
-//  }
-
   meshOptimizer(gm, par);
 
   p.CPU = par.CPU;
-//  p.minNCJ = minMaxNCJBarFunc.getMin();
-//  p.maxNCJ = minMaxNCJBarFunc.getMax();
-  p.minInvCond = minInvCondBarFunc.getMin();
-  p.maxInvCond = minInvCondBarFunc.getMax();
-
-  Msg::StatusBar(true, "Done optimizing high order mesh (%g s)", p.CPU);
+  p.minIdealJac = minIdealJacBarFunc.getMin();
+  p.maxIdealJac = minIdealJacBarFunc.getMax();
 }
diff --git a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h
index d34d1083d33b01a16617e1d57d5402a836d6c753..36722f0a453d634a96f480992703533d7841cbe8 100644
--- a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h
+++ b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h
@@ -33,15 +33,15 @@
 class GModel;
 
 struct MeshQualOptParameters {
-//  double minTargetNCJ, maxTargetNCJ;
-  double minTargetInvCond;
-  double weightFixed ; // weight of the energy for fixed nodes
-  double weightFree ; // weight of the energy for free nodes
-  int nbLayers ; // number of layers taken around a bad element
-  int dim ; // which dimension to optimize
-  int itMax ; // max number of iterations in the optimization process
-  int optPassMax ; // max number of optimization passes
-  bool onlyVisible ; // apply optimization to visible entities ONLY
+  bool excludeHex, excludePrism;
+  double minTargetIdealJac;
+  double weightFixed; // weight of the energy for fixed nodes
+  double weightFree; // weight of the energy for free nodes
+  int nbLayers; // number of layers taken around a bad element
+  int dim; // which dimension to optimize
+  int itMax; // max number of iterations in the optimization process
+  int optPassMax; // max number of optimization passes
+  bool onlyVisible; // apply optimization to visible entities ONLY
   double distanceFactor; // filter elements such that no elements further away
                          // than DistanceFactor times the max distance to
                          // straight sided version of an element are optimized
@@ -52,16 +52,15 @@ struct MeshQualOptParameters {
   double adaptBlobDistFact; // Growth factor in distance factor for blob adaptation
 
   int SUCCESS ; // 0 --> success , 1 --> Not converged
-//  double minNCJ, maxNCJ; // after optimization, range of jacobians
-  double minInvCond, maxInvCond; // after optimization, range of jacobians
+  double minIdealJac, maxIdealJac; // after optimization, range of jacobians
   double CPU; // Time for optimization
 
   MeshQualOptParameters ()
-//    : minTargetNCJ(0.5), maxTargetNCJ(1.5), weightFixed(1000.),
-    : minTargetInvCond(0.5), weightFixed(1000.),
+    : excludeHex(false), excludePrism(false), minTargetIdealJac(0.1), weightFixed(1000.),
       weightFree (1.), nbLayers (6) , dim(3) , itMax(300), optPassMax(50),
       onlyVisible(true), distanceFactor(12), fixBndNodes(false), strategy(0),
-      maxAdaptBlob(3), adaptBlobLayerFact(2.), adaptBlobDistFact(2.)
+      maxAdaptBlob(3), adaptBlobLayerFact(2.), adaptBlobDistFact(2.), CPU(0.),
+      minIdealJac(0.), maxIdealJac(0.), SUCCESS(-1)
   {
   }
 };