diff --git a/Common/Context.h b/Common/Context.h
index 8b43003b95de128629e48eda5a5f908615779484..e9121396c3ead20d5a6057fc4162cfd22a45ba16 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -236,8 +236,10 @@ class CTX {
   int mouseSelection, mouseHoverMeshes, pickElements;
   // disable some warnings for expert users?
   int expertMode;
+#if defined(HAVE_VISUDEV)
   // Enable heavy visualization capabilities (for development purpose)
   int heavyVisu;
+#endif
   // dynamic: equal to 1 while gmsh is printing
   int printing;
   // hide all unselected entities?
diff --git a/Common/Options.h b/Common/Options.h
index 53a35ad8bb72b56ac60a329035d6ee7f62334b34..12b9a3e5e2c366be1bf9cad79154e25d3234dbed 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -285,7 +285,9 @@ double opt_general_zoom_factor(OPT_ARGS_NUM);
 double opt_general_expert_mode(OPT_ARGS_NUM);
 double opt_general_stereo_mode(OPT_ARGS_NUM);
 double opt_general_camera_mode(OPT_ARGS_NUM);
+#if defined(HAVE_VISUDEV)
 double opt_general_heavy_visualization(OPT_ARGS_NUM);
+#endif
 double opt_general_eye_sep_ratio(OPT_ARGS_NUM);
 double opt_general_focallength_ratio(OPT_ARGS_NUM);
 double opt_general_camera_aperture(OPT_ARGS_NUM);
diff --git a/Mesh/qualityMeasuresJacobian.cpp b/Mesh/qualityMeasuresJacobian.cpp
index 97eb1da16e508001473a02a6e1d30d1e91510fe8..2742a079780a064ee168a0c08c8d679246bf85de 100644
--- a/Mesh/qualityMeasuresJacobian.cpp
+++ b/Mesh/qualityMeasuresJacobian.cpp
@@ -405,6 +405,32 @@ double minICNMeasure(MElement *el,
 }
 
 void sampleIGEMeasure(MElement *el, int deg, double &min, double &max)
+{
+  fullVector<double> ige;
+  sampleIGEMeasure(el, deg, ige);
+
+  min = std::numeric_limits<double>::infinity();
+  max = -min;
+  for (int i = 0; i < ige.size(); ++i) {
+    min = std::min(min, ige(i));
+    max = std::max(max, ige(i));
+  }
+}
+
+void sampleJacobian(MElement *el, int deg, fullVector<double> &jac,
+                    const fullMatrix<double> *normals)
+{
+  FuncSpaceData sampleSpace = FuncSpaceData(el, deg);
+  const JacobianBasis *jacBasis = BasisFactory::getJacobianBasis(sampleSpace);
+
+  fullMatrix<double> nodesXYZ(el->getNumVertices(), 3);
+  el->getNodesCoord(nodesXYZ);
+
+  jac.resize(jacBasis->getNumJacNodes());
+  jacBasis->getSignedJacobian(nodesXYZ, jac, normals);
+}
+
+void sampleIGEMeasure(MElement *el, int deg, fullVector<double> &ige)
 {
   fullMatrix<double> nodesXYZ(el->getNumVertices(), 3);
   el->getNodesCoord(nodesXYZ);
@@ -427,7 +453,7 @@ void sampleIGEMeasure(MElement *el, int deg, double &min, double &max)
     jacDetSpace = FuncSpaceData(el, true, deg-1, 1, &serendipFalse);
     break;
   default:
-    Msg::Error("ICN not implemented for type of element %d", el->getType());
+    Msg::Error("IGE not implemented for type of element %d", el->getType());
     return;
   }
 
@@ -439,21 +465,12 @@ void sampleIGEMeasure(MElement *el, int deg, double &min, double &max)
 
   fullMatrix<double> coeffMatLag(gradBasis->getNumSamplingPoints(), 9);
   gradBasis->getAllGradientsFromNodes(nodesXYZ, coeffMatLag);
+  if (el->getDim() == 2) coeffMatLag.resize(coeffMatLag.size1(), 6, false);
 
   fullMatrix<double> v;
   computeCoeffLengthVectors_(coeffMatLag, v, type);
 
-  fullVector<double> ige;
   computeIGE_(coeffDeterminant, v, ige, type);
-
-  min = std::numeric_limits<double>::infinity();
-  max = -min;
-  for (int i = 0; i < ige.size(); ++i) {
-    min = std::min(min, ige(i));
-    max = std::max(max, ige(i));
-  }
-
-  return;
 }
 
 double minSampledICNMeasure(MElement *el, int deg)//fordebug
