diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8b5cd59757de2780c15566396d31176fe6da3d56
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,65 @@
+# cmake ../ -DCMAKE_BUILD_TYPE=Debug
+
+cmake_minimum_required(VERSION 3.1)
+project(Linear_cell_complex_Demo)
+
+if(NOT POLICY CMP0070 AND POLICY CMP0053)
+  # Only set CMP0053 to OLD with CMake<3.10, otherwise there is a warning.
+  cmake_policy(SET CMP0053 OLD)
+endif()
+if(POLICY CMP0071)
+  cmake_policy(SET CMP0071 NEW)
+endif()
+
+# Find includes in corresponding build directories
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+# Instruct CMake to run moc automatically when needed.
+set(CMAKE_AUTOMOC ON)
+################################################################################
+add_definitions("-Wall -Wextra")
+set(CMAKE_CXX_STANDARD 17)
+
+add_definitions("-g") # for profilling with vtune
+add_link_options("-g")
+
+## For profilling with gprof
+# add_definitions("-pg")
+# add_link_options("-pg")
+################################################################################
+find_package(CGAL REQUIRED COMPONENTS Qt5)
+find_package(Qt5 REQUIRED COMPONENTS Script OpenGL Svg)
+
+add_definitions(-DCGAL_USE_BASIC_VIEWER -DQT_NO_KEYWORDS)
+
+## To add expensive tests
+# add_definitions("-DCGAL_CHECK_EXPENSIVE")
+################################################################################
+find_package(ASSIMP)
+if (ASSIMP_FOUND)
+  ADD_DEFINITIONS(-DWITH_ASSIMP)
+endif (ASSIMP_FOUND)
+################################################################################
+include_directories(tools)
+include_directories(BEFORE SYSTEM ${CMAKE_SOURCE_DIR})
+
+set(src_tools
+
+  cmap_copy.h
+  cmap_isomorphisms.h
+  cmap_signature.h
+  )
+add_library(lcc_tools_lib SHARED ${src_tools})
+target_link_libraries(lcc_tools_lib PUBLIC
+  CGAL::CGAL
+  CGAL::CGAL_Qt5
+  tet)
+if (ASSIMP_FOUND)
+  target_link_libraries(lcc_tools_lib PUBLIC assimp)
+endif (ASSIMP_FOUND)
+################################################################################
+add_executable(hexa-subdivision hexa-subdivision.cpp ${src_tools})
+target_link_libraries(hexa-subdivision PUBLIC lcc_tools_lib)
+################################################################################
+add_executable(tetra-to-hexa tetra-to-hexa.cpp ${src_tools})
+target_link_libraries(tetra-to-hexa PUBLIC lcc_tools_lib)
+################################################################################
diff --git a/src/Compute_stats.h b/src/Compute_stats.h
new file mode 100644
index 0000000000000000000000000000000000000000..27ee8151dbe7017d9b167550f1ba89cc7ca2a88c
--- /dev/null
+++ b/src/Compute_stats.h
@@ -0,0 +1,190 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+
+#ifndef COMPUTE_STATS_H
+#define COMPUTE_STATS_H
+
+#include "Element_topo.h"
+#include "lcc_convexity_test.h"
+#include "One_info.h"
+#include "Orientation.h"
+#include "Volume_computation.h"
+#include <iostream>
+
+///////////////////////////////////////////////////////////////////////////////
+template<typename LCC>
+void display_stats(LCC& lcc, bool with_geom_tests=false)
+{
+  lcc.display_characteristics(std::cout);
+  std::cout<<", valid="<<lcc.is_valid()<<std::endl;
+
+  typename LCC::FT vol=0, sum_vol=0;
+  One_info<double> vol_tetra, vol_hexa, vol_prism, vol_pyramid, vol_generic;
+  std::size_t nb_0free=0, nb_1free=0, nb_2free=0, nb_3free=0, nb_face_3_free=0;
+  std::size_t nbvol=0, nbvolconvex=0;
+  cell_topo t;
+  typename LCC::Dart_handle sd;
+
+  auto treated=lcc.get_new_mark();
+  auto face_treated=lcc.get_new_mark();
+  // std::cout<<"Volumes of each 3-cell:"<<std::endl;
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+  {
+    if (lcc.template is_free<0>(it)) { ++nb_0free; }
+    if (lcc.template is_free<1>(it)) { ++nb_1free; }
+    if (lcc.template is_free<2>(it)) { ++nb_2free; }
+    if (lcc.template is_free<3>(it))
+    {
+      ++nb_3free;
+      if (!lcc.is_marked(it, face_treated))
+      {
+        ++nb_face_3_free;
+        lcc.template mark_cell<2>(it, face_treated);
+      }
+    }
+    else
+    {
+      if (!lcc.is_marked(it, face_treated))
+      { lcc.template mark_cell<2>(it, face_treated); }
+    }
+
+    if(!lcc.is_marked(it, treated))
+    {
+      lcc.template mark_cell<3>(it, treated);
+      t=Get_cell_topo<LCC,3>::run(lcc, it, sd);
+      if(with_geom_tests)
+      { vol=signed_volume(lcc, it); }
+      switch(t)
+      {
+        case PRISM:
+          //std::cout<<"  PRISM: "<<vol<<std::endl;
+          vol_prism.update(vol);
+          break;
+        case PYRAMID:
+          //std::cout<<"  PYRAMID: "<<vol<<std::endl;
+          vol_pyramid.update(vol);
+          break;
+        case TETRAHEDRON:
+          //std::cout<<"  TETRAHEDRON: "<<vol<<std::endl;
+          vol_tetra.update(vol);
+          break;
+        case HEXAHEDRON:
+          //std::cout<<"  HEXAHEDRON: "<<vol<<std::endl;
+          vol_hexa.update(vol);
+          break;
+        case GENERIC_3D:
+          //std::cout<<"  GENERIC_3D: "<<vol<<std::endl;
+          vol_generic.update(vol);
+          break;
+        default:
+          //std::cout<<"  ERROR: unknown type: "<<t<<std::endl;
+          break;
+      }
+      if(with_geom_tests)
+      {
+        if (is_volume_convex(lcc, it)) { ++nbvolconvex; }
+        /*std::cout<<"TO DEBUG [display_stats]: vol="<<vol
+              <<" generic_vol="<<signed_volume_of_generic_cell(lcc, it)<<std::endl;*/
+        sum_vol+=vol;
+      }
+      ++nbvol;
+    }
+  }
+
+  std::cout<<"#prisms="<<vol_prism.number_of_elements()
+          <<" #pyramids="<<vol_pyramid.number_of_elements()
+         <<" #tetrahedra="<<vol_tetra.number_of_elements()
+        <<" #hexahedra="<<vol_hexa.number_of_elements()
+       <<" #generic="<<vol_generic.number_of_elements()
+      <<" (TOTAL="<<nbvol;
+  if(with_geom_tests) { std::cout<<", convex="<<nbvolconvex<<")"<<std::endl; }
+  else { std::cout<<")"<<std::endl; }
+
+  std::cout<<"#darts free=("<<nb_0free<<", "<<nb_1free<<", "<<nb_2free
+          <<", "<<nb_3free<<") #faces 3-free="<<nb_face_3_free<<std::endl;
+  if(with_geom_tests)
+  {
+    std::cout<<"Volume of all the 3-cells: "<<sum_vol<<std::endl;
+    std::cout<<"    hexa:"<<vol_hexa<<std::endl;
+    std::cout<<"    tetra:"<<vol_tetra<<std::endl;
+    std::cout<<"    prism:"<<vol_prism<<std::endl;
+    std::cout<<"    pyramid:"<<vol_pyramid<<std::endl;
+    std::cout<<"    generic:"<<vol_generic<<std::endl;
+  }
+
+  lcc.free_mark(face_treated);
+  lcc.free_mark(treated);
+
+  check_orientation(lcc, true);
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename LCC>
+void display_volume(LCC& lcc, typename LCC::Dart_handle dh)
+{
+  typename LCC::Dart_handle sd;
+  cell_topo t=Get_cell_topo<LCC,3>::run(lcc, dh, sd);
+  switch(t)
+  {
+    case PRISM:
+      std::cout<<"PRISM:";
+      break;
+    case PYRAMID:
+      std::cout<<"PYRAMID:";
+      break;
+    case TETRAHEDRON:
+      std::cout<<"TETRAHEDRON:";
+      break;
+    case HEXAHEDRON:
+      std::cout<<"HEXAHEDRON:";
+      break;
+    case GENERIC_3D:
+      std::cout<<"GENERIC_3D:";
+      break;
+    default:
+      std::cout<<"  ERROR: unknown type: "<<t<<std::endl;
+      break;
+  }
+  std::vector<typename LCC::Point> points;
+  for(auto it=lcc.template one_dart_per_incident_cell<0,3>(sd).begin(),
+      itend=lcc.template one_dart_per_incident_cell<0,3>(sd).end(); it!=itend; ++it)
+  { points.push_back(lcc.point(it)); }
+  std::sort(points.begin(), points.end());
+  bool first=true;
+  for(auto& pt: points)
+  {
+    if(!first) { std::cout<<"; "; }
+    else { std::cout<<"("; first=false; }
+    std::cout<<pt;
+  }
+  std::cout<<")"<<std::endl;
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename LCC>
+void display_all_volumes(LCC& lcc)
+{
+  std::cout<<"*********************************************"<<std::endl;
+  for(auto it=lcc.template one_dart_per_cell<3>().begin(),
+      itend=lcc.template one_dart_per_cell<3>().end(); it!=itend; ++it)
+  { display_volume(lcc, it); }
+  std::cout<<"*********************************************"<<std::endl;
+}
+///////////////////////////////////////////////////////////////////////////////
+#endif // COMPUTE_STATS_H
diff --git a/src/Element_topo.h b/src/Element_topo.h
new file mode 100644
index 0000000000000000000000000000000000000000..5579a6642ce02db6092547db3a36a912d253bc6d
--- /dev/null
+++ b/src/Element_topo.h
@@ -0,0 +1,137 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>, 
+//                 Florence Zara <florence.zara@liris.cnrs.fr>
+//
+
+#ifndef ELEMENT_TOPO_H
+#define ELEMENT_TOPO_H
+
+#include "Prism_and_pyramid_creation.h"
+
+enum cell_topo 
+  {
+    SQUARE = 0,
+    TRIANGLE = 1,
+    HEXAHEDRON = 2,
+    TETRAHEDRON = 3,
+    PRISM = 4,
+    PYRAMID = 5,
+    GENERIC_2D = 6,
+    GENERIC_3D = 7,
+    EDGE = 8,
+    NO_TYPE = -1
+  };
+
+/**
+ * @brief To get the type of dimD cell of the LCC of dimlcc dimension.
+ */
+template<typename LCC, unsigned int dim, unsigned int dimlcc=LCC::dimension>
+struct Get_cell_topo
+{
+  static cell_topo run(LCC&, typename LCC::Dart_handle dh,
+                       typename LCC::Dart_handle& starting_dart)
+  {
+    starting_dart=dh;
+    return NO_TYPE;
+  }
+};
+
+/**
+ * @brief To get the type associated of an edge. For now only one type.
+ */
+template<typename LCC, unsigned int dimlcc>
+struct Get_cell_topo<LCC, 1, dimlcc>
+{
+  static cell_topo run(LCC&, typename LCC::Dart_handle it,
+                       typename LCC::Dart_handle& starting_dart)
+  {
+    starting_dart=it;
+    return EDGE;
+  }
+};
+
+/**
+ * @brief To get the type of 2D cell of the LCC of dimlcc dimension.
+ */
+template<typename LCC, unsigned int dimlcc>
+struct Get_cell_topo<LCC, 2, dimlcc>
+{
+  static cell_topo run(LCC& lcc, typename LCC::Dart_handle it,
+                       typename LCC::Dart_handle& starting_dart)
+  {
+    starting_dart=it;
+
+    if (lcc.is_face_combinatorial_polygon(it, 3))
+      return TRIANGLE;
+
+    else if (lcc.is_face_combinatorial_polygon(it, 4))
+      return SQUARE;
+
+    return GENERIC_2D;
+  }
+};
+
+/**
+ * @brief To get the type of 3D cell of the LCC of dimension 3.
+ */
+template<typename LCC>
+struct Get_cell_topo<LCC, 3, 3>
+{
+  static cell_topo run(LCC& lcc, typename LCC::Dart_handle it,
+                       typename LCC::Dart_handle& starting_dart)
+  {
+    starting_dart=it;
+
+    if (lcc.is_volume_combinatorial_tetrahedron(it))
+      return TETRAHEDRON;
+
+    else if (lcc.is_volume_combinatorial_hexahedron(it))
+      return HEXAHEDRON;
+
+    // For non symetric object, we need to test all darts
+    for (auto itv=lcc.template darts_of_cell<3>(it).begin(),
+         itvend=lcc.template darts_of_cell<3>(it).end(); itv!=itvend; ++itv)
+    {
+      starting_dart=itv;
+
+      if (is_volume_combinatorial_prism(lcc, itv))
+        return PRISM;
+
+      else if (is_volume_combinatorial_pyramid(lcc, itv))
+        return PYRAMID;
+    }
+
+    return GENERIC_3D;
+  }
+};
+
+template<typename LCC>
+cell_topo get_cell_topo(LCC& lcc, typename LCC::Dart_handle it,
+                        typename LCC::Dart_handle& starting_dart)
+{ return Get_cell_topo<LCC, LCC::dimension>::run(lcc, it, starting_dart); }
+
+template<typename LCC>
+cell_topo get_cell_topo(LCC& lcc, typename LCC::Dart_handle it)
+{
+  typename LCC::Dart_handle dummy;
+  return get_cell_topo(lcc, it, dummy);
+}
+
+#endif // ELEMENT_TOPO_H
diff --git a/src/MeshComplex_3InTriangulation_3_to_lcc.h b/src/MeshComplex_3InTriangulation_3_to_lcc.h
new file mode 100644
index 0000000000000000000000000000000000000000..b14569d33f001db55e41acdded27eb1580e0b3b5
--- /dev/null
+++ b/src/MeshComplex_3InTriangulation_3_to_lcc.h
@@ -0,0 +1,163 @@
+// Copyright (c) 2011 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef MESH_COMPLEX_3_IN_TRIANGULATION_3_TO_LCC_H
+#define MESH_COMPLEX_3_IN_TRIANGULATION_3_TO_LCC_H
+
+#include <CGAL/assertions.h>
+#include <unordered_map>
+#include <CGAL/Weighted_point_3.h>
+
+namespace internal 
+{
+template<typename Point>
+struct Get_point
+{
+    static const Point& run(const Point& p)
+    { return p; }
+};
+
+template<typename Kernel>
+struct Get_point<CGAL::Weighted_point_3<Kernel> >
+{
+    static const typename Kernel::Point_3& run(const CGAL::Weighted_point_3<Kernel>& p)
+    { return p.point(); }
+};
+}
+
+/** Convert a given Triangulation_3 into a 3D linear cell complex.
+ * @param alcc the used linear cell complex.
+ * @param atr the Triangulation_3.
+ * @param avol_to_dart a pointer to a std::map associating to each
+ *        tetrahedron of atr a corresponding dart in alcc. Not used if nullptr.
+ * @return A dart incident to the infinite vertex.
+ */
+template < class LCC, class Triangulation >
+typename LCC::Dart_handle import_from_complex_3_in_triangulation_3
+(LCC& alcc, const Triangulation &atr,
+std::unordered_map<typename Triangulation::Cell_handle,
+ typename LCC::Dart_handle >* avol_to_dart=nullptr)
+{
+  CGAL_static_assertion( LCC::dimension>=3 && LCC::ambient_dimension==3 );
+
+  // Case of empty triangulations.
+  if (atr.triangulation().number_of_vertices()==0) return LCC::null_handle;
+
+  // Check the dimension.
+  if (atr.triangulation().dimension()!=3) return LCC::null_handle;
+  CGAL_assertion(atr.is_valid());
+
+  typedef typename Triangulation::Vertex_handle TVertex_handle;
+  typedef typename Triangulation::Cell_iterator TCell_iterator;
+
+  // Create vertices in the map and associate in a map
+  // TVertex_handle and vertices in the map.
+  std::unordered_map< TVertex_handle, typename LCC::Vertex_attribute_handle > TV;
+  for (auto itv=atr.triangulation().vertices_begin();
+       itv!=atr.triangulation().vertices_end(); ++itv)
+  {
+    TV[itv]=alcc.create_vertex_attribute
+            (internal::Get_point<typename Triangulation::Point>::run(itv->point()));
+  }
+
+  // Create the tetrahedron and create a map to link Cell_iterator
+  // and tetrahedron.
+  TCell_iterator it;
+  std::unordered_map<typename Triangulation::Cell_handle, typename LCC::Dart_handle> TC;
+  std::unordered_map<typename Triangulation::Cell_handle, typename LCC::Dart_handle>*
+      mytc = (avol_to_dart==nullptr?&TC:avol_to_dart);
+
+  typename LCC::Dart_handle res=LCC::null_handle, dart=LCC::null_handle;
+  typename LCC::Dart_handle cur=LCC::null_handle, neighbor=LCC::null_handle;
+
+  for (it=atr.cells_in_complex_begin(); it!=atr.cells_in_complex_end(); ++it)
+  {
+    if (it->vertex(0)!=atr.triangulation().infinite_vertex() &&
+        it->vertex(1)!=atr.triangulation().infinite_vertex() &&
+        it->vertex(2)!=atr.triangulation().infinite_vertex() &&
+        it->vertex(3)!=atr.triangulation().infinite_vertex())
+    {
+      assert(TV.count(it->vertex(0))==1);
+      assert(TV.count(it->vertex(1))==1);
+      assert(TV.count(it->vertex(2))==1);
+      assert(TV.count(it->vertex(3))==1);
+
+      res=alcc.make_tetrahedron(TV[it->vertex(0)],
+          TV[it->vertex(1)],
+          TV[it->vertex(2)],
+          TV[it->vertex(3)]);
+
+      if ( dart==LCC::null_handle )
+      { dart=res; }
+
+      for (unsigned int i=0; i<4; ++i)
+      {
+        assert(&*(it->neighbor(i)->neighbor(atr.triangulation().mirror_index(it, i)))==&*it);
+        assert(&*(it->neighbor(i))!=&*it);
+
+        switch (i)
+        {
+          case 0: cur=alcc.template opposite<2>(alcc.next(res)); break;
+          case 1: cur=alcc.template opposite<2>(alcc.previous(res)); break;
+          case 2: cur=alcc.template opposite<2>(res); break;
+          case 3: cur=res; break;
+        }
+
+        auto maptcell_it=mytc->find(it->neighbor(i));
+        if (maptcell_it!=mytc->end())
+        {
+          switch (atr.triangulation().mirror_index(it,i) )
+          {
+            case 0: neighbor=alcc.template opposite<2>(alcc.next(maptcell_it->second));
+              break;
+            case 1: neighbor=alcc.template opposite<2>(alcc.previous(maptcell_it->second));
+              break;
+            case 2: neighbor=alcc.template opposite<2>(maptcell_it->second); break;
+            case 3: neighbor=maptcell_it->second; break;
+          }
+
+          while (alcc.vertex_attribute(neighbor)!=
+                 alcc.vertex_attribute(alcc.other_extremity(cur)))
+          { neighbor = alcc.next(neighbor); }
+
+          assert(alcc.vertex_attribute(alcc.other_extremity(cur))==
+                 alcc.vertex_attribute(alcc.other_orientation(neighbor)));
+          assert(alcc.vertex_attribute(alcc.other_extremity(alcc.next(cur)))==
+                 alcc.vertex_attribute(alcc.other_orientation(alcc.previous(neighbor))));
+          assert(alcc.vertex_attribute(alcc.other_extremity(alcc.previous(cur)))==
+                 alcc.vertex_attribute(alcc.other_orientation(alcc.next(neighbor))));
+          assert(alcc.template is_free<3>(cur));
+          assert(alcc.template is_free<3>(alcc.other_orientation(neighbor)));
+
+          alcc.template topo_sew<3>(cur, alcc.other_orientation(neighbor));
+        }
+      }
+      (*mytc)[it]=res;
+    }
+  }
+  CGAL_assertion(dart!=LCC::null_handle);
+  alcc.correct_invalid_attributes(); // Necessary to correct problem of two
+  // tetra adjacent by a vertex (non manifold case).
+  return dart;
+}
+
+#endif // MESH_COMPLEX_3_IN_TRIANGULATION_3_TO_LCC_H
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/My_linear_cell_complex_incremental_builder.h b/src/My_linear_cell_complex_incremental_builder.h
new file mode 100644
index 0000000000000000000000000000000000000000..f98a2996b0d765bdeca46af34c9b8e03d71a2331
--- /dev/null
+++ b/src/My_linear_cell_complex_incremental_builder.h
@@ -0,0 +1,570 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+#ifndef MY_LINEAR_CELL_COMPLEX_INCREMENTAL_BUILDER_H
+#define MY_LINEAR_CELL_COMPLEX_INCREMENTAL_BUILDER_H 1
+
+#include <vector>
+#include <cstddef>
+#include <unordered_map>
+#include <initializer_list>
+#include <CGAL/Linear_cell_complex_base.h>
+
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC, class Combinatorial_data_structure=
+         typename LCC::Combinatorial_data_structure>
+struct Add_vertex_to_face
+{
+  static typename LCC::Dart_handle run(LCC&,
+                                       typename LCC::Vertex_attribute_handle,
+                                       typename LCC::Dart_handle)
+  {}
+};
+template<class LCC>
+struct Add_vertex_to_face<LCC, CGAL::Combinatorial_map_tag>
+{
+  static typename LCC::Dart_handle run(LCC& lcc,
+                                       typename LCC::Vertex_attribute_handle vh,
+                                       typename LCC::Dart_handle prev_dart)
+  {
+    typename LCC::Dart_handle res=lcc.create_dart(vh);
+    if (prev_dart!=lcc.null_handle)
+    { 
+       lcc.template link_beta<1>(prev_dart, res); 
+    }
+    return res;
+  }
+  static void run_for_last(LCC&,
+                           typename LCC::Vertex_attribute_handle,
+                           typename LCC::Dart_handle)
+  { // here nothing to do, all darts were already created.
+  }
+};
+template<class LCC>
+struct Add_vertex_to_face<LCC, CGAL::Generalized_map_tag>
+{
+  static typename LCC::Dart_handle run(LCC& lcc,
+                                       typename LCC::Vertex_attribute_handle vh,
+                                       typename LCC::Dart_handle prev_dart)
+  {
+    typename LCC::Dart_handle res=lcc.create_dart(vh);
+    if (prev_dart!=lcc.null_handle)
+    {
+      lcc.template link_alpha<0>(prev_dart, res);
+      lcc.template link_alpha<1>(res, lcc.create_dart(vh));
+      res=lcc.template alpha<1>(res);
+    }
+    return res;
+  }
+  static void run_for_last(LCC& lcc,
+                           typename LCC::Vertex_attribute_handle vh,
+                           typename LCC::Dart_handle prev_dart)
+  {
+    // here we need to create a last dart and 0-link it
+    assert(prev_dart!=lcc.null_handle);
+    lcc.template link_alpha<0>(prev_dart, lcc.create_dart(vh));
+  }
+};
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC, class Combinatorial_data_structure=
+         typename LCC::Combinatorial_data_structure>
+struct Find_opposite_2_no_control // No difference for CMap and GMap
+{
+  typedef typename LCC::Dart_handle             DH;
+  typedef typename LCC::Vertex_attribute_handle VAH;
+  static DH run(LCC&,
+                std::unordered_map<VAH, std::unordered_map<VAH, DH>>&
+                vertex_to_dart_map_in_surface,
+                VAH vah1, VAH vah2)
+  {
+    // We are searching edge vah2->vah1 (the opposite of edge vah1->vah2)
+    auto it2=vertex_to_dart_map_in_surface.find(vah2);
+    if (it2!=vertex_to_dart_map_in_surface.end())
+    {
+      auto it1=it2->second.find(vah1);
+      if (it1!=it2->second.end())
+      { return it1->second; }
+    }
+    return nullptr;
+  }
+};
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC, class Combinatorial_data_structure=
+         typename LCC::Combinatorial_data_structure>
+struct Find_opposite_2_with_control
+{
+  typedef typename LCC::Dart_handle             DH;
+  typedef typename LCC::Vertex_attribute_handle VAH;
+  static DH run(LCC&,
+                std::unordered_map<VAH, std::unordered_map<VAH, DH>>&,
+                VAH, VAH)
+  { return nullptr; }
+};
+template<class LCC>
+struct Find_opposite_2_with_control<LCC, CGAL::Combinatorial_map_tag>
+{
+  typedef typename LCC::Dart_handle             DH;
+  typedef typename LCC::Vertex_attribute_handle VAH;
+  static DH run(LCC& lcc,
+                std::unordered_map<VAH, std::unordered_map<VAH, DH>>&
+                vertex_to_dart_map_in_surface,
+                VAH vah1, VAH vah2)
+  {
+    DH res=Find_opposite_2_no_control<LCC>::run(lcc,
+                                                vertex_to_dart_map_in_surface,
+                                                vah1, vah2);
+    if (res!=nullptr)
+    {
+      if (!lcc.template is_free<2>(res))
+      { // Here a dart vah1->vah2 already exists, and it was already 2-sewn.
+        std::cerr<<"ERROR in My_linear_cell_complex_incremental_builder_3: try to use a same oriented edge twice."<<std::endl;
+        return nullptr;
+      }
+    }
+    if (Find_opposite_2_no_control<LCC>::run(lcc,
+                                             vertex_to_dart_map_in_surface,
+                                             vah2, vah1)!=nullptr)
+    { // Here a dart vah1->vah2 already exists (but it was not already 2-sewn).
+      std::cerr<<"ERROR in My_linear_cell_complex_incremental_builder_3: try to use a same oriented edge twice."<<std::endl;
+      return nullptr;
+    }
+
+    return res;
+  }
+};
+template<class LCC>
+struct Find_opposite_2_with_control<LCC, CGAL::Generalized_map_tag>
+{
+  typedef typename LCC::Dart_handle             DH;
+  typedef typename LCC::Vertex_attribute_handle VAH;
+  static DH run(LCC& lcc,
+                std::unordered_map<VAH, std::unordered_map<VAH, DH>>&
+                vertex_to_dart_map_in_surface,
+                VAH vah1, VAH vah2)
+  {
+    DH res=Find_opposite_2_no_control<LCC>::run(lcc,
+                                                vertex_to_dart_map_in_surface,
+                                                vah1, vah2);
+    if (res!=nullptr)
+    {
+      if (!lcc.template is_free<2>(res))
+      { // Here a dart vah1->vah2 already exists, and it was already 2-sewn.
+        std::cerr<<"ERROR in My_linear_cell_complex_incremental_builder_3: try to use a same oriented edge twice."<<std::endl;
+        return nullptr;
+      }
+    }
+    return res;
+  }
+};
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC, class Combinatorial_data_structure=
+         typename LCC::Combinatorial_data_structure>
+struct Add_edge_in_associative_array
+{
+  typedef typename LCC::Dart_handle             DH;
+  typedef typename LCC::Vertex_attribute_handle VAH;
+  static void run(LCC&, DH,
+                  std::unordered_map<VAH, std::unordered_map<VAH, DH>>&)
+   {}
+};
+template<class LCC>
+struct Add_edge_in_associative_array<LCC, CGAL::Combinatorial_map_tag>
+{
+  typedef typename LCC::Dart_handle             DH;
+  typedef typename LCC::Vertex_attribute_handle VAH;
+  static void run(LCC& lcc, DH dh,
+                  std::unordered_map<VAH, std::unordered_map<VAH, DH>>&
+                  vertex_to_dart_map_in_surface)
+  {
+    vertex_to_dart_map_in_surface[lcc.vertex_attribute(dh)].insert
+        (std::make_pair(lcc.vertex_attribute(lcc.next(dh)), dh));
+  }
+};
+template<class LCC>
+struct Add_edge_in_associative_array<LCC, CGAL::Generalized_map_tag>
+{
+  typedef typename LCC::Dart_handle             DH;
+  typedef typename LCC::Vertex_attribute_handle VAH;
+  static void run(LCC& lcc, DH dh,
+                  std::unordered_map<VAH, std::unordered_map<VAH, DH>>&
+                  vertex_to_dart_map_in_surface)
+  {
+    vertex_to_dart_map_in_surface[lcc.vertex_attribute(dh)].insert
+        (std::make_pair(lcc.vertex_attribute(lcc.template alpha<0>(dh)), dh));
+
+    vertex_to_dart_map_in_surface
+        [lcc.vertex_attribute(lcc.template alpha<0>(dh))].insert
+        (std::make_pair(lcc.vertex_attribute(dh), lcc.template alpha<0>(dh)));
+  }
+};
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC_, unsigned int dim=LCC_::dimension>
+struct Sew3_for_LCC_incremental_builder
+{
+  static void run(LCC_& lcc,
+                  typename LCC_::Dart_handle dh1, typename LCC_::Dart_handle dh2)
+  {
+    if(dh1!=nullptr)
+    {
+      if(!lcc.template is_free<3>(dh1))
+      {
+        std::cerr<<"ERROR in My_linear_cell_complex_incremental_builder_3: "
+                 <<"it exists more than 2 faces with same indices."<<std::endl;
+      }
+      else
+      { lcc.template sew<3>(lcc.other_orientation(dh1), dh2); }
+    }
+  }
+};
+template<class LCC_>
+struct Sew3_for_LCC_incremental_builder<LCC_, 2>
+{
+  static void run(LCC_&, typename LCC_::Dart_handle, typename LCC_::Dart_handle)
+  {}
+};
+///////////////////////////////////////////////////////////////////////////////
+// Incremental builder
+template < class LCC_ >
+class My_linear_cell_complex_incremental_builder_3
+{
+public:
+  typedef LCC_ LCC;
+  typedef typename LCC::Dart_handle             DH;
+  typedef typename LCC::Vertex_attribute_handle VAH;
+  typedef typename LCC::Point                   Point_3;
+  typedef typename LCC::size_type               size_type;
+
+  My_linear_cell_complex_incremental_builder_3(LCC & alcc) :
+    lcc(alcc)
+  {}
+
+  VAH add_vertex(const Point_3& p)
+  {
+    VAH res=lcc.create_vertex_attribute(p);
+    vertex_map.push_back(res);
+    return res;
+  }
+
+  void begin_facet()
+  { // std::cout<<"Begin facet: "<<std::flush;
+    first_dart=lcc.null_handle;
+    prev_dart =lcc.null_handle;
+  }
+
+  void add_vertex_to_facet(size_type i)
+  {
+    CGAL_assertion(i<vertex_map.size());
+    // std::cout<<i<<"  "<<std::flush;
+    DH cur_dart=Add_vertex_to_face<LCC>::run(lcc, vertex_map[i], prev_dart);
+    if(prev_dart!=lcc.null_handle)
+    {
+      DH opposite=Find_opposite_2_with_control<LCC>::
+                  run(lcc,
+                      vertex_to_dart_map_in_surface,
+                      lcc.vertex_attribute(prev_dart),
+                      lcc.vertex_attribute(cur_dart));
+      if(opposite!=lcc.null_handle)
+      {
+        CGAL_assertion(lcc.template is_free<2>(opposite));
+        lcc.template set_opposite<2>(prev_dart, opposite);
+      }
+
+      Add_edge_in_associative_array<LCC>::run(lcc, prev_dart,
+                                              vertex_to_dart_map_in_surface);
+
+      if (i<min_vertex) { min_vertex=i; min_dart=cur_dart; }
+      if (i>max_vertex) { max_vertex=i; }
+    }
+    else
+    { first_dart=cur_dart; min_vertex=max_vertex=i; min_dart=cur_dart; }
+
+    prev_dart=cur_dart;
+  }
+
+  // End of the facet. Return the first dart of this facet.
+  DH end_facet()
+  {
+    CGAL_assertion(first_dart!=lcc.null_handle && prev_dart!=lcc.null_handle);
+
+    Add_vertex_to_face<LCC>::run_for_last(lcc,
+                                          lcc.vertex_attribute(first_dart),
+                                          prev_dart);
+
+    lcc.set_next(prev_dart, first_dart);
+
+    DH opposite=Find_opposite_2_with_control<LCC>::
+                run(lcc,
+                    vertex_to_dart_map_in_surface,
+                    lcc.vertex_attribute(prev_dart),
+                    lcc.vertex_attribute(first_dart));
+    if(opposite!=lcc.null_handle)
+    {
+      CGAL_assertion(lcc.template is_free<2>(opposite));
+      lcc.template set_opposite<2>(prev_dart, opposite);
+    }
+
+    Add_edge_in_associative_array<LCC>::run(lcc, prev_dart,
+                                            vertex_to_dart_map_in_surface);
+
+    if(LCC::dimension>2)
+    {
+      opposite=opposite_face();
+      Sew3_for_LCC_incremental_builder<LCC>::run(lcc, opposite, min_dart);
+      add_face_in_array();
+    }
+    return first_dart;
+  }
+
+  DH add_facet(std::initializer_list<size_type> l)
+  {
+    begin_facet();
+    for (std::size_t i:l)
+    { add_vertex_to_facet(i); }
+    return end_facet();
+  }
+
+  void begin_surface()
+  {
+    vertex_to_dart_map_in_surface.clear();
+  }
+
+  // End of the surface. Return one dart of the created surface.
+  DH end_surface()
+  { return first_dart; }
+
+protected:
+  /** test if the two given facets have the same vertex handle but with
+   *  opposite orientations. For closed facets.
+   * @return true iff the two facets have the same vertex handle with opposite
+   *         orientation.
+   */
+  bool are_facets_opposite_and_same_vertex_handles(DH d1, DH d2) const
+  {
+    DH s1=d1;
+    DH s2=d2;
+    do
+    {
+      assert(lcc.is_next_exist(d1) && lcc.is_previous_exist(d2));
+      assert(lcc.other_extremity(d2)!=lcc.null_handle);
+
+      if (lcc.vertex_attribute(d1)!=lcc.vertex_attribute(d2))
+      { return false; }
+      d1=lcc.next(d1);
+      d2=lcc.previous(d2);
+    }
+    while(d1!=s1);
+
+    if (d2!=s2) { return false; }
+    return true;
+  }
+
+  DH opposite_face()
+  {
+    auto it1=faces.find(min_vertex);
+    if(it1==faces.end()) { return nullptr; }
+    auto it2=it1->second.find(max_vertex);
+    if(it2==it1->second.end()) { return nullptr; }
+    for(auto it3=it2->second.begin(), it3end=it2->second.end(); it3!=it3end; ++it3)
+    {
+      if (are_facets_opposite_and_same_vertex_handles(*it3, min_dart))
+      { return lcc.previous(*it3); }
+    }
+    return nullptr;
+  }
+
+  void add_face_in_array()
+  {
+    faces[min_vertex][max_vertex].push_back(min_dart);
+  }
+
+private:
+  LCC& lcc;
+  std::vector<VAH> vertex_map; // Map each index to the corresponding vertex handle
+
+  // A map to associate to each edge of a surface its dart. The edge is given
+  // by its two vertex handles (source-target).
+  std::unordered_map<VAH, std::unordered_map<VAH, DH>> vertex_to_dart_map_in_surface;
+  std::unordered_map<std::size_t, std::unordered_map<std::size_t, std::vector<DH>>> faces;
+
+  DH first_dart; /// First dart of the current face
+  DH prev_dart; /// Prev dart of the current face
+  DH min_dart; /// dart with the min vertex of the current facet.
+  std::size_t min_vertex, max_vertex; /// min and max indices of vertices of the current face
+};
+///////////////////////////////////////////////////////////////////////////////
+/* Create an hexahedron, given the indices of its vertices (in the following
+*  order), the vertex must already have been added in the incremental builder.
+*      3
+*     /|\
+*    0-|-2
+*     \|/
+*      1
+*/
+template<typename IncrementalBuilder>
+typename IncrementalBuilder::LCC::Dart_handle
+make_tetrahedron_with_builder(IncrementalBuilder& ib,
+                                   std::size_t i0,
+                                   std::size_t i1,
+                                   std::size_t i2,
+                                   std::size_t i3)
+{
+  ib.begin_surface();
+  ib.add_facet({i0,i1,i2});
+  ib.add_facet({i1,i0,i3});
+  ib.add_facet({i2,i1,i3});
+  ib.add_facet({i0,i2,i3});
+  return ib.end_surface();
+}
+///////////////////////////////////////////////////////////////////////////////
+/*      4
+ *     /|\
+ *    0-|-3
+ *    | | |
+ *    1---2
+ */
+template<typename IncrementalBuilder>
+typename IncrementalBuilder::LCC::Dart_handle
+ make_pyramid_with_builder(IncrementalBuilder& ib,
+                               std::size_t i0,
+                               std::size_t i1,
+                               std::size_t i2,
+                               std::size_t i3,
+                               std::size_t i4)
+{
+  ib.begin_surface();
+  ib.add_facet({i0,i1,i2,i3});
+  ib.add_facet({i1,i0,i4});
+  ib.add_facet({i2,i1,i4});
+  ib.add_facet({i3,i2,i4});
+  ib.add_facet({i0,i3,i4});
+  return ib.end_surface();
+}
+///////////////////////////////////////////////////////////////////////////////
+/*      3
+ *     /|\
+ *    4---5
+ *    | | |
+ *    | 0 |
+ *    |/ \|
+ *    1---2
+ */
+template<typename IncrementalBuilder>
+typename IncrementalBuilder::LCC::Dart_handle
+ make_prism_with_builder(IncrementalBuilder& ib,
+                             std::size_t i0,
+                             std::size_t i1,
+                             std::size_t i2,
+                             std::size_t i3,
+                             std::size_t i4,
+                             std::size_t i5)
+{
+  ib.begin_surface();
+  ib.add_facet({i0,i1,i2});
+  ib.add_facet({i1,i0,i3,i4});
+  ib.add_facet({i2,i1,i4,i5});
+  ib.add_facet({i0,i2,i5,i3});
+  ib.add_facet({i5,i4,i3});
+  return ib.end_surface();
+}
+///////////////////////////////////////////////////////////////////////////////
+/*      7----6
+ *     /|   /|
+ *    4----5 |
+ *    | 3--|-2
+ *    |/   |/
+ *    0----1
+ */
+template<typename IncrementalBuilder>
+typename IncrementalBuilder::LCC::Dart_handle
+ make_hexahedron_with_builder(IncrementalBuilder& ib,
+                                  std::size_t i0,
+                                  std::size_t i1,
+                                  std::size_t i2,
+                                  std::size_t i3,
+                                  std::size_t i4,
+                                  std::size_t i5,
+                                  std::size_t i6,
+                                  std::size_t i7)
+{
+  ib.begin_surface();
+  ib.add_facet({i0,i1,i2,i3});
+  ib.add_facet({i1,i0,i4,i5});
+  ib.add_facet({i2,i1,i5,i6});
+  ib.add_facet({i3,i2,i6,i7});
+  ib.add_facet({i0,i3,i7,i4});
+  ib.add_facet({i7,i6,i5,i4});
+  return ib.end_surface();
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename IncrementalBuilder>
+typename IncrementalBuilder::LCC::Dart_handle
+ make_pentagonal_prism_with_builder(IncrementalBuilder& ib,
+                                        std::size_t i0,
+                                        std::size_t i1,
+                                        std::size_t i2,
+                                        std::size_t i3,
+                                        std::size_t i4,
+                                        std::size_t i5,
+                                        std::size_t i6,
+                                        std::size_t i7,
+                                        std::size_t i8,
+                                        std::size_t i9)
+{
+  ib.begin_surface();
+  ib.add_facet({i0,i1,i2,i3,i4});
+  ib.add_facet({i1,i0,i5,i6});
+  ib.add_facet({i2,i1,i6,i7});
+  ib.add_facet({i3,i2,i7,i8});
+  ib.add_facet({i4,i3,i8,i9});
+  ib.add_facet({i0,i4,i9,i5});
+  ib.add_facet({i9,i8,i7,i6,i5});
+  return ib.end_surface();
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename IncrementalBuilder>
+typename IncrementalBuilder::LCC::Dart_handle
+ make_hexagonal_prism_with_builder(IncrementalBuilder& ib,
+                                       std::size_t i0,
+                                       std::size_t i1,
+                                       std::size_t i2,
+                                       std::size_t i3,
+                                       std::size_t i4,
+                                       std::size_t i5,
+                                       std::size_t i6,
+                                       std::size_t i7,
+                                       std::size_t i8,
+                                       std::size_t i9,
+                                       std::size_t i10,
+                                       std::size_t i11)
+{
+  ib.begin_surface();
+  ib.add_facet({i0,i1,i2,i3,i4,i5});
+  ib.add_facet({i1,i0,i6,i7});
+  ib.add_facet({i2,i1,i7,i8});
+  ib.add_facet({i3,i2,i8,i9});
+  ib.add_facet({i4,i3,i9,i10});
+  ib.add_facet({i5,i4,i10,i11});
+  ib.add_facet({i0,i5,i11,i6});
+  ib.add_facet({i11,i10,i9,i8,i7,i6});
+  return ib.end_surface();
+}
+///////////////////////////////////////////////////////////////////////////////
+#endif // MY_LINEAR_CELL_COMPLEX_INCREMENTAL_BUILDER_H //
+// EOF //
diff --git a/src/One_info.h b/src/One_info.h
new file mode 100644
index 0000000000000000000000000000000000000000..d1755fcaec55136d8dfedc17a087eebe4308598f
--- /dev/null
+++ b/src/One_info.h
@@ -0,0 +1,91 @@
+// compute_arrangement: a new method to compute arrangement of segments.
+// Copyright (C) 2020 CNRS and LIRIS' Establishments (France).
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+
+#ifndef ONE_INFO_H
+#define ONE_INFO_H
+
+#include <cstddef>
+#include <ostream>
+
+/// To store min, max and sum of a given info
+template<typename T>
+class One_info
+{
+public:
+  One_info(): m_min(static_cast<T>(0)),
+              m_max(static_cast<T>(0)),
+              m_sum(static_cast<T>(0)),
+              m_nb(0)
+  {}
+
+  void update(T val)
+  {
+    if (m_nb==0)
+    {
+      m_min=val;
+      m_max=val;
+      m_sum=val;
+    }
+    else
+    {
+      if (val<m_min) m_min=val;
+      if (val>m_max) m_max=val;
+      m_sum+=val;
+    }
+    ++m_nb;
+  }
+
+  T min() const
+  { return m_min; }
+
+  T max() const
+  { return m_max; }
+
+  double mean() const
+  {
+    if (m_nb==0) {return 0.; }
+    return static_cast<double>(m_sum)/static_cast<double>(m_nb);
+  }
+
+  T sum() const
+  { return m_sum; }
+
+  std::size_t number_of_elements() const
+  { return  m_nb; }
+
+  void reinit()
+  {
+    m_min=static_cast<T>(0);
+    m_max=static_cast<T>(0);
+    m_sum=static_cast<T>(0);
+    m_nb=0;
+  }
+
+  friend std::ostream& operator<<(std::ostream& os, const One_info& info)
+  {
+    os<<info.mean()<<" ("<<info.min()<<", "<<info.max()<<")";
+    return os;
+  }
+
+protected:
+  T m_min, m_max, m_sum;
+  std::size_t m_nb;
+};
+
+#endif // ONE_INFO_H
diff --git a/src/Orientation.h b/src/Orientation.h
new file mode 100644
index 0000000000000000000000000000000000000000..f20d082dda891a67f0a2a3abe2b1fe6903dc3a73
--- /dev/null
+++ b/src/Orientation.h
@@ -0,0 +1,285 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+
+#ifndef ORIENTATION_H
+#define ORIENTATION_H
+
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include "Element_topo.h"
+#include "Volume_computation.h"
+
+/*      3
+ *     /|\
+ *    0-|-2
+ *     \|/
+ *      1
+ */
+template<typename Point>
+bool is_positive_tetra(const Point& p0, const Point& p1,
+                       const Point& p2, const Point& p3)
+{ return CGAL::orientation(p0, p1, p2, p3)==CGAL::POSITIVE; }
+
+/*       4
+ *      /|\
+ *     0-|-3
+ *     | | |
+ *     1---2
+ */
+template<typename Point>
+bool is_positive_pyramid(const Point& p0, const Point& p1,
+                         const Point& p2, const Point& p3,
+                         const Point& p4)
+{
+  CGAL_USE(p3);
+  assert(is_positive_tetra(p0, p1, p2, p4)==is_positive_tetra(p0, p2, p3, p4));
+  return is_positive_tetra(p0, p1, p2, p4);
+}
+
+/*      3
+ *     /|\
+ *    4---5
+ *    | | |
+ *    | 0 |
+ *    |/ \|
+ *    1---2
+ */
+template<typename Point>
+bool is_positive_prism(const Point& p0, const Point& p1,
+                       const Point& p2, const Point& p3,
+                       const Point& p4, const Point& p5)
+{
+  CGAL_USE(p3); CGAL_USE(p4);
+  assert(is_positive_tetra(p0, p1, p2, p5)==is_positive_tetra(p1, p0, p3, p5));
+  assert(is_positive_tetra(p0, p1, p2, p5)==is_positive_tetra(p4, p3, p5, p1));
+  return is_positive_tetra(p0, p1, p2, p5);
+}
+
+/*      7----6
+ *     /|   /|
+ *    4----5 |
+ *    | 3--|-2
+ *    |/   |/
+ *    0----1
+*/
+template<typename Point>
+bool is_positive_hexa(const Point& p0, const Point& p1,
+                      const Point& p2, const Point& p3,
+                      const Point& p4, const Point& p5,
+                      const Point& p6, const Point& p7)
+{
+  CGAL_USE(p2); CGAL_USE(p5); CGAL_USE(p6); CGAL_USE(p7);
+  assert(is_positive_tetra(p0, p1, p3, p4)==is_positive_tetra(p3, p1, p2, p6));
+  assert(is_positive_tetra(p0, p1, p3, p4)==is_positive_tetra(p6, p5, p4, p1));
+  assert(is_positive_tetra(p0, p1, p3, p4)==is_positive_tetra(p6, p4, p7, p3));
+  assert(is_positive_tetra(p0, p1, p3, p4)==is_positive_tetra(p1, p3, p4, p6));
+  return is_positive_tetra(p0, p1, p3, p4);
+}
+
+template<typename LCC>
+bool is_positive_generic_cell(LCC& lcc, typename LCC::Dart_handle dh)
+{
+  // Is is possible to do better? (since virtual tetra are not necessarily correct
+  // geometrically...)
+  return signed_volume_of_generic_cell(lcc,dh)>0;
+}
+
+/// @return test if the 3-cell containing dg has positive orientation
+template<typename LCC>
+bool is_positive(LCC& lcc, typename LCC::Dart_handle dh)
+{
+  typename LCC::Dart_handle sd,d2;
+  cell_topo celltopo = Get_cell_topo<LCC, 3>::run(lcc, dh, sd);
+
+  switch(celltopo)
+  {
+    case TETRAHEDRON:
+      return is_positive_tetra(lcc.point(sd),
+                               lcc.point(lcc.template beta<1>(sd)),
+                               lcc.point(lcc.template beta<0>(sd)),
+                               lcc.point(lcc.template beta<2, 0>(sd)));
+    case HEXAHEDRON:
+      d2=lcc.template beta<2, 1, 1, 2, 1>(sd);
+      return is_positive_hexa(lcc.point(sd),
+                              lcc.point(lcc.template beta<1>(sd)),
+                              lcc.point(lcc.template beta<1,1>(sd)),
+                              lcc.point(lcc.template beta<0>(sd)),
+                              lcc.point(d2),
+                              lcc.point(lcc.template beta<0>(d2)),
+                              lcc.point(lcc.template beta<0,0>(d2)),
+                              lcc.point(lcc.template beta<1>(d2)));
+    case PRISM:
+      d2=lcc.template beta<2, 1, 1, 2>(sd);
+      return is_positive_prism(lcc.point(sd),
+                               lcc.point(lcc.template beta<1>(sd)),
+                               lcc.point(lcc.template beta<0>(sd)),
+                               lcc.point(lcc.template beta<1>(d2)),
+                               lcc.point(d2),
+                               lcc.point(lcc.template beta<0>(d2)));
+    case PYRAMID:
+      return is_positive_pyramid(lcc.point(sd),
+                                 lcc.point(lcc.template beta<1>(sd)),
+                                 lcc.point(lcc.template beta<1,1>(sd)),
+                                 lcc.point(lcc.template beta<0>(sd)),
+                                 lcc.point(lcc.template beta<2,0>(sd)));
+    case GENERIC_3D:
+      return is_positive_generic_cell(lcc, dh);
+    default:
+      std::cerr<<"Error in is_positive"<<std::endl;
+  }
+  return false;
+}
+
+template<typename LCC>
+bool check_orientation(LCC& lcc, bool messages=false)
+{
+  std::size_t nbplus=0, nbminus=0;
+  typename LCC::Dart_handle sd;
+  bool res=true;
+
+  auto treated_cc=lcc.get_new_mark();
+  auto treated_volume=lcc.get_new_mark();
+  // std::cout<<"Volumes of each 3-cell:"<<std::endl;
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+  {
+    if(!lcc.is_marked(it, treated_cc))
+    {
+      std::size_t nbplus_cc=0, nbminus_cc=0;
+      for(auto itcc=lcc.template darts_of_cell_basic<4>(it, treated_cc).begin(),
+          itccend=lcc.template darts_of_cell_basic<4>(it, treated_cc).end();
+          itcc!=itccend; ++itcc)
+      {
+        lcc.mark(itcc, treated_cc); // Normally not necessary, but safer
+        if(!lcc.is_marked(itcc, treated_volume))
+        {
+          lcc.template mark_cell<3>(itcc, treated_volume);
+          if(is_positive(lcc, it)) { ++nbplus_cc; }
+          else { ++nbminus_cc; }
+        }
+      }
+      if(nbplus_cc!=0 && nbminus_cc!=0)
+      {
+        if(messages)
+        {
+          std::cout<<"[check_orientation]: INCORRECT ORIENTATION: one cc has "
+                  <<nbplus_cc<<" positive volumes and "<<nbminus_cc
+                  <<" negative ones."<<std::endl;
+        }
+        res=false;
+      }
+      nbplus+=nbplus_cc; nbminus+=nbminus_cc;
+    }
+  }
+
+  if(messages)
+  {
+    if(nbplus==0)
+    {
+      if(nbminus==0)
+      { std::cout<<"[check_orientation]: empty map."<<std::endl; }
+      else
+      {
+        std::cout<<"[check_orientation]: all the "<<nbminus
+                 <<" volumes have negative orientations."<<std::endl;
+      }
+    }
+    else
+    {
+      if(nbminus==0)
+      {
+        std::cout<<"[check_orientation]: all the "<<nbplus
+                 <<" volumes have positive orientations."<<std::endl;
+      }
+      else
+      {
+        std::cout<<"[check_orientation]: INCORRECT ORIENTATION: "
+                <<nbplus<<" positive volumes and "<<nbminus
+                <<" negative ones."<<std::endl;
+      }
+    }
+  }
+  if (nbplus!=0 && nbminus!=0) { res=false; }
+
+  lcc.free_mark(treated_cc);
+  lcc.free_mark(treated_volume);
+  return res;
+}
+
+/// Reorient all the 3-cells to be positive (if true) or negative (if false)
+/// @return true iff at least one cell was reorient,
+///         false otherwise (the mesh has already the correct orientation)
+/// @warning this method does not work if the lcc has no 3-boundary. Indeed,
+///          in such a case, the infinite volume of a cc has necessarily the
+///          opposite orientation of all the finite volumes in the same cc!!
+template<typename LCC>
+bool reorient_all(LCC& lcc, bool positive=true)
+{
+  typename LCC::Dart_handle sd;
+  bool res=false;
+  bool error=false;
+
+  auto treated_cc=lcc.get_new_mark();
+  auto treated_volume=lcc.get_new_mark();
+  // std::cout<<"Volumes of each 3-cell:"<<std::endl;
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+  {
+    if(!lcc.is_marked(it, treated_cc))
+    {
+      std::size_t nbplus_cc=0, nbminus_cc=0;
+      for(auto itcc=lcc.template darts_of_cell_basic<4>(it, treated_cc).begin(),
+          itccend=lcc.template darts_of_cell_basic<4>(it, treated_cc).end();
+          itcc!=itccend; ++itcc)
+      {
+        lcc.mark(itcc, treated_cc); // Normally not necessary, but safer
+        if(!lcc.is_marked(itcc, treated_volume))
+        {
+          lcc.template mark_cell<3>(itcc, treated_volume);
+          if(is_positive(lcc, it)) { ++nbplus_cc; }
+          else { ++nbminus_cc; }
+        }
+      }
+      if(nbplus_cc!=0 && nbminus_cc!=0)
+      {
+        if(!error)
+        {
+          std::cout<<"[reorient_all]: INCORRECT ORIENTATION: one cc has "
+                   <<nbplus_cc<<" positive volumes and "<<nbminus_cc
+                   <<" negative ones. It is not possible to directly reorient "
+                   <<"the mesh."<<std::endl;
+          error=true;
+        }
+      }
+      else if ((nbminus_cc!=0 && positive) || (nbplus_cc!=0 && !positive))
+      {
+        lcc.reverse_orientation_connected_component(it);
+        res=true;
+      }
+    }
+  }
+
+  assert(check_orientation(lcc, false));
+
+  lcc.free_mark(treated_cc);
+  lcc.free_mark(treated_volume);
+  return res;
+}
+
+#endif // ORIENTATION_H
diff --git a/src/Print_txt.h b/src/Print_txt.h
new file mode 100644
index 0000000000000000000000000000000000000000..416ee448469a711d5eaa18b58e2dd4f1526a04c7
--- /dev/null
+++ b/src/Print_txt.h
@@ -0,0 +1,44 @@
+#ifndef PRINT_TXT_H
+#define PRINT_TXT_H
+
+#include <sstream>
+#include <utility>
+#include <chrono>
+#include <iostream>
+
+///////////////////////////////////////////////////////////////////////////////
+template<typename T>
+void put_one_value(std::ostringstream& txt, const T& v)
+{ txt<<v; }
+//----------------------------------------------------------------------------
+template<> inline
+void put_one_value(std::ostringstream& txt,
+                   const std::chrono::duration<double>& v)
+{
+  //std::chrono::seconds s=std::chrono::duration_cast<std::chrono::seconds>(v);
+  txt<<v.count();
+}
+///////////////////////////////////////////////////////////////////////////////
+template <typename Arg, typename... Args>
+void print_txt(Arg&& arg, Args&&... args)
+{
+  std::ostringstream txt;
+  put_one_value(txt, std::forward<Arg>(arg));
+  using expander = int[];
+  (void)expander{0, (void(put_one_value(txt, std::forward<Args>(args))),0)...};
+  std::cout<<txt.str()<<std::flush;
+}
+///////////////////////////////////////////////////////////////////////////////
+template <typename Arg, typename... Args>
+void print_txt_with_endl(Arg&& arg, Args&&... args)
+{
+  std::ostringstream txt;
+  put_one_value(txt, std::forward<Arg>(arg));
+  using expander = int[];
+  (void)expander{0, (void(put_one_value(txt, std::forward<Args>(args))),0)...};
+  txt<<std::endl;
+  std::cout<<txt.str()<<std::flush;
+}
+///////////////////////////////////////////////////////////////////////////////
+
+#endif // PRINT_TXT_H
diff --git a/src/Prism_and_pyramid_creation.h b/src/Prism_and_pyramid_creation.h
new file mode 100644
index 0000000000000000000000000000000000000000..b03f050e1522c0a2d149325f06e097041261274f
--- /dev/null
+++ b/src/Prism_and_pyramid_creation.h
@@ -0,0 +1,357 @@
+// Copyright (c) 2011 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef PRISM_AND_PYRAMID_CREATION_H
+#define PRISM_AND_PYRAMID_CREATION_H
+
+/** Create a combinatorial prism from 2 triangles and 3 squares.
+   * @param amap the used combinatorial map.
+   * @param d1 a dart onto a first triangle.
+   * @param d2 a dart onto a first square.
+   * @param d3 a dart onto a second square.
+   * @param d4 a dart onto a thirth square.
+   * @param d5 a dart onto a second triangle.
+   * @return a new dart.
+   */
+  template < class Map >
+  typename Map::Dart_handle
+  make_combinatorial_prism(Map& amap,
+                           typename Map::Dart_handle d1,
+                           typename Map::Dart_handle d2,
+                           typename Map::Dart_handle d3,
+                           typename Map::Dart_handle d4,
+                           typename Map::Dart_handle d5)
+  {
+    // 2-link for first triangle
+    amap.basic_link_beta_for_involution(d1, d2, 2);
+    amap.basic_link_beta_for_involution(amap.beta(d1, 1), d3, 2);
+    amap.basic_link_beta_for_involution(amap.beta(d1, 0), d4, 2);
+
+    // 2-link for quandrangles between them
+    amap.basic_link_beta_for_involution(amap.beta(d2, 0), amap.beta(d3, 1), 2);
+    amap.basic_link_beta_for_involution(amap.beta(d2, 1), amap.beta(d4, 0), 2);
+    amap.basic_link_beta_for_involution(amap.beta(d3, 0), amap.beta(d4, 1), 2);
+
+    // 2-link for second triangle
+    amap.basic_link_beta_for_involution(amap.beta(d2, 1, 1), d5, 2);
+    amap.basic_link_beta_for_involution(amap.beta(d3, 1, 1), amap.beta(d5, 0), 2);
+    amap.basic_link_beta_for_involution(amap.beta(d4, 1, 1), amap.beta(d5, 1), 2);
+
+    return d1;
+  }
+
+  /** Create a new combinatorial prism.
+   * @param amap the used combinatorial map.
+   * @return a new dart.
+   */
+  template < class Map >
+  typename Map::Dart_handle make_combinatorial_prism(Map& amap)
+  {
+    typename Map::Dart_handle d1 = make_combinatorial_polygon(amap,3);
+    typename Map::Dart_handle d2 = make_combinatorial_polygon(amap,4);
+    typename Map::Dart_handle d3 = make_combinatorial_polygon(amap,4);
+    typename Map::Dart_handle d4 = make_combinatorial_polygon(amap,4);
+    typename Map::Dart_handle d5 = make_combinatorial_polygon(amap,3);
+
+    return make_combinatorial_prism(amap, d1, d2, d3, d4, d5);
+  }
+
+/** Test if a volume is a combinatorial prism.
+ * @param amap the used combinatorial map.
+ * @param adart an intial dart
+ * @return true iff the volume containing adart is a combinatorial prism.
+ */
+template < class Map >
+bool is_volume_combinatorial_prism(const Map& amap,
+                                   typename Map::Dart_const_handle d1)
+{
+  typename Map::Dart_const_handle d2 = amap.beta(d1, 2);
+  typename Map::Dart_const_handle d3 = amap.beta(d1, 1, 2);
+  typename Map::Dart_const_handle d4 = amap.beta(d1, 0, 2);
+  typename Map::Dart_const_handle d5 = amap.beta(d2, 1, 1, 2);
+
+  if ( d1==amap.null_dart_handle || d2==amap.null_dart_handle ||
+       d3==amap.null_dart_handle || d4==amap.null_dart_handle ||
+       d5==amap.null_dart_handle ) return false;
+
+  if (!amap.is_face_combinatorial_polygon(d1, 3) ||
+      !amap.is_face_combinatorial_polygon(d2, 4) ||
+      !amap.is_face_combinatorial_polygon(d3, 4) ||
+      !amap.is_face_combinatorial_polygon(d4, 4) ||
+      !amap.is_face_combinatorial_polygon(d5, 3)) return false;
+
+  // TODO do better with marks.
+  if ( amap.template belong_to_same_cell<2,1>(d1, d2) ||
+       amap.template belong_to_same_cell<2,1>(d1, d3) ||
+       amap.template belong_to_same_cell<2,1>(d1, d4) ||
+       amap.template belong_to_same_cell<2,1>(d1, d5) ||
+       amap.template belong_to_same_cell<2,1>(d2, d3) ||
+       amap.template belong_to_same_cell<2,1>(d2, d4) ||
+       amap.template belong_to_same_cell<2,1>(d2, d5) ||
+       amap.template belong_to_same_cell<2,1>(d3, d4) ||
+       amap.template belong_to_same_cell<2,1>(d3, d5) ||
+       amap.template belong_to_same_cell<2,1>(d4, d5))
+    return false;
+
+  if (amap.beta(d2,0,2)  !=amap.beta(d3,1) ||
+      amap.beta(d2,1,2)  !=amap.beta(d4,0) ||
+      amap.beta(d3,0,2)  !=amap.beta(d4,1) ||
+      amap.beta(d3,1,1,2)!=amap.beta(d5,0) ||
+      amap.beta(d4,1,1,2)!=amap.beta(d5,1)) return false;
+
+  return true;
+}
+
+/** Create a combinatorial pyramid from 1 square and 4 triangles.
+   * @param amap the used combinatorial map.
+   * @param d1 a dart onto the square.
+   * @param d2 a dart onto a first triangle.
+   * @param d3 a dart onto a second triangle.
+   * @param d4 a dart onto a thirth triangle.
+   * @param d5 a dart onto a fourth triangle.
+   * @return a new dart.
+   */
+  template < class Map >
+  typename Map::Dart_handle
+  make_combinatorial_pyramid(Map& amap,
+                             typename Map::Dart_handle d1,
+                             typename Map::Dart_handle d2,
+                             typename Map::Dart_handle d3,
+                             typename Map::Dart_handle d4,
+                             typename Map::Dart_handle d5)
+  {
+    // 2-link for the square
+    amap.basic_link_beta_for_involution(d1, d2, 2);
+    amap.basic_link_beta_for_involution(amap.beta(d1, 1), d5, 2);
+    amap.basic_link_beta_for_involution(amap.beta(d1, 1, 1), d4, 2);
+    amap.basic_link_beta_for_involution(amap.beta(d1, 0), d3, 2);
+
+    // 2-link for first triangle
+    amap.basic_link_beta_for_involution(amap.beta(d2, 1), amap.beta(d3, 0), 2);
+    amap.basic_link_beta_for_involution(amap.beta(d2, 0), amap.beta(d5, 1), 2);
+
+    // 2-link for triangles between them
+    amap.basic_link_beta_for_involution(amap.beta(d5, 0), amap.beta(d4, 1), 2);
+    amap.basic_link_beta_for_involution(amap.beta(d4, 0), amap.beta(d3, 1), 2);
+
+    return d1;
+  }
+
+  /** Create a new combinatorial pyramid.
+   * @param amap the used combinatorial map.
+   * @return a new dart.
+   */
+  template < class Map >
+  typename Map::Dart_handle make_combinatorial_pyramid(Map& amap)
+  {
+    typename Map::Dart_handle d1 = make_combinatorial_polygon(amap,4);
+    typename Map::Dart_handle d2 = make_combinatorial_polygon(amap,3);
+    typename Map::Dart_handle d3 = make_combinatorial_polygon(amap,3);
+    typename Map::Dart_handle d4 = make_combinatorial_polygon(amap,3);
+    typename Map::Dart_handle d5 = make_combinatorial_polygon(amap,3);
+
+    return make_combinatorial_pyramid(amap, d1, d2, d3, d4, d5);
+  }
+
+/** Test if a volume is a combinatorial pyramid.
+ * @param amap the used combinatorial map.
+ * @param adart an intial dart
+ * @return true iff the volume containing adart is a combinatorial pyramid.
+ */
+template < class Map >
+bool is_volume_combinatorial_pyramid(const Map& amap,
+                                     typename Map::Dart_const_handle d1)
+{ 
+  typename Map::Dart_const_handle d2 = amap.beta(d1, 2);
+  typename Map::Dart_const_handle d3 = amap.beta(d1, 0, 2);
+  typename Map::Dart_const_handle d4 = amap.beta(d1, 1, 1, 2);
+  typename Map::Dart_const_handle d5 = amap.beta(d1, 1, 2);
+
+  if ( d1==amap.null_dart_handle || d2==amap.null_dart_handle ||
+       d3==amap.null_dart_handle || d4==amap.null_dart_handle ||
+       d5==amap.null_dart_handle ) return false;
+
+  if (!amap.is_face_combinatorial_polygon(d1, 4) ||
+      !amap.is_face_combinatorial_polygon(d2, 3) ||
+      !amap.is_face_combinatorial_polygon(d3, 3) ||
+      !amap.is_face_combinatorial_polygon(d4, 3) ||
+      !amap.is_face_combinatorial_polygon(d5, 3)) return false;
+
+  // TODO do better with marks.
+  if ( amap.template belong_to_same_cell<2,1>(d1, d2) ||
+       amap.template belong_to_same_cell<2,1>(d1, d3) ||
+       amap.template belong_to_same_cell<2,1>(d1, d4) ||
+       amap.template belong_to_same_cell<2,1>(d1, d5) ||
+       amap.template belong_to_same_cell<2,1>(d2, d3) ||
+       amap.template belong_to_same_cell<2,1>(d2, d4) ||
+       amap.template belong_to_same_cell<2,1>(d2, d5) ||
+       amap.template belong_to_same_cell<2,1>(d3, d4) ||
+       amap.template belong_to_same_cell<2,1>(d3, d5) ||
+       amap.template belong_to_same_cell<2,1>(d4, d5))
+    return false;
+
+  if (amap.beta(d2,1,2)!=amap.beta(d3,0) ||
+      amap.beta(d2,0,2)!=amap.beta(d5,1) ||
+      amap.beta(d5,0,2)!=amap.beta(d4,1) ||
+      amap.beta(d4,0,2)!=amap.beta(d3,1)) return false;
+
+  return true;
+}
+
+/** Create an prism given 6 Vertex_attribute_handle.
+     *    (6 vertices, 9 edges and 5 facets)
+     * \verbatim
+     *      3---4
+     *      |\ /|
+     *      0-5-1
+     *       \|/
+     *        2
+     * \endverbatim
+     * @param h0 the first vertex handle.
+     * @param h1 the second vertex handle.
+     * @param h2 the third vertex handle.
+     * @param h3 the fourth vertex handle.
+     * @param h4 the fifth vertex handle.
+     * @param h5 the sixth vertex handle.
+     * @return the dart of the new prism incident to h0 and to
+     *         the facet (h0,h1,h2).
+     */
+     template < class Map >
+     typename Map::Dart_handle make_prism(Map& amap,
+                                          typename Map::Vertex_attribute_handle h0,
+                                          typename Map::Vertex_attribute_handle h1,
+                                          typename Map::Vertex_attribute_handle h2,
+                                          typename Map::Vertex_attribute_handle h3,
+                                          typename Map::Vertex_attribute_handle h4,
+                                          typename Map::Vertex_attribute_handle h5)
+    {
+      typename Map::Dart_handle d1 = amap.make_triangle(h0, h1, h2);
+      typename Map::Dart_handle d2 = amap.make_quadrangle(h1, h0, h3, h4);
+      typename Map::Dart_handle d3 = amap.make_quadrangle(h2, h1, h4, h5);
+      typename Map::Dart_handle d4 = amap.make_quadrangle(h0, h2, h5, h3);
+      typename Map::Dart_handle d5 = amap.make_triangle(h4, h3, h5);
+
+      return make_combinatorial_prism(amap, d1, d2, d3, d4, d5);
+    }
+
+    /** Create an prism given 6 points.
+     * \verbatim
+     *      3---4
+     *      |\ /|
+     *      0-5-1
+     *       \|/
+     *        2
+     * \endverbatim
+     * @param p0 the first point.
+     * @param p1 the second point.
+     * @param p2 the third point.
+     * @param p3 the fourth point.
+     * @param p4 the fifth point.
+     * @param p5 the sixth point.
+     * @return the dart of the new prism incident to p0 and to
+     *         the facet (p0,p1,p2).
+     */
+     template < class Map >
+     typename Map::Dart_handle make_prism(Map& amap,
+                            const typename Map::Point& p0,
+                            const typename Map::Point& p1,
+                            const typename Map::Point& p2,
+                            const typename Map::Point& p3,
+                            const typename Map::Point& p4,
+                            const typename Map::Point& p5)
+    {
+      return make_prism(amap,
+                        amap.create_vertex_attribute(p0),
+                        amap.create_vertex_attribute(p1),
+                        amap.create_vertex_attribute(p2),
+                        amap.create_vertex_attribute(p3),
+                        amap.create_vertex_attribute(p4),
+                        amap.create_vertex_attribute(p5));
+    }
+
+    /** Create an pyramid given 5 Vertex_attribute_handle.
+     *    (5 vertices, 8 edges and 5 facets)
+     * \verbatim
+     *       4
+     *      /|\
+     *     0-|-1
+     *     | | |
+     *     3---2
+     * \endverbatim
+     * @param h0 the first vertex handle.
+     * @param h1 the second vertex handle.
+     * @param h2 the third vertex handle.
+     * @param h3 the fourth vertex handle.
+     * @param h4 the fifth vertex handle.
+     * @return the dart of the new pyramid incident to h0 and to
+     *         the facet (h0,h1,h2,h3).
+     */
+     template < class Map >
+    typename Map::Dart_handle make_pyramid(Map& amap,
+                             typename Map::Vertex_attribute_handle h0,
+                             typename Map::Vertex_attribute_handle h1,
+                             typename Map::Vertex_attribute_handle h2,
+                             typename Map::Vertex_attribute_handle h3,
+                             typename Map::Vertex_attribute_handle h4)
+    {
+      typename Map::Dart_handle d1 = amap.make_quadrangle(h0, h1, h2, h3);
+      typename Map::Dart_handle d2 = amap.make_triangle(h1, h0, h4);
+      typename Map::Dart_handle d3 = amap.make_triangle(h0, h3, h4);
+      typename Map::Dart_handle d4 = amap.make_triangle(h3, h2, h4);
+      typename Map::Dart_handle d5 = amap.make_triangle(h2, h1, h4);
+
+      return make_combinatorial_pyramid(amap, d1, d2, d3, d4, d5);
+    }
+
+    /** Create an pyramid given 5 points.
+     * \verbatim
+     *       4
+     *      /|\
+     *     0-|-1
+     *     | | |
+     *     3---2
+     * \endverbatim
+     * @param p0 the first point.
+     * @param p1 the second point.
+     * @param p2 the third point.
+     * @param p3 the fourth point.
+     * @param p4 the fifth point.
+     * @return the dart of the new pyramid incident to p0 and to
+     *         the facet (p0,p1,p2,p3).
+     */
+    template < class Map >
+    typename Map::Dart_handle make_pyramid(Map& amap,
+                            const typename Map::Point& p0,
+                            const typename Map::Point& p1,
+                            const typename Map::Point& p2,
+                            const typename Map::Point& p3,
+                            const typename Map::Point& p4)
+    {
+      return make_pyramid(amap,
+                          amap.create_vertex_attribute(p0),
+                          amap.create_vertex_attribute(p1),
+                          amap.create_vertex_attribute(p2),
+                          amap.create_vertex_attribute(p3),
+                          amap.create_vertex_attribute(p4));
+    }
+
+#endif // PRISM_AND_PYRAMID_CREATION_H
+///////////////////////////////////////////////////////////////////////////////
diff --git a/src/Tetrahedral_tools.h b/src/Tetrahedral_tools.h
new file mode 100644
index 0000000000000000000000000000000000000000..cb6bb81a9ae597b92ab9c3b82af546ac37058bb1
--- /dev/null
+++ b/src/Tetrahedral_tools.h
@@ -0,0 +1,251 @@
+// Copyright (c) 2011 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+////////////////////////////////////////////////////////////////////////////////
+#include <CGAL/Triangulation_3_to_lcc.h>
+#include <CGAL/Mesh_triangulation_3.h>
+#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
+#include <CGAL/Mesh_criteria_3.h>
+#include <CGAL/Polyhedral_mesh_domain_3.h>
+#include <CGAL/Surface_mesh.h>
+#include <CGAL/make_mesh_3.h>
+#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
+#include <CGAL/Polygon_mesh_processing/measure.h>
+#include "lcc_to_face_graph.h"
+#include "lcc_to_tetgen_io.h"
+#include "lcc_triangulate_faces.h"
+#include "MeshComplex_3InTriangulation_3_to_lcc.h"
+#include <tetgen.h>
+////////////////////////////////////////////////////////////////////////////////
+/* Code trying to use CGAL mesher, problem to fix parameters.
+template<typename LCC>
+void tetrahedralize(LCC &lcc)
+{
+  typedef typename LCC::Traits K;
+  typedef typename CGAL::Surface_mesh<typename K::Point_3> Polyhedron;
+  typedef CGAL::Polyhedral_mesh_domain_3<Polyhedron, K> Mesh_domain;
+  typedef CGAL::Sequential_tag Concurrency_tag; // Or CGAL::Parallel_tag
+  typedef typename CGAL::Mesh_triangulation_3<Mesh_domain, CGAL::Default,
+      Concurrency_tag>::type Tr;
+  typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
+  typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3T3;
+
+  Polyhedron p;
+  lcc_to_face_graph(lcc, p);
+  CGAL::Polygon_mesh_processing::triangulate_faces(p);
+
+  double cursize, sumsize=0., minsize, maxsize;
+  std::size_t nbf=0;
+  for(typename boost::graph_traits<Polyhedron>::face_descriptor f: faces(p))
+  {
+    auto he1=CGAL::halfedge(f, p);
+    auto he2=CGAL::next(he1, p);
+    auto he3=CGAL::next(he2, p);
+    cursize=std::sqrt(CGAL::squared_area(p.point(CGAL::source(he1, p)),
+                                         p.point(CGAL::source(he2, p)),
+                                         p.point(CGAL::source(he3, p))));
+    sumsize+=cursize;
+    if (nbf==0 || cursize<minsize) { minsize=cursize; }
+    if (nbf==0 || cursize>maxsize) { maxsize=cursize; }
+    ++nbf;
+  }
+
+  double myvol=CGAL::Polygon_mesh_processing::volume(p);
+
+  std::cout<<"minsize="<<minsize<<"  maxsize="<<maxsize<<"  meansize="
+          <<sumsize/nbf<<"   myvol="<<myvol<<std::endl;
+  std::size_t nbcells=10000; // Wanted number of cells
+
+  Mesh_domain domain(p);
+  using namespace CGAL::parameters;
+  double fs=10*sumsize/nbf, fd=fs/100., es=fs;
+  std::cout<<"make_mesh_3: facet_size="<<fs<<", edge_size="<<es
+          <<", facet_distance="<<fd<<std::endl;
+
+  double s=pow((myvol*10 / * /nbcells * /)*6*sqrt(2), 1.0/3.0);
+  fs=s*s*sqrt(3)/4.;
+  fd=fs/10;
+  es=fs;
+
+  std::cout<<"make_mesh_3: facet_size="<<fs<<", edge_size="<<es
+          <<", facet_distance="<<fd<<std::endl;
+
+  Mesh_criteria criteria(cell_size=myvol, ///nbcells,
+                         facet_size=fs,
+                         edge_size=es,
+                         facet_distance=fd);//facet_size=fs, edge_size=es, facet_distance=fd);
+                         // cell_radius_edge_ratio=3, facet_angle=30);
+        //facet_angle=25, facet_size=0.15, facet_distance=0.008,
+         //                cell_radius_edge_ratio=3); // TODO compute parameters from the mesh
+
+  C3T3 c3t3 = CGAL::make_mesh_3<C3T3>(domain, criteria);//, manifold());
+  / * edge_size = 8,
+                                      facet_angle = 25, facet_size = 0.1, facet_distance = 0.2,
+                                      cell_radius_edge_ratio = 3, cell_size = 0.1);* /
+  // CGAL::refine_mesh_3(c3t3, domain, criteria);
+
+  lcc.clear();
+  import_from_complex_3_in_triangulation_3(lcc, c3t3);
+}*/
+////////////////////////////////////////////////////////////////////////////////
+inline void tetgen_options(tetgenbehavior& b)
+{
+  // Required option
+  b.plc=1;           // '-p', 0. Tetrahedralizes a piecewise linear complex (PLC).
+  b.zeroindex=1;     // '-z', 0. Numbers all output items starting from zero.
+  b.neighout=1;      // '-n', 0. Outputs tetrahedra neighbors to .neigh file.
+
+  // Required to be able to tetrahedralize only some volumes
+  b.nobisect=1;      // '-Y', 0. Preserves the input surface mesh (does not modify it).
+
+  // Optimisation
+  b.quality=1;       // '-q', 0. Refines mesh (to improve mesh quality).
+
+  // To debug
+  // b.diagnose=1;      // '-d', 0. Detects self-intersections of facets of the PLC.
+
+  /*
+  b.psc;             // '-s', 0.
+  b.refine;          // '-r', 0. Reconstructs a previously generated mesh.
+  b.coarsen;         // '-R', 0. Mesh coarsening (to reduce the mesh elements).
+  b.weighted;        // '-w', 0. Generates weighted Delaunay (regular) triangulation.
+  b.brio_hilbert;    // '-b', 1.
+  b.incrflip;        // '-l', 0.
+  b.flipinsert;      // '-L', 0.
+  b.metric;          // '-m', 0. Applies a mesh sizing function.
+  b.varvolume;       // '-a', 0. Applies a maximum tetrahedron volume constraint.
+  b.fixedvolume;     // '-a', 0.
+  b.regionattrib;    // '-A', 0. Assigns attributes to tetrahedra in different regions.
+  b.conforming;      // '-D', 0.
+  b.insertaddpoints; // '-i', 0. Inserts a list of additional points.
+  b.convex;          // '-c', 0. Retains the convex hull of the PLC.
+  b.nomergefacet;    // '-M', 0. No merge of coplanar facets or very close vertices.
+  b.nomergevertex;   // '-M', 0.
+  b.noexact;         // '-X', 0. Suppresses use of exact arithmetic.
+  b.nostaticfilter;  // '-X', 0.
+  b.facesout;        // '-f', 0. Outputs all faces to .face file.
+  b.edgesout;        // '-e', 0. Outputs all edges to .edge file.
+  b.voroout;         // '-v', 0. Outputs Voronoi diagram to files.
+  b.meditview;       // '-g', 0. Outputs mesh to .mesh file for viewing by Medit.
+  b.vtkview;         // '-k', 0. Outputs mesh to .vtk file for viewing by Paraview.
+  b.nobound;         // '-B', 0. Suppresses output of boundary information.
+  b.nonodewritten;   // '-N', 0. Suppresses output of .node file.
+  b.noelewritten;    // '-E', 0. Suppresses output of .ele file.
+  b.nofacewritten;   // '-F', 0. Suppresses output of .face and .edge file.
+  b.noiterationnum;  // '-I', 0. Suppresses mesh iteration numbers.
+  b.nojettison;      // '-J', 0. No jettison of unused vertices from output .node file.
+  b.reversetetori;   // '-R', 0.
+  b.docheck;         // '-C', 0. Checks the consistency of the final mesh.
+  b.quiet;           // '-Q', 0. Quiet: No terminal output except errors.
+  b.verbose;         // '-V', 0. Verbose: Detailed information, more terminal output.
+
+  b.vertexperblock;     // '-x', 4092.
+  b.tetrahedraperblock; // '-x', 8188.
+  b.shellfaceperblock;  // '-x', 2044.
+  b.nobisect_param;     // '-Y', 2.
+  b.addsteiner_algo;    // '-Y/', 1.
+  b.coarsen_param;      // '-R', 0. Mesh coarsening (to reduce the mesh elements).
+  b.weighted_param;     // '-w', 0. Generates weighted Delaunay (regular) triangulation.
+  b.fliplinklevel;      // -1.
+  b.flipstarsize;       // -1.
+  b.fliplinklevelinc;   //  1.
+  b.reflevel;           // '-D', 3.
+  b.optlevel;           // '-O', 2. Specifies the level of mesh optimization.
+  b.optscheme;          // '-O', 7.
+  b.delmaxfliplevel;    // 1.
+  b.order;              // '-o', 1.
+  b.steinerleft;        // '-S', 0. Specifies maximum number of added points.
+  b.no_sort;            // 0.
+  b.hilbert_order;      // '-b///', 52.
+  b.hilbert_limit;      // '-b//'  8.
+  b.brio_threshold;     // '-b' 64.
+  b.brio_ratio;         // '-b/' 0.125.
+  b.facet_ang_tol;      // '-p', 179.9.
+  b.maxvolume;          // '-a', -1.0. Applies a maximum tetrahedron volume constraint.
+  b.minratio;           // '-q', 0.0.
+  b.mindihedral;        // '-q', 5.0.
+  b.optmaxdihedral;     // 165.0.
+  b.optminsmtdihed;     // 179.0.
+  b.optminslidihed;     // 179.0.
+  b.epsilon;            // '-T', 1.0e-8. Sets a tolerance for coplanar test (default 10−8).
+  b.minedgelength;      // 0.0.
+  b.coarsen_percent;    // -R1/#, 1.0.
+*/
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Tetrahedralize all marked volumes of the lcc.
+///   (a volume is considered marked if one its dart is marked)
+/// At the end, no more dart is marked.
+template <typename LCC>
+void tetrahedralize_with_tetgen(LCC& lcc, typename LCC::size_type amark)
+{
+  // 1) Triangulate all marked faces
+  triangulate_marked_faces(lcc, amark);
+
+  auto newdart=lcc.get_new_mark();
+  lcc.negate_mark(newdart); // Old darts are marked
+  for(auto it=lcc.darts().begin(); it!=lcc.darts().end(); ++it)
+  {
+    if(lcc.is_marked(it, amark))
+    {
+      // 2) Fill tetgen surface
+      tetgenio mysurface;
+      tetgenbehavior b;
+      lcc_to_tetgen_one_volume_(lcc, it, mysurface);
+
+      // 3) Tetrahedralize
+      tetgenio result;
+      tetgen_options(b);
+      tetrahedralize(&b, &mysurface, &result); // char *switches, tetgenio *in, tetgenio *out, tetgenio *addin = NULL, tetgenio *bgmin = NULL
+
+      // 4) Transfert tetra into lcc
+      lcc.template remove_cell<3>(it);
+      tetgen_to_lcc(result, lcc);
+    }
+  }
+
+  lcc.negate_mark(newdart); // Now only new darts are marked
+  lcc.sew3_same_facets(newdart); // 3-sew faces of the new tetrahedra with old faces
+
+  lcc.free_mark(newdart);
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Tetrahedralize all volumes of the lcc.
+template<typename LCC>
+void tetrahedralize_with_tetgen(LCC &lcc)
+{
+  // 1) Triangulate all faces
+  triangulate_all_faces(lcc);
+
+  // 2) Fill tetgen surface
+  tetgenio mysurface;
+  tetgenbehavior b;
+  lcc_to_tetgen(lcc, mysurface);
+
+  // 3) Tetrahedralize
+  tetgenio result;
+  tetgen_options(b);
+  tetrahedralize(&b, &mysurface, &result); // char *switches, tetgenio *in, tetgenio *out, tetgenio *addin = NULL, tetgenio *bgmin = NULL
+
+  // 4) Transfert tetra into lcc
+  lcc.clear();
+  tetgen_to_lcc(result, lcc);
+}
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/Volume_computation.h b/src/Volume_computation.h
new file mode 100644
index 0000000000000000000000000000000000000000..76efb8d215b87f8c8c0dda2d00474fc98890a955
--- /dev/null
+++ b/src/Volume_computation.h
@@ -0,0 +1,235 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//                 Florence Zara <florence.zara@liris.cnrs.fr>
+//
+
+#ifndef VOLUME_COMPUTATION_H
+#define VOLUME_COMPUTATION_H
+
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Kernel_traits.h>
+#include <CGAL/Origin.h>
+#include <cmath>
+#include "Element_topo.h"
+
+/*! Compute the area of the triangle p0, p1, p2 (points are 3D points). */
+template<typename Point>
+typename Point::FT area_of_triangle(const Point& p0,
+                                    const Point& p1,
+                                    const Point& p2)
+{
+  typename CGAL::Kernel_traits<Point>::Kernel::Triangle_3 t(p0, p1, p2);
+  return std::sqrt(t.squared_area());
+}
+
+ /*      3
+  *     /|\
+  *    0-|-2
+  *     \|/
+  *      1
+  */
+template<typename Point>
+typename Point::FT signed_volume_of_tetra(const Point& p0, const Point& p1,
+                                          const Point& p2, const Point& p3)
+{ return CGAL::volume(p0, p1, p2, p3); }
+
+template<typename Point>
+typename Point::FT volume_of_tetra(const Point& p0, const Point& p1,
+                                   const Point& p2, const Point& p3)
+{ return std::abs(signed_volume_of_tetra(p0, p1, p2, p3)); }
+
+/*       4
+ *      /|\
+ *     0-|-3
+ *     | | |
+ *     1---2
+ */
+template<typename Point>
+typename Point::FT signed_volume_of_pyramid(const Point& p0, const Point& p1,
+                                            const Point& p2, const Point& p3,
+                                            const Point& p4)
+{ return signed_volume_of_tetra(p0, p1, p2, p4)+
+      signed_volume_of_tetra(p0, p2, p3, p4); }
+
+template<typename Point>
+typename Point::FT volume_of_pyramid(const Point& p0, const Point& p1,
+                                     const Point& p2, const Point& p3,
+                                     const Point& p4)
+{ return std::abs(signed_volume_of_pyramid(p0, p1, p2, p3, p4)); }
+
+/*      3
+ *     /|\
+ *    4---5
+ *    | | |
+ *    | 0 |
+ *    |/ \|
+ *    1---2
+ */
+template<typename Point>
+typename Point::FT signed_volume_of_prism(const Point& p0, const Point& p1,
+                                          const Point& p2, const Point& p3,
+                                          const Point& p4, const Point& p5)
+{
+  return signed_volume_of_tetra(p0, p1, p2, p5) +
+      signed_volume_of_tetra(p1, p0, p3, p5) +
+      signed_volume_of_tetra(p4, p3, p5, p1); }
+
+template<typename Point>
+typename Point::FT volume_of_prism(const Point& p0, const Point& p1,
+                                   const Point& p2, const Point& p3,
+                                   const Point& p4, const Point& p5)
+{ return std::abs(signed_volume_of_prism(p0, p1, p2, p3, p4, p5)); }
+
+/*      7----6
+ *     /|   /|
+ *    4----5 |
+ *    | 3--|-2
+ *    |/   |/
+ *    0----1
+*/
+template<typename Point>
+typename Point::FT signed_volume_of_hexa(const Point& p0, const Point& p1,
+                                  const Point& p2, const Point& p3,
+                                  const Point& p4, const Point& p5,
+                                  const Point& p6, const Point& p7)
+{
+  return signed_volume_of_tetra(p0, p1, p3, p4) +
+    signed_volume_of_tetra(p3, p1, p2, p6) +
+    signed_volume_of_tetra(p6, p5, p4, p1) +
+    signed_volume_of_tetra(p6, p4, p7, p3) +
+    signed_volume_of_tetra(p1, p3, p4, p6);
+}
+
+template<typename Point>
+typename Point::FT volume_of_hexa(const Point& p0, const Point& p1,
+                                  const Point& p2, const Point& p3,
+                                  const Point& p4, const Point& p5,
+                                  const Point& p6, const Point& p7)
+{ return std::abs(signed_volume_of_hexa(p0, p1, p2, p3, p4, p5, p6, p7)); }
+
+template<typename LCC>
+typename LCC::FT signed_volume_of_generic_cell(LCC& lcc,
+                                               typename LCC::Dart_handle dh)
+{
+  typename LCC::FT vol=0;
+  typename LCC::Point *p0, *p1, *p2;
+  typename LCC::Point p3;
+  typename LCC::Point p4=CGAL::ORIGIN; // Used instead barycenter of volume; it is supposed to work whatever the position of this point
+  typename LCC::Dart_handle dh2;
+
+  // Iterate through one dart per face of the volume containing dh.
+  for (auto it=lcc.template one_dart_per_incident_cell<2,3,2>(dh).begin(),
+       itend=lcc.template one_dart_per_incident_cell<2,3,2>(dh).end();
+       it!=itend; ++it)
+  {
+    dh2=lcc.template beta<1,1,1>(it);
+    if (dh2==it)
+    { // Triangle
+      p0=&(lcc.point(it));
+      p1=&(lcc.point(lcc.template beta<1>(it)));
+      p2=&(lcc.point(lcc.template beta<0>(it)));
+      vol+=signed_volume_of_tetra(*p0, *p1, *p2, p4);
+    }
+    else if  (lcc.template beta<1>(dh2)==it)
+    { // Square
+      p0=&(lcc.point(it));
+      p1=&(lcc.point(lcc.template beta<1>(it)));
+      p2=&(lcc.point(lcc.template beta<1,1>(it)));
+      vol+=signed_volume_of_tetra(*p0, *p1, *p2, p4);
+
+      p1=p2;
+      p2=&(lcc.point(lcc.template beta<0>(it)));
+      vol+=signed_volume_of_tetra(*p0, *p1, *p2, p4);
+    }
+    else
+    { // Generic face (>4 edges)
+      p3=lcc.template barycenter<2>(it);
+      typename LCC::Dart_handle cur=it;
+      p0=&(lcc.point(cur));
+      do
+      {
+        cur=lcc.next(cur);
+        p1=&(lcc.point(cur));
+        vol+=signed_volume_of_tetra(*p0, *p1, p3, p4);
+        p0=p1;
+      }
+      while(cur!=it);
+    }
+  }
+  return vol;
+}
+
+template<typename LCC>
+typename LCC::FT volume_of_generic_cell(LCC& lcc,
+                                        typename LCC::Dart_handle dh)
+{ return std::abs(signed_volume_of_generic_cell(lcc, dh)); }
+
+/// @return the volume of the cell
+template<typename LCC>
+typename LCC::FT signed_volume(LCC& lcc, typename LCC::Dart_handle dh)
+{
+  typename LCC::Dart_handle sd,d2;
+  cell_topo celltopo = Get_cell_topo<LCC, 3>::run(lcc, dh, sd);
+
+  switch(celltopo)
+  {
+    case TETRAHEDRON:
+      return signed_volume_of_tetra(lcc.point(sd),
+                                    lcc.point(lcc.template beta<1>(sd)),
+                                    lcc.point(lcc.template beta<0>(sd)),
+                                    lcc.point(lcc.template beta<2, 0>(sd)));
+    case HEXAHEDRON:
+      d2=lcc.template beta<2, 1, 1, 2, 1>(sd);
+      return signed_volume_of_hexa(lcc.point(sd),
+                                   lcc.point(lcc.template beta<1>(sd)),
+                                   lcc.point(lcc.template beta<1,1>(sd)),
+                                   lcc.point(lcc.template beta<0>(sd)),
+                                   lcc.point(d2),
+                                   lcc.point(lcc.template beta<0>(d2)),
+                                   lcc.point(lcc.template beta<0,0>(d2)),
+                                   lcc.point(lcc.template beta<1>(d2)));
+    case PRISM:
+      d2=lcc.template beta<2, 1, 1, 2>(sd);
+      return signed_volume_of_prism(lcc.point(sd),
+                                    lcc.point(lcc.template beta<1>(sd)),
+                                    lcc.point(lcc.template beta<0>(sd)),
+                                    lcc.point(lcc.template beta<1>(d2)),
+                                    lcc.point(d2),
+                                    lcc.point(lcc.template beta<0>(d2)));
+    case PYRAMID:
+      return signed_volume_of_pyramid(lcc.point(sd),
+                                      lcc.point(lcc.template beta<1>(sd)),
+                                      lcc.point(lcc.template beta<1,1>(sd)),
+                                      lcc.point(lcc.template beta<0>(sd)),
+                                      lcc.point(lcc.template beta<2,0>(sd)));
+    case GENERIC_3D:
+      return signed_volume_of_generic_cell(lcc, dh);
+    default:
+      std::cerr<<"Error in signed_volume"<<std::endl;
+  }
+  return 0;
+}
+
+template<typename LCC>
+typename LCC::FT volume(LCC& lcc, typename LCC::Dart_handle dh)
+{ return std::abs(signed_volume(lcc, dh)); }
+
+#endif // VOLUME_COMPUTATION_H
diff --git a/src/cmap_3close_cc.h b/src/cmap_3close_cc.h
new file mode 100644
index 0000000000000000000000000000000000000000..64a79689650b68e90c0cd238834e6907edc3e357
--- /dev/null
+++ b/src/cmap_3close_cc.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+
+#ifndef CMAP_3CLOSE_CC_H
+#define CMAP_3CLOSE_CC_H
+
+#include <cstddef>
+
+/** 3-close a connected component
+ *  @param dh a dart
+ *  @return the number of new darts.
+ */
+template<typename LCC>
+std::size_t close_cc_for_beta3(LCC& lcc, typename LCC::Dart_handle dh)
+{
+  std::size_t res=0;
+  typename LCC::Dart_handle d, d2;
+
+  for (auto it=lcc.template darts_of_cell<3>(dh).begin(),
+       itend=lcc.template darts_of_cell<3>(dh).end(); it!=itend; ++it)
+  {
+    if(lcc.template is_free<3>(it))
+    {
+      d=lcc.create_dart();
+      ++res;
+      lcc.template link_beta_for_involution<3>(it, d);
+
+      // Special cases for 0 and 1
+      if (!lcc.template is_free<1>(it) &&
+          !lcc.template is_free<3>(lcc.template beta<1>(it)))
+      { lcc.template link_beta<1>(lcc.template beta<1,3>(it),d); }
+      if (!lcc.template is_free<0>(it) &&
+          !lcc.template is_free<3>(lcc.template beta<0>(it)))
+      { lcc.template link_beta<0>(lcc.template beta<0,3>(it),d); }
+
+      d2=lcc.template beta<2>(it);
+      while (d2!=lcc.null_dart_handle &&
+             !lcc.template is_free<2>(lcc.template beta<3>(d2)))
+      { d2=lcc.template beta<3, 2>(d2); }
+      if (d2!=lcc.null_dart_handle && !lcc.template is_free<3>(d2))
+      {
+        lcc.template basic_link_beta_for_involution<2>
+            (lcc.template beta<3>(d2), d);
+      }
+    }
+  }
+  return res;
+}
+
+#endif // CMAP_3CLOSE_CC_H
diff --git a/src/cmap_copy.h b/src/cmap_copy.h
new file mode 100644
index 0000000000000000000000000000000000000000..26f62ec88368ad4741251d859020739703fcbc6c
--- /dev/null
+++ b/src/cmap_copy.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+
+#ifndef CMAP_COPY_H
+#define CMAP_COPY_H
+
+#include <unordered_map>
+#include <CGAL/Combinatorial_map/internal/Combinatorial_map_copy_functors.h>
+
+/** Copy volume(dh) from lcc1 to lcc2.
+ *  @return the number of new darts.
+ */
+template<unsigned int dim, typename CMap1, typename CMap2,
+         typename Converters, typename DartInfoConverter, typename PointConverter>
+std::size_t copy_cell(CMap1& amap1, typename CMap1::Dart_handle dh,
+                      CMap2& amap2,
+                      std::unordered_map
+                      <typename CMap1::Dart_handle, typename CMap2::Dart_handle>*
+                      origin_to_copy,
+                      std::unordered_map
+                      <typename CMap1::Dart_handle, typename CMap2::Dart_handle>*
+                      copy_to_origin,
+                      const Converters& converters,
+                      const DartInfoConverter& dartinfoconverter,
+                      const PointConverter& pointconverter,
+                      bool copy_perforated_darts=false,
+                      typename CMap1::size_type mark_perforated=CMap1::INVALID_MARK)
+{
+  std::size_t res=0;
+
+  std::unordered_map<typename CMap1::Dart_handle, typename CMap2::Dart_handle> local_dartmap;
+  if (origin_to_copy==nullptr) // Use local_dartmap if user does not provides its own unordered_map
+  { origin_to_copy=&local_dartmap; }
+
+  typename CMap2::Dart_handle new_dart;
+  for(auto it=amap1.template darts_of_cell<dim>(dh).begin(),
+      itend=amap1.template darts_of_cell<dim>(dh).end(); it!=itend; ++it)
+  {
+    if (copy_perforated_darts || !amap1.is_perforated(it))
+    {
+      new_dart=amap2.create_dart(); // , amap.get_marks(it));
+
+      if (mark_perforated!=CMap1::INVALID_MARK && amap1.is_perforated(it))
+      { amap2.mark(new_dart, mark_perforated); }
+
+      (*origin_to_copy)[it]=new_dart;
+      if(copy_to_origin!=nullptr) { (*copy_to_origin)[new_dart]=it; }
+
+      CGAL::internal::Copy_dart_info_functor
+        <typename CMap1::Refs, typename CMap2::Refs, DartInfoConverter>::run
+        (static_cast<const typename CMap1::Refs&>(amap1),
+         static_cast<typename CMap2::Refs&>(amap2),
+         it, new_dart, dartinfoconverter);
+    }
+  }
+
+  unsigned int min_dim=std::min(amap1.dimension, amap2.dimension);
+
+  typename std::unordered_map<typename CMap1::Dart_handle,
+      typename CMap2::Dart_handle>::iterator
+    dartmap_iter, dartmap_iter_end=origin_to_copy->end();
+  for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end;
+       ++dartmap_iter)
+  {
+    for (unsigned int i=0; i<=min_dim; i++)
+    {
+      if (i!=dim &&
+          !amap1.is_free(dartmap_iter->first,i) &&
+          amap2.is_free(dartmap_iter->second,i))
+      {
+        amap2.basic_link_beta(dartmap_iter->second,
+                              (*origin_to_copy)[amap1.beta(dartmap_iter->first,i)], i);
+      }
+    }
+  }
+
+  /** Copy attributes */
+  for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end;
+       ++dartmap_iter)
+  {
+    CMap2::Helper::template Foreach_enabled_attributes
+      <CGAL::internal::Copy_attributes_functor<typename CMap1::Refs,
+        typename CMap2::Refs, Converters, PointConverter>>::
+      run(static_cast<const typename CMap1::Refs&>(amap1),
+          static_cast<typename CMap2::Refs&>(amap2),
+          dartmap_iter->first, dartmap_iter->second, converters, pointconverter);
+  }
+
+  CGAL_assertion (amap2.is_valid());
+
+  return res;
+}
+
+template<unsigned int dim, typename CMap1, typename CMap2>
+std::size_t copy_cell(CMap1& amap1, typename CMap1::Dart_handle dh,
+                      CMap2& amap2,
+                      std::unordered_map
+                      <typename CMap1::Dart_handle, typename CMap2::Dart_handle>*
+                      origin_to_copy=nullptr,
+                      std::unordered_map
+                      <typename CMap1::Dart_handle, typename CMap2::Dart_handle>*
+                      copy_to_origin=nullptr,
+                      bool copy_perforated_darts=false,
+                      typename CMap1::size_type mark_perforated=CMap1::INVALID_MARK)
+{
+  std::tuple<> converters;
+  CGAL::Default_converter_dart_info<typename CMap1::Refs,
+      typename CMap2::Refs> dartinfoconverter;
+  CGAL::Default_converter_cmap_0attributes_with_point<typename CMap1::Refs,
+       typename CMap2::Refs> pointconverter;
+  return copy_cell<dim>(amap1, dh, amap2, origin_to_copy, copy_to_origin,
+                        converters, dartinfoconverter, pointconverter,
+                        copy_perforated_darts, mark_perforated);
+}
+
+#endif // CMAP_COPY_H
diff --git a/src/cmap_isomorphisms.h b/src/cmap_isomorphisms.h
new file mode 100644
index 0000000000000000000000000000000000000000..163ed29fa54dd4ac9e96e9e36ec95f3724ad5e2f
--- /dev/null
+++ b/src/cmap_isomorphisms.h
@@ -0,0 +1,435 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+
+#ifndef CMAP_ISOMORPHISMS_H
+#define CMAP_ISOMORPHISMS_H
+
+#include <CGAL/Handle_hash_function.h>
+#include <CGAL/Unique_hash_map.h>
+#include <CGAL/Combinatorial_map/internal/Combinatorial_map_internal_functors.h>
+
+#include <queue>
+#include <functional>
+
+/// @pre both faces are a cycle of darts (no 1-boundary).
+template<typename LCC1, typename LCC2>
+bool are_faces_isomorphic_from_darts(LCC1& lcc1, typename LCC1::Dart_handle sd1,
+                                     LCC2& lcc2, typename LCC2::Dart_handle sd2,
+                                     typename LCC1::size_type marktopreserve1,
+                                     typename LCC2::size_type marktopreserve2,
+                                     std::function<typename LCC1::Dart_handle
+                                     (typename LCC1::Dart_handle)> next1,
+                                     std::function<typename LCC2::Dart_handle
+                                     (typename LCC2::Dart_handle)> next2,
+                                     bool testDartInfo=true,
+                                     bool testAttributes=true,
+                                     bool testPoint=true)
+{
+  if(marktopreserve1!=LCC1::INVALID_MARK &&
+     marktopreserve2!=LCC2::INVALID_MARK &&
+     lcc1.is_marked(sd1, marktopreserve1)!=lcc2.is_marked(sd2, marktopreserve2))
+  { return false; }
+
+  bool match=true;
+  typename LCC1::Dart_handle dh1=sd1;
+  typename LCC2::Dart_handle dh2=sd2;
+  do
+  {
+    if(marktopreserve1!=LCC1::INVALID_MARK &&
+       marktopreserve2!=LCC2::INVALID_MARK &&
+       lcc1.is_marked(dh1, marktopreserve1)!=lcc2.is_marked(dh2, marktopreserve2))
+    { match=false; }
+
+    // We first test info of darts
+    if(match && testDartInfo)
+    { match=CGAL::internal::template Test_is_same_dart_info_functor<LCC1, LCC2>::
+          run(lcc1, lcc2, dh1, dh2); }
+
+    // We need to test in both direction because
+    // Foreach_enabled_attributes only test non void attributes
+    // of Self. Functor Test_is_same_attribute_functor will modify
+    // the value of match to false if attributes do not match
+    if(testAttributes)
+    {
+      if (match)
+      { LCC1::Helper::template Foreach_enabled_attributes
+            <CGAL::internal::template Test_is_same_attribute_functor
+            <LCC1, LCC2>>::run(lcc1, lcc2, dh1, dh2, match); }
+      if (match)
+      { LCC2::Helper::template Foreach_enabled_attributes
+            <CGAL::internal::template Test_is_same_attribute_functor
+            <LCC2, LCC1>>::run(lcc2, lcc1, dh2, dh1, match); }
+    }
+
+    if(match && testPoint)
+    {
+      // Only point of 0-attributes are tested. TODO test point of all
+      // attributes ?
+      match=CGAL::internal::template Test_is_same_attribute_point_functor
+            <LCC1, LCC2, 0>::run(lcc1, lcc2, dh1, dh2);
+    }
+
+    if(match)
+    {
+      dh1=next1(dh1);
+      dh2=next2(dh2);
+      assert(dh1!=lcc1.null_dart_handle);
+      assert(dh2!=lcc2.null_dart_handle);
+    }
+  }
+  while(match && dh1!=sd1 && dh2!=sd2);
+  if(dh1!=sd1 || dh2!=sd2) { match=false; }
+
+  return match;
+}
+
+/// Test if face(sd) is isomorphic with the border of the fpattern
+/// @pre both faces are a cycle of darts (no 1-boundary).
+/// @return the dart of vpattern satisfying the bijection, nullprt if there is
+/// no isomorphism.
+template<typename LCC1, typename LCC2>
+typename LCC2::Dart_handle is_face_isomorphic_to_fpattern
+(LCC1& lcc, typename LCC1::Dart_handle sd,
+ LCC2& fpattern,
+ typename LCC1::size_type marktopreserve1=LCC1::INVALID_MARK,
+ typename LCC2::size_type marktopreserve2=LCC2::INVALID_MARK,
+ bool testDartInfo=true,
+ bool testAttributes=true,
+ bool testPoint=true)
+{
+  typename LCC2::Dart_handle res=nullptr;
+  for(auto it=fpattern.darts().begin(), itend=fpattern.darts().end();
+      res==nullptr && it!=itend; ++it)
+  {
+    if(fpattern.template is_free<2>(it))
+    {
+      if(are_faces_isomorphic_from_darts(lcc, sd, fpattern, it,
+                                         marktopreserve1, marktopreserve2,
+
+                                         [&lcc](typename LCC1::Dart_handle dh)
+                                         -> typename LCC1::Dart_handle
+                                         { return lcc.template beta<1>(dh); },
+
+                                         [&fpattern](typename LCC2::Dart_handle dh)
+                                         -> typename LCC2::Dart_handle
+                                         { typename LCC2::Dart_handle other=
+                                         fpattern.template beta<1>(dh);
+                                         while(!fpattern.template is_free<2>(other))
+                                         { other=fpattern.template beta<2,1>(other); }
+                                         return other;
+                                         },
+                                         testDartInfo,
+                                         testAttributes,
+                                         testPoint))
+      { res=it; }
+    }
+  }
+  return res;
+}
+
+template<typename LCC1, typename LCC2>
+bool are_volumes_isomorphic_from_darts(LCC1& lcc1, typename LCC1::Dart_handle sd1,
+                                       LCC2& lcc2, typename LCC2::Dart_handle sd2,
+                                       typename LCC1::size_type marktopreserve1,
+                                       typename LCC2::size_type marktopreserve2,
+                                       std::function<typename LCC1::Dart_handle
+                                       (typename LCC1::Dart_handle)> next1,
+                                       std::function<typename LCC1::Dart_handle
+                                       (typename LCC1::Dart_handle)> opposite1,
+                                       std::function<typename LCC2::Dart_handle
+                                       (typename LCC2::Dart_handle)> next2,
+                                       std::function<typename LCC2::Dart_handle
+                                       (typename LCC2::Dart_handle)> opposite2,
+                                       bool testDartInfo=true,
+                                       bool testAttributes=true,
+                                       bool testPoint=true)
+{
+  if(marktopreserve1!=LCC1::INVALID_MARK &&
+     marktopreserve2!=LCC2::INVALID_MARK &&
+     lcc1.is_marked(sd1, marktopreserve1)!=lcc2.is_marked(sd2, marktopreserve2))
+  { return false; }
+
+  bool match = true;
+
+  // Two stacks used to run through the two maps.
+  std::deque<typename LCC1::Dart_handle> toTreat1;
+  std::deque<typename LCC2::Dart_handle> toTreat2;
+
+   // A dart of this map is marked with m1 if its bijection was set
+  // (and similarly for mark m2 and darts of map2)
+  typename LCC1::size_type m1=lcc1.get_new_mark();
+  typename LCC2::size_type m2=lcc2.get_new_mark();
+
+  // A dart of this map is marked with markpush if it was already pushed
+  // in the queue toTreat1.
+  typename LCC1::size_type markpush=lcc1.get_new_mark();
+
+  toTreat1.push_back(sd1);
+  toTreat2.push_back(sd2);
+  lcc1.mark(sd1, markpush);
+
+  typename LCC1::Dart_handle dh1, other1;
+  typename LCC2::Dart_handle dh2, other2;
+
+  CGAL::Unique_hash_map<typename LCC1::Dart_handle,
+                        typename LCC2::Dart_handle,
+                        typename CGAL::Handle_hash_function> bijection;
+
+  while (match && !toTreat1.empty())
+  {
+    // Next dart
+    dh1=toTreat1.front();
+    toTreat1.pop_front();
+    dh2=toTreat2.front();
+    toTreat2.pop_front();
+
+    if(lcc1.is_marked(dh1, m1)!=lcc2.is_marked(dh2, m2))
+    { match=false; }
+    else if(!lcc1.is_marked(dh1, m1))
+    {
+      bijection[dh1]=dh2;
+      lcc1.mark(dh1, m1);
+      lcc2.mark(dh2, m2);
+
+      // We first test info of darts
+      if(match && testDartInfo)
+      { match=CGAL::internal::template Test_is_same_dart_info_functor<LCC1, LCC2>::
+            run(lcc1, lcc2, dh1, dh2); }
+
+      // We need to test in both direction because
+      // Foreach_enabled_attributes only test non void attributes
+      // of Self. Functor Test_is_same_attribute_functor will modify
+      // the value of match to false if attributes do not match
+      if(testAttributes)
+      {
+        if (match)
+        { LCC1::Helper::template Foreach_enabled_attributes
+              <CGAL::internal::template Test_is_same_attribute_functor
+              <LCC1, LCC2>>::run(lcc1, lcc2, dh1, dh2, match); }
+        if (match)
+        { LCC2::Helper::template Foreach_enabled_attributes
+              <CGAL::internal::template Test_is_same_attribute_functor
+              <LCC2, LCC1>>::run(lcc2, lcc1, dh2, dh1, match); }
+      }
+
+      if(match && testPoint)
+      {
+        // Only point of 0-attributes are tested. TODO test point of all
+        // attributes ?
+        match=CGAL::internal::template Test_is_same_attribute_point_functor
+              <LCC1, LCC2, 0>::run(lcc1, lcc2, dh1, dh2);
+      }
+
+      if(match &&
+         marktopreserve1!=LCC1::INVALID_MARK &&
+         marktopreserve2!=LCC2::INVALID_MARK &&
+         lcc1.is_marked(dh1, marktopreserve1)!=
+         lcc2.is_marked(dh2, marktopreserve2))
+      { match=false; }
+
+      // We test if the injection is valid with its neighboors.
+      // We go out as soon as it is not satisfied.
+      // Process next then opposite
+      other1=next1(dh1); other2=next2(dh2);
+      for(int i:{0,1})
+      {
+        if(other1==lcc1.null_dart_handle && other2!=lcc2.null_dart_handle)
+        { match=false; }
+        else if(other1!=lcc1.null_dart_handle && other2==lcc2.null_dart_handle)
+        { match=false; }
+        else if(other1!=lcc1.null_dart_handle && other2!=lcc2.null_dart_handle)
+        {
+          if(lcc1.is_marked(other1, m1)!=lcc2.is_marked(other2, m2))
+          { match=false; }
+          else
+          {
+            if(!lcc1.is_marked(other1, m1))
+            {
+              if (!lcc1.is_marked(other1, markpush))
+              {
+                toTreat1.push_back(other1);
+                toTreat2.push_back(other2);
+                lcc1.mark(other1, markpush);
+              }
+            }
+            else
+            {
+              if (bijection[other1]!=other2)
+              { match=false; }
+            }
+          }
+        }
+        if(i==0) { other1=opposite1(dh1); other2=opposite2(dh2); }
+      }
+    }
+  }
+
+  // Here we test if both queue are empty
+  if(!toTreat1.empty() || !toTreat2.empty())
+  { match=false; }
+
+  // Here we unmark all the marked darts.
+  toTreat1.clear();
+  toTreat2.clear();
+
+  toTreat1.push_back(sd1);
+  toTreat2.push_back(sd2);
+  lcc1.unmark(sd1, markpush);
+
+  while (!toTreat1.empty())
+  {
+    dh1=toTreat1.front();
+    toTreat1.pop_front();
+    dh2=toTreat2.front();
+    toTreat2.pop_front();
+
+    lcc1.unmark(dh1, m1);
+    lcc2.unmark(dh2, m2);
+
+    other1=next1(dh1); other2=next2(dh2);
+    for(int i:{0,1})
+    {
+      if(other1!=lcc1.null_dart_handle && other2!=lcc2.null_dart_handle)
+      {
+        if (lcc1.is_marked(other1, markpush))
+        {
+          toTreat1.push_back(other1);
+          toTreat2.push_back(other2);
+          lcc1.unmark(other1, markpush);
+        }
+      }
+      if(i==0) { other1=opposite1(dh1); other2=opposite2(dh2); }
+    }
+  }
+
+  assert(lcc1.is_whole_map_unmarked(m1));
+  assert(lcc1.is_whole_map_unmarked(markpush));
+  assert(lcc2.is_whole_map_unmarked(m2));
+  lcc1.free_mark(m1);
+  lcc1.free_mark(markpush);
+  lcc2.free_mark(m2);
+
+  return match;
+}
+
+/// Test if surface(sd) is isomorphic with the border of the spattern
+/// @return the dart of spattern satisfying the bijection, nullprt if there is
+/// no isomorphism.
+template<typename LCC1, typename LCC2>
+typename LCC2::Dart_handle is_surface_isomorphic_to_spattern
+(LCC1& lcc, typename LCC1::Dart_handle sd,
+ LCC2& spattern,
+ typename LCC2::size_type faceborder,
+ typename LCC1::size_type marktopreserve1=LCC1::INVALID_MARK,
+ typename LCC2::size_type marktopreserve2=LCC2::INVALID_MARK,
+ bool testDartInfo=true,
+ bool testAttributes=true,
+ bool testPoint=true)
+{
+  typename LCC2::Dart_handle res=nullptr;
+  for(auto it=spattern.darts().begin(), itend=spattern.darts().end();
+      res==nullptr && it!=itend; ++it)
+  {
+    if(spattern.is_marked(it, faceborder))
+    {
+      if(are_volumes_isomorphic_from_darts(lcc, sd, spattern, it,
+                                           marktopreserve1, marktopreserve2,
+
+                                           [&lcc](typename LCC1::Dart_handle dh)
+                                           -> typename LCC1::Dart_handle
+                                           { return lcc.template beta<1>(dh); },
+                                           [&lcc](typename LCC1::Dart_handle dh)
+                                           -> typename LCC1::Dart_handle
+                                           { return lcc.template beta<2>(dh); },
+
+                                           [&spattern, faceborder](typename LCC2::Dart_handle dh)
+                                           -> typename LCC2::Dart_handle
+                                           { typename LCC2::Dart_handle other=
+                                           spattern.template beta<1>(dh);
+                                           while(!spattern.is_marked(other, faceborder))
+                                           { other=spattern.template beta<2,1>(other); }
+                                           return other;
+                                           },
+
+                                           [&spattern](typename LCC2::Dart_handle dh)
+                                           -> typename LCC2::Dart_handle
+                                            { return spattern.template beta<2>(dh); },
+
+                                           testDartInfo,
+                                           testAttributes,
+                                           testPoint))
+      { res=it; }
+    }
+  }
+  return res;
+}
+
+/// Test if volume(sd) is isomorphic with the border of the vpattern
+/// @return the dart of vpattern satisfying the bijection, nullprt if there is
+/// no isomorphism.
+template<typename LCC1, typename LCC2>
+typename LCC2::Dart_handle is_volume_isomorphic_to_vpattern
+(LCC1& lcc, typename LCC1::Dart_handle sd,
+ LCC2& vpattern,
+ typename LCC1::size_type marktopreserve1=LCC1::INVALID_MARK,
+ typename LCC2::size_type marktopreserve2=LCC2::INVALID_MARK,
+ bool testDartInfo=true,
+ bool testAttributes=true,
+ bool testPoint=true)
+{
+  typename LCC2::Dart_handle res=nullptr;
+  for(auto it=vpattern.darts().begin(), itend=vpattern.darts().end();
+      res==nullptr && it!=itend; ++it)
+  {
+    if(vpattern.template is_free<3>(it))
+    {
+      if(are_volumes_isomorphic_from_darts(lcc, sd, vpattern, it,
+                                           marktopreserve1, marktopreserve2,
+
+                                           [&lcc](typename LCC1::Dart_handle dh)
+                                           -> typename LCC1::Dart_handle
+                                           { return lcc.template beta<1>(dh); },
+                                           [&lcc](typename LCC1::Dart_handle dh)
+                                           -> typename LCC1::Dart_handle
+                                           { return lcc.template beta<2>(dh); },
+
+                                           [&vpattern](typename LCC2::Dart_handle dh)
+                                           -> typename LCC2::Dart_handle
+                                           { return vpattern.template beta<1>(dh); },
+                                           [&vpattern](typename LCC2::Dart_handle dh)
+                                           -> typename LCC2::Dart_handle
+                                           { typename LCC2::Dart_handle other=
+                                           vpattern.template beta<2>(dh);
+                                           while(!vpattern.template is_free<3>(other))
+                                           { other=vpattern.template beta<3,2>(other); }
+                                           return other;
+                                           },
+
+                                         testDartInfo,
+                                         testAttributes,
+                                         testPoint))
+      { res=it; }
+    }
+  }
+  return res;
+}
+
+#endif // CMAP_ISOMORPHISMS_H
diff --git a/src/cmap_query_replace.h b/src/cmap_query_replace.h
new file mode 100644
index 0000000000000000000000000000000000000000..25674a3f9b8ba688de1509ecd03ee26d7f050f6c
--- /dev/null
+++ b/src/cmap_query_replace.h
@@ -0,0 +1,1025 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CMAP_QUERY_REPLACE_H
+#define CMAP_QUERY_REPLACE_H
+
+#include <filesystem>
+#include <limits>
+#include <queue>
+#include <sstream>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "cmap_copy.h" // TEMPO TO REMOVE
+#include <CGAL/draw_linear_cell_complex.h> // TEMPO TO REMOVE
+#include "cmap_3close_cc.h"
+#include "cmap_copy.h"
+#include "cmap_query_replace_geometry.h"
+#include "cmap_isomorphisms.h"
+#include "cmap_signature.h"
+#include "lcc_read_depending_extension.h"
+
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+class Pattern_substituer
+{
+public:
+  using Dart_handle=typename LCC::Dart_handle;
+  using size_type=typename LCC::size_type;
+
+  using Signature_mapping=std::unordered_map<Signature,
+  std::pair<Dart_handle, std::size_t>>;
+
+  template<unsigned int type> // type==1 for face, 2 for surface and 3 for volume
+  using Pattern_set=std::vector<Pattern<LCC, type>>;
+
+  std::size_t number_of_fpatterns() const
+  { return m_fpatterns.size(); }
+  std::size_t number_of_spatterns() const
+  { return m_spatterns.size(); }
+  std::size_t number_of_vpatterns() const
+  { return m_vpatterns.size(); }
+
+  LCC& fpattern(std::size_t i) 
+  { return m_fpatterns[i].lcc(); }
+  LCC& spattern(std::size_t i) 
+  { return m_spatterns[i].lcc(); }
+  LCC& vpattern(std::size_t i) 
+  { return m_vpatterns[i].lcc(); }
+
+   Signature_mapping& fsignatures() 
+  { return m_fsignatures; }
+   Signature_mapping& ssignatures() 
+  { return m_ssignatures; }
+   Signature_mapping& vsignatures() 
+  { return m_vsignatures; }
+
+  typename Signature_mapping::const_iterator find_fpattern(const Signature& s) const
+  { return m_fsignatures.find(s); }
+  typename Signature_mapping::const_iterator find_spattern(const Signature& s) const
+  { return m_ssignatures.find(s); }
+  typename Signature_mapping::const_iterator find_vpattern(const Signature& s) const
+  { return m_vsignatures.find(s); }
+
+  typename Signature_mapping::const_iterator fpattern_end() const
+  { return m_fsignatures.end(); }
+  typename Signature_mapping::const_iterator spattern_end() const
+  { return m_ssignatures.end(); }
+  typename Signature_mapping::const_iterator vpattern_end() const
+  { return m_vsignatures.end(); }
+
+  void load_fpatterns(const std::string& directory_name,
+                      std::function<void(LCC&, size_type)> init_topreserve=nullptr)
+  {
+    load_all_patterns<1>(directory_name, m_fpatterns);
+    Signature signature;
+    Dart_handle dh;
+    size_type mark_to_preserve=LCC::INVALID_MARK;
+    std::size_t nb=0;
+    m_fsignatures.clear();
+    for(auto& pattern: m_fpatterns)
+    {
+      if(init_topreserve!=nullptr) // true iff the std::function is not empty
+      {
+        mark_to_preserve=pattern.reserve_mark_to_preserve();
+        init_topreserve(pattern.lcc(), mark_to_preserve);
+      }
+      dh=fsignature_of_pattern(pattern.lcc(), mark_to_preserve, signature, false);
+      auto res=m_fsignatures.find(signature);
+      if(res==m_fsignatures.end())
+      {
+        pattern.compute_barycentric_coord();
+        m_fsignatures[signature]=std::make_pair(dh, nb);
+      }
+      else
+      {
+        std::cout<<"[ERROR] load_fpatterns: two patterns have same signature "
+                 <<nb<<" and "<<res->second.second<<std::endl;
+      }
+      ++nb;
+      // std::cout<<"[Pattern] Signature "<<nb<<": "; print_signature(signature);
+    }
+  }
+  void load_spatterns(const std::string& directory_name,
+                      std::function<void(LCC&, size_type)> init_faceborder,
+                      std::function<void(LCC&, size_type)> init_topreserve=nullptr)
+  {
+    load_all_patterns<2>(directory_name, m_spatterns);
+    Signature signature;
+    Dart_handle dh;
+    size_type mark_to_preserve=LCC::INVALID_MARK;
+    std::size_t nb=0;
+    m_ssignatures.clear();
+    for(auto& pattern: m_spatterns)
+    {
+      init_faceborder(pattern.lcc(), pattern.m_mark_faceborder);
+      if(init_topreserve!=nullptr) // true iff the std::function is not empty
+      {
+        mark_to_preserve=pattern.reserve_mark_to_preserve();
+        init_topreserve(pattern.lcc(), mark_to_preserve);
+      }
+      dh=ssignature_of_pattern(pattern.lcc(), pattern.m_mark_faceborder,
+                               mark_to_preserve, signature, false);
+      auto res=m_ssignatures.find(signature);
+      if(res==m_ssignatures.end())
+      {
+        pattern.compute_barycentric_coord();
+        assert(pattern.lcc().is_marked(dh, pattern.m_mark_faceborder));
+        m_ssignatures[signature]=std::make_pair(dh, nb);
+      }
+      else
+      {
+        std::cout<<"[ERROR] load_spatterns: two patterns have same signature "
+                 <<nb<<" and "<<res->second.second<<std::endl;
+      }
+      ++nb;
+      // std::cout<<"[Pattern] Signature "<<nb<<": "; print_signature(signature);
+    }
+  }
+  void load_vpatterns(const std::string& directory_name,
+                      std::function<void(LCC&, size_type)> init_topreserve=nullptr)
+  {
+    load_all_patterns<3>(directory_name, m_vpatterns);
+    Signature signature;
+    Dart_handle dh;
+    size_type mark_to_preserve=LCC::INVALID_MARK;
+    std::size_t nb=0;
+    m_vsignatures.clear();
+    for(auto& pattern: m_vpatterns)
+    {
+      if(init_topreserve!=nullptr) // true iff the std::function is not empty
+      {
+        mark_to_preserve=pattern.reserve_mark_to_preserve();
+        init_topreserve(pattern.lcc(), mark_to_preserve);
+      }
+      dh=vsignature_of_pattern(pattern.lcc(), mark_to_preserve, signature, false);
+      auto res=m_vsignatures.find(signature);
+      if(res==m_vsignatures.end())
+      {
+        pattern.compute_barycentric_coord();
+        m_vsignatures[signature]=std::make_pair(dh, nb);
+      }
+      else
+      {
+        std::cout<<"[ERROR] load_vpatterns: two patterns have same signature "
+                 <<nb<<" and "<<res->second.second<<std::endl;
+      }
+      ++nb;
+      // std::cout<<"[Pattern] Signature "<<nb<<": "; print_signature(signature);
+    }
+  }
+
+protected:
+  template<unsigned int type>
+  void load_all_patterns(const std::string& directory_name,
+                         Pattern_set<type>& patterns)
+  {
+    patterns.clear();
+    std::size_t nb=0;
+    const std::filesystem::path dir(directory_name);
+    if(!std::filesystem::exists(dir) || !std::filesystem::is_directory(dir))
+    { return; }
+
+    for(auto const& dir_entry: std::filesystem::directory_iterator{dir})
+    {
+      if(dir_entry.is_regular_file() &&
+         is_lcc_readable_file(dir_entry.path().string()))
+      { ++nb; }
+    }
+
+    patterns.resize(nb);
+    nb=0;
+    // std::cout<<"##############################"<<std::endl;
+    for(auto const& dir_entry: std::filesystem::directory_iterator{dir})
+    {
+      if(dir_entry.is_regular_file() &&
+         is_lcc_readable_file(dir_entry.path().string()))
+      {
+        // std::cout<<"pattern "<<nb<<": "<<dir_entry.path().string()<<std::endl;
+        read_depending_extension(dir_entry.path().string(),
+                                 patterns[nb].lcc());
+        ++nb;
+      }
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  /// Compute the bijection between the external edges of the pattern and
+  /// the face isomorphic to this external boundary.
+  /// Mark the dart of the external faces of the pattern.
+  /// @input dh1 is a copy of a dart of the pattern into lcc
+  /// @input dh2 is a dart of the face into lcc
+  /// @pre the two elements must be isomorphic
+  void compute_face_bijection_from_pattern_to_dart(LCC& lcc,
+                                                   Dart_handle dh1,
+                                                   Dart_handle dh2,
+                                                   size_type markexternal,
+                                                   Dart_mapping<LCC>&
+                                                   pattern_to_face)
+  {
+    assert(lcc.template is_free<2>(dh1));
+    pattern_to_face.clear();
+    Dart_handle cur1=dh1;
+    Dart_handle cur2=dh2;
+    do
+    {
+      pattern_to_face[cur1]=cur2;
+      lcc.mark(cur1, markexternal);
+      cur1=lcc.template beta<1>(cur1);
+      while(!lcc.template is_free<2>(cur1))
+      { cur1=lcc.template beta<2,1>(cur1); }
+      cur2=lcc.template beta<1>(cur2);
+    }
+    while(cur1!=dh1);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  /// Compute the bijection between the edges of the pattern and
+  /// the faces isomorphic to these external boundaries.
+  /// 2-unsew all darts marked face border.
+  /// @input dh1 is a dart of the pattern (WARNING: and NOT a copy in LCC contrary to similar methods for face and volume)
+  /// @input dh2 is a dart of the face
+  /// @pre the two elements must be isomorphic
+  void compute_surface_bijection_from_pattern_to_dart(LCC& lcc,
+                                                      Pattern<LCC, 2>& pattern,
+                                                      Dart_handle dh1,
+                                                      Dart_handle dh2,
+                                                      Dart_mapping<LCC>&
+                                                      pattern_to_global,
+                                                      Dart_mapping<LCC>&
+                                                      pattern_to_surface)
+  {
+    assert(!pattern.lcc().template is_free<2>(dh1));
+    assert(pattern.lcc().is_marked(dh1, pattern.m_mark_faceborder));
+    std::queue<std::pair<Dart_handle, Dart_handle>> to_treat;
+    size_type treated=pattern.lcc().get_new_mark();
+    Dart_handle other1, other2;
+    pattern_to_surface.clear();
+    to_treat.push(std::make_pair(dh1, dh2));
+    pattern.lcc().mark(dh1, treated);
+    while(!to_treat.empty())
+    {
+      auto cur=to_treat.front();
+      to_treat.pop();
+      pattern_to_surface[pattern_to_global[cur.first]]=cur.second;
+
+      // Process beta1
+      other1=pattern.lcc().template beta<1>(cur.first);
+      while(!pattern.lcc().is_marked(other1, pattern.m_mark_faceborder))
+      { other1=pattern.lcc().template beta<2,1>(other1); }
+
+      other2=lcc.template beta<1>(cur.second);
+      assert(other1!=lcc.null_handle && other2!=lcc.null_handle);
+      if(!pattern.lcc().is_marked(other1, treated))
+      {
+        to_treat.push(std::make_pair(other1, other2));
+        pattern.lcc().mark(other1, treated);
+      }
+
+      // Process beta2
+      other1=pattern.lcc().template beta<2>(cur.first);
+      other2=lcc.template beta<2>(cur.second);
+      assert(other1!=lcc.null_handle && other2!=lcc.null_handle);
+      if(!pattern.lcc().is_marked(other1, treated))
+      {
+        to_treat.push(std::make_pair(other1, other2));
+        pattern.lcc().mark(other1, treated);
+      }
+    }
+
+    for(auto it=pattern.lcc().darts().begin(),
+        itend=pattern.lcc().darts().end(); it!=itend; ++it)
+    {
+      if(pattern.lcc().is_marked(it, pattern.m_mark_faceborder))
+      {
+        pattern.lcc().unmark(it, treated);
+        if(!lcc.template is_free<2>(pattern_to_global[it]))
+        { lcc.template unsew<2>(pattern_to_global[it]); }
+      }
+      assert(!pattern.lcc().is_marked(it, treated));
+    }
+    pattern.lcc().free_mark(treated);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  /// Compute the bijection between the external faces of the pattern and
+  /// the faces of the volume isomorphic to these external boundaries.
+  /// Mark the dart of the external boundary of the pattern.
+  /// @input dh1 is a copy of a dart of the pattern into lcc
+  /// @input dh2 is a dart of the volume into lcc
+  /// @pre the two elements must be isomorphic
+  void compute_volume_bijection_from_pattern_to_dart(LCC& lcc,
+                                                     Dart_handle dh1,
+                                                     Dart_handle dh2,
+                                                     size_type markexternal,
+                                                     Dart_mapping<LCC>&
+                                                     pattern_to_volume)
+  {
+    assert(lcc.template is_free<3>(dh1));
+    std::queue<std::pair<Dart_handle, Dart_handle>> to_treat;
+    Dart_handle other1, other2;
+    pattern_to_volume.clear();
+    to_treat.push(std::make_pair(dh1, dh2));
+    lcc.mark(dh1, markexternal);
+    while(!to_treat.empty())
+    {
+      auto cur=to_treat.front();
+      to_treat.pop();
+      assert(lcc.template is_free<3>(cur.first));
+      pattern_to_volume[cur.first]=cur.second;
+
+      // Process beta1
+      other1=lcc.template beta<1>(cur.first);
+      other2=lcc.template beta<1>(cur.second);
+      assert(other1!=lcc.null_handle && other2!=lcc.null_handle);
+      if(!lcc.is_marked(other1, markexternal))
+      {
+        to_treat.push(std::make_pair(other1, other2));
+        lcc.mark(other1, markexternal);
+      }
+
+      // Process beta2
+      other1=lcc.template beta<2>(cur.first);
+      while(!lcc.template is_free<3>(other1))
+      { other1=lcc.template beta<3,2>(other1); }
+      other2=lcc.template beta<2>(cur.second);
+      assert(other1!=lcc.null_handle && other2!=lcc.null_handle);
+      if(!lcc.is_marked(other1, markexternal))
+      {
+        to_treat.push(std::make_pair(other1, other2));
+        lcc.mark(other1, markexternal);
+      }
+    }
+  }
+
+public:
+
+////////////////////////////////////////////////////////////////////////////////
+/// Replace volume(dh1) by the vpattern, knowing that the surface of
+/// vpattern is isomorphic with volume(dh1) starting from the pair of darts
+/// (dh1, dh2).
+/// @pre the surface of vpattern is isomorphic with volume(dh1)
+void replace_one_volume_from_dart(LCC& lcc,
+                                  Dart_handle dh1,
+                                  Pattern<LCC, 3>& vpattern,
+                                  Dart_handle dh2)
+{
+  Dart_mapping<LCC> pattern_to_global;
+  Dart_mapping<LCC> links_from_pattern_to_volume;
+  auto amark=lcc.get_new_mark();
+  // 1) Copy pattern into lcc. New darts are not be marked
+  lcc.copy(vpattern.lcc(), &pattern_to_global);
+  // 2) Compute old_3sew to store 3-links of darts in volume(dh2)
+  assert(vpattern.lcc().darts().owns(dh2));
+  compute_volume_bijection_from_pattern_to_dart
+      (lcc, pattern_to_global[dh2], dh1, amark,
+      links_from_pattern_to_volume);
+  transform_geometry_of_vpattern(lcc, links_from_pattern_to_volume,
+                                 pattern_to_global, vpattern);
+
+  // 3) Remove all the external faces of the copy of the pattern, and 2-sew
+  //    the internal faces of the copy of the pattern with the boundary of
+  //    the volume.
+  std::vector<std::pair<Dart_handle, Dart_handle>> tosew;
+  Dart_handle otherdh;
+  tosew.reserve(links_from_pattern_to_volume.size());
+  for(auto curdh: links_from_pattern_to_volume)
+  {
+    otherdh=lcc.template beta<2>(curdh.first);
+    if(lcc.is_dart_used(otherdh) && !lcc.is_marked(otherdh, amark))
+    {
+      lcc.template topo_unsew<2>(curdh.first);
+      if(!lcc.template is_free<2>(curdh.second))
+      { lcc.template unsew<2>(curdh.second); }
+      tosew.push_back(std::make_pair(curdh.second, otherdh));
+    }
+  }
+  for(auto curdh: tosew)
+  { lcc.template sew<2>(curdh.first, curdh.second); }
+
+  for(auto curdh: links_from_pattern_to_volume)
+  { lcc.erase_dart(curdh.first); }
+  // assert(lcc.is_valid());
+  assert(lcc.is_whole_map_unmarked(amark));
+  lcc.free_mark(amark);
+}
+////////////////////////////////////////////////////////////////////////////////
+std::size_t query_replace_one_volume_from_dart(LCC& lcc,
+                                               Dart_handle dh,
+                                               size_type marktopreserve)
+{
+  std::size_t replaced=std::numeric_limits<std::size_t>::max();
+  Signature word_signature;
+  Dart_handle
+      dh2=vsignature_of_volume_for_dart(lcc, dh, marktopreserve, word_signature); //, true);
+
+  if (dh2==nullptr) { return replaced; }
+
+  Signature signature;
+  vsignature_of_volume(lcc, dh, marktopreserve, signature);
+  if(signature!=word_signature) { return replaced; }
+
+  //std::cout<<"Source: "; print_signature(signature);
+  auto res=m_vsignatures.find(signature);
+  if(res!=m_vsignatures.end())
+  {
+    replace_one_volume_from_dart(lcc, dh2, m_vpatterns[res->second.second],
+                                 res->second.first);
+    replaced=res->second.second;
+  }
+  // else { std::cout<<"NOT found"<<std::endl; }
+  return replaced;
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Query volume(dh) in the set of patterns, and if one pattern matches,
+/// replace volume(dh).
+/// @return the index of the replaced pattern, max(std::size_t) if no match.
+std::size_t query_replace_one_volume(LCC& lcc,
+                                     Dart_handle dh,
+                                     size_type marktopreserve=LCC::INVALID_MARK)
+{
+  Signature signature;
+  Dart_handle
+      dh2=vsignature_of_volume(lcc, dh, marktopreserve, signature); //, true);
+  std::size_t replaced=std::numeric_limits<std::size_t>::max();
+  auto res=m_vsignatures.find(signature);
+  if(res!=m_vsignatures.end())
+  {
+    replace_one_volume_from_dart(lcc, dh2, m_vpatterns[res->second.second],
+        res->second.first);
+    replaced=res->second.second;
+  }
+  else { // std::cout<<"volume NOT found"<<std::endl;
+    /* static std::size_t nberrors=0; // TODO REMOVE (or add an option to enable/disable dynamically)
+    LCC lcc_error;
+    copy_cell<3>(lcc, dh, lcc_error);
+    // CGAL::draw(lcc_error);
+    // save_object_3D(std::string("error"+std::to_string(nberrors++)+".mesh"), lcc_error);
+    CGAL::write_off(lcc_error, std::string("error"+(std::to_string(nberrors++)+
+                                           ".off")).c_str()); */
+  }
+  return replaced;
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Query volume(dh) but without using signatures. If one pattern matches,
+/// replace volume(dh).
+/// @return the index of the replaced pattern, max(std::size_t) if no match.
+std::size_t query_replace_one_volume_without_signature(LCC& lcc,
+                                                       Dart_handle dh,
+                                                       size_type marktopreserve=LCC::INVALID_MARK)
+{
+  Dart_handle res=nullptr, sd=dh;
+
+  if(marktopreserve!=LCC::INVALID_MARK && !lcc.is_marked(dh, marktopreserve))
+  {
+    auto it=lcc.template darts_of_cell<3>(dh).begin(),
+          itend=lcc.template darts_of_cell<3>(dh).end();
+    while(it!=itend && !lcc.is_marked(it, marktopreserve))
+    { ++it; }
+    if(it!=itend) { sd=it; }
+  }
+
+  std::size_t i=0;
+  while(res==nullptr && i<number_of_vpatterns())
+  {
+    res=is_volume_isomorphic_to_vpattern(lcc, sd, vpattern(i), marktopreserve,
+                                         m_vpatterns[i].mark_to_preserve(),
+                                         false, false, false);
+    if(res==nullptr) { ++i; }
+  }
+
+  if(res!=nullptr)
+  { replace_one_volume_from_dart(lcc, sd, m_vpatterns[i], res); }
+  else
+  { i=std::numeric_limits<std::size_t>::max(); }
+  // std::cout<<"NOT found"<<std::endl;
+  return i;
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Replace face(dh1) by the fpattern, knowing that the border of
+/// fpattern is isomorphic with face(dh1) starting from the pair of darts
+/// (dh1, dh2).
+/// @pre the border of fpattern is isomorphic with face(dh1)
+void replace_one_face_from_dart(LCC& lcc,
+                                Dart_handle dh1,
+                                Pattern<LCC, 1>& fpattern,
+                                Dart_handle dh2)
+{
+  Dart_mapping<LCC> pattern_to_global;
+  Dart_mapping<LCC> links_from_pattern_to_face;
+  bool with_beta3=false;
+  // 1) Copy pattern into lcc.
+  lcc.copy(fpattern.lcc(), &pattern_to_global);
+  if(!lcc.template is_free<3>(dh1))
+  {
+    close_cc_for_beta3(lcc, pattern_to_global[dh2]);
+    with_beta3=true;
+  }
+  // 2) Compute mapping from the boundary of the pattern and
+  //    the face isomorphic to this external boundary
+  auto amark=lcc.get_new_mark();
+  compute_face_bijection_from_pattern_to_dart
+      (lcc, pattern_to_global[dh2], dh1, amark, links_from_pattern_to_face);
+  transform_geometry_of_fpattern(lcc, links_from_pattern_to_face,
+                                 pattern_to_global, fpattern);
+
+  // 3) Remove all the external edges of the copy of the pattern, and 1-sew
+  //    the internal edges of the copy of the pattern with the boundary of
+  //    the face.
+  std::vector<std::pair<Dart_handle, Dart_handle>> tosew0, tosew1;
+  tosew0.reserve(links_from_pattern_to_face.size());
+  tosew1.reserve(links_from_pattern_to_face.size());
+  Dart_handle otherdh;
+  for(auto curdh: links_from_pattern_to_face)
+  {
+    otherdh=lcc.template beta<0>(curdh.first);
+    if(lcc.is_dart_used(otherdh) && !lcc.is_marked(otherdh, amark))
+    {
+      lcc.template topo_unsew<0>(curdh.first);
+      //lcc.template unsew<0>(curdh.first);
+      if(!lcc.template is_free<0>(curdh.second))
+      { lcc.template unsew<0>(curdh.second); }
+      //lcc.template sew<0>(curdh.second, otherdh);
+      tosew0.push_back(std::make_pair(curdh.second, otherdh));
+    }
+    otherdh=lcc.template beta<1>(curdh.first);
+    if(lcc.is_dart_used(otherdh) && !lcc.is_marked(otherdh, amark))
+    {
+      lcc.template topo_unsew<1>(curdh.first);
+      //lcc.template unsew<1>(curdh.first);
+      if(!lcc.template is_free<1>(curdh.second))
+      { lcc.template unsew<1>(curdh.second); }
+      //lcc.template sew<1>(curdh.second, otherdh);
+      tosew1.push_back(std::make_pair(curdh.second, otherdh));
+    }
+  }
+  for(auto curdh: tosew0)
+  { lcc.template sew<0>(curdh.first, curdh.second); }
+  for(auto curdh: tosew1)
+  { lcc.template sew<1>(curdh.first, curdh.second); }
+  for(auto curdh: links_from_pattern_to_face)
+  {
+    if(with_beta3)
+    { lcc.erase_dart(lcc.template beta<3>(curdh.first)); }
+    lcc.erase_dart(curdh.first);
+  }
+  assert(lcc.is_whole_map_unmarked(amark));
+  lcc.free_mark(amark);
+  // assert(lcc.is_valid());
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Query face(dh) in the set of patterns, and if one pattern matches,
+/// replace face(dh).
+/// @return the index of the replaced pattern, max(std::size_t) if no match.
+std::size_t query_replace_one_face(LCC& lcc,
+                                   Dart_handle dh,
+                                   size_type marktopreserve=LCC::INVALID_MARK)
+{
+  Signature signature;
+  Dart_handle
+      dh2=fsignature_of_face(lcc, dh, marktopreserve, signature); //, true);
+  //std::cout<<"Source: "; print_signature(signature);
+  std::size_t replaced=std::numeric_limits<std::size_t>::max();
+  auto res=m_fsignatures.find(signature);
+  if(res!=m_fsignatures.end())
+  {
+    // std::cout<<"FOUND Pattern "<<res->second.second+1<<std::endl;
+    replace_one_face_from_dart(lcc, dh2, m_fpatterns[res->second.second],
+        res->second.first);
+    replaced=res->second.second;
+  }
+  // else { std::cout<<"face NOT found"<<std::endl; }
+  return replaced;
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Query face(dh) but without using signatures. If one pattern matches,
+/// replace face(dh).
+/// @return the index of the replaced pattern, max(std::size_t) if no match.
+std::size_t query_replace_one_face_without_signature(LCC& lcc,
+                                                     Dart_handle dh,
+                                                     size_type marktopreserve=LCC::INVALID_MARK)
+{
+  Dart_handle res=nullptr, sd=dh;
+
+  if(marktopreserve!=LCC::INVALID_MARK && !lcc.is_marked(dh, marktopreserve))
+  {
+    auto it=lcc.template darts_of_cell<2,2>(dh).begin(),
+          itend=lcc.template darts_of_cell<2,2>(dh).end();
+    while(it!=itend && !lcc.is_marked(it, marktopreserve))
+    { ++it; }
+    if(it!=itend) { sd=it; }
+  }
+
+  std::size_t i=0;
+  while(res==nullptr && i<number_of_fpatterns())
+  {
+    res=is_face_isomorphic_to_fpattern(lcc, sd, fpattern(i), marktopreserve,
+                                       m_fpatterns[i].mark_to_preserve(),
+                                       false, false, false);
+    if(res==nullptr) { ++i; }
+  }
+
+  if(res!=nullptr)
+  { replace_one_face_from_dart(lcc, sd, m_fpatterns[i], res); }
+  else
+  { i=std::numeric_limits<std::size_t>::max(); }
+  // std::cout<<"NOT found"<<std::endl;
+  return i;
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Replace surface(dh1) by the spattern, knowing that the border of
+/// spattern is isomorphic with surface(dh1) starting from the pair of darts
+/// (dh1, dh2).
+/// @pre the border of spattern is isomorphic with surface(dh1)
+void replace_one_surface_from_dart(LCC& lcc,
+                                   Dart_handle dh1,
+                                   Pattern<LCC, 2>& spattern,
+                                   Dart_handle dh2)
+{
+  Dart_mapping<LCC> pattern_to_global;
+  Dart_mapping<LCC> links_from_pattern_to_surface;
+  // 1) Copy pattern into lcc.
+  lcc.copy(spattern.lcc(), &pattern_to_global);
+
+  // 2) Compute mapping from the boundary of the pattern and
+  //    the surface isomorphic to this external boundary, and 2-unsew
+  //    each face border of the pattern
+  auto amark=lcc.get_new_mark();
+  compute_surface_bijection_from_pattern_to_dart(lcc, spattern,
+                                                 dh2, dh1,
+                                                 pattern_to_global,
+                                                 links_from_pattern_to_surface);
+
+  // Transform the geometry of all faces (same method than for faces)
+  transform_geometry_of_spattern(lcc, links_from_pattern_to_surface,
+                                 pattern_to_global, spattern);
+
+  // 3) Remove all the external edges of the copy of the pattern, and 1-sew
+  //    the internal edges of the copy of the pattern with the boundary of
+  //    the face.
+  for(auto curdh: links_from_pattern_to_surface)
+  {
+    if(!lcc.template is_free<3>(curdh.second) &&
+       lcc.template is_free<3>(curdh.first))
+    { close_cc_for_beta3(lcc, curdh.first); }
+
+    dh2=lcc.template beta<0>(curdh.first);
+    if(lcc.is_dart_used(dh2) && !lcc.is_marked(dh2, amark))
+    {
+      lcc.template unsew<0>(curdh.first);
+      if(!lcc.template is_free<0>(curdh.second))
+      { lcc.template unsew<0>(curdh.second); }
+      lcc.template sew<0>(curdh.second, dh2);
+    }
+    dh2=lcc.template beta<1>(curdh.first);
+    if(lcc.is_dart_used(dh2) && !lcc.is_marked(dh2, amark))
+    {
+      lcc.template unsew<1>(curdh.first);
+      if(!lcc.template is_free<1>(curdh.second))
+      { lcc.template unsew<1>(curdh.second); }
+      lcc.template sew<1>(curdh.second, dh2);
+    }
+   }
+  for(auto curdh: links_from_pattern_to_surface)
+  {
+    if(!lcc.template is_free<3>(curdh.first))
+    { lcc.erase_dart(lcc.template beta<3>(curdh.first)); }
+    lcc.erase_dart(curdh.first);
+  }
+  assert(lcc.is_whole_map_unmarked(amark));
+  lcc.free_mark(amark);
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Query surface(dh) in the set of patterns, and if one pattern matches,
+/// replace surface(dh).
+/// @return the index of the replaced pattern, max(std::size_t) if no match.
+std::size_t query_replace_one_surface(LCC& lcc,
+                                      Dart_handle dh,
+                                      size_type marktopreserve=LCC::INVALID_MARK)
+{
+  Signature signature;
+  Dart_handle
+      dh2=ssignature_of_surface(lcc, dh, marktopreserve, signature); //, true);
+  typename LCC::Vector v1, v2;
+  // std::cout<<"Source: "; print_signature(signature);
+  std::size_t replaced=std::numeric_limits<std::size_t>::max();
+  auto res=m_ssignatures.find(signature);
+  if(res!=m_ssignatures.end())
+  {
+    // std::cout<<"FOUND Pattern "<<res->second.second+1<<std::endl;
+    replace_one_surface_from_dart(lcc, dh2, m_spatterns[res->second.second],
+        res->second.first);
+    replaced=res->second.second;
+    // assert(lcc.is_valid());
+  }
+  // else { std::cout<<"NOT found"<<std::endl; }
+  return replaced;
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Query surface(dh) but without using signatures. If one pattern matches,
+/// replace surface(dh).
+/// @return the index of the replaced pattern, max(std::size_t) if no match.
+std::size_t query_replace_one_surface_without_signature(LCC& lcc,
+                                                        Dart_handle dh,
+                                                        size_type marktopreserve=LCC::INVALID_MARK)
+{
+  Dart_handle res=nullptr, sd=dh;
+
+  if(marktopreserve!=LCC::INVALID_MARK && !lcc.is_marked(dh, marktopreserve))
+  {
+    auto it=lcc.template darts_of_cell<3>(dh).begin(),
+          itend=lcc.template darts_of_cell<3>(dh).end();
+    while(it!=itend && !lcc.is_marked(it, marktopreserve))
+    { ++it; }
+    if(it!=itend) { sd=it; }
+  }
+
+  std::size_t i=0;
+  while(res==nullptr && i<number_of_spatterns())
+  {
+    res=is_surface_isomorphic_to_spattern(lcc, sd, spattern(i),
+                                          m_spatterns[i].m_mark_faceborder,
+                                          marktopreserve,
+                                          m_spatterns[i].mark_to_preserve(),
+                                          false, false, false);
+    if(res==nullptr) { ++i; }
+  }
+
+  if(res!=nullptr)
+  { replace_one_surface_from_dart(lcc, sd, m_spatterns[i], res); }
+  else
+  { i=std::numeric_limits<std::size_t>::max(); }
+  // std::cout<<"NOT found"<<std::endl;
+  return i;
+}
+////////////////////////////////////////////////////////////////////////////////
+std::size_t replace_vpatterns(LCC& lcc,
+                              size_type marktopreserve,
+                              bool nosignature=false,
+                              bool all=true,
+                              bool trace=false)
+{
+  auto amark=lcc.get_new_mark();
+  lcc.negate_mark(amark); // All darts are marked
+  std::size_t res=0;
+  for(auto it=lcc.darts().begin(); it!=lcc.darts().end(); ++it)
+  {
+    if(lcc.is_marked(it, amark))
+    {
+      lcc.template unmark_cell<3>(it, amark);
+      // New darts will not be marked
+      std::size_t replaced=
+          (nosignature?query_replace_one_volume_without_signature
+                       (lcc, it, marktopreserve):
+           query_replace_one_volume(lcc, it, marktopreserve));
+      if(replaced!=std::numeric_limits<std::size_t>::max())
+      {
+        ++res;
+        if(!all)
+        {
+          lcc.free_mark(amark);
+          return true;
+        }
+        if(trace) { std::cout<<replaced+1<<" "; }
+      }
+    }
+  }
+
+  lcc.free_mark(amark);
+  return res;
+}
+////////////////////////////////////////////////////////////////////////////////
+std::size_t replace_spatterns(LCC& lcc,
+                              size_type marktopreserve,
+                              bool nosignature=false,
+                              bool all=true,
+                              bool trace=false)
+{
+  auto amark=lcc.get_new_mark();
+  lcc.negate_mark(amark); // All darts are marked
+  std::size_t res=0;
+  for(auto it=lcc.darts().begin(); it!=lcc.darts().end(); ++it)
+  {
+    if(lcc.is_marked(it, amark))
+    {
+      lcc.template unmark_cell<3>(it, amark);
+      // New darts will not be marked
+      std::size_t replaced=
+          (nosignature?query_replace_one_surface_without_signature
+                       (lcc, it, marktopreserve):
+           query_replace_one_surface(lcc, it, marktopreserve));
+      if(replaced!=std::numeric_limits<std::size_t>::max())
+      {
+        ++res;
+        if(!all)
+        {
+          lcc.free_mark(amark);
+          return true;
+        }
+        if(trace) { std::cout<<replaced+1<<" "; }
+      }
+    }
+  }
+
+  lcc.free_mark(amark);
+  return res;
+}
+////////////////////////////////////////////////////////////////////////////////
+std::size_t replace_fpatterns(LCC& lcc,
+                              size_type marktopreserve,
+                              bool nosignature=false,
+                              bool all=true,
+                              bool trace=false)
+{
+  auto amark=lcc.get_new_mark();
+  lcc.negate_mark(amark); // All darts are marked
+  std::size_t res=0;
+  for(auto it=lcc.darts().begin(); it!=lcc.darts().end(); ++it)
+  {
+    if(lcc.is_marked(it, amark))
+    {
+      lcc.template unmark_cell<2>(it, amark);
+      // New darts will not be marked
+      std::size_t replaced=
+          (nosignature?query_replace_one_face_without_signature
+                       (lcc, it, marktopreserve):
+           query_replace_one_face(lcc, it, marktopreserve));
+      if(replaced!=std::numeric_limits<std::size_t>::max())
+      {
+        ++res;
+        if(!all)
+        {
+          lcc.free_mark(amark);
+          return true;
+        }
+        if(trace) { std::cout<<replaced+1<<" "; }
+      }
+    }
+  }
+
+  lcc.free_mark(amark);
+  return res;
+}
+////////////////////////////////////////////////////////////////////////////////
+void generate_all_face_replacement(LCC& lcc,
+                                   size_type marktopreserve,
+                                   std::list<LCC>& reslccs)
+{
+  std::list<LCC> totreat; // list to avoid copy of LCC
+  totreat.push_back(LCC());
+  totreat.back()=lcc; // copy
+  while(!totreat.empty())
+  {
+    LCC current=std::move(totreat.front());
+    totreat.pop_front();
+
+    bool replaced=false;
+    for(auto it=current.darts().begin(), itend=current.darts().end();
+        !replaced && it!=itend; ++it)
+    {
+      Signature signature;
+      fsignature_of_face_for_dart(current, it, marktopreserve, signature); //, true);
+      auto res=m_fsignatures.find(signature);
+      if(res!=m_fsignatures.end())
+      {
+        Dart_handle dh2=it;
+        do
+        {
+          totreat.push_back(LCC());
+          std::unordered_map<Dart_handle, Dart_handle> origin_to_copy;
+          totreat.back().copy(current, &origin_to_copy, nullptr);
+          replace_one_face_from_dart(totreat.back(), origin_to_copy[dh2],
+                                     m_fpatterns[res->second.second],
+                                     res->second.first);
+          replaced=true;
+          do
+          {
+            dh2=current.template beta<1>(dh2);
+            fsignature_of_face_for_dart(current, dh2, marktopreserve, signature); //, true);
+            res=m_fsignatures.find(signature);
+          }
+          while(res==m_fsignatures.end() && dh2!=it);
+        }
+        while(dh2!=it);
+      }
+    }
+    if(!replaced)
+    {
+      reslccs.push_back(LCC());
+      current.swap(reslccs.back());
+    }
+  }
+}
+////////////////////////////////////////////////////////////////////////////////
+void generate_all_surface_replacement(LCC& lcc,
+                                      size_type marktopreserve,
+                                      std::list<LCC>& reslccs)
+{
+  std::list<LCC> totreat; // list to avoid copy of LCC
+  totreat.push_back(LCC());
+  totreat.back()=lcc;
+  while(!totreat.empty())
+  {
+    LCC current;
+    current->swap(totreat.front());
+    totreat.pop_front();
+
+    std::size_t replaced=std::numeric_limits<std::size_t>::max();
+    for(auto it=current.darts().begin(), itend=current.darts().end();
+        it!=itend; ++it)
+    {
+      Signature signature;
+      Dart_handle
+          dh2=ssignature_of_surface_for_dart(current, it, marktopreserve, signature); //, true);
+      auto res=m_ssignatures.find(signature);
+      if(res!=m_ssignatures.end())
+      {
+        totreat.push_back(LCC());
+        std::unordered_map<Dart_handle, Dart_handle> origin_to_copy;
+        totreat.back().copy(current, &origin_to_copy, nullptr);
+        replace_one_surface_from_dart(totreat.back(), origin_to_copy[dh2],
+                                      m_spatterns[res->second.second],
+                                      res->second.first);
+        replaced=res->second.second;
+      }
+    }
+    if(replaced==std::numeric_limits<std::size_t>::max())
+    {
+      reslccs.push_back(LCC());
+      current->swap(reslccs.back());
+    }
+  }
+}
+////////////////////////////////////////////////////////////////////////////////
+void generate_all_volume_replacement(LCC& lcc,
+                                     size_type marktopreserve,
+                                     std::list<LCC>& reslccs)
+{
+  std::list<LCC> totreat; // list to avoid copy of LCC
+  totreat.push_back(LCC());
+  totreat.back()=lcc;
+  while(!totreat.empty())
+  {
+    LCC current;
+    current->swap(totreat.front());
+    totreat.pop_front();
+
+    std::size_t replaced=std::numeric_limits<std::size_t>::max();
+    for(auto it=current.darts().begin(), itend=current.darts().end();
+        it!=itend; ++it)
+    {
+      Signature signature;
+      Dart_handle
+          dh2=vsignature_of_volume_for_dart(current, it, marktopreserve, signature); //, true);
+      auto res=m_vsignatures.find(signature);
+      if(res!=m_vsignatures.end())
+      {
+        totreat.push_back(LCC());
+        std::unordered_map<Dart_handle, Dart_handle> origin_to_copy;
+        totreat.back().copy(current, &origin_to_copy, nullptr);
+        replace_one_volume_from_dart(totreat.back(), origin_to_copy[dh2],
+                                     m_vpatterns[res->second.second],
+                                     res->second.first);
+        replaced=res->second.second;
+      }
+    }
+    if(replaced==std::numeric_limits<std::size_t>::max())
+    {
+      reslccs.push_back(LCC());
+      current->swap(reslccs.back());
+    }
+  }
+}
+
+public:
+  Pattern_set<1> m_fpatterns;
+  Signature_mapping m_fsignatures;
+
+  Pattern_set<2> m_spatterns;
+  Signature_mapping m_ssignatures;
+
+  Pattern_set<3> m_vpatterns;
+  Signature_mapping m_vsignatures;
+};
+////////////////////////////////////////////////////////////////////////////////
+#endif // CMAP_QUERY_REPLACE_H
diff --git a/src/cmap_query_replace_geometry.h b/src/cmap_query_replace_geometry.h
new file mode 100644
index 0000000000000000000000000000000000000000..b807fa2ab12fc9e6c7fa988dcf182193e5807551
--- /dev/null
+++ b/src/cmap_query_replace_geometry.h
@@ -0,0 +1,893 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CMAP_QUERY_REPLACE_GEOMETRY_H
+#define CMAP_QUERY_REPLACE_GEOMETRY_H
+
+#include <unordered_map>
+#include <utility>
+#include <vector>
+#include <tuple>
+#include <queue>
+
+#include <CGAL/Kernel_traits.h>
+
+#include "cmap_3close_cc.h"
+#include "cmap_signature.h"
+#include "lcc_geometry_transformation.h"
+#include "lcc_read_depending_extension.h"
+
+template<class LCC>
+class Pattern_substituer;
+
+template<class LCC, unsigned int>
+class Pattern;
+
+template<class LCC>
+using Dart_mapping=std::unordered_map<typename LCC::Dart_handle,
+                                      typename LCC::Dart_handle>;
+
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC, unsigned int type>
+class Barycentric_coord
+{};
+
+template<class LCC>
+class Barycentric_coord<LCC, 1>
+{
+public:
+  using Dart_handle=typename LCC::Dart_handle;
+
+  void display(LCC& lcc)
+  {
+    std::cout<<lcc.point(m_dart)<<": ";
+    for(auto& it: m_coords)
+    { std::cout<<"["<<"  "<<lcc.point(std::get<0>(it))<<": "<<std::get<1>(it)
+               <<", "<<std::get<2>(it)<<", "<<std::get<3>(it)<<"] "; }
+    std::cout<<std::endl;
+  }
+
+  Dart_handle m_dart; // dart of an inner vertex
+  /// barycentric coords of this inner vertex for each border vertex
+  std::vector<std::tuple<Dart_handle, double, double, double>> m_coords;
+};
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+class Barycentric_coord<LCC, 3>
+{
+public:
+  using Dart_handle=typename LCC::Dart_handle;
+
+  void display(LCC& lcc)
+  {
+    std::cout<<lcc.point(m_dart)<<": ";
+    for(auto& it: m_coords)
+    { std::cout<<"["<<"  "<<lcc.point(std::get<0>(it))<<": "<<std::get<1>(it)<<", "
+               <<", "<<std::get<2>(it)<<", "<<std::get<3>(it)<<", "
+               <<std::get<4>(it)<<"] "; }
+    std::cout<<std::endl;
+  }
+
+  Dart_handle m_dart;
+  std::vector<std::tuple<Dart_handle, double, double, double, double>> m_coords;
+};
+///////////////////////////////////////////////////////////////////////////////
+template<typename Point>
+bool compute_alpha_beta_gamma_of_point(const Point& a, const Point& b,
+                                       const Point& c, const Point& p,
+                                       double& alpha, double& beta, double& gamma)
+{
+  typename CGAL::Kernel_traits<Point>::Kernel::Triangle_3 t(a, b, c);
+  if(t.is_degenerate()) { return false; }
+
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vap(a, p);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vbp(b, p);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vcp(c, p);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vab(a, b);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vac(a, c);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vca(c, a);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vbc(b, c);
+
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3
+      n=CGAL::cross_product(vab, vac);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3
+      na=CGAL::cross_product(vbc, vbp);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3
+      nb=CGAL::cross_product(vca, vcp);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3
+      nc=CGAL::cross_product(vab, vap);
+
+  alpha=(n*na)/(n*n);
+  beta=(n*nb)/(n*n);
+  gamma=(n*nc)/(n*n);
+  return true;
+
+ /* typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 v0(p0, p1);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 v1(p0, p2);
+
+  double div=v0.y()*v1.z()-v1.y()*v0.z();
+  if(div!=0)
+  { beta=(v0.y()*(p.z()-p0.z())-(p.y()-p0.y())*v0.z())/(div); }
+  else
+  {
+    div=v0.x()*v1.z()-v1.x()*v0.z();
+    if(div!=0)
+    { beta=(v0.x()*(p.z()-p0.z())-(p.x()-p0.x())*v0.z())/(div); }
+    else
+    {
+      div=v0.y()*v1.x()-v1.y()*v0.x();
+      assert(div!=0);
+      beta=(v0.y()*(p.x()-p0.x())-(p.y()-p0.y())*v0.x())/(div);
+    }
+  }
+
+  if(v0.x()!=0)
+  { alpha=((p.x()-p0.x())-beta*v1.x())/v0.x(); }
+  else if (v0.y()!=0)
+  { alpha=((p.y()-p0.y())-beta*v1.y())/v0.y(); }
+  else
+  {
+    assert(v1.z()!=0);
+    alpha=((p.z()-p0.z())-beta*v1.z())/v0.z();
+  }*/
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename Point>
+bool compute_point_from_alpha_beta_gamma(const Point& p0, const Point& p1,
+                                         const Point& p2, double alpha,
+                                         double beta, double gamma,
+                                         Point& p)
+{
+  typename CGAL::Kernel_traits<Point>::Kernel::Triangle_3 t(p0, p1, p2);
+  if(t.is_degenerate()) { return false; }
+  p=Point(alpha*p0.x()+beta*p1.x()+gamma*p2.x(),
+          alpha*p0.y()+beta*p1.y()+gamma*p2.y(),
+          alpha*p0.z()+beta*p1.z()+gamma*p2.z());
+  return true;
+
+  /* typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 v0(p0, p1);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 v1(p0, p2);
+  p=Point(p0.x()+alpha*v0.x()+beta*v1.x(),
+          p0.y()+alpha*v0.y()+beta*v1.y(),
+          p0.z()+alpha*v0.z()+beta*v1.z()); */
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename Point>
+bool compute_alpha_beta_gamma_delta_of_point(const Point& a, const Point& b,
+                                             const Point& c, const Point& d,
+                                             const Point& p, double& alpha,
+                                             double& beta, double& gamma,
+                                             double& delta)
+{
+  typename CGAL::Kernel_traits<Point>::Kernel::Tetrahedron_3 t(a, b, c, d);
+  if(t.is_degenerate()) { return false; }
+
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vap(a, p);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vbp(b, p);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vcp(c, p);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vdp(d, p);
+
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vab(a, b);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vac(a, c);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vad(a, d);
+
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vbc(b, c);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 vbd(b, d);
+
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3
+      temp=CGAL::cross_product(vac, vad);
+
+  double va=(vbp*CGAL::cross_product(vbd, vbc));
+  double vb=(vap*temp);
+  double vc=(vap*CGAL::cross_product(vad, vab));
+  double vd=(vap*CGAL::cross_product(vab, vac));
+  double v=/* std::abs */((vab*temp));
+
+  alpha=va/v;
+  beta=vb/v;
+  gamma=vc/v;
+  delta=vd/v;
+  return true;
+
+  /* std::cout<<"[compute alpha...] "<<a<<" "<<b<<" "<<c<<" "<<d<<" "
+           <<alpha<<" "<<beta<<" "<<gamma<<" "<<delta<<" -> "<<p<<std::endl; */
+
+  /*
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 u(p0, p1);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 v(p0, p2);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 w(p0, p3);
+
+  if((v.x()*u.y()-v.y()*u.x())!=0)
+  {
+    double part1=((p.x()*u.y()-p0.x()*u.y()-u.x()*p.y()+p0.y()*u.x())*
+                  (v.z()*u.x()-v.x()*u.z()))/(v.x()*u.y()-v.y()*u.x());
+    double part2=((w.y()*u.x()-w.x()*u.y())*(v.z()*u.x()-v.x()*u.z())+
+                  (v.x()*u.y()-v.y()*u.x())*(w.z()*u.x()-w.x()*u.z()))/
+                 (v.x()*u.y()-v.y()*u.x());
+    assert(part2!=0);
+    gamma=((p.z()*u.x()-p0.z()*u.x()-p.x()*u.z()+p0.x()*u.z())-part1)/part2;
+  }
+  else if((v.x()*u.z()-v.z()*u.x())!=0)
+  {
+    double part1=((p.x()*u.z()-p0.x()*u.z()-u.x()*p.z()+p0.z()*u.x())*
+                  (v.y()*u.x()-v.x()*u.y()))/(v.x()*u.z()-v.z()*u.x());
+    double part2=((w.z()*u.x()-w.x()*u.z())*(v.y()*u.x()-v.x()*u.y())+
+                  (v.x()*u.z()-v.z()*u.x())*(w.y()*u.x()-w.x()*u.y()))/
+                 (v.x()*u.z()-v.z()*u.x());
+    assert(part2!=0);
+    gamma=((p.y()*u.x()-p0.y()*u.x()-p.x()*u.y()+p0.x()*u.y())-part1)/part2;
+  }
+  else
+  {
+    assert((v.y()*u.z()-v.z()*u.y())!=0);
+    double part1=((p.y()*u.z()-p0.y()*u.z()-u.y()*p.z()+p0.z()*u.y())*
+                  (v.x()*u.y()-v.y()*u.x()))/(v.y()*u.z()-v.z()*u.y());
+    double part2=((w.z()*u.y()-w.y()*u.z())*(v.x()*u.y()-v.y()*u.x())+
+                  (v.y()*u.z()-v.z()*u.y())*(w.x()*u.y()-w.y()*u.x()))/
+                 (v.y()*u.z()-v.z()*u.y());
+    assert(part2!=0);
+    gamma=((p.x()*u.y()-p0.x()*u.y()-p.y()*u.x()+p0.y()*u.x())-part1)/part2;
+  }
+
+  if((v.x()*u.y()-v.y()*u.x())!=0)
+  {
+    beta=((p.x()*u.y()-p0.x()*u.y()-u.x()*p.y()+p0.y()*u.x())/
+          (v.x()*u.y()-v.y()*u.x()))+
+         ((w.y()*u.x()-w.x()*u.y())/(v.x()*u.y()-v.y()*u.x()))*gamma;
+  }
+  else if((v.x()*u.z()-v.z()*u.x())!=0)
+  {
+    beta=((p.x()*u.z()-p0.x()*u.z()-u.x()*p.z()+p0.z()*u.x())/
+          (v.x()*u.z()-v.z()*u.x()))+
+         ((w.z()*u.x()-w.x()*u.z())/(v.x()*u.z()-v.z()*u.x()))*gamma;
+  }
+  else
+  {
+    assert((v.y()*u.z()-v.z()*u.y())!=0);
+    beta=((p.y()*u.z()-p0.y()*u.z()-u.y()*p.z()+p0.z()*u.y())/
+          (v.y()*u.z()-v.z()*u.y()))+
+         ((w.z()*u.y()-w.y()*u.z())/(v.y()*u.z()-v.z()*u.y()))*gamma;
+  }
+
+  if(u.x()!=0)
+  { alpha=(p.x()-p0.x()-beta*v.x()-gamma*w.x())/u.x(); }
+  else if(u.y()!=0)
+  { alpha=(p.y()-p0.y()-beta*v.y()-gamma*w.y())/u.y(); }
+  else
+  {
+    assert(u.z()!=0);
+    alpha=(p.z()-p0.z()-beta*v.z()-gamma*w.z())/u.z();
+  }*/
+
+  // TODO assertion true if we use epsilon comparison
+  // assert(p.x()==alpha*a.x()+beta*b.x()+gamma*c.x()+delta*d.x());
+  // assert(p.y()==alpha*a.y()+beta*b.y()+gamma*c.y()+delta*d.y());
+  // assert(p.z()==alpha*a.z()+beta*b.z()+gamma*c.z()+delta*d.z());
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename Point>
+bool compute_point_from_alpha_beta_gamma_delta(const Point& p0, const Point& p1,
+                                               const Point& p2, const Point& p3,
+                                               double alpha, double beta,
+                                               double gamma, double delta,
+                                               Point& p)
+{
+  /* typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 u(p0, p1);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 v(p0, p2);
+  typename CGAL::Kernel_traits<Point>::Kernel::Vector_3 w(p0, p3);
+  p=Point(p0.x()+alpha*u.x()+beta*v.x()+gamma*w.x(),
+          p0.y()+alpha*u.y()+beta*v.y()+gamma*w.y(),
+          p0.z()+alpha*u.z()+beta*v.z()+gamma*w.z()); */
+  typename CGAL::Kernel_traits<Point>::Kernel::Tetrahedron_3 t(p0, p1, p2, p3);
+  if(t.is_degenerate()) { return false; }
+  p=Point(alpha*p0.x()+beta*p1.x()+gamma*p2.x()+delta*p3.x(),
+          alpha*p0.y()+beta*p1.y()+gamma*p2.y()+delta*p3.y(),
+          alpha*p0.z()+beta*p1.z()+gamma*p2.z()+delta*p3.z());
+  return true;
+  /* std::cout<<"[compute point] "<<p0<<" "<<p1<<" "<<p2<<" "<<p3<<" "
+           <<alpha<<" "<<beta<<" "<<gamma<<" "<<delta<<" -> "<<p<<std::endl; */
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename LCC>
+typename LCC::Point
+compute_point_2D(LCC& lcc,
+                 Dart_mapping<LCC>& links_from_pattern_to_face,
+                 Dart_mapping<LCC>& pattern_to_global,
+                 Barycentric_coord<LCC, 1>& m_barycentric_coords)
+{
+  typename LCC::Point p;
+  typename LCC::Vector res=CGAL::NULL_VECTOR;
+  typename LCC::Dart_handle cur, dh1, dh2;
+  std::size_t nb=0;
+  typename LCC::Dart_handle firstdh=
+      links_from_pattern_to_face[pattern_to_global
+      [std::get<0>(m_barycentric_coords.m_coords.front())]];
+  typename LCC::Point bary2=lcc.template barycenter<2>(firstdh);
+  for(std::tuple<typename LCC::Dart_handle, double, double, double>& e:
+      m_barycentric_coords.m_coords)
+  {
+    assert(pattern_to_global.find(std::get<0>(e))!=pattern_to_global.end());
+    assert(links_from_pattern_to_face.find(pattern_to_global[std::get<0>(e)])
+        !=links_from_pattern_to_face.end());
+    cur=links_from_pattern_to_face[pattern_to_global[std::get<0>(e)]];
+    dh1=lcc.other_extremity(cur);
+    if(compute_point_from_alpha_beta_gamma(lcc.point(cur), lcc.point(dh1),
+                                           bary2, std::get<1>(e),
+                                           std::get<2>(e), std::get<3>(e), p))
+    {
+      res+=typename LCC::Vector(p.x(), p.y(), p.z());
+      ++nb;
+    }
+  }
+  assert(nb>0);
+  return typename LCC::Point(res.x()/nb, res.y()/nb, res.z()/nb);
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename LCC>
+typename LCC::Point
+compute_point_3D(LCC& lcc,
+                 Dart_mapping<LCC>& links_from_pattern_to_volume,
+                 Dart_mapping<LCC>& pattern_to_global,
+                 Barycentric_coord<LCC, 3>& m_barycentric_coords)
+{
+  typename LCC::Point p;
+  typename LCC::Vector res=CGAL::NULL_VECTOR;
+  typename LCC::Dart_handle cur, dh1, dh2, dh3;
+  std::size_t nb=0;
+  for(std::tuple<typename LCC::Dart_handle, double, double, double, double>& e:
+      m_barycentric_coords.m_coords)
+  {
+    assert(pattern_to_global.find(std::get<0>(e))!=pattern_to_global.end());
+    assert(links_from_pattern_to_volume.find(pattern_to_global[std::get<0>(e)])
+        !=links_from_pattern_to_volume.end());
+    cur=links_from_pattern_to_volume[pattern_to_global[std::get<0>(e)]];
+    dh1=lcc.template beta<0>(cur);
+    dh2=lcc.other_extremity(cur);
+    dh3=lcc.template beta<2,1,2>(cur);
+    if(compute_point_from_alpha_beta_gamma_delta(lcc.point(cur), lcc.point(dh1),
+                                                 lcc.point(dh2), lcc.point(dh3),
+                                                 std::get<1>(e), std::get<2>(e),
+                                                 std::get<3>(e), std::get<4>(e),
+                                                 p))
+    {
+      res+=typename LCC::Vector(p.x(), p.y(), p.z());
+      ++nb;
+    }
+  }
+  assert(nb>0);
+  return typename LCC::Point(res.x()/nb, res.y()/nb, res.z()/nb);
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename LCC>
+typename LCC::Point
+compute_point_3D_v2(LCC& lcc,
+                    Dart_mapping<LCC>& links_from_pattern_to_volume,
+                    Dart_mapping<LCC>& pattern_to_global,
+                    Barycentric_coord<LCC, 3>& m_barycentric_coords)
+{
+  assert(!m_barycentric_coords.m_coords.empty());
+  typename LCC::Point p;
+  typename LCC::Vector res=CGAL::NULL_VECTOR;
+  typename LCC::Dart_handle cur, dh1, dh2, dh3;
+  std::size_t nb=0;
+  typename LCC::Dart_handle firstdh=
+      links_from_pattern_to_volume[pattern_to_global
+      [std::get<0>(m_barycentric_coords.m_coords.front())]];
+  typename LCC::Point bary3=lcc.template barycenter<3>(firstdh);
+  for(std::tuple<typename LCC::Dart_handle, double, double, double, double>& e:
+      m_barycentric_coords.m_coords)
+  {
+    assert(pattern_to_global.find(std::get<0>(e))!=pattern_to_global.end());
+    assert(links_from_pattern_to_volume.find(pattern_to_global[std::get<0>(e)])
+        !=links_from_pattern_to_volume.end());
+    cur=links_from_pattern_to_volume[pattern_to_global[std::get<0>(e)]];
+    dh1=lcc.other_extremity(cur);
+
+    // TODO avoid to recompute barycenters several times (?)
+    if(compute_point_from_alpha_beta_gamma_delta(lcc.point(cur), lcc.point(dh1),
+                                                 lcc.template barycenter<2>(cur),
+                                                 bary3,
+                                                 std::get<1>(e), std::get<2>(e),
+                                                 std::get<3>(e), std::get<4>(e),
+                                                 p))
+    {
+      res+=typename LCC::Vector(p.x(), p.y(), p.z());
+      ++nb;
+    }
+  }
+  assert(nb>0);
+  return typename LCC::Point(res.x()/nb, res.y()/nb, res.z()/nb);
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Transform the geometry of the fpattern according to the geometry of the
+/// target.
+template<typename LCC>
+void transform_geometry_of_fpattern(LCC& lcc,
+                                    Dart_mapping<LCC>& links_from_pattern_to_face,
+                                    Dart_mapping<LCC>& pattern_to_global,
+                                    Pattern<LCC, 1>& pattern)
+{
+  for(Barycentric_coord<LCC, 1>& inner: pattern.barycentric_coords())
+  {
+    assert(pattern_to_global.find(inner.m_dart)!=pattern_to_global.end());
+    typename LCC::Dart_handle res=pattern_to_global[inner.m_dart];
+    // TODO avoid to recompute barycenters several times (?)
+    lcc.point(res)=compute_point_2D(lcc,
+                                    links_from_pattern_to_face,
+                                    pattern_to_global,
+                                    inner);
+  }
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Transform the geometry of the spattern according to the geometry of the
+/// target. For now same method than transform_geometry_of_fpattern
+template<typename LCC>
+void transform_geometry_of_spattern(LCC& lcc,
+                                    Dart_mapping<LCC>& links_from_pattern_to_face,
+                                    Dart_mapping<LCC>& pattern_to_global,
+                                    Pattern<LCC, 2>& pattern)
+{
+  for(Barycentric_coord<LCC, 1>& inner: pattern.barycentric_coords())
+  {
+    assert(pattern_to_global.find(inner.m_dart)!=pattern_to_global.end());
+    typename LCC::Dart_handle res=pattern_to_global[inner.m_dart];
+    // TODO avoid to recompute barycenters several times (?)
+    lcc.point(res)=compute_point_2D(lcc,
+                                    links_from_pattern_to_face,
+                                    pattern_to_global,
+                                    inner);
+  }
+}
+////////////////////////////////////////////////////////////////////////////////
+/// Transform the geometry of the vpattern according to the geometry of the
+/// target. Mark the dart of the external faces of the pattern.
+/// For now simple solution that does not work for any pattern. TODO better?
+template<typename LCC>
+void transform_geometry_of_vpattern(LCC& lcc,
+                                    Dart_mapping<LCC>& links_from_pattern_to_volume,
+                                    Dart_mapping<LCC>& pattern_to_global,
+                                    Pattern<LCC, 3>& pattern)
+{
+  for(Barycentric_coord<LCC, 3>& inner: pattern.barycentric_coords())
+  {
+    assert(pattern_to_global.find(inner.m_dart)!=pattern_to_global.end());
+    typename LCC::Dart_handle res=pattern_to_global[inner.m_dart];
+    // std::cout<<"[transform_geometry_of_vpattern] "<<lcc.point()<<" -> before "
+    //          <<lcc.point()<<" and  after ";
+    /* lcc.point(res)=compute_point_3D(lcc,
+                                    links_from_pattern_to_volume,
+                                    pattern_to_global,
+                                    inner); */
+    lcc.point(res)=compute_point_3D_v2(lcc,
+                                       links_from_pattern_to_volume,
+                                       pattern_to_global,
+                                       inner);
+    // std::cout<<lcc.point()<<std::endl;
+  }
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC, unsigned int type> // type==1 for face, 2 for surface, 3 for volume
+class Pattern;
+////////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+class Pattern<LCC, 1> // Face pattern
+{
+  friend class Pattern_substituer<LCC>;
+
+  using Dart_handle=typename LCC::Dart_handle;
+  using size_type=typename LCC::size_type;
+  using Point=typename LCC::Point;
+  using Vector=typename LCC::Vector;
+public:
+  Pattern(): m_mark_to_preserve(LCC::INVALID_MARK)
+  {}
+
+  LCC& lcc()
+  { return m_lcc; }
+
+  size_type reserve_mark_to_preserve()
+  {
+    if(m_mark_to_preserve==LCC::INVALID_MARK)
+    { m_mark_to_preserve=m_lcc.get_new_mark(); }
+    return m_mark_to_preserve;
+  }
+
+  size_type mark_to_preserve() const
+  { return m_mark_to_preserve; }
+
+  std::vector<Barycentric_coord<LCC, 1>>& barycentric_coords()
+  { return m_barycentric_coords; }
+
+  void compute_barycentric_coord()
+  {
+    auto mark_vertices=m_lcc.get_new_mark();
+    for(auto it=m_lcc.darts().begin(), itend=m_lcc.darts().end(); it!=itend; ++it)
+    {
+      if(!m_lcc.is_marked(it, mark_vertices))
+      {
+        if(m_lcc.template is_free<2>(it)) // not an inner vertex
+        { m_lcc.template mark_cell<0>(it, mark_vertices); }
+      }
+    }
+
+    typename LCC::Point bary2=CGAL::ORIGIN;
+    std::vector<Dart_handle> boundary_darts;
+    std::vector<Dart_handle> inner_vertices;
+    std::size_t nb1=0;
+    auto vertex_treated=m_lcc.get_new_mark();
+    for(auto it=m_lcc.darts().begin(), itend=m_lcc.darts().end(); it!=itend; ++it)
+    {
+      if(m_lcc.template is_free<2>(it))
+      { boundary_darts.push_back(it); }
+      if(!m_lcc.is_marked(it, vertex_treated))
+      { // TODO we can improve the traversal of cells (regroup, use basic it...)
+        m_lcc.template mark_cell<0>(it, vertex_treated);
+        if(!m_lcc.is_marked(it, mark_vertices))
+        { // Here it is incident to an inner vertex
+          m_lcc.template mark_cell<0>(it, mark_vertices);
+          inner_vertices.push_back(it);
+        }
+        else // Here is is incident to a vertex of the boundary
+        {
+          const Point& p=m_lcc.point(it);
+          bary2=Point(bary2.x()+p.x(), bary2.y()+p.y(), bary2.z()+p.z());
+          ++nb1;
+        }
+      }
+    }
+    m_lcc.free_mark(mark_vertices);
+    m_lcc.free_mark(vertex_treated);
+    assert(nb1>0);
+    bary2=Point(bary2.x()/nb1, bary2.y()/nb1, bary2.z()/nb1);
+
+    nb1=0;
+    m_barycentric_coords.resize(inner_vertices.size());
+    for(auto it: inner_vertices)
+    {
+      m_barycentric_coords[nb1].m_coords.reserve(boundary_darts.size());
+      m_barycentric_coords[nb1].m_dart=it;
+      ++nb1;
+    }
+
+    double alpha, beta, gamma;
+    for(auto& itd: boundary_darts)
+    {
+      const Point& p0=m_lcc.point(itd);
+      const Point& p1=m_lcc.point(m_lcc.other_extremity(itd));
+      nb1=0;
+      for(auto& it: inner_vertices)
+      {
+        if(compute_alpha_beta_gamma_of_point(p0, p1, bary2, m_lcc.point(it),
+                                             alpha, beta, gamma))
+        {
+          m_barycentric_coords[nb1].m_coords.push_back
+              (std::make_tuple(itd, alpha, beta, gamma));
+        ++nb1;
+        }
+      }
+    }
+  }
+
+  void display()
+  {
+    for(auto& it: m_barycentric_coords)
+    { it.display(m_lcc); }
+  }
+
+protected:
+  LCC m_lcc;
+  typename LCC::size_type m_mark_to_preserve;
+  /// For each inner point, its barycentric coordinates for each external point
+  std::vector<Barycentric_coord<LCC, 1>> m_barycentric_coords;
+};
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+class Pattern<LCC, 2> // Surfacic pattern
+{
+  friend class Pattern_substituer<LCC>;
+
+  using Dart_handle=typename LCC::Dart_handle;
+  using size_type=typename LCC::size_type;
+  using Point=typename LCC::Point;
+  using Vector=typename LCC::Vector;
+public:
+  Pattern():
+    m_mark_faceborder(m_lcc.get_new_mark()),
+    m_mark_to_preserve(LCC::INVALID_MARK)
+  {}
+
+  LCC& lcc()
+  { return m_lcc; }
+
+  size_type reserve_mark_to_preserve()
+  {
+    if(m_mark_to_preserve==LCC::INVALID_MARK)
+    { m_mark_to_preserve=m_lcc.get_new_mark(); }
+    return m_mark_to_preserve;
+  }
+
+  size_type mark_to_preserve() const
+  { return m_mark_to_preserve; }
+
+  // same barycentric coords than for face => 1
+  std::vector<Barycentric_coord<LCC, 1>>& barycentric_coords()
+  { return m_barycentric_coords; }
+
+  void compute_barycentric_coord()
+  {
+    // Mark vertices that belong to a face border.
+    auto border_vertex=m_lcc.get_new_mark();
+    for(auto it=m_lcc.darts().begin(), itend=m_lcc.darts().end(); it!=itend; ++it)
+    {
+      if(!m_lcc.is_marked(it, border_vertex))
+      {
+        if(m_lcc.is_marked(it, m_mark_faceborder)) // not an inner vertex
+        { m_lcc.template mark_cell<0>(it, border_vertex); }
+      }
+    }
+
+    typename LCC::Point bary2=CGAL::ORIGIN;
+    std::vector<Dart_handle> boundary_darts;
+    std::vector<Dart_handle> inner_vertices;
+    std::size_t nb1=0, new_index=0;
+    Dart_handle cur, other;
+    auto treated=m_lcc.get_new_mark();
+    auto vertex_treated=m_lcc.get_new_mark();
+    std::queue<Dart_handle> to_treat;
+    for(auto it=m_lcc.darts().begin(), itend=m_lcc.darts().end(); it!=itend; ++it)
+    {
+      if(!m_lcc.is_marked(it, treated))
+      {
+        boundary_darts.clear();
+        inner_vertices.clear();
+        nb1=0;
+        bary2=CGAL::ORIGIN;
+
+        // Here we iterate through the cc of faces inside a same cycle of edges
+        // marked by m_mark_faceborder
+        to_treat.push(it);
+        m_lcc.mark(it, treated);
+        while(!to_treat.empty())
+        {
+          cur=to_treat.front();
+          to_treat.pop();
+
+          if(m_lcc.is_marked(cur, m_mark_faceborder))
+          {  boundary_darts.push_back(cur); }
+
+          if(!m_lcc.is_marked(cur, vertex_treated))
+          { // TODO we can improve the traversal of cells (regroup, use basic it...)
+            m_lcc.template mark_cell<0>(cur, vertex_treated);
+            if(!m_lcc.is_marked(cur, border_vertex))
+            { // Here it is incident to an inner vertex
+              inner_vertices.push_back(cur);
+            }
+            else // Here is is incident to a vertex of the boundary
+            {
+              const Point& p=m_lcc.point(cur);
+              bary2=Point(bary2.x()+p.x(), bary2.y()+p.y(), bary2.z()+p.z());
+              ++nb1;
+            }
+          }
+
+          other=m_lcc.template beta<1>(cur);
+          if(!m_lcc.is_marked(other, treated))
+          {
+            to_treat.push(other);
+            m_lcc.mark(other, treated);
+          }
+
+          if(!m_lcc.is_marked(cur, m_mark_faceborder))
+          {
+            other=m_lcc.template beta<2>(cur);
+            if(!m_lcc.is_marked(other, treated))
+            {
+              to_treat.push(other);
+              m_lcc.mark(other, treated);
+            }
+          }
+        }
+
+        assert(nb1>0);
+        // Now compute the barycentric coordinates of inner vertices
+        if(inner_vertices.size()>0)
+        {
+          bary2=Point(bary2.x()/nb1, bary2.y()/nb1, bary2.z()/nb1);
+
+          new_index=m_barycentric_coords.size();
+          nb1=new_index;
+          m_barycentric_coords.resize(m_barycentric_coords.size()+
+                                      inner_vertices.size());
+          for(auto iti: inner_vertices)
+          {
+            m_barycentric_coords[nb1].m_coords.reserve(boundary_darts.size());
+            m_barycentric_coords[nb1].m_dart=iti;
+            ++nb1;
+            if(m_lcc.is_marked(iti, vertex_treated))
+            { m_lcc.template unmark_cell<0>(iti, vertex_treated);}
+          }
+
+          double alpha, beta, gamma;
+          for(auto& itd: boundary_darts)
+          {
+            const Point& p0=m_lcc.point(itd);
+            const Point& p1=m_lcc.point(m_lcc.other_extremity(itd));
+            nb1=new_index;
+            for(auto& iti: inner_vertices)
+            {
+              if(compute_alpha_beta_gamma_of_point(p0, p1, bary2, m_lcc.point(iti),
+                                                   alpha, beta, gamma))
+              {
+                m_barycentric_coords[nb1].m_coords.push_back
+                    (std::make_tuple(itd, alpha, beta, gamma));
+                ++nb1;
+              }
+            }
+            if(m_lcc.is_marked(itd, vertex_treated))
+            { m_lcc.template unmark_cell<0>(itd, vertex_treated);}
+          }
+        }
+        else
+        {
+          for(auto& itd: boundary_darts)
+          {
+            if(m_lcc.is_marked(itd, vertex_treated))
+            { m_lcc.template unmark_cell<0>(itd, vertex_treated);}
+          }
+        }
+        assert(m_lcc.is_whole_map_unmarked(vertex_treated));
+      }
+    }
+    assert(m_lcc.is_whole_map_marked(treated));
+    m_lcc.free_mark(treated);
+    m_lcc.free_mark(border_vertex);
+    m_lcc.free_mark(vertex_treated);
+ }
+
+  void display()
+  {
+    for(auto& it: m_barycentric_coords)
+    { it.display(m_lcc); }
+  }
+
+protected:
+  LCC m_lcc;
+  typename LCC::size_type m_mark_faceborder;
+  typename LCC::size_type m_mark_to_preserve;
+  /// For each inner point, its barycentric coordinates for each external point
+  std::vector<Barycentric_coord<LCC, 1>> m_barycentric_coords;
+};
+////////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+class Pattern<LCC, 3> // Volumic pattern
+{
+  friend class Pattern_substituer<LCC>;
+
+  using Dart_handle=typename LCC::Dart_handle;
+  using size_type=typename LCC::size_type;
+  using Point=typename LCC::Point;
+  using Vector=typename LCC::Vector;
+public:
+  Pattern(): m_mark_to_preserve(LCC::INVALID_MARK)
+  {}
+
+  LCC& lcc()
+  { return m_lcc; }
+
+  size_type reserve_mark_to_preserve()
+  {
+    if(m_mark_to_preserve==LCC::INVALID_MARK)
+    { m_mark_to_preserve=m_lcc.get_new_mark(); }
+    return m_mark_to_preserve;
+  }
+
+  size_type mark_to_preserve() const
+  { return m_mark_to_preserve; }
+
+  std::vector<Barycentric_coord<LCC, 3>>& barycentric_coords()
+  { return m_barycentric_coords; }
+
+  void compute_barycentric_coord()
+  {
+    auto mark_vertices=m_lcc.get_new_mark();
+    for(auto it=m_lcc.darts().begin(), itend=m_lcc.darts().end(); it!=itend; ++it)
+    {
+      if(!m_lcc.is_marked(it, mark_vertices))
+      {
+        if(m_lcc.template is_free<3>(it)) // not an inner vertex
+        { m_lcc.template mark_cell<0>(it, mark_vertices); }
+      }
+    }
+
+    typename LCC::Point bary3=CGAL::ORIGIN;
+    std::vector<Dart_handle> boundary_darts;
+    std::vector<Dart_handle> inner_vertices;
+    std::size_t nb1=0;
+    auto vertex_treated=m_lcc.get_new_mark();
+    for(auto it=m_lcc.darts().begin(), itend=m_lcc.darts().end(); it!=itend; ++it)
+    {
+      if(m_lcc.template is_free<3>(it))
+      { boundary_darts.push_back(it); }
+      if(!m_lcc.is_marked(it, vertex_treated))
+      { // TODO we can improve the traversal of cells (regroup, use basic it...)
+        m_lcc.template mark_cell<0>(it, vertex_treated);
+        if(!m_lcc.is_marked(it, mark_vertices))
+        { // Here it is incident to an inner vertex
+          m_lcc.template mark_cell<0>(it, mark_vertices);
+          inner_vertices.push_back(it);
+        }
+        else // Here is is incident to a vertex of the boundary
+        {
+          const Point& p=m_lcc.point(it);
+          bary3=Point(bary3.x()+p.x(), bary3.y()+p.y(), bary3.z()+p.z());
+          ++nb1;
+        }
+      }
+    }
+    m_lcc.free_mark(mark_vertices);
+    m_lcc.free_mark(vertex_treated);
+    assert(nb1>0);
+    bary3=Point(bary3.x()/nb1, bary3.y()/nb1, bary3.z()/nb1);
+
+    nb1=0;
+    m_barycentric_coords.resize(inner_vertices.size());
+    for(auto it: inner_vertices)
+    {
+      m_barycentric_coords[nb1].m_coords.reserve(boundary_darts.size());
+      m_barycentric_coords[nb1].m_dart=it;
+      ++nb1;
+    }
+
+    double alpha, beta, gamma, delta;
+    for(auto& itd: boundary_darts)
+    {
+      const Point& p0=m_lcc.point(itd);
+      const Point& p1=m_lcc.point(m_lcc.other_extremity(itd));
+      const Point p2=m_lcc.template barycenter<2>(itd);
+      nb1=0;
+      for(auto& it: inner_vertices)
+      { // TODO we can test if tetra (p0, p1, p2, bary3) before to enter in the loop
+        if(compute_alpha_beta_gamma_delta_of_point(p0, p1, p2, bary3,
+                                                   m_lcc.point(it),
+                                                   alpha, beta, gamma, delta))
+        {
+          m_barycentric_coords[nb1].m_coords.push_back
+              (std::make_tuple(itd, alpha, beta, gamma, delta));
+          ++nb1;
+        }
+      }
+    }
+  }
+
+  void display()
+  {
+    for(auto& it: m_barycentric_coords)
+    { it.display(m_lcc); }
+  }
+
+protected:
+  LCC m_lcc;
+  size_type m_mark_to_preserve;
+  /// For each inner point, its barycentric coordinates for each external point
+  std::vector<Barycentric_coord<LCC, 3>> m_barycentric_coords;
+};
+////////////////////////////////////////////////////////////////////////////////
+#endif // CMAP_QUERY_REPLACE_GEOMETRY_H
diff --git a/src/cmap_signature.h b/src/cmap_signature.h
new file mode 100644
index 0000000000000000000000000000000000000000..23d48e0b8dea26b5fd3a0e29fd59ba8bbd09e5d1
--- /dev/null
+++ b/src/cmap_signature.h
@@ -0,0 +1,647 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CMAP_SIGNATURE_H
+#define CMAP_SIGNATURE_H
+
+#include <cassert>
+#include <unordered_map>
+#include <queue>
+#include <functional>
+#include <iostream>
+#include <boost/container_hash/hash.hpp>
+
+// We have 3 type of words:
+//      fword for faces; sword for surfaces; vword for volumes
+// 3 types of patterns:
+//      fpattern: a connected set of faces
+//      spattern: a closed surface (a set of connected faces without boundary)
+//      vpattern: a connected sef of volumes
+// and 3 types of signatures:
+//      fsignature; ssignature; vsignature
+///////////////////////////////////////////////////////////////////////////////
+using MyInt=std::uint16_t;
+using Signature=std::vector<MyInt>;
+////////////////////////////////////////////////////////////////////////////////
+namespace  std {
+template<>
+class hash<Signature>
+{
+public:
+  size_t operator() (const Signature& s) const
+  {
+    std::size_t seed=0;
+    for(auto n: s)
+    { boost::hash_combine(seed, n); }
+    return seed;
+  }
+};
+}
+////////////////////////////////////////////////////////////////////////////////
+void print_signature(const Signature& s)
+{
+  bool first=true;
+  std::cout<<"[";
+  for(auto n: s)
+  { if(!first) { std::cout<<" "; } else { first=false; } std::cout<<(int)n; }
+  std::cout<<"]  "<<std::hash<Signature>()(s)<<std::endl;
+}
+///////////////////////////////////////////////////////////////////////////////
+//// Signature for faces //////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the face word of the given map starting from a dart.
+/// Takes one function next as parameter, allowing to change
+/// the object considered (face or border of the fpattern)
+/// If signature is non empty, compare the current word with signature, and
+/// stop as soon as the word becomes bigger than signature.
+/// @return true iff the computed word is the new minimal one
+template<class CMAP>
+bool compute_fword_from_dart(CMAP& cmap,
+                             typename CMAP::Dart_handle dh,
+                             typename CMAP::size_type marktopreserve,
+                             Signature& word,
+                             const Signature& signature,
+                             std::function<typename CMAP::Dart_handle
+                             (typename CMAP::Dart_handle)> next,
+                             bool trace=false)
+{
+  word.clear();
+  if(marktopreserve!=CMAP::INVALID_MARK && !cmap.is_marked(dh, marktopreserve))
+  { return false; }
+
+  if(!signature.empty()) { word.reserve(signature.size()); }
+  MyInt nb=0;
+  typename CMAP::Dart_handle cur=dh;
+  bool same_prefix=true, bigger=false;
+  do
+  {
+    nb=0;
+    do
+    {
+      ++nb;
+      cur=next(cur);
+    }
+    while(cur!=dh &&
+          (marktopreserve==CMAP::INVALID_MARK ||
+           !cmap.is_marked(cur, marktopreserve)));
+    word.push_back(nb);
+    if(same_prefix && !signature.empty())
+    {
+      if(word.back()!=signature[word.size()-1])
+      {
+        same_prefix=false;
+        if(word.back()>signature[word.size()-1])
+        {
+          bigger=true;
+          assert(word>signature);
+        }
+      }
+    }
+  }
+  while(!bigger && cur!=dh);
+
+  if(trace)
+  {
+    bool first=true;
+    std::cout<<"[";
+    for(auto n: word)
+    { if(!first) { std::cout<<" "; } else { first=false; } std::cout<<(int)n; }
+    std::cout<<"]  "<<std::endl;
+  }
+
+  if(signature.empty() || (!bigger && !same_prefix))
+  {
+    assert(signature.empty() || word<signature);
+    return true; // word<signature
+  }
+  assert(!signature.empty() && word>=signature);
+  return false; // word>=signature
+
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the face signature of the given pattern.
+/// @pre cmap is a fpattern, i.e. a connected set of faces.
+/// @return the initial dart of the signature
+template<class CMAP>
+typename CMAP::Dart_handle fsignature_of_pattern(CMAP& cmap,
+                                                 typename CMAP::size_type marktopreserve,
+                                                 Signature& signature,
+                                                 bool trace=false)
+{
+  signature.clear();
+  typename CMAP::Dart_handle res=nullptr;
+  Signature current_word;
+
+  for(auto it=cmap.darts().begin(), itend=cmap.darts().end(); it!=itend; ++it)
+  {
+    if(cmap.template is_free<2>(it))
+    {
+      if(compute_fword_from_dart(cmap, it, marktopreserve, current_word, signature,
+
+                                 [&cmap](typename CMAP::Dart_handle dh)
+                                 -> typename CMAP::Dart_handle
+                                 { typename CMAP::Dart_handle other=
+                                 cmap.template beta<1>(dh);
+                                 while(!cmap.template is_free<2>(other))
+                                 { other=cmap.template beta<2,1>(other); }
+                                 return other;
+                                 },
+
+                                 trace))
+      {
+        res=it;
+        std::swap(current_word, signature);
+        if(signature.size()==1)
+        { return res; } // No need to test all starting darts if we have only one value
+      }
+    }
+  }
+  return res;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the face signature of the given face.
+/// @return the initial dart of the signature
+template<class CMAP>
+typename CMAP::Dart_handle fsignature_of_face_for_dart
+(CMAP& cmap, typename CMAP::Dart_handle dh,
+ typename CMAP::size_type marktopreserve, Signature& signature, bool trace=false)
+{
+  signature.clear();
+  typename CMAP::Dart_handle res=nullptr;
+  Signature current_word;
+
+  if(compute_fword_from_dart(cmap, dh, marktopreserve, current_word, signature,
+
+                             [&cmap](typename CMAP::Dart_handle dh)
+                             -> typename CMAP::Dart_handle
+                             { return cmap.template beta<1>(dh); },
+
+                             trace))
+  {
+    res=dh;
+    std::swap(current_word, signature);
+  }
+  return res;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the face signature of the given face.
+/// @return the initial dart of the signature
+template<class CMAP>
+typename CMAP::Dart_handle fsignature_of_face(CMAP& cmap,
+                                              typename CMAP::Dart_handle dh,
+                                              typename CMAP::size_type marktopreserve,
+                                              Signature& signature,
+                                              bool trace=false)
+{
+  signature.clear();
+  typename CMAP::Dart_handle res=nullptr;
+  Signature current_word;
+
+  typename CMAP::Dart_handle cur=dh;
+  do
+  {
+    if(compute_fword_from_dart(cmap, cur, marktopreserve, current_word, signature,
+
+                               [&cmap](typename CMAP::Dart_handle dh)
+                               -> typename CMAP::Dart_handle
+                               { return cmap.template beta<1>(dh); },
+
+                               trace))
+    {
+      res=cur;
+      std::swap(current_word, signature);
+      if(signature.size()==1)
+      { return res; } // No need to test all starting darts if we have only one value
+    }
+    cur=cmap.template beta<1>(cur);
+  }
+  while(cur!=dh);
+  return res;
+}
+///////////////////////////////////////////////////////////////////////////////
+//// Signature for volumes/////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the volume word of the given map starting from a dart.
+/// Takes two functions next and opposite as parameter, allowing to change
+/// the object considered (volume, surface...)
+/// If signature is non empty, compare the current word with signature, and
+/// stop as soon as the word becomes bigger than signature.
+/// @return true iff the computed word is the new minimal one
+template<class CMAP>
+bool compute_vword_from_dart(CMAP& cmap,
+                             typename CMAP::Dart_handle dh,
+                             typename CMAP::size_type marktopreserve,
+                             Signature& word,
+                             const Signature& signature,
+                             std::function<typename CMAP::Dart_handle
+                             (typename CMAP::Dart_handle)> next,
+                             std::function<typename CMAP::Dart_handle
+                             (typename CMAP::Dart_handle)> opposite,
+                             bool trace=false)
+{
+  word.clear();
+  if(marktopreserve!=CMAP::INVALID_MARK && !cmap.is_marked(dh, marktopreserve))
+  { return false; }
+
+  if(!signature.empty()) { word.reserve(signature.size()); }
+  typename CMAP::size_type amark=cmap.get_new_mark();
+  std::unordered_map<typename CMAP::Dart_handle, MyInt> indices;
+  std::queue<typename CMAP::Dart_handle> to_treat;
+  std::vector<typename CMAP::Dart_handle> to_unmark;
+  typename CMAP::Dart_handle cur, other;
+  bool same_prefix=true, bigger=false;
+  MyInt nb=1;
+
+  to_treat.push(dh);
+  cmap.mark(dh, amark);
+  to_unmark.push_back(dh);
+  indices[dh]=nb++;
+  while(!bigger && !to_treat.empty())
+  {
+    cur=to_treat.front();
+    to_treat.pop();
+
+    if(marktopreserve==CMAP::INVALID_MARK || cmap.is_marked(cur, marktopreserve))
+    {
+      word.push_back(0);
+      if(same_prefix && !signature.empty())
+      {
+        if(word.back()!=signature[word.size()-1])
+        {
+          same_prefix=false;
+          if(word.back()>signature[word.size()-1])
+          {
+            bigger=true;
+            assert(word>signature);
+          }
+        }
+      }
+    }
+
+    // Process next then opposite
+    for(auto f: {next, opposite})
+    {
+      other=f(cur);
+      assert(other!=cmap.null_handle);
+      if(!cmap.is_marked(other, amark))
+      {
+        to_treat.push(other);
+        cmap.mark(other, amark);
+        to_unmark.push_back(other);
+        assert(nb!=std::numeric_limits<MyInt>::max());
+        indices[other]=nb++;
+      }
+      assert(indices.count(other)==1);
+      word.push_back(indices[other]);
+      if(same_prefix && !signature.empty())
+      {
+        if(word.back()!=signature[word.size()-1])
+        {
+          same_prefix=false;
+          if(word.back()>signature[word.size()-1])
+          {
+            bigger=true;
+            assert(word>signature);
+          }
+        }
+      }
+    }
+  }
+
+  if(trace)
+  {
+    bool first=true;
+    std::cout<<"[";
+    for(auto n: word)
+    { if(!first) { std::cout<<" "; } else { first=false; } std::cout<<(int)n; }
+    std::cout<<"]  "<<std::endl;
+  }
+
+  for(auto dhtou: to_unmark)
+  { cmap.unmark(dhtou, amark); }
+  cmap.free_mark(amark);
+  if(signature.empty() || (!bigger && !same_prefix))
+  {
+    assert(signature.empty() || word<signature);
+    return true; // word<signature
+  }
+  assert(!signature.empty() && word>=signature);
+  return false; // word>=signature
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the volume signature of the given pattern.
+/// @pre cmap is a connected set of volumes.
+/// @return the initial dart of the signature
+template<class CMAP>
+typename CMAP::Dart_handle vsignature_of_pattern(CMAP& cmap,
+                                                 typename CMAP::size_type marktopreserve,
+                                                 Signature& signature,
+                                                 bool trace=false)
+{
+  signature.clear();
+  typename CMAP::Dart_handle res=nullptr;
+  Signature current_word;
+
+  for(auto it=cmap.darts().begin(), itend=cmap.darts().end(); it!=itend; ++it)
+  {
+    if(cmap.template is_free<3>(it))
+    {
+      if(compute_vword_from_dart(cmap, it, marktopreserve, current_word, signature,
+
+                                 [&cmap](typename CMAP::Dart_handle dh)
+                                 -> typename CMAP::Dart_handle
+                                 { return cmap.template beta<1>(dh); },
+
+                                 [&cmap](typename CMAP::Dart_handle dh)
+                                 -> typename CMAP::Dart_handle
+                                 { typename CMAP::Dart_handle other=
+                                 cmap.template beta<2>(dh);
+                                 while(!cmap.template is_free<3>(other))
+                                 { other=cmap.template beta<3,2>(other); }
+                                 return other;
+                                 },
+
+                                 trace))
+      {
+        res=it;
+        std::swap(current_word, signature);
+      }
+    }
+  }
+  return res;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the vsignature of one volume but only for the given dart.
+/// Function used only in order to validate all the patterns. Use
+/// vsignature_of_volume instead.
+/// @return the initial dart of the signature
+template<class CMAP>
+typename CMAP::Dart_handle vsignature_of_volume_for_dart
+(CMAP& cmap, typename CMAP::Dart_handle dh,
+ typename CMAP::size_type marktopreserve, Signature& signature, bool trace=false)
+{
+  signature.clear();
+  typename CMAP::Dart_handle res=nullptr;
+  Signature current_word;
+
+  if(compute_vword_from_dart(cmap, dh, marktopreserve, current_word, signature,
+
+                             [&cmap](typename CMAP::Dart_handle dh)
+                             -> typename CMAP::Dart_handle
+                             { return cmap.template beta<1>(dh); },
+
+                             [&cmap](typename CMAP::Dart_handle dh)
+                             -> typename CMAP::Dart_handle
+                             { return cmap.template beta<2>(dh); },
+
+                             trace))
+  {
+    res=dh;
+    std::swap(current_word, signature);
+  }
+  return res;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the vsignature of one volume.
+/// @return the initial dart of the signature
+template<class CMAP>
+typename CMAP::Dart_handle vsignature_of_volume(CMAP& cmap,
+                                                typename CMAP::Dart_handle dh,
+                                                typename CMAP::size_type marktopreserve,
+                                                Signature& signature,
+                                                bool trace=false)
+{
+  signature.clear();
+  typename CMAP::Dart_handle res=nullptr;
+  Signature current_word;
+
+  for(auto it=cmap.template darts_of_cell<3>(dh).begin(),
+        itend=cmap.template darts_of_cell<3>(dh).end(); it!=itend; ++it)
+  {
+    if(compute_vword_from_dart(cmap, it, marktopreserve, current_word, signature,
+
+                               [&cmap](typename CMAP::Dart_handle dh)
+                               -> typename CMAP::Dart_handle
+                                { return cmap.template beta<1>(dh); },
+
+                               [&cmap](typename CMAP::Dart_handle dh)
+                               -> typename CMAP::Dart_handle
+                                { return cmap.template beta<2>(dh); },
+
+                               trace))
+    {
+      res=it;
+      std::swap(current_word, signature);
+    }
+  }
+  return res;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the number of automorphisms of the vpattern of the given CMap,
+/// knowing its vsignature.
+/// @pre cmap is a vpattern, i.e. a connected set of volumes.
+template<class CMAP>
+std::size_t number_of_automorphisms_of_vpattern(CMAP& cmap,
+                                                typename CMAP::size_type marktopreserve,
+                                                const Signature& signature,
+                                                bool trace=false)
+{
+  Signature current_word;
+  std::size_t nb=0;
+
+  for(auto it=cmap.darts().begin(), itend=cmap.darts().end(); it!=itend; ++it)
+  {
+    if(cmap.template is_free<3>(it))
+    {
+      if(!compute_vword_from_dart(cmap, it, marktopreserve, current_word, signature,
+
+                                  [&cmap](typename CMAP::Dart_handle dh)
+                                  -> typename CMAP::Dart_handle
+                                  { return cmap.template beta<1>(dh); },
+
+                                  [&cmap](typename CMAP::Dart_handle dh)
+                                  -> typename CMAP::Dart_handle
+                                  { typename CMAP::Dart_handle other=
+                                  cmap.template beta<2>(dh);
+                                  while(!cmap.template is_free<3>(other))
+                                  { other=cmap.template beta<3,2>(other); }
+                                  return other;
+                                  },
+
+                                  trace))
+      {
+        // std::cout<<&*it<<"  "; print_signature(current_word);
+        if(current_word==signature) { ++nb; }
+      }
+    }
+  }
+  return nb;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the number of automorphisms of the volume, knowing its signature.
+template<class CMAP>
+std::size_t number_of_automorphisms_of_volume
+(CMAP& cmap, typename CMAP::Dart_handle dh,
+ const Signature& signature, typename CMAP::size_type marktopreserve,
+ bool trace=false)
+{
+  Signature current_word;
+  std::size_t nb=0;
+
+  for(auto it=cmap.template darts_of_cell<3>(dh).begin(),
+      itend=cmap.template darts_of_cell<3>(dh).end(); it!=itend; ++it)
+  {
+    if(!compute_vword_from_dart(cmap, it, marktopreserve, current_word, signature,
+
+                                [&cmap](typename CMAP::Dart_handle dh)
+                                -> typename CMAP::Dart_handle
+                                  { return cmap.template beta<1>(dh); },
+
+                                [&cmap](typename CMAP::Dart_handle dh)
+                                -> typename CMAP::Dart_handle
+                                 { return cmap.template beta<2>(dh); },
+
+                                trace))
+    {
+      if(current_word==signature) { ++nb; }
+    }
+  }
+  return nb;
+}
+///////////////////////////////////////////////////////////////////////////////
+//// Signature for surfaces////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Note: compute_vword_from_dart is reused to compute sword, only changing
+/// the next and opposite methods.
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the ssignature of the given pattern.
+/// @pre cmap is a spattern, i.e. a closed connected set of faces.
+/// @return the initial dart of the signature
+/// @note Be careful: contrary to f and vsignature, a ssignature does not exist
+///       without some darts marked as face borders. Indeed, without marked darts,
+///       it is not possible to know which edges are border of faces and which
+///       ones are not. Note that this mark is only used for the pattern, not
+///       for the target.
+template<class CMAP>
+typename CMAP::Dart_handle ssignature_of_pattern(CMAP& cmap,
+                                                 typename CMAP::size_type faceborder,
+                                                 typename CMAP::size_type marktopreserve,
+                                                 Signature& signature,
+                                                 bool trace=false)
+{
+  signature.clear();
+  typename CMAP::Dart_handle res=nullptr;
+  Signature current_word;
+
+  for(auto it=cmap.darts().begin(), itend=cmap.darts().end(); it!=itend; ++it)
+  {
+    if(cmap.is_marked(it, faceborder) &&
+       compute_vword_from_dart(cmap, it, marktopreserve, current_word, signature,
+
+                               [&cmap, faceborder](typename CMAP::Dart_handle dh)
+                               -> typename CMAP::Dart_handle
+                               { typename CMAP::Dart_handle other=
+                               cmap.template beta<1>(dh);
+                               while(!cmap.is_marked(other, faceborder))
+                               { other=cmap.template beta<2,1>(other); }
+                               return other;
+                               },
+
+                               [&cmap](typename CMAP::Dart_handle dh)
+                               -> typename CMAP::Dart_handle
+                                { return cmap.template beta<2>(dh); },
+
+                               trace))
+    {
+      res=it;
+      std::swap(current_word, signature);
+      if(signature.size()==1)
+      { return res; } // No need to test all starting darts if we have only one value
+    }
+  }
+  return res;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the ssignature of one surface.
+/// @return the initial dart of the signature
+template<class CMAP>
+typename CMAP::Dart_handle ssignature_of_surface_for_dart
+(CMAP& cmap, typename CMAP::Dart_handle dh,
+ typename CMAP::size_type marktopreserve, Signature& signature, bool trace=false)
+{
+  signature.clear();
+  typename CMAP::Dart_handle res=nullptr;
+  Signature current_word;
+
+  if(compute_vword_from_dart(cmap, dh, marktopreserve, current_word, signature,
+
+                             [&cmap](typename CMAP::Dart_handle dh)
+                             -> typename CMAP::Dart_handle
+                             { return cmap.template beta<1>(dh); },
+
+                             [&cmap](typename CMAP::Dart_handle dh)
+                             -> typename CMAP::Dart_handle
+                             { return cmap.template beta<2>(dh); },
+
+                             trace))
+  {
+    res=dh;
+    std::swap(current_word, signature);
+  }
+  return res;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Compute the ssignature of one surface.
+/// @return the initial dart of the signature
+template<class CMAP>
+typename CMAP::Dart_handle ssignature_of_surface(CMAP& cmap,
+                                                 typename CMAP::Dart_handle dh,
+                                                 typename CMAP::size_type marktopreserve,
+                                                 Signature& signature,
+                                                 bool trace=false)
+{
+  signature.clear();
+  typename CMAP::Dart_handle res=nullptr;
+  Signature current_word;
+
+  for(auto it=cmap.template darts_of_cell<3>(dh).begin(),
+        itend=cmap.template darts_of_cell<3>(dh).end(); it!=itend; ++it)
+  {
+    if(compute_vword_from_dart(cmap, it, marktopreserve, current_word, signature,
+
+                               [&cmap](typename CMAP::Dart_handle dh)
+                               -> typename CMAP::Dart_handle
+                                { return cmap.template beta<1>(dh); },
+
+                               [&cmap](typename CMAP::Dart_handle dh)
+                               -> typename CMAP::Dart_handle
+                                { return cmap.template beta<2>(dh); },
+
+                               trace))
+    {
+      res=it;
+      std::swap(current_word, signature);
+    }
+  }
+  return res;
+}
+///////////////////////////////////////////////////////////////////////////////
+#endif // CMAP_SIGNATURE_H
diff --git a/src/hexa-subdivision.cpp b/src/hexa-subdivision.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..749673154d7066147d5366aed4dd21c88e136f6b
--- /dev/null
+++ b/src/hexa-subdivision.cpp
@@ -0,0 +1,1664 @@
+// Copyright (c) 2011 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+
+// Prog that uses the query/replace method to generate transitions
+// for hexaedral meshes (based on the work of Claudio).
+// It uses the 325 vpatterns in hexa-325-patterns
+// and the 5 fpatterns in square-5-patterns
+
+#include <CGAL/Linear_cell_complex_for_combinatorial_map.h>
+#include <CGAL/Linear_cell_complex_operations.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/draw_linear_cell_complex.h>
+#include <CGAL/Polyhedron_3.h>
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_face_graph_triangle_primitive.h>
+#include <CGAL/Side_of_triangle_mesh.h>
+#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
+#include <CGAL/Aff_transformation_3.h>
+#include <CGAL/aff_transformation_tags.h>
+
+#include <map>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "cmap_copy.h"
+#include "cmap_query_replace.h"
+#include "Compute_stats.h"
+#include "init_to_preserve_for_query_replace.h"
+#include "lcc_read_depending_extension.h"
+#include "lcc_save_load_mesh.h"
+#include "Print_txt.h"
+
+////////////////////////////////////////////////////////////////////////////////
+typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+typedef Kernel::FT       FT;
+typedef Kernel::Point_3  Point;
+typedef Kernel::Vector_3 Vector;
+////////////////////////////////////////////////////////////////////////////////
+template<typename Refs>
+struct My_vertex: public CGAL::Cell_attribute_with_point<Refs>
+{
+  using Base=CGAL::Cell_attribute_with_point<Refs>;
+
+  My_vertex():
+    m_outside(false),
+    m_new_vertex(false)
+  {}
+
+  My_vertex(const Point& p):
+    Base(p),
+    m_outside(false),
+    m_new_vertex(false)
+  {}
+
+  bool m_outside; // Use to compute marching cube
+  bool m_new_vertex; // Use to compute marching cube
+};
+////////////////////////////////////////////////////////////////////////////////
+class Myitems
+{
+public:
+  template < class Refs >
+  struct Dart_wrapper
+  {
+    typedef My_vertex<Refs> Vertex_attrib;
+    typedef CGAL::Cell_attribute<Refs, unsigned int> Volume_attrib;
+    typedef std::tuple<Vertex_attrib, void, void, Volume_attrib> Attributes;
+  };
+};
+typedef CGAL::Linear_cell_complex_traits<3,Kernel> Mytraits;
+typedef CGAL::Linear_cell_complex_for_combinatorial_map<3,3,Mytraits,Myitems> LCC3;
+
+// The last template argument CGAL::Tag_true allows to use concurent compact
+// container instead of compact container => thread safe
+/* typedef CGAL::Linear_cell_complex_for_combinatorial_map
+       <3,3,Mytraits,Myitems,CGAL_ALLOCATOR(int),
+       CGAL::Combinatorial_map_base,
+       CGAL::CMap_linear_cell_complex_storage_1
+            <3, 3, Mytraits, Myitems, CGAL_ALLOCATOR(int),
+          // CGAL::Tag_false>>
+          CGAL::Tag_true>>
+    LCC3; */
+
+typedef typename LCC3::Dart_handle Dart_handle;
+typedef typename LCC3::Vertex_attribute_handle Vertex_handle;
+typedef typename LCC3::Attribute_handle<3>::type Volume_handle;
+typedef typename LCC3::size_type   size_type;
+
+typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
+typedef CGAL::AABB_face_graph_triangle_primitive<Polyhedron> Primitive;
+typedef CGAL::AABB_traits<Kernel, Primitive> Traits;
+typedef CGAL::AABB_tree<Traits> Tree;
+typedef typename Kernel::Triangle_3 Triangle;
+typedef typename Kernel::Segment_3 Segment;
+typedef CGAL::Side_of_triangle_mesh<Polyhedron, Kernel> Side_of_mesh;
+
+////////////////////////////////////////////////////////////////////////////////
+[[ noreturn ]] void usage(int /*argc*/, char** argv)
+{
+  // Name
+  std::cout<<"Name"<<std::endl;
+  std::cout<<"        "<<argv[0]<<" - subdivides the given off file in hexahedra.";
+  std::cout<<std::endl<<std::endl;
+  // Synopsis
+  std::cout<<"SYNOPSIS"<<std::endl;
+  std::cout<<"        "<<argv[0]<<" [--help|-h|-?] "
+           <<"[-create-transitions] [-draw] [-init X] [-lmax L] [-marching-cubes]"
+           <<"[-no-remove-outside] [-no-signature] [-save] [-smooth] "
+           <<"[-truncated-cubes] filename"
+           <<std::endl<<std::endl;
+  // Description
+  std::cout<<"DESCRIPTION"<<std::endl;
+  std::cout<<"        "<<" subdivides the given off file in hexahedra."
+           <<std::endl<<std::endl;
+  // Options
+  std::cout<<"        --help, -h, -?"<<std::endl
+           <<"                display this help and exit."
+           <<std::endl<<std::endl;
+  std::cout<<"        -create-transitions"<<std::endl
+           <<"                use the 325 patterns to create transitions between hexahedra with 1 level of difference"
+           <<std::endl<<std::endl;
+  std::cout<<"        -draw"<<std::endl
+           <<"                draw the final lcc."
+           <<std::endl<<std::endl;
+  std::cout<<"        -init X"<<std::endl
+           <<"                fix the number of hexa in x axis to X (2 by default). Number of hexa in Y and Z are automatically computed to try to keep the ratio of the initial bounding box."
+           <<std::endl<<std::endl;
+  std::cout<<"        -lmax L"<<std::endl
+           <<"                gives the maximum subdvision level (4 by default)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -marching-cubes"<<std::endl
+           <<"                create an approximation of the surface using marching cube method (imply !create-transition !no-remove-outside and !smooth)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -no-remove-outside"<<std::endl
+           <<"                do not remove outside hexa."
+           <<std::endl<<std::endl;
+  std::cout<<"        -no-signature"<<std::endl
+           <<"                do not use signature to test isomorphism (but classical method)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -save"<<std::endl
+           <<"                save the lcc resulting of the subdvision (format mesh)."
+           <<std::endl;
+  std::cout<<"        -smooth"<<std::endl
+           <<"                smooth the final volumic mesh. Contrary to marching-cubes keep all the volumes instead of creating a surface."
+           <<std::endl<<std::endl;
+  std::cout<<"        -truncated-cubes"<<std::endl
+           <<"                create a mesh with truncated cubes instead of cube (imply all hexa with same level and !marching-cubes !smooth)."
+           <<std::endl<<std::endl;
+  exit(EXIT_FAILURE);
+}
+////////////////////////////////////////////////////////////////////////////////
+[[ noreturn ]] void error_command_line(int argc, char** argv, const char* msg)
+{
+  std::cout<<"ERROR: "<<msg<<std::endl;
+  usage(argc, argv);
+}
+////////////////////////////////////////////////////////////////////////////////
+void process_command_line(int argc, char** argv,
+                          std::string& filename,
+                          bool& create_transitions,
+                          bool& draw,
+                          unsigned int& initX,
+                          unsigned int& lmax,
+                          bool& marching_cubes,
+                          bool& no_remove_outside,
+                          bool& no_signature,
+                          bool& save,
+                          bool& smooth,
+                          bool& truncated_cubes
+                          )
+{
+  filename="";
+  create_transitions=false;
+  draw=false;
+  initX=2;
+  lmax=4;
+  marching_cubes=false;
+  no_remove_outside=false;
+  no_signature=false;
+  save=false;
+  smooth=false;
+  truncated_cubes=false;
+
+  bool helprequired=false;
+  std::string arg;
+  for (int i=1; i<argc; ++i)
+  {
+    arg=std::string(argv[i]);
+    if(arg==std::string("-h") || arg==std::string("--help") || arg==std::string("-?"))
+    { helprequired=true; }
+    else if(arg=="-create-transitions")
+    { create_transitions=true; }
+    else if(arg=="-draw")
+    { draw=true; }
+    else if(arg=="-init")
+    {
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "no numbers after -init"); }
+      initX=std::stoi(std::string(argv[++i]));
+    }
+    else if(arg=="-lmax")
+    {
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "no number after -lmax"); }
+      lmax=std::stoi(std::string(argv[++i]));
+    }
+    else if(arg=="-marching-cubes")
+    { marching_cubes=true; }
+    else if(arg=="-no-remove-outside")
+    { no_remove_outside=true; }
+    else if(arg=="-no-signature")
+    { no_signature=true; }
+    else if(arg=="-save")
+    { save=true; }
+    else if(arg=="-smooth")
+    { smooth=true; }
+    else if(arg=="-truncated-cubes")
+    { truncated_cubes=true; }
+    else if(arg[0]=='-')
+    { std::cout<<"Unknown option "<<arg<<", ignored."<<std::endl; }
+    else { filename=arg; }
+  }
+  if (helprequired || filename.empty()) { usage(argc, argv); }
+
+  if(truncated_cubes) { create_transitions=false; marching_cubes=false; smooth=false; }
+  if(marching_cubes) { create_transitions=false; no_remove_outside=false; smooth=false; }
+}
+///////////////////////////////////////////////////////////////////////////////
+/* To check the intersection between a particular square (given by its four
+ * points) and the aabbtree t
+*/
+bool is_intersect(double x1, double y1, double z1,
+                  double x2, double y2, double z2,
+                  double x3, double y3, double z3,
+                  double x4, double y4, double z4,
+                  const Tree& t)
+{
+  Kernel::Point_3 p1(x1,y1,z1);
+  Kernel::Point_3 p2(x2,y2,z2);
+  Kernel::Point_3 p3(x3,y3,z3);
+  Kernel::Point_3 p4(x4,y4,z4);
+
+  // And compute the two triangles
+  Triangle t1(p1, p2, p3);
+  if(t.do_intersect(t1))
+  { return true; }
+
+  t1=Triangle(p1, p3, p4);
+  if(t.do_intersect(t1))
+  { return true; }
+
+  return false;
+}
+///////////////////////////////////////////////////////////////////////////////
+/* Test the intersection between a particular voxel (given by its two
+ * extremal points) and the aabbtree t
+*/
+bool is_intersect(double x1, double y1, double z1,
+                  double x2, double y2, double z2,
+                  const Tree& t)
+{
+  return
+      is_intersect(x1,y1,z1, x2,y1,z1, x2,y1,z2, x1,y1,z2, t) || // f1 y1
+      is_intersect(x2,y2,z1, x2,y1,z1, x2,y1,z2, x2,y2,z2, t) || // f2 x2
+      is_intersect(x1,y2,z1, x2,y2,z1, x2,y2,z2, x1,y2,z2, t) || // f3 y2
+      is_intersect(x1,y1,z1, x1,y1,z2, x1,y2,z2, x1,y2,z1, t) || // f4 x1
+      is_intersect(x1,y1,z1, x2,y1,z1, x2,y2,z1, x1,y2,z1, t) || // f5 z1
+      is_intersect(x1,y1,z2, x2,y1,z2, x2,y2,z2, x1,y2,z2, t);   // f6 z2
+}
+///////////////////////////////////////////////////////////////////////////////
+/* Test if a particular point is outside of the object (Tree), knowing there is
+ * no intersection between its voxel and the tree.
+ */
+bool is_outside_knowing_no_intersect(const Kernel::Point_3& p,
+                                     const Tree& t)
+{
+  Side_of_mesh s(t);
+  CGAL::Bounded_side res=s(p);
+  return res!=CGAL::ON_BOUNDED_SIDE; // && !=CGAL::ON_BOUNDARY ?
+}
+///////////////////////////////////////////////////////////////////////////////
+/* Test if a particular voxel (given by its two extremal points) is outside
+   * of the object (Tree).
+   */
+bool is_outside(double x1, double y1, double z1,
+                double x2, double y2, double z2,
+                const Tree& t)
+{
+  if (is_intersect(x1, y1, z1, x2, y2, z2, t)) { return false; }
+  return is_outside_knowing_no_intersect(Kernel::Point_3(x1, y1, z1), t);
+}
+///////////////////////////////////////////////////////////////////////////////
+/* Test the intersection between a particular voxel of the LCC3
+ * and the Tree (variable t - the object - created from the load of a surface mesh file).
+ * (Rq: the variable lcc represents a set of voxels - a block of voxels of the grid).
+ */
+bool is_intersect(LCC3& lcc, Dart_handle dh, const Tree& t)
+{
+  CGAL::Bbox_3 bbox=lcc.point(dh).bbox();
+  // For each vertex of the volume
+  for(auto it=lcc.one_dart_per_incident_cell<0,3>(dh).begin(),
+      itend=lcc.one_dart_per_incident_cell<0,3>(dh).end(); it!=itend; ++it)
+  { bbox+=lcc.point(it).bbox(); }
+
+  return is_intersect(bbox.xmin(), bbox.ymin(), bbox.zmin(),
+                      bbox.xmax(), bbox.ymax(), bbox.zmax(), t);
+}
+///////////////////////////////////////////////////////////////////////////////
+/* Test if a particular voxel of the LCC3 (lcc) is outside of the object (Tree).
+ * (Rq: the variable lcc represents a set of voxels - a block of voxels of the grid).
+ */
+bool is_outside(LCC3& lcc, Dart_handle dh, const Tree& t)
+{
+  CGAL::Bbox_3 bbox=lcc.point(dh).bbox();
+  // For each vertex of the volume
+  for(auto it=lcc.one_dart_per_incident_cell<0,3>(dh).begin(),
+      itend=lcc.one_dart_per_incident_cell<0,3>(dh).end(); it!=itend; ++it)
+  { bbox+=lcc.point(it).bbox(); }
+
+  return is_outside(bbox.xmin(), bbox.ymin(), bbox.zmin(),
+                    bbox.xmax(), bbox.ymax(), bbox.zmax(), t);
+}
+////////////////////////////////////////////////////////////////////////////////
+void count_subdivisions(LCC3& lcc, std::map<std::size_t, std::size_t>& levels)
+{
+  levels.clear();
+  unsigned int mylevel;
+  for(auto it=lcc.attributes<3>().begin(), itend=lcc.attributes<3>().end();
+      it!=itend; ++it)
+  {
+    mylevel=lcc.info_of_attribute<3>(it);
+    auto l=levels.find(mylevel);
+    if(l==levels.end())
+    { levels[mylevel]=1; }
+    else
+    { ++(l->second); }
+  }
+  for(auto it: levels)
+  { std::cout<<it.first<<"->"<<it.second<<"  "; }
+  std::cout<<std::endl;
+}
+void count_subdivisions(LCC3& lcc)
+{
+  std::map<std::size_t, std::size_t> levels;
+  count_subdivisions(lcc, levels);
+}
+///////////////////////////////////////////////////////////////////////////////
+LCC3::Dart_handle make_one_hexa(LCC3& lcc, double x1, double y1, double z1,
+                                double x2, double y2, double z2)
+{
+  LCC3::Dart_handle dh = lcc.make_hexahedron
+    (LCC3::Point(x1, y1, z1),
+     LCC3::Point(x2, y1, z1),
+     LCC3::Point(x2, y2, z1),
+     LCC3::Point(x1, y2, z1),
+     LCC3::Point(x1, y2, z2),
+     LCC3::Point(x1, y1, z2),
+     LCC3::Point(x2, y1, z2),
+     LCC3::Point(x2, y2, z2));
+  return dh;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Create a block of (nbx x nby x nbz) hexa. External hexa are not created.
+/// First hexa starts at position (startx, starty, starty) and each hexa has size
+/// (sizex, sizey, sizez)
+void create_hexa_that_intersect(LCC3& lcc,
+                                const Tree& t,
+                                unsigned int nbx, unsigned int nby, unsigned nbz,
+                                double startx, double starty, double startz,
+                                double sizex, double sizey, double sizez)
+{
+  Dart_handle dh;
+  double x1, y1, z1, x2, y2, z2;
+  for (unsigned int x=0; x<nbx; ++x)
+  {
+    for (unsigned int y=0; y<nby; ++y)
+    {
+      for (unsigned int z=0; z<nbz; ++z)
+      {
+        x1=startx+x*sizex; y1=starty+y*sizey; z1=startz+z*sizez;
+        x2=startx+(x+1)*sizex; y2=starty+(y+1)*sizey; z2=startz+(z+1)*sizez;
+        if (!is_outside(x1, y1, z1, x2, y2, z2, t))
+        {
+          dh=make_one_hexa(lcc,x1, y1, z1, x2, y2, z2);
+          lcc.set_attribute<3>(dh, lcc.create_attribute<3>(0));
+        }
+      }
+    }
+  }
+  lcc.sew3_same_facets();
+}
+///////////////////////////////////////////////////////////////////////////////
+void compute_size_and_init(unsigned int init, const Tree& aabb_tree,
+                           int& longestAxis,
+                           double& sx, double& sy, double& sz,
+                           unsigned int& initX,
+                           unsigned int& initY,
+                           unsigned int& initZ)
+{
+  sx=(aabb_tree.bbox().xmax()-aabb_tree.bbox().xmin());
+  sy=(aabb_tree.bbox().ymax()-aabb_tree.bbox().ymin());
+  sz=(aabb_tree.bbox().zmax()-aabb_tree.bbox().zmin());
+
+  if (sx>=sy && sx>=sz)     longestAxis = 0;
+  else if(sy>=sx && sy>=sz) longestAxis = 1;
+  else                      longestAxis = 2;
+
+  if(longestAxis == 0)
+  {
+    initX = init;
+    initY = std::ceil(init * (sy / sx));
+    initZ = std::ceil(init * (sz / sx));
+  }
+  else if(longestAxis == 1)
+  {
+    initX = std::ceil(init * (sx / sy));
+    initY = init;
+    initZ = std::ceil(init * (sz / sy));
+  }
+  else
+  {
+    initX = std::ceil(init * (sx / sz));
+    initY = std::ceil(init * (sy / sz));
+    initZ = init;
+  }
+
+  sx/=initX;
+  sy/=initY;
+  sz/=initZ;
+}
+///////////////////////////////////////////////////////////////////////////////
+bool create_initial_voxels(const std::string& file,
+                           LCC3& lcc,
+                           unsigned int init,
+                           CGAL::Polyhedron_3<Kernel>& surface,
+                           Tree& aabb_tree)
+{
+  // 1) Load surface mesh
+  std::ifstream off_file(file);
+  if(!off_file.good()) return false; // File open error
+
+  std::chrono::system_clock::time_point start2=std::chrono::system_clock::now();
+
+  surface.clear();
+  off_file>>surface;
+  CGAL::Polygon_mesh_processing::triangulate_faces(surface);
+
+  std::chrono::duration<double> diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Load off: ", diff, "s.");
+
+  // 2) Compute AABB tree
+  start2 = std::chrono::system_clock::now();
+
+  aabb_tree.insert(faces(surface).first, faces(surface).second, surface);
+  aabb_tree.accelerate_distance_queries();
+  aabb_tree.bbox();
+
+  diff = std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Compute AABB tree: ", diff, "s.");
+
+  // std::cout<<"AABB tree bbox="<<aabb_tree.bbox()<<std::endl;
+
+  double sx, sy, sz;
+  int longestAxis;    // 0 = x, 1 = y, 2 = z
+  unsigned int initX, initY, initZ;
+  compute_size_and_init(init, aabb_tree, longestAxis, sx, sy, sz,
+                        initX, initY, initZ);
+
+  start2 = std::chrono::system_clock::now();
+
+  // 3) Create a block of hexahedra
+  create_hexa_that_intersect(lcc, aabb_tree,
+                             initX, initY, initZ,
+                             aabb_tree.bbox().xmin(),
+                             aabb_tree.bbox().ymin(),
+                             aabb_tree.bbox().zmin(),
+                             sx, sy, sz);
+
+  diff = std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Create block of hexa: ", diff, "s.");
+
+  return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+void subdivide_edges(LCC3& lcc,
+                     const std::vector<Dart_handle>& hexa_tosubdivide,
+                     size_type corner_mark)
+{
+  size_type amark=lcc.get_new_mark();
+  std::vector<Dart_handle> edges_to_subdivide;
+  edges_to_subdivide.reserve(hexa_tosubdivide.size()); // a la louche ;)
+
+  for(Dart_handle its: hexa_tosubdivide)
+  {
+    for(auto itd=lcc.darts_of_cell<3>(its).begin(),
+        itdend=lcc.darts_of_cell<3>(its).end(); itd!=itdend; ++itd)
+    {
+      if(!lcc.is_marked(itd, amark) && lcc.is_marked(itd, corner_mark) &&
+         lcc.is_marked(lcc.beta<2>(itd), corner_mark))
+      {
+        lcc.mark_cell<1>(itd, amark);
+        edges_to_subdivide.push_back(itd);
+      }
+    }
+  }
+
+  for(Dart_handle itd: edges_to_subdivide)
+  {
+    lcc.unmark_cell<1>(itd, amark);
+    lcc.insert_barycenter_in_cell<1>(itd);
+  }
+
+  assert(lcc.is_whole_map_unmarked(amark));
+  lcc.free_mark(amark);
+}
+////////////////////////////////////////////////////////////////////////////////
+void subdivide_faces(LCC3& lcc,
+                     const std::vector<Dart_handle>& hexa_tosubdivide,
+                     size_type corner_mark,
+                     Pattern_substituer<LCC3>& ps,
+                     std::size_t& nb_replaced)
+{
+  size_type amark=lcc.get_new_mark();
+  std::vector<Dart_handle> faces_to_subdivide;
+  faces_to_subdivide.reserve(hexa_tosubdivide.size()); // a la louche ;)
+  for(Dart_handle its: hexa_tosubdivide)
+  {
+    for(auto itd=lcc.darts_of_cell<3>(its).begin(),
+        itdend=lcc.darts_of_cell<3>(its).end(); itd!=itdend; ++itd)
+    {
+      if(!lcc.is_marked(itd, amark) && lcc.is_marked(itd, corner_mark) &&
+         lcc.beta<1,1,1,1>(itd)!=itd)
+      {
+        lcc.mark_cell<2>(itd, amark);
+        faces_to_subdivide.push_back(itd);
+      }
+    }
+  }
+
+  for(Dart_handle itd: faces_to_subdivide)
+  {
+    lcc.unmark_cell<2>(itd, amark);   
+    /*if(ps.query_replace_one_face(lcc, itd, corner_mark)==
+       std::numeric_limits<std::size_t>::max())
+    { std::cout<<"[ERROR] in subdivide_faces: one query/replace failed."
+               <<std::endl;
+      / *LCC3 lcc_error;
+      copy_cell<3>(lcc, itd, lcc_error);
+      for(auto itnewv=lcc.one_dart_per_incident_cell<2,3>(itd).begin(),
+          itnewvend=lcc.one_dart_per_incident_cell<2,3>(itd).end(); itnewv!=itnewvend; ++itnewv)
+      {
+        if(!lcc.is_free<3>(itnewv))
+        { copy_cell<3>(lcc, lcc.beta<3>(itnewv), lcc_error); }
+      }
+      CGAL::draw(lcc_error);
+      * /
+    }*/
+    ps.replace_one_face_from_dart(lcc, itd, ps.m_fpatterns[0],
+                                  ps.m_fsignatures.begin()->second.first);
+    ++nb_replaced;
+  }
+
+  assert(lcc.is_whole_map_unmarked(amark));
+  lcc.free_mark(amark);
+}
+////////////////////////////////////////////////////////////////////////////////
+void subdivide_volumes(LCC3& lcc,
+                       const std::vector<Dart_handle>& hexa_tosubdivide,
+                       size_type corner_mark,
+                       Pattern_substituer<LCC3>& ps,
+                       std::size_t& nb_replaced)
+{
+  std::vector<Dart_handle> vol_darts;
+  vol_darts.reserve(96);
+  Dart_handle corner_dart=nullptr;
+
+  for(Dart_handle its: hexa_tosubdivide)
+  {
+    vol_darts.clear();
+    corner_dart=nullptr;
+    for(auto it=lcc.darts_of_cell<3>(its).begin(),
+        itend=lcc.darts_of_cell<3>(its).end(); it!=itend; ++it)
+    {
+      if(!lcc.is_marked(it, corner_mark)) { vol_darts.push_back(it); }
+      else if(corner_dart==nullptr) { corner_dart=it; }
+    }
+
+    lcc.info<3>(its)=1+lcc.info<3>(its);
+    /* if(ps.query_replace_one_volume(lcc, its, corner_mark)==
+       std::numeric_limits<std::size_t>::max())
+    { std::cout<<"[ERROR] in subdivide_volumes: one query/replace failed."
+              <<std::endl; } */
+    ps.replace_one_volume_from_dart(lcc, corner_dart, ps.m_vpatterns[0],
+                                    ps.m_vsignatures.begin()->second.first);
+    ++nb_replaced;
+
+    // Mark all old darts of the 8 volume as corners
+    for(Dart_handle itv: vol_darts)
+    {
+      if(!lcc.is_marked(itv, corner_mark))
+      {
+        for(auto itnewv=lcc.darts_of_cell<3>(itv).begin(),
+            itnewvend=lcc.darts_of_cell<3>(itv).end(); itnewv!=itnewvend; ++itnewv)
+        { lcc.mark(itnewv, corner_mark); }
+      }
+    }
+  }
+}
+////////////////////////////////////////////////////////////////////////////////
+void subdivide_hexa(LCC3& lcc, Dart_handle dh, LCC3::size_type corner_mark,
+                    Pattern_substituer<LCC3>& ps)
+{
+  size_type mark_to_preserve_v=lcc.get_new_mark();
+  mark_volume_corners<LCC3>(lcc, dh, mark_to_preserve_v);
+  std::vector<Dart_handle> tounmark;
+  //size_type mark_to_preserve_s=lcc.get_new_mark();
+  std::unordered_set<Vertex_handle> vertices;
+  std::vector<Dart_handle> one_dart_per_corner;
+  one_dart_per_corner.reserve(8);
+
+  lcc.info<3>(dh)=1+lcc.info<3>(dh);
+
+  // 1) Subdivide each edge which is not yet subdivide
+  std::vector<Dart_handle> tosubdivide;
+  for(auto it=lcc.darts_of_cell<3>(dh).begin(),
+      itend=lcc.darts_of_cell<3>(dh).end(); it!=itend; ++it)
+  {
+    if(it<lcc.beta<2>(it)) // considere only one dart per edge of the hexa
+    {
+      if(lcc.is_marked(it, corner_mark) && lcc.is_marked(lcc.beta<2>(it), corner_mark))
+      { tosubdivide.push_back(it); }
+    }
+    if(lcc.is_marked(it, corner_mark) && vertices.count(lcc.vertex_attribute(it))==0)
+    {
+      one_dart_per_corner.push_back(it);
+      vertices.insert(lcc.vertex_attribute(it));
+    }
+    tounmark.push_back(it);
+  }
+  assert(one_dart_per_corner.size()==8);
+
+  for(auto it: tosubdivide)
+  { lcc.insert_barycenter_in_cell<1>(it); }
+
+  // 2) Subdivide faces.
+  tosubdivide.clear();
+  for(auto it=lcc.one_dart_per_incident_cell<2,3>(dh).begin(),
+      itend=lcc.one_dart_per_incident_cell<2,3>(dh).end(); it!=itend; ++it)
+  { tosubdivide.push_back(it); }
+
+  for(auto it: tosubdivide)
+  { ps.query_replace_one_face(lcc, it, mark_to_preserve_v); }
+
+  // 3) Subdivide the hexa itself
+  ps.query_replace_one_volume(lcc, dh, mark_to_preserve_v);
+
+  // 4) Mark all darts of the 8 volume as corners
+  for(auto itv: one_dart_per_corner)
+  {
+    std::size_t nb=0;
+    for(auto it=lcc.darts_of_cell<3>(itv).begin(),
+        itend=lcc.darts_of_cell<3>(itv).end(); it!=itend; ++it)
+    { lcc.mark(it, corner_mark); ++nb; }
+    assert(nb==24);
+  }
+
+  for(auto it: tounmark)
+  { lcc.unmark(it, mark_to_preserve_v); }
+  assert(lcc.is_whole_map_unmarked(mark_to_preserve_v));
+  lcc.free_mark(mark_to_preserve_v);
+
+  // assert(lcc.is_valid());
+}
+////////////////////////////////////////////////////////////////////////////////
+std::size_t compute_hexa_to_subdivide_for_truncated_cubes
+(LCC3& lcc,
+ const Tree& aabb_tree,
+ bool no_remove_outside,
+ std::vector<std::vector<Dart_handle>>& hexa_tosubdivide)
+{
+  std::size_t res=0;
+  for(auto& it: hexa_tosubdivide)
+  { it.clear(); }
+
+  std::queue<Volume_handle> totreat;
+  unsigned int mylevel;
+  for (auto it=lcc.attributes<3>().begin(); it!=lcc.attributes<3>().end(); ++it)
+  {
+    mylevel=lcc.info_of_attribute<3>(it);
+    if(is_intersect(lcc, lcc.dart_of_attribute<3>(it), aabb_tree))
+    {
+      totreat.push(it);
+      hexa_tosubdivide[mylevel].push_back(lcc.dart_of_attribute<3>(it));
+      ++res;
+    }
+    else if(!no_remove_outside &&
+            is_outside_knowing_no_intersect
+            (lcc.point(lcc.dart_of_attribute<3>(it)), aabb_tree))
+    { lcc.remove_cell<3>(lcc.dart_of_attribute<3>(it)); }
+    else // Hexa inside
+    {
+      totreat.push(it);
+      hexa_tosubdivide[mylevel].push_back(lcc.dart_of_attribute<3>(it));
+      ++res;
+    }
+  }
+  return res;
+}
+////////////////////////////////////////////////////////////////////////////////
+std::size_t compute_hexa_to_subdivide(LCC3& lcc,
+                                      const Tree& aabb_tree,
+                                      unsigned int curlevel,
+                                      bool no_remove_outside,
+                                      bool marching_cubes,
+                                      std::vector<std::vector<Dart_handle>>&
+                                      hexa_tosubdivide)
+{
+  std::size_t res=0;
+
+  for(auto& it: hexa_tosubdivide)
+  { it.clear(); }
+
+  std::queue<Volume_handle> totreat;
+  unsigned int mylevel;
+  size_type treated=lcc.get_new_mark();
+  for (auto it=lcc.attributes<3>().begin(); it!=lcc.attributes<3>().end(); ++it)
+  {
+    mylevel=lcc.info_of_attribute<3>(it);
+    if (mylevel==curlevel)
+    {
+      if(is_intersect(lcc, lcc.dart_of_attribute<3>(it), aabb_tree))
+      {
+        totreat.push(it);
+        assert(lcc.dart_of_attribute<3>(it)!=nullptr);
+        hexa_tosubdivide[mylevel].push_back(lcc.dart_of_attribute<3>(it));
+        ++res;
+        lcc.mark_cell<3>(lcc.dart_of_attribute<3>(it), treated);
+      }
+      else if(marching_cubes ||
+              (!no_remove_outside &&
+               is_outside_knowing_no_intersect
+               (lcc.point(lcc.dart_of_attribute<3>(it)), aabb_tree)))
+      { lcc.remove_cell<3>(lcc.dart_of_attribute<3>(it)); }
+    }
+  }
+  if(!marching_cubes)
+  {
+    Volume_handle curvh;
+    while(!totreat.empty())
+    {
+      curvh=totreat.front();
+      totreat.pop();
+      mylevel=lcc.info_of_attribute<3>(curvh);
+      // Test all neighboors of curvh
+      for(auto it=lcc.darts_of_cell<3>(lcc.dart_of_attribute<3>(curvh)).begin(),
+          itend=lcc.darts_of_cell<3>(lcc.dart_of_attribute<3>(curvh)).end();
+          it!=itend; ++it)
+      {
+        // Adjacency through faces AND edges !
+        for(auto ite=lcc.darts_of_cell<1>(it).begin(),
+            iteend=lcc.darts_of_cell<1>(it).end(); ite!=iteend; ++ite)
+        {
+          if(!lcc.is_marked(ite, treated) && mylevel==1+lcc.info<3>(ite))
+          {
+            totreat.push(lcc.attribute<3>(ite));
+            hexa_tosubdivide[lcc.info<3>(ite)].push_back(ite);
+            ++res;
+            lcc.mark_cell<3>(ite, treated);
+          }
+        }
+      }
+    }
+  }
+  lcc.free_mark(treated);
+  return res;
+}
+////////////////////////////////////////////////////////////////////////////////
+void compute_marching_cubes(LCC3& lcc, size_type corner_mark,
+                            const Tree& aabb_tree, bool no_signature)
+{
+  std::chrono::system_clock::time_point start=std::chrono::system_clock::now();
+  std::chrono::system_clock::time_point start2=std::chrono::system_clock::now();
+  Pattern_substituer<LCC3> ps2; // pattern substituer to create transitions
+  ps2.load_vpatterns("data/marching-cubes/vpattern/",
+                     mark_vpattern_corners<LCC3>);
+  ps2.load_fpatterns("data/marching-cubes/fpattern/",
+                     mark_fpattern_corners<LCC3>);
+  std::chrono::duration<double> diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Load transition patterns: ", diff, "s.");
+
+  start2 = std::chrono::system_clock::now();
+  Side_of_mesh s(aabb_tree);
+  for (auto it=lcc.attributes<0>().begin(); it!=lcc.attributes<0>().end(); ++it)
+  {
+    it->m_outside=(s(lcc.point_of_vertex_attribute(it))!=
+        CGAL::ON_BOUNDED_SIDE);  //CGAL::ON_UNBOUNDED_SIDE);
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Compute inside/outside: ", diff, "s.");
+
+  // 1) Split edges
+  start2 = std::chrono::system_clock::now();
+  std::vector<Dart_handle> to_subdivide;
+  to_subdivide.reserve(lcc.number_of_attributes<3>()); // a la louche ;)
+  std::size_t nb_replaced_f=0;
+  std::size_t nb_replaced_v=0;
+  
+  for(auto itd=lcc.one_dart_per_cell<1>().begin(),
+      itdend=lcc.one_dart_per_cell<1>().end(); itd!=itdend; ++itd)
+  {
+    if(lcc.vertex_attribute(itd)->m_outside!=
+       lcc.vertex_attribute(lcc.other_extremity(itd))->m_outside)
+    { to_subdivide.push_back(itd); }
+  }
+
+  for(Dart_handle itd: to_subdivide)
+  {
+    FT d1=std::sqrt(aabb_tree.squared_distance(lcc.point(itd)));
+    FT d2=std::sqrt(aabb_tree.squared_distance(lcc.point(lcc.other_extremity(itd))));
+    Vector v(lcc.point(itd), lcc.point(lcc.other_extremity(itd)));
+    FT lg=std::sqrt(v.squared_length());
+    Point p1=lcc.point(itd);
+    Point p2=lcc.point(lcc.other_extremity(itd));
+    p1=p1.transform(Kernel::Aff_transformation_3(CGAL::TRANSLATION, (v*d1)/lg));
+    p2=p2.transform(Kernel::Aff_transformation_3(CGAL::TRANSLATION, (-v*d2)/lg));
+    auto newv=lcc.insert_point_in_cell<1>(itd, Point((p1.x()+p2.x())/2,
+                                                     (p1.y()+p2.y())/2,
+                                                     (p1.z()+p2.z())/2));
+    lcc.vertex_attribute(newv)->m_outside=false; // new vertices belong to the surface => no outside
+    lcc.vertex_attribute(newv)->m_new_vertex=true;
+    // Complicated computation; but try to deal with the case where the surface
+    // intersect the edge several times.
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Split edges: ", diff, "s.");
+
+  // 2) Replace faces
+  to_subdivide.clear();
+  start2=std::chrono::system_clock::now();
+  for(auto itd=lcc.one_dart_per_cell<2>().begin(),
+      itdend=lcc.one_dart_per_cell<2>().end(); itd!=itdend; ++itd)
+  {
+    if(lcc.beta<1,1,1,1>(itd)!=itd)
+    { to_subdivide.push_back(itd); }
+  }
+  if(no_signature)
+  {
+    for(auto itf: to_subdivide)
+    {
+      ps2.query_replace_one_face_without_signature(lcc, itf, corner_mark);
+      ++nb_replaced_f;
+    }
+  }
+  else
+  {
+    for(auto itf: to_subdivide)
+    {
+      ps2.query_replace_one_face(lcc, itf, corner_mark);
+      ++nb_replaced_f;
+    }
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Replace faces: ", diff, "s.");
+
+  auto markfaces=lcc.get_new_mark();
+  lcc.negate_mark(markfaces); // All darts of voxel faces are marked
+
+  // 3) Replace volumes
+  to_subdivide.clear();
+  start2=std::chrono::system_clock::now();
+  for(auto itv=lcc.attributes<3>().begin(),
+      itvend=lcc.attributes<3>().end(); itv!=itvend; ++itv)
+  {
+    if(!lcc.is_volume_combinatorial_hexahedron(lcc.dart_of_attribute<3>(itv)))
+    { to_subdivide.push_back(lcc.dart_of_attribute<3>(itv)); }
+  }
+  if(no_signature)
+  {
+    for(auto itv: to_subdivide)
+    {
+      ps2.query_replace_one_volume_without_signature(lcc, itv, corner_mark);
+      ++nb_replaced_v;
+    }
+  }
+  else
+  {
+    for(auto itv: to_subdivide)
+    {
+      ps2.query_replace_one_volume(lcc, itv, corner_mark);
+      ++nb_replaced_v;
+    }
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Replace volumes: ", diff, "s.");
+
+  // 4) Remove external faces
+  start2=std::chrono::system_clock::now();
+  lcc.set_automatic_attributes_management(false);
+  for(auto it=lcc.darts().begin(); it!=lcc.darts().end(); ++it)
+  {
+    if(lcc.is_marked(it, markfaces))
+    {
+      bool newface=true;
+      Dart_handle curdh=it;
+      do
+      {
+        if(!lcc.vertex_attribute(curdh)->m_new_vertex)
+        { newface=false; }
+        else
+        { curdh=lcc.beta<1>(curdh); }
+      }
+      while(newface && curdh!=it);
+      if(!newface)
+      { lcc.remove_cell<2>(it); }
+      else
+      { lcc.unmark_cell<2>(it, markfaces); }
+    }
+  }
+  assert(lcc.is_whole_map_unmarked(markfaces));
+  lcc.free_mark(markfaces);
+
+  // Now we have two volume (isomorphic) and 3-sew => remove one out of the two
+  // lcc.remove_cell<3>(lcc.first_dart()); // TODO PB when several cc !
+  lcc.set_automatic_attributes_management(true);
+
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Remove outside faces: ", diff, "s.");
+
+  // End
+  diff=std::chrono::system_clock::now()-start;
+  print_txt_with_endl("Compute marching cube TOTAL: ", diff, "s.");
+
+  std::cout<<"#faces-replaced: "<<nb_replaced_f<<", #volumes-replaced: "<<nb_replaced_v<<std::endl;
+}
+////////////////////////////////////////////////////////////////////////////////
+void smooth_mesh(LCC3& lcc, size_type corner_mark, const Tree& aabb_tree,
+                 bool no_signature)
+{
+  std::chrono::system_clock::time_point start=std::chrono::system_clock::now();
+  std::chrono::system_clock::time_point start2=std::chrono::system_clock::now();
+  Pattern_substituer<LCC3> ps2; // pattern substituer to create transitions
+  ps2.load_vpatterns("data/marching-cubes/vpattern/",
+                     mark_vpattern_corners<LCC3>);
+  ps2.load_fpatterns("data/marching-cubes/fpattern/",
+                     mark_fpattern_corners<LCC3>);
+  std::chrono::duration<double> diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Load transition patterns: ", diff, "s.");
+
+  start2 = std::chrono::system_clock::now();
+  Side_of_mesh s(aabb_tree);
+  for (auto it=lcc.attributes<0>().begin(); it!=lcc.attributes<0>().end(); ++it)
+  {
+    it->m_outside=(s(lcc.point_of_vertex_attribute(it))!=
+                   CGAL::ON_BOUNDED_SIDE);  //CGAL::ON_UNBOUNDED_SIDE);
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Compute inside/outside: ", diff, "s.");
+
+  bool mark_to_subdivide=lcc.get_new_mark();
+  // 1) Split edges
+  start2 = std::chrono::system_clock::now();
+  size_type amark=lcc.get_new_mark();
+  std::vector<Dart_handle> to_subdivide;
+  to_subdivide.reserve(lcc.number_of_attributes<3>()); // a la louche ;)
+  std::size_t nb_replaced_f=0;
+  std::size_t nb_replaced_v=0;
+  
+  for(auto itd=lcc.darts().begin(), itdend=lcc.darts().end(); itd!=itdend; ++itd)
+  {
+    if(!lcc.is_marked(itd, amark) &&
+       lcc.vertex_attribute(itd)->m_outside!=
+       lcc.vertex_attribute(lcc.other_extremity(itd))->m_outside)
+    {
+      for(auto ite=lcc.darts_of_cell_basic<1>(itd, amark).begin(),
+          iteend=lcc.darts_of_cell_basic<1>(itd, amark).end(); ite!=iteend; ++ite)
+      {
+        lcc.mark(ite, amark);
+        if(!lcc.is_marked(ite, mark_to_subdivide) &&
+           lcc.is_volume_combinatorial_hexahedron(ite))
+        { lcc.mark_cell<3>(ite, mark_to_subdivide); }
+      }
+      to_subdivide.push_back(itd);
+    }
+  }
+
+  for(Dart_handle itd: to_subdivide)
+  {
+    lcc.unmark_cell<1>(itd, amark);
+    FT d1=std::sqrt(aabb_tree.squared_distance(lcc.point(itd)));
+    FT d2=std::sqrt(aabb_tree.squared_distance(lcc.point(lcc.other_extremity(itd))));
+    Vector v(lcc.point(itd), lcc.point(lcc.other_extremity(itd)));
+    FT lg=std::sqrt(v.squared_length());
+    Point p1=lcc.point(itd);
+    Point p2=lcc.point(lcc.other_extremity(itd));
+    p1=p1.transform(Kernel::Aff_transformation_3(CGAL::TRANSLATION, (v*d1)/lg));
+    p2=p2.transform(Kernel::Aff_transformation_3(CGAL::TRANSLATION, (-v*d2)/lg));
+    auto newv=lcc.insert_point_in_cell<1>(itd, Point((p1.x()+p2.x())/2,
+                                                     (p1.y()+p2.y())/2,
+                                                     (p1.z()+p2.z())/2));
+    lcc.vertex_attribute(newv)->m_outside=false; // new vertices belong to the surface => no outside
+    lcc.vertex_attribute(newv)->m_new_vertex=true;
+    // Complicated computation; but try to deal with the case where the surface
+    // intersect the edge several times.
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Split edges: ", diff, "s.");
+  assert(lcc.is_whole_map_unmarked(amark));
+
+  // 2) Replace faces
+  to_subdivide.clear();
+  start2=std::chrono::system_clock::now();
+  for(auto itd=lcc.darts().begin(), itdend=lcc.darts().end();
+      itd!=itdend; ++itd)
+  {
+    if(!lcc.is_marked(itd, amark) && lcc.is_marked(itd, mark_to_subdivide) &&
+       lcc.beta<1,1,1,1>(itd)!=itd)
+    {
+      lcc.mark_cell<2>(itd, amark);
+      to_subdivide.push_back(itd);
+    }
+  }
+  if(no_signature)
+  {
+    for(auto itf: to_subdivide)
+    {
+      lcc.unmark_cell<2>(itf, amark);
+      ps2.query_replace_one_face_without_signature(lcc, itf, corner_mark);
+      ++nb_replaced_f;
+    }
+  }
+  else
+  {
+    for(auto itf: to_subdivide)
+    {
+      lcc.unmark_cell<2>(itf, amark);
+      ps2.query_replace_one_face(lcc, itf, corner_mark);
+      ++nb_replaced_f;
+    }
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Replace faces: ", diff, "s.");
+  assert(lcc.is_whole_map_unmarked(amark));
+
+  // 3) Replace volumes
+  to_subdivide.clear();
+  start2=std::chrono::system_clock::now();
+  for(auto itd=lcc.darts().begin(), itdend=lcc.darts().end();
+      itd!=itdend; ++itd)
+  {
+    if(lcc.is_marked(itd, mark_to_subdivide))
+    {
+      for(auto itv=lcc.darts_of_cell<3>(itd).begin(),
+          itvend=lcc.darts_of_cell<3>(itd).end(); itv!=itvend; ++itv)
+      { lcc.unmark(itv, mark_to_subdivide); }
+      if(!lcc.is_volume_combinatorial_hexahedron(itd))
+      { to_subdivide.push_back(itd); }
+    }
+  }
+  if(no_signature)
+  {
+    for(auto itv: to_subdivide)
+    {
+      ps2.query_replace_one_volume_without_signature(lcc, itv, corner_mark);
+      ++nb_replaced_v;
+    }
+  }
+  else
+  {
+    for(auto itv: to_subdivide)
+    {
+      ps2.query_replace_one_volume(lcc, itv, corner_mark);
+      ++nb_replaced_v;
+    }
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Replace volumes: ", diff, "s.");
+  assert(lcc.is_whole_map_unmarked(amark));
+  lcc.free_mark(amark);
+  assert(lcc.is_whole_map_unmarked(mark_to_subdivide));
+  lcc.free_mark(mark_to_subdivide);
+
+  // 4) Remove external faces
+  start2=std::chrono::system_clock::now();
+  auto markfaces=lcc.get_new_mark();
+  lcc.set_automatic_attributes_management(false);
+  for(auto it=lcc.darts().begin(); it!=lcc.darts().end(); ++it)
+  {
+    if(!lcc.is_marked(it, markfaces))
+    {
+      bool outside=false;
+      Dart_handle curdh=it;
+      do
+      {
+        if(lcc.vertex_attribute(curdh)->m_outside &&
+           !lcc.vertex_attribute(curdh)->m_new_vertex)
+        { outside=true; }
+        lcc.mark(curdh, markfaces);
+        if(!lcc.is_free<3>(curdh))
+        { lcc.mark(lcc.beta<3>(curdh), markfaces); }
+        curdh=lcc.beta<1>(curdh);
+      }
+      while(curdh!=it);
+      if(outside)
+      { lcc.remove_cell<2>(it); }
+    }
+  }
+  assert(lcc.is_whole_map_marked(markfaces));
+  lcc.free_mark(markfaces);
+
+  // Now we have two volume (isomorphic) and 3-sew => remove one out of the two
+  // lcc.remove_cell<3>(lcc.first_dart()); // TODO PB when several cc !
+  lcc.set_automatic_attributes_management(true);
+
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Remove outside faces: ", diff, "s.");
+
+  // End
+  diff=std::chrono::system_clock::now()-start;
+  print_txt_with_endl("Compute marching cube TOTAL: ", diff, "s.");
+
+  std::cout<<"#faces-replaced: "<<nb_replaced_f<<", #volumes-replaced: "<<nb_replaced_v<<std::endl;
+}
+////////////////////////////////////////////////////////////////////////////////
+void create_transition_patterns(LCC3& lcc, size_type corner_mark,
+                                bool no_signature)
+{
+  std::chrono::system_clock::time_point start=std::chrono::system_clock::now();
+  std::chrono::system_clock::time_point start2=std::chrono::system_clock::now();
+  Pattern_substituer<LCC3> ps2; // pattern substituer to create transitions
+  ps2.load_vpatterns("data/hexa-325-patterns/",
+                     mark_vpattern_corners<LCC3>);
+  ps2.load_fpatterns("data/square-5-patterns",
+                     mark_fpattern_corners<LCC3>);
+  std::chrono::duration<double> diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Load transition patterns: ", diff, "s.");
+
+  start2 = std::chrono::system_clock::now();
+  // size_type mark_to_preserve=lcc.get_new_mark();
+  std::vector<Dart_handle> faces;
+  std::vector<Dart_handle> volumes;
+  std::size_t nb_replaced_f=0;
+  std::size_t nb_replaced_v=0;
+  
+  cell_topo t;
+  for(auto it=lcc.attributes<3>().begin(); it!=lcc.attributes<3>().end(); ++it)
+  {
+    t=get_cell_topo(lcc, lcc.dart_of_attribute<3>(it));
+    if(t==GENERIC_3D)
+    { volumes.push_back(lcc.dart_of_attribute<3>(it)); }
+  }
+  for(auto curdh: volumes)
+  {
+    // mark_volume_corners(lcc, curdh, mark_to_preserve);
+    faces.clear();
+    for(auto itf=lcc.one_dart_per_incident_cell<2,3>(curdh).begin(),
+        itfend=lcc.one_dart_per_incident_cell<2,3>(curdh).end(); itf!=itfend; ++itf)
+    { faces.push_back(itf); }
+    if(no_signature)
+    {
+      for(auto itf: faces)
+      {
+        ps2.query_replace_one_face_without_signature(lcc, itf, corner_mark);
+        ++nb_replaced_f;
+      }
+    }
+    else
+    {
+      for(auto itf: faces)
+      {
+        ps2.query_replace_one_face(lcc, itf, corner_mark);
+        ++nb_replaced_f;
+      }
+    }
+
+    std::size_t res;
+    if(no_signature)
+    {
+      res=ps2.query_replace_one_volume_without_signature(lcc, curdh, corner_mark);
+      ++nb_replaced_v;
+    }
+    else
+    {
+      res=ps2.query_replace_one_volume(lcc, curdh, corner_mark);
+      ++nb_replaced_v;
+    }
+    if(res==std::numeric_limits<std::size_t>::max())
+    {
+      std::cout<<"[ERROR] transition not found for volume "
+                    <<lcc.attributes<3>().index(lcc.attribute<3>(curdh))
+                   <<std::endl;
+      static unsigned int nberror=0;
+      LCC3 lcc_error;
+      copy_cell<3>(lcc, curdh, lcc_error);
+      CGAL::draw(lcc_error);
+      save_object_3D(std::string("error"+std::to_string(nberror++)+
+                                 ".mesh"), lcc_error);
+    }
+  }
+  // lcc.free_mark(mark_to_preserve);
+  diff=std::chrono::system_clock::now()-start;
+  print_txt_with_endl("Create transitions TOTAL: ", diff, "s.");
+
+  std::cout<<"#faces-replaced: "<<nb_replaced_f<<", #volumes-replaced: "<<nb_replaced_v<<std::endl;
+}
+////////////////////////////////////////////////////////////////////////////////
+void create_truncated_cubes(LCC3& lcc, size_type corner_mark,
+                            bool no_signature)
+{
+  std::chrono::system_clock::time_point start=std::chrono::system_clock::now();
+  std::chrono::system_clock::time_point start2=std::chrono::system_clock::now();
+  Pattern_substituer<LCC3> ps2; // pattern substituer to create transitions
+  ps2.load_vpatterns("data/hexa-to-truncated-cube/vpattern/",
+                     mark_vpattern_corners<LCC3>);
+  ps2.load_fpatterns("data/hexa-to-truncated-cube/fpattern/",
+                     mark_fpattern_corners<LCC3>);
+  std::chrono::duration<double> diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Load transition patterns: ", diff, "s.");
+
+  // 1) Split edges
+  start2 = std::chrono::system_clock::now();
+  std::vector<Dart_handle> to_treat;
+  to_treat.reserve(lcc.number_of_attributes<3>()); // a la louche ;)
+  for(auto itd=lcc.one_dart_per_cell<1>().begin(),
+      itdend=lcc.one_dart_per_cell<1>().end(); itd!=itdend; ++itd)
+  { to_treat.push_back(itd); }
+
+  for(Dart_handle itd: to_treat)
+  {
+    Dart_handle itd2=lcc.beta<2>(itd);
+    Vector v(lcc.point(itd), lcc.point(itd2));
+    Point p1=lcc.point(itd);
+    Point p2=lcc.point(itd2);
+    p1=p1.transform(Kernel::Aff_transformation_3(CGAL::TRANSLATION, v/3.6));
+    p2=p2.transform(Kernel::Aff_transformation_3(CGAL::TRANSLATION, -v/3.6));
+    lcc.insert_point_in_cell<1>(itd, p1);
+    lcc.insert_point_in_cell<1>(itd2, p2);
+  }
+
+  to_treat.clear();
+  for(auto itd=lcc.one_dart_per_cell<3>().begin(),
+      itdend=lcc.one_dart_per_cell<3>().end(); itd!=itdend; ++itd)
+  { to_treat.push_back(itd); }
+  
+  std::size_t nb_replaced_f=0;
+  std::size_t nb_replaced_v=0;
+  
+  // size_type mark_to_preserve=lcc.get_new_mark();
+  std::vector<Dart_handle> faces;
+  for(auto curdh: to_treat)
+  {
+    // mark_volume_corners(lcc, curdh, mark_to_preserve);
+    faces.clear();
+    for(auto itf=lcc.one_dart_per_incident_cell<2,3>(curdh).begin(),
+        itfend=lcc.one_dart_per_incident_cell<2,3>(curdh).end(); itf!=itfend; ++itf)
+    { faces.push_back(itf); }
+    if(no_signature)
+    {
+      for(auto itf: faces)
+      {
+        ps2.query_replace_one_face_without_signature(lcc, itf, corner_mark);
+        ++nb_replaced_f;
+      }
+    }
+    else
+    {
+      for(auto itf: faces)
+      {
+        ps2.query_replace_one_face(lcc, itf, corner_mark);
+        ++nb_replaced_f;
+      }
+    }
+
+    std::size_t res;
+    if(no_signature)
+    {
+      res=ps2.query_replace_one_volume_without_signature(lcc, curdh, corner_mark);
+      ++nb_replaced_v;
+    }
+    else
+    {
+      res=ps2.query_replace_one_volume(lcc, curdh, corner_mark);
+      ++nb_replaced_v;
+    }
+    if(res==std::numeric_limits<std::size_t>::max())
+    {
+      std::cout<<"[ERROR] transition not found for volume "
+                    <<lcc.attributes<3>().index(lcc.attribute<3>(curdh))
+                   <<std::endl;
+      static unsigned int nberror=0;
+      LCC3 lcc_error;
+      copy_cell<3>(lcc, curdh, lcc_error);
+      CGAL::draw(lcc_error);
+      save_object_3D(std::string("error"+std::to_string(nberror++)+
+                                 ".mesh"), lcc_error);
+    }
+  }
+  to_treat.clear();
+  for(auto itd=lcc.one_dart_per_cell<2>().begin(),
+      itdend=lcc.one_dart_per_cell<2>().end(); itd!=itdend; ++itd)
+  {
+    if(lcc.beta<1,1,1>(itd)==itd && !lcc.is_free<3>(itd) &&
+       itd<lcc.beta<3>(itd) &&
+       lcc.is_volume_combinatorial_tetrahedron(itd) &&
+       lcc.is_volume_combinatorial_tetrahedron(lcc.beta<3>(itd)))
+    { to_treat.push_back(itd);  }
+  }
+  for(auto itd: to_treat)
+  { lcc.remove_cell<2>(itd); }
+
+  // lcc.free_mark(mark_to_preserve);
+  diff=std::chrono::system_clock::now()-start;
+  print_txt_with_endl("Create truncated cubes TOTAL: ", diff, "s.");
+
+  std::cout<<"#faces-replaced: "<<nb_replaced_f<<", #volumes-replaced: "<<nb_replaced_v<<std::endl;
+}
+////////////////////////////////////////////////////////////////////////////////
+/* TODO
+   void chamfer_edges(LCC3& lcc, size_type corner_mark, bool no_signature)
+{
+  std::chrono::system_clock::time_point start=std::chrono::system_clock::now();
+  std::chrono::system_clock::time_point start2=std::chrono::system_clock::now();
+
+  Pattern_substituer<LCC3> ps1; // pattern substituer to subdivide cube
+  ps1.load_fpatterns("data/hexa-8-subdivision/fpattern/",
+                     mark_fpattern_corners<LCC3>);
+  ps1.load_vpatterns("data/hexa-8-subdivision/vpattern/",
+                     mark_vpattern_corners<LCC3>);
+
+  Pattern_substituer<LCC3> ps2; // pattern substituer to chamfer edges
+  ps2.load_vpatterns("data/chamfer-cube/vpatterns/",
+                     mark_vpattern_corners<LCC3>);
+  ps2.load_fpatterns("data/chamfer-cube/fpatterns/",
+                     mark_fpattern_corners<LCC3>);
+
+  std::chrono::duration<double> diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Load transition patterns: ", diff, "s.");
+
+  auto oldmark=lcc.get_new_mark();
+  lcc.negate_mark(oldmark); // all "old" darts are marked
+
+  // 1) Compute hexa to chamfer
+  start2 = std::chrono::system_clock::now();
+  std::vector<Dart_handle> to_subdivide;
+  to_subdivide.reserve(lcc.number_of_attributes<3>()); // a la louche ;)
+  std::vector<Dart_handle> edges_to_chamfer;
+  edges_to_chamfer.reserve(lcc.number_of_attributes<3>()); // a la louche ;)
+  auto markvol=lcc.get_new_mark();
+
+  for(auto itd=lcc.one_dart_per_cell<1>().begin(),
+      itdend=lcc.one_dart_per_cell<1>().end(); itd!=itdend; ++itd)
+  {
+    if(CGAL::degree<LCC3, 1>(lcc, itd)==2) // Edge incident to exactly 2 faces
+    {
+      if(!lcc.is_marked(itd, markvol))
+      {
+        to_subdivide.push_back(itd);
+        lcc.mark_cell<3>(itd, markvol);
+      }
+      edges_to_chamfer.push_back(itd);
+      edges_to_chamfer.push_back(lcc.beta<2>(itd));
+    }
+  }
+
+  // 2) Split hexa in 8
+  subdivide_edges(lcc, to_subdivide, corner_mark);
+  subdivide_faces(lcc, to_subdivide, corner_mark, ps1);
+  subdivide_volumes(lcc, to_subdivide, corner_mark, ps1);
+
+  // 3) Insert vertices adjacent to edges to chamfer
+  for(Dart_handle itd: edges_to_chamfer)
+  {
+    for(Dart_handle itn: {lcc.beta<0>(itd) / * TODO ,XXX, XXX * /}) // TODO split 4 adjacent edges
+    {
+      Vector v(lcc.point(itn), lcc.point(lcc.other_extremity(itn)));
+      Point p1=lcc.point(itn);
+      p1=p1.transform(Kernel::Aff_transformation_3(CGAL::TRANSLATION, v/6));
+      lcc.insert_point_in_cell<1>(itn, p1);
+    }
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Split edges: ", diff, "s.");
+
+  // 2) Replace faces
+  to_subdivide.clear();
+  start2=std::chrono::system_clock::now();
+  for(auto itd=lcc.one_dart_per_cell<2>().begin(),
+      itdend=lcc.one_dart_per_cell<2>().end(); itd!=itdend; ++itd)
+  {
+    if(lcc.beta<1,1,1,1>(itd)!=itd)
+    { to_subdivide.push_back(itd); }
+  }
+  if(no_signature)
+  {
+    for(auto itf: to_subdivide)
+    { ps2.query_replace_one_face_without_signature(lcc, itf, corner_mark); }
+  }
+  else
+  {
+    for(auto itf: to_subdivide)
+    { ps2.query_replace_one_face(lcc, itf, corner_mark); }
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Replace faces: ", diff, "s.");
+
+  auto markfaces=lcc.get_new_mark();
+  lcc.negate_mark(markfaces); // All darts of voxel faces are marked
+
+  // 3) Replace volumes
+  to_subdivide.clear();
+  start2=std::chrono::system_clock::now();
+  for(auto itv=lcc.attributes<3>().begin(),
+      itvend=lcc.attributes<3>().end(); itv!=itvend; ++itv)
+  {
+    if(!lcc.is_volume_combinatorial_hexahedron(lcc.dart_of_attribute<3>(itv)))
+    { to_subdivide.push_back(lcc.dart_of_attribute<3>(itv)); }
+  }
+  if(no_signature)
+  {
+    for(auto itv: to_subdivide)
+    { ps2.query_replace_one_volume_without_signature(lcc, itv, corner_mark); }
+  }
+  else
+  {
+    for(auto itv: to_subdivide)
+    { ps2.query_replace_one_volume(lcc, itv, corner_mark); }
+  }
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Replace volumes: ", diff, "s.");
+
+  // 4) Remove external volumes and merge 8 volumes split in 2)
+  start2=std::chrono::system_clock::now();
+  lcc.set_automatic_attributes_management(false);
+  for(auto it=lcc.darts().begin(); it!=lcc.darts().end(); ++it)
+  {
+    if(lcc.is_marked(it, markfaces))
+    {
+      bool newface=true;
+      Dart_handle curdh=it;
+      do
+      {
+        if(!lcc.vertex_attribute(curdh)->m_new_vertex)
+        { newface=false; }
+        else
+        { curdh=lcc.beta<1>(curdh); }
+      }
+      while(newface && curdh!=it);
+      if(!newface)
+      { lcc.remove_cell<2>(it); }
+      else
+      { lcc.unmark_cell<2>(it, markfaces); }
+    }
+  }
+  assert(lcc.is_whole_map_unmarked(markfaces));
+  lcc.free_mark(markfaces);
+
+  // Now we have two volume (isomorphic) and 3-sew => remove one out of the two
+  // lcc.remove_cell<3>(lcc.first_dart()); // TODO PB when several cc !
+  lcc.set_automatic_attributes_management(true);
+
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Remove outside faces: ", diff, "s.");
+
+  // End
+  diff=std::chrono::system_clock::now()-start;
+  print_txt_with_endl("Compute marching cube TOTAL: ", diff, "s.");
+  
+  std::cout<<"#faces-replaced: "<<nb_replaced_f<<", #volumes-replaced: "<<nb_replaced_v<<std::endl;
+} */
+////////////////////////////////////////////////////////////////////////////////
+bool create_mesh_from_off(const std::string& filename,
+                          bool create_transitions,
+                          bool draw,
+                          unsigned int initX,
+                          unsigned int lmax,
+                          bool marching_cubes,
+                          bool no_remove_outside,
+                          bool no_signature,
+                          bool save,
+                          bool smooth,
+                          bool truncated_cubes
+                          )
+{
+  LCC3 lcc;
+  CGAL::Polyhedron_3<Kernel> surface;
+  Tree aabb_tree;
+  size_type corner_mark=lcc.get_new_mark();
+
+  if (!create_initial_voxels(filename, lcc, initX, surface, aabb_tree))
+  {
+    lcc.clear();
+    return false;
+  }
+  lcc.negate_mark(corner_mark); // At the beginning, all darts are corners
+
+  std::chrono::system_clock::time_point start=std::chrono::system_clock::now();
+  std::chrono::system_clock::time_point start2=std::chrono::system_clock::now();
+
+  Pattern_substituer<LCC3> ps1; // pattern substituer to subdivide hexa
+  /*ps1.load_spatterns("data/hexa-8-subdivision/spattern/",
+                     mark_spattern_edges<LCC3>);*/
+  ps1.load_fpatterns("data/hexa-8-subdivision/fpattern/",
+                     mark_fpattern_corners<LCC3>);
+  ps1.load_vpatterns("data/hexa-8-subdivision/vpattern/",
+                     mark_vpattern_corners<LCC3>);
+
+  bool cont=true;
+  unsigned int curlevel=0; //, level_of_hexa;
+  std::vector<std::vector<Dart_handle>> hexa_tosubdivide(lmax);
+  std::size_t nbtosubdivide;
+  std::size_t nb_replaced_f=0;
+  std::size_t nb_replaced_v=0;
+    
+  /*std::map<std::size_t, std::size_t> levels_to_debug1, levels_to_debug2;
+  count_subdivisions(lcc, levels_to_debug1);
+  unsigned int nb1_debug, nb2_debug;*/
+  while (curlevel<lmax && cont)
+  {
+    cont=false;
+    nbtosubdivide=(truncated_cubes?
+                     compute_hexa_to_subdivide_for_truncated_cubes(lcc, aabb_tree,
+                                                                   no_remove_outside,
+                                                                   hexa_tosubdivide):
+                     compute_hexa_to_subdivide(lcc, aabb_tree, curlevel,
+                                               no_remove_outside, marching_cubes,
+                                               hexa_tosubdivide));
+    if(nbtosubdivide>0)
+    {
+      /*for(std::size_t i=0; i<=curlevel; ++i)
+      {
+        for(auto it: tosubdivide[i])
+        {
+          assert(lcc.info<3>(it)==i);
+          subdivide_hexa(lcc, it, corner_mark, ps1);
+        }
+      }*/
+      for(std::size_t i=0; i<=curlevel; ++i)
+      {
+        subdivide_edges(lcc, hexa_tosubdivide[i], corner_mark);
+        subdivide_faces(lcc, hexa_tosubdivide[i], corner_mark, ps1, nb_replaced_f);
+        subdivide_volumes(lcc, hexa_tosubdivide[i], corner_mark, ps1, nb_replaced_v);
+      }
+      cont=true;
+    }
+    ++curlevel;
+  }
+
+  std::chrono::duration<double> diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Subdivision: ", diff, "s.");
+
+  if(!no_remove_outside)
+  {
+    start2=std::chrono::system_clock::now();
+    // Longer !! lcc.set_automatic_attributes_management(false);
+    for (auto it=lcc.attributes<3>().begin(); it!=lcc.attributes<3>().end(); ++it)
+    {
+      if(lcc.info_of_attribute<3>(it)==lmax)
+      {
+        if((marching_cubes &&
+            !is_intersect(lcc, lcc.dart_of_attribute<3>(it), aabb_tree)) ||
+           (!marching_cubes &&
+            is_outside(lcc, lcc.dart_of_attribute<3>(it), aabb_tree)))
+        { lcc.remove_cell<3>(lcc.dart_of_attribute<3>(it)); }
+      }
+    }
+    // lcc.set_automatic_attributes_management(true);
+    diff=std::chrono::system_clock::now()-start2;
+    print_txt_with_endl("    Remove outside: ", diff, "s.");
+  }
+
+  if(create_transitions)
+  { create_transition_patterns(lcc, corner_mark, no_signature); }
+  else if(marching_cubes)
+  { compute_marching_cubes(lcc, corner_mark, aabb_tree, no_signature); }
+
+  if(smooth)
+  { smooth_mesh(lcc, corner_mark, aabb_tree, no_signature); }
+
+  if(truncated_cubes)
+  { create_truncated_cubes(lcc, corner_mark, no_signature); }
+
+  diff=std::chrono::system_clock::now()-start;
+  print_txt_with_endl("Create mesh TOTAL: ", diff, "s.");
+  std::cout<<"Final map: "; display_stats(lcc);
+  std::cout<<"#faces-replaced: "<<nb_replaced_f<<", #volumes-replaced: "<<nb_replaced_v<<std::endl;
+  assert(lcc.is_valid());
+
+  if(draw)
+  { CGAL::draw(lcc); }
+
+  if(save)
+  {
+    std::filesystem::path p(filename);
+    save_object_3D(p.stem().string()+std::to_string(lmax)+".mesh", lcc);
+  }
+
+  lcc.free_mark(corner_mark);
+  return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+int main(int argc, char** argv)
+{
+  if (argc<2) // We need at least one filename
+  { usage(argc, argv); }
+
+  std::string filename;
+  bool create_transitions;
+  bool draw;
+  unsigned int initX;
+  unsigned int lmax;
+  bool marching_cubes;
+  bool no_remove_outside;
+  bool no_signature;
+  bool save;
+  bool smooth;
+  bool truncated_cubes;
+
+  process_command_line(argc, argv,
+                       filename,
+                       create_transitions,
+                       draw,
+                       initX,
+                       lmax,
+                       marching_cubes,
+                       no_remove_outside,
+                       no_signature,
+                       save,
+                       smooth,
+                       truncated_cubes);
+
+  if (!create_mesh_from_off(filename,
+                            create_transitions,
+                            draw,
+                            initX,
+                            lmax,
+                            marching_cubes,
+                            no_remove_outside,
+                            no_signature,
+                            save,
+                            smooth,
+                            truncated_cubes))
+  { return EXIT_FAILURE; }
+
+  return EXIT_SUCCESS;
+}
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/import_moka.h b/src/import_moka.h
new file mode 100644
index 0000000000000000000000000000000000000000..b0423008ebaadad6433474730a0d4e3cf258d505
--- /dev/null
+++ b/src/import_moka.h
@@ -0,0 +1,201 @@
+// Copyright (c) 2011 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+#ifndef IMPORT_MOKA_H
+#define IMPORT_MOKA_H
+
+#include <vector>
+#include <stack>
+#include <fstream>
+#include <string>
+#include <iostream>
+#include <cassert>
+
+namespace CGAL
+{
+template<typename LCC>
+struct GDart
+{
+  unsigned int alpha[4];
+  typename LCC::Dart_handle dh;
+  typename LCC::Vertex_attribute_handle vh;
+
+  GDart() : dh(nullptr), vh(nullptr)
+  {}
+
+  GDart(const GDart& adart) : dh(adart.dh),
+    vh(adart.vh)
+  {
+    for (unsigned int i=0; i<4; ++i)
+    { alpha[i]=adart.alpha[i]; }
+  }
+};
+
+template<typename LCC>
+bool import_from_moka(LCC& lcc, const char* filename)
+{
+  typedef typename LCC::Point Point;
+
+  std::ifstream ifile(filename);
+  if (!ifile)
+  {
+    std::cout<<"Error opening file "<<filename<<"."<<std::endl;
+    return false;
+  }
+
+  std::string line;
+  std::getline(ifile, line);
+
+  if ( line == "Moka file [binary]" )
+  {
+    std::cout<<"Binary file not (yet) considered.\n";
+    return false;
+  }
+  else if ( line != "Moka file [ascii]" )
+  {
+    std::cout<<"File "<<filename<<" is not a moka file.\n";
+    std::cout<< line;
+    return false;
+  }
+
+  // To skip the masks mark (TODO read the marks ?)
+  std::getline(ifile, line);
+
+  std::vector<GDart<LCC>> gdarts;
+  unsigned int nbLoaded = 0;
+  unsigned int number;
+  double x,y,z;
+
+  // First load all the gdarts, and create vertex attributes
+  while(ifile)
+  {
+    GDart<LCC> agdart;
+    ifile>>agdart.alpha[0]>>agdart.alpha[1]
+        >>agdart.alpha[2]>>agdart.alpha[3]; // the 4 alpha
+    ifile>>number>>number>>number>>number; // to skip the 4*8 marks
+    if ( agdart.alpha[0]==nbLoaded )
+    {
+      std::cout<<"Impossible to load a moka file with 0-free darts.\n";
+      return false;
+    }
+    if ( ifile )
+    {
+      ifile>>number; // bool to know if dart has a vertex of not.
+      if (number)
+      {
+        ifile>>x>>y>>z;
+        agdart.vh = lcc.create_vertex_attribute(Point(x, y, z));
+      }
+
+      gdarts.push_back(agdart);
+      ++nbLoaded;
+    }
+  }
+  ifile.close();
+
+  // Second orient the gmap, and create oriented darts.
+  std::stack<unsigned int> totreat;
+  for (unsigned int startingdart = 0; startingdart<nbLoaded; ++startingdart)
+  {
+    bool orient=(gdarts[startingdart].dh==nullptr);
+    for (unsigned int dim=0; orient && dim<4; ++dim)
+      if (gdarts[gdarts[startingdart].alpha[dim]].dh!=nullptr) orient=false;
+
+    if ( orient )
+    {
+      totreat.push(startingdart);
+      gdarts[startingdart].dh=lcc.create_dart();
+
+      while ( !totreat.empty() )
+      {
+        unsigned int i=totreat.top();
+        totreat.pop();
+
+        assert(gdarts[i].dh!=nullptr);
+
+        for (unsigned int dim=1; dim<4; ++dim)
+        {
+          if (gdarts[i].alpha[dim]!=i &&
+              gdarts[gdarts[i].alpha[dim]].vh!=nullptr)
+          {
+            gdarts[i].vh = gdarts[gdarts[i].alpha[dim]].vh;
+            gdarts[gdarts[i].alpha[dim]].vh = nullptr;
+          }
+
+          unsigned int alpha0 = gdarts[i].alpha[0];
+          assert( alpha0!=i );
+
+          if (gdarts[alpha0].alpha[dim]!=alpha0)
+          {
+            if ( gdarts[gdarts[alpha0].alpha[dim]].dh==nullptr )
+            {
+              totreat.push(gdarts[alpha0].alpha[dim]);
+              gdarts[gdarts[alpha0].alpha[dim]].dh = lcc.create_dart();
+              lcc.basic_link_beta(gdarts[i].dh,
+                                  gdarts[gdarts[alpha0].alpha[dim]].dh,
+                  dim);
+            }
+            else if (lcc.is_free(gdarts[i].dh, dim))
+            {
+              lcc.basic_link_beta(gdarts[i].dh,
+                                  gdarts[gdarts[alpha0].alpha[dim]].dh,
+                  dim);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Test that the gmap was orientable.
+  bool orientable = true;
+  for (unsigned int i = 0; i<nbLoaded; ++i)
+  {
+    if (gdarts[i].dh!=nullptr)
+    {
+      for (unsigned int dim=0; dim<4; ++dim)
+      {
+        if (orientable &&
+            gdarts[i].alpha[dim]!=i &&
+            gdarts[gdarts[i].alpha[dim]].dh!=nullptr)
+        {
+          std::cout<<"Pb, the gmap is NOT orientable."<<std::endl;
+          orientable=false;
+          // lcc.clear();
+        }
+      }
+
+      /* if ( lcc.template attribute<3>(gdarts[i].dh) == nullptr )
+      {
+        lcc.template set_attribute<3>(gdarts[i].dh, lcc.template create_attribute<3>());
+      } */
+    }
+    if (gdarts[i].vh!=nullptr)
+    {
+      lcc.set_vertex_attribute(gdarts[i].dh, gdarts[i].vh);
+    }
+  }
+
+  return true;
+}
+
+}
+
+#endif
diff --git a/src/init_to_preserve_for_query_replace.h b/src/init_to_preserve_for_query_replace.h
new file mode 100644
index 0000000000000000000000000000000000000000..3cee45f3db3411c3cd67d4c4e9798f1305bbae7c
--- /dev/null
+++ b/src/init_to_preserve_for_query_replace.h
@@ -0,0 +1,214 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef INIT_TO_PRESERVE_FOR_QUERY_REPLACE_H
+#define INIT_TO_PRESERVE_FOR_QUERY_REPLACE_H
+
+#include"lcc_geometrical_tests.h"
+#include <CGAL/Bbox_3.h>
+
+///////////////////////////////////////////////////////////////////////////////
+template<typename Point>
+bool is_square_extremal_point(const Point& p, const CGAL::Bbox_3& b)
+{
+  return (b.xmin()==b.xmax() || (p.x()==b.xmin() || p.x()==b.xmax())) &&
+      (b.ymin()==b.ymax() || (p.y()==b.ymin() || p.y()==b.ymax())) &&
+      (b.zmin()==b.zmax() || (p.z()==b.zmin() || p.z()==b.zmax()));
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename Point>
+bool is_edge_on_square_border(const Point& p1, const Point& p2,
+                              const CGAL::Bbox_3& b)
+{
+  return (b.xmin()!=b.xmax() && p1.x()==p2.x()) ||
+      (b.ymin()!=b.ymax() && p1.y()==p2.y()) ||
+      (b.zmin()!=b.zmax() && p1.z()==p2.z());
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename Point>
+bool is_hexa_extremal_point(const Point& p, const CGAL::Bbox_3& b)
+{
+  return (p.x()==b.xmin() || p.x()==b.xmax()) &&
+      (p.y()==b.ymin() || p.y()==b.ymax()) &&
+      (p.z()==b.zmin() || p.z()==b.zmax());
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename Point>
+bool is_edge_on_hexa_border(const Point& p1, const Point& p2)
+{
+  return ((p1.x()==p2.x() && p1.y()==p2.y()) ||
+          (p1.x()==p2.x() && p1.z()==p2.z()) ||
+          (p1.y()==p2.y() && p1.z()==p2.z()));
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void mark_fpattern_corners(LCC& pattern, typename LCC::size_type mark_to_preserve)
+{
+  double epsilon=.1;
+  for(auto it=pattern.darts().begin(), itend=pattern.darts().end(); it!=itend; ++it)
+  {
+    if(pattern.template is_free<2>(it))
+    {
+      typename LCC::Dart_handle prev=pattern.template beta<0>(it);
+      while(!pattern.template is_free<2>(prev))
+      { prev=pattern.template beta<2,0>(prev); }
+      if(!lcc_tests::aligned(pattern.point(prev),
+                             pattern.point(it),
+                             pattern.point(pattern.other_extremity(it)), epsilon))
+      { pattern.mark(it, mark_to_preserve); }
+    }
+  }
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void mark_face_corners(LCC& lcc, typename LCC::Dart_handle dh,
+                       typename LCC::size_type mark_to_preserve)
+{
+  double epsilon=.1;
+  typename LCC::Dart_handle cur=dh;
+  do
+  {
+    if(!lcc_tests::aligned(lcc.point(lcc.beta(cur, 0)),
+                           lcc.point(cur),
+                           lcc.point(lcc.beta(cur, 1)), epsilon))
+    { lcc.mark(cur, mark_to_preserve); }
+    cur=lcc.template beta<1>(cur);
+  }
+  while(cur!=dh);
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void mark_spattern_edges(LCC& pattern, typename LCC::size_type mark_border)
+{
+  // Mark edges between non coplanar faces
+  double epsilon=.1;
+  for(auto it=pattern.darts().begin(), itend=pattern.darts().end(); it!=itend; ++it)
+  {
+    assert(!pattern.template is_free<2>(it) && pattern.template is_free<3>(it));
+    if(!pattern.is_marked(it, mark_border) && it<pattern.template beta<2>(it))
+    {
+      typename LCC::Vector n1=CGAL::compute_normal_of_cell_2(pattern, it);
+      typename LCC::Vector n2=CGAL::compute_normal_of_cell_2
+                              (pattern, pattern.template beta<2>(it));
+      if(!lcc_tests::coplanar(n1, n2, epsilon))
+      { pattern.template mark_cell<1>(it, mark_border); }
+    }
+  }
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void mark_vpattern_corners(LCC& pattern, typename LCC::size_type mark_to_preserve)
+{
+  // 1) mark edges between non coplanar faces
+  // 2) mark origin of these edges having its previous marked edge non align
+  double epsilon=.1;
+  typename LCC::Dart_handle dh2;
+  typename LCC::size_type cube_border=pattern.get_new_mark();
+  for(auto it=pattern.darts().begin(), itend=pattern.darts().end(); it!=itend; ++it)
+  {
+    if(pattern.template is_free<3>(it) && !pattern.is_marked(it, cube_border))
+    {
+      dh2=pattern.template beta<2>(it);
+      while(!pattern.template is_free<3>(dh2))
+      { dh2=pattern.template beta<3,2>(dh2); }
+      typename LCC::Vector n1=CGAL::compute_normal_of_cell_2(pattern, it);
+      typename LCC::Vector n2=CGAL::compute_normal_of_cell_2(pattern, dh2);
+      if(!lcc_tests::coplanar(n1, n2, epsilon))
+      { pattern.template mark_cell<1>(it, cube_border); }
+    }
+  }
+  for(auto it=pattern.darts().begin(), itend=pattern.darts().end(); it!=itend; ++it)
+  {
+    if(pattern.is_marked(it, cube_border) && pattern.template is_free<3>(it))
+    {
+      dh2=pattern.template beta<0>(it);
+      while(!pattern.is_marked(dh2, cube_border))
+      {
+        dh2=pattern.template beta<2>(dh2);
+        while(!pattern.template is_free<3>(dh2))
+        { dh2=pattern.template beta<3,2>(dh2); }
+        dh2=pattern.template beta<0>(dh2);
+      }
+      if(!lcc_tests::aligned(pattern.point(dh2), pattern.point(it),
+                             pattern.point(pattern.other_extremity(it)), epsilon))
+      { pattern.mark(it, mark_to_preserve); }
+    }
+  }
+  for(auto it=pattern.darts().begin(), itend=pattern.darts().end(); it!=itend;
+      ++it)
+  { pattern.unmark(it, cube_border); }
+  pattern.free_mark(cube_border);
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void mark_volume_corners(LCC& lcc, typename LCC::Dart_handle dh,
+                         typename LCC::size_type mark_to_preserve)
+{
+  // 1) mark edges between non coplanar faces
+  // 2) mark origin of these edges having its previous marked edge non align
+  double epsilon=.1;
+  typename LCC::Dart_handle dh2;
+  typename LCC::size_type amark=lcc.get_new_mark();
+  typename LCC::size_type cube_border=lcc.get_new_mark();
+  for(auto it=lcc.template darts_of_cell_basic<3>(dh, amark).begin(),
+        itend=lcc.template darts_of_cell_basic<3>(dh, amark).end(); it!=itend; ++it)
+  {
+    lcc.mark(it, amark);
+    if(!lcc.is_marked(it, cube_border))
+    {
+      dh2=lcc.template beta<2>(it);
+      typename LCC::Vector n1=CGAL::compute_normal_of_cell_2(lcc, it);
+      typename LCC::Vector n2=CGAL::compute_normal_of_cell_2(lcc, dh2);
+      if(!lcc_tests::coplanar(n1, n2, epsilon))
+      { lcc.template mark_cell<1>(it, cube_border); }
+    }
+  }
+  lcc.negate_mark(amark);
+  for(auto it=lcc.template darts_of_cell_basic<3>(dh, amark).begin(),
+        itend=lcc.template darts_of_cell_basic<3>(dh, amark).end(); it!=itend; ++it)
+  {
+    lcc.mark(it, amark);
+    if(lcc.is_marked(it, cube_border))
+    {
+      dh2=lcc.template beta<0>(it);
+      while(!lcc.is_marked(dh2, cube_border))
+      { dh2=lcc.template beta<2,0>(dh2); }
+      if(!lcc_tests::aligned(lcc.point(dh2), lcc.point(it),
+                             lcc.point(lcc.other_extremity(it)), epsilon))
+      { lcc.mark(it, mark_to_preserve); }
+    }
+  }
+  lcc.negate_mark(amark);
+
+  for(auto it=lcc.template darts_of_cell<3>(dh).begin(),
+        itend=lcc.template darts_of_cell<3>(dh).end(); it!=itend; ++it)
+  {
+    if(lcc.is_marked(it, cube_border))
+    { lcc.template unmark_cell<1>(it, cube_border); }
+  }
+
+  assert(lcc.is_whole_map_unmarked(amark));
+  assert(lcc.is_whole_map_unmarked(cube_border));
+  lcc.free_mark(amark);
+  lcc.free_mark(cube_border);
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif // INIT_TO_PRESERVE_FOR_QUERY_REPLACE_H
diff --git a/src/lcc_convexity_test.h b/src/lcc_convexity_test.h
new file mode 100644
index 0000000000000000000000000000000000000000..e3968a273f938fffac1b0cd536847a50c36387b7
--- /dev/null
+++ b/src/lcc_convexity_test.h
@@ -0,0 +1,223 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef LCC_CONVEXITY_TEST_H
+#define LCC_CONVEXITY_TEST_H
+///////////////////////////////////////////////////////////////////////////////
+#include <CGAL/squared_distance_3.h>
+#include <CGAL/Linear_cell_complex_operations.h>
+///////////////////////////////////////////////////////////////////////////////
+/// @return true iff face(df) is convex
+template<class LCC>
+bool is_face_convex(LCC& lcc,
+                    typename LCC::Dart_handle dh)
+{
+  return true;
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void mark_vertices_of_face(LCC& lcc, typename LCC::Dart_handle dh,
+                           typename LCC::size_type mark)
+{
+  typename LCC::Dart_handle dh2=dh;
+  do
+  {
+    if(!lcc.is_marked(dh2, mark)) // Already marked => dangling or inner edge
+    { lcc.template mark_cell<0>(dh2, mark); }
+    dh2=lcc.next(dh2);
+  }
+  while(dh2!=dh);
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void unmark_vertices_of_face(LCC& lcc, typename LCC::Dart_handle dh,
+                             typename LCC::size_type mark)
+{
+  lcc.negate_mark(mark);
+  mark_vertices_of_face(lcc, dh, mark);
+  lcc.negate_mark(mark);
+}
+///////////////////////////////////////////////////////////////////////////////
+/// @return true iff volume(df) is convex
+/// Use EPSILON to test if a point belongs to a plane.
+template<class LCC>
+bool is_volume_convex(LCC& lcc,
+                      typename LCC::Dart_handle dh,
+                      const typename LCC::FT EPSILON=0.0001)
+{ // TODO we can improve the test: in the current code, we test face f1
+  // and its adjacent faces f2; and reciprocally for f2 we test again f1.
+  bool first=true;
+  bool positive=true;
+  CGAL::Oriented_side side;
+  auto mark=lcc.get_new_mark();
+  bool on_plane=false;
+
+  for(auto it=lcc.template one_dart_per_incident_cell<2,3>(dh).begin(),
+      itend=lcc.template one_dart_per_incident_cell<2,3>(dh).end(); it!=itend; ++it)
+  {
+    typename LCC::Traits::Plane_3 plane(lcc.point(it),
+                                        CGAL::compute_normal_of_cell_2(lcc, it));
+    mark_vertices_of_face(lcc, it, mark);
+    typename LCC::Dart_handle dh2=it;
+    do
+    {
+      auto dh3=lcc.opposite2(dh2);
+      do
+      {
+        if (!lcc.is_marked(dh3, mark))
+        {
+          on_plane=(CGAL::squared_distance(lcc.point(dh3), plane)<EPSILON);
+          if (!on_plane)
+          {
+            side=plane.oriented_side(lcc.point(dh3));
+            assert(side!=CGAL::ON_ORIENTED_BOUNDARY);
+            if (first)
+            {
+              if (side==CGAL::ON_POSITIVE_SIDE) { first=false; positive=true; }
+              else if (side==CGAL::ON_NEGATIVE_SIDE) { first=false; positive=false; }
+            }
+            else
+            {
+              if ((side==CGAL::ON_POSITIVE_SIDE && !positive) ||
+                  (side==CGAL::ON_NEGATIVE_SIDE && positive))
+              {
+                unmark_vertices_of_face(lcc, it, mark);
+                lcc.free_mark(mark);
+                return false;
+              }
+            }
+          }
+        }
+        dh3=lcc.next(dh3);
+      }
+      while(dh3!=lcc.opposite2(dh2));
+
+      dh2=lcc.next(dh2);
+    }
+    while(dh2!=it);
+    unmark_vertices_of_face(lcc, it, mark);
+  }
+  lcc.free_mark(mark);
+  return true;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// @return true iff face(df) union face(beta2(dh)) is convex
+template<class LCC>
+bool adjacent_faces_are_convex(LCC& lcc,
+                               typename LCC::Dart_handle dh)
+{
+  if(lcc.template is_free<2>(dh)) { return false; }
+  return true;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// @return true iff volume(df) union volume(beta3(dh)) is convex
+/// Use EPSILON to test if a point belongs to a plane.
+template<class LCC>
+bool adjacent_volume_are_convex(LCC& lcc,
+                                typename LCC::Dart_handle dh,
+                                const typename LCC::FT EPSILON=0.0001)
+{ // TODO we can improve the test: in the current code, we test face f1
+  // and its adjacent faces f2; and reciprocally for f2 we test again f1.
+  if(lcc.template is_free<3>(dh)) { return false; }
+  bool first=true;
+  bool positive=true;
+  CGAL::Oriented_side side;
+  auto mark=lcc.get_new_mark();
+  auto markface=lcc.get_new_mark();
+  typename LCC::Dart_handle sd=dh;
+  bool on_plane=false;
+
+  lcc.template mark_cell<2>(dh, markface);
+  for(int i=0; i<2; ++i)
+  {
+    for(auto it=lcc.template one_dart_per_incident_cell<2,3>(sd).begin(),
+        itend=lcc.template one_dart_per_incident_cell<2,3>(sd).end(); it!=itend; ++it)
+    {
+      if (!lcc.is_marked(it, markface))
+      {
+        typename LCC::Traits::Plane_3 plane(lcc.point(it),
+                                            CGAL::compute_normal_of_cell_2(lcc, it));
+        mark_vertices_of_face(lcc, it, mark);
+        typename LCC::Dart_handle dh2=it;
+        do
+        {
+          typename LCC::Dart_handle sdh3=lcc.opposite2(dh2);
+          while(lcc.is_marked(sdh3, markface))
+          { sdh3=lcc.opposite2(lcc.template opposite<3>(sdh3)); }
+          if(sdh3!=lcc.null_handle)
+          {
+            if(lcc.template beta<3>(sdh3)==dh2)
+            { // Case of future dangling face => return false
+              unmark_vertices_of_face(lcc, it, mark);
+              lcc.template unmark_cell<2>(dh, markface);
+              lcc.free_mark(mark);
+              lcc.free_mark(markface);
+              return false;
+            }
+            typename LCC::Dart_handle dh3=sdh3;
+            do
+            {
+              if (!lcc.is_marked(dh3, mark))
+              {
+                on_plane=(CGAL::squared_distance(lcc.point(dh3), plane)<EPSILON);
+                if (!on_plane)
+                {
+                  side=plane.oriented_side(lcc.point(dh3));
+                  assert(side!=CGAL::ON_ORIENTED_BOUNDARY);
+                  if (first)
+                  {
+                    if (side==CGAL::ON_POSITIVE_SIDE) { first=false; positive=true; }
+                    else if (side==CGAL::ON_NEGATIVE_SIDE) { first=false; positive=false; }
+                  }
+                  else
+                  {
+                    if ((side==CGAL::ON_POSITIVE_SIDE && !positive) ||
+                        (side==CGAL::ON_NEGATIVE_SIDE && positive))
+                    {
+                      unmark_vertices_of_face(lcc, it, mark);
+                      lcc.template unmark_cell<2>(dh, markface);
+                      lcc.free_mark(mark);
+                      lcc.free_mark(markface);
+                      return false;
+                    }
+                  }
+                }
+              }
+              dh3=lcc.next(dh3);
+            }
+            while(dh3!=sdh3);
+          }
+          dh2=lcc.next(dh2);
+        }
+        while(dh2!=it);
+        unmark_vertices_of_face(lcc, it, mark);
+      }
+    }
+    sd=lcc.template opposite<3>(dh);
+  }
+  lcc.template unmark_cell<2>(dh, markface);
+  lcc.free_mark(mark);
+  lcc.free_mark(markface);
+
+  return true;
+}
+///////////////////////////////////////////////////////////////////////////////
+#endif // LCC_CONVEXITY_TEST_H
diff --git a/src/lcc_geometrical_tests.h b/src/lcc_geometrical_tests.h
new file mode 100644
index 0000000000000000000000000000000000000000..7c5dd0e3e3fbaf13fdd220d73a75dfe8d2e96dbc
--- /dev/null
+++ b/src/lcc_geometrical_tests.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef LCC_GEOMETRICAL_TESTS_H
+#define LCC_GEOMETRICAL_TESTS_H
+///////////////////////////////////////////////////////////////////////////////
+#include <CGAL/Linear_cell_complex_operations.h>
+
+namespace lcc_tests
+{
+///////////////////////////////////////////////////////////////////////////////
+enum FACE_ORIENTATION
+  {
+   ALMOST_XY,
+   ALMOST_XZ,
+   ALMOST_YZ,
+   ORIENTATION_UNKNOWN
+  };
+const double LCC_GEOMETRICAL_TESTS_EPSILON_DIST=0.000001;
+const double LCC_GEOMETRICAL_TESTS_EPSILON_ANGLE=0.1;
+///////////////////////////////////////////////////////////////////////////////
+bool almost_zero(double d, double epsilon=LCC_GEOMETRICAL_TESTS_EPSILON_DIST)
+{ return d>=-epsilon && d<=epsilon; }
+///////////////////////////////////////////////////////////////////////////////
+bool almost_non_zero(double d, double epsilon=LCC_GEOMETRICAL_TESTS_EPSILON_DIST)
+{ return d<-epsilon || d>epsilon; }
+///////////////////////////////////////////////////////////////////////////////
+bool almost_flat(double angle, double epsilon=LCC_GEOMETRICAL_TESTS_EPSILON_ANGLE)
+{ return (angle<epsilon || angle>(360-epsilon) ||
+          (angle>180-epsilon && angle<180+epsilon));
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+FACE_ORIENTATION get_face_orientation(LCC& lcc,
+                                      typename LCC::Dart_handle dh,
+                                      double epsilon=LCC_GEOMETRICAL_TESTS_EPSILON_DIST)
+{
+  typename LCC::Vector n(CGAL::compute_normal_of_cell_2(lcc, dh));
+  if(almost_zero(n.x(), epsilon) && almost_zero(n.y(), epsilon) && almost_non_zero(n.z(), epsilon))
+  { return ALMOST_XY; }
+  if(almost_zero(n.x(), epsilon) && almost_non_zero(n.y(), epsilon) && almost_zero(n.z(), epsilon))
+  { return ALMOST_XZ; }
+  if(almost_non_zero(n.x(), epsilon) && almost_zero(n.y(), epsilon) && almost_zero(n.z(), epsilon))
+  { return ALMOST_YZ; }
+  return ORIENTATION_UNKNOWN;
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename Point>
+bool aligned(const Point& p1, const Point& p2, const Point& p3,
+             double epsilon=LCC_GEOMETRICAL_TESTS_EPSILON_ANGLE)
+{
+  double angle=CGAL::approximate_angle(p1, p2, p3);
+  return almost_flat(angle, epsilon);
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename Vector>
+bool coplanar(const Vector& normal1, const Vector& normal2,
+             double epsilon=LCC_GEOMETRICAL_TESTS_EPSILON_ANGLE)
+{
+  double angle=CGAL::approximate_angle(normal1, normal2);
+  return almost_flat(angle, epsilon);
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+CGAL::Bbox_3 compute_bbox_of_lcc(LCC& pattern)
+{
+  CGAL::Bbox_3 bbox=pattern.point(pattern.darts().begin()).bbox();
+  for(auto it=pattern.darts().begin(), itend=pattern.darts().end(); it!=itend; ++it)
+  { bbox+=pattern.point(it).bbox(); }
+  return bbox;
+}
+///////////////////////////////////////////////////////////////////////////////
+} // namespace lcc_tests
+
+#endif // LCC_GEOMETRICAL_TESTS_H
diff --git a/src/lcc_geometry_transformation.h b/src/lcc_geometry_transformation.h
new file mode 100644
index 0000000000000000000000000000000000000000..9fd46d2852f50deb135f81671ad82e8ef2b23f5f
--- /dev/null
+++ b/src/lcc_geometry_transformation.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef LCC_GEOMETRY_TRANSFORMATION_H
+#define LCC_GEOMETRY_TRANSFORMATION_H
+
+#include <CGAL/Aff_transformation_3.h>
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void lcc_translate_cc(LCC& lcc, typename LCC::Dart_handle dh,
+                      const typename LCC::Vector& v)
+{
+  typename LCC::Traits::Aff_transformation_3 translate(CGAL::TRANSLATION, v);
+  for(auto it=lcc.template one_dart_per_incident_cell<0,4>(dh).begin(),
+      itend=lcc.template one_dart_per_incident_cell<0,4>(dh).end(); it!=itend; ++it)
+  { lcc.point(it)=translate(lcc.point(it)); }
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void lcc_translate_all(LCC& lcc, const typename LCC::Vector& v)
+{
+  typename LCC::Traits::Aff_transformation_3 translate(CGAL::TRANSLATION, v);
+  for(auto itv=lcc.vertex_attribute_range().begin(),
+      itvend=lcc.vertex_attribute_range().end(); itv!=itvend; ++itv)
+  {
+    lcc.point_of_vertex_attribute(itv)=
+        translate(lcc.point_of_vertex_attribute(itv));
+  }
+}
+///////////////////////////////////////////////////////////////////////////////
+#endif // LCC_GEOMETRY_TRANSFORMATION_H
diff --git a/src/lcc_read_depending_extension.h b/src/lcc_read_depending_extension.h
new file mode 100644
index 0000000000000000000000000000000000000000..98efdd77ce6f983c136187f8b07986e9f63a4d56
--- /dev/null
+++ b/src/lcc_read_depending_extension.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef LCC_READ_DEPENDING_EXTENSION_H
+#define LCC_READ_DEPENDING_EXTENSION_H
+
+#include <filesystem>
+#include <string>
+
+#include <CGAL/Linear_cell_complex_constructors.h>
+#include <CGAL/Combinatorial_map_save_load.h>
+
+#include "import_moka.h"
+#include "lcc_read_from_vtk.h"
+#include "lcc_save_load_mesh.h"
+#include "lcc_save_load_with_assimp.h"
+
+///////////////////////////////////////////////////////////////////////////////
+bool is_lcc_readable_file(const std::string& filename)
+{
+  std::filesystem::path p(filename);
+  std::string ext=p.extension().string();
+  return ext==".3map" ||
+      ext==".moka" ||
+      ext==".off" ||
+      ext==".mesh" ||
+      ext==".toposim" ||
+      ext==".vtk" ||
+      ext==".obj" ||
+      ext==".ply"; // More possibilities from collada ?
+}
+///////////////////////////////////////////////////////////////////////////////
+template<typename LCC>
+typename LCC::Dart_handle read_depending_extension(const std::string& filename,
+                                                   LCC& lcc)
+{
+  if(!is_lcc_readable_file(filename)) { return nullptr; }
+
+  bool res=false;
+  typename LCC::size_type amark=LCC::INVALID_MARK;
+  if(!lcc.is_empty())
+  {
+    amark=lcc.get_new_mark();
+    lcc.negate_mark(amark); // All old darts are marked
+  }
+  std::filesystem::path p(filename);
+  std::string ext=p.extension().string();
+  if(ext==".3map")
+  { res=CGAL::load_combinatorial_map(filename.c_str(), lcc); }
+  else if(ext==".moka")
+  { res=import_from_moka(lcc, filename.c_str()); }
+  else if(ext==".off")
+  { res=CGAL::load_off(lcc, filename.c_str()); }
+  else if(ext==".mesh" || ext==".toposim")
+  { res=load_object_3D(filename, lcc); }
+  else if(ext==".vtk")
+  { res=(read_vtk(filename, lcc)!=nullptr); }
+#ifdef WITH_ASSIMP
+  else // By default use load with collada
+  { res=load_object_3D_with_assimp(filename, lcc); }
+#endif // WITH_ASSIMP
+
+  if(!res) { return nullptr; }
+  if(amark==LCC::INVALID_MARK) { return lcc.darts().begin(); }
+
+  typename LCC::Dart_handle resdh=nullptr;
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+  {
+    if(lcc.is_marked(it, amark))
+    {
+      lcc.unmark(it, amark);
+      if(resdh==nullptr) { resdh=it; }
+    }
+  }
+  lcc.free_mark(amark);
+  return resdh;
+}
+///////////////////////////////////////////////////////////////////////////////
+#endif // LCC_READ_DEPENDING_EXTENSION_H
diff --git a/src/lcc_read_from_vtk.h b/src/lcc_read_from_vtk.h
new file mode 100644
index 0000000000000000000000000000000000000000..49b0ba2dbf56fb23888a2e4394de255e6f25ab41
--- /dev/null
+++ b/src/lcc_read_from_vtk.h
@@ -0,0 +1,174 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef LCC_READ_FROM_VTK_H
+#define LCC_READ_FROM_VTK_H
+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include "My_linear_cell_complex_incremental_builder.h"
+
+template<typename LCC>
+typename LCC::Dart_handle read_vtk(const std::string& filename, LCC& lcc)
+{
+  std::ifstream file(filename);
+  if(!file.is_open())
+  {
+    std::cerr<<"[ERROR] read_vtk: cannot open file "<<filename<<std::endl;
+    return nullptr;
+  }
+
+  typename LCC::Dart_handle res=nullptr;
+  My_linear_cell_complex_incremental_builder_3<LCC> ib(lcc);
+  
+  std::size_t npoints, ncells, ncells2;
+  std::string line,tmp;
+
+  while(line.find("POINTS")==std::string::npos)
+  { std::getline(file,line); }
+  std::stringstream ss(line);
+  std::getline(ss,tmp,' '); // skip POINTS
+  ss>>npoints;
+
+  std::vector<typename LCC::Vertex_attribute_handle> points(npoints);
+  typename LCC::FT x,y,z;
+  for(std::size_t i=0; i<npoints; ++i)
+  {
+    file>>x>>y>>z;
+    points[i]=ib.add_vertex(typename LCC::Point(x, y, z));
+  }
+  // std::cout<<npoints<<"\n";
+  // std::cout<<points[0]<<" "<<points[1]<<" "<<points[2]<<"\n";
+
+  // Read Connectivity
+  // read until you find the CELLS  line 
+  // this is needed because meshes exported from Paraview have sometimes 
+  // a METADATA section
+  while(line.find("CELLS")==std::string::npos)
+  { std::getline(file,line); }
+  ss=std::stringstream(line);
+  std::getline(ss,tmp,' '); // skip CELLS
+  ss>>ncells;
+   
+  // std::cout<<ncells<<std::endl;
+
+  std::size_t points_per_cell;
+  std::vector<std::vector<std::size_t>> faces(ncells);
+  for(std::size_t i=0; i<ncells; ++i)
+  {
+    file>>points_per_cell;
+    faces[i].resize(points_per_cell);
+    for(std::size_t j=0; j<points_per_cell; ++j)
+    { file>>faces[i][j]; }
+  }
+
+  while(line.find("CELL_TYPES")==std::string::npos)
+  { std::getline(file,line); }
+  ss=std::stringstream(line);
+  std::getline(ss,tmp,' '); // skip CELL_TYPES
+  ss>>ncells2;
+  assert(ncells==ncells2);
+
+  std::size_t cell_type;
+  for(std::size_t i=0; i<ncells; ++i)
+  {
+    file>>cell_type;
+    //std::cout<<"cell_type "<<cell_type<<"  ";
+    switch(cell_type)
+    {
+      case 10: // TETRA
+        res=make_tetrahedron_with_builder(ib,
+                                      faces[i][0], faces[i][1],
+                                      faces[i][2], faces[i][3]);
+        break;
+      case 11: // VOXEL (special case in VTK)
+        res=make_hexahedron_with_builder(ib, faces[i][0], faces[i][1],
+                            faces[i][3], faces[i][2], faces[i][4],
+                            faces[i][5], faces[i][7], faces[i][6]);
+        break;
+      case 12: // HEXA
+        res=make_hexahedron_with_builder(ib, faces[i][0], faces[i][1],
+                            faces[i][2], faces[i][3], faces[i][4],
+                            faces[i][5], faces[i][6], faces[i][7]);
+        break;
+      case 13: // PRISM (WEDGE in VTK)
+        res=make_prism_with_builder(ib, faces[i][0], faces[i][1],
+            faces[i][2], faces[i][3], faces[i][4], faces[i][5]);
+        break;
+      case 14: // PYRAMID
+        res=make_pyramid_with_builder(ib, faces[i][0], faces[i][1],
+            faces[i][2], faces[i][3], faces[i][4]);
+        break;
+      case 15: // PENTAGONAL_PRISM
+        res=make_pentagonal_prism_with_builder(ib, faces[i][0], faces[i][1],
+            faces[i][2], faces[i][3], faces[i][4], faces[i][5],
+            faces[i][6], faces[i][7], faces[i][8], faces[i][9]);
+        break;
+      case 16: // HEXAGONAL_PRISM
+        res=make_hexagonal_prism_with_builder(ib, faces[i][0], faces[i][1],
+            faces[i][2], faces[i][3], faces[i][4], faces[i][5],
+            faces[i][6], faces[i][7], faces[i][8], faces[i][9],
+            faces[i][10], faces[i][11]);
+        break;
+        // TODO: 24 QUADRATIC_TETRA
+        //       25 QUADRATIC_HEXAHEDRON
+        //       26 QUADRATIC_WEDGE
+        //       27 QUADRATIC_PYRAMID
+
+      default:
+        std::cerr<<"[ERROR] read_vtk: type "<<cell_type<<" unknown."<<std::endl;
+    };
+    //std::cout<<std::endl;
+  }
+
+  for(auto itv=lcc.vertex_attributes().begin();
+      itv!=lcc.vertex_attributes().end(); ++itv)
+  {
+    if(itv->dart()==nullptr)
+    { lcc.erase_vertex_attribute(itv); }
+  }
+  // Read weights    
+  // Read until you find the POINTDATA  line 
+  /*  while(line.find("POINT_DATA") == std::string::npos)
+  { std::getline(file,line); }
+    
+  std::stringstream ss1(line);
+
+  std::size_t nweights;
+  std::getline(ss1,tmp,' '); // skip POINT_DATA
+  ss1>>nweights;
+  assert(nweights==npoints);
+  // skip next two lines
+  std::getline(file,line);
+  std::getline(file,line);
+    
+  std::vector<float> weights(npoints);
+  for(std::size_t i = 0 ; i < npoints; i++)
+  { file >> weights[i]; }
+  std::cout << weights[0] << "\n"; */
+
+  return res;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#endif // LCC_READ_FROM_VTK_H
diff --git a/src/lcc_save_load_mesh.h b/src/lcc_save_load_mesh.h
new file mode 100644
index 0000000000000000000000000000000000000000..028d8e9b2aea08c96dfd0f061f2b12cb8537146c
--- /dev/null
+++ b/src/lcc_save_load_mesh.h
@@ -0,0 +1,500 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef LCC_SAVE_LOAD_MESH_H
+#define LCC_SAVE_LOAD_MESH_H
+
+#include "Prism_and_pyramid_creation.h"
+#include "Element_topo.h"
+#include <fstream>
+#include <unordered_map>
+#include "My_linear_cell_complex_incremental_builder.h"
+
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void load_object_2D(const std::string& filename, LCC& lcc)
+{
+  std::ifstream fi(filename.c_str());
+  if(!fi.good()) return; // File open error
+
+  unsigned int nbparticles, nbelements, dim;
+  fi >> nbparticles >> nbelements >> dim;
+
+  if(nbparticles==0 || dim!=2)
+  {
+    fi.close();
+    return;
+  }
+
+  typename LCC::FT x, y, z;
+  int index;
+  unsigned int nb_sommets;
+  std::size_t i, j;
+
+  /*! Use incremental builder to create LCC from a 2D mesh */
+  typedef My_linear_cell_complex_incremental_builder_3<LCC>
+    IncrementalBuilder;
+  IncrementalBuilder IB(lcc);
+
+  IB.begin_surface(nbparticles, nbelements, 0);
+
+  // Initialization of the particles
+  for(i=0; i<nbparticles; i++)
+  {
+    fi>>x>>y>>z;
+    IB.add_vertex(typename LCC::Point(x, y, z));
+  }
+
+  // Initialization of the elements
+  for(i=0; i<nbelements; i++)
+  {
+    fi>>nb_sommets;
+    IB.begin_facet();
+
+    for(j=0; j<nb_sommets; j++)
+    {
+      fi>>index;
+      IB.add_vertex_to_facet(index);
+    }
+    IB.end_facet();
+  }
+
+  IB.end_surface();
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+bool load_object_3D(const std::string& filename, LCC& lcc)
+{
+  std::ifstream fi(filename.c_str());
+  if(!fi.good()) return false; // File open error
+
+  std::size_t nbparticles, nbvols, dim;
+  fi >> nbparticles >> nbvols >> dim;
+
+  if(nbparticles == 0 || dim != 3)
+  {
+    fi.close();
+    return false;
+  }
+
+  typename LCC::FT x, y, z;
+  std::size_t index_element[8];
+  ptrdiff_t nb_vertices_signed;
+  std::size_t nb_faces, nb_vertices_in_face;
+  std::size_t index;
+
+  // Retrieve geometrical coordinates of particle; add vertices in an incremental builder
+  My_linear_cell_complex_incremental_builder_3<LCC> IB(lcc);
+  for(std::size_t i = 0; i < nbparticles; ++i)
+  {
+    fi >> x >> y >> z;
+    IB.add_vertex(typename LCC::Point(x, y, z));
+  }
+
+  for(std::size_t  i = 0; i < nbvols; ++i)
+  {
+    fi >> nb_vertices_signed;
+
+    /* Convention used in the file (the same than the one of gmesh, vtk...)
+     *      7----6
+     *     /|   /|
+     *    4----5 |
+     *    | 3--|-2
+     *    |/   |/
+     *    0----1
+     *
+     *      3
+     *     /|\
+     *    4---5
+     *    | | |
+     *    | 0 |
+     *    |/ \|
+     *    1---2
+     *
+     *      4
+     *     /|\
+     *    0-|-3
+     *    | | |
+     *    1---2
+     *
+     *      3
+     *     /|\
+     *    0-|-2
+     *     \|/
+     *      1
+     */
+    if(nb_vertices_signed == 4)//tetra
+    {
+      fi >> index_element[0] >> index_element[1] >> index_element[2]
+         >> index_element[3];
+
+      make_tetrahedron_with_builder(IB, index_element[0], index_element[1],
+                       index_element[2], index_element[3]);
+    }
+
+    else if(nb_vertices_signed == 5)//pyramid
+    {
+      fi >> index_element[0] >> index_element[1] >> index_element[2]
+         >> index_element[3] >> index_element[4];
+
+      make_pyramid_with_builder(IB, index_element[0], index_element[1],
+          index_element[2], index_element[3], index_element[4]);
+    }
+
+    else if(nb_vertices_signed == 6)//prism
+    {
+      fi >> index_element[0] >> index_element[1] >> index_element[2]
+         >> index_element[3] >> index_element[4] >> index_element[5];
+
+      make_prism_with_builder(IB, index_element[0], index_element[1],
+          index_element[2], index_element[3], index_element[4], index_element[5]);
+    }
+
+    else if(nb_vertices_signed == 8)// hexa
+    {
+      fi >> index_element[0] >> index_element[1] >> index_element[2]
+         >> index_element[3] >> index_element[4] >> index_element[5]
+         >> index_element[6] >> index_element[7];
+
+      make_hexahedron_with_builder(IB, index_element[0], index_element[1],
+                          index_element[2], index_element[3], index_element[4],
+                          index_element[5], index_element[6], index_element[7]);
+    }
+
+    else if(nb_vertices_signed<0) // "generic" cell
+    {
+      fi>>nb_faces;
+      IB.begin_surface();
+      for(std::size_t j=0; j<nb_faces; ++j)
+      {
+        fi>>nb_vertices_in_face;
+        IB.begin_facet();
+
+        for(std::size_t k=0; k<nb_vertices_in_face; ++k)
+        {
+          fi>>index;
+          IB.add_vertex_to_facet(index);
+        }
+        IB.end_facet();
+      }
+
+      IB.end_surface();
+    }
+  }
+
+  return true;
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void save_one_generic_face(LCC& lcc, typename LCC::Dart_handle dh,
+                           std::unordered_map<typename LCC::Vertex_attribute_handle, std::size_t>& index,
+                           std::ofstream& of)
+{
+  std::size_t nb=0;
+  typename LCC::Dart_handle cur=dh;
+  do
+  {
+    ++nb;
+    cur=lcc.next(cur);
+  }
+  while(cur!=dh);
+  of<<nb<<" ";
+  do
+  {
+    of<<index[lcc.vertex_attribute(cur)]<<" ";
+    cur=lcc.next(cur);
+  }
+  while(cur!=dh);
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void save_object_3D(const std::string& filename, LCC& lcc)
+{
+  std::ofstream fo(filename.c_str());
+  if(!fo.good()) return; // File open error
+
+  // #vertices #volumes dimension
+  fo<<lcc.vertex_attributes().size()<<" "
+    <<lcc.template one_dart_per_cell<3>().size()<<" 3"<<std::endl<<std::endl;
+
+  std::unordered_map<typename LCC::Vertex_attribute_handle, std::size_t> index;
+  std::size_t nb=0;
+  typename LCC::Dart_handle sd;
+  
+  // all vertices
+  for(auto itv=lcc.vertex_attributes().begin(),
+        itvend=lcc.vertex_attributes().end(); itv!=itvend; ++itv)
+  {    
+    fo<<itv->point()<<std::endl;
+    index[itv]=nb++;
+  }
+  fo<<std::endl;
+  
+  // all volumes; using indices of vertices
+  for(auto itvol=lcc.template one_dart_per_cell<3>().begin(),
+        itvolend=lcc.template one_dart_per_cell<3>().end(); 
+      itvol!=itvolend; ++itvol)
+  {
+    /* Convention used in CGAL LCC (different than the one used in the file, cf above)
+     *      3
+     *     /|\
+     *    0-|-2
+     *     \|/
+     *      1
+     *  Dart incident to p0, to edge p0,p1 and to facet p0,p1,p2.
+     *
+     *      4
+     *     /|\
+     *    0-|-3
+     *    | | |
+     *    1---2
+     *  Dart incident to p0 and to the facet (p0,p1,p2,p3).
+     *
+     *      3
+     *     /|\
+     *    4---5
+     *    | | |
+     *    | 0 |
+     *    |/ \|
+     *    1---2
+      *  Dart incident to p0 and to the facet (p0,p1,p2).
+     *
+     *      7----6
+     *     /|   /|
+     *    4----5 |
+     *    | 3--|-2
+     *    |/   |/
+     *    0----1
+     *  Dart incident to p0, to edge p0,p5 and to the facet (p0,p5,p6,p1).
+     */
+    cell_topo vol_type=get_cell_topo(lcc, itvol, sd);
+    if(vol_type==TETRAHEDRON)
+    {
+       fo<<"4 "
+         <<index[lcc.vertex_attribute(sd)]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<1>(sd))]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<0>(sd))]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<2, 0>(sd))]<<std::endl;
+    }
+    else if(vol_type==PYRAMID)
+    {
+      fo<<"5 "
+        <<index[lcc.vertex_attribute(sd)]<<" "
+        <<index[lcc.vertex_attribute(lcc.template beta<1>(sd))]<<" "
+        <<index[lcc.vertex_attribute(lcc.template beta<1,1>(sd))]<<" "
+        <<index[lcc.vertex_attribute(lcc.template beta<0>(sd))]<<" "
+        <<index[lcc.vertex_attribute(lcc.template beta<2,0>(sd))]<<std::endl;
+    }
+    else if(vol_type==PRISM)
+    {
+      fo<<"6 "
+        <<index[lcc.vertex_attribute(sd)]<<" "
+        <<index[lcc.vertex_attribute(lcc.template beta<1>(sd))]<<" "
+        <<index[lcc.vertex_attribute(lcc.template beta<0>(sd))]<<" ";
+      
+      // Move to the up face
+      typename LCC::Dart_handle d2=lcc.template beta<2, 1, 1, 2>(sd);
+      fo<<index[lcc.vertex_attribute(lcc.template beta<1>(d2))]<<" "
+        <<index[lcc.vertex_attribute(d2)]<<" "
+        <<index[lcc.vertex_attribute(lcc.template beta<0>(d2))]<<std::endl;
+    }
+    else if(vol_type==HEXAHEDRON)
+    {
+      fo<<"8 ";
+      // Darts associated with particles 0, 1, 2, 3
+      for(unsigned int i=0; i<4; ++i)
+      {
+        fo<<index[lcc.vertex_attribute(sd)]<<" ";
+        sd=lcc.template beta<1>(sd);
+      }
+      typename LCC::Dart_handle d2=lcc.template beta<2, 1, 1, 2, 1>(sd);
+      // Darts associated with particles 4, 5, 6, 7
+      for(unsigned int i = 0; i < 4; i++)
+        {
+          fo<<index[lcc.vertex_attribute(d2)]<<" ";
+          d2 = lcc.template beta<0>(d2);
+        }
+      fo<<std::endl;
+    }
+    else
+    {
+      // 1) number of vertices of the volume (negative number for generic cell)
+      // and number of faces of the volume
+      fo<<-static_cast<ptrdiff_t>(lcc.template one_dart_per_incident_cell<0,3,2>(sd).size())<<" "
+        <<(lcc.template one_dart_per_incident_cell<2,3,2>(sd).size())<<std::endl;
+      // 2) save each face
+      for(auto itface=lcc.template one_dart_per_incident_cell<2,3,2>(sd).begin(),
+            itfaceend=lcc.template one_dart_per_incident_cell<2,3,2>(sd).end();
+          itface!=itfaceend; ++itface)
+      {
+        fo<<"  ";
+        save_one_generic_face(lcc, itface, index, fo);
+        fo<<std::endl;
+      }
+    }
+  }
+
+  fo.close();
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void save_object_3D_gmsh(const std::string& filename, LCC& lcc)
+{
+  std::ofstream fo(filename.c_str());
+  if(!fo.good()) return; // File open error
+
+  fo<<"$MeshFormat"<<std::endl;
+  fo<<"2.2 0 8"<<std::endl;
+  fo<<"$EndMeshFormat"<<std::endl;
+
+  fo<<"$Nodes"<<std::endl;
+  fo<<lcc.vertex_attributes().size()<<std::endl;
+  std::unordered_map<typename LCC::Vertex_attribute_handle, std::size_t> index;
+  std::size_t nb=0;
+  typename LCC::Dart_handle sd;
+
+  for(auto itv=lcc.vertex_attributes().begin(),
+        itvend=lcc.vertex_attributes().end(); itv!=itvend; ++itv)
+  {
+    fo<<nb<<" "<<itv->point()<<std::endl;
+    index[itv]=nb++;
+  }
+  fo<<"$EndNodes"<<std::endl;
+
+  nb=0;
+  fo<<"$Elements"<<std::endl;
+  fo<<lcc.template one_dart_per_cell<3>().size()<<std::endl;
+  for(auto itvol=lcc.template one_dart_per_cell<3>().begin(),
+        itvolend=lcc.template one_dart_per_cell<3>().end();
+      itvol!=itvolend; ++itvol, ++nb)
+  {
+    cell_topo vol_type=get_cell_topo(lcc, itvol, sd);
+    if(vol_type==TETRAHEDRON)
+    {
+       fo<<nb<<" 4 2 0 1 "
+         <<index[lcc.vertex_attribute(sd)]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<1>(sd))]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<0>(sd))]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<2, 0>(sd))]<<std::endl;
+    }
+    else if(vol_type==PYRAMID)
+    {
+      fo<<nb<<" 7 2 0 1 "
+         <<index[lcc.vertex_attribute(sd)]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<1>(sd))]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<1,1>(sd))]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<0>(sd))]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<2,0>(sd))]<<std::endl;
+    }
+    else if(vol_type==PRISM)
+    {
+      fo<<nb<<" 6 2 0 1 "
+         <<index[lcc.vertex_attribute(sd)]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<1>(sd))]<<" "
+         <<index[lcc.vertex_attribute(lcc.template beta<0>(sd))]<<" ";
+      // Move to the up face
+      typename LCC::Dart_handle d2=lcc.template beta<2, 1, 1, 2>(sd);
+      fo<<index[lcc.vertex_attribute(lcc.template beta<1>(d2))]<<" "
+        <<index[lcc.vertex_attribute(d2)]<<" "
+        <<index[lcc.vertex_attribute(lcc.template beta<0>(d2))]<<std::endl;
+    }
+    else if(vol_type==HEXAHEDRON)
+    {
+      fo<<nb<<" 5 2 0 1 ";
+      for(unsigned int i=0; i<4; ++i)
+      {
+        fo<<index[lcc.vertex_attribute(sd)]<<" ";
+        sd=lcc.template beta<1>(sd);
+      }
+      typename LCC::Dart_handle d2=lcc.template beta<2, 1, 1, 2, 1>(sd);
+      // Darts associated with particles 4, 5, 6, 7
+      for(unsigned int i = 0; i < 4; i++)
+        {
+          fo<<index[lcc.vertex_attribute(d2)]<<" ";
+          d2 = lcc.template beta<0>(d2);
+        }
+      fo<<std::endl;
+    }
+    else
+    { // TODO Generic case, not posible with gmsh format
+    }
+  }
+  fo<<"$EndElements"<<std::endl;
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void save_lcc_surface_into_off(const std::string& filename, LCC& lcc)
+{
+  std::ofstream fo(filename.c_str());
+  if(!fo.good()) return; // File open error
+
+  auto vertex_3free=lcc.get_new_mark(), face_3free=lcc.get_new_mark();
+
+  // count and mark all 3 free vertices and faces.
+  std::size_t nbvertices=0, nbfaces=0;
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+  {
+    if(lcc.template is_free<3>(it))
+    {
+      if(!lcc.is_marked(it, vertex_3free))
+      { lcc.template mark_cell<0>(it, vertex_3free); ++nbvertices; }
+      if(!lcc.is_marked(it, face_3free))
+      { lcc.template mark_cell<2,2>(it, face_3free); ++nbfaces; }
+    }
+  }
+
+  // #vertices #faces 0 (0 to ignore number of edges)
+  fo<<"OFF"<<std::endl<<nbvertices<<" "<<nbfaces<<" 0"<<std::endl<<std::endl;
+
+  std::unordered_map<typename LCC::Vertex_attribute_handle, std::size_t> index;
+
+  // all vertices
+  std::size_t nb=0;
+  // For this loop, we cannot iterate through vertex attributes since they may
+  // not contain one of its dart. In such a case, it is not possible to ummark
+  // the 3free vertices.
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+  {
+    if (lcc.is_marked(it, vertex_3free))
+    {
+      fo<<lcc.point(it)<<std::endl;
+      index[lcc.vertex_attribute(it)]=nb++;
+      lcc.template unmark_cell<0>(it, vertex_3free);
+    }
+  }
+  fo<<std::endl;
+
+  // all 3free faces
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+  {
+    if (lcc.is_marked(it, face_3free))
+    {
+      save_one_generic_face(lcc, it, index, fo);
+      fo<<std::endl;
+      lcc.template unmark_cell<2,2>(it, face_3free);
+    }
+  }
+
+  lcc.free_mark(vertex_3free);
+  lcc.free_mark(face_3free);
+}
+///////////////////////////////////////////////////////////////////////////////
+#endif // LCC_SAVE_LOAD_MESH_H
diff --git a/src/lcc_save_load_with_assimp.h b/src/lcc_save_load_with_assimp.h
new file mode 100644
index 0000000000000000000000000000000000000000..a3786a43265e32e61171487dc44eed928d72fd38
--- /dev/null
+++ b/src/lcc_save_load_with_assimp.h
@@ -0,0 +1,186 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef LCC_SAVE_LOAD_WITH_ASSIMP_H
+#define LCC_SAVE_LOAD_WITH_ASSIMP_H
+
+#ifdef WITH_ASSIMP
+
+#include <assimp/Importer.hpp>
+#include <assimp/Exporter.hpp>
+#include <assimp/scene.h>       // Output data structure
+#include <assimp/postprocess.h> // Post processing flags
+#include <unordered_map>
+#include "My_linear_cell_complex_incremental_builder.h"
+
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+bool load_object_3D_with_assimp(const std::string& filename, LCC& lcc)
+{
+  Assimp::Importer importer;
+  importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
+                              aiComponent_NORMALS|
+                              aiComponent_TANGENTS_AND_BITANGENTS|
+                              aiComponent_COLORS|
+                              aiComponent_TEXCOORDS|
+                              aiComponent_BONEWEIGHTS|
+                              aiComponent_ANIMATIONS|
+                              aiComponent_TEXTURES|
+                              aiComponent_LIGHTS|
+                              aiComponent_CAMERAS|
+                              aiComponent_MATERIALS);
+  const aiScene* scene=importer.ReadFile(filename,
+                                         aiProcess_RemoveComponent |
+                                         aiProcess_JoinIdenticalVertices);
+  if( scene==nullptr) return false; // the import failed
+
+  // Retrieve the geometry node of a model from an input file
+  aiMesh** allmeshes=scene->mMeshes;
+  unsigned int n_meshes=scene->mNumMeshes;
+
+  My_linear_cell_complex_incremental_builder_3<LCC> IB(lcc);
+  for(unsigned int m=0; m<n_meshes; ++m)
+  {
+    IB.begin_surface();
+    aiMesh* mesh=allmeshes[m];
+    aiVector3D* vertices=mesh->mVertices;
+    aiFace* faces=mesh->mFaces;
+
+    unsigned int n_vertices=mesh->mNumVertices;
+    unsigned int n_faces=mesh->mNumFaces;
+
+    // Add all vertices
+    for (unsigned int i=0; i<n_vertices; ++i)
+    {
+      IB.add_vertex(typename LCC::Point(vertices[i].x,
+                                        vertices[i].y,
+                                        vertices[i].z));
+    }
+    // Add all faces
+    for (unsigned int i=0; i<n_faces; ++i)
+    {
+      IB.begin_facet();
+      const unsigned int nbPts=faces[i].mNumIndices;
+      for(unsigned int j=0; j<nbPts; ++j)
+      { IB.add_vertex_to_facet(faces[i].mIndices[j]); }
+      IB.end_facet();
+    }
+    IB.end_surface();
+  }
+
+  return true;
+}
+///////////////////////////////////////////////////////////////////////////////
+template<class LCC>
+void save_object_3D_with_assimp(const std::string& filename, LCC& lcc)
+{
+  std::unordered_map<typename LCC::Vertex_attribute_handle, std::size_t> index;
+  
+  aiScene scene;
+  scene.mRootNode=new aiNode();
+  scene.mRootNode->mMeshes=new unsigned int[1];
+  scene.mRootNode->mMeshes[0]=0;
+  scene.mRootNode->mNumMeshes=1;
+
+  scene.mNumMeshes=lcc.template one_dart_per_cell<3>().size();
+  scene.mMeshes=new aiMesh*[scene.mNumMeshes];
+
+  std::size_t nbvol=0, nb=0, nb2=0;
+  typename LCC::Dart_handle dhcur;
+
+  for(auto itvol=lcc.template one_dart_per_cell<3>().begin(),
+      itvolend=lcc.template one_dart_per_cell<3>().end();
+      itvol!=itvolend; ++itvol, ++nbvol)
+  {
+    scene.mMeshes[nbvol]=new aiMesh();
+    scene.mMeshes[nbvol]->mMaterialIndex=0;
+
+    auto pMesh=scene.mMeshes[nbvol];
+    pMesh->mNumVertices=lcc.template one_dart_per_incident_cell<0,3,2>(itvol).size();
+    pMesh->mVertices=new aiVector3D[pMesh->mNumVertices];
+
+    // save each vertex
+    nb=0;
+    for(auto itv=lcc.template one_dart_per_incident_cell<0,3,2>(itvol).begin(),
+        itvend=lcc.template one_dart_per_incident_cell<0,3,2>(itvol).end();
+        itv!=itvend; ++itv, ++nb)
+    {
+      const auto& pt=lcc.point(itv);
+      pMesh->mVertices[nb]=aiVector3D(pt.x(), pt.y(), pt.z());
+      index[lcc.vertex_attribute(itv)]=nb;
+    }
+
+    pMesh->mNumFaces=lcc.template one_dart_per_incident_cell<2,3,2>(itvol).size();
+    pMesh->mFaces=new aiFace[pMesh->mNumFaces];
+
+    // save each face
+    nb=0;
+    for(auto itface=lcc.template one_dart_per_incident_cell<2,3,2>(itvol).begin(),
+        itfaceend=lcc.template one_dart_per_incident_cell<2,3,2>(itvol).end();
+        itface!=itfaceend; ++itface, ++nb)
+    {
+      aiFace& face=pMesh->mFaces[nb];
+      nb2=0;
+      dhcur=itface;
+      do
+      { ++nb2; dhcur=lcc.template beta<1>(dhcur); }
+      while(dhcur!=itface);
+      face.mNumIndices=nb2;
+      face.mIndices=new unsigned int[face.mNumIndices];
+      dhcur=itface; nb2=0;
+      do
+      {
+        face.mIndices[nb2]=index[lcc.vertex_attribute(dhcur)];
+        ++nb2; dhcur=lcc.template beta<1>(dhcur);
+      }
+      while(dhcur!=itface);
+    }
+  }
+
+/*
+'assbin'    *.assbin
+'assxml'   Assxml Document - *.assxml
+'3ds'      Autodesk 3DS (legacy) - *.3ds
+'fbxa'     Autodesk FBX (ascii) - *.fbx
+'fbx'      Autodesk FBX (binary) - *.fbx
+'collada'  COLLADA - Digital Asset Exchange Schema - *.dae
+'x3d'      Extensible 3D - *.x3d
+'gltf'     GL Transmission Format - *.gltf
+'glb'      GL Transmission Format (binary) - *.glb
+'gltf2'    GL Transmission Format v. 2 - *.gltf
+'glb2'     GL Transmission Format v. 2 (binary) - *.glb
+'ply'      Stanford Polygon Library - *.ply
+'plyb'     Stanford Polygon Library (binary) - *.ply
+'stp'      Step Files - *.stp
+'stl'      Stereolithography - *.stl
+'stlb'     Stereolithography (binary) - *.stl
+'3mf'      The 3MF-File-Format - *.3mf
+'obj'      Wavefront OBJ format - *.obj
+'objnomtl' Wavefront OBJ format without material file - *.obj
+'x'        X Files - *.x */
+  // Export(&scene, const std::string &pFormatId, const std::string &pPath);
+  Assimp::Exporter exporter;
+  // TODO exporter.Export(&scene, format, filename);
+}
+
+#endif // WITH_ASSIMP
+///////////////////////////////////////////////////////////////////////////////
+#endif // LCC_SAVE_LOAD_WITH_ASSIMP_H
diff --git a/src/lcc_to_face_graph.h b/src/lcc_to_face_graph.h
new file mode 100644
index 0000000000000000000000000000000000000000..e767b24949afd95a2a2db2d98ef3a86a01658f2e
--- /dev/null
+++ b/src/lcc_to_face_graph.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2011 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef CGAL_LCC_TO_FACE_GRAPH_H
+#define CGAL_LCC_TO_FACE_GRAPH_H
+
+#include <unordered_map>
+#include <vector>
+#include <CGAL/config.h>
+#include <CGAL/iterator.h>
+#include <CGAL/Kernel_traits.h>
+#include <CGAL/Cartesian_converter.h>
+
+#include <CGAL/boost/graph/Euler_operations.h>
+#include <CGAL/boost/graph/iterator.h>
+#include <CGAL/boost/graph/helpers.h>
+#include <CGAL/boost/graph/named_params_helper.h>
+#include <CGAL/property_map.h>
+#include <boost/unordered_map.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/iterator/function_output_iterator.hpp>
+
+namespace CGAL {
+
+/** Build a face graph from an LCC. Only 3-free faces are used in order to
+ *  construct in tm only the surface of lcc. */
+template <typename LCC, typename TargetMesh>
+void lcc_to_face_graph(const LCC& lcc, TargetMesh& tm)
+{
+  typedef typename LCC::Dart_const_handle DH;
+  typedef typename LCC::Vertex_attribute_const_handle VH;
+
+  typedef typename boost::graph_traits<TargetMesh>::vertex_descriptor tm_vertex_descriptor;
+  
+  std::unordered_map<VH, tm_vertex_descriptor> vertices_map;
+  std::vector<tm_vertex_descriptor> vertices;
+
+  for (auto it=lcc.vertex_attributes().begin();
+       it!=lcc.vertex_attributes().end(); ++it)
+  {
+    tm_vertex_descriptor vd=CGAL::add_vertex(tm);
+    tm.point(vd)=it->point();
+    vertices_map[it]=vd;
+  }
+
+  auto treated=lcc.get_new_mark();
+  for (auto it=lcc.darts().begin(); it!=lcc.darts().end(); ++it)
+  {
+    if (lcc.template is_free<3>(it) && !lcc.is_marked(it, treated))
+    {
+      vertices.clear();
+      DH cur=it;
+      do
+      {
+        vertices.push_back(vertices_map[lcc.vertex_attribute(cur)]);
+        lcc.mark(cur, treated);
+        cur=lcc.next(cur);
+      }
+      while(cur!=it);
+
+      if (!CGAL::Euler::can_add_face(vertices, tm))
+      { std::cerr<<"[ERROR] a face cannot be added !!"<<std::endl; }
+
+      CGAL::Euler::add_face(vertices, tm);
+    }
+    else
+    { lcc.mark(it, treated); }
+  }
+
+  assert(lcc.is_whole_map_marked(treated));
+  lcc.free_mark(treated);
+}
+
+} // namespace CGAL
+
+#endif //  CGAL_LCC_TO_FACE_GRAPH_H
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/lcc_to_tetgen_io.h b/src/lcc_to_tetgen_io.h
new file mode 100644
index 0000000000000000000000000000000000000000..7921fb508bfb36a90adb55e9ce087718d734b366
--- /dev/null
+++ b/src/lcc_to_tetgen_io.h
@@ -0,0 +1,376 @@
+// Copyright (c) 2011 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef LCC_TO_TETGEN_IO_H
+#define LCC_TO_TETGEN_IO_H
+
+#include <tetgen.h>
+#include <unordered_map>
+#include <vector>
+#include <iostream>
+////////////////////////////////////////////////////////////////////////////////
+/** Internal function that process one vertex of the lcc
+ */
+template <typename LCC>
+void lcc_to_tetgen_process_vertex(const LCC& lcc,
+                                  typename LCC::Dart_const_handle dh,
+                                  typename LCC::size_type markv,
+                                  tetgenio& io, std::size_t nbv,
+                                  std::unordered_map
+                                  <typename LCC::Vertex_attribute_const_handle,
+                                  std::size_t>& vertices_map)
+{
+  io.pointlist[nbv*3]=lcc.point(dh).x();
+  io.pointlist[(nbv*3)+1]=lcc.point(dh).y();
+  io.pointlist[(nbv*3)+2]=lcc.point(dh).z();
+  vertices_map[lcc.vertex_attribute(dh)]=nbv;
+  lcc.template unmark_cell<0>(dh, markv);
+}
+////////////////////////////////////////////////////////////////////////////////
+/** Internal function that process one face of the lcc
+ */
+template <typename LCC>
+void lcc_to_tetgen_process_face(const LCC& lcc,
+                                typename LCC::Dart_const_handle dh,
+                                typename LCC::size_type markf,
+                                tetgenio& io, std::size_t nbf,
+                                std::unordered_map
+                                <typename LCC::Vertex_attribute_const_handle,
+                                std::size_t>& vertices_map)
+{
+  std::size_t nb=0;
+  typename LCC::Dart_const_handle cur=dh;
+  do
+  {
+    lcc.unmark(cur, markf);
+    ++nb;
+    cur=lcc.next(cur);
+  }
+  while(cur!=dh);
+
+  tetgenio::facet *f=&io.facetlist[nbf];
+  // Initialize the fields of this facet.
+  //   There is one polygon, no hole.
+  f->numberofpolygons=1;
+  f->polygonlist=new tetgenio::polygon[1]; // Allocate memory for polygons.
+  f->numberofholes=0;
+  f->holelist=nullptr;
+  tetgenio::polygon *p=&f->polygonlist[0];
+  p->numberofvertices=nb;
+  p->vertexlist=new int[nb]; // Allocate memory for vertices.
+  nb=0;
+  do
+  {
+    p->vertexlist[nb++]=vertices_map[lcc.vertex_attribute(cur)];
+    cur=lcc.next(cur);
+  }
+  while(cur!=dh);
+}
+////////////////////////////////////////////////////////////////////////////////
+/** Build a tetgenio frwom a given volume of an LCC.
+   * @pre all the faces of the volume must be triangles
+   *       (we can call constrained_delaunay_triangulation as pre-process).
+   */
+template <typename LCC>
+void lcc_to_tetgen_one_volume_(const LCC& lcc,
+                               typename LCC::Dart_const_handle dh,
+                               tetgenio& io)
+{
+  // All indices start from 0.
+  io.firstnumber=0;
+
+  // First copy vertices
+  std::unordered_map<typename LCC::Vertex_attribute_const_handle, std::size_t>
+      vertices_map;
+  auto markv=lcc.get_new_mark();
+  auto markf=lcc.get_new_mark();
+  auto treatedv=lcc.get_new_mark();
+
+  io.numberofpoints=0;
+  io.numberoffacets=0;
+  for(auto itvol=lcc.template darts_of_cell_basic<3>(dh, treatedv).begin(),
+      itvolend=lcc.template darts_of_cell_basic<3>(dh, treatedv).end();
+      itvol!=itvolend; ++itvol)
+  {
+    lcc.mark(itvol, treatedv);
+    if(!lcc.is_marked(itvol, markv))
+    {
+      ++(io.numberofpoints);
+      lcc.template mark_cell<0>(itvol, markv);
+    }
+    if(!lcc.is_marked(itvol, markf))
+    {
+      ++(io.numberoffacets);
+      lcc.template mark_cell<2>(itvol, markf);
+    }
+  }
+
+  lcc.negate_mark(treatedv);
+  io.pointlist=new REAL[io.numberofpoints*3];
+  std::size_t nb=0;
+  std::vector<typename LCC::Dart_const_handle> faces;
+  faces.reserve(io.numberoffacets);
+  for(auto itvol=lcc.template darts_of_cell_basic<3>(dh, treatedv).begin(),
+      itvolend=lcc.template darts_of_cell_basic<3>(dh, treatedv).end();
+      itvol!=itvolend; ++itvol)
+  {
+    lcc.mark(itvol, treatedv);
+    if(lcc.is_marked(itvol, markv))
+    { lcc_to_tetgen_process_vertex(lcc, itvol, markv, io, nb++, vertices_map); }
+    if(lcc.is_marked(itvol, markf))
+    {
+      faces.push_back(itvol);
+      lcc.template unmark_cell<2>(itvol, markf);
+    }
+  }
+  lcc.negate_mark(treatedv);
+
+  io.facetlist=new tetgenio::facet[io.numberoffacets];
+  nb=0;
+  for(auto dh: faces)
+ { lcc_to_tetgen_process_face(lcc, dh, markf, io, nb++, vertices_map); }
+
+  assert(lcc.is_whole_map_unmarked(markv));
+  assert(lcc.is_whole_map_unmarked(markf));
+  assert(lcc.is_whole_map_unmarked(treatedv));
+  lcc.free_mark(markv);
+  lcc.free_mark(markf);
+  lcc.free_mark(treatedv);
+}
+////////////////////////////////////////////////////////////////////////////////
+/** Build a tetgenio from an LCC, using only marked volumes
+ *   (a volume is considered marked if one of its dart is marked)
+ *  Face between 2 marked volumes are ignored (to satisty tetgen constraint)
+ *  and thus only preserve the external boundary of the marked volumes.
+ * @pre all the faces of marked volumes must be triangles
+ *       (we can call constrained_delaunay_triangulation as pre-process).
+ */
+template <typename LCC>
+void lcc_to_tetgen(const LCC& lcc, typename LCC::size_type amark, tetgenio& io)
+{
+  typedef typename LCC::Dart_const_handle DH;
+  typedef typename LCC::Vertex_attribute_const_handle VH;
+
+  // All indices start from 0.
+  io.firstnumber=0;
+
+  // First copy vertices
+  std::unordered_map<VH, std::size_t> vertices_map;
+  auto markv=lcc.get_new_mark();
+  auto markf=lcc.get_new_mark();
+  auto treatedv=lcc.get_new_mark();
+
+  io.numberoffacets=0;
+  // 1) We mark all faces
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+  {
+    if(lcc.is_marked(it, amark) && !lcc.is_marked(it, treatedv))
+    {
+      for(auto itvol=lcc.template darts_of_cell_basic<3>(it, treatedv).begin(),
+          itvolend=lcc.template darts_of_cell_basic<3>(it, treatedv).end();
+          itvol!=itvolend; ++itvol)
+      {
+        lcc.mark(itvol, treatedv);
+        if(!lcc.is_marked(itvol, markf))
+        {
+          ++(io.numberoffacets);
+          lcc.template mark_cell<2,2>(itvol, markf);
+        }
+      }
+    }
+  }
+
+  // 2) We unmark faces that are incident to two marked volumes,
+  //    and mark and count vertices incident fo marked faces.
+  io.numberofpoints=0;
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+  {
+    if(lcc.is_marked(it, markf))
+    {
+      if(lcc.is_marked(lcc.template beta<3>(it), markf))
+      {
+        lcc.template unmark_cell<2>(it, markf);
+        (io.numberoffacets)-=2;
+      }
+      else
+      {
+        DH cur=it;
+        do
+        {
+          if(!lcc.is_marked(cur, markv))
+          {
+            ++(io.numberofpoints);
+            lcc.template mark_cell<0>(cur, markv);
+          }
+          cur=lcc.next(cur);
+        }
+        while(cur!=it);
+      }
+    }
+  }
+
+  // 3) We create the array of points and fill it.
+  io.pointlist=new REAL[io.numberofpoints*3];
+  std::size_t nb=0;
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+  {
+    lcc.unmark(it, treatedv);
+    if(lcc.is_marked(it, markv))
+    { lcc_to_tetgen_process_vertex(lcc, it, markv, io, nb++, vertices_map); }
+  }
+
+  // 4) We create the array of faces and fill it.
+  io.facetlist=new tetgenio::facet[io.numberoffacets];
+  nb=0;
+  for(auto it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it)
+   {
+    if(lcc.is_marked(it, markf))
+    { lcc_to_tetgen_process_face(lcc, it, markf, io, nb++, vertices_map); }
+  }
+
+  assert(lcc.is_whole_map_unmarked(markv));
+  assert(lcc.is_whole_map_unmarked(markf));
+  assert(lcc.is_whole_map_unmarked(treatedv));
+  lcc.free_mark(markv);
+  lcc.free_mark(markf);
+  lcc.free_mark(treatedv);
+}
+////////////////////////////////////////////////////////////////////////////////
+/** Build a tetgenio from the entire given LCC. Preserve only the external
+ *  surface of the volumic mesh (and not the internal faces).
+ * @pre all the faces of marked volumes must be triangles
+ *       (we can call constrained_delaunay_triangulation as pre-process).
+ */
+template <typename LCC>
+void lcc_to_tetgen(const LCC& lcc, tetgenio& io)
+{
+  auto amark=lcc.get_new_mark();
+  lcc.negate_mark(amark);
+  lcc_to_tetgen(lcc, amark, io);
+  lcc.negate_mark(amark);
+}
+////////////////////////////////////////////////////////////////////////////////
+template <typename LCC>
+typename LCC::Dart_handle dart_of_ith_face_of_tetra(LCC& lcc,
+                                                    typename LCC::Dart_handle dh,
+                                                    int i)
+{
+  switch(i)
+  {
+    case 3: return dh;
+    case 1: return lcc.template beta<2>(dh);
+    case 0: return lcc.template beta<1,2>(dh);
+    case 2: return lcc.template beta<0,2>(dh);
+    default: break;
+  }
+  std::cerr<<"ERROR dart_of_ith_face_of_tetra"<<std::endl;
+  return nullptr;
+}
+////////////////////////////////////////////////////////////////////////////////
+// Return the dart of the volume containing dh2 that matches dh1
+template <typename LCC>
+typename LCC::Dart_handle find_dart_that_match(LCC& lcc,
+                                               typename LCC::Dart_handle dh1,
+                                               typename LCC::Dart_handle dh2)
+{
+  typename LCC::Vertex_attribute_handle vh1=lcc.vertex_attribute(dh1);
+  typename LCC::Vertex_attribute_handle vh2=lcc.vertex_attribute(lcc.next(dh1));
+  typename LCC::Vertex_attribute_handle vh3=lcc.vertex_attribute(lcc.previous(dh1));
+
+  /*if (lcc.template attributes<0>().index(vh1)==0 ||
+      lcc.template attributes<0>().index(vh2)==0 ||
+      lcc.template attributes<0>().index(vh3)==0)
+    std::cout<<"Face to match: "<<lcc.template attributes<0>().index(vh1)<<" "
+             <<lcc.template attributes<0>().index(vh2)<<" "
+             <<lcc.template attributes<0>().index(vh3)<<std::endl;*/
+
+  for (auto it=lcc.template darts_of_cell<3>(dh2).begin(),
+       itend=lcc.template darts_of_cell<3>(dh2).end(); it!=itend; ++it)
+  {
+    /*if (lcc.template attributes<0>().index(vh1)==0 ||
+        lcc.template attributes<0>().index(vh2)==0 ||
+        lcc.template attributes<0>().index(vh3)==0)
+      std::cout<<"     tested: "<<lcc.template attributes<0>().index(lcc.vertex_attribute(lcc.next(it)))<<" "
+               <<lcc.template attributes<0>().index(lcc.vertex_attribute(it))<<" "
+               <<lcc.template attributes<0>().index(lcc.vertex_attribute(lcc.previous(it)))<<std::endl;*/
+
+    if (vh1==lcc.vertex_attribute(lcc.next(it)) &&
+        vh2==lcc.vertex_attribute(it) &&
+        vh3==lcc.vertex_attribute(lcc.previous(it)))
+    { return it; }
+  }
+  std::cerr<<"ERROR in find_dart_that_match."<<std::endl;
+  return nullptr;
+}
+////////////////////////////////////////////////////////////////////////////////
+template <typename LCC>
+void tetgen_to_lcc(const tetgenio& io, LCC& lcc)
+{
+  if (io.numberofcorners!=4)
+  {
+    std::cout<<"Conversion from tetgen to lcc for "<<io.numberofcorners
+             <<" not implemented."<<std::endl;
+    return;
+  }
+
+  std::vector<typename LCC::Vertex_attribute_handle> TV;
+  TV.resize(io.numberofpoints);
+  for (int i=0; i<io.numberofpoints; ++i)
+  {
+    TV[i]=lcc.create_vertex_attribute(typename LCC::Point(io.pointlist[3*i],
+                                                          io.pointlist[(3*i)+1],
+                                                          io.pointlist[(3*i)+2]));
+  }
+
+  typename LCC::Dart_handle dh, nh;
+  std::vector<typename LCC::Dart_handle> TH; // One dart per tetrahedra
+  TH.resize(io.numberoftetrahedra);
+  for (int i=0; i<io.numberoftetrahedra; ++i)
+  {
+    /*if (lcc.template attributes<0>().index(TV[io.tetrahedronlist[i*4]])==0 ||
+        lcc.template attributes<0>().index(TV[io.tetrahedronlist[(i*4)+1]])==0 ||
+        lcc.template attributes<0>().index(TV[io.tetrahedronlist[(i*4)+2]])==0 ||
+        lcc.template attributes<0>().index(TV[io.tetrahedronlist[(i*4)+3]])==0)
+      std::cout<<"make_tetrahedron "
+               <<lcc.template attributes<0>().index(TV[io.tetrahedronlist[i*4]])<<" "
+               <<lcc.template attributes<0>().index(TV[io.tetrahedronlist[(i*4)+1]])<<" "
+               <<lcc.template attributes<0>().index(TV[io.tetrahedronlist[(i*4)+2]])<<" "
+               <<lcc.template attributes<0>().index(TV[io.tetrahedronlist[(i*4)+3]])<<std::endl;*/
+
+    TH[i]=lcc.make_tetrahedron(TV[io.tetrahedronlist[i*4]],
+        TV[io.tetrahedronlist[(i*4)+2]],
+        TV[io.tetrahedronlist[(i*4)+1]],
+        TV[io.tetrahedronlist[(i*4)+3]]);
+    for (int j=0; j<4; ++j)
+    {
+      if (io.neighborlist[(4*i)+j]!=-1 && io.neighborlist[(4*i)+j]<i) // jth neighboor of ith tetra
+      { // We have one dart of this tetra
+        dh=dart_of_ith_face_of_tetra(lcc, TH[i], j);
+        nh=find_dart_that_match(lcc, dh, TH[io.neighborlist[(4*i)+j]]);
+        assert(nh!=nullptr);
+        lcc.template topo_sew<3>(nh, dh);
+      }
+    }
+  }
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif //  CGAL_LCC_TO_TETGEN_IO_H
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/lcc_triangulate_faces.h b/src/lcc_triangulate_faces.h
new file mode 100644
index 0000000000000000000000000000000000000000..8456ee7dec81a0c09ed599943f68a04f062ed8aa
--- /dev/null
+++ b/src/lcc_triangulate_faces.h
@@ -0,0 +1,270 @@
+// Copyright (c) 2021 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef LCC_TRIANGULATE_FACES_H
+#define LCC_TRIANGULATE_FACES_H
+
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Projection_traits_3.h>
+#include <CGAL/Triangulation_vertex_base_with_info_2.h>
+#include <CGAL/Triangulation_face_base_with_info_2.h>
+#include <CGAL/Constrained_Delaunay_triangulation_2.h>
+#include <CGAL/Constrained_triangulation_plus_2.h>
+#include <CGAL/Linear_cell_complex_operations.h>
+///////////////////////////////////////////////////////////////////////////////
+template<typename Face_handle>
+bool is_external(Face_handle fh)
+{
+  return fh->info().is_external;
+}
+
+template<typename Face_handle>
+int number_of_existing_edge(Face_handle fh)
+{
+  unsigned res=0;
+  for(int i=0; i<3; ++i)
+  { if(fh->info().exist_edge[i]) ++res; }
+  return res;
+}
+
+template<typename Face_handle>
+int get_free_edge(Face_handle fh)
+{
+  CGAL_assertion( number_of_existing_edge(fh)==2 );
+  for(int i=0; i<3; ++i)
+  { if(!fh->info().exist_edge[i]) return i; }
+
+  CGAL_assertion(false);
+  return -1;
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Triangulate the face containing dart d1.
+template<typename LCC>
+void constrained_delaunay_triangulation(LCC &lcc, typename LCC::Dart_handle d1)
+{
+  struct Vertex_info
+  {
+    typename LCC::Dart_handle dh;
+    typename LCC::Vector v;
+  };
+
+  struct Face_info {
+    bool exist_edge[3];
+    bool is_external;
+    bool is_process;
+  };
+
+  typedef CGAL::Projection_traits_3<CGAL::Exact_predicates_inexact_constructions_kernel> P_traits;
+  typedef CGAL::Triangulation_vertex_base_with_info_2<Vertex_info, P_traits> Vb;
+
+  typedef CGAL::Triangulation_face_base_with_info_2<Face_info,P_traits> Fb1;
+
+  typedef CGAL::Constrained_triangulation_face_base_2<P_traits, Fb1>    Fb;
+  typedef CGAL::Triangulation_data_structure_2<Vb,Fb>                   TDS;
+  typedef CGAL::Exact_predicates_tag                                    Itag;
+  typedef CGAL::Constrained_Delaunay_triangulation_2<P_traits, TDS,
+                                                     Itag>              CDT;
+
+  if(lcc.template beta<1,1,1>(d1)==d1) { return; } // The face is already triangulated
+
+  typename LCC::Vector normal=CGAL::compute_normal_of_cell_2(lcc,d1);
+  P_traits cdt_traits(normal);
+  CDT cdt(cdt_traits);
+
+  //inserting the constraints edge by edge
+  typename LCC::template Dart_of_orbit_range<1>::iterator
+    it(lcc.template darts_of_orbit<1>(d1).begin());
+
+  typename CDT::Vertex_handle previous=LCC::null_handle, first=LCC::null_handle,
+    vh=LCC::null_handle;
+
+   for(typename LCC::template Dart_of_orbit_range<1>::iterator
+         itend(lcc.template darts_of_orbit<1>(d1).end()); it!=itend; ++it)
+   {
+     vh=cdt.insert(lcc.point(it));
+     vh->info().dh=it;
+     if(first==nullptr)
+     { first=vh; }
+     if(previous!=nullptr)
+     {
+       if(previous!=vh)
+       { cdt.insert_constraint(previous,vh); }
+     }
+
+     previous=vh;
+   }
+   cdt.insert_constraint(previous,first);
+   CGAL_assertion(cdt.is_valid());
+
+   // sets mark is_external
+   for(typename CDT::All_faces_iterator fit=cdt.all_faces_begin(),
+         fitend=cdt.all_faces_end(); fit!=fitend; ++fit)
+   {
+     fit->info().is_external  = true;
+     fit->info().is_process   = false;
+     fit->info().exist_edge[0]=false;
+     fit->info().exist_edge[1]=false;
+     fit->info().exist_edge[2]=false;
+   }
+
+   std::queue<typename CDT::Face_handle> face_queue;
+   typename CDT::Face_handle face_internal = nullptr;
+
+   face_queue.push(cdt.infinite_vertex()->face());
+   while(!face_queue.empty())
+   {
+     typename CDT::Face_handle fh=face_queue.front();
+     face_queue.pop();
+     if(!fh->info().is_process)
+     {
+       fh->info().is_process = true;
+       for(int i = 0; i<3; ++i)
+       {
+         if(!cdt.is_constrained(std::make_pair(fh, i)))
+         {
+           face_queue.push(fh->neighbor(i));
+         }
+         else if(face_internal==nullptr)
+         {
+           face_internal=fh->neighbor(i);
+         }
+       }
+     }
+   }
+   if(face_internal!=nullptr)
+   { face_queue.push(face_internal); }
+   
+   while(!face_queue.empty())
+   {
+     typename CDT::Face_handle fh=face_queue.front();
+     face_queue.pop();
+     if(!fh->info().is_process)
+     {
+       fh->info().is_process =true;
+       fh->info().is_external=false;
+       for(int i = 0; i <3; ++i)
+       {
+         if(!cdt.is_constrained(std::make_pair(fh, i)))
+         {
+           face_queue.push(fh->neighbor(i));
+         }
+       }
+     }
+   }
+
+   for(typename CDT::Finite_edges_iterator eit = cdt.finite_edges_begin(),
+         eitend=cdt.finite_edges_end(); eit!=eitend; ++eit)
+   {
+     typename CDT::Face_handle fh=eit->first;
+     int index=eit->second;
+     typename CDT::Face_handle opposite_fh=fh->neighbor(index);
+     if(cdt.is_constrained(std::make_pair(fh, index)))
+     {
+       fh->info().exist_edge[index]=true;
+       opposite_fh->info().exist_edge[cdt.mirror_index(fh,index)]=true;
+
+       if(!fh->info().is_external && number_of_existing_edge(fh)==2)
+         face_queue.push(fh);
+       if(!opposite_fh->info().is_external &&
+          number_of_existing_edge(opposite_fh)==2)
+         face_queue.push(opposite_fh);
+     }
+   }
+
+   while(!face_queue.empty())
+   {
+     typename CDT::Face_handle fh=face_queue.front();
+     face_queue.pop();
+     CGAL_assertion(number_of_existing_edge(fh)>=2); // i.e. ==2 or ==3
+     CGAL_assertion(!fh->info().is_external);
+
+     if(number_of_existing_edge(fh)==2)
+     {
+       int index=get_free_edge(fh);
+       typename CDT::Face_handle opposite_fh=fh->neighbor(index);
+
+       CGAL_assertion( !fh->info().exist_edge[index] );
+       CGAL_assertion( !opposite_fh->info().
+                       exist_edge[cdt.mirror_index(fh,index)] );
+       // triangle is (vc, vb, va)
+       const typename CDT::Vertex_handle va = fh->vertex(cdt. cw(index));
+       const typename CDT::Vertex_handle vb = fh->vertex(cdt.ccw(index));
+       const typename CDT::Vertex_handle vc = fh->vertex(index);
+
+       typename LCC::Dart_handle dd1 = nullptr;
+       for(typename LCC::template Dart_of_cell_range<0, 2>::iterator
+             iti=lcc.template darts_of_cell<0, 2>(va->info().dh).begin();
+           dd1==nullptr && iti.cont(); ++iti)
+       {
+         if(lcc.point(lcc.template beta<1>(iti))==vc->point())
+         { dd1=iti; }
+       }
+
+       typename LCC::Dart_handle dd2 = nullptr;
+       for(typename LCC::template Dart_of_cell_range<0, 2>::iterator
+             iti=lcc.template darts_of_cell<0, 2>(vb->info().dh).begin();
+           dd2==nullptr && iti.cont(); ++iti)
+       {
+         if(lcc.point(lcc.template beta<0>(iti))==vc->point())
+         { dd2=iti; }
+       }
+
+       //       assert(((lcc.beta<0,0>(dd1)==dd2) || lcc.beta<1,1>(dd1)==dd2));
+
+       typename LCC::Dart_handle ndart=lcc.insert_cell_1_in_cell_2(dd1, dd2);
+       va->info().dh=lcc.template beta<2>(ndart);
+
+       fh->info().exist_edge[index]=true;
+       opposite_fh->info().exist_edge[cdt.mirror_index(fh,index)]=true;
+
+       if(!opposite_fh->info().is_external &&
+          number_of_existing_edge(opposite_fh)==2)
+       { face_queue.push(opposite_fh); }
+     }
+   }
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Triangulate all marked faces (each face having at least one marked dart)
+template<typename LCC>
+void triangulate_marked_faces(LCC &lcc, typename LCC::size_type amark)
+{
+  // We are going to call constrained_delaunay_triangulation several time for
+  // a same face when it has all its darts marked. But only the first call will
+  // triangulate the face, the other ones will do nothing since the faces are
+  // already triangulated. It is maybe faster to mark darts of the face in order
+  // to avoid these successive calls, but not sure since we must unmark the
+  // marked darts in another loop.
+  for(auto it=lcc.darts().begin(); it!=lcc.darts().end(); ++it)
+  {
+    if(lcc.is_marked(it, amark))
+    { constrained_delaunay_triangulation(lcc, it); }
+  }
+}
+///////////////////////////////////////////////////////////////////////////////
+/// Triangulate all faces of the lcc.
+template<typename LCC>
+void triangulate_all_faces(LCC &lcc)
+{
+  for(auto it=lcc.darts().begin(); it!=lcc.darts().end(); ++it)
+  { constrained_delaunay_triangulation(lcc, it); }
+}
+///////////////////////////////////////////////////////////////////////////////
+#endif // LCC_TRIANGULATE_FACES_H
diff --git a/src/tetra-to-hexa.cpp b/src/tetra-to-hexa.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ef65e08cfb57b4972729b0aa4e28a9f895e34c4
--- /dev/null
+++ b/src/tetra-to-hexa.cpp
@@ -0,0 +1,264 @@
+// Copyright (c) 2022 CNRS and LIRIS' Establishments (France).
+// All rights reserved.
+//
+// This file is part of LCC-Demo.
+//
+// LCC-Demo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Foobar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+//    along with LCC-Demo.  If not, see <https://www.gnu.org/licenses/>.
+//
+// Author(s)     : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
+//
+
+// Prog that uses the query/replace method to generate transitions
+// for hexaedral meshes (based on the paper "Fast Quadtree/Octree adaptive
+// meshing and re-meshing with linear mixed elements").
+// It uses the 325 vpatterns in hexa-325-patterns
+// and the 5 fpatterns in square-5-patterns
+
+#include <CGAL/Linear_cell_complex_for_combinatorial_map.h>
+#include <CGAL/Linear_cell_complex_operations.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/draw_linear_cell_complex.h>
+#include <CGAL/Polyhedron_3.h>
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_face_graph_triangle_primitive.h>
+#include <CGAL/Side_of_triangle_mesh.h>
+#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
+#include <CGAL/Aff_transformation_3.h>
+#include <CGAL/aff_transformation_tags.h>
+
+#include <map>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "cmap_copy.h"
+#include "cmap_query_replace.h"
+#include "Compute_stats.h"
+#include "init_to_preserve_for_query_replace.h"
+#include "lcc_read_depending_extension.h"
+#include "lcc_save_load_mesh.h"
+#include "Print_txt.h"
+#include "Tetrahedral_tools.h"
+
+////////////////////////////////////////////////////////////////////////////////
+typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+typedef Kernel::FT       FT;
+typedef Kernel::Point_3  Point;
+typedef Kernel::Vector_3 Vector;
+typedef CGAL::Linear_cell_complex_for_combinatorial_map<3,3> LCC3;
+typedef typename LCC3::Dart_handle Dart_handle;
+typedef typename LCC3::Vertex_attribute_handle Vertex_handle;
+typedef typename LCC3::size_type   size_type;
+
+////////////////////////////////////////////////////////////////////////////////
+[[ noreturn ]] void usage(int /*argc*/, char** argv)
+{
+  // Name
+  std::cout<<"Name"<<std::endl;
+  std::cout<<"        "<<argv[0]<<" - subdivides the given off file in hexahedra.";
+  std::cout<<std::endl<<std::endl;
+  // Synopsis
+  std::cout<<"SYNOPSIS"<<std::endl;
+  std::cout<<"        "<<argv[0]<<" [--help|-h|-?] "
+           <<"[-draw] [-save] filename"
+           <<std::endl<<std::endl;
+  // Description
+  std::cout<<"DESCRIPTION"<<std::endl;
+  std::cout<<"        "<<" subdivides the given off file in hexahedra, by first computing a tetrahedral mesh, then transform all tetrahedra into hexahedra."
+           <<std::endl<<std::endl;
+  // Options
+  std::cout<<"        --help, -h, -?"<<std::endl
+           <<"                display this help and exit."
+           <<std::endl<<std::endl;
+  std::cout<<"        -draw"<<std::endl
+           <<"                draw the final lcc."
+           <<std::endl<<std::endl;
+  std::cout<<"        -save"<<std::endl
+           <<"                save the lcc resulting of the subdvision (format mesh)."
+           <<std::endl;
+  exit(EXIT_FAILURE);
+}
+////////////////////////////////////////////////////////////////////////////////
+[[ noreturn ]] void error_command_line(int argc, char** argv, const char* msg)
+{
+  std::cout<<"ERROR: "<<msg<<std::endl;
+  usage(argc, argv);
+}
+////////////////////////////////////////////////////////////////////////////////
+void process_command_line(int argc, char** argv,
+                          std::string& filename,
+                          bool& draw,
+                          bool& save
+                          )
+{
+  filename="";
+  draw=false;
+  save=false;
+
+  bool helprequired=false;
+  std::string arg;
+  for (int i=1; i<argc; ++i)
+  {
+    arg=std::string(argv[i]);
+    if(arg==std::string("-h") || arg==std::string("--help") || arg==std::string("-?"))
+    { helprequired=true; }
+    else if(arg=="-draw")
+    { draw=true; }
+    else if(arg=="-save")
+    { save=true; }
+    else if(arg[0]=='-')
+    { std::cout<<"Unknown option "<<arg<<", ignored."<<std::endl; }
+    else { filename=arg; }
+  }
+  if (helprequired || filename.empty()) { usage(argc, argv); }
+}
+////////////////////////////////////////////////////////////////////////////////
+void subdivide_edges(LCC3& lcc)
+{
+  std::vector<Dart_handle> edges_to_subdivide;
+  edges_to_subdivide.reserve(lcc.number_of_darts()/3); // a la louche ;)
+
+  for(auto itd=lcc.one_dart_per_cell<1>().begin(),
+        itdend=lcc.one_dart_per_cell<1>().end(); itd!=itdend; ++itd)
+  { edges_to_subdivide.push_back(itd); }
+
+  for(Dart_handle itd: edges_to_subdivide)
+  { lcc.insert_barycenter_in_cell<1>(itd); }
+}
+////////////////////////////////////////////////////////////////////////////////
+void subdivide_faces(LCC3& lcc,
+                     size_type corner_mark,
+                     Pattern_substituer<LCC3>& ps)
+{
+  std::vector<Dart_handle> faces_to_subdivide;
+  faces_to_subdivide.reserve(lcc.number_of_darts()/9); // a la louche ;)
+  for(auto itd=lcc.one_dart_per_cell<2>().begin(),
+        itdend=lcc.one_dart_per_cell<2>().end(); itd!=itdend; ++itd)
+  {
+    if(lcc.is_marked(itd, corner_mark))
+    { faces_to_subdivide.push_back(itd); }
+    else
+    {
+      assert(lcc.is_marked(lcc.beta<0>(itd), corner_mark));
+      faces_to_subdivide.push_back(lcc.beta<0>(itd));
+    }
+  }
+
+  for(Dart_handle itd: faces_to_subdivide)
+  {
+    ps.replace_one_face_from_dart(lcc, itd, ps.m_fpatterns[0],
+                                  ps.m_fsignatures.begin()->second.first);
+  }
+}
+////////////////////////////////////////////////////////////////////////////////
+void subdivide_volumes(LCC3& lcc,
+                       size_type corner_mark,
+                       Pattern_substituer<LCC3>& ps)
+{
+  std::vector<Dart_handle> vols_to_subdivide;
+  vols_to_subdivide.reserve(lcc.number_of_darts()/24);
+  for(auto itd=lcc.one_dart_per_cell<3>().begin(),
+        itdend=lcc.one_dart_per_cell<3>().end(); itd!=itdend; ++itd)
+  {
+    if(lcc.is_marked(itd, corner_mark))
+    { vols_to_subdivide.push_back(itd); }
+    else
+    {
+      assert(lcc.is_marked(lcc.beta<0>(itd), corner_mark));
+      vols_to_subdivide.push_back(lcc.beta<0>(itd));
+    }
+  }
+
+  for(Dart_handle itd: vols_to_subdivide)
+  {
+    ps.replace_one_volume_from_dart(lcc, itd, ps.m_vpatterns[0],
+                                    ps.m_vsignatures.begin()->second.first);
+  }
+}
+////////////////////////////////////////////////////////////////////////////////
+bool create_mesh_from_off(const std::string& filename,
+                          bool draw,
+                          bool save
+                          )
+{
+  std::chrono::system_clock::time_point start=std::chrono::system_clock::now();
+  std::chrono::system_clock::time_point start2=std::chrono::system_clock::now();
+
+  LCC3 lcc;
+  size_type corner_mark=lcc.get_new_mark();
+  if(read_depending_extension(filename, lcc)==nullptr)
+  {
+    std::cout<<"[ERROR] problem when reading file "<<filename<<std::endl;
+    return false;
+  }
+  tetrahedralize_with_tetgen(lcc);
+  lcc.negate_mark(corner_mark); // At the beginning, all darts are corners
+  std::chrono::duration<double> diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Tetrahedral mesh computation: ", diff, "s.");
+
+  start2=std::chrono::system_clock::now();
+
+  Pattern_substituer<LCC3> ps1;
+  ps1.load_fpatterns("data/tetra-to-hexa/fpattern/",
+                     mark_fpattern_corners<LCC3>);
+  ps1.load_vpatterns("data/tetra-to-hexa/vpattern/",
+                     mark_vpattern_corners<LCC3>);
+
+  subdivide_edges(lcc);
+  subdivide_faces(lcc, corner_mark, ps1);
+  subdivide_volumes(lcc, corner_mark, ps1);
+
+  diff=std::chrono::system_clock::now()-start2;
+  print_txt_with_endl("    Subdivision: ", diff, "s.");
+
+  diff=std::chrono::system_clock::now()-start;
+  print_txt_with_endl("Create mesh TOTAL: ", diff, "s.");
+  std::cout<<"Final map: "; display_stats(lcc);
+  assert(lcc.is_valid());
+
+  if(draw)
+  { CGAL::draw(lcc); }
+
+  if(save)
+  {
+    std::filesystem::path p(filename);
+    save_object_3D(p.stem().string()+"-hexa.mesh", lcc);
+  }
+
+  lcc.free_mark(corner_mark);
+  return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+int main(int argc, char** argv)
+{
+  if (argc<2) // We need at least one filename
+  { usage(argc, argv); }
+
+  std::string filename;
+  bool draw;
+  bool save;
+
+  process_command_line(argc, argv,
+                       filename,
+                       draw,
+                       save);
+
+  if (!create_mesh_from_off(filename,
+                            draw,
+                            save))
+  { return EXIT_FAILURE; }
+
+  return EXIT_SUCCESS;
+}
+////////////////////////////////////////////////////////////////////////////////