diff --git a/Mesh/meshGRegionBoundaryLayers.cpp b/Mesh/meshGRegionBoundaryLayers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7640fbc25e883d5b36071aa8899a3d2109297a36
--- /dev/null
+++ b/Mesh/meshGRegionBoundaryLayers.cpp
@@ -0,0 +1,204 @@
+#include "meshGFaceBoundaryLayers.h"
+#include "GModel.h"
+#include "GRegion.h"
+#include "MTriangle.h"
+#include "MTetrahedron.h"
+#include "MVertex.h"
+#include "Field.h"
+
+
+//
+//               ^  ni
+//               |   
+//               |
+//      +-----------------+
+//               bi      /
+//                 bj  /
+//                   /\
+//                 /    \   nj
+//               /        Z
+//             +
+
+static double solidAngle (SVector3 &ni, SVector3 &nj,
+			  SPoint3  &bi, SPoint3  &bj) {
+  double cosa = dot (ni, nj);
+  SVector3 bibj = bj - bi;
+  SVector3 sina = crossprod ( ni , nj );
+  double a = atan2(sina.norm(),cosa);
+  double sign = dot (nj, bibj);
+  return sign > 0 ? fabs (a) : -fabs(a);
+} 
+
+BoundaryLayerColumns* buildAdditionalPoints3D_CAD_BASED (GRegion *gr) {
+}
+
+
+
+BoundaryLayerColumns* buildAdditionalPoints3D (GRegion *gr)
+{
+#if !defined(HAVE_ANN)
+  return 0;
+#else
+  FieldManager *fields = gr->model()->getFields();
+  if(fields->getBoundaryLayerField() <= 0){
+    return 0;
+  }
+  Field *bl_field = fields->get(fields->getBoundaryLayerField());
+  BoundaryLayerField *blf = dynamic_cast<BoundaryLayerField*> (bl_field);
+
+  if (!blf)return 0;
+
+  double _treshold = blf->fan_angle * M_PI / 180 ;
+
+  BoundaryLayerColumns * _columns = new BoundaryLayerColumns;
+
+  std::list<GFace*> faces = gr->faces();
+  std::list<GFace*>::iterator itf = faces.begin();
+  std::set<MVertex*> _vertices;
+  std::map<MFace,SVector3,Less_Face> _normals;
+
+  // filter vertices : belong to BL and are classified on FACES
+  while(itf != faces.end()){
+    if (blf->isFaceBL((*itf)->tag())){
+      printf("FACE %d is a boundary layer face %d triangles\n",(*itf)->tag(),(*itf)->triangles.size());
+      for(unsigned int i = 0; i< (*itf)->triangles.size(); i++)      
+	for(unsigned int j = 0; j< 3; j++){
+	  if ((*itf)->triangles[i]->getVertex(j)->onWhat()->dim() != 3){
+	    _columns->_non_manifold_faces.insert(std::make_pair((*itf)->triangles[i]->getVertex(j),(*itf)->triangles[i]));
+	    _vertices.insert((*itf)->triangles[i]->getVertex(j));
+	    _normals [(*itf)->triangles[i]->getFace(0)] = SVector3(0,0,0);
+	  }
+	}
+    }
+    ++itf;
+  }
+  printf("%d vertices \n",_vertices.size());
+  
+  // assume that the initial mesh has been created i.e. that there exist
+  // tetrahedra inside the domain. Tetrahedra are used to define
+  // exterior normals
+  for (unsigned int i=0;i<gr->tetrahedra.size();i++){
+    for (int j=0;j<4;j++){
+      MFace f = gr->tetrahedra[i]->getFace(j);
+      std::map<MFace,SVector3,Less_Face>::iterator it = _normals.find(f);
+      if (it != _normals.end()){
+	MVertex *v0 = f.getVertex(0);
+	MVertex *v1 = f.getVertex(1);
+	MVertex *v2 = f.getVertex(2);
+	MVertex *v3 = 0;
+	for (int k=0;k<4;k++){
+	  if (gr->tetrahedra[i]->getVertex(k) != v0 && 
+	      gr->tetrahedra[i]->getVertex(k) != v1 && 
+	      gr->tetrahedra[i]->getVertex(k) != v2 ){
+	    v3 = gr->tetrahedra[i]->getVertex(k);
+	  }
+	}
+	SVector3 v01 (v1->x()-v0->x(),v1->y()-v0->y(),v1->z()-v0->z());
+	SVector3 v02 (v2->x()-v0->x(),v2->y()-v0->y(),v2->z()-v0->z());
+	SVector3 v03 (v3->x()-v0->x(),v3->y()-v0->y(),v3->z()-v0->z());
+	SVector3 n = crossprod (v01,v02);
+	double sign = dot(n,v03);
+	n.normalize();
+	if (sign > 0)it->second = n;
+	else it->second = n*(-1.0);
+      }
+    }    
+  }
+  
+  // for all boundry points
+  for (std::set<MVertex*>::iterator it = _vertices.begin(); it != _vertices.end() ; ++it){
+    std::vector<MTriangle*> _connections;
+    std::vector<SVector3> _dirs, _allDirs;
+    for (std::multimap<MVertex*,MTriangle*>::iterator itm =
+           _columns->_non_manifold_faces.lower_bound(*it);
+         itm != _columns->_non_manifold_faces.upper_bound(*it); ++itm){
+      _connections.push_back (itm->second);
+      _allDirs.push_back (_normals[itm->second->getFace(0)]);
+    }
+    
+    // a list of normals is associated to a given vertex
+    SPoint3 p ((*it)->x(),(*it)->y(),(*it)->z());
+    std::vector<std::vector<int> > groupsOfDirections;
+    for (unsigned int i=0;i<_connections.size();i++){
+      SPoint3 bi = _connections[i]->barycenter();
+      SVector3 ni = _allDirs[i];
+      bool found = false;
+      for (unsigned int j=0;j<groupsOfDirections.size();j++){
+	for (unsigned int k=0;k<groupsOfDirections[j].size();k++){
+	  int iDir = groupsOfDirections[j][k];
+	  SPoint3 bj = _connections[iDir]->barycenter();
+	  SVector3 nj = _allDirs[iDir];
+	  double angle = solidAngle (ni,nj,bi,bj);
+	  // those two directions are 
+	  if (angle < _treshold){
+	    found = true;
+	    groupsOfDirections[j].push_back(i);
+	    goto gotit;
+	  }
+	}
+      }
+    gotit:
+      if (!found){
+	std::vector<int> newDir;
+	newDir.push_back(i);
+	groupsOfDirections.push_back(newDir);
+      }
+    }
+    
+    
+    std::vector<SVector3> shoot;
+    for (unsigned int j=0;j<groupsOfDirections.size();j++){
+      SVector3 n;
+      for (unsigned int k=0;k<groupsOfDirections[j].size();k++){
+	int iDir = groupsOfDirections[j][k];
+	n += _allDirs[iDir];
+      }
+      n.normalize();
+      shoot.push_back(n);
+    }
+    
+    // now create the BL points
+    for (unsigned int DIR=0;DIR<shoot.size();DIR++){
+      SVector3 n = shoot[DIR];
+      MVertex *current = *it;
+      SVector3 basis (current->x(),current->y(),current->z());
+      double H = blf->hwall_n;
+      std::vector<MVertex*> _column;
+      std::vector<SMetric3> _metrics;
+      double dist = H;
+      while(dist < blf->thickness){
+	SVector3 newp = basis + n * H;
+	MVertex *_current = new MVertex (newp.x(),newp.y(),newp.z());
+	_column.push_back(_current);
+	H *=  blf->ratio;
+	dist += H;
+	basis = newp;
+      }
+      _columns->addColumn(n,*it, _column, _metrics);
+    }
+  }
+  // HERE WE SHOULD FILTER THE POINTS IN ORDER NOT TO HAVE POINTS THAT ARE TOO CLOSE
+
+  // DEBUG STUFF
+
+  FILE *f = fopen ("test3D.pos","w");
+  fprintf(f,"View \"\" {\n");
+  for (std::set<MVertex*>::iterator it = _vertices.begin(); it != _vertices.end() ; ++it){
+    MVertex *v = *it;
+    for (int i=0;i<_columns->getNbColumns(v);i++){
+      const BoundaryLayerData &data = _columns->getColumn(v,i);
+      for (unsigned int j=0;j<data._column.size();j++){
+	MVertex *blv = data._column[j];
+	fprintf(f,"SP(%g,%g,%g){%d};\n",blv->x(),blv->y(),blv->z(),v->getNum());
+      }
+    }
+  }
+  fprintf(f,"};\n");
+  fclose (f);
+
+  // END OF DEBUG STUFF
+
+  return _columns;
+#endif
+  return 0;
+}
diff --git a/Post/PViewAsSimpleFunction.cpp b/Post/PViewAsSimpleFunction.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7a2f347dd3146db83bfebd7bc332c52c16f6dad1
--- /dev/null
+++ b/Post/PViewAsSimpleFunction.cpp
@@ -0,0 +1,10 @@
+#include "PView.h"
+#include "PViewData.h"
+#include "PViewAsSimpleFunction.h"
+double PViewEvaluator::operator() (const double x, const double y, const double z) const{
+  PViewData * pvd = _pv->getData();
+  double value;
+  bool found = pvd->searchScalar(x,y,z,&value,_step);
+  if (found) return value;
+  return 1.e22;
+}
diff --git a/Post/PViewAsSimpleFunction.h b/Post/PViewAsSimpleFunction.h
new file mode 100644
index 0000000000000000000000000000000000000000..e02918fcc1f55542c75dcac181ccea9e446904e1
--- /dev/null
+++ b/Post/PViewAsSimpleFunction.h
@@ -0,0 +1,14 @@
+#ifndef _PVIEW_AS_SIMPLEFUNCTION_H
+#define _PVIEW_AS_SIMPLEFUNCTION_H
+#include "simpleFunction.h"
+class PView;
+class PViewEvaluator : public simpleFunction<double> {
+  PView *_pv;
+  int _step;
+public:
+  PViewEvaluator (PView *pv) : _pv(pv),_step(0) {}
+  double operator() (const double x, const double y, const double z) const;
+  void setStep (int s) {_step=s;}
+};
+
+#endif