From f05a271c37e85153784227c0f238d57edd3b3181 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Wed, 17 Jul 2013 11:03:15 +0000
Subject: [PATCH] first pass at CELUM file format

---
 Common/CreateFile.cpp  |   7 +++
 Common/GmshDefines.h   |   1 +
 Fltk/graphicWindow.cpp |   4 ++
 Geo/CMakeLists.txt     |   2 +-
 Geo/GModel.h           |   4 ++
 Geo/GModelIO_CELUM.cpp | 120 +++++++++++++++++++++++++++++++++++++++++
 Geo/gmshFace.cpp       |   2 +-
 7 files changed, 138 insertions(+), 2 deletions(-)
 create mode 100644 Geo/GModelIO_CELUM.cpp

diff --git a/Common/CreateFile.cpp b/Common/CreateFile.cpp
index 1345fbe1af..89cf2a95ec 100644
--- a/Common/CreateFile.cpp
+++ b/Common/CreateFile.cpp
@@ -46,6 +46,7 @@ int GetFileFormatFromExtension(const std::string &ext)
   else if(ext == ".bdf")  return FORMAT_BDF;
   else if(ext == ".diff") return FORMAT_DIFF;
   else if(ext == ".inp")  return FORMAT_INP;
+  else if(ext == ".celum")return FORMAT_CELUM;
   else if(ext == ".nas")  return FORMAT_BDF;
   else if(ext == ".p3d")  return FORMAT_P3D;
   else if(ext == ".wrl")  return FORMAT_VRML;
@@ -99,6 +100,7 @@ std::string GetDefaultFileName(int format)
   case FORMAT_BDF:  name += ".bdf"; break;
   case FORMAT_DIFF: name += ".diff"; break;
   case FORMAT_INP:  name += ".inp"; break;
+  case FORMAT_CELUM:name += ".celum"; break;
   case FORMAT_P3D:  name += ".p3d"; break;
   case FORMAT_VRML: name += ".wrl"; break;
   case FORMAT_PLY2: name += ".ply2"; break;
@@ -311,6 +313,11 @@ void CreateOutputFile(const std::string &fileName, int format, bool redraw)
        CTX::instance()->mesh.scalingFactor);
     break;
 
+  case FORMAT_CELUM:
+    GModel::current()->writeCELUM
+      (name, CTX::instance()->mesh.saveAll, CTX::instance()->mesh.scalingFactor);
+    break;
+
   case FORMAT_P3D:
     GModel::current()->writeP3D
       (name, CTX::instance()->mesh.saveAll, CTX::instance()->mesh.scalingFactor);
diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h
index 5217a9215f..0eb368dd1a 100644
--- a/Common/GmshDefines.h
+++ b/Common/GmshDefines.h
@@ -47,6 +47,7 @@
 #define FORMAT_IR3   38
 #define FORMAT_INP   39
 #define FORMAT_PLY2  40
+#define FORMAT_CELUM 41
 
 // Element types
 #define TYPE_PNT     1
diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp
index 9b76308953..26f5d28753 100644
--- a/Fltk/graphicWindow.cpp
+++ b/Fltk/graphicWindow.cpp
@@ -270,6 +270,8 @@ static int _save_diff(const char *name){ return genericMeshFileDialog
     (name, "Diffpack Options", FORMAT_DIFF, true, false); }
 static int _save_inp(const char *name){ return unvinpFileDialog
     (name, "Abaqus INP Options", FORMAT_INP); }
