Salome HOME
Update copyright info (2010->2011)
[plugins/blsurfplugin.git] / src / BLSURFPlugin / BLSURFPlugin_BLSURF.cxx
index 401cb483657bdfbb22765ece181b1adde48a1272..4efd4f8bd0a1d1a9b64d08fbd510b7369585c9cc 100644 (file)
@@ -1,4 +1,4 @@
-//  Copyright (C) 2007-2008  CEA/DEN, EDF R&D
+//  Copyright (C) 2007-2011  CEA/DEN, EDF R&D
 //
 //  This library is free software; you can redistribute it and/or
 //  modify it under the terms of the GNU Lesser General Public
@@ -16,6 +16,7 @@
 //
 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+
 // ---
 // File    : BLSURFPlugin_BLSURF.cxx
 // Authors : Francis KLOSS (OCC) & Patrick LAUG (INRIA) & Lioka RAZAFINDRAZAKA (CEA)
 #include "BLSURFPlugin_Hypothesis.hxx"
 
 extern "C"{
-#include "distene/blsurf.h"
 #include <distene/api.h>
+#include <distene/blsurf.h>
 }
 
 #include <structmember.h>
 
 
+#include <Basics_Utils.hxx>
+
 #include <SMESH_Gen.hxx>
 #include <SMESH_Mesh.hxx>
 #include <SMESH_ControlsDef.hxx>
+#include <SMDSAbs_ElementType.hxx>
+#include "SMESHDS_Group.hxx"
+#include "SMESH_Group.hxx"
 
 #include <utilities.h>
 