diff --git a/Mesh/qualityMeasuresJacobian.h b/Mesh/qualityMeasuresJacobian.h
index 6c3b62992a1df10b80eed5c812d02207a1c11103..1bb4fc2a35d7dc8fcf8df15649c6fecf4e46dced 100644
--- a/Mesh/qualityMeasuresJacobian.h
+++ b/Mesh/qualityMeasuresJacobian.h
@@ -24,6 +24,10 @@ double minICNMeasure(MElement *el,
                      bool knownValid = false,
                      bool reversedOk = false);
 void sampleIGEMeasure(MElement *el, int order, double &min, double &max);
+void sampleJacobian(MElement *el, int order, fullVector<double> &jac,
+                    const fullMatrix<double> *normals = NULL);
+void sampleIGEMeasure(MElement *el, int order, fullVector<double> &ige);
+void sampleICNMeasure(MElement *el, int order, fullVector<double> &icn);
 double minSampledICNMeasure(MElement *el, int order);//fordebug
 double minSampledIGEMeasure(MElement *el, int order);//fordebug
 
diff --git a/Plugin/AnalyseCurvedMesh.cpp b/Plugin/AnalyseCurvedMesh.cpp
index c798ab731f8d45ea8a26b9f7c94ef87afa4643af..cc33b71d9966b15b7edbcae1eedab29aba0c26c3 100644
--- a/Plugin/AnalyseCurvedMesh.cpp
+++ b/Plugin/AnalyseCurvedMesh.cpp
@@ -7,6 +7,7 @@
 
 #if defined(HAVE_MESH)
 
+
 #include "AnalyseCurvedMesh.h"
 #include "OS.h"
 #include "Context.h"
@@ -19,6 +20,9 @@
 #include <sstream>
 #include <fstream>
 #include "qualityMeasuresJacobian.h"
+#if defined(HAVE_VISUDEV)
+#include "BasisFactory.h"
+#endif
 
 class bezierBasis;
 
@@ -30,6 +34,9 @@ StringXNumber CurvedMeshOptions_Number[] = {
   {GMSH_FULLRC, "Draw PView", NULL, 0},
   {GMSH_FULLRC, "Recompute", NULL, 0},
   {GMSH_FULLRC, "Dimension of elements", NULL, -1}
+#if defined(HAVE_VISUDEV)
+ ,{GMSH_FULLRC, "Element to draw quality", NULL, 0}
+#endif
 };
 
 extern "C"
@@ -97,13 +104,25 @@ std::string GMSH_AnalyseCurvedMeshPlugin::getHelp() const
 PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
 {
   _m = GModel::current();
-  bool computeJac = static_cast<int>(CurvedMeshOptions_Number[0].def);
-  bool computeIGE = static_cast<int>(CurvedMeshOptions_Number[1].def);
-  bool computeICN = static_cast<int>(CurvedMeshOptions_Number[2].def);
-  _threshold      = static_cast<double>(CurvedMeshOptions_Number[3].def);
-  bool drawPView  = static_cast<int>(CurvedMeshOptions_Number[4].def);
-  bool recompute  = static_cast<bool>(CurvedMeshOptions_Number[5].def);
-  int askedDim    = static_cast<int>(CurvedMeshOptions_Number[6].def);
+  int computeJac = static_cast<int>(CurvedMeshOptions_Number[0].def);
+  int computeIGE = static_cast<int>(CurvedMeshOptions_Number[1].def);
+  int computeICN = static_cast<int>(CurvedMeshOptions_Number[2].def);
+  _threshold     = CurvedMeshOptions_Number[3].def;
+  bool drawPView = static_cast<bool>(CurvedMeshOptions_Number[4].def);
+  bool recompute = static_cast<bool>(CurvedMeshOptions_Number[5].def);
+  int askedDim   = static_cast<int>(CurvedMeshOptions_Number[6].def);
+
+#if defined(HAVE_VISUDEV)
+  _pwJac = computeJac/2;
+  _pwIGE = computeIGE/2;
+  _pwICN = computeICN/2;
+
+  _numElementToScan = static_cast<int>(CurvedMeshOptions_Number[7].def);
+  _viewOrder = 0;
+  _dataPViewJac.clear();
+  _dataPViewIGE.clear();
+  _dataPViewICN.clear();
+#endif
 
   if (askedDim < 0 || askedDim > 4) askedDim = _m->getDim();
 
@@ -163,6 +182,10 @@ PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
   if (printStatS) _printStatIGE();
   if (printStatI) _printStatICN();
 
+#if defined(HAVE_VISUDEV)
+  _createPViewPointwise();
+#endif
+
   // Create PView
   if (drawPView)
   for (int dim = 1; dim <= 3; ++dim) {
@@ -342,6 +365,10 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(int dim)
       _data.push_back(data_elementMinMax(el, min, max));
       if (min < 0 && max < 0) ++cntInverted;
       progress.next();
+
+#if defined(HAVE_VISUDEV)
+      _computePointwiseQuantities(el, normals);
+#endif
     }
     delete normals;
   }
