From 63d1380bdbf83e7f663d5d3ce32ecea2fe1f74b3 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Wed, 27 Feb 2019 20:32:57 +0100
Subject: [PATCH 01/19] add Ng_OptimizeVolume add Ng_AddLockedPoint extend API
 so user can set/get domain for element (optional -> does not break existing
 API)

the commit also (optionally) allows to send log messages (cout, cerr, testout) to a Null stream buffer. this allows applications to make netgen quiet
---
 nglib/nglib.cpp | 117 +++++++++++++++++++++++++++++++++++++-----------
 nglib/nglib.h   |  29 ++++++++----
 2 files changed, 111 insertions(+), 35 deletions(-)

diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index 54fff0966..8f6be7cd7 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -23,8 +23,6 @@
 #include <occgeom.hpp>
 #endif
 
-#include <nginterface.h>
-
 
 namespace netgen {
    extern void MeshFromSpline2D (SplineGeometry2d & geometry,
@@ -73,16 +71,26 @@ using namespace netgen;
 
 namespace nglib
 {
-  inline void NOOP_Deleter(void *) { ; }
+   inline void NOOP_Deleter(void *) { ; }
+
+   class NullStreambuf : public std::streambuf
+   {
+      char dummyBuffer[64];
+   protected:
+      virtual int overflow(int c)
+      {
+         setp(dummyBuffer, dummyBuffer + sizeof(dummyBuffer));
+         return (c == traits_type::eof()) ? '\0' : c;
+      }
+   };
 
-  
    // initialize, deconstruct Netgen library:
-   DLL_HEADER void Ng_Init ()
+   DLL_HEADER void Ng_Init (bool cout_to_null, bool cerr_to_null, bool testout_to_null)
    {
-      mycout = &cout;
-      myerr = &cerr;
-      // netgen::testout->SetOutStream (new ofstream ("test.out"));
-      testout = new ofstream ("test.out");
+      static ostream* null_stream = new ostream(new NullStreambuf);
+      mycout  = cout_to_null ? null_stream : &cout;
+      myerr   = cerr_to_null ? null_stream : &cerr;
+      testout = testout_to_null ? null_stream :  new ofstream("test.out");
    }
 
 
@@ -205,18 +213,39 @@ namespace nglib
    }
 
 
+   // Manually lock a specific point
+   DLL_HEADER void Ng_AddLockedPoint(Ng_Mesh * mesh, int pi)
+   {
+      Mesh * m = (Mesh*)mesh;
+      m->AddLockedPoint(pi);
+   }
 
 
    // Manually add a surface element of a given type to an existing mesh object
    DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et,
-                                         int * pi)
+                                         int * pi, int domain)
    {
+      int n = 3;
+      switch (et)
+      {
+      case NG_TRIG:
+         n = 3; break;
+      case NG_QUAD:
+         n = 4; break;
+      case NG_QUAD6:
+         n = 6; break;
+      case NG_TRIG6:
+         n = 6; break;
+      case NG_QUAD8:
+         n = 8; break;
+      default: break;
+      }
+      
       Mesh * m = (Mesh*)mesh;
-      Element2d el (3);
-      el.SetIndex (1);
-      el.PNum(1) = pi[0];
-      el.PNum(2) = pi[1];
-      el.PNum(3) = pi[2];
+      Element2d el (n);
+      el.SetIndex (domain);
+      for (int i=0; i<n; ++i)
+         el.PNum(i+1) = pi[i];
       m->AddSurfaceElement (el);
    }
 
@@ -225,15 +254,27 @@ namespace nglib
 
    // Manually add a volume element of a given type to an existing mesh object
    DLL_HEADER void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et,
-                                        int * pi)
+                                        int * pi, int domain)
    {
+      int n = 4;
+      switch (et)
+      {
+      case NG_TET:
+         n = 4; break;
+      case NG_PYRAMID:
+         n = 5; break;
+      case NG_PRISM:
+         n = 6; break;
+      case NG_TET10:
+         n = 10; break;
+      default: break;
+      }
+      
       Mesh * m = (Mesh*)mesh;
-      Element el (4);
-      el.SetIndex (1);
-      el.PNum(1) = pi[0];
-      el.PNum(2) = pi[1];
-      el.PNum(3) = pi[2];
-      el.PNum(4) = pi[3];
+      Element el (n);
+      el.SetIndex (domain);
+      for (int i=0; i<n; ++i)
+         el.PNum(i+1) = pi[i];
       m->AddVolumeElement (el);
    }
 
@@ -281,7 +322,7 @@ namespace nglib
 
    // Return the surface element at a given index "pi"
    DLL_HEADER Ng_Surface_Element_Type 
-      Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi)
+      Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi, int * domain)
    {
       const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num);
       for (int i = 1; i <= el.GetNP(); i++)
@@ -304,6 +345,8 @@ namespace nglib
       default:
          et = NG_TRIG; break; // for the compiler
       }
+      if (domain)
+        *domain = el.GetIndex();
       return et;
    }
 
@@ -312,7 +355,7 @@ namespace nglib
 
    // Return the volume element at a given index "pi"
    DLL_HEADER Ng_Volume_Element_Type
-      Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi)
+      Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi, int * domain)
    {
       const Element & el = ((Mesh*)mesh)->VolumeElement(num);
       for (int i = 1; i <= el.GetNP(); i++)
@@ -327,6 +370,8 @@ namespace nglib
       default:
          et = NG_TET; break; // for the compiler
       }
+      if (domain)
+		  *domain = el.GetIndex();
       return et;
    }
 
@@ -386,6 +431,24 @@ namespace nglib
 
 
 
+   // Optimize existing mesh
+   DLL_HEADER Ng_Result Ng_OptimizeVolume(Ng_Mesh *mesh, Ng_Meshing_Parameters *mp)
+   {
+      Mesh * m = (Mesh*)mesh;
+
+      mp->Transfer_Parameters();
+
+      m->CalcLocalH(mparam.grading);
+
+      RemoveIllegalElements(*m);
+      OptimizeVolume(mparam, *m);
+
+      return NG_OK;
+   }
+
+
+
+
    /* ------------------ 2D Meshing Functions ------------------------- */
    DLL_HEADER void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x)
    {
@@ -397,14 +460,16 @@ namespace nglib
 
 
 
-   DLL_HEADER void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2)
+   DLL_HEADER void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2, int domain_in, int domain_out)
    {
       Mesh * m = (Mesh*)mesh;
 
       Segment seg;
       seg[0] = pi1;
       seg[1] = pi2;
-      m->AddSegment (seg);
+      seg.domin = domain_in;
+      seg.domout = domain_out;
+	  m->AddSegment(seg);
    }
 
 
diff --git a/nglib/nglib.h b/nglib/nglib.h
index 8a78da075..da3bee501 100644
--- a/nglib/nglib.h
+++ b/nglib/nglib.h
@@ -193,7 +193,7 @@ class Ng_Meshing_Parameters
     program before beginning to use the other Netgen 
     specific functions.
 */
-DLL_HEADER void Ng_Init ();
+DLL_HEADER void Ng_Init (bool cout_to_null = false, bool cerr_to_null = false, bool testout_to_null = false);
 
 
 /*! \brief Exit the Netgen meshing kernel in a clean manner
@@ -312,6 +312,11 @@ DLL_HEADER Ng_Result Ng_MergeMesh(Ng_Mesh * mesh1, Ng_Mesh * mesh2);
 DLL_HEADER void Ng_AddPoint (Ng_Mesh * mesh, double * x);
 
 
+/*! Add locked point which should not get modified by optimization routines
+
+*/
+DLL_HEADER void Ng_AddLockedPoint(Ng_Mesh * mesh, int pi);
+
 /*! \brief Add a surface element to a given Netgen Mesh Structure
 
     This function allows the top-level code to directly add individual 
@@ -332,7 +337,7 @@ DLL_HEADER void Ng_AddPoint (Ng_Mesh * mesh, double * x);
     \param pi   Pointer to an array of integers containing the indices of the 
                 points which constitute the surface element being added
 */
-DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et, int * pi);
+DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et, int * pi, int domain=1);
 
 
 /*! \brief Add a volume element to a given Netgen Mesh Structure
@@ -356,7 +361,7 @@ DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et
                 points which constitute the volume element being added
 
 */
-DLL_HEADER void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et, int * pi);
+DLL_HEADER void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et, int * pi, int domain=1);
   
 // ------------------------------------------------------------------
 
@@ -471,6 +476,12 @@ DLL_HEADER void Ng_RestrictMeshSizeBox (Ng_Mesh * mesh, double * pmin, double *
 */
 DLL_HEADER Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp);
 
+
+/*! \brief Improve quality of an existing 3D Volume Mesh
+	
+*/
+DLL_HEADER Ng_Result Ng_OptimizeVolume(Ng_Mesh *mesh, Ng_Meshing_Parameters *mp);
+
 // ------------------------------------------------------------------
 
 
@@ -536,10 +547,10 @@ DLL_HEADER void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x);
 
 // return surface and volume element in pi
 DLL_HEADER Ng_Surface_Element_Type 
-Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi);
+Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi, int * domain = nullptr);
 
 DLL_HEADER Ng_Volume_Element_Type
-Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi);
+Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi, int * domain = nullptr);
 
 // ------------------------------------------------------------------
 
@@ -554,7 +565,7 @@ Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi);
 // feeds points and boundary to mesh
 
 DLL_HEADER void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x);
-DLL_HEADER void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2);
+DLL_HEADER void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2, int domain_in = -1, int domain_out = -1);
   
 // ask for number of points, elements and boundary segments
 DLL_HEADER int Ng_GetNP_2D (Ng_Mesh * mesh);
@@ -566,10 +577,10 @@ DLL_HEADER void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x);
 
 // return 2d elements
 DLL_HEADER Ng_Surface_Element_Type 
-Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = NULL);
+Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = nullptr);
 
 // return 2d boundary segment
-DLL_HEADER void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = NULL);
+DLL_HEADER void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = nullptr);
 
 
 // load 2d netgen spline geometry
@@ -606,7 +617,7 @@ DLL_HEADER Ng_STL_Geometry * Ng_STL_NewGeometry ();
 // normal vector may be null-pointer
 DLL_HEADER void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, 
                          double * p1, double * p2, double * p3, 
-                         double * nv = NULL);
+                         double * nv = nullptr);
 
 // add (optional) edges :
 DLL_HEADER void Ng_STL_AddEdge (Ng_STL_Geometry * geom, 

From 227d297f781ff5d91754c0bbc7ce98c1b9b886ba Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Fri, 1 Mar 2019 09:43:47 +0100
Subject: [PATCH 02/19] add support for exporting mesh to user file format (at
 least some of the formats available internally)

---
 libsrc/interface/CMakeLists.txt |   2 +-
 libsrc/interface/writeuser.cpp  |   6 +-
 libsrc/interface/writeuser.hpp  |   3 +
 libsrc/interface/writevtk.cpp   | 124 ++++++++++++++++++++++++++++++++
 nglib/nglib.cpp                 |  74 +++++++++++++++++--
 nglib/nglib.h                   |  19 ++++-
 6 files changed, 220 insertions(+), 8 deletions(-)
 create mode 100644 libsrc/interface/writevtk.cpp

diff --git a/libsrc/interface/CMakeLists.txt b/libsrc/interface/CMakeLists.txt
index afd301d96..8c8d1eb23 100644
--- a/libsrc/interface/CMakeLists.txt
+++ b/libsrc/interface/CMakeLists.txt
@@ -3,7 +3,7 @@ add_library(interface ${NG_LIB_TYPE}
         nginterface.cpp nginterface_v2.cpp 
         read_fnf_mesh.cpp readtetmesh.cpp readuser.cpp writeabaqus.cpp writediffpack.cpp 
         writedolfin.cpp writeelmer.cpp writefeap.cpp writefluent.cpp writegmsh.cpp writejcm.cpp 
-        writepermas.cpp writetecplot.cpp writetet.cpp writetochnog.cpp writeuser.cpp
+        writepermas.cpp writetecplot.cpp writetet.cpp writetochnog.cpp writeuser.cpp writevtk.cpp
         wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp 
         )
 
diff --git a/libsrc/interface/writeuser.cpp b/libsrc/interface/writeuser.cpp
index 99a88dde7..7a6d98806 100644
--- a/libsrc/interface/writeuser.cpp
+++ b/libsrc/interface/writeuser.cpp
@@ -39,8 +39,9 @@ namespace netgen
       "VRML Format", ".*",
       "Gmsh Format", ".gmsh",
       "Gmsh2 Format", ".gmsh2",
+      "VTK Format", ".vtk",
       "OpenFOAM 1.5+ Format", "*",
-	  "OpenFOAM 1.5+ Compressed", "*",
+	    "OpenFOAM 1.5+ Compressed", "*",
       "JCMwave Format", ".jcm",
       "TET Format", ".tet",
       //      { "Chemnitz Format" },
@@ -128,6 +129,9 @@ bool WriteUserFormat (const string & format,
   else if (format == "Gmsh2 Format")
     WriteGmsh2Format (mesh, geom, filename);
 
+  else if (format == "VTK Format")
+    WriteVtkFormat (mesh, filename);
+
   // Philippose - 25/10/2009
   // Added OpenFOAM 1.5+ Mesh export capability
   else if (format == "OpenFOAM 1.5+ Format")
diff --git a/libsrc/interface/writeuser.hpp b/libsrc/interface/writeuser.hpp
index 5ceda0bad..704d7c8cb 100644
--- a/libsrc/interface/writeuser.hpp
+++ b/libsrc/interface/writeuser.hpp
@@ -73,6 +73,9 @@ void WriteGmsh2Format (const Mesh & mesh,
                        const NetgenGeometry & geom,
                        const string & filename);
 
+extern
+void WriteVtkFormat (const Mesh & mesh,
+                      const string & filename);
 
 // Philippose - 25/10/2009
 // Added OpenFOAM 1.5+ Mesh Export support
diff --git a/libsrc/interface/writevtk.cpp b/libsrc/interface/writevtk.cpp
new file mode 100644
index 000000000..4e6f80ea0
--- /dev/null
+++ b/libsrc/interface/writevtk.cpp
@@ -0,0 +1,124 @@
+/*************************************
+ * Write Gmsh file
+ * First issue the 04/26/2004 by Paul CARRICO (paul.carrico@free.fr)
+ * At the moment, the GMSH format is available for
+ * linear tetrahedron elements i.e. in 3D
+ * (based on Neutral Format)
+ *
+ * Second issue the 05/05/2004 by Paul CARRICO
+ * Thanks to Joachim Schoeberl for the correction of a minor bug
+ * the 2 initial Gmsh Format (i.e. volume format and surface format) are group together)
+ * in only one file
+ **************************************/
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+  extern MeshingParameters mparam;
+
+
+/*
+ *  VTK mesh format
+ *  points, elements, surface elements
+ */
+
+void WriteVtkFormat (const Mesh & mesh,
+                      const string & filename)
+{
+  ofstream outfile (filename.c_str());
+  outfile.precision(6);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+
+  int np = mesh.GetNP();  /// number of point
+  int ne = mesh.GetNE();  /// number of element
+  int nse = mesh.GetNSE();  /// number of surface element (BC)
+
+  outfile << "# vtk DataFile Version 2.0\n";
+  outfile << "Created with netgen\n";
+  outfile << "ASCII\n";
+  outfile << "DATASET UNSTRUCTURED_GRID\n";
+  
+  outfile << "POINTS " << np << " double\n";
+  for (int i=0; i<np; i++)
+  {
+	auto & p = mesh.Point(i+1);
+    outfile << p[0] << " " << p[1] << " " << p[2] << "\n";
+  }
+
+  std::vector<int> types;
+  if (ne > 0)
+  {
+    unsigned int size = 0;
+    for (int i=0; i<ne; i++)
+	  size += mesh.VolumeElement(i+1).GetNV() + 1; // only save "linear" corners
+
+    outfile << "CELLS " << ne << " " << size << "\n";
+    for (int i=0; i<ne; i++)
+    {
+	  auto& el = mesh.VolumeElement(i+1);
+	  switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10: // reorder to follow VTK convention & zero based indices
+        outfile << 4 << " " << el[0]-1 << " " << el[1]-1 << " " << el[3]-1 << " " << el[2]-1 << "\n";
+		types.push_back(10);
+		break;
+	  case PRISM: // reorder to follow VTK convention & zero based indices
+        outfile << 6 << " "
+				<< el[0]-1 << " " << el[2]-1 << " " << el[1]-1 << " " 
+				<< el[3]-1 << " " << el[5]-1 << " " << el[4]-1 << "\n";
+		types.push_back(13);
+		break;
+	  default:
+	    throw ngcore::Exception("Unexpected element type");
+		break;
+	  }
+    }
+  }
+  else
+  {
+    unsigned int size = 0;
+    for (int i=0; i<ne; i++)
+	  size += mesh.SurfaceElement(i+1).GetNV() + 1;
+
+    outfile << "CELLS " << nse << " " << size << "\n";
+    for (int i=0; i<nse; i++)
+    {
+	  auto& el = mesh.SurfaceElement(i+1);
+	  switch (el.GetType())
+	  {
+	  case TRIG:
+	  case TRIG6:
+        outfile << el[0]-1 << " " << el[1]-1 << " " << el[2]-1 << "\n";
+		types.push_back(5);
+		break;
+	  case QUAD:
+        outfile << el[0]-1 << " " << el[1]-1 << " " << el[2]-1 << " " << el[3]-1 << "\n";
+		types.push_back(9);
+	  default:
+	    throw ngcore::Exception("Unexpected element type");
+		break;
+	  }
+    }
+  }
+
+  outfile << "CELL_TYPES " << types.size() << "\n";
+  for (auto type_id: types)
+  {
+    outfile << type_id << "\n";
+  }
+
+  outfile.close();
+}
+}
+
+
diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index 8f6be7cd7..ea681ac91 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -18,6 +18,7 @@
 #include <geometry2d.hpp>
 #include <meshing.hpp>
 #include <../visualization/soldata.hpp>