@@ -46,16 +52,12 @@ extern "C"{
 #include <set>
 #include <cstdlib>
 
+// OPENCASCADE includes
 #include <BRep_Tool.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
 #include <NCollection_Map.hxx>
-#include <Standard_ErrorHandler.hxx>
-
-extern "C"{
-#include "distene/blsurf.h"
-#include <distene/api.h>
-}
 
 #include <Geom_Surface.hxx>
 #include <Handle_Geom_Surface.hxx>
@@ -63,9 +65,18 @@ extern "C"{
 #include <Handle_Geom2d_Curve.hxx>
 #include <Geom_Curve.hxx>
 #include <Handle_Geom_Curve.hxx>
+#include <Handle_AIS_InteractiveObject.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Wire.hxx>
+#include <TopoDS_Face.hxx>
+
 #include <gp_Pnt2d.hxx>
 #include <TopTools_IndexedMapOfShape.hxx>
+#include <TopoDS_Shape.hxx>
+#include <BRep_Builder.hxx>
 #include <BRepTools.hxx>
+
 #include <TopTools_DataMapOfShapeInteger.hxx>
 #include <GProp_GProps.hxx>
 #include <BRepGProp.hxx>
@@ -74,6 +85,7 @@ extern "C"{
 #include <fenv.h>
 #endif
 
+#include <Standard_ErrorHandler.hxx>
 #include <GeomAPI_ProjectPointOnCurve.hxx>
 #include <GeomAPI_ProjectPointOnSurf.hxx>
 #include <gp_XY.hxx>
@@ -202,6 +214,7 @@ std::map<int,std::vector<double> > FaceId2AttractorCoords;
 
 TopTools_IndexedMapOfShape FacesWithEnforcedVertices;
 std::map< int, std::set< std::vector<double> > > FaceId2EnforcedVertexCoords;
+std::map< std::vector<double>, std::vector<double> > EnfVertex2ProjVertex;
 
 bool HasSizeMapOnFace=false;
 bool HasSizeMapOnEdge=false;
@@ -234,7 +247,8 @@ BLSURFPlugin_BLSURF::BLSURFPlugin_BLSURF(int hypId, int studyId,
 
   myStudy = NULL;
   myStudy = aStudyMgr->GetStudyByID(_studyId);
-  MESSAGE("myStudy->StudyId() = " << myStudy->StudyId());
+  if (myStudy)
+    MESSAGE("myStudy->StudyId() = " << myStudy->StudyId());
 
   /* Initialize the Python interpreter */
   assert(Py_IsInitialized());
@@ -262,7 +276,7 @@ BLSURFPlugin_BLSURF::BLSURFPlugin_BLSURF(int hypId, int studyId,
   FaceId2AttractorCoords.clear();
   FacesWithEnforcedVertices.Clear();
   FaceId2EnforcedVertexCoords.clear();
-
+  EnfVertex2ProjVertex.clear();
 }
 
 //=============================================================================
@@ -351,8 +365,8 @@ status_t size_on_vertex(integer vertex_id, real *size, void *user_data);
 double my_u_min=1e6,my_v_min=1e6,my_u_max=-1e6,my_v_max=-1e6;
 
 typedef struct {
-       gp_XY uv;
-       gp_XYZ xyz;
+        gp_XY uv;
+        gp_XYZ xyz;
 } projectionPoint;
 /////////////////////////////////////////////////////////
 projectionPoint getProjectionPoint(const TopoDS_Face& face, const gp_XYZ& point)
@@ -361,7 +375,7 @@ projectionPoint getProjectionPoint(const TopoDS_Face& face, const gp_XYZ& point)
   Handle(Geom_Surface) surface = BRep_Tool::Surface(face);
   GeomAPI_ProjectPointOnSurf projector( point, surface );
   if ( !projector.IsDone() || projector.NbPoints()==0 )
-    throw "Can't project";
+    throw "getProjectionPoint: Can't project";
 
   Quantity_Parameter u,v;
   projector.LowerDistanceParameters(u,v);
@@ -387,7 +401,7 @@ double getT(const TopoDS_Edge& edge, const gp_XYZ& point)
 /////////////////////////////////////////////////////////
 TopoDS_Shape BLSURFPlugin_BLSURF::entryToShape(std::string entry)
 {
-  MESSAGE("BLSURFPlugin_BLSURF::entryToShape"<<entry );
+  MESSAGE("BLSURFPlugin_BLSURF::entryToShape "<<entry );
   GEOM::GEOM_Object_var aGeomObj;
   TopoDS_Shape S = TopoDS_Shape();
   SALOMEDS::SObject_var aSObj = myStudy->FindObjectID( entry.c_str() );
@@ -405,19 +419,22 @@ TopoDS_Shape BLSURFPlugin_BLSURF::entryToShape(std::string entry)
 }
 
 /////////////////////////////////////////////////////////
-void createEnforcedVertexOnFace(TopoDS_Shape GeomShape, BLSURFPlugin_Hypothesis::TEnforcedVertexList enforcedVertexList)
+void createEnforcedVertexOnFace(TopoDS_Shape GeomShape, BLSURFPlugin_Hypothesis::TEnfVertexList enfVertexList)
 {
   double xe, ye, ze;
   std::vector<double> coords;
-  BLSURFPlugin_Hypothesis::TEnforcedVertex enforcedVertex;
-  BLSURFPlugin_Hypothesis::TEnforcedVertexList::const_iterator evlIt = enforcedVertexList.begin();
+  std::vector<double> s_coords;
+  std::vector<double> enfVertex;
+//   BLSURFPlugin_Hypothesis::TEnfVertex enfVertex;
+  BLSURFPlugin_Hypothesis::TEnfVertexList::const_iterator evlIt = enfVertexList.begin();
 
-  for( ; evlIt != enforcedVertexList.end() ; ++evlIt ) {
+  for( ; evlIt != enfVertexList.end() ; ++evlIt ) {
     coords.clear();
-    enforcedVertex = *evlIt;
-    xe = enforcedVertex[0];
-    ye = enforcedVertex[1];
-    ze = enforcedVertex[2];
+    s_coords.clear();
+    enfVertex = *evlIt;
+    xe = enfVertex[0];
+    ye = enfVertex[1];
+    ze = enfVertex[2];
     MESSAGE("Enforced Vertex: " << xe << ", " << ye << ", " << ze);
     // Get the (u,v) values of the enforced vertex on the face
     projectionPoint myPoint = getProjectionPoint(TopoDS::Face(GeomShape),gp_XYZ(xe,ye,ze));
@@ -429,12 +446,22 @@ void createEnforcedVertexOnFace(TopoDS_Shape GeomShape, BLSURFPlugin_Hypothesis:
     Standard_Real y0 = xyzPoint.Y();
     Standard_Real z0 = xyzPoint.Z();
     MESSAGE("Projected Vertex: " << x0 << ", " << y0 << ", " << z0);
+    MESSAGE("Parametric coordinates: " << u0 << ", " << v0 );
     coords.push_back(u0);
     coords.push_back(v0);
     coords.push_back(x0);
     coords.push_back(y0);
     coords.push_back(z0);
-  
+    
+    s_coords.push_back(x0);
+    s_coords.push_back(y0);
+    s_coords.push_back(z0);
+
+    // Save pair projected vertex / enf vertex
+    MESSAGE("Storing pair projected vertex / enf vertex:");
+    MESSAGE("("<< x0 << ", " << y0 << ", " << z0 <<") / (" << xe << ", " << ye << ", " << ze<<")");
+    EnfVertex2ProjVertex[s_coords] = enfVertex;
+    
     int key = 0;
     if (! FacesWithEnforcedVertices.Contains(TopoDS::Face(GeomShape))) {
       key = FacesWithEnforcedVertices.Add(TopoDS::Face(GeomShape));
@@ -565,7 +592,9 @@ void createAttractorOnFace(TopoDS_Shape GeomShape, std::string AttractorFunction
 
 /////////////////////////////////////////////////////////
 
-void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, blsurf_session_t *bls)
+void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp,
+                                        blsurf_session_t *             bls,
+                                        SMESH_Mesh&                   mesh)
 {
   int    _topology      = BLSURFPlugin_Hypothesis::GetDefaultTopology();
   int    _physicalMesh  = BLSURFPlugin_Hypothesis::GetDefaultPhysicalMesh();
@@ -609,6 +638,9 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, blsu
       }
 
   } else {
+    //0020968: EDF1545 SMESH: Problem in the creation of a mesh group on geometry
+    // GetDefaultPhySize() sometimes leads to computation failure
+    _phySize = mesh.GetShapeDiagonalSize() / _gen->GetBoundaryBoxSegmentation();
     MESSAGE("BLSURFPlugin_BLSURF::SetParameters using defaults");
   }
   _smp_phy_size = _phySize;
@@ -673,8 +705,9 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, blsu
               }
               else {
                 key = VerticesWithSizeMap.FindIndex(TopoDS::Vertex(it.Value()));
-//                 MESSAGE("Vertex with key " << key << " already in map");
+                MESSAGE("Group of vertices with key " << key << " already in map");
               }
+              MESSAGE("Group of vertices with key " << key << " has a size map: " << smIt->second);
               VertexId2SizeMap[key] = smIt->second;
             }
           }
@@ -714,8 +747,9 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, blsu
           }
           else {
             key = VerticesWithSizeMap.FindIndex(TopoDS::Vertex(GeomShape));
-//             MESSAGE("Vertex with key " << key << " already in map");
+             MESSAGE("Vertex with key " << key << " already in map");
           }
+          MESSAGE("Vertex with key " << key << " has a size map: " << smIt->second);
           VertexId2SizeMap[key] = smIt->second;
         }
       }
@@ -741,7 +775,7 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, blsu
             }
           }
         }