@@ -515,4 +542,84 @@ void GMSH_AnalyseCurvedMeshPlugin::_printStatICN()
             infminI, avgminI, supminI);
 }
 
+#if defined(HAVE_VISUDEV)
+void GMSH_AnalyseCurvedMeshPlugin::_computePointwiseQuantities(MElement *el,
+                                                               const fullMatrix<double> *normals) {
+  if (_numElementToScan != -1 && el->getNum() != _numElementToScan) return;
+
+  if (!_type2tag[el->getType()])
+    _type2tag[el->getType()] = el->getTypeForMSH();
+  else
+    // Skip if element tag is different from previous elements of same type
+    if (_type2tag[el->getType()] != el->getTypeForMSH()) return;
+
+  static fullVector<double> tmpVector;
+  int num = el->getNum();
+
+  if (!_viewOrder) {
+//    _viewOrder = std::min(10, 2 * el->getPolynomialOrder());
+    _viewOrder = 9;
+  }
+
+  if (_pwJac) {
+    jacobianBasedQuality::sampleJacobian(el, _viewOrder, tmpVector, normals);
+    std::vector<double> &vec = _dataPViewJac[num];
+    for (int j = 0; j < tmpVector.size(); ++j)
+      vec.push_back(tmpVector(j));
+  }
+
+  if (_pwIGE) {
+    jacobianBasedQuality::sampleIGEMeasure(el, _viewOrder, tmpVector);
+    std::vector<double> &vec = _dataPViewIGE[num];
+    for (int j = 0; j < tmpVector.size(); ++j)
+      vec.push_back(tmpVector(j));
+  }
+
+  if (_pwICN) {
+//    jacobianBasedQuality::sampleICNMeasure(el, _viewOrder, tmpVector);
+//    std::vector<double> &vec = _dataPViewICN[num];
+//    for (int j = 0; j < tmpVector.size(); ++j)
+//      vec.push_back(tmpVector(j));
+  }
+}
+
+void GMSH_AnalyseCurvedMeshPlugin::_setInterpolationMatrices(PView *view)
+{
+  PViewData *viewData = view->getData();
+  for (int type = 0; type < 20; ++type) {
+    if (!_type2tag[type]) continue;
+    viewData->deleteInterpolationMatrices(type);
+    const nodalBasis *fsE = BasisFactory::getNodalBasis(_type2tag[type]);
+    const polynomialBasis *pfsE = dynamic_cast<const polynomialBasis *>(fsE);
+    const int hoTag = ElementType::getTag(type, _viewOrder);
+    const nodalBasis *fsV = BasisFactory::getNodalBasis(hoTag);
+    const polynomialBasis *pfsV = dynamic_cast<const polynomialBasis *>(fsV);
+    viewData->setInterpolationMatrices(type,
+                                       pfsV->coefficients, pfsV->monomials,
+                                       pfsE->coefficients, pfsE->monomials);
+  }
+}
+
+void GMSH_AnalyseCurvedMeshPlugin::_createPViewPointwise()
+{
+  if (_pwJac) {
+    _setInterpolationMatrices(
+        new PView("Pointwise Jacobian", "ElementNodeData", _m, _dataPViewJac, 0, 1)
+    );
+  }
+
+  if (_pwIGE) {
+    _setInterpolationMatrices(
+        new PView("Pointwise IGE", "ElementNodeData", _m, _dataPViewIGE, 0, 1)
+    );
+  }
+
+  if (_pwICN) {
+    _setInterpolationMatrices(
+        new PView("Pointwise ICN", "ElementNodeData", _m, _dataPViewICN, 0, 1)
+    );
+  }
+}
+#endif
+
 #endif