+#include <../interface/writeuser.hpp>
 
 #ifdef OCCGEOMETRY
 #include <occgeom.hpp>
@@ -154,6 +155,25 @@ namespace nglib
 
 
 
+   DLL_HEADER void Ng_ExportMesh(Ng_Mesh * ng_mesh, Ng_Export_Formats format, const char* filename)
+   {
+      Mesh * mesh = (Mesh*)ng_mesh;
+      switch (format)
+      {
+      case NG_GMSH:
+         WriteUserFormat( "Gmsh Format", *mesh, filename ); break;
+      case NG_GMSH2:
+         WriteUserFormat( "Gmsh2 Format", *mesh, filename ); break;
+      case NG_VTK:
+         WriteUserFormat( "VTK Format", *mesh, filename ); break;
+      case NG_FLUENT:
+         WriteUserFormat( "Fluent Format", *mesh, filename ); break;
+      case NG_ABAQUS:
+         WriteUserFormat( "Abaqus Format", *mesh, filename ); break;
+      }
+   }
+
+
 
    // Merge another mesh file into the currently loaded one
    DLL_HEADER Ng_Result Ng_MergeMesh( Ng_Mesh* mesh, const char* filename)
@@ -265,6 +285,8 @@ namespace nglib
          n = 5; break;
       case NG_PRISM:
          n = 6; break;
+      case NG_HEX:
+         n = 8; break;
       case NG_TET10:
          n = 10; break;
       default: break;
@@ -279,8 +301,6 @@ namespace nglib
    }
 
 
-
-
    // Obtain the number of points in the mesh
    DLL_HEADER int Ng_GetNP (Ng_Mesh * mesh)
    {
@@ -366,6 +386,7 @@ namespace nglib
       case 4: et = NG_TET; break;
       case 5: et = NG_PYRAMID; break;
       case 6: et = NG_PRISM; break;
+      case 8: et = NG_HEX; break;
       case 10: et = NG_TET10; break;
       default:
          et = NG_TET; break; // for the compiler
@@ -1202,6 +1223,53 @@ namespace nglib
    }
 
 
+   void Ng_SetRefinementFlag (Ng_Mesh * ng_mesh, int ei, int flag)
+   {
+      Mesh * mesh = (Mesh*) ng_mesh;
+      
+      if (mesh->GetDimension() == 3)
+      {
+         mesh->VolumeElement(ei).SetRefinementFlag (flag != 0);
+         mesh->VolumeElement(ei).SetStrongRefinementFlag (flag >= 10);
+      }
+      else
+      {
+         mesh->SurfaceElement(ei).SetRefinementFlag (flag != 0);
+         mesh->SurfaceElement(ei).SetStrongRefinementFlag (flag >= 10);
+      }
+   }
+
+
+   void Ng_SetSurfaceRefinementFlag (Ng_Mesh * ng_mesh, int ei, int flag)
+   {
+      Mesh * mesh = (Mesh*) ng_mesh;
+
+      if (mesh->GetDimension() == 3)
+      {
+         mesh->SurfaceElement(ei).SetRefinementFlag (flag != 0);
+         mesh->SurfaceElement(ei).SetStrongRefinementFlag (flag >= 10);
+      }
+   }
+
+
+   void Ng_Refine (Ng_Mesh * ng_mesh)
+   {
+      Mesh * mesh = (Mesh*) ng_mesh;
+      BisectionOptions biopt;
+      biopt.usemarkedelements = 1;
+      biopt.refine_p = 0; // only h-refinement
+      biopt.refine_hp = 0;
+
+      if (auto geom = mesh->GetGeometry())
+         geom->GetRefinement().Bisect (*mesh, biopt);
+      else
+         Refinement().Bisect (*mesh, biopt);
+
+      // not sure if this is needed?
+      //mesh -> UpdateTopology();
+      //mesh -> GetCurvedElements().SetIsHighOrder (false);
+   }
+
 
 
    DLL_HEADER void Ng_2D_Uniform_Refinement (Ng_Geometry_2D * geom,
@@ -1212,7 +1280,6 @@ namespace nglib
 
 
 
-
    DLL_HEADER void Ng_STL_Uniform_Refinement (Ng_STL_Geometry * geom,
       Ng_Mesh * mesh)
    {
@@ -1312,7 +1379,6 @@ void Ng_InitSolutionData (Ng_SolutionData * soldata) { ; }
 */
 
 // Force linking libinterface to libnglib
-#include <../interface/writeuser.hpp>
 void MyDummyToForceLinkingLibInterface(Mesh &mesh, NetgenGeometry &geom)
 {
   netgen::WriteUserFormat("", mesh, /* geom, */ "");
diff --git a/nglib/nglib.h b/nglib/nglib.h
index da3bee501..d8022b13e 100644
--- a/nglib/nglib.h
+++ b/nglib/nglib.h
@@ -71,7 +71,7 @@ enum Ng_Surface_Element_Type
 
 /// Currently implemented volume element types
 enum Ng_Volume_Element_Type 
-   { NG_TET = 1, NG_PYRAMID = 2, NG_PRISM = 3, NG_TET10 = 4 };
+   { NG_TET = 1, NG_PYRAMID = 2, NG_PRISM = 3, NG_TET10 = 4, NG_HEX = 5 };
 
 /// Values returned by Netgen functions
 enum Ng_Result 
@@ -258,6 +258,13 @@ DLL_HEADER void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename);
 DLL_HEADER Ng_Mesh * Ng_LoadMesh(const char* filename);
 
 
+/*! \brief Save mesh in various external formats, e.g. fluent, gmsh, gmsh2, vtk, ...
+
+*/
+enum Ng_Export_Formats { NG_GMSH = 1, NG_GMSH2 = 2, NG_VTK = 3, NG_FLUENT = 4, NG_ABAQUS = 5 };
+DLL_HEADER void Ng_ExportMesh(Ng_Mesh * mesh, Ng_Export_Formats format, const char* filename);
+
+
 /*! \brief Merge a Netgen VOL Mesh from disk into an existing mesh in memory
 
     A Netgen mesh saved in the internal VOL format can be merged 
@@ -362,7 +369,7 @@ DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et
 
 */
 DLL_HEADER void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et, int * pi, int domain=1);
-  
+
 // ------------------------------------------------------------------
 
 
@@ -712,6 +719,14 @@ DLL_HEADER Ng_Result Ng_OCC_GetFMap(Ng_OCC_Geometry * geom,
 DLL_HEADER void Ng_Uniform_Refinement (Ng_Mesh * mesh);
 
 
+// non-uniform mesh refinement
+DLL_HEADER void Ng_SetRefinementFlag (Ng_Mesh * ng_mesh, int ei, int flag);
+
+DLL_HEADER void Ng_SetSurfaceRefinementFlag (Ng_Mesh * ng_mesh, int ei, int flag);
+
+DLL_HEADER void Ng_Refine (Ng_Mesh * ng_mesh);
+
+
 // uniform mesh refinement with geometry adaption:
 
 DLL_HEADER void Ng_2D_Uniform_Refinement (Ng_Geometry_2D * geom,

From 292f8556a4b8bad52dd27f8266b3d62d64bcb8f5 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.ethz.ch>
Date: Fri, 1 Mar 2019 10:05:24 +0100
Subject: [PATCH 03/19] expose mesh optimization parameters, e.g. to allow only
 smoothing or swapping

---
 nglib/nglib.cpp | 64 ++++++++++++++++---------------------------------
 nglib/nglib.h   |  3 +++
 2 files changed, 24 insertions(+), 43 deletions(-)

diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index ea681ac91..e17fc2fb5 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -1067,9 +1067,9 @@ namespace nglib
 
       closeedgeenable = 0;
       closeedgefact = 2.0;
-
-	  minedgelenenable = 0;
-	  minedgelen = 1e-4;
+      
+      minedgelenenable = 0;
+      minedgelen = 1e-4;
 
       second_order = 0;
       quad_dominated = 0;
@@ -1081,6 +1081,9 @@ namespace nglib
 
       optsteps_2d = 3;
       optsteps_3d = 3;
+      
+      optimize3d = "cmdmustm";
+      optimize2d = "smsmsmSmSmSm";
 
       invert_tets = 0;
       invert_trigs = 0;
@@ -1095,39 +1098,7 @@ namespace nglib
    // Reset the local meshing parameters to the default values
    DLL_HEADER void Ng_Meshing_Parameters :: Reset_Parameters()
    {
-      uselocalh = 1;
-
-      maxh = 1000;
-      minh = 0;
-
-      fineness = 0.5;
-      grading = 0.3;
-
-      elementsperedge = 2.0;
-      elementspercurve = 2.0;
-
-      closeedgeenable = 0;
-      closeedgefact = 2.0;
-
-  	  minedgelenenable = 0;
-	  minedgelen = 1e-4;
-
-      second_order = 0;
-      quad_dominated = 0;
-
-      meshsize_filename = 0;
-
-      optsurfmeshenable = 1;
-      optvolmeshenable = 1;
-
-      optsteps_2d = 3;
-      optsteps_3d = 3;
-
-      invert_tets = 0;
-      invert_trigs = 0;
-
-      check_overlap = 1;
-      check_overlapping_boundary = 1;
+      (*this) = Ng_Meshing_Parameters();
    }
 
 
@@ -1154,6 +1125,9 @@ namespace nglib
         mparam.meshsizefilename = "";
       mparam.optsteps2d = optsteps_2d;
       mparam.optsteps3d = optsteps_3d;
+      
+      if (strlen(optimize2d) > 0) mparam.optimize2d = optimize2d;
+      if (strlen(optimize3d) > 0) mparam.optimize3d = optimize3d;
 
       mparam.inverttets = invert_tets;
       mparam.inverttrigs = invert_trigs;
@@ -1216,14 +1190,18 @@ namespace nglib
 
 
    // ------------------ Begin - Uniform Mesh Refinement functions ---------------------
-   DLL_HEADER void Ng_Uniform_Refinement (Ng_Mesh * mesh)
+   DLL_HEADER void Ng_Uniform_Refinement (Ng_Mesh * ng_mesh)
    {
-      Refinement ref;
-      ref.Refine ( * (Mesh*) mesh );
+      Mesh * mesh = (Mesh*) ng_mesh;
+
+      if (auto geom = mesh->GetGeometry())
+         geom->GetRefinement().Refine (*mesh);
+      else
+         Refinement().Refine (*mesh);
    }
 
 
-   void Ng_SetRefinementFlag (Ng_Mesh * ng_mesh, int ei, int flag)
+   DLL_HEADER void Ng_SetRefinementFlag (Ng_Mesh * ng_mesh, int ei, int flag)
    {
       Mesh * mesh = (Mesh*) ng_mesh;
       
@@ -1240,7 +1218,7 @@ namespace nglib
    }
 
 
-   void Ng_SetSurfaceRefinementFlag (Ng_Mesh * ng_mesh, int ei, int flag)
+   DLL_HEADER void Ng_SetSurfaceRefinementFlag (Ng_Mesh * ng_mesh, int ei, int flag)
    {
       Mesh * mesh = (Mesh*) ng_mesh;
 
@@ -1252,7 +1230,7 @@ namespace nglib
    }
 
 
-   void Ng_Refine (Ng_Mesh * ng_mesh)
+   DLL_HEADER void Ng_Refine (Ng_Mesh * ng_mesh)
    {
       Mesh * mesh = (Mesh*) ng_mesh;
       BisectionOptions biopt;
@@ -1265,7 +1243,7 @@ namespace nglib
       else
          Refinement().Bisect (*mesh, biopt);
 
-      // not sure if this is needed?
+      // \todo not sure if this is needed?
       //mesh -> UpdateTopology();
       //mesh -> GetCurvedElements().SetIsHighOrder (false);
    }
diff --git a/nglib/nglib.h b/nglib/nglib.h
index d8022b13e..ef57a48d4 100644
--- a/nglib/nglib.h
+++ b/nglib/nglib.h
@@ -120,6 +120,9 @@ class Ng_Meshing_Parameters
    int optsteps_3d;                     //!< Number of optimize steps to use for 3-D mesh optimization
    int optsteps_2d;                     //!< Number of optimize steps to use for 2-D mesh optimization
 
+   const char* optimize3d;              //!< Optimization strategy (s=swap shape, c=collapse, d=divide, m=move, M=cheap move)
+   const char* optimize2d;              //!< Optimization strategy (s=swap tolopgical, S=swap shape, c=collapse, m=move)
+
    // Philippose - 13/09/2010
    // Added a couple more parameters into the meshing parameters list 
    // from Netgen into Nglib

From 533e5dedac275f5b11435b0918a26066afbf020f Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.ethz.ch>
Date: Fri, 1 Mar 2019 15:00:41 +0100
Subject: [PATCH 04/19] typo

---
 nglib/nglib.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/nglib/nglib.h b/nglib/nglib.h
index ef57a48d4..d87e305c9 100644
--- a/nglib/nglib.h
+++ b/nglib/nglib.h
@@ -121,7 +121,7 @@ class Ng_Meshing_Parameters
    int optsteps_2d;                     //!< Number of optimize steps to use for 2-D mesh optimization
 
    const char* optimize3d;              //!< Optimization strategy (s=swap shape, c=collapse, d=divide, m=move, M=cheap move)
-   const char* optimize2d;              //!< Optimization strategy (s=swap tolopgical, S=swap shape, c=collapse, m=move)
+   const char* optimize2d;              //!< Optimization strategy (s=swap topological, S=swap shape, c=collapse, m=move)
 
    // Philippose - 13/09/2010
    // Added a couple more parameters into the meshing parameters list 

From 85fcc6843e0c182affad67ab904cc50a1c9362f2 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.ethz.ch>
Date: Fri, 1 Mar 2019 16:40:28 +0100
Subject: [PATCH 05/19] expose stl meshing options (algorithm for
 auto-detecting feature edges)

---
 nglib/nglib.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++++----
 nglib/nglib.h   | 57 +++++++++++++++++++++++++++---
 2 files changed, 139 insertions(+), 12 deletions(-)

diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index e17fc2fb5..df3447a03 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -392,7 +392,7 @@ namespace nglib
          et = NG_TET; break; // for the compiler
       }
       if (domain)
-		  *domain = el.GetIndex();
+        *domain = el.GetIndex();
       return et;
    }
 
@@ -490,7 +490,7 @@ namespace nglib
       seg[1] = pi2;
       seg.domin = domain_in;
       seg.domout = domain_out;
-	  m->AddSegment(seg);
+     m->AddSegment(seg);
    }
 
 