-               
+                
         if (GeomType == TopAbs_FACE){
           HasSizeMapOnFace = true;
           createAttractorOnFace(GeomShape, atIt->second);
@@ -767,9 +801,9 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, blsu
     // Enforced Vertices
     //
     MESSAGE("Setting Enforced Vertices");
-    const BLSURFPlugin_Hypothesis::TEnforcedVertexMap enforcedVertexMap = BLSURFPlugin_Hypothesis::GetAllEnforcedVertices(hyp);
-    BLSURFPlugin_Hypothesis::TEnforcedVertexMap::const_iterator enfIt = enforcedVertexMap.begin();
-    for ( ; enfIt != enforcedVertexMap.end(); ++enfIt ) {
+    const BLSURFPlugin_Hypothesis::TEntryEnfVertexListMap entryEnfVertexListMap = BLSURFPlugin_Hypothesis::GetAllEnforcedVertices(hyp);
+    BLSURFPlugin_Hypothesis::TEntryEnfVertexListMap::const_iterator enfIt = entryEnfVertexListMap.begin();
+    for ( ; enfIt != entryEnfVertexListMap.end(); ++enfIt ) {
       if ( !enfIt->second.empty() ) {
         GeomShape = entryToShape(enfIt->first);
         GeomType  = GeomShape.ShapeType();
@@ -818,8 +852,9 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, blsu
 
 status_t curv_fun(real t, real *uv, real *dt, real *dtt, void *user_data);
 status_t surf_fun(real *uv, real *xyz, real*du, real *dv,
-                 real *duu, real *duv, real *dvv, void *user_data);
-status_t message_callback(message_t *msg, void *user_data);
+                  real *duu, real *duv, real *dvv, void *user_data);
+status_t message_cb(message_t *msg, void *user_data);
+status_t interrupt_cb(integer *interrupt_status, void *user_data);
 
 //=============================================================================
 /*!
@@ -831,16 +866,26 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
 
   MESSAGE("BLSURFPlugin_BLSURF::Compute");
 
-  if (aShape.ShapeType() == TopAbs_COMPOUND) {
-    MESSAGE("  the shape is a COMPOUND");
-  }
-  else {
-    MESSAGE("  the shape is UNKNOWN");
-  };
+//   if (aShape.ShapeType() == TopAbs_COMPOUND) {
+//     MESSAGE("  the shape is a COMPOUND");
+//   }
+//   else {
+//     MESSAGE("  the shape is UNKNOWN");
+//   };
 
+  // Fix problem with locales
+  Kernel_Utils::Localizer loc;
+
+  /* create a distene context (generic object) */
+  status_t status = STATUS_ERROR;
+  
   context_t *ctx =  context_new();
-  context_set_message_callback(ctx, message_callback, &_comment);
+  
+  /* Set the message callback in the working context */
+  context_set_message_callback(ctx, message_cb, &_comment);
+  context_set_interrupt_callback(ctx, interrupt_cb, NULL);
 
+  /* create the CAD object we will work on. It is associated to the context ctx. */
   cad_t *c = cad_new(ctx);
 
   blsurf_session_t *bls = blsurf_session_new(ctx);
@@ -853,23 +898,31 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
   VertexId2SizeMap.clear();
 
   MESSAGE("BEGIN SetParameters");
-  SetParameters(_hypothesis, bls);
+  SetParameters(_hypothesis, bls, aMesh);
   MESSAGE("END SetParameters");
 
-  TopTools_IndexedMapOfShape fmap;
-  TopTools_IndexedMapOfShape emap;
-  TopTools_IndexedMapOfShape pmap;
+  /* Now fill the CAD object with data from your CAD
+   * environement. This is the most complex part of a successfull
+   * integration.
+   */
+
+  // needed to prevent the opencascade memory managmement from freeing things
   vector<Handle(Geom2d_Curve)> curves;
   vector<Handle(Geom_Surface)> surfaces;
 
+  surfaces.resize(0);
+  curves.resize(0);
+  
+  TopTools_IndexedMapOfShape fmap;
+  TopTools_IndexedMapOfShape emap;
+  TopTools_IndexedMapOfShape pmap;
+  
   fmap.Clear();
   FaceId2PythonSmp.clear();
   emap.Clear();
   EdgeId2PythonSmp.clear();
   pmap.Clear();
   VertexId2PythonSmp.clear();
-  surfaces.resize(0);
-  curves.resize(0);
 
   assert(Py_IsInitialized());
   PyGILState_STATE gstate;
@@ -883,8 +936,13 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
   int iface = 0;
   string bad_end = "return";
   int faceKey = -1;
+  int ienf = 0;
   for (TopExp_Explorer face_iter(aShape,TopAbs_FACE);face_iter.More();face_iter.Next()) {
     TopoDS_Face f=TopoDS::Face(face_iter.Current());
+
+    // make INTERNAL face oriented FORWARD (issue 0020993)
+    if (f.Orientation() != TopAbs_FORWARD && f.Orientation() != TopAbs_REVERSED )
+      f.Orientation(TopAbs_FORWARD);
     
     if (fmap.FindIndex(f) > 0)
       continue;
@@ -892,9 +950,19 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
     fmap.Add(f);
     iface++;
     surfaces.push_back(BRep_Tool::Surface(f));
-
+    
+    /* create an object representing the face for blsurf */
+    /* where face_id is an integer identifying the face.
+     * surf_function is the function that defines the surface
+     * (For this face, it will be called by blsurf with your_face_object_ptr
+     * as last parameter.
+     */
     cad_face_t *fce = cad_face_new(c, iface, surf_fun, surfaces.back());
+    
+    /* by default a face has no tag (color). The following call sets it to the same value as the face_id : */
     cad_face_set_tag(fce, iface);
+      
+    /* Set face orientation (optional if you want a well oriented output mesh)*/
     if(f.Orientation() != TopAbs_FORWARD){
       cad_face_set_orientation(fce, CAD_ORIENTATION_REVERSED);
     } else {
@@ -902,7 +970,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
     }
     
     if (HasSizeMapOnFace){
-      std::cout << "A size map is defined on a face" << std::endl;
+//       std::cout << "A size map is defined on a face" << std::endl;
       // Classic size map
       faceKey = FacesWithSizeMap.FindIndex(f);
       
@@ -965,22 +1033,21 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
       faceKey = FacesWithEnforcedVertices.FindIndex(f);
       std::map<int,std::set<std::vector<double> > >::const_iterator evmIt = FaceId2EnforcedVertexCoords.find(faceKey);
       if (evmIt != FaceId2EnforcedVertexCoords.end()) {
-        std::cout << "Some enforced vertices are defined" << std::endl;
-        int ienf = 0;
+        MESSAGE("Some enforced vertices are defined");
+//         int ienf = 0;
         std::set<std::vector<double> > evl;
 //         std::vector<double> ev;
         MESSAGE("Face indice: " << iface);
         MESSAGE("Adding enforced vertices");
         evl = evmIt->second;
-        MESSAGE("Number of vertices to add: "<< evl.size())
+        MESSAGE("Number of vertices to add: "<< evl.size());
         std::set< std::vector<double> >::const_iterator evlIt = evl.begin();
         for (; evlIt != evl.end(); ++evlIt) {
-//           ev = *evlIt;
-//         for (int i=0; i<evl.size() ; i++) {
-//           ev = evl[i];
-          
-//           double xyzCoords[3]  = {ev[2], ev[3], ev[4]};
-          double xyzCoords[3]  = {evlIt->at(0), evlIt->at(3), evlIt->at(4)};
+          std::vector<double> xyzCoords;
+          xyzCoords.push_back(evlIt->at(2));
+          xyzCoords.push_back(evlIt->at(3));
+          xyzCoords.push_back(evlIt->at(4));
+//           double xyzCoords[3]  = {evlIt->at(2), evlIt->at(3), evlIt->at(4)};
           MESSAGE("Check position of vertex =(" << xyzCoords[0] << "," << xyzCoords[1] << "," << xyzCoords[2] << ")");
           gp_Pnt P(xyzCoords[0],xyzCoords[1],xyzCoords[2]);
           BRepClass_FaceClassifier scl(f,P,1e-7);
@@ -989,12 +1056,21 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
           BRepClass_FaceClassifierPerform(&scl,f,P,1e-7);
           TopAbs_State result = scl.State();
           MESSAGE("Position of point on face: "<<result);
-          if ( result == TopAbs_OUT )
+          if ( result == TopAbs_OUT ) {
               MESSAGE("Point is out of face: node is not created");
-          if ( result == TopAbs_UNKNOWN )
-              MESSAGE("Point position on face is unknown: node is not created");
-          if ( result == TopAbs_ON )
-              MESSAGE("Point is on border of face: node is not created");
+              if (EnfVertex2ProjVertex.find(xyzCoords) != EnfVertex2ProjVertex.end())
+                EnfVertex2ProjVertex.erase(xyzCoords);
+          }
+          if ( result == TopAbs_UNKNOWN ) {
+            MESSAGE("Point position on face is unknown: node is not created");
+            if (EnfVertex2ProjVertex.find(xyzCoords) != EnfVertex2ProjVertex.end())
+              EnfVertex2ProjVertex.erase(xyzCoords);
+          }
+          if ( result == TopAbs_ON ) {
+            MESSAGE("Point is on border of face: node is not created");
+            if (EnfVertex2ProjVertex.find(xyzCoords) != EnfVertex2ProjVertex.end())
+              EnfVertex2ProjVertex.erase(xyzCoords);
+          }
           if ( result == TopAbs_IN )
           {
             // Point is inside face and not on border
@@ -1009,13 +1085,14 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
         }
         FaceId2EnforcedVertexCoords.erase(faceKey);
       }
-      else
-        std::cout << "No enforced vertex defined" << std::endl;
+//       else
+//         std::cout << "No enforced vertex defined" << std::endl;
     }
     
     
     /****************************************************************************************
                                     EDGES
+                   now create the edges associated to this face
     *****************************************************************************************/
     int edgeKey = -1;
     for (TopExp_Explorer edge_iter(f,TopAbs_EDGE);edge_iter.More();edge_iter.Next()) {
@@ -1030,7 +1107,8 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
       if (HasSizeMapOnEdge){
         edgeKey = EdgesWithSizeMap.FindIndex(e);
         if (EdgeId2SizeMap.find(edgeKey)!=EdgeId2SizeMap.end()) {
-          theSizeMapStr = EdgeId2SizeMap[faceKey];
+          MESSAGE("Sizemap defined on edge with index " << edgeKey);
+          theSizeMapStr = EdgeId2SizeMap[edgeKey];
           if (theSizeMapStr.find(bad_end) == (theSizeMapStr.size()-bad_end.size()-1))
             continue;
           // Expr To Python function, verification is performed at validation in GUI
@@ -1043,9 +1121,19 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
           EdgeId2SizeMap.erase(edgeKey);
         }
       }
+      
+      /* attach the edge to the current blsurf face */
       cad_edge_t *edg = cad_edge_new(fce, ic, tmin, tmax, curv_fun, curves.back());
+      
+      /* by default an edge has no tag (color). The following call sets it to the same value as the edge_id : */
       cad_edge_set_tag(edg, ic);
+      
+      /* by default, an edge does not necessalry appear in the resulting mesh,
+     unless the following property is set :
+      */
       cad_edge_set_property(edg, EDGE_PROPERTY_SOFT_REQUIRED);
+      
+      /* by default an edge is a boundary edge */
       if (e.Orientation() == TopAbs_INTERNAL)
         cad_edge_set_property(edg, EDGE_PROPERTY_INTERNAL);
 
@@ -1074,11 +1162,12 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
         if(*ip <= 0)
           *ip = pmap.Add(v);
         
-        vertexKey = VerticesWithSizeMap.FindIndex(v);
+        //vertexKey = VerticesWithSizeMap.FindIndex(v);
         if (HasSizeMapOnVertex){
           vertexKey = VerticesWithSizeMap.FindIndex(v);
           if (VertexId2SizeMap.find(vertexKey)!=VertexId2SizeMap.end()){
-            theSizeMapStr = VertexId2SizeMap[faceKey];
+            theSizeMapStr = VertexId2SizeMap[vertexKey];
+            //MESSAGE("VertexId2SizeMap[faceKey]: " << VertexId2SizeMap[vertexKey]);
             if (theSizeMapStr.find(bad_end) == (theSizeMapStr.size()-bad_end.size()-1))
               continue;
             // Expr To Python function, verification is performed at validation in GUI
@@ -1088,7 +1177,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
             PyObject * func = NULL;
             func = PyObject_GetAttrString(main_mod, "f");
             VertexId2PythonSmp[*ip]=func;
-//             VertexId2SizeMap.erase(vertexKey);   // do not erase if using a vector
+            VertexId2SizeMap.erase(vertexKey);   // do not erase if using a vector
           }
         }
       }
@@ -1096,10 +1185,16 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
         // should not happen
         MESSAGE("An edge does not have 2 extremities.");
       } else {
-        if (d1 < d2)
+        if (d1 < d2) {
+          // This defines the curves extremity connectivity
           cad_edge_set_extremities(edg, ip1, ip2);
-        else
+          /* set the tag (color) to the same value as the extremity id : */
+          cad_edge_set_extremities_tag(edg, ip1, ip2);
+        }
+        else {
           cad_edge_set_extremities(edg, ip2, ip1);
+          cad_edge_set_extremities_tag(edg, ip2, ip1);
+        }
       }
     } // for edge
   } //for face
@@ -1119,8 +1214,6 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
   int oldFEFlags = fedisableexcept( FE_ALL_EXCEPT );
 #endif
 
-  status_t status = STATUS_ERROR;
-
   try {
     OCC_CATCH_SIGNALS;
 
@@ -1142,6 +1235,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
       _comment = "Exception in blsurf_compute_mesh()";
   }
   if ( status != STATUS_OK) {
+    // There was an error while meshing
     blsurf_session_delete(bls);
     cad_delete(c);
     context_delete(ctx);
@@ -1153,7 +1247,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
   std::cout << "End of Surface Mesh generation" << std::endl;
   std::cout << std::endl;
 
-  mesh_t *msh;
+  mesh_t *msh = NULL;
   blsurf_data_get_mesh(bls, &msh);
   if(!msh){
     blsurf_session_delete(bls);
@@ -1164,6 +1258,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
     //return false;
   }
 
+  /* retrieve mesh data (see distene/mesh.h) */
   integer nv, ne, nt, nq, vtx[4], tag;
   real xyz[3];
 
@@ -1177,12 +1272,92 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
   SMDS_MeshNode** nodes = new SMDS_MeshNode*[nv+1];
   bool* tags = new bool[nv+1];
 
+  /* enumerated vertices */
   for(int iv=1;iv<=nv;iv++) {
     mesh_get_vertex_coordinates(msh, iv, xyz);
     mesh_get_vertex_tag(msh, iv, &tag);
+    // Issue 0020656. Use vertex coordinates
+    if ( tag > 0 && tag <= pmap.Extent() ) {
+      TopoDS_Vertex v = TopoDS::Vertex(pmap(tag));
+      double tol = BRep_Tool::Tolerance( v );
+      gp_Pnt p = BRep_Tool::Pnt( v );
+      if ( p.IsEqual( gp_Pnt( xyz[0], xyz[1], xyz[2]), 2*tol))
+        xyz[0] = p.X(), xyz[1] = p.Y(), xyz[2] = p.Z();
+      else
+        tag = 0; // enforced or attracted vertex
+    }
     nodes[iv] = meshDS->AddNode(xyz[0], xyz[1], xyz[2]);
+
+    /* TODO GROUPS
+    // Create group of enforced vertices if requested
+    if(_hypothesis) {
+      std::vector<double> projVertex;
+      projVertex.push_back((double)xyz[0]);
+      projVertex.push_back((double)xyz[1]);
+      projVertex.push_back((double)xyz[2]);
+      std::map< std::vector<double>, std::vector<double> >::const_iterator projIt = EnfVertex2ProjVertex.find(projVertex);
+      if (projIt != EnfVertex2ProjVertex.end()) {
+        double x = (projIt->second)[0];
+        double y = (projIt->second)[1];
+        double z = (projIt->second)[2];
+        BLSURFPlugin_Hypothesis::TEnfVertex enfVertex;
+        enfVertex.push_back(x);
+        enfVertex.push_back(y);
+        enfVertex.push_back(z);
+          
+        BLSURFPlugin_Hypothesis::TEnfVertexGroupNameMap groupNameMap =  _hypothesis->_GetEnforcedVertexGroupNameMap();
+        BLSURFPlugin_Hypothesis::TEnfVertexGroupNameMap::const_iterator groupNameMapIt = groupNameMap.find(enfVertex);
+        if (groupNameMapIt != groupNameMap.end()) {
+          MESSAGE("Found enforced vertex @ " << xyz[0] << ", " << xyz[1] << ", " << xyz[2])
+          BLSURFPlugin_Hypothesis::TEnfGroupName groupName = groupNameMapIt->second;
+          if (groupName != "") {
+            bool groupDone = false;
+            const set<SMESHDS_GroupBase*>& allGroups = meshDS->GetGroups();
+            set<SMESHDS_GroupBase*>::const_iterator grIt;
+            MESSAGE("Parsing the groups of the mesh");
+            for ( grIt = allGroups.begin(); grIt != allGroups.end(); ++grIt ) {
+              SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
+              MESSAGE("Group: " << group->GetStoreName());
+              if ( group && group->SMDSGroup().GetType()==SMDSAbs_Node
+                          && groupName.compare(group->GetStoreName())==0) {
+                group->SMDSGroup().Add(nodes[iv]);
+//                 int id = // recuperer l'id SMESH du noeud
+//                 _hypothesis->AddEnfVertexIDs(groupName,id)
+                groupDone = true;
+                MESSAGE("Successfully added enforced vertex to existing group " << groupName);
+                break;
+              }
+            }
+            if (!groupDone)
+            {
+              int groupId;
+              SMESH_Group* aGroup = aMesh.AddGroup(SMDSAbs_Node, groupName.c_str(), groupId);
+              if ( aGroup ) {
+                SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
+                if ( aGroupDS ) {
+                  aGroupDS->SetStoreName( groupName.c_str() );
+                  aGroupDS->SMDSGroup().Add(nodes[iv]);
+                  MESSAGE("Successfully created enforced vertex group " << groupName);
+                  groupDone = true;
+                }
+              }
+            }
+            if (!groupDone)
+              throw SALOME_Exception(LOCALIZED("A enforced vertex node was not added to a group"));
+          }
+          else
+            MESSAGE("Group name is empty: '"<<groupName<<"' => group is not created");
+        }
+        else
+          MESSAGE("No group name for projected vertex ("<<x<<","<<y<<","<<z<<")")
+      }
+//       else
+//         MESSAGE("No group name for vertex ("<<xyz[0]<<","<<xyz[1]<<","<<xyz[2]<<")")
+    }
+    */
+
     // internal point are tagged to zero
-    if(tag){
+    if(tag > 0 && tag <= pmap.Extent() ){
       meshDS->SetNodeOnVertex(nodes[iv], TopoDS::Vertex(pmap(tag)));
       tags[iv] = false;
     } else {
@@ -1190,6 +1365,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
     }
   }
 
+  /* enumerate edges */
   for(int it=1;it<=ne;it++) {
     mesh_get_edge_vertices(msh, it, vtx);
     SMDS_MeshEdge* edg = meshDS->AddEdge(nodes[vtx[0]], nodes[vtx[1]]);
@@ -1207,6 +1383,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
 
   }
 
+  /* enumerate triangles */
   for(int it=1;it<=nt;it++) {
     mesh_get_triangle_vertices(msh, it, vtx);
     SMDS_MeshFace* tri = meshDS->AddFace(nodes[vtx[0]], nodes[vtx[1]], nodes[vtx[2]]);
@@ -1226,6 +1403,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
     };
   }
 
+  /* enumerate quadrangles */
   for(int it=1;it<=nq;it++) {
     mesh_get_quadrangle_vertices(msh, it, vtx);
     SMDS_MeshFace* quad = meshDS->AddFace(nodes[vtx[0]], nodes[vtx[1]], nodes[vtx[2]], nodes[vtx[3]]);
@@ -1266,7 +1444,8 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
     feenableexcept( oldFEFlags );
   feclearexcept( FE_ALL_EXCEPT );
 #endif
-  
+
+  /*  
   std::cout << "FacesWithSizeMap" << std::endl;
   FacesWithSizeMap.Statistics(std::cout);
   std::cout << "EdgesWithSizeMap" << std::endl;
@@ -1275,6 +1454,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
   VerticesWithSizeMap.Statistics(std::cout);
   std::cout << "FacesWithEnforcedVertices" << std::endl;
   FacesWithEnforcedVertices.Statistics(std::cout);
+  */
   
   return true;
 }
@@ -1292,15 +1472,29 @@ void BLSURFPlugin_BLSURF::Set_NodeOnEdge(SMESHDS_Mesh* meshDS, SMDS_MeshNode* no
 
   Standard_Real p0 = 0.0;
   Standard_Real p1 = 1.0;
-  Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, p0, p1);
-
-  GeomAPI_ProjectPointOnCurve proj(pnt, curve);
+  TopLoc_Location loc;
+  Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, loc, p0, p1);
 
-  double pa = (double)proj.Parameter(1);
+  if ( !loc.IsIdentity() ) pnt.Transform( loc.Transformation().Inverted() );
+  GeomAPI_ProjectPointOnCurve proj(pnt, curve, p0, p1);
 
-  GProp_GProps LProps;
-  BRepGProp::LinearProperties(ed, LProps);
-  double lg = (double)LProps.Mass();
+  double pa = 0.;
+  if ( proj.NbPoints() > 0 )
+  {
+    pa = (double)proj.LowerDistanceParameter();
+    // Issue 0020656. Move node if it is too far from edge
+    gp_Pnt curve_pnt = curve->Value( pa );
+    double dist2 = pnt.SquareDistance( curve_pnt );
+    double tol = BRep_Tool::Tolerance( edge );
+    if ( 1e-12 < dist2 && dist2 <= 2*tol*tol ) // large enough and within tolerance
+    {
+      curve_pnt.Transform( loc );
+      meshDS->MoveNode( node, curve_pnt.X(), curve_pnt.Y(), curve_pnt.Z() );
+    }
+  }
+//   GProp_GProps LProps;
+//   BRepGProp::LinearProperties(ed, LProps);
+//   double lg = (double)LProps.Mass();
 
   meshDS->SetNodeOnEdge(node, edge, pa);
 }
@@ -1349,34 +1543,61 @@ istream & operator >> (istream & load, BLSURFPlugin_BLSURF & hyp)
   return hyp.LoadFrom( load );
 }
 