diff --git a/Plugin/AnalyseCurvedMesh.h b/Plugin/AnalyseCurvedMesh.h
index d1aac032a5306c5db3438f49739f82779a8e130d..cddb2796fcbfb1086125fd1c20b0588b447be9f9 100644
--- a/Plugin/AnalyseCurvedMesh.h
+++ b/Plugin/AnalyseCurvedMesh.h
@@ -22,11 +22,9 @@ private:
   double _minJac, _maxJac, _minIGE, _minICN;
 public:
   data_elementMinMax(MElement *e,
-                     double minJ = 2,
-                     double maxJ = 0,
-                     double minIGE = -1,
-                     double minICN = -1)
-    : _el(e), _minJac(minJ), _maxJac(maxJ), _minIGE(minIGE), _minICN(minICN) {}
+                     double minJ = 2, double maxJ = 0,
+                     double minIGE = -1, double minICN = -1)
+      : _el(e), _minJac(minJ), _maxJac(maxJ), _minIGE(minIGE), _minICN(minICN) {}
   void setMinS(double r) { _minIGE = r; }
   void setMinI(double r) { _minICN = r; }
   MElement* element() { return _el; }
@@ -42,6 +40,17 @@ private :
   GModel *_m;
   double _threshold;
 
+#if defined(HAVE_VISUDEV)
+  // Pointwise data
+  int _numElementToScan;
+  bool _pwJac, _pwIGE, _pwICN;
+  std::map<int, std::vector<double>> _dataPViewJac;
+  std::map<int, std::vector<double>> _dataPViewIGE;
+  std::map<int, std::vector<double>> _dataPViewICN;
+  int _type2tag[20] = {0};
+  int _viewOrder = 0;
+#endif
+
   // for 1d, 2d, 3d
   bool _computedJac[3], _computedIGE[3], _computedICN[3];
   bool _PViewJac[3], _PViewIGE[3], _PViewICN[3];
@@ -81,6 +90,12 @@ private :
   void _printStatJacobian();
   void _printStatIGE();
   void _printStatICN();
+
+#if defined(HAVE_VISUDEV)
+  void _computePointwiseQuantities(MElement *, const fullMatrix<double> *normals);
+  void _createPViewPointwise();
+  void _setInterpolationMatrices(PView *);
+#endif
 };
 
 #endif
diff --git a/Post/PViewData.cpp b/Post/PViewData.cpp
index 59d56e5155b7a33ff0feac502e4407cc291d5402..0473d24ec2da431bc3d1266b4d80f29a5edf348e 100644
--- a/Post/PViewData.cpp
+++ b/Post/PViewData.cpp
@@ -184,6 +184,11 @@ bool PViewData::haveInterpolationMatrices(int type)
     return _interpolation.count(type) ? true : false;
 }
 
+void PViewData::deleteInterpolationMatrices(int type)
+{
+  _interpolation.erase(type);
+}
+
 void PViewData::removeInterpolationScheme(const std::string &name)
 {
   std::map<std::string, interpolationMatrices>::iterator it = _interpolationSchemes.find(name);
diff --git a/Post/PViewData.h b/Post/PViewData.h
index 9b5449ec1227eb610707e2891c246d09dccdd6de..922083f18097416c4b61b40962f604d8b01bfd35 100644
--- a/Post/PViewData.h
+++ b/Post/PViewData.h
@@ -225,6 +225,7 @@ class PViewData {
                                 const fullMatrix<double> &expGeo);
   int getInterpolationMatrices(int type, std::vector<fullMatrix<double>*> &p);
   bool haveInterpolationMatrices(int type=0);
+  void deleteInterpolationMatrices(int type=0);
 
   // access to global interpolation schemes
   static void removeInterpolationScheme(const std::string &name);