@@ -694,6 +694,16 @@ namespace nglib
    } 
 
 
+   DLL_HEADER void Ng_STL_DeleteGeometry (Ng_STL_Geometry * geom)
+   {
+      if (geom)
+      {
+         STLGeometry* geometry = (STLGeometry*)geom;
+         geometry->Clear();
+         delete geometry;
+         geometry = NULL;
+      }
+   }
 
 
    // after adding triangles (and edges) initialize
@@ -724,7 +734,8 @@ namespace nglib
    // automatically generates edges:
    DLL_HEADER Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom,
                                           Ng_Mesh* mesh,
-                                          Ng_Meshing_Parameters * mp)
+                                          Ng_Meshing_Parameters * mp,
+                                          Ng_STL_Parameters * stlp)
    {
       STLGeometry* stlgeometry = (STLGeometry*)geom;
       Mesh* me = (Mesh*)mesh;
@@ -734,6 +745,7 @@ namespace nglib
       // object 
       //MeshingParameters mparam;
       mp->Transfer_Parameters();
+      if (stlp) stlp->Transfer_Parameters();
 
       me -> SetGlobalH (mparam.maxh);
       me -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
@@ -769,7 +781,8 @@ namespace nglib
    // generates mesh, empty mesh be already created.
    DLL_HEADER Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom,
                                                     Ng_Mesh* mesh,
-                                                    Ng_Meshing_Parameters * mp)
+                                                    Ng_Meshing_Parameters * mp,
+                                                    Ng_STL_Parameters * stlp)
    {
       STLGeometry* stlgeometry = (STLGeometry*)geom;
       Mesh* me = (Mesh*)mesh;
@@ -779,6 +792,7 @@ namespace nglib
       // object
       //MeshingParameters mparam;
       mp->Transfer_Parameters();
+      if (stlp) stlp->Transfer_Parameters();
 
 
       /*
@@ -1135,6 +1149,72 @@ namespace nglib
       mparam.checkoverlap = check_overlap;
       mparam.checkoverlappingboundary = check_overlapping_boundary;
    }
+
+
+
+   DLL_HEADER Ng_STL_Parameters :: Ng_STL_Parameters()
+   {
+      yangle = 30;
+      contyangle = 20;
+      
+      chartangle = 10; // original = 15
+      outerchartangle = 80; // original = 70;
+      
+      usesearchtree = 0;
+      
+      atlasminh = 1.0; // original = 1E-4
+      
+      resthatlasenable = 1;
+      resthatlasfac = 2;
+      
+      resthchartdistenable = 1;
+      resthchartdistfac = 0.3; // original = 1.2
+      
+      resthedgeangleenable = 0;
+      resthedgeanglefac = 1;
+      
+      resthsurfmeshcurvenable = 1;
+      resthsurfmeshcurvfac = 1;
+      
+      resthlinelengthenable = 1;
+      resthlinelengthfac = 0.2; // original = 0.5
+      
+      resthcloseedgefac = 1;
+      resthcloseedgeenable = 1;
+   }
+
+
+
+   DLL_HEADER void Ng_STL_Parameters :: Transfer_Parameters()
+   {
+      stlparam.yangle = yangle;
+      stlparam.contyangle = contyangle;
+
+      stlparam.chartangle = chartangle;
+      stlparam.outerchartangle = outerchartangle;
+
+      stlparam.usesearchtree = usesearchtree;
+
+      stlparam.atlasminh = atlasminh;
+
+      stlparam.resthatlasenable = resthatlasenable;
+      stlparam.resthatlasfac = resthatlasfac;
+
+      stlparam.resthchartdistenable = resthchartdistenable;
+      stlparam.resthchartdistfac = resthchartdistfac;
+
+      stlparam.resthedgeangleenable = resthedgeangleenable;
+      stlparam.resthedgeanglefac = resthedgeanglefac;
+
+      stlparam.resthsurfmeshcurvenable = resthsurfmeshcurvenable;
+      stlparam.resthsurfmeshcurvfac = resthsurfmeshcurvfac;
+
+      stlparam.resthlinelengthenable = resthlinelengthenable;
+      stlparam.resthlinelengthfac = resthlinelengthfac;
+
+      stlparam.resthcloseedgeenable = resthcloseedgeenable;
+      stlparam.resthcloseedgefac = resthcloseedgefac;
+   }
    // ------------------ End - Meshing Parameters related functions --------------------
 
 
@@ -1151,7 +1231,7 @@ namespace nglib
 
 
    DLL_HEADER void Ng_2D_Generate_SecondOrder(Ng_Geometry_2D * geom,
-					  Ng_Mesh * mesh)
+                 Ng_Mesh * mesh)
    {
       ( (SplineGeometry2d*)geom ) -> GetRefinement().MakeSecondOrder( * (Mesh*) mesh );
    }
@@ -1160,7 +1240,7 @@ namespace nglib
 
 
    DLL_HEADER void Ng_STL_Generate_SecondOrder(Ng_STL_Geometry * geom,
-					   Ng_Mesh * mesh)
+                  Ng_Mesh * mesh)
    {
       ((STLGeometry*)geom)->GetRefinement().MakeSecondOrder(*(Mesh*) mesh);
    }
@@ -1169,7 +1249,7 @@ namespace nglib
 
 
    DLL_HEADER void Ng_CSG_Generate_SecondOrder (Ng_CSG_Geometry * geom,
-					   Ng_Mesh * mesh)
+                  Ng_Mesh * mesh)
    {
       ((CSGeometry*)geom)->GetRefinement().MakeSecondOrder(*(Mesh*) mesh);
    }
diff --git a/nglib/nglib.h b/nglib/nglib.h
index d87e305c9..2c2b05445 100644
--- a/nglib/nglib.h
+++ b/nglib/nglib.h
@@ -23,8 +23,8 @@
 
 // Philippose - 14.02.2009
 // Modifications for creating a DLL in Windows
-#ifdef WIN32
-   #ifdef NGLIB_EXPORTS || nglib_EXPORTS
+#if defined(WIN32)
+   #if defined(NGLIB_EXPORTS) || defined(nglib_EXPORTS)
       #define DLL_HEADER   __declspec(dllexport)
    #else
       #define DLL_HEADER   __declspec(dllimport)
@@ -183,6 +183,49 @@ class Ng_Meshing_Parameters
 };
 
 
+class DLL_HEADER Ng_STL_Parameters
+{
+public:
+   // Algorithm may be somewhat like Canny edge detector 
+   // on mesh?
+   double yangle; // 30
+   double contyangle; // 30
+   
+   // I think this is used to split surface into patches/charts,
+   //which  are flattened to use 2d meshing routines.
+   double chartangle; // 15
+   double outerchartangle; // 70
+   
+   int usesearchtree; // 0
+   
+   double atlasminh; // 1e-4
+   
+   // Factors which influence the local mesh size
+   // as a relation to some metric, e.g. curvature, 
+   // line length, etc.
+   // TODO: document each of these properly
+   int resthatlasenable; // 1
+   double resthatlasfac; // 2
+   
+   int resthchartdistenable; // 1
+   double resthchartdistfac; // 0.3
+   
+   int resthedgeangleenable; // 0
+   double resthedgeanglefac; // 1
+   
+   int resthsurfmeshcurvenable; // 0
+   double resthsurfmeshcurvfac; // 0.5
+   
+   int resthlinelengthenable; // 1
+   double resthlinelengthfac; // 0.5
+   
+   int resthcloseedgeenable; // 1
+   double resthcloseedgefac; // 1.0
+   
+   Ng_STL_Parameters();
+   
+   void Transfer_Parameters();
+};
 
 
 // *** Functions Exported by this Library *************
@@ -620,7 +663,9 @@ DLL_HEADER Ng_STL_Geometry * Ng_STL_LoadGeometry (const char * filename, int bin
 
 // generate new STL Geometry
 DLL_HEADER Ng_STL_Geometry * Ng_STL_NewGeometry ();
-  
+
+
+DLL_HEADER void Ng_STL_DeleteGeometry (Ng_STL_Geometry * geom);
 
 // fills STL Geometry
 // positive orientation
@@ -639,13 +684,15 @@ DLL_HEADER Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom);
 // automatically generates edges:
 DLL_HEADER Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom,
                             Ng_Mesh* mesh,
-                            Ng_Meshing_Parameters * mp);
+                            Ng_Meshing_Parameters * mp,
+                            Ng_STL_Parameters * stlp = nullptr);
 
 
 // generates mesh, empty mesh must be already created.
 DLL_HEADER Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom,
                                                  Ng_Mesh * mesh,
-                                                 Ng_Meshing_Parameters * mp);
+                                                 Ng_Meshing_Parameters * mp,
+                                                 Ng_STL_Parameters * stlp = nullptr);
 
 
 #ifdef ACIS

From 353795062c45191132f5dace03c3e7b0a3568db5 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.ethz.ch>
Date: Fri, 1 Mar 2019 16:48:32 +0100
Subject: [PATCH 06/19] add function signatures (implementation missing) of API
 needed for 2D meshing - > add temporary file, where these functions are
 implemented

---
 nglib/mynglib.cpp | 1548 +++++++++++++++++++++++++++++++++++++++++++++
 nglib/nglib.h     |   21 +-
 2 files changed, 1566 insertions(+), 3 deletions(-)
 create mode 100644 nglib/mynglib.cpp

diff --git a/nglib/mynglib.cpp b/nglib/mynglib.cpp
new file mode 100644
index 000000000..1bac1329a
--- /dev/null
+++ b/nglib/mynglib.cpp
@@ -0,0 +1,1548 @@
+/**************************************************************************/
+/* File:   nglib.cpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   7. May. 2000                                                   */
+/**************************************************************************/
+
+/*
+  
+  Interface to the netgen meshing kernel
+  
+*/
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <stlgeom.hpp>
+#include <geometry2d.hpp>
+#include <meshing.hpp>
+#include <../visualization/soldata.hpp>
+
+#ifdef OCCGEOMETRY
+#include <occgeom.hpp>
+#endif
+
+#include <nginterface.h>
+
+
+namespace netgen {
+   extern void MeshFromSpline2D (SplineGeometry2d & geometry,
+                                 shared_ptr<Mesh> & mesh, 
+                                 MeshingParameters & mp);
+
+   extern void Optimize2d (Mesh & mesh, 
+	   MeshingParameters & mp);
+
+   // Global meshing parameters !!
+   //MeshingParameters mparam;
+}
+
+
+
+#ifdef PARALLEL
+#include <mpi.h>
+
+namespace netgen
+{
+  // int id = 0, ntasks = 1;
+  MPI_Comm mesh_comm;
+}
+#endif
+
+
+/*
+namespace netgen
+{
+  int id = 0, ntasks = 1;
+}
+*/
+
+
+/*
+// should not be needed (occ currently requires it)
+namespace netgen {
+#include "../libsrc/visualization/vispar.hpp"
+  VisualizationParameters vispar;
+  VisualizationParameters :: VisualizationParameters() { ; }
+}
+*/
+
+
+namespace nglib {
+#include "mynglib.h"
+}
+
+using namespace netgen;
+
+// constants and types:
+
+namespace nglib
+{
+  inline void NOOP_Deleter(void *) { ; }
+
+  
+   // initialize, deconstruct Netgen library:
+   DLL_HEADER void Ng_Init ()
+   {
+      mycout = &cout;
+      myerr = &cerr;
+      // netgen::testout->SetOutStream (new ofstream ("test.out"));
+      testout = new ofstream ("test.out");
+   }
+
+
+
+
+   // Clean-up functions before ending usage of nglib
+   DLL_HEADER void Ng_Exit ()
+   {
+      ;
+   }
+
+
+
+
+   // Create a new netgen mesh object
+   DLL_HEADER Ng_Mesh * Ng_NewMesh ()
+   {
+      Mesh * mesh = new Mesh;  
+      mesh->AddFaceDescriptor (FaceDescriptor (1, 1, 0, 1));
+      return (Ng_Mesh*)(void*)mesh;
+   }
+
+
+
+
+   // Delete an existing netgen mesh object
+   DLL_HEADER void Ng_DeleteMesh (Ng_Mesh * mesh)
+   {
+      if(mesh != NULL)
+      {
+         // Delete the Mesh structures
+         ((Mesh*)mesh)->DeleteMesh();
+
+         // Now delete the Mesh class itself
+         delete (Mesh*)mesh;
+
+         // Set the Ng_Mesh pointer to NULL
+         mesh = NULL;
+      }
+   }
+
+
+
+
+   // Save a netgen mesh in the native VOL format 
+   DLL_HEADER void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename)
+   {
+      ((Mesh*)mesh)->Save(filename);
+   }
+
+
+
+
+   // Load a netgen native VOL mesh from a given file
+   DLL_HEADER Ng_Mesh * Ng_LoadMesh(const char* filename)
+   {
+      Mesh * mesh = new Mesh;
+      mesh->Load(filename);
+      return ( (Ng_Mesh*)mesh );
+   }
+
+
+
+
+   // Merge another mesh file into the currently loaded one
+   DLL_HEADER Ng_Result Ng_MergeMesh( Ng_Mesh* mesh, const char* filename)
+   {
+      Ng_Result status = NG_OK;
+
+      ifstream infile(filename);
+      Mesh * m = (Mesh*)mesh;
+
+      if(!infile.good())
+      {
+         status = NG_FILE_NOT_FOUND;
+      }
+
+      if(!m)
+      {
+         status = NG_ERROR;
+      }
+
+      if(status == NG_OK)
+      {
+         const int num_pts = m->GetNP();
+         const int face_offset = m->GetNFD();
+
+         m->Merge(infile, face_offset);
+
+         if(m->GetNP() > num_pts)
+         {
+            status = NG_OK;
+         }
+         else
+         {
+            status = NG_ERROR;
+         }
+      }
+
+      return status;
+   }
+
+
+
+
+   // Merge another mesh file into the currently loaded one
+   DLL_HEADER Ng_Result Ng_MergeMesh( Ng_Mesh* mesh1, Ng_Mesh* mesh2)
+   {
+      return NG_ERROR;
+   }
+
+
+
+
+   // Manually add a point to an existing mesh object
+   DLL_HEADER void Ng_AddPoint (Ng_Mesh * mesh, double * x)
+   {
+      Mesh * m = (Mesh*)mesh;
+      m->AddPoint (Point3d (x[0], x[1], x[2]));
+   }
+
+
+   DLL_HEADER void Ng_AddLockedPoint(Ng_Mesh * mesh, int pi)
+   {
+	   Mesh * m = (Mesh*)mesh;
+	   m->AddLockedPoint(pi);
+   }
+
+
+
+   // Manually add a surface element of a given type to an existing mesh object
+   DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et,
+                                         int * pi)
+   {
+      Mesh * m = (Mesh*)mesh;
+      Element2d el (3);
+      el.SetIndex (1);
+      el.PNum(1) = pi[0];
+      el.PNum(2) = pi[1];
+      el.PNum(3) = pi[2];
+      m->AddSurfaceElement (el);
+   }
+
+
+
+
+   // Manually add a volume element of a given type to an existing mesh object
+   DLL_HEADER void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et,
+                                        int * pi, int domain)
+   {
+      Mesh * m = (Mesh*)mesh;
+      Element el (4);
+      el.SetIndex (domain);
+      el.PNum(1) = pi[0];
+      el.PNum(2) = pi[1];
+      el.PNum(3) = pi[2];
+      el.PNum(4) = pi[3];
+      m->AddVolumeElement (el);
+   }
+
+
+
+
+   // Obtain the number of points in the mesh
+   DLL_HEADER int Ng_GetNP (Ng_Mesh * mesh)
+   {
+      return ((Mesh*)mesh) -> GetNP();
+   }
+
+
+
+
+   // Obtain the number of surface elements in the mesh
+   DLL_HEADER int Ng_GetNSE (Ng_Mesh * mesh)
+   {
+      return ((Mesh*)mesh) -> GetNSE();
+   }
+
+
+
+
+   // Obtain the number of volume elements in the mesh
+   DLL_HEADER int Ng_GetNE (Ng_Mesh * mesh)
+   {
+      return ((Mesh*)mesh) -> GetNE();
+   }
+
+
+
+
+   //  Return point coordinates of a given point index in the mesh
+   DLL_HEADER void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x)
+   {
+      const Point3d & p = ((Mesh*)mesh)->Point(num);
+      x[0] = p.X();
+      x[1] = p.Y();
+      x[2] = p.Z();
+   }
+
+
+
+
+   // Return the surface element at a given index "pi"
+   DLL_HEADER Ng_Surface_Element_Type 
+      Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi)
+   {
+      const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num);
+      for (int i = 1; i <= el.GetNP(); i++)
+         pi[i-1] = el.PNum(i);
+      Ng_Surface_Element_Type et;
+      switch (el.GetNP())
+      {
+      case 3: et = NG_TRIG; break;
+      case 4: et = NG_QUAD; break;
+      case 6: 
+         switch (el.GetNV())
+         {
+         case 3: et = NG_TRIG6; break;
+         case 4: et = NG_QUAD6; break;
+         default:
+            et = NG_TRIG6; break;
+         }
+         break;
+      case 8: et = NG_QUAD8; break;
+      default:
+         et = NG_TRIG; break; // for the compiler
+      }
+      return et;
+   }
+
+
+
+
+   // Return the volume element at a given index "pi"
+   DLL_HEADER Ng_Volume_Element_Type
+      Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi, int & domain)
+   {
+      const Element & el = ((Mesh*)mesh)->VolumeElement(num);
+      for (int i = 1; i <= el.GetNP(); i++)
+         pi[i-1] = el.PNum(i);
+      Ng_Volume_Element_Type et;
+      switch (el.GetNP())
+      {
+      case 4: et = NG_TET; break;
+      case 5: et = NG_PYRAMID; break;
+      case 6: et = NG_PRISM; break;
+      case 10: et = NG_TET10; break;
+      default:
+         et = NG_TET; break; // for the compiler
+      }
+	  domain = el.GetIndex();
+      return et;
+   }
+
+
+
+
+   // Set a global limit on the maximum mesh size allowed
+   DLL_HEADER void Ng_RestrictMeshSizeGlobal (Ng_Mesh * mesh, double h)
+   {
+      ((Mesh*)mesh) -> SetGlobalH (h);
+   }
+
+
+
+
+   // Set a local limit on the maximum mesh size allowed around the given point
+   DLL_HEADER void Ng_RestrictMeshSizePoint (Ng_Mesh * mesh, double * p, double h)
+   {
+      ((Mesh*)mesh) -> RestrictLocalH (Point3d (p[0], p[1], p[2]), h);
+   }
+
+
+
+
+   // Set a local limit on the maximum mesh size allowed within a given box region
+   DLL_HEADER void Ng_RestrictMeshSizeBox (Ng_Mesh * mesh, double * pmin, double * pmax, double h)
+   {
+      for (double x = pmin[0]; x < pmax[0]; x += h)
+         for (double y = pmin[1]; y < pmax[1]; y += h)
+            for (double z = pmin[2]; z < pmax[2]; z += h)
+               ((Mesh*)mesh) -> RestrictLocalH (Point3d (x, y, z), h);
+   }
+
+
+
+
+   // Generates volume mesh from an existing surface mesh
+   DLL_HEADER Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp)
+   {
+      Mesh * m = (Mesh*)mesh;
+
+      // Philippose - 30/08/2009
+      // Do not locally re-define "mparam" here... "mparam" is a global 
+      // object 
+      //MeshingParameters mparam;
+      mp->Transfer_Parameters();
+
+      m->CalcLocalH(mparam.grading);
+
+      MeshVolume (mparam, *m);
+      RemoveIllegalElements (*m);
+      OptimizeVolume (mparam, *m);
+
+      return NG_OK;
+   }
+
+   // added by Bryn Lloyd, blloyd@vision.ee.ethz.ch
+   DLL_HEADER Ng_Result Ng_OptimizeVolume (Ng_Mesh *mesh, Ng_Meshing_Parameters *mp)
+   {
+	   Mesh * m = (Mesh*)mesh;
+
+	   mp->Transfer_Parameters();
+
+	   m->CalcLocalH(mparam.grading);
+
+	   RemoveIllegalElements (*m);
+	   OptimizeVolume (mparam, *m);
+
+	   return NG_OK;
+   }
+
+
+
+   /* ------------------ 2D Meshing Functions ------------------------- */
+   DLL_HEADER void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x)
+   {
+      Mesh * m = (Mesh*)mesh;
+
+      m->AddPoint (Point3d (x[0], x[1], 0));
+   }
+
+
+
+
+   DLL_HEADER void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2)
+   {
+      Mesh * m = (Mesh*)mesh;
+
+      Segment seg;
+      seg[0] = pi1;
+      seg[1] = pi2;
+      m->AddSegment (seg);
+   }
+
+
+   DLL_HEADER void Ng_SetupFacedescriptors (Ng_Mesh * mesh, int maxdomnr)
+   {
+	   Mesh * m = (Mesh*)mesh;
+	   m->ClearFaceDescriptors();
+	   for (int i = 1; i <= maxdomnr; i++)
+		   m->AddFaceDescriptor (FaceDescriptor (i, 0, 0, i));
+   }
+
+   DLL_HEADER void Ng_AddTriangle_2D (Ng_Mesh * mesh, int pi1, int pi2, int pi3, int matnum)
+   {
+	   Mesh * m = (Mesh*)mesh;
+
+	   Element2d tri;
+	   tri[0] = pi1;
+	   tri[1] = pi2;
+	   tri[2] = pi3;
+	   tri.SetIndex(matnum);
+	   m->AddSurfaceElement (tri);
+   }
+
+
+   DLL_HEADER int Ng_GetNP_2D (Ng_Mesh * mesh)
+   {
+      Mesh * m = (Mesh*)mesh;
+      return m->GetNP();
+   }
+
+
+
+
+   DLL_HEADER int Ng_GetNE_2D (Ng_Mesh * mesh)
+   {
+      Mesh * m = (Mesh*)mesh;
+      return m->GetNSE();
+   }
+
+
+
+
+   DLL_HEADER int Ng_GetNSeg_2D (Ng_Mesh * mesh)
+   {
+      Mesh * m = (Mesh*)mesh;
+      return m->GetNSeg();
+   }
+
+
+
+
+   DLL_HEADER void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x)
+   {
+      Mesh * m = (Mesh*)mesh;
+
+      Point<3> & p = m->Point(num);
+      x[0] = p(0);
+      x[1] = p(1);
+   }
+
+
+
+
+   DLL_HEADER Ng_Surface_Element_Type
+      Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum)
+   {
+      const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num);
+      for (int i = 1; i <= el.GetNP(); i++)
+         pi[i-1] = el.PNum(i);
+
+      Ng_Surface_Element_Type et;
+      switch (el.GetNP())
+      {
+      case 3: et = NG_TRIG; break;
+      case 4: et = NG_QUAD; break;
+      case 6: 
+         switch (el.GetNV())
+         {
+         case 3: et = NG_TRIG6; break;
+         case 4: et = NG_QUAD6; break;
+         default:
+            et = NG_TRIG6; break;
+         }
+         break;
+      case 8: et = NG_QUAD8; break;
+      default:
+         et = NG_TRIG; break; // for the compiler
+      }
+
+      if (matnum)
+         *matnum = el.GetIndex();
+
+      return et;
+   }
+
+
+
+
+   DLL_HEADER void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum)
+   {
+      const Segment & seg = ((Mesh*)mesh)->LineSegment(num);
+      pi[0] = seg[0];
+      pi[1] = seg[1];
+
+      if (matnum)
+         *matnum = seg.edgenr;
+   }
+
+
+
+
+   DLL_HEADER Ng_Geometry_2D * Ng_LoadGeometry_2D (const char * filename)
+   {
+      SplineGeometry2d * geom = new SplineGeometry2d();
+      geom -> Load (filename);
+      return (Ng_Geometry_2D *)geom;
+   }
+
+
+   DLL_HEADER Ng_Geometry_2D * Ng_NewGeometry_2D ()
+   {
+	   SplineGeometry2d * geom = new SplineGeometry2d();
+	   return (Ng_Geometry_2D *)geom;
+   }
+
+   DLL_HEADER void Ng_DeleteGeometry_2D (Ng_Geometry_2D * geom)
+   {
+	   if (geom)
+	   {
+		   SplineGeometry2d* spline_geom = (SplineGeometry2d*)geom;
+		   delete spline_geom;
+		   geom = NULL;
+	   }
+   }
+
+   DLL_HEADER void Ng_AppendPoint_2D (Ng_Geometry_2D* geom, double * x, double h)
+   {
+	   if (geom)
+	   {
+		   SplineGeometry2d* spline_geom = (SplineGeometry2d*)geom;
+		   Point<2> p(x[0],x[1]);
+		   spline_geom->AppendPoint(p, h);
+	   }
+   }
+
+   DLL_HEADER void Ng_AppendLineSegment_2D (Ng_Geometry_2D* geom, int n1, int n2,
+	   int leftdomain, int rightdomain, double h)
+   {
+	   if (geom)
+	   {
+		   SplineGeometry2d* spline_geom = (SplineGeometry2d*)geom;
+		   // zero-offset!
+		   LineSeg<2>* line = new LineSeg<2>(spline_geom->geompoints[n1], spline_geom->geompoints[n2]);
+		   SplineSegExt* seg = new SplineSegExt(*line);
+		   seg->leftdom = leftdomain;
+		   seg->rightdom = rightdomain;
+		   seg->hmax = h;
+		   seg->copyfrom = -1;
+		   seg->bc = 1;
+		   spline_geom->AppendSegment(seg);
+	   }
+   }
+
+
+   DLL_HEADER Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom,
+                                            Ng_Mesh ** mesh,
+                                            Ng_Meshing_Parameters * mp)
+   {
+      // use global variable mparam
+      //  MeshingParameters mparam;  
+      mp->Transfer_Parameters();
+
+      shared_ptr<Mesh> m(new Mesh, &NOOP_Deleter);
+      MeshFromSpline2D (*(SplineGeometry2d*)geom, m, mparam);
+      // new shared_ptr<Mesh> (m);  // hack to keep mesh m alive 
+
+      cout << m->GetNSE() << " elements, " << m->GetNP() << " points" << endl;
+
+      *mesh = (Ng_Mesh*)m.get();
+      return NG_OK;
+   }
+
+
+   DLL_HEADER Ng_Result Ng_OptimizeMesh_2D (Ng_Mesh *mesh, 
+	   Ng_Meshing_Parameters * mp)
+   {
+	   Mesh * m = (Mesh*)mesh;
+
+	   mp->Transfer_Parameters();
+
+	   m->CalcLocalH(mparam.grading);
+
+	   Optimize2d(*m, mparam);
+
+	   return NG_OK;
+   }
+
+
+   DLL_HEADER void Ng_HP_Refinement (Ng_Geometry_2D * geom,
+      Ng_Mesh * mesh,
+      int levels)
+   {
+      Refinement2d ref(*(SplineGeometry2d*)geom);
+      HPRefinement (*(Mesh*)mesh, &ref, levels);
+   }
+
+
+
+
+   DLL_HEADER void Ng_HP_Refinement (Ng_Geometry_2D * geom,
+      Ng_Mesh * mesh,
+      int levels, double parameter)
+   {
+      Refinement2d ref(*(SplineGeometry2d*)geom);
+      HPRefinement (*(Mesh*)mesh, &ref, levels, parameter);
+   }
+
+
+
+
+   Array<STLReadTriangle> readtrias; //only before initstlgeometry
+   Array<Point<3> > readedges; //only before init stlgeometry
+
+   // loads geometry from STL file
+   DLL_HEADER Ng_STL_Geometry * Ng_STL_LoadGeometry (const char * filename, int binary)
+   {
+      int i;
+      STLGeometry geom;
+      STLGeometry* geo;
+      ifstream ist(filename);
+
+      if (binary)
+      {
+         geo = geom.LoadBinary(ist);
+      }
+      else
+      {
+         geo = geom.Load(ist);
+      }
+
+      readtrias.SetSize(0);
+      readedges.SetSize(0);
+
+      Point3d p;
+      Vec3d normal;
+      double p1[3];
+      double p2[3];
+      double p3[3];
+      double n[3];
+
+      Ng_STL_Geometry * geo2 = Ng_STL_NewGeometry();
+
+      for (i = 1; i <= geo->GetNT(); i++)
+      {
+         const STLTriangle& t = geo->GetTriangle(i);
+         p = geo->GetPoint(t.PNum(1));
+         p1[0] = p.X(); p1[1] = p.Y(); p1[2] = p.Z(); 
+         p = geo->GetPoint(t.PNum(2));
+         p2[0] = p.X(); p2[1] = p.Y(); p2[2] = p.Z(); 
+         p = geo->GetPoint(t.PNum(3));
+         p3[0] = p.X(); p3[1] = p.Y(); p3[2] = p.Z();
+         normal = t.Normal();
+         n[0] = normal.X(); n[1] = normal.Y(); n[2] = normal.Z();
+
+         Ng_STL_AddTriangle(geo2, p1, p2, p3, n);
+      }
+
+      return geo2;
+   }
+
+
+
+
+   // generate new STL Geometry
+   DLL_HEADER Ng_STL_Geometry * Ng_STL_NewGeometry ()
+   {
+      return (Ng_STL_Geometry*)(void*)new STLGeometry;
+   } 
+
+
+   DLL_HEADER void Ng_STL_DeleteGeometry (Ng_STL_Geometry * geom)
+   {
+	   if (geom)
+	   {
+		   STLGeometry* geometry = (STLGeometry*)geom;
+		   geometry->Clear();
+		   delete geometry;
+		   geometry = NULL;
+	   }
+   }
+
+
+   // after adding triangles (and edges) initialize
+   DLL_HEADER Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom)
+   {
+      STLGeometry* geo = (STLGeometry*)geom;
+      geo->InitSTLGeometry(readtrias);
+      readtrias.SetSize(0);
+
+      if (readedges.Size() != 0)
+      {
+         /*
+         for (int i = 1; i <= readedges.Size(); i+=2)
+         {
+         cout << "e(" << readedges.Get(i) << "," << readedges.Get(i+1) << ")" << endl;
+         }
+         */
+         geo->AddEdges(readedges);
+      }
+
+      if (geo->GetStatus() == STLTopology::STL_GOOD || geo->GetStatus() == STLTopology::STL_WARNING) return NG_OK;
+      return NG_SURFACE_INPUT_ERROR;
+   }
+
+
+
+
+   // automatically generates edges:
+   DLL_HEADER Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom,
+                                          Ng_Mesh* mesh,
+                                          Ng_Meshing_Parameters * mp)
+   {
+      STLGeometry* stlgeometry = (STLGeometry*)geom;
+      Mesh* me = (Mesh*)mesh;
+
+      // Philippose - 27/07/2009
+      // Do not locally re-define "mparam" here... "mparam" is a global 
+      // object 
+      //MeshingParameters mparam;
+      mp->Transfer_Parameters();
+
+      me -> SetGlobalH (mparam.maxh);
+      me -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+                       stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+                       0.3);
+
+      // cout << "meshsize = " << mp->meshsize_filename << endl;
+      if (mp->meshsize_filename)
+        me -> LoadLocalMeshSize (mp->meshsize_filename);
+
+      /*
+      if (mp->meshsize_filename)
+      {
+      ifstream infile (mp->meshsize_filename);
+      if (!infile.good()) return NG_FILE_NOT_FOUND;
+      me -> LoadLocalMeshSize (infile);
+      }
+      */
+
+      STLMeshing (*stlgeometry, *me);
+
+      stlgeometry->edgesfound = 1;
+      stlgeometry->surfacemeshed = 0;
+      stlgeometry->surfaceoptimized = 0;
+      stlgeometry->volumemeshed = 0;
+
+      return NG_OK;
+   }
+
+   // automatically generates edges:
+   DLL_HEADER Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom,
+	   Ng_Mesh* mesh,
+	   Ng_Meshing_Parameters * mp,
+	   Ng_STL_Parameters * stlp)
+   {
+	   STLGeometry* stlgeometry = (STLGeometry*)geom;
+	   Mesh* me = (Mesh*)mesh;
+
+	   mp->Transfer_Parameters();
+	   stlp->Transfer_Parameters();
+
+	   me->SetGlobalH(mparam.maxh);
+
+	   Box<3> box = stlgeometry->GetBoundingBox();
+	   double delta = 0.05 * box.Diam();
+	   Vec3d deltav(delta, delta, delta);
+	   double grading = (mp->grading > 0.1) ? mp->grading : 0.1;
+	   me->SetLocalH(box.PMin() - deltav, box.PMax() + deltav, grading); // TODO: grading not passed to mesher!
+
+	   if (mp->meshsize_filename)
+	   {
+		   me->LoadLocalMeshSize(mp->meshsize_filename);
+	   }
+
+	   STLMeshing (*stlgeometry, *me);
+
+	   stlgeometry->edgesfound = 1;
+	   stlgeometry->surfacemeshed = 0;
+	   stlgeometry->surfaceoptimized = 0;
+	   stlgeometry->volumemeshed = 0;
+
+	   return NG_OK;
+   }
+
+
+
+   // generates mesh, empty mesh be already created.
+   DLL_HEADER Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom,
+                                                    Ng_Mesh* mesh,
+                                                    Ng_Meshing_Parameters * mp)
+   {
+      STLGeometry* stlgeometry = (STLGeometry*)geom;
+      Mesh* me = (Mesh*)mesh;
+
+      // Philippose - 27/07/2009
+      // Do not locally re-define "mparam" here... "mparam" is a global 
+      // object
+      //MeshingParameters mparam;
+      mp->Transfer_Parameters();
+
+
+      /*
+      me -> SetGlobalH (mparam.maxh);
+      me -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+      stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+      0.3);
+      */
+      /*
+      STLMeshing (*stlgeometry, *me);
+
+      stlgeometry->edgesfound = 1;
+      stlgeometry->surfacemeshed = 0;
+      stlgeometry->surfaceoptimized = 0;
+      stlgeometry->volumemeshed = 0;
+      */  
+      int retval = STLSurfaceMeshing (*stlgeometry, *me);
+      if (retval == MESHING3_OK)
+      {
+         (*mycout) << "Success !!!!" << endl;
+         stlgeometry->surfacemeshed = 1;
+         stlgeometry->surfaceoptimized = 0;
+         stlgeometry->volumemeshed = 0;
+      } 
+      else if (retval == MESHING3_OUTERSTEPSEXCEEDED)
+      {
+         (*mycout) << "ERROR: Give up because of too many trials. Meshing aborted!" << endl;
+      }
+      else if (retval == MESHING3_TERMINATE)
+      {
+         (*mycout) << "Meshing Stopped!" << endl;
+      }
+      else
+      {
+         (*mycout) << "ERROR: Surface meshing not successful. Meshing aborted!" << endl;
+      }
+
+
+      STLSurfaceOptimization (*stlgeometry, *me, mparam);
+
+      return NG_OK;
+   }
+
+   // optimizes an existing surface mesh
+   DLL_HEADER Ng_Result Ng_STL_OptimizeSurfaceMesh (Ng_STL_Geometry * geom,
+	   Ng_Mesh * mesh,
+	   Ng_Meshing_Parameters * mp,
+	   Ng_STL_Parameters * stlp)
+   {
+	   STLGeometry* stlgeometry = (STLGeometry*)geom;
+	   Mesh* me = (Mesh*)mesh;
+
+	   PointGeomInfo gi;
+	   for(int i=1; i<=me->GetNSE(); i++)
+	   {
+		   Element2d &el = me->SurfaceElement(i);
+
+		   for(int d=0; d<3; d++)
+		   {
+			   gi.trignum = i;
+			   el.GeomInfoPi(d + 1) = gi;
+		   }
+	   }
+
+	   mp->Transfer_Parameters();
+	   stlp->Transfer_Parameters();
+
+	   STLSurfaceOptimization (*stlgeometry, *me, mparam);
+
+	   return NG_OK;
+   }
+
+
+   // generates mesh, empty mesh be already created.
+   DLL_HEADER Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom,
+	   Ng_Mesh* mesh,
+	   Ng_Meshing_Parameters * mp,
+	   Ng_STL_Parameters * stlp)
+   {
+	   STLGeometry* stlgeometry = (STLGeometry*)geom;
+	   Mesh* me = (Mesh*)mesh;
+
+	   mp->Transfer_Parameters();
+	   stlp->Transfer_Parameters();
+
+	   int retval = STLSurfaceMeshing (*stlgeometry, *me);
+	   if (retval == MESHING3_OK)
+	   {
+		   (*mycout) << "Success !!!!" << endl;
+		   stlgeometry->surfacemeshed = 1;
+		   stlgeometry->surfaceoptimized = 0;
+		   stlgeometry->volumemeshed = 0;
+	   } 
+	   else if (retval == MESHING3_OUTERSTEPSEXCEEDED)
+	   {
+		   (*mycout) << "ERROR: Give up because of too many trials. Meshing aborted!" << endl;
+	   }
+	   else if (retval == MESHING3_TERMINATE)
+	   {
+		   (*mycout) << "Meshing Stopped!" << endl;
+	   }
+	   else
+	   {
+		   (*mycout) << "ERROR: Surface meshing not successful. Meshing aborted!" << endl;
+	   }
+
+
+	   STLSurfaceOptimization (*stlgeometry, *me, mparam);
+
+	   return NG_OK;
+   }
+
+
+
+   // fills STL Geometry
+   // positive orientation
+   // normal vector may be null-pointer
+   DLL_HEADER void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, 
+                                       double * p1, double * p2, double * p3, 
+                                       double * nv)
+   {
+      Point<3> apts[3];
+      apts[0] = Point<3>(p1[0],p1[1],p1[2]);
+      apts[1] = Point<3>(p2[0],p2[1],p2[2]);
+      apts[2] = Point<3>(p3[0],p3[1],p3[2]);
+
+      Vec<3> n;
+      if (!nv)
+         n = Cross (apts[0]-apts[1], apts[0]-apts[2]);
+      else
+         n = Vec<3>(nv[0],nv[1],nv[2]);
+
+      readtrias.Append(STLReadTriangle(apts,n));
+   }
+
+   // add (optional) edges:
+   DLL_HEADER void Ng_STL_AddEdge (Ng_STL_Geometry * geom, 
+      double * p1, double * p2)
+   {
+      readedges.Append(Point3d(p1[0],p1[1],p1[2]));
+      readedges.Append(Point3d(p2[0],p2[1],p2[2]));
+   }
+
+
+
+
+#ifdef OCCGEOMETRY
+   // --------------------- OCC Geometry / Meshing Utility Functions -------------------
+   // Create new OCC Geometry Object
+   DLL_HEADER Ng_OCC_Geometry * Ng_OCC_NewGeometry ()
+   {
+      return (Ng_OCC_Geometry*)(void*)new OCCGeometry;
+   } 
+
+
+
+
+   // Delete the OCC Geometry Object
+   DLL_HEADER Ng_Result Ng_OCC_DeleteGeometry(Ng_OCC_Geometry * geom)
+   {
+      if (geom != NULL)
+      {
+         delete (OCCGeometry*)geom;
+         geom = NULL;
+         return NG_OK;
+      }
+      
+      return NG_ERROR;
+   }
+
+
+
+   
+   // Loads geometry from STEP File
+   DLL_HEADER Ng_OCC_Geometry * Ng_OCC_Load_STEP (const char * filename)
+   {
+      // Call the STEP File Load function. Note.. the geometry class 
+      // is created and instantiated within the load function
+      OCCGeometry * occgeo = LoadOCC_STEP(filename);
+
+      return ((Ng_OCC_Geometry *)occgeo);
+   }
+
+
+
+   
+   // Loads geometry from IGES File
+   DLL_HEADER Ng_OCC_Geometry * Ng_OCC_Load_IGES (const char * filename)
+   {
+      // Call the IGES File Load function. Note.. the geometry class 
+      // is created and instantiated within the load function
+      OCCGeometry * occgeo = LoadOCC_IGES(filename);
+
+      return ((Ng_OCC_Geometry *)occgeo);
+   }
+
+
+
+   
+   // Loads geometry from BREP File
+   DLL_HEADER Ng_OCC_Geometry * Ng_OCC_Load_BREP (const char * filename)
+   {
+      // Call the BREP File Load function. Note.. the geometry class 
+      // is created and instantiated within the load function
+      OCCGeometry * occgeo = LoadOCC_BREP(filename);
+
+      return ((Ng_OCC_Geometry *)occgeo);
+   }
+
+
+
+
+   // Locally limit the size of the mesh to be generated at various points 
+   // based on the topology of the geometry
+   DLL_HEADER Ng_Result Ng_OCC_SetLocalMeshSize (Ng_OCC_Geometry * geom,
+                                                 Ng_Mesh * mesh,
+                                                 Ng_Meshing_Parameters * mp)
+   {
+      OCCGeometry * occgeom = (OCCGeometry*)geom;
+      Mesh * me = (Mesh*)mesh;
+
+      me->geomtype = Mesh::GEOM_OCC;
+
+      mp->Transfer_Parameters();
+      
+      occparam.resthcloseedgeenable = mp->closeedgeenable;
+      occparam.resthcloseedgefac = mp->closeedgefact;
+
+      // Delete the mesh structures in order to start with a clean 
+      // slate
+      me->DeleteMesh();
+
+      OCCSetLocalMeshSize(*occgeom, *me);
+
+      return(NG_OK);
+   }
+
+
+
+   
+   // Mesh the edges and add Face descriptors to prepare for surface meshing
+   DLL_HEADER Ng_Result Ng_OCC_GenerateEdgeMesh (Ng_OCC_Geometry * geom,
+                                                 Ng_Mesh * mesh,
+                                                 Ng_Meshing_Parameters * mp)
+   {
+      OCCGeometry * occgeom = (OCCGeometry*)geom;
+      Mesh * me = (Mesh*)mesh;
+
+      mp->Transfer_Parameters();
+
+      OCCFindEdges(*occgeom, *me);
+
+      if((me->GetNP()) && (me->GetNFD()))
+      {
+         return NG_OK;
+      }
+      else
+      {
+         return NG_ERROR;
+      }
+   }
+
+
+
+   
+   // Mesh the edges and add Face descriptors to prepare for surface meshing
+   DLL_HEADER Ng_Result Ng_OCC_GenerateSurfaceMesh (Ng_OCC_Geometry * geom,
+                                                    Ng_Mesh * mesh,
+                                                    Ng_Meshing_Parameters * mp)
+   {
+      int numpoints = 0;
+
+      OCCGeometry * occgeom = (OCCGeometry*)geom;
+      Mesh * me = (Mesh*)mesh;
+
+      // Set the internal meshing parameters structure from the nglib meshing 
+      // parameters structure
+      mp->Transfer_Parameters();
+
+
+      // Only go into surface meshing if the face descriptors have already been added
+      if(!me->GetNFD())
+         return NG_ERROR;
+
+      numpoints = me->GetNP();
+
+      // Initially set up only for surface meshing without any optimisation
+      int perfstepsend = MESHCONST_MESHSURFACE;
+
+      // Check and if required, enable surface mesh optimisation step
+      if(mp->optsurfmeshenable)
+      {
+         perfstepsend = MESHCONST_OPTSURFACE;
+      }
+
+      OCCMeshSurface(*occgeom, *me, perfstepsend);
+
+      me->CalcSurfacesOfNode();
+      
+      if(me->GetNP() <= numpoints)
+         return NG_ERROR;
+
+      if(me->GetNSE() <= 0)
+         return NG_ERROR;
+
+      return NG_OK;
+   }
+
+
+
+
+   // Extract the face map from the OCC geometry
+   // The face map basically gives an index to each face in the geometry, 
+   // which can be used to access a specific face
+   DLL_HEADER Ng_Result Ng_OCC_GetFMap(Ng_OCC_Geometry * geom, 
+                                       Ng_OCC_TopTools_IndexedMapOfShape * FMap)
+   {
+      OCCGeometry* occgeom = (OCCGeometry*)geom;
+      TopTools_IndexedMapOfShape *occfmap = (TopTools_IndexedMapOfShape *)FMap;
+
+      // Copy the face map from the geometry to the given variable
+      occfmap->Assign(occgeom->fmap);
+
+      if(occfmap->Extent())
+      {
+         return NG_OK;
+      }
+      else
+      {
+         return NG_ERROR;
+      }
+   }
+
+   // ------------------ End - OCC Geometry / Meshing Utility Functions ----------------
+#endif
+
+
+
+
+   // ------------------ Begin - Meshing Parameters related functions ------------------
+   // Constructor for the local nglib meshing parameters class
+   DLL_HEADER Ng_Meshing_Parameters :: Ng_Meshing_Parameters()
+   {
+      uselocalh = 1;
+
+      maxh = 1000;
+      minh = 0.0;
+
+      fineness = 0.5;
+      grading = 0.3;
+
+      elementsperedge = 2.0;
+      elementspercurve = 2.0;
+
+      closeedgeenable = 0;
+      closeedgefact = 2.0;
+
+	  minedgelenenable = 0;
+	  minedgelen = 1e-4;
+
+      second_order = 0;
+      quad_dominated = 0;
+
+      meshsize_filename = 0;
+
+      optsurfmeshenable = 1;
+      optvolmeshenable = 1;
+
+      optsteps_2d = 3;
+      optsteps_3d = 3;
+
+	  optimize3d = "cmdmustm";
+	  optimize2d = "smsmsmSmSmSm";
+
+      invert_tets = 0;
+      invert_trigs = 0;
+
+      check_overlap = 1;
+      check_overlapping_boundary = 1;
+   }
+
+
+
+
+   // Reset the local meshing parameters to the default values
+   DLL_HEADER void Ng_Meshing_Parameters :: Reset_Parameters()
+   {
+      uselocalh = 1;
+
+      maxh = 1000;
+      minh = 0;
+
+      fineness = 0.5;
+      grading = 0.3;
+
+      elementsperedge = 2.0;
+      elementspercurve = 2.0;
+
+      closeedgeenable = 0;
+      closeedgefact = 2.0;
+
+  	  minedgelenenable = 0;
+	  minedgelen = 1e-4;
+
+      second_order = 0;
+      quad_dominated = 0;
+
+      meshsize_filename = 0;
+
+      optsurfmeshenable = 1;
+      optvolmeshenable = 1;
+
+      optsteps_2d = 3;
+      optsteps_3d = 3;
+
+	  optimize3d = "cmdmustm";
+	  optimize2d = "smsmsmSmSmSm";
+
+      invert_tets = 0;
+      invert_trigs = 0;
+
+      check_overlap = 1;
+      check_overlapping_boundary = 1;
+   }
+
+
+
+
+   // 
+   DLL_HEADER void Ng_Meshing_Parameters :: Transfer_Parameters()
+   {
+      mparam.uselocalh = uselocalh;
+      
+      mparam.maxh = maxh;
+      mparam.minh = minh;
+
+      mparam.grading = grading;
+      mparam.curvaturesafety = elementspercurve;
+      mparam.segmentsperedge = elementsperedge;
+
+      mparam.secondorder = second_order;
+      mparam.quad = quad_dominated;
+
+      if (meshsize_filename)
+        mparam.meshsizefilename = meshsize_filename;
+      else
+        mparam.meshsizefilename = "";
+      mparam.optsteps2d = optsteps_2d;
+      mparam.optsteps3d = optsteps_3d;
+
+	  if(strlen(optimize2d) > 0) mparam.optimize2d = optimize2d;
+	  if(strlen(optimize3d) > 0) mparam.optimize3d = optimize3d;
+
+      mparam.inverttets = invert_tets;
+      mparam.inverttrigs = invert_trigs;
+
+      mparam.checkoverlap = check_overlap;
+      mparam.checkoverlappingboundary = check_overlapping_boundary;
+   }
+
+   DLL_HEADER Ng_STL_Parameters :: Ng_STL_Parameters()
+   {
+	   Reset_Parameters();
+   }
+
+   DLL_HEADER void Ng_STL_Parameters :: Reset_Parameters()
+   {
+	   yangle = 30;
+	   contyangle = 20;
+
+	   chartangle = 10; // original = 15
+	   outerchartangle = 80; // original = 70;
+
+	   usesearchtree = 0;
+
+	   atlasminh = 1.0; // original = 1E-4
+
+	   resthatlasenable = 1;
+	   resthatlasfac = 2;
+
+	   resthchartdistenable = 1;
+	   resthchartdistfac = 0.3; // original = 1.2
+
+	   resthedgeangleenable = 0;
+	   resthedgeanglefac = 1;
+
+	   resthsurfmeshcurvenable = 1;
+	   resthsurfmeshcurvfac = 1;
+
+	   resthlinelengthenable = 1;
+	   resthlinelengthfac = 0.2; // original = 0.5
+
+	   resthcloseedgefac = 1;
+	   resthcloseedgeenable = 1;
+   }
+
+   DLL_HEADER void Ng_STL_Parameters :: Transfer_Parameters()
+   {
+	   // Algorithm may be somewhat like Canny edge detector on mesh?
+	   stlparam.yangle = yangle;
+	   stlparam.contyangle = contyangle;
+
+	   stlparam.chartangle = chartangle;
+	   stlparam.outerchartangle = outerchartangle;
+
+	   stlparam.usesearchtree = usesearchtree;
+
+	   stlparam.atlasminh = atlasminh;
+
+	   stlparam.resthatlasenable = resthatlasenable;
+	   stlparam.resthatlasfac = resthatlasfac;
+
+	   stlparam.resthchartdistenable = resthchartdistenable;
+	   stlparam.resthchartdistfac = resthchartdistfac;
+
+	   stlparam.resthedgeangleenable = resthedgeangleenable;
+	   stlparam.resthedgeanglefac = resthedgeanglefac;
+
+	   stlparam.resthsurfmeshcurvenable = resthsurfmeshcurvenable;
+	   stlparam.resthsurfmeshcurvfac = resthsurfmeshcurvfac;
+
+	   stlparam.resthlinelengthenable = resthlinelengthenable;
+	   stlparam.resthlinelengthfac = resthlinelengthfac;
+
+	   stlparam.resthcloseedgeenable = resthcloseedgeenable;
+	   stlparam.resthcloseedgefac = resthcloseedgefac;
+   }
+   // ------------------ End - Meshing Parameters related functions --------------------
+
+
+
+
+   // ------------------ Begin - Second Order Mesh generation functions ----------------
+   DLL_HEADER void Ng_Generate_SecondOrder(Ng_Mesh * mesh)
+   {
+      Refinement ref;
+      ref.MakeSecondOrder(*(Mesh*) mesh);
+   }
+
+
+
+
+   DLL_HEADER void Ng_2D_Generate_SecondOrder(Ng_Geometry_2D * geom,
+					  Ng_Mesh * mesh)
+   {
+      ( (SplineGeometry2d*)geom ) -> GetRefinement().MakeSecondOrder( * (Mesh*) mesh );
+   }
+
+
+
+
+   DLL_HEADER void Ng_STL_Generate_SecondOrder(Ng_STL_Geometry * geom,
+					   Ng_Mesh * mesh)
+   {
+      ((STLGeometry*)geom)->GetRefinement().MakeSecondOrder(*(Mesh*) mesh);
+   }
+
+
+
+
+   DLL_HEADER void Ng_CSG_Generate_SecondOrder (Ng_CSG_Geometry * geom,
+					   Ng_Mesh * mesh)
+   {
+      ((CSGeometry*)geom)->GetRefinement().MakeSecondOrder(*(Mesh*) mesh);
+   }
+
+
+
+
+#ifdef OCCGEOMETRY
+   DLL_HEADER void Ng_OCC_Generate_SecondOrder (Ng_OCC_Geometry * geom,
+                  Ng_Mesh * mesh)
+   {
+      ((OCCGeometry*)geom )->GetRefinement().MakeSecondOrder(*(Mesh*) mesh);
+   }
+#endif
+   // ------------------ End - Second Order Mesh generation functions ------------------
+
+
+
+
+   // ------------------ Begin - Uniform Mesh Refinement functions ---------------------
+   DLL_HEADER void Ng_Uniform_Refinement (Ng_Mesh * mesh)
+   {
+      Refinement ref;
+      ref.Refine ( * (Mesh*) mesh );
+   }
+
+
+
+
+   DLL_HEADER void Ng_2D_Uniform_Refinement (Ng_Geometry_2D * geom,
+      Ng_Mesh * mesh)
+   {
+      ( (SplineGeometry2d*)geom ) -> GetRefinement().Refine ( * (Mesh*) mesh );
+   }
+
+
+
+
+   DLL_HEADER void Ng_STL_Uniform_Refinement (Ng_STL_Geometry * geom,
+      Ng_Mesh * mesh)
+   {
+      ( (STLGeometry*)geom ) -> GetRefinement().Refine ( * (Mesh*) mesh );
+   }
+
+
+
+
+   DLL_HEADER void Ng_CSG_Uniform_Refinement (Ng_CSG_Geometry * geom,
+      Ng_Mesh * mesh)
+   {
+      ( (CSGeometry*)geom ) -> GetRefinement().Refine ( * (Mesh*) mesh );
+   }
+
+
+
+
+#ifdef OCCGEOMETRY
+   DLL_HEADER void Ng_OCC_Uniform_Refinement (Ng_OCC_Geometry * geom,
+      Ng_Mesh * mesh)
+   {
+      ( (OCCGeometry*)geom ) -> GetRefinement().Refine ( * (Mesh*) mesh );
+   }
+#endif
+   // ------------------ End - Uniform Mesh Refinement functions -----------------------
+} // End of namespace nglib
+
+
+
+
+// compatibility functions:
+namespace netgen 
+{
+   char geomfilename[255];
+
+   DLL_HEADER void MyError2 (const char * ch)
+   {
+      cerr << ch;
+   }
+
+
+
+
+   //Destination for messages, errors, ...
+   DLL_HEADER void Ng_PrintDest2(const char * s)
+   {
+#ifdef PARALLEL
+     int id = 0;
+     MPI_Comm_rank(MPI_COMM_WORLD, &id);
+     if (id != 0) return;
+#endif
+     (*mycout) << s << flush;
+   }
+
+
+  /*
+   DLL_HEADER double GetTime ()
+   {
+      return 0;
+   }
+  */
+
+
+#ifndef WIN32
+   void ResetTime ()
+   {
+      ;
+   }
+#endif
+
+
+
+   void MyBeep (int i)
+   {
+      ;
+   }
+
+
+
+  //void Render() { ; }
+
+} // End of namespace netgen
+
+
+/*
+
+#ifndef WIN32
+void Ng_Redraw () { ; }
+void Ng_ClearSolutionData () { ; }
+#endif
+void Ng_SetSolutionData (Ng_SolutionData * soldata) 
+{ 
+  delete soldata->solclass;
+}
+void Ng_InitSolutionData (Ng_SolutionData * soldata) { ; }
+*/
+
+// Force linking libinterface to libnglib
+#include <../interface/writeuser.hpp>
+void MyDummyToForceLinkingLibInterface(Mesh &mesh, NetgenGeometry &geom)
+{
+  netgen::WriteUserFormat("", mesh, geom, "");
+}
+
diff --git a/nglib/nglib.h b/nglib/nglib.h
index 2c2b05445..38e60faa5 100644
--- a/nglib/nglib.h
+++ b/nglib/nglib.h
@@ -616,6 +616,14 @@ Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi, int * domain = nullptr);
 
 
 // feeds points and boundary to mesh