+/* Curve definition function See cad_curv_t in file distene/cad.h for
+ * more information.
+ * NOTE : if when your CAD systems evaluates second
+ * order derivatives it also computes first order derivatives and
+ * function evaluation, you can optimize this example by making only
+ * one CAD call and filling the necessary uv, dt, dtt arrays.
+ */
 status_t curv_fun(real t, real *uv, real *dt, real *dtt, void *user_data)
 {
+  /* t is given. It contains the t (time) 1D parametric coordintaes
+     of the point PreCAD/BLSurf is querying on the curve */
+  
+  /* user_data identifies the edge PreCAD/BLSurf is querying
+   * (see cad_edge_new later in this example) */
   const Geom2d_Curve*pargeo = (const Geom2d_Curve*) user_data;
 
   if (uv){
+   /* BLSurf is querying the function evaluation */
     gp_Pnt2d P;
     P=pargeo->Value(t);
     uv[0]=P.X(); uv[1]=P.Y();
   }
 
   if(dt) {
+   /* query for the first order derivatives */
     gp_Vec2d V1;
     V1=pargeo->DN(t,1);
     dt[0]=V1.X(); dt[1]=V1.Y();
   }
 
   if(dtt){
+    /* query for the second order derivatives */
     gp_Vec2d V2;
     V2=pargeo->DN(t,2);
     dtt[0]=V2.X(); dtt[1]=V2.Y();
   }
 
-  return 0;
+  return STATUS_OK;
 }
 