+static int _save_celum(const char *name){ return genericMeshFileDialog
+    (name, "CELUM Options", FORMAT_CELUM, false, false); }
 static int _save_med(const char *name){ return genericMeshFileDialog
     (name, "MED Options", FORMAT_MED, false, false); }
 static int _save_mesh(const char *name){ return genericMeshFileDialog
@@ -332,6 +334,7 @@ static int _save_auto(const char *name)
   case FORMAT_BDF  : return _save_bdf(name);
   case FORMAT_DIFF : return _save_diff(name);
   case FORMAT_INP  : return _save_inp(name);
+  case FORMAT_CELUM: return _save_celum(name);
   case FORMAT_P3D  : return _save_p3d(name);
   case FORMAT_IR3  : return _save_ir3(name);
   case FORMAT_STL  : return _save_stl(name);
@@ -371,6 +374,7 @@ static void file_save_as_cb(Fl_Widget *w, void *data)
 #endif
     {"Mesh - Gmsh MSH" TT "*.msh", _save_msh},
     {"Mesh - Abaqus INP" TT "*.inp", _save_inp},
+    {"Mesh - CELUM" TT "*.celum", _save_celum},
 #if defined(HAVE_LIBCGNS)
     {"Mesh - CGNS (Experimental)" TT "*.cgns", _save_cgns},
 #endif
diff --git a/Geo/CMakeLists.txt b/Geo/CMakeLists.txt
index 07ac19e7eb..2f9474c13c 100644
--- a/Geo/CMakeLists.txt
+++ b/Geo/CMakeLists.txt
@@ -26,7 +26,7 @@ set(SRC
       GModelIO_CGNS.cpp GModelIO_MED.cpp GModelIO_MESH.cpp GModelIO_STL.cpp 
       GModelIO_PLY.cpp GModelIO_VRML.cpp GModelIO_UNV.cpp GModelIO_BDF.cpp 
       GModelIO_IR3.cpp GModelIO_DIFF.cpp GModelIO_GEOM.cpp GModelIO_INP.cpp
-      GModelIO_MAIL.cpp GModelIO_P3D.cpp GModelIO_SGEOM.cpp
+      GModelIO_MAIL.cpp GModelIO_P3D.cpp GModelIO_SGEOM.cpp GModelIO_CELUM.cpp
   ExtrudeParams.cpp
   Geo.cpp
   GeoStringInterface.cpp GeoInterpolation.cpp
diff --git a/Geo/GModel.h b/Geo/GModel.h
index d6d8ab132a..98dd7bf120 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -697,6 +697,10 @@ class GModel
   int writeINP(const std::string &name, bool saveAll=false,
                bool saveGroupsOfNodes=false, double scalingFactor=1.0);
 
+  // CELUM
+  int writeCELUM(const std::string &name, bool saveAll=false,
+                 double scalingFactor=1.0);
+
   // Geomview mesh
   int readGEOM(const std::string &name);
 
diff --git a/Geo/GModelIO_CELUM.cpp b/Geo/GModelIO_CELUM.cpp
new file mode 100644
index 0000000000..38b7263cc2
--- /dev/null
+++ b/Geo/GModelIO_CELUM.cpp
@@ -0,0 +1,120 @@
+// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh@geuz.org>.
+
+#include "GModel.h"
+#include "OS.h"
+#include "MTriangle.h"
+#include "MQuadrangle.h"
+
+class CelumInfo{
+public:
+  SVector3 normal, dirMax, dirMin;
+  double curvMax, curvMin;
+};
+
+int GModel::writeCELUM(const std::string &name, bool saveAll,
+                       double scalingFactor)
+{
+  std::string namef = name + "_f";
+  FILE *fpf = Fopen(namef.c_str(), "w");
+  if(!fpf){
+    Msg::Error("Unable to open file '%s'", namef.c_str());
+    return 0;
+  }
+
+  std::string names = name + "_s";
+  FILE *fps = Fopen(names.c_str(), "w");
+  if(!fps){
+    Msg::Error("Unable to open file '%s'", names.c_str());
+    return 0;
+  }
+
+  // count faces and vertices; the CELUM format duplicates vertices on the
+  // boundary of CAD patches
+  int numf = 0, nums = 0;
+  for(fiter it = firstFace(); it != lastFace(); it++){
+    GFace *f = *it;
+    if(!saveAll && f->physicals.empty()) continue;
+    numf += f->triangles.size();
+    std::set<MVertex*> vset;
+    for(unsigned int i = 0; i < f->triangles.size(); i++){
+      for(int j = 0; j < 3; j++)
+        vset.insert(f->triangles[i]->getVertex(j));
+    }
+    nums += vset.size();
+  }
+
+  Msg::Info("Writing %d triangles and %d vertices", numf, nums);
+
+  int idf = 1, ids = 1;
+  /*
+   * un fichier de facettes
+     - nombre de facettes
+     - ligne vide
+     ... pour chaque facette
+     - numéro de la facette (commence à 1 : utilisé dans les erreurs de lectures)
+     - chaîne de caractères (nom de la partie géométrique, matériau,... )
+     - la liste des 3 numéros de sommets
+     - ligne vide
+     ...
+   * un fichier de sommets
+     - nombre de sommets
+     - facteur de conversion
+     - ligne vide
+     ... pour chaque sommet
+     - numéro du sommet (commence à 1 : utilisé dans les erreurs de lectures)
+     - coordonnées cartésiennes du sommet
+     - composantes de la normale extérieure orientée
+     - valeur de la 1ière courbure principale
+     - valeur de la 2ième courbure principale
+     - composantes de la 1ière direction principale
+     - composantes de la 2ième direction principale
+     - ligne blanche
+     ...
+  */
+  fprintf(fpf, "%d\n\n", numf);
+  fprintf(fps, "%d %g\n\n", nums, 1.0);
+  for(fiter it = firstFace(); it != lastFace(); it++){
+    GFace *f = *it;
+    if(!saveAll && f->physicals.empty()) continue;
+    std::vector<MVertex*> vvec;
+    std::map<MVertex*, CelumInfo> vmap;
+    for(unsigned int i = 0; i < f->triangles.size(); i++){
+      fprintf(fpf, "%d \"face %d\"", idf++, f->tag());
+      for(int j = 0; j < 3; j++){
+        MVertex *v = f->triangles[i]->getVertex(j);
+        if(!vmap.count(v)){
+          v->setIndex(ids++);
+          SPoint2 param;
+          bool ok = reparamMeshVertexOnFace(v, f, param);
+          if(!ok)
+            Msg::Warning("Could not reparamtrize vertex %d on face %d",
+                         v->getNum(), f->tag());
+          CelumInfo info;
+          info.normal = f->normal(param);
+          f->curvatures(param, &info.dirMax, &info.dirMin,
+                        &info.curvMax, &info.curvMin);
+          vmap[v] = info;
+          vvec.push_back(v);
+        }
+        fprintf(fpf, " %d", v->getIndex());
+      }
+      fprintf(fpf, "\n\n");
+    }
+    for(unsigned int i = 0; i < vvec.size(); i++){
+      MVertex *v = vvec[i];
+      std::map<MVertex *, CelumInfo>::iterator it = vmap.find(v);
+      fprintf(fps, "%d %g %g %g %g %g %g %g %g %g %g %g\n\n",
+              it->first->getIndex(), it->second.normal.x(), it->second.normal.y(),
+              it->second.normal.z(), it->second.curvMin, it->second.curvMax,
+              it->second.dirMin.x(), it->second.dirMin.y(), it->second.dirMin.z(),
+              it->second.dirMax.x(), it->second.dirMax.y(), it->second.dirMax.z());
+    }
+  }
+
+  fclose(fpf);
+  fclose(fps);
+  return 1;
+}
diff --git a/Geo/gmshFace.cpp b/Geo/gmshFace.cpp
index 026ad19c04..fff57b475e 100644
--- a/Geo/gmshFace.cpp
+++ b/Geo/gmshFace.cpp
@@ -188,7 +188,7 @@ SVector3 gmshFace::normal(const SPoint2 &param) const
         Msg::Debug("Could not compute normal of surface %d - retrying with %d points",
                    tag(), NP);
         if(tries > 10){
-          Msg::Warning("Could not compute normal of surface %d", tag());
+          Msg::Warning("Could not orient normal of surface %d", tag());
           return SVector3(n[0], n[1], n[2]);
         }
       }
-- 
GitLab