+DLL_HEADER Ng_Geometry_2D * Ng_NewGeometry_2D();
+
+DLL_HEADER void Ng_DeleteGeometry_2D(Ng_Geometry_2D * geom);
+
+DLL_HEADER void Ng_AppendPoint_2D(Ng_Geometry_2D* geom, double * x, double h);
+
+DLL_HEADER void Ng_AppendLineSegment_2D(Ng_Geometry_2D* geom, int pi1, int pi2,
+	int leftdomain, int rightdomain, double h);
 
 DLL_HEADER void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x);
 DLL_HEADER void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2, int domain_in = -1, int domain_out = -1);
@@ -629,8 +637,7 @@ DLL_HEADER int Ng_GetNSeg_2D (Ng_Mesh * mesh);
 DLL_HEADER void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x);
 
 // return 2d elements
-DLL_HEADER Ng_Surface_Element_Type 
-Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = nullptr);
+DLL_HEADER Ng_Surface_Element_Type Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = nullptr);
 
 // return 2d boundary segment
 DLL_HEADER void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = nullptr);
@@ -643,7 +650,15 @@ DLL_HEADER Ng_Geometry_2D * Ng_LoadGeometry_2D (const char * filename);
 DLL_HEADER Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom,
                                          Ng_Mesh ** mesh,
                                          Ng_Meshing_Parameters * mp);