+/* Surface definition function.
+ * See cad_surf_t in file distene/cad.h for more information.
+ * NOTE : if when your CAD systems evaluates second order derivatives it also
+ * computes first order derivatives and function evaluation, you can optimize 
+ * this example by making only one CAD call and filling the necessary xyz, du, dv, etc.. 
+ * arrays.
+ */
 status_t surf_fun(real *uv, real *xyz, real*du, real *dv,
-                 real *duu, real *duv, real *dvv, void *user_data)
+                  real *duu, real *duv, real *dvv, void *user_data)
 {
+  /* uv[2] is given. It contains the u,v coordinates of the point
+   * PreCAD/BLSurf is querying on the surface */
+  
+  /* user_data identifies the face PreCAD/BLSurf is querying (see
+   * cad_face_new later in this example)*/
   const Geom_Surface* geometry = (const Geom_Surface*) user_data;
 
   if(xyz){
@@ -1395,6 +1616,7 @@ status_t surf_fun(real *uv, real *xyz, real*du, real *dv,
   }
 
   if(duu && duv && dvv){
+
     gp_Pnt P;
     gp_Vec D1U,D1V;
     gp_Vec D2U,D2V,D2UV;
@@ -1405,7 +1627,7 @@ status_t surf_fun(real *uv, real *xyz, real*du, real *dv,
     dvv[0]=D2V.X(); dvv[1]=D2V.Y(); dvv[2]=D2V.Z();
   }
 
-  return 0;
+  return STATUS_OK;
 }
 
 
@@ -1527,7 +1749,12 @@ status_t size_on_vertex(integer point_id, real *size, void *user_data)
  return STATUS_OK;
 }
 
-status_t message_callback(message_t *msg, void *user_data)
+/*
+ * The following function will be called for PreCAD/BLSurf message
+ * printing.  See context_set_message_callback (later in this
+ * template) for how to set user_data.
+ */
+status_t message_cb(message_t *msg, void *user_data)
 {
   integer errnumber = 0;
   char *desc;
@@ -1549,27 +1776,43 @@ status_t message_callback(message_t *msg, void *user_data)
   return STATUS_OK;
 }
 
+/* This is the interrupt callback. PreCAD/BLSurf will call this
+ * function regularily. See the file distene/interrupt.h
+ */
+status_t interrupt_cb(integer *interrupt_status, void *user_data)
+{
+  integer you_want_to_continue = 1;
+
+  if(you_want_to_continue)
+    *interrupt_status = INTERRUPT_CONTINUE;
+  else /* you want to stop BLSurf */
+    *interrupt_status = INTERRUPT_STOP;
+  
+  return STATUS_OK;
+}
 
 //=============================================================================
 /*!
  *  
  */
 //=============================================================================
-bool BLSURFPlugin_BLSURF::Evaluate(SMESH_Mesh& aMesh,
-                                  const TopoDS_Shape& aShape,
-                                  MapShapeNbElems& aResMap)
+bool BLSURFPlugin_BLSURF::Evaluate(SMESH_Mesh&         aMesh,
+                                   const TopoDS_Shape& aShape,
+                                   MapShapeNbElems&    aResMap)
 {
   int    _physicalMesh  = BLSURFPlugin_Hypothesis::GetDefaultPhysicalMesh();
   double _phySize       = BLSURFPlugin_Hypothesis::GetDefaultPhySize();
   //int    _geometricMesh = BLSURFPlugin_Hypothesis::GetDefaultGeometricMesh();
   //double _angleMeshS    = BLSURFPlugin_Hypothesis::GetDefaultAngleMeshS();
   double _angleMeshC    = BLSURFPlugin_Hypothesis::GetDefaultAngleMeshC();
+  bool   _quadAllowed   = BLSURFPlugin_Hypothesis::GetDefaultQuadAllowed();
   if(_hypothesis) {
     _physicalMesh  = (int) _hypothesis->GetPhysicalMesh();
     _phySize       = _hypothesis->GetPhySize();
     //_geometricMesh = (int) hyp->GetGeometricMesh();
     //_angleMeshS    = hyp->GetAngleMeshS();
     _angleMeshC    = _hypothesis->GetAngleMeshC();
+    _quadAllowed   = _hypothesis->GetQuadAllowed();
   }
 
   bool IsQuadratic = false;
@@ -1602,11 +1845,11 @@ bool BLSURFPlugin_BLSURF::Evaluate(SMESH_Mesh& aMesh,
       C->D0(f+dp,P2);
       gp_Vec V1(P1,P2);
       for(int j=2; j<=200; j++) {
-       C->D0(f+dp*j,P3);
-       gp_Vec V2(P2,P3);
-       fullAng += fabs(V1.Angle(V2));
-       V1 = V2;
-       P2 = P3;
+        C->D0(f+dp*j,P3);
+        gp_Vec V2(P2,P3);
+        fullAng += fabs(V1.Angle(V2));
+        V1 = V2;
+        P2 = P3;
       }
       nb1d = (int)( fullAng/_angleMeshC + 1 );
     }
@@ -1636,21 +1879,40 @@ bool BLSURFPlugin_BLSURF::Evaluate(SMESH_Mesh& aMesh,
     BRepGProp::SurfaceProperties(F,G);
     double anArea = G.Mass();
     int nb1d = 0;
+    std::vector<int> nb1dVec;
     for (TopExp_Explorer exp1(F,TopAbs_EDGE); exp1.More(); exp1.Next()) {
-      nb1d += EdgesMap.Find(exp1.Current());
+      int nbSeg = EdgesMap.Find(exp1.Current());
+      nb1d += nbSeg;
+      nb1dVec.push_back( nbSeg );
     }
-    int nbFaces = (int) ( anArea/( ELen*ELen*sqrt(3.) / 4 ) );
-    int nbNodes = (int) ( ( nbFaces*3 - (nb1d-1)*2 ) / 6 + 1 );
-    std::vector<int> aVec(SMDSEntity_Last);
-    for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
+    int nbQuad = 0;
+    int nbTria = (int) ( anArea/( ELen*ELen*sqrt(3.) / 4 ) );
+    int nbNodes = (int) ( ( nbTria*3 - (nb1d-1)*2 ) / 6 + 1 );
+    if ( _quadAllowed )
+    {
+      if ( nb1dVec.size() == 4 ) // quadrangle geom face
+      {
+        int n1 = nb1dVec[0], n2 = nb1dVec[ nb1dVec[1] == nb1dVec[0] ? 2 : 1 ];
+        nbQuad = n1 * n2;
+        nbNodes = (n1 + 1) * (n2 + 1);
+        nbTria = 0;
+      }
+      else
+      {
+        nbTria = nbQuad = nbTria / 3 + 1;
+      }
+    }
+    std::vector<int> aVec(SMDSEntity_Last,0);
     if( IsQuadratic ) {
-      int nb1d_in = (nbFaces*3 - nb1d) / 2;
+      int nb1d_in = (nbTria*3 - nb1d) / 2;
       aVec[SMDSEntity_Node] = nbNodes + nb1d_in;
-      aVec[SMDSEntity_Quad_Triangle] = nbFaces;
+      aVec[SMDSEntity_Quad_Triangle] = nbTria;
+      aVec[SMDSEntity_Quad_Quadrangle] = nbQuad;
     }
     else {
       aVec[SMDSEntity_Node] = nbNodes;
-      aVec[SMDSEntity_Triangle] = nbFaces;
+      aVec[SMDSEntity_Triangle] = nbTria;
+      aVec[SMDSEntity_Quadrangle] = nbQuad;
     }
     aResMap.insert(std::make_pair(sm,aVec));
   }
@@ -1662,8 +1924,8 @@ bool BLSURFPlugin_BLSURF::Evaluate(SMESH_Mesh& aMesh,
   BRepGProp::VolumeProperties(aShape,G);
   double aVolume = G.Mass();
   double tetrVol = 0.1179*ELen*ELen*ELen;
-  int nbVols = (int)aVolume/tetrVol;
-  int nb1d_in = (int) ( ( nbVols*6 - fullNbSeg ) / 6 );
+  int nbVols  = int(aVolume/tetrVol);
+  int nb1d_in = int(( nbVols*6 - fullNbSeg ) / 6 );
   std::vector<int> aVec(SMDSEntity_Last);
   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
   if( IsQuadratic ) {