-  
+ 
+// functions added to make Optimize2d mesh accessible from nglib
+DLL_HEADER void Ng_SetupFacedescriptors(Ng_Mesh * mesh, int maxdomnr);
+
+DLL_HEADER void Ng_AddTriangle_2D(Ng_Mesh * mesh, int pi1, int pi2, int pi3, int matnum = 1);
+
+DLL_HEADER Ng_Result Ng_OptimizeMesh_2D(Ng_Mesh *mesh, Ng_Meshing_Parameters * mp);
+
+
 DLL_HEADER void Ng_HP_Refinement (Ng_Geometry_2D * geom,
                                   Ng_Mesh * mesh,
                                   int levels);

From b19a17f2d774cd24213eb1e06f3435767b630f62 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Fri, 1 Mar 2019 22:21:55 +0100
Subject: [PATCH 07/19] implement meshing from 2D geometry fix vtk writer for
 2d meshes extend vtk writer to write also domain index per cell

---
 libsrc/interface/writevtk.cpp | 82 ++++++++++++++++++++---------------
 nglib/nglib.cpp               | 65 +++++++++++++++++++++++++--
 nglib/nglib.h                 |  3 ++
 3 files changed, 112 insertions(+), 38 deletions(-)

diff --git a/libsrc/interface/writevtk.cpp b/libsrc/interface/writevtk.cpp
index 4e6f80ea0..ff7ba9fe7 100644
--- a/libsrc/interface/writevtk.cpp
+++ b/libsrc/interface/writevtk.cpp
@@ -50,64 +50,68 @@ void WriteVtkFormat (const Mesh & mesh,
   outfile << "POINTS " << np << " double\n";
   for (int i=0; i<np; i++)
   {
-	auto & p = mesh.Point(i+1);
+  auto & p = mesh.Point(i+1);
     outfile << p[0] << " " << p[1] << " " << p[2] << "\n";
   }
 
   std::vector<int> types;
+  std::vector<int> domains;
   if (ne > 0)
   {
     unsigned int size = 0;
     for (int i=0; i<ne; i++)
-	  size += mesh.VolumeElement(i+1).GetNV() + 1; // only save "linear" corners
+      size += mesh.VolumeElement(i+1).GetNV() + 1; // only save "linear" corners
 
     outfile << "CELLS " << ne << " " << size << "\n";
     for (int i=0; i<ne; i++)
     {
-	  auto& el = mesh.VolumeElement(i+1);
-	  switch (el.GetType())
-	  {
-	  case TET:
-	  case TET10: // reorder to follow VTK convention & zero based indices
+      auto& el = mesh.VolumeElement(i+1);
+      domains.push_back(el.GetIndex());
+      switch (el.GetType())
+      {
+      case TET:
+      case TET10: // reorder to follow VTK convention & zero based indices
         outfile << 4 << " " << el[0]-1 << " " << el[1]-1 << " " << el[3]-1 << " " << el[2]-1 << "\n";
-		types.push_back(10);
-		break;
-	  case PRISM: // reorder to follow VTK convention & zero based indices
+        types.push_back(10);
+        break;
+      case PRISM: // reorder to follow VTK convention & zero based indices
         outfile << 6 << " "
-				<< el[0]-1 << " " << el[2]-1 << " " << el[1]-1 << " " 
-				<< el[3]-1 << " " << el[5]-1 << " " << el[4]-1 << "\n";
-		types.push_back(13);
-		break;
-	  default:
-	    throw ngcore::Exception("Unexpected element type");
-		break;
-	  }
+          << el[0]-1 << " " << el[2]-1 << " " << el[1]-1 << " " 
+          << el[3]-1 << " " << el[5]-1 << " " << el[4]-1 << "\n";
+        types.push_back(13);
+        break;
+      default:
+        throw ngcore::Exception("Unexpected element type");
+        break;
+      }
     }
   }
   else
   {
     unsigned int size = 0;
-    for (int i=0; i<ne; i++)
-	  size += mesh.SurfaceElement(i+1).GetNV() + 1;
+    for (int i=0; i<nse; i++)
+      size += mesh.SurfaceElement(i+1).GetNV() + 1;
 
     outfile << "CELLS " << nse << " " << size << "\n";
     for (int i=0; i<nse; i++)
     {
-	  auto& el = mesh.SurfaceElement(i+1);
-	  switch (el.GetType())
-	  {
-	  case TRIG:
-	  case TRIG6:
-        outfile << el[0]-1 << " " << el[1]-1 << " " << el[2]-1 << "\n";
-		types.push_back(5);
-		break;
-	  case QUAD:
-        outfile << el[0]-1 << " " << el[1]-1 << " " << el[2]-1 << " " << el[3]-1 << "\n";
-		types.push_back(9);
-	  default:
-	    throw ngcore::Exception("Unexpected element type");
-		break;
-	  }
+      auto& el = mesh.SurfaceElement(i+1);
+      domains.push_back(el.GetIndex());
+      switch (el.GetType())
+      {
+      case TRIG:
+      case TRIG6:
+        outfile << 3 << " " << el[0]-1 << " " << el[1]-1 << " " << el[2]-1 << "\n";
+        types.push_back(5);
+        break;
+      case QUAD:
+        outfile << 4 << " " << el[0]-1 << " " << el[1]-1 << " " << el[2]-1 << " " << el[3]-1 << "\n";
+        types.push_back(9);
+        break;
+      default:
+        throw ngcore::Exception("Unexpected element type");
+      break;
+      }
     }
   }
 
@@ -117,6 +121,14 @@ void WriteVtkFormat (const Mesh & mesh,
     outfile << type_id << "\n";
   }
 
+  outfile << "CELL_DATA " << domains.size() << "\n";
+  outfile << "SCALARS scalars int 1\n";
+  outfile << "LOOKUP_TABLE default\n";
+  for (auto id: domains)
+  {
+    outfile << id << "\n";
+  }
+
   outfile.close();
 }
 }
diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index df3447a03..18dfd24b2 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -591,6 +591,68 @@ namespace nglib
    }
 
 
+   DLL_HEADER Ng_Geometry_2D * Ng_NewGeometry_2D ()
+   {
+      SplineGeometry2d * geom = new SplineGeometry2d();
+      return (Ng_Geometry_2D *)geom;
+   }
+
+   DLL_HEADER void Ng_DeleteGeometry_2D (Ng_Geometry_2D * geom)
+   {
+      if (geom)
+      {
+         SplineGeometry2d* spline_geom = (SplineGeometry2d*)geom;
+         delete spline_geom;
+         geom = NULL;
+      }
+   }
+
+   DLL_HEADER void Ng_AppendPoint_2D (Ng_Geometry_2D* geom, double * x, double h)
+   {
+      if (geom)
+      {
+         SplineGeometry2d* spline_geom = (SplineGeometry2d*)geom;
+         Point<2> p(x[0],x[1]);
+         spline_geom->AppendPoint(p, h);
+      }
+   }
+
+   DLL_HEADER void Ng_AppendLineSegment_2D (Ng_Geometry_2D* geom, int n1, int n2,
+      int leftdomain, int rightdomain, double h)
+   {
+      if (geom)
+      {
+         SplineGeometry2d* spline_geom = (SplineGeometry2d*)geom;
+         // zero-offset!
+         LineSeg<2>* line = new LineSeg<2>(spline_geom->geompoints[n1-1], spline_geom->geompoints[n2-1]);
+         SplineSegExt* seg = new SplineSegExt(*line);
+         seg->leftdom = leftdomain;
+         seg->rightdom = rightdomain;
+         seg->hmax = h;
+         seg->copyfrom = -1;
+         seg->bc = 1;
+         spline_geom->AppendSegment(seg);
+      }
+   }
+
+   DLL_HEADER void Ng_AppendSplinSegment_2D (Ng_Geometry_2D* geom, int n1, int n2, int n3,
+      int leftdomain, int rightdomain, double h)
+   {
+      if (geom)
+      {
+         SplineGeometry2d* spline_geom = (SplineGeometry2d*)geom;
+         // zero-offset!
+         SplineSeg3<2>* line = new SplineSeg3<2>(spline_geom->geompoints[n1-1], spline_geom->geompoints[n2-1], spline_geom->geompoints[n3-1]);
+         SplineSegExt* seg = new SplineSegExt(*line);
+         seg->leftdom = leftdomain;
+         seg->rightdom = rightdomain;
+         seg->hmax = h;
+         seg->copyfrom = -1;
+         seg->bc = 1;
+         spline_geom->AppendSegment(seg);
+      }
+   }
+
    DLL_HEADER Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom,
                                             Ng_Mesh ** mesh,
                                             Ng_Meshing_Parameters * mp)
@@ -601,9 +663,6 @@ namespace nglib
 
       shared_ptr<Mesh> m(new Mesh, &NOOP_Deleter);
       MeshFromSpline2D (*(SplineGeometry2d*)geom, m, mparam);
-      // new shared_ptr<Mesh> (m);  // hack to keep mesh m alive 
-      
-      cout << m->GetNSE() << " elements, " << m->GetNP() << " points" << endl;
 
       *mesh = (Ng_Mesh*)m.get();
       return NG_OK;
diff --git a/nglib/nglib.h b/nglib/nglib.h
index 38e60faa5..28155ad7d 100644
--- a/nglib/nglib.h
+++ b/nglib/nglib.h
@@ -625,6 +625,9 @@ DLL_HEADER void Ng_AppendPoint_2D(Ng_Geometry_2D* geom, double * x, double h);
 DLL_HEADER void Ng_AppendLineSegment_2D(Ng_Geometry_2D* geom, int pi1, int pi2,
 	int leftdomain, int rightdomain, double h);
 
+DLL_HEADER void Ng_AppendSplinSegment_2D(Ng_Geometry_2D* geom, int pi1, int pi2, int pi3,
+	int leftdomain, int rightdomain, double h);
+
 DLL_HEADER void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x);
 DLL_HEADER void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2, int domain_in = -1, int domain_out = -1);
   

From 0d83ea01cda5b32b5df50f6b16b3bbe39b48f57e Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Fri, 1 Mar 2019 22:39:03 +0100
Subject: [PATCH 08/19] replace quadratric spline by Bspline

---
 nglib/nglib.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index 18dfd24b2..25e2f4bab 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -642,7 +642,12 @@ namespace nglib
       {
          SplineGeometry2d* spline_geom = (SplineGeometry2d*)geom;
          // zero-offset!
-         SplineSeg3<2>* line = new SplineSeg3<2>(spline_geom->geompoints[n1-1], spline_geom->geompoints[n2-1], spline_geom->geompoints[n3-1]);
+         Array<Point<2> > pts;
+         pts.Append(spline_geom->geompoints[n1-1]);
+         pts.Append(spline_geom->geompoints[n2-1]);
+         pts.Append(spline_geom->geompoints[n3-1]);
+         auto line = new BSplineSeg<2,3>(pts);
+         //SplineSeg3<2>* line = new SplineSeg3<2>(spline_geom->geompoints[n1-1], spline_geom->geompoints[n2-1], spline_geom->geompoints[n3-1]);
          SplineSegExt* seg = new SplineSegExt(*line);
          seg->leftdom = leftdomain;
          seg->rightdom = rightdomain;

From 0be72fb3744caaabad5326a8ca4e4db05f120d3c Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Mon, 4 Mar 2019 14:46:11 +0100
Subject: [PATCH 09/19] add missing ingredient to tag faces for
 preserving/reconstructing face ids (surfnr, bcnr, domin, domout) via
 FaceDescriptor

---
 nglib/nglib.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++-----
 nglib/nglib.h   | 25 +++++++++++++++---
 2 files changed, 82 insertions(+), 10 deletions(-)

diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index 25e2f4bab..b0af1059c 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -241,9 +241,52 @@ namespace nglib
    }
 
 
+   DLL_HEADER void Ng_ClearFaceDescriptors (Ng_Mesh * ng_mesh)
+   {
+      Mesh * mesh = (Mesh*)ng_mesh;
+      mesh->ClearFaceDescriptors();
+   }
+
+
+   DLL_HEADER int Ng_AddFaceDescriptor (Ng_Mesh * ng_mesh, int surfnr, int domin, int domout, int bcp)
+   {
+      Mesh * mesh = (Mesh*)ng_mesh;
+      int nfd = mesh->GetNFD();
+      
+      int faceind = 0;
+      for (int j = 1; j <= nfd; j++)
+      {
+         if (mesh->GetFaceDescriptor(j).SurfNr() == surfnr 
+            && mesh->GetFaceDescriptor(j).BCProperty() == bcp 
+            && mesh->GetFaceDescriptor(j).DomainIn() == domin 
+            && mesh->GetFaceDescriptor(j).DomainOut() == domout)
+         {
+            faceind = j;
+            break;
+         }
+      }
+
+      if (!faceind)
+      {
+         faceind = mesh->AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));
+         mesh->GetFaceDescriptor(faceind).SetBCProperty (bcp);
+      }
+      return faceind;
+   }
+
+
+   DLL_HEADER void Ng_SetupFacedescriptors (Ng_Mesh * mesh, int maxbc)
+   {
+	   Mesh * m = (Mesh*)mesh;
+	   m->ClearFaceDescriptors();
+	   for (int i = 1; i <= maxbc; i++)
+		   m->AddFaceDescriptor (FaceDescriptor (i, 0, 0, i));
+   }
+
+
    // Manually add a surface element of a given type to an existing mesh object
    DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et,
-                                         int * pi, int domain)
+                                         int * pi, int facenr)
    {
       int n = 3;
       switch (et)
@@ -263,7 +306,7 @@ namespace nglib
       
       Mesh * m = (Mesh*)mesh;
       Element2d el (n);
-      el.SetIndex (domain);
+      el.SetIndex (facenr);
       for (int i=0; i<n; ++i)
          el.PNum(i+1) = pi[i];
       m->AddSurfaceElement (el);
@@ -338,11 +381,23 @@ namespace nglib
    }
 
 
-
+   DLL_HEADER bool Ng_GetFaceDescriptor (Ng_Mesh * mesh, int facenr, int &surfnr, int &domin, int &domout, int &bcp)
+   {
+      Mesh * m = (Mesh*)mesh;
+      if (facenr <= m->GetNFD())
+      {
+         surfnr = m->GetFaceDescriptor(facenr).SurfNr();
+         domin = m->GetFaceDescriptor(facenr).DomainIn();
+         domout = m->GetFaceDescriptor(facenr).DomainOut();
+         bcp = m->GetFaceDescriptor(facenr).BCProperty();
+         return true;
+      }
+      return false;
+   }
 
    // Return the surface element at a given index "pi"
    DLL_HEADER Ng_Surface_Element_Type 
-      Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi, int * domain)
+      Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi, int * facenr)
    {
       const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num);
       for (int i = 1; i <= el.GetNP(); i++)
@@ -365,8 +420,8 @@ namespace nglib
       default:
          et = NG_TRIG; break; // for the compiler
       }
-      if (domain)
-        *domain = el.GetIndex();
+      if (facenr)
+        *facenr = el.GetIndex();
       return et;
    }
 
diff --git a/nglib/nglib.h b/nglib/nglib.h
index 28155ad7d..63f457ff6 100644
--- a/nglib/nglib.h
+++ b/nglib/nglib.h
@@ -370,6 +370,22 @@ DLL_HEADER void Ng_AddPoint (Ng_Mesh * mesh, double * x);
 */
 DLL_HEADER void Ng_AddLockedPoint(Ng_Mesh * mesh, int pi);
 
+
+/*! \brief Remove any existing face descriptors
+*/
+DLL_HEADER int Ng_AddFaceDescriptor (Ng_Mesh * ng_mesh, int surfnr, int domin, int domout, int bcp);
+
+
+/*! \brief Remove any existing face descriptors
+*/
+DLL_HEADER void Ng_ClearFaceDescriptors (Ng_Mesh * ng_mesh);
+
+
+/*! \brief Generate simple facedescriptors, with facenr==bc, from 1...maxbc
+*/
+DLL_HEADER void Ng_SetupFacedescriptors(Ng_Mesh * mesh, int maxbc);
+
+
 /*! \brief Add a surface element to a given Netgen Mesh Structure
 
     This function allows the top-level code to directly add individual 
@@ -389,8 +405,9 @@ DLL_HEADER void Ng_AddLockedPoint(Ng_Mesh * mesh, int pi);
                 #Ng_Surface_Element_Type 
     \param pi   Pointer to an array of integers containing the indices of the 
                 points which constitute the surface element being added
+    \param facenr Index of face descriptor. Used e.g. to attach boundary condition types to surface elements
 */
-DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et, int * pi, int domain=1);
+DLL_HEADER void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et, int * pi, int facenr=1);
 
 
 /*! \brief Add a volume element to a given Netgen Mesh Structure
@@ -597,10 +614,12 @@ DLL_HEADER int Ng_GetNE (Ng_Mesh * mesh);
 DLL_HEADER void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x);
 
 
+// return bcp and surfnr for specified face descriptor (facenr)
+DLL_HEADER bool Ng_GetFaceDescriptor (Ng_Mesh * mesh, int facenr, int &surfnr, int &domin, int &domout, int &bcp);
 
 // return surface and volume element in pi
 DLL_HEADER Ng_Surface_Element_Type 
-Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi, int * domain = nullptr);
+Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi, int * facenr = nullptr);
 
 DLL_HEADER Ng_Volume_Element_Type
 Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi, int * domain = nullptr);
@@ -655,8 +674,6 @@ DLL_HEADER Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom,
                                          Ng_Meshing_Parameters * mp);
  
 // functions added to make Optimize2d mesh accessible from nglib
-DLL_HEADER void Ng_SetupFacedescriptors(Ng_Mesh * mesh, int maxdomnr);
-
 DLL_HEADER void Ng_AddTriangle_2D(Ng_Mesh * mesh, int pi1, int pi2, int pi3, int matnum = 1);
 
 DLL_HEADER Ng_Result Ng_OptimizeMesh_2D(Ng_Mesh *mesh, Ng_Meshing_Parameters * mp);

From 8f1799b4be8d960cbef04f24f123643bbb8aded0 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Mon, 4 Mar 2019 14:52:58 +0100
Subject: [PATCH 10/19] get rid of warning about macro redefinition

---
 nglib/nglib.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index b0af1059c..332ce73bb 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -62,6 +62,11 @@ namespace netgen {
 */
 
 
+// Bryn Lloyd - get rid of warning about macro redefinition (previously defined in mydefs.hpp)
+#if defined(DLL_HEADER)
+   #undef DLL_HEADER
+#endif
+
 namespace nglib {
 #include "nglib.h"
 }

From f242926f724558d45070ca54cf67b2f0a6992cb8 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.ethz.ch>
Date: Tue, 5 Mar 2019 13:04:54 +0100
Subject: [PATCH 11/19] implement missing functions for 2d mesh optimization

---
 nglib/nglib.cpp | 13 +++++++++++++
 nglib/nglib.h   |  2 --
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index 332ce73bb..4e189c869 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -29,6 +29,7 @@ namespace netgen {
    extern void MeshFromSpline2D (SplineGeometry2d & geometry,
                                  shared_ptr<Mesh> & mesh, 
                                  MeshingParameters & mp);
+   extern void Optimize2d(Mesh & mesh, MeshingParameters & mp);
 }
 
 
@@ -734,6 +735,18 @@ namespace nglib
    }
 
 
+   DLL_HEADER Ng_Result Ng_OptimizeMesh_2D(Ng_Mesh *mesh, Ng_Meshing_Parameters * mp)
+   {
+       Mesh * m = (Mesh*)mesh;
+
+       mp->Transfer_Parameters();
+
+       m->CalcLocalH(mparam.grading);
+
+       Optimize2d(*m, mparam);
+
+       return NG_OK;
+   }
 
 
    DLL_HEADER void Ng_HP_Refinement (Ng_Geometry_2D * geom,
diff --git a/nglib/nglib.h b/nglib/nglib.h
index 63f457ff6..eb8c312d4 100644
--- a/nglib/nglib.h
+++ b/nglib/nglib.h
@@ -674,8 +674,6 @@ DLL_HEADER Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom,
                                          Ng_Meshing_Parameters * mp);
  
 // functions added to make Optimize2d mesh accessible from nglib
-DLL_HEADER void Ng_AddTriangle_2D(Ng_Mesh * mesh, int pi1, int pi2, int pi3, int matnum = 1);
-
 DLL_HEADER Ng_Result Ng_OptimizeMesh_2D(Ng_Mesh *mesh, Ng_Meshing_Parameters * mp);
 
 

From ba5b3a07dd41a933b3566eebd322ec6b0fd727a6 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.ethz.ch>
Date: Wed, 29 May 2019 16:35:39 +0200
Subject: [PATCH 12/19] expose Ng_SetTerminate for nglib

---
 nglib/nglib.cpp | 14 +++++++++++++-
 nglib/nglib.h   | 10 ++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index 4e189c869..b692ce46e 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -44,7 +44,6 @@ namespace netgen
 }
 #endif
 
-
 /*
 namespace netgen
 {
@@ -101,6 +100,19 @@ namespace nglib
    }
 
 
+   DLL_HEADER void Ng_GetStatus(char ** str, double & percent)
+   {
+	   ::netgen::MyStr s;
+	   ::netgen::GetStatus(s, percent);
+	   *str = new char[s.Length() + 1];
+	   strcpy(*str, s.c_str());
+   }
+
+
+   DLL_HEADER void Ng_SetTerminate(bool abort)
+   {
+	   ::netgen::multithread.terminate = abort ? 1 : 0;
+   }
 
 
    // Clean-up functions before ending usage of nglib
diff --git a/nglib/nglib.h b/nglib/nglib.h
index eb8c312d4..913b66a53 100644
--- a/nglib/nglib.h
+++ b/nglib/nglib.h
@@ -250,6 +250,16 @@ DLL_HEADER void Ng_Init (bool cout_to_null = false, bool cerr_to_null = false, b
 DLL_HEADER void Ng_Exit ();
   
 
+/*! \brief Get current status, e.g. info string and percent
+*/
+DLL_HEADER void Ng_GetStatus(char ** str, double & percent);
+
+
+/*! \brief Set abort flag
+*/
+DLL_HEADER void Ng_SetTerminate(bool abort);
+
+
 /*! \brief Create a new (and empty) Netgen Mesh Structure
 
     This function creates a new Netgen Mesh, initialises 

From 1d979cc16f5b22fc08de5f75c9ed9a9e195573e7 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Wed, 31 May 2023 11:42:40 +0200
Subject: [PATCH 13/19] fix version parsing (?)

---
 libsrc/core/version.cpp | 2 +-
 libsrc/core/version.hpp | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/libsrc/core/version.cpp b/libsrc/core/version.cpp
index 546abbf72..4247cfb13 100644
--- a/libsrc/core/version.cpp
+++ b/libsrc/core/version.cpp
@@ -23,7 +23,7 @@ namespace ngcore
   }
 
   static bool dummy = [](){
-    SetLibraryVersion("netgen", NETGEN_VERSION);
+    SetLibraryVersion("netgen", VersionInfo(NETGEN_VERSION));
     return true;
   }();
 } // namespace ngcore
diff --git a/libsrc/core/version.hpp b/libsrc/core/version.hpp
index 3048ce5b9..0e5a1777b 100644
--- a/libsrc/core/version.hpp
+++ b/libsrc/core/version.hpp
@@ -24,25 +24,25 @@ namespace ngcore
         vstring = vstring.substr(1,vstring.size()-1);
       auto dot = vstring.find('.');
       mayor_ = std::stoi(vstring.substr(0,dot));
-      if(dot == size_t(-1)) vstring = "";
+      if(dot == std::string::npos) vstring = "";
       else vstring = vstring.substr(dot+1, vstring.size()-dot-1);
       if(!vstring.empty())
         {
           dot = vstring.find('.');
           minor_ = std::stoi(vstring.substr(0,dot));
-          if (dot == size_t(-1)) vstring = "";
+          if (dot == std::string::npos) vstring = "";
           else vstring = vstring.substr(dot+1, vstring.size()-dot-1);
           if(!vstring.empty())
             {
               dot = vstring.find('-');
               release = std::stoi(vstring.substr(0,dot));
-              if(dot == size_t(-1)) vstring = "";
+              if(dot == std::string::npos) vstring = "";
               else vstring = vstring.substr(dot+1,vstring.size()-dot-1);
               if(!vstring.empty())
                 {
                   dot = vstring.find('-');
                   patch = std::stoi(vstring.substr(0,dot));
-                  if(dot == size_t(-1)) vstring = "";
+                  if(dot == std::string::npos) vstring = "";
                   else vstring = vstring.substr(dot+1, vstring.size()-dot-1);
                   if(!vstring.empty())
                     git_hash = vstring;

From 9e28b04e334bfd98f955228570cebd7a3a0a343f Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Wed, 31 May 2023 12:09:41 +0200
Subject: [PATCH 14/19] add try-catch

---
 libsrc/core/version.hpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libsrc/core/version.hpp b/libsrc/core/version.hpp
index 0e5a1777b..92cbb6b80 100644
--- a/libsrc/core/version.hpp
+++ b/libsrc/core/version.hpp
@@ -18,6 +18,7 @@ namespace ngcore
     VersionInfo() = default;
     VersionInfo(std::string vstring)
     {
+      try {
       minor_ = release = patch = 0;
       git_hash = "";
       if(vstring.substr(0,1) == "v")
@@ -49,6 +50,9 @@ namespace ngcore
                 }
             }
         }
+      }
+      catch (std::invalid_argument&)
+      {}
     }
     VersionInfo(const char* cstr) : VersionInfo(std::string(cstr)) { }
 

From 9d8da1560435d87c65ed775663e235ca901cfb99 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Wed, 31 May 2023 13:54:05 +0200
Subject: [PATCH 15/19] const ...

---
 libsrc/core/version.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libsrc/core/version.hpp b/libsrc/core/version.hpp
index 92cbb6b80..cb44d50ca 100644
--- a/libsrc/core/version.hpp
+++ b/libsrc/core/version.hpp
@@ -51,7 +51,7 @@ namespace ngcore
             }
         }
       }
-      catch (std::invalid_argument&)
+      catch (const std::invalid_argument&)
       {}
     }
     VersionInfo(const char* cstr) : VersionInfo(std::string(cstr)) { }

From 7a766a23eb6239c9a2e3518e6efe3e22ecb51f59 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Thu, 1 Jun 2023 14:01:57 +0200
Subject: [PATCH 16/19] disable CleanupDemangledName

---
 libsrc/core/utils.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libsrc/core/utils.cpp b/libsrc/core/utils.cpp
index 062114e68..7eda05f56 100644
--- a/libsrc/core/utils.cpp
+++ b/libsrc/core/utils.cpp
@@ -17,6 +17,7 @@ namespace ngcore
 {
     namespace detail
     {
+      /*
         // see https://github.com/RobotLocomotion/drake/blob/master/common/nice_type_name.cc
         static const auto demangle_regexes =
             std::array<std::pair<std::regex, std::string>, 8>{
@@ -39,10 +40,11 @@ namespace ngcore
                 {std::regex("\\bstd::basic_string<char,std::char_traits<char>,"
                         "std::allocator<char>>"), "std::string"}
             };
+        */
         std::string CleanupDemangledName( std::string s )
         {
-            for(const auto & [r, sub] : demangle_regexes)
-                s = std::regex_replace (s,r,sub);
+            //for(const auto & [r, sub] : demangle_regexes)
+            //    s = std::regex_replace (s,r,sub);
 
             return s;
         }

From 0df91284bf6957d9b590227a4279e1498370e3b4 Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <lloyd@itis.swiss>
Date: Fri, 23 May 2025 08:48:47 +0200
Subject: [PATCH 17/19] small fixes to build with VS 2022

---
 .gitignore               | 1 +
 CMakeLists.txt           | 8 ++++----
 libsrc/core/bitarray.hpp | 2 +-
 libsrc/core/utils.cpp    | 4 ++--
 nglib/mynglib.cpp        | 8 ++------
 nglib/nglib.cpp          | 2 +-
 6 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6eb7a9e45..c2d9b5223 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ __pycache__
 *.zip
 .cache
 *.patch
+.vscode/
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9c54e30e3..5a4ab6de5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,12 +25,12 @@ option( USE_GEOM2D     "build 2d geometry kernels" ON)
 option( USE_JPEG    "enable snapshots using library libjpeg" OFF )
 option( USE_MPEG    "enable video recording with FFmpeg, uses libavcodec" OFF )
 option( USE_CGNS    "enable CGNS file read/write support" OFF )
-option( USE_NUMA         "compile with NUMA-aware code")
-option( INTEL_MIC        "cross compile for intel xeon phi")
+option( USE_NUMA         "compile with NUMA-aware code" OFF)
+option( INTEL_MIC        "cross compile for intel xeon phi" OFF)
 option( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF )
-option( USE_CCACHE       "use ccache")
+option( USE_CCACHE       "use ccache" OFF)
 option( USE_INTERNAL_TCL "Compile tcl files into the code and don't install them" ON)
-option( ENABLE_UNIT_TESTS "Enable Catch unit tests")
+option( ENABLE_UNIT_TESTS "Enable Catch unit tests" OFF)
 option( ENABLE_CPP_CORE_GUIDELINES_CHECK "Enable cpp core guideline checks on ngcore" OFF)
 option( DEBUG_LOG "Enable more debug output (may increase computation time) - only works with USE_SPDLOG=ON" OFF)
 option( CHECK_RANGE "Check array range access, automatically enabled if built in debug mode" OFF)
diff --git a/libsrc/core/bitarray.hpp b/libsrc/core/bitarray.hpp
index caa8345cc..73029a9dc 100644
--- a/libsrc/core/bitarray.hpp
+++ b/libsrc/core/bitarray.hpp
@@ -226,7 +226,7 @@ class BitArray
     
     bool operator[] (IndexType i) const { return Test(i); } 
     T_Range<IndexType> Range() const { return { IndexBASE<IndexType>(), IndexBASE<IndexType>()+Size() }; }
-    NGCORE_API TBitArray & Or (const TBitArray & ba2)
+    inline TBitArray & Or (const TBitArray & ba2)
     {
       BitArray::Or(ba2);
       return *this;
diff --git a/libsrc/core/utils.cpp b/libsrc/core/utils.cpp
index 8a792ea98..aed4fd4e7 100644
--- a/libsrc/core/utils.cpp
+++ b/libsrc/core/utils.cpp
@@ -52,8 +52,8 @@ namespace ngcore
         */
         std::string CleanupDemangledName( std::string s )
         {
-            for(const auto & [r, sub] : demangle_regexes)
-                s = std::regex_replace (s,r,sub);
+            // for(const auto & [r, sub] : demangle_regexes)
+            //     s = std::regex_replace (s,r,sub);
 #ifdef EMSCRIPTEN
             // for some reason regex_replace is not working at all
             std::string temp = s;
diff --git a/nglib/mynglib.cpp b/nglib/mynglib.cpp
index 1bac1329a..9b722378f 100644
--- a/nglib/mynglib.cpp
+++ b/nglib/mynglib.cpp
@@ -17,7 +17,6 @@
 #include <stlgeom.hpp>
 #include <geometry2d.hpp>
 #include <meshing.hpp>
-#include <../visualization/soldata.hpp>
 
 #ifdef OCCGEOMETRY
 #include <occgeom.hpp>
@@ -31,9 +30,7 @@ namespace netgen {
                                  shared_ptr<Mesh> & mesh, 
                                  MeshingParameters & mp);
 
-   extern void Optimize2d (Mesh & mesh, 
-	   MeshingParameters & mp);
-
+   extern void Optimize2d(Mesh & mesh, MeshingParameters & mp, int faceindex=0);
    // Global meshing parameters !!
    //MeshingParameters mparam;
 }
@@ -615,8 +612,7 @@ namespace nglib
    }
 
 
-   DLL_HEADER Ng_Result Ng_OptimizeMesh_2D (Ng_Mesh *mesh, 
-	   Ng_Meshing_Parameters * mp)
+   DLL_HEADER Ng_Result Ng_OptimizeMesh_2D (Ng_Mesh *mesh, Ng_Meshing_Parameters * mp)
    {
 	   Mesh * m = (Mesh*)mesh;
 
diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp
index e5bf70572..3d1e78521 100644
--- a/nglib/nglib.cpp
+++ b/nglib/nglib.cpp
@@ -25,7 +25,7 @@ namespace netgen {
    extern void MeshFromSpline2D (SplineGeometry2d & geometry,
                                  shared_ptr<Mesh> & mesh, 
                                  MeshingParameters & mp);
-   extern void Optimize2d(Mesh & mesh, MeshingParameters & mp);
+   extern void Optimize2d(Mesh & mesh, MeshingParameters & mp, int faceindex=0);
    extern MeshingParameters mparam;
    DLL_HEADER extern STLParameters stlparam;
 }

From e3c3de012a22da6790820cfcf8ab77b3c17ff4ea Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <12702862+dyollb@users.noreply.github.com>
Date: Fri, 23 May 2025 08:56:01 +0200
Subject: [PATCH 18/19] add config used to build 2025.05.23

---
 vscode_ref/settings.json | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 vscode_ref/settings.json

diff --git a/vscode_ref/settings.json b/vscode_ref/settings.json
new file mode 100644
index 000000000..089fd7919
--- /dev/null
+++ b/vscode_ref/settings.json
@@ -0,0 +1,30 @@
+{
+    "cmake.generator": "Ninja",
+    "cmake.sourceDirectory": "${workspaceFolder}",
+    "cmake.buildDirectory": "${workspaceFolder}/build",
+    "cmake.configureOnOpen": false,
+    "cmake.configureOnEdit": false,
+    "cmake.useCMakePresets": "never",
+    "cmake.configureSettings": {
+        //
+        "CMAKE_C_COMPILER": "cl",
+        "CMAKE_CXX_COMPILER": "cl",
+        //
+        "USE_SUPERBUILD": false,
+        "USE_GUI": false,
+        "USE_PYTHON": false,
+        "USE_TESTING": false,
+        "USE_OCC": false,
+        "CMAKE_INSTALL_PREFIX": "${workspaceFolder}/../netgen_svn",
+        "ZLIB_INCLUDE_DIRS": "D:/lloyd/dev/z43libs/svn-esx.speag.com_SuperMash_libraries_zlib_zlib-1_2_11_msvc140-win10/include",
+        "ZLIB_LIBRARIES": "D:/lloyd/dev/z43libs/svn-esx.speag.com_SuperMash_libraries_zlib_zlib-1_2_11_msvc140-win10/lib/x64/zlibwapi.lib",
+    },
+    "files.associations": {
+        "*.py": "python",
+        "memory": "cpp",
+        "algorithm": "cpp",
+        "xiosbase": "cpp",
+        "xlocale": "cpp",
+        "xutility": "cpp"
+    }
+}
\ No newline at end of file

From 91f8d76612ba0d1282a45c51239b2558147b17dc Mon Sep 17 00:00:00 2001
From: Bryn Lloyd <12702862+dyollb@users.noreply.github.com>
Date: Fri, 23 May 2025 09:03:10 +0200
Subject: [PATCH 19/19] gitignore change

---
 .gitignore | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index c2d9b5223..ad37922f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,6 @@ build
 *.vol
 *.ini
 __pycache__
-*.json
 *.zip
 .cache
 *.patch