diff --git a/src/CGAL_typedefs.h b/src/CGAL_typedefs.h
new file mode 100644
index 0000000000000000000000000000000000000000..7c88a59410f3c3d43f564847774f0ab739bbbf0a
--- /dev/null
+++ b/src/CGAL_typedefs.h
@@ -0,0 +1,97 @@
+// 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 CGAL_TYPEDEFS_H
+#define CGAL_TYPEDEFS_H
+
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Linear_cell_complex_for_combinatorial_map.h>
+#include <CGAL/Compact_container.h>
+#include <CGAL/Real_timer.h>
+#include <CGAL/Timer.h>
+#include <vector>
+
+template<typename LCC>
+class Inner_point;
+
+///////////////////////////////////////////////////////////////////////////////
+typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
+typedef CGAL::Exact_predicates_exact_constructions_kernel   EPECK;
+typedef EPECK::FT              ECoord;
+typedef EPECK::Point_2         EPoint;
+typedef EPECK::Segment_2       ESegment;
+typedef EPECK::Iso_rectangle_2 ERectangle;
+typedef EPICK::FT              ICoord;
+typedef EPICK::Point_2         IPoint;
+typedef EPICK::Segment_2       ISegment;
+typedef EPICK::Iso_rectangle_2 IRectangle;
+///////////////////////////////////////////////////////////////////////////////
+// typedef CGAL::Timer My_timer;
+typedef CGAL::Real_timer My_timer;
+///////////////////////////////////////////////////////////////////////////////
+template<typename Ref>
+struct Info_for_face
+{
+  using Face_attribute_handle=
+         typename Ref::template Attribute_handle<2>::type;
+
+  Info_for_face() : m_finite(true), m_father(nullptr)
+  {}
+
+  bool m_finite;
+  std::vector<Face_attribute_handle> m_son;
+  Face_attribute_handle m_father;
+};
+////////////////////////////////////////////////////////////////////////////////
+template<typename Ref>
+struct Info_for_vertex
+{
+  using Dart_handle=typename Ref::Dart_handle;
+
+  Info_for_vertex(Dart_handle dh=nullptr) : m_dart_above(dh)
+  {}
+
+  Dart_handle m_dart_above;
+};
+////////////////////////////////////////////////////////////////////////////////
+struct Myitem
+{
+  template<class Ref>
+  struct Dart_wrapper
+  {
+    typedef CGAL::Cell_attribute_with_point<Ref, Info_for_vertex<Ref>> Vertex_attribute;
+    typedef CGAL::Cell_attribute<Ref, Info_for_face<Ref>> Face_attribute;
+    typedef std::tuple<Vertex_attribute,void,Face_attribute> Attributes;
+  };
+};
+typedef CGAL::Linear_cell_complex_traits
+<2, CGAL::Exact_predicates_exact_constructions_kernel> Traits;
+ typedef CGAL::Linear_cell_complex_for_combinatorial_map
+       <2,2,Traits,Myitem,CGAL_ALLOCATOR(int),
+       CGAL::Combinatorial_map_base,
+       CGAL::CMap_linear_cell_complex_storage_1
+            <2, 2, Traits, Myitem, CGAL_ALLOCATOR(int), CGAL::Tag_true>
+> LCC_2;
+///////////////////////////////////////////////////////////////////////////////
+typedef LCC_2::Dart_handle Dart_handle;
+typedef LCC_2::Dart_const_handle Dart_const_handle;
+///////////////////////////////////////////////////////////////////////////////
+
+#endif // CGAL_TYPEDEFS_H
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c5e704758aea7cfef3b53cb99d1155039dce23c8
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,81 @@
+project(Parallel_arrangement)
+
+cmake_minimum_required(VERSION 3.1)
+if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6)
+  if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
+    cmake_policy(VERSION 2.8.4)
+  else()
+    cmake_policy(VERSION 2.6)
+  endif()
+endif()
+
+cmake_policy(SET CMP0064 NEW)
+
+set( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true )
+if ( COMMAND cmake_policy )
+  cmake_policy( SET CMP0003 NEW )
+endif()
+
+# ADD_DEFINITIONS("-Wall -Wextra")
+# ADD_DEFINITIONS("-O3")
+# -fsanitize=thread
+
+set(CMAKE_CXX_STANDARD 17)
+find_package(Boost COMPONENTS system filesystem REQUIRED)
+
+# ##########################################################
+# Find some packages
+
+find_package(CGAL COMPONENTS Qt5 REQUIRED) # CGAL and QT5 component
+if(CGAL_Qt5_FOUND)
+  add_definitions(-DCGAL_USE_BASIC_VIEWER -DQT_NO_KEYWORDS)
+endif()
+
+# ##########################################################
+## For profilling with gprof
+# add_definitions("-pg")
+# SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg")
+# add_definitions("-D_GLIBCXX_DEBUG")
+add_definitions("-g") # for vtune (perf evaluator)
+
+# ##########################################################
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}/")
+
+set(HEADER_FILES
+  CGAL_typedefs.h
+  draw_shds.h
+  Export_xfig.hh
+  Hds.h
+  memory.h
+  My_arr_segment_traits_2.h
+  My_construction_subcurve.h
+  My_event.h
+  My_surface_sweep.h
+  My_visitor.h
+  Partial_hds.h
+  SHds.h
+  SHds_to_lcc.h
+  SHds_to_cgal_arrangement.h
+  Segment_readers.h
+  Print_txt.h)
+
+set(SOURCE_FILES
+ parallel-arrangement-bench.cpp
+ parallel-arrangement.cpp
+ compute-arrangement-streamed.cpp)
+
+foreach(cppfile ${SOURCE_FILES})
+  create_single_source_cgal_program("${cppfile}" "${HEADER_FILES}")
+endforeach()
+# ##########################################################
+# Link
+if (CGAL_Qt5_FOUND)
+  target_link_libraries(parallel-arrangement PUBLIC CGAL::CGAL_Qt5)
+endif()
+
+find_package(TBB REQUIRED)
+include(CGAL_TBB_support)
+target_link_libraries(parallel-arrangement PUBLIC pthread CGAL::TBB_support ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY})
+target_link_libraries(parallel-arrangement-bench PUBLIC pthread CGAL::TBB_support ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY})
+target_link_libraries(compute-arrangement-streamed PUBLIC pthread CGAL::TBB_support ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY})
+# ##########################################################
diff --git a/src/Export_xfig.hh b/src/Export_xfig.hh
new file mode 100644
index 0000000000000000000000000000000000000000..43a34ec23fef540297df01ce15d19d58ae24e07d
--- /dev/null
+++ b/src/Export_xfig.hh
@@ -0,0 +1,205 @@
+// 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 EXPORT_XFIG_H
+#define EXPORT_XFIG_H
+
+#include <cmath>
+#include <string>
+#include <fstream>
+
+class Export_xfig
+{
+  constexpr static unsigned int MAX_PROF=999; // max depth for xfig
+
+public:
+  // xsize is the length of the bbox in x-coordinates
+  // We resize the scene so that the x-length is xfig_x_size.
+  Export_xfig(const std::string& filename, double xsize,
+              double xfig_x_size=20000.,
+              bool invert_y=false) :
+    m_nb_couls(0),
+    m_invert_y(invert_y),
+    m_x_factor(xfig_x_size/xsize),
+    m_x_shift(0),
+    m_y_shift(0)
+  {
+    m_ofstream.open(filename);
+    if (!m_ofstream)
+    { std::cerr<<"ERROR opening "<<filename<<std::endl; }
+
+    sauveEntete();
+  }
+
+  ~Export_xfig()
+  { m_ofstream.close(); }
+
+  void set_x_shift(int x)
+  { m_x_shift=x; }
+  void set_y_shift(int y)
+  { m_y_shift=y; }
+
+  uint8_t add_color(const CGAL::Color& c)
+  {
+    m_ofstream<<std::setfill('0');
+    m_ofstream<<"0 "<<32+m_nb_couls<<" #"
+             <<std::hex<<std::uppercase<<std::setw(2)
+            <<static_cast<int>(c.red())
+           <<static_cast<int>(c.green())
+          <<static_cast<int>(c.blue())<<std::dec<<std::endl;
+    ++m_nb_couls;
+    return m_nb_couls-1;
+  }
+
+  /* TODO void debutComposante( ofstream &os,
+                        const CVertex & min, const CVertex & max )
+  {
+    m_ofstream<<"6 "
+     <<int(RINT(min.getX()+decalageX))<<" "
+    <<int(RINT(min.getY()+decalageY))<<" "
+    <<int(RINT(max.getX()+decalageX))<<" "
+    <<int(RINT(max.getY()+decalageY))<<endl;
+  }*/
+
+  // Fin d'une composante : m_ofstream<<"-6\n";
+
+
+  void point(double x, double y, uint16_t rayon,
+             u_int8_t coul, uint16_t larg, uint16_t prof)
+  {
+    m_ofstream<<"1 4 0 "<<static_cast<int>(larg)<<" "
+             <<static_cast<int>(32+coul)<<" "
+            <<static_cast<int>(32+coul)<<" "
+           <<static_cast<int>(prof);
+    m_ofstream <<" 0 20 0.000 1 0.0000 ";
+
+
+    m_ofstream<<point_to_string(x, y)<<" "  // Centre x et y
+             <<static_cast<int>(rayon)<<" "<<static_cast<int>(rayon)<<" " //Rayon en x et en y
+            <<point_to_string(x, y)<<" "  // Premier point == centre
+           <<point_to_string(x+rayon, y)<<" " // deuxieme point (sur le cercle)
+          <<std::endl;
+  }
+
+  void segment(double x1, double y1, double x2, double y2,
+               u_int8_t coul, uint16_t larg, bool arrow, uint16_t prof)
+  {
+    int ix1=p_to_x(x1);
+    int iy1=p_to_y(y1);
+    int ix2=p_to_x(x2);
+    int iy2=p_to_y(y2);
+
+    if (ix1!=ix2 || iy1!=iy2)
+    {
+      m_ofstream<<"2 1 0 "<<static_cast<int>(larg)<<" "
+               <<static_cast<int>(32+coul)<<" "
+              <<static_cast<int>(32+coul)<<" "
+             <<static_cast<int>(prof)
+            <<" 0 -1 0.000 1 0 7 ";
+      if (arrow)
+      {
+        m_ofstream<<"1 0 2\n"
+                 <<"     2 0 1.00 60.00 120.00\n";
+      }
+      else
+      { m_ofstream<<"0 0 2\n"; }
+
+      m_ofstream<<ix1<<" "<<iy1<<" "<<ix2<<" "<<iy2<<std::endl;
+    }
+  }
+
+  void rectangle(double x1, double y1, double x2, double y2,
+                 u_int8_t coul, uint16_t larg, bool arrow, uint16_t prof)
+  {
+    segment(x1, y1, x2, y1, coul, larg, arrow, prof);
+    segment(x2, y1, x2, y2, coul, larg, arrow, prof);
+    segment(x2, y2, x1, y2, coul, larg, arrow, prof);
+    segment(x1, y2, x1, y1, coul, larg, arrow, prof);
+  }
+
+protected:
+
+  int transfoMmPixel(double val) const
+  {
+    // Xfig est en 1200 dpi, et donc le nombre de pixel par mm vaut 1200/25.4
+    // (sachant que 1inch==25.4mm)
+    // double dpmX=(1200/25.4);
+    return std::round(val*m_x_factor); //(val*dpmX)/COEF_DE_REDUCTION);
+  }
+
+  int p_to_x(double val) const
+  { return transfoMmPixel(val)+m_x_shift; }
+  int p_to_y(double val) const
+  {
+    int res=transfoMmPixel(val)+m_y_shift;
+    if (m_invert_y) { res=-res; }
+    return res;
+  }
+
+  std::string value_to_string(double val)
+  { return std::to_string(transfoMmPixel(val)); }
+
+  std::string point_to_string(double x, double y)
+  {
+    int ix=p_to_x(x);
+    int iy=p_to_y(y);
+    return std::string(std::to_string(ix)+" "+std::to_string(iy));
+  }
+
+  void sauveEntete()
+  {
+    m_ofstream<<"#FIG 3.2"<<std::endl
+             <<"Portrait"<<std::endl
+            <<"Metric"<<std::endl
+           <<"A4"<<std::endl
+          <<"100.00"<<std::endl
+         <<"Single"<<std::endl
+        <<"-2"<<std::endl
+       <<"1200 2"<<std::endl;
+  }
+
+
+/* void CControlerGMap::sauveFace(const std::vector<Point2d>& pts,
+                               int coulFill, int larg, int AProf )
+{
+  assert(pts.size()>=3); // 3 => polygone à 2 arêtes...
+
+
+  os<<"2 1 0 " << larg << " "
+    << 32+COUL_DART << " " << 32+coulFill << " "
+    << (1+AProf) <<" 0 20 0.000 1 0 7 0 0 "
+    << nbPts << endl;
+
+  for (int i=0; i<nbPts; ++i)
+  {
+    os << int(RINT(p[i].getX()+decalageX)) << " "
+       << int(RINT(p[i].getY()+decalageY)) << endl;
+  }
+}
+*/
+
+protected:
+  std::ofstream m_ofstream;
+  uint8_t m_nb_couls;
+  bool m_invert_y;
+  double m_x_factor;
+  int m_x_shift, m_y_shift;
+};
+////////////////////////////////////////////////////////////////////////////////
+#endif // EXPORT_XFIG_H
diff --git a/src/Hds.h b/src/Hds.h
new file mode 100644
index 0000000000000000000000000000000000000000..30a6c4c36da285888d9c9865866f5d979b10490f
--- /dev/null
+++ b/src/Hds.h
@@ -0,0 +1,525 @@
+// 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 HDS_H
+#define HDS_H
+
+#include <bitset>
+
+#include "CGAL_typedefs.h"
+#include "Print_txt.h"
+#include "Export_xfig.hh"
+
+///////////////////////////////////////////////////////////////////////////////
+class Halfedge;
+class Vertex;
+class Face;
+class HDS;
+class SHds;
+////////////////////////////////////////////////////////////////////////////////
+typedef CGAL::Compact_container<Halfedge>::iterator Halfedge_handle;
+typedef CGAL::Compact_container<Halfedge>::const_iterator Halfedge_const_handle;
+typedef CGAL::Compact_container<Vertex>::iterator Vertex_handle;
+typedef CGAL::Compact_container<Face>::iterator Face_handle;
+////////////////////////////////////////////////////////////////////////////////
+class Halfedge
+{
+public:
+  friend class HDS;
+  friend class Vertex;
+  friend class SHds;
+
+  typedef uint32_t size_type;
+  static const size_type NB_MARKS = 32;
+
+  Halfedge(Halfedge_handle opposite=nullptr,
+           Vertex_handle vertex=nullptr,
+           int edge_id=0) :
+    m_opposite(opposite),
+    m_prev_around_vertex(nullptr),
+    m_next_around_vertex(nullptr),
+    m_vertex(vertex),
+    m_face(nullptr),
+    m_edge_id(edge_id)
+  {}
+
+  void set( Halfedge_handle opposite,
+            Halfedge_handle prev_around_vertex,
+            Halfedge_handle next_around_vertex,
+            Vertex_handle   vertex,
+            int             edge_id)
+  {
+    m_opposite=opposite;
+    m_prev_around_vertex=prev_around_vertex;
+    m_next_around_vertex=next_around_vertex;
+    m_vertex=vertex;
+    m_edge_id=edge_id;
+  }
+
+  Halfedge_handle opposite() const
+  { return m_opposite; }
+  Halfedge_handle prev_around_vertex() const
+  { return m_prev_around_vertex; }
+  Halfedge_handle next_around_vertex() const
+  { return m_next_around_vertex; }
+  Vertex_handle vertex() const
+  { return m_vertex; }
+  Face_handle face() const
+  { return m_face; }
+ int edge_id() const
+  { return m_edge_id; }
+
+ bool get_mark(size_type amark) const
+ {
+   CGAL_assertion(amark>=0 && amark<NB_MARKS);
+   return m_marks[amark];
+ }
+ void set_mark(size_type amark, bool avalue) const
+ {
+   CGAL_assertion(amark>=0 && amark<NB_MARKS);
+   m_marks.set(amark, avalue);
+ }
+ void flip_mark(size_type amark) const
+ {
+   CGAL_assertion(amark>=0 && amark<NB_MARKS);
+   m_marks.flip(amark);
+ }
+ std::bitset<NB_MARKS> get_marks() const
+ { return m_marks; }
+ void set_marks(const std::bitset<NB_MARKS>& amarks) const
+ { m_marks=amarks; }
+
+  void* for_compact_container() const
+  { return m_opposite.for_compact_container(); }
+  void for_compact_container(void* p)
+  { m_opposite.for_compact_container(p);}
+
+protected:
+  Halfedge_handle m_opposite;
+  Halfedge_handle m_prev_around_vertex;
+  Halfedge_handle m_next_around_vertex;
+  Vertex_handle   m_vertex;
+  Face_handle     m_face;
+  int             m_edge_id; // >0 if halfedge from left to right or vertical and bottom to top, <0 otherwise
+                             // two halfedges of the same edge have the same value and opposite sign
+  mutable std::bitset<NB_MARKS> m_marks;
+};
+////////////////////////////////////////////////////////////////////////////////
+class Global_halfedge
+{
+public:
+  friend class SHds;
+
+  Global_halfedge(std::size_t strip_id=0,
+                  Halfedge_handle hh=nullptr):
+    m_strip_id(strip_id),
+    m_hh(hh)
+  {}
+
+  void set(std::size_t strip_id=0, Halfedge_handle hh=nullptr)
+  { m_strip_id=strip_id; m_hh=hh; }
+
+  void set_halfedge(Halfedge_handle hh)
+  { m_hh=hh; }
+
+  std::size_t strip_id() const
+  { return m_strip_id; }
+
+  const Halfedge_handle& halfedge() const
+  { return m_hh; }
+  Halfedge_handle& halfedge()
+  { return m_hh; }
+
+  void go_to_left_strip()
+  { assert(m_strip_id>0); --m_strip_id; }
+  void go_to_right_strip()
+  { ++m_strip_id; }
+
+  bool operator==(const Global_halfedge& other) const
+  { return m_hh==other.m_hh; } // Handle are unique, thus we don't need to compare m_strip_id
+  bool operator!=(const Global_halfedge& other) const
+  { return !operator==(other); }
+
+  bool operator<(const Global_halfedge& other) const
+  { return m_strip_id<other.m_strip_id ||
+        (m_strip_id==other.m_strip_id && m_hh<other.m_hh); }
+  bool operator>(const Global_halfedge& other) const
+  { return other.operator<(*this); }
+  bool operator>=(const Global_halfedge& other) const
+  { return !operator<(other); }
+  bool operator<=(const Global_halfedge& other) const
+  { return !operator>(other); }
+
+protected:
+  std::size_t m_strip_id;
+  Halfedge_handle m_hh;
+};
+////////////////////////////////////////////////////////////////////////////////
+class Vertex
+{
+public:
+  friend class HDS;
+  friend class Halfedge;
+
+  Vertex() :
+    m_first_halfedge(nullptr),
+    m_above_halfedge(nullptr)
+  {}
+
+  Vertex(const EPoint& p) :
+    m_point(p),
+    m_first_halfedge(nullptr),
+    m_above_halfedge(nullptr)
+  {}
+
+  void set(const EPoint& p, Halfedge_handle first_halfedge,
+           Halfedge_handle above_halfedge)
+  {
+    m_point=p;
+    m_first_halfedge=first_halfedge;
+    m_above_halfedge=above_halfedge;
+  }
+
+  const EPoint& point() const
+  { return m_point; }
+
+  Halfedge_handle first_halfedge() const
+  { return m_first_halfedge; }
+
+  Halfedge_handle above_halfedge() const
+  { return m_above_halfedge; }
+  void set_above_halfedge(Halfedge_handle dh)
+  { m_above_halfedge=dh; }
+
+  bool no_left_edge() const
+  {
+    return m_first_halfedge->m_edge_id>0; // If the first halfedge is from left to right
+    // or vertical and bottom to up, there is no left edge around the vertex
+  }
+
+  void serialize_point(std::ostream& os) const
+  {
+    CGAL::exact(m_point);
+    os<<std::setprecision(17)<<m_point;
+  }
+
+  void* for_compact_container() const
+  { return m_first_halfedge.for_compact_container(); }
+  void for_compact_container(void* p)
+  { m_first_halfedge.for_compact_container(p);}
+
+protected:
+  EPoint          m_point;
+  Halfedge_handle m_first_halfedge;
+  Halfedge_handle m_above_halfedge; // Halfedge handle of the edge above this vertex (nullptr if no such edge)
+};
+////////////////////////////////////////////////////////////////////////////////
+class Face
+{
+public:
+  friend class HDS;
+  friend class Halfedge;
+  friend class SHds;
+
+  Face() :
+    m_strip_id(0),
+    m_first_halfedge(nullptr),
+    m_father(nullptr),
+    m_finite(true)
+  {}
+
+  void set(std::size_t     strip_id,
+           Halfedge_handle first_halfedge,
+           Face_handle     father,
+           bool            finite)
+  {
+    m_strip_id=strip_id;
+    m_first_halfedge=first_halfedge;
+    m_father=father;
+    m_finite=finite;
+  }
+
+  std::size_t strip_id() const
+  { return m_strip_id; }
+
+  Halfedge_handle first_halfedge() const
+  { return m_first_halfedge; }
+
+  Face_handle father() const
+  { return m_father; }
+
+  bool finite() const
+  { return m_finite; }
+
+  const std::vector<Face_handle>& sons() const
+  { return m_son; }
+
+  void* for_compact_container() const
+  { return m_first_halfedge.for_compact_container(); }
+  void for_compact_container(void* p)
+  { m_first_halfedge.for_compact_container(p);}
+
+protected:
+  std::size_t              m_strip_id; // strip id of the first halfedge
+  Halfedge_handle          m_first_halfedge;
+  Face_handle              m_father;
+  std::vector<Face_handle> m_son;
+  bool                     m_finite;
+};
+////////////////////////////////////////////////////////////////////////////////
+class HDS
+{
+public:
+  typedef uint32_t size_type;
+
+  typedef CGAL::Compact_container<Halfedge> Halfedges_container;
+  typedef CGAL::Compact_container<Vertex>   Vertices_container;
+
+  void clear()
+  {
+    m_halfedges.clear();
+    m_vertices.clear();
+  }
+
+  std::size_t number_of_halfedges() const
+  { return m_halfedges.size(); }
+  std::size_t number_of_vertices() const
+  { return m_vertices.size(); }
+
+  Halfedges_container& halfedges()
+  { return m_halfedges; }
+  Vertices_container& vertices()
+  { return m_vertices; }
+
+  const Halfedges_container& halfedges() const
+  { return m_halfedges; }
+  const Vertices_container& vertices() const
+  { return m_vertices; }
+
+  Halfedge_handle opposite(Halfedge_handle hh) const
+  { return hh->m_opposite; }
+  Halfedge_handle prev_around_vertex(Halfedge_handle hh) const
+  { return hh->m_prev_around_vertex; }
+  Halfedge_handle next_around_vertex(Halfedge_handle hh) const
+  { return hh->m_next_around_vertex; }
+  Vertex_handle vertex(Halfedge_handle hh) const
+  { return hh->m_vertex; }
+  Face_handle face(Halfedge_handle hh) const
+  { return hh->m_face; }
+  const EPoint& point(Vertex_handle vh) const
+  { return vh->point(); }
+  const EPoint& point(Halfedge_handle hh) const
+  { return point(vertex(hh)); }
+ int edge_id(Halfedge_handle hh) const
+  { return hh->m_edge_id; }
+
+  void move_to_opposite(Halfedge_handle& hh) const
+  { hh=opposite(hh); }
+  void move_to_prev_around_vertex(Halfedge_handle& hh) const
+  { hh=prev_around_vertex(hh); }
+  void move_to_next_around_vertex(Halfedge_handle& hh) const
+  { hh=next_around_vertex(hh); }
+
+  // @return true iff halfedge hh is from left to right
+  //   (or vertical and from bottom to top)
+  bool left_to_right(Halfedge_handle hh) const
+  { return edge_id(hh)>0; }
+  // @return true iff halfedge hh is from right to left
+  bool right_to_left(Halfedge_handle hh) const
+  { return edge_id(hh)<0; }
+
+  Vertex_handle create_vertex(const EPoint& p)
+  { return m_vertices.emplace(p); }
+  void set_vertex(Halfedge_handle hh, Vertex_handle vh)
+  { hh->m_vertex=vh; }
+  void set_vertex(Halfedge_handle hh, const EPoint& p)
+  { set_vertex(hh, create_vertex(p)); }
+
+  Halfedge_handle create_edge(Vertex_handle vh, int segmentid)
+  {
+    assert(segmentid>0);
+
+    Halfedge_handle hh1=m_halfedges.emplace(nullptr, vh, segmentid);
+    Halfedge_handle hh2=m_halfedges.emplace(hh1, nullptr, -segmentid);
+    hh1->m_opposite=hh2;
+
+    return hh1;
+  }
+
+  void erase_halfedge(Halfedge_handle hh)
+  { m_halfedges.erase(hh); }
+
+  void erase_edge(Halfedge_handle hh)
+  {
+    erase_halfedge(hh->m_opposite);
+    erase_halfedge(hh);
+  }
+
+  Halfedge_handle add_segment_around_vertex(Halfedge_handle hh,
+                                            Vertex_handle vh,
+                                            Halfedge_handle prevhh)
+  {
+    if (prevhh==nullptr)
+    {
+      assert(vh->first_halfedge()==nullptr);
+      vh->m_first_halfedge=hh;
+    }
+    else
+    {
+      assert(vh->first_halfedge()!=nullptr);
+      prevhh->m_next_around_vertex=hh;
+      hh->m_prev_around_vertex=prevhh;
+    }
+    return hh;
+  }
+
+  void end_of_vertex(Vertex_handle vh, Halfedge_handle prevhh)
+  {
+    assert(vh->first_halfedge()!=nullptr);
+    {
+      prevhh->m_next_around_vertex=vh->first_halfedge();
+      vh->first_halfedge()->m_prev_around_vertex=prevhh;
+    }
+  }
+
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const HDS& hds)
+  {
+    os<<hds.halfedges().size()<<" "<<hds.vertices().size()<<std::endl;
+    for (auto it=hds.vertices().begin(), itend=hds.vertices().end(); it!=itend; ++it)
+    {
+      assert(it->first_halfedge()!=nullptr);
+      it->serialize_point(os);
+      os<<" "<<hds.halfedges().index(it->first_halfedge())
+       <<" "<<(it->above_halfedge()==nullptr?'-':'+');
+      if (it->above_halfedge()!=nullptr)
+      { os<<" "<<hds.halfedges().index(it->above_halfedge()); }
+      os<<std::endl;
+    }
+
+    os<<std::endl;
+    for (auto it=hds.halfedges().begin(), itend=hds.halfedges().end(); it!=itend; ++it)
+    {
+      assert(it->opposite()!=nullptr);
+      assert(it->vertex()==nullptr || it->prev_around_vertex()!=nullptr);
+      assert(it->vertex()==nullptr || it->next_around_vertex()!=nullptr);
+
+      os<<" "<<hds.halfedges().index(it->opposite())
+       <<" "<<(it->vertex()!=nullptr?'+':'-');
+      if (it->vertex()!=nullptr)
+      {
+        os<<" "<<hds.halfedges().index(it->prev_around_vertex())
+         <<" "<<hds.halfedges().index(it->next_around_vertex())
+        <<" "<<hds.vertices().index(it->vertex());
+      }
+      os<<" "<<it->edge_id()<<std::endl;
+    }
+    return os;
+  }
+
+  void load(std::istream& is,
+            std::vector<Halfedge_handle>& halfedges,
+            std::vector<Vertex_handle>& vertices)
+  {
+    clear();
+    halfedges.clear();
+    vertices.clear();
+
+    std::size_t nb_halfedges, nb_vertices;
+    is>>nb_halfedges>>nb_vertices;
+
+    halfedges.reserve(nb_halfedges);
+    vertices.reserve(nb_vertices);
+
+    for (std::size_t i=0; i<nb_vertices; ++i)
+    { vertices.push_back(m_vertices.emplace()); }
+    for (std::size_t i=0; i<nb_halfedges; ++i)
+    { halfedges.push_back(m_halfedges.emplace()); }
+
+    EPoint p;
+    std::size_t ind1, ind2, ind3, ind4;
+    int int1;
+    char c;
+
+    for (std::size_t i=0; i<nb_vertices; ++i)
+    {
+      is>>p>>ind1>>c;
+      if (c=='+') is>>ind2;
+      vertices[i]->set(p, halfedges[ind1], (c=='+'?halfedges[ind2]:nullptr));
+    }
+    for (std::size_t i=0; i<nb_halfedges; ++i)
+    {
+      is>>ind1>>c;
+      if (c=='+') is>>ind2>>ind3>>ind4;
+      is>>int1;
+      halfedges[i]->set(halfedges[ind1],
+                        (c=='+'?halfedges[ind2]:nullptr),
+                        (c=='+'?halfedges[ind3]:nullptr),
+                        (c=='+'?vertices[ind4]:nullptr), int1);
+    }
+  }
+
+  friend std::istream& operator>>(std::istream& is, HDS& hds)
+  {
+    std::vector<Halfedge_handle> halfedges;
+    std::vector<Vertex_handle> vertices;
+    hds.load(is, halfedges, vertices);
+    return is;
+  }
+
+  void export_to_xfig(Export_xfig& export_xfig,
+                      double dx, double dy,
+                      uint8_t coul_segments,
+                      uint8_t coul_disks,
+                      uint16_t width_segments,
+                      uint16_t radius_disks) const
+  {
+    if (width_segments>0)
+    {
+      for (auto it=halfedges().begin(), itend=halfedges().end(); it!=itend; ++it)
+      {
+        if (it->vertex()!=nullptr && it->opposite()->vertex()!=nullptr &&
+            it<it->opposite())
+        {
+          export_xfig.segment(CGAL::to_double(it->vertex()->point().x())+dx,
+                              CGAL::to_double(it->vertex()->point().y())+dy,
+                              CGAL::to_double(it->opposite()->vertex()->point().x())+dx,
+                              CGAL::to_double(it->opposite()->vertex()->point().y())+dy,
+                              coul_segments, width_segments, false, 90);
+        }
+      }
+    }
+
+    if (radius_disks>0)
+    {
+      for (auto it=vertices().begin(), itend=vertices().end(); it!=itend; ++it)
+      {
+        export_xfig.point(CGAL::to_double(it->point().x())+dx,
+                          CGAL::to_double(it->point().y())+dy,
+                          radius_disks, coul_disks, false, 70);
+      }
+    }
+  }
+
+protected:
+    CGAL::Compact_container<Halfedge> m_halfedges;
+    CGAL::Compact_container<Vertex>   m_vertices;
+};
+////////////////////////////////////////////////////////////////////////////////
+#endif // HDS_H
diff --git a/src/My_arr_segment_traits_2.h b/src/My_arr_segment_traits_2.h
new file mode 100644
index 0000000000000000000000000000000000000000..7fed9307e7fc7c55ed6c9e0a75c9f07b13a839b5
--- /dev/null
+++ b/src/My_arr_segment_traits_2.h
@@ -0,0 +1,1556 @@
+// Copyright (c) 2006,2007,2009,2010,2011 Tel-Aviv University (Israel).
+// All rights reserved.
+//
+// This file is part of CGAL (www.cgal.org).
+//
+// $URL$
+// $Id$
+// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
+//
+// Author(s): Ron Wein          <wein@post.tau.ac.il>
+//            Efi Fogel         <efif@gmail.com>
+//            Waqar Khan        <wkhan@mpi-inf.mpg.de>
+//            Simon Giraudot    <simon.giraudot@geometryfactory.com>
+
+#ifndef MY_ARR_SEGMENT_TRAITS_2_H
+#define MY_ARR_SEGMENT_TRAITS_2_H
+
+#include <CGAL/disable_warnings.h>
+
+/*! \file
+ * The segment traits-class for the arrangement package.
+ */
+
+#include <fstream>
+
+#include <boost/variant.hpp>
+
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/tags.h>
+#include <CGAL/intersections.h>
+#include <CGAL/Arr_tags.h>
+#include <CGAL/Arr_enums.h>
+#include <CGAL/Arr_geometry_traits/Segment_assertions.h>
+
+/*! \class A traits class for maintaining an arrangement of segments, avoiding
+ * cascading of computations as much as possible.
+ *
+ * The class is derived from the parameterized kernel to extend the traits
+ * with all the types and operations supported by the kernel. This makes it
+ * possible to use the traits class for data structures that extend the
+ * Arrangement_2 type and require objects and operations supported by the
+ * kernel, but not defined in this derived class.
+ */
+
+template <typename Kernel_ = CGAL::Exact_predicates_exact_constructions_kernel>
+class My_arr_segment_2;
+
+template <typename Kernel_ = CGAL::Exact_predicates_exact_constructions_kernel>
+class My_arr_segment_traits_2 : public Kernel_ {
+  friend class My_arr_segment_2<Kernel_>;
+
+public:
+  typedef Kernel_                         Kernel;
+  typedef typename Kernel::FT             FT;
+
+  typedef typename CGAL::Algebraic_structure_traits<FT>::Is_exact
+                                          Has_exact_division;
+
+  // Category tags:
+  typedef CGAL::Tag_true                        Has_left_category;
+  typedef CGAL::Tag_true                        Has_merge_category;
+  typedef CGAL::Tag_false                       Has_do_intersect_category;
+
+  typedef CGAL::Arr_oblivious_side_tag          Left_side_category;
+  typedef CGAL::Arr_oblivious_side_tag          Bottom_side_category;
+  typedef CGAL::Arr_oblivious_side_tag          Top_side_category;
+  typedef CGAL::Arr_oblivious_side_tag          Right_side_category;
+
+  typedef typename Kernel::Line_2         Line_2;
+  typedef CGAL::Segment_assertions<My_arr_segment_traits_2<Kernel> >
+                                          Segment_assertions;
+
+  using Comparison_result=CGAL::Comparison_result;
+#define SMALLER CGAL::SMALLER
+#define EQUAL CGAL::EQUAL
+#define LARGER CGAL::LARGER
+  // using Bbox_2=CGAL::Bbox_2;
+
+  /*! \class Representation of a segment with cached data.
+   */
+  class _Segment_cached_2 {
+  public:
+    typedef typename Kernel::Line_2                Line_2;
+    typedef typename Kernel::Segment_2             Segment_2;
+    typedef typename Kernel::Point_2               Point_2;
+
+  protected:
+    Line_2 m_l;               // the line that supports the segment.
+    Point_2 m_ps;             // the source point of the segment.
+    Point_2 m_pt;             // the target point of the segment.
+    bool m_is_directed_right; // is (lexicographically) directed left to right.
+    bool m_is_vert;           // is this a vertical segment.
+    bool m_is_degen;          // is the segment degenerate (a single point).
+
+  public:
+
+    /// \name Creation
+    //@{
+
+    /*! Construct default. */
+    _Segment_cached_2();
+
+    /*! Construct a segment from a Kernel segment.
+     * \param seg the segment.
+     * \pre the segment is not degenerate.
+     */
+    _Segment_cached_2(const Segment_2& seg);
+
+    /*! Construct a segment from two endpoints.
+     * \param source the source point.
+     * \param target the target point.
+     * \param `source` and `target` are not equal.
+     */
+    _Segment_cached_2(const Point_2& source, const Point_2& target);
+
+    /*! Construct a segment from two endpoints on a supporting line.
+     * \param line the supporting line.
+     * \param source the source point.
+     * \param target the target point.
+     * \pre `source` and `target` are not equal and both lie on `line`.
+     */
+    _Segment_cached_2(const Line_2& line,
+                      const Point_2& source, const Point_2& target);
+
+    /*! Construct a segment from all fields.
+     * \param line the supporting line.
+     * \param source the source point.
+     * \param target the target point.
+     * \param is_directed_right is (lexicographically) directed left to right.
+     * \param is_vert is the segment vertical.
+     * \param is_degen is the segment degenerate (a single point).
+     */
+    _Segment_cached_2(const Line_2& line,
+                      const Point_2& source, const Point_2& target,
+                      bool is_directed_right, bool is_vert, bool is_degen);
+
+    /*! Assign.
+     * \param seg the source segment to copy from
+     * \pre the segment is not degenerate.
+     */
+    const _Segment_cached_2& operator=(const Segment_2& seg);
+
+    //@}
+
+    /// \name Accessors
+    //@{
+
+    /*! Obtain the supporting line.
+     * \return the supporting line.
+     */
+    const Line_2& line() const;
+
+    /*! Obtain the segment source.
+     * \return the segment source.
+     */
+    const Point_2& source() const;
+
+    /*! Obtain the segment target.
+     * \return the segment target.
+     */
+    const Point_2& target() const;
+
+    /*! Determine whether the curve is vertical.
+     * \return a Boolean flag indicating whether the curve is vertical.
+     */
+    bool is_vertical() const;
+
+    /*! Determine whether the curve is degenerate.
+     * return a Boolean flag indicating whether the curve is degenerate.
+     */
+    bool is_degenerate() const;
+
+    /*! Determine whether the curve is lexicographically directed from left to
+     * right.
+     * \return a Boolean flag indicating whether the curve is lexicographically
+     *         directed from left to right.
+     */
+    bool is_directed_right() const;
+
+    /*! Obtain the (lexicographically) left endpoint.
+     * \return the (lexicographically) left endpoint.
+     */
+    const Point_2& left() const;
+
+    /*! Obtain the (lexicographically) right endpoint.
+     * \return the (lexicographically) right endpoint.
+     */
+    const Point_2& right() const;
+
+    //@}
+
+    /// \name Modifiers
+    //@{
+
+    /*! Set the (lexicographically) left endpoint.
+     * \param p the point to set.
+     * \pre p lies on the supporting line to the left of the right endpoint.
+     */
+    void set_left(const Point_2& p);
+
+    /*! Set the (lexicographically) right endpoint.
+     * \param p the point to set.
+     * \pre p lies on the supporting line to the right of the left endpoint.
+     */
+    void set_right(const Point_2& p);
+
+    //@}
+
+    /// \name Deprecated
+    //@{
+
+    /*! Determine whether the given point is in the x-range of the segment.
+     * \param p the query point.
+     * \return (true) is in the x-range of the segment; (false) if it is not.
+     */
+    CGAL_DEPRECATED bool is_in_x_range(const Point_2& p) const;
+
+    /*! Determine whether the given point is in the y-range of the segment.
+     * \param p the query point.
+     * \return (true) is in the y-range of the segment; (false) if it is not.
+     */
+    CGAL_DEPRECATED bool is_in_y_range(const Point_2& p) const;
+
+    //@}
+  };
+
+public:
+  // Traits objects
+  typedef typename Kernel::Point_2        Point_2;
+  typedef My_arr_segment_2<Kernel>           X_monotone_curve_2;
+  typedef My_arr_segment_2<Kernel>           Curve_2;
+  typedef unsigned int                    Multiplicity;
+
+public:
+  /*! Construct default. */
+  My_arr_segment_traits_2() {}
+
+  /// \name Basic functor definitions.
+  //@{
+
+  class Compare_x_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    //! The traits (in case it has state).
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Compare_x_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Compare the x-coordinates of two points.
+     * \param p1 the first point.
+     * \param p2 the second point.
+     * \return LARGER if x(p1) > x(p2);
+     *         SMALLER if x(p1) < x(p2);
+     *         EQUAL if x(p1) = x(p2).
+     */
+    Comparison_result operator()(const Point_2& p1, const Point_2& p2) const
+    {
+      const Kernel& kernel = m_traits;
+      return (kernel.compare_x_2_object()(p1, p2));
+    }
+  };
+
+  /*! Obtain a Compare_x_2 functor object. */
+  Compare_x_2 compare_x_2_object() const { return Compare_x_2(*this); }
+
+  class Compare_xy_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    /*! The traits (in case it has state) */
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Compare_xy_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Compare two points lexicographically: by x, then by y.
+     * \param p1 the first point.
+     * \param p2 the second point.
+     * \return LARGER if x(p1) > x(p2), or if x(p1) = x(p2) and y(p1) > y(p2);
+     *         SMALLER if x(p1) < x(p2), or if x(p1) = x(p2) and y(p1) < y(p2);
+     *         EQUAL if the two points are equal.
+     */
+    Comparison_result operator()(const Point_2& p1, const Point_2& p2) const
+    {
+      const Kernel& kernel = m_traits;
+      return (kernel.compare_xy_2_object()(p1, p2));
+    }
+  };
+
+  /*! Obtain a Compare_xy_2 functor object. */
+  Compare_xy_2 compare_xy_2_object() const { return Compare_xy_2(*this); }
+
+  class Construct_min_vertex_2 {
+  public:
+    /*! Obtain the left endpoint of the x-monotone curve (segment).
+     * \param cv the curve.
+     * \return the left endpoint.
+     */
+    const Point_2& operator()(const X_monotone_curve_2& cv) const
+    { return (cv.left()); }
+  };
+
+  /*! Obtain a Construct_min_vertex_2 functor object. */
+  Construct_min_vertex_2 construct_min_vertex_2_object() const
+  { return Construct_min_vertex_2(); }
+
+  class Construct_max_vertex_2 {
+  public:
+    /*! Obtain the right endpoint of the x-monotone curve (segment).
+     * \param cv the curve.
+     * \return the right endpoint.
+     */
+    const Point_2& operator()(const X_monotone_curve_2& cv) const
+    { return (cv.right()); }
+  };
+
+  /*! Obtain a Construct_max_vertex_2 functor object. */
+  Construct_max_vertex_2 construct_max_vertex_2_object() const
+  { return Construct_max_vertex_2(); }
+
+  class Is_vertical_2 {
+  public:
+    /*! Check whether the given x-monotone curve is a vertical segment.
+     * \param cv the curve.
+     * \return (true) if the curve is a vertical segment; (false) otherwise.
+     */
+    bool operator()(const X_monotone_curve_2& cv) const
+    { return (cv.is_vertical()); }
+  };
+
+  /*! Obtain an Is_vertical_2 functor object. */
+  Is_vertical_2 is_vertical_2_object () const { return Is_vertical_2(); }
+
+  class Compare_y_at_x_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    /*! the traits (in case it has state) */
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Compare_y_at_x_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Return the location of the given point with respect to the input curve.
+     * \param cv the curve.
+     * \param p the point.
+     * \pre p is in the x-range of cv.
+     * \return SMALLER if y(p) < cv(x(p)), i.e. the point is below the curve;
+     *         LARGER if y(p) > cv(x(p)), i.e. the point is above the curve;
+     *         EQUAL if p lies on the curve.
+     */
+    Comparison_result operator()(const Point_2& p,
+                                 const X_monotone_curve_2& cv) const
+    {
+      CGAL_precondition(m_traits.is_in_x_range_2_object()(cv, p));
+
+      const Kernel& kernel = m_traits;
+
+      if (! cv.is_vertical()) {
+        // Compare p with the segment supporting line.
+        CGAL_assertion_code(auto cmp_x = kernel.compare_x_2_object());
+        CGAL_assertion(cmp_x(cv.left(), cv.right()) == SMALLER);
+        return kernel.orientation_2_object()(cv.left(), cv.right(), p);
+      }
+
+      // Compare with the vertical segment endpoints.
+      auto compare_y = kernel.compare_y_2_object();
+      Comparison_result res1 = compare_y(p, cv.left());
+      Comparison_result res2 = compare_y(p, cv.right());
+      return (res1 == res2) ? res1 : EQUAL;
+    }
+  };
+
+  /*! Obtain a Compare_y_at_x_2 functor object. */
+  Compare_y_at_x_2 compare_y_at_x_2_object() const
+  { return Compare_y_at_x_2(*this); }
+
+  class Compare_y_at_x_left_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    /*! The traits (in case it has state) */
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Compare_y_at_x_left_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Compare the y value of two x-monotone curves immediately to the left
+     * of their intersection point.
+     * \param cv1 the first curve.
+     * \param cv2 the second curve.
+     * \param p the intersection point.
+     * \pre the point p lies on both curves, and both of them must be also be
+     *      defined (lexicographically) to its left.
+     * \return the relative position of cv1 with respect to cv2 immediately to
+     *         the left of p: SMALLER, LARGER or EQUAL.
+     */
+    Comparison_result operator()(const X_monotone_curve_2& cv1,
+                                 const X_monotone_curve_2& cv2,
+                                 const Point_2& CGAL_assertion_code(p)) const
+    {
+      const Kernel& kernel = m_traits;
+
+      // Make sure that p lies on both curves, and that both are defined to its
+      // left (so their left endpoint is lexicographically smaller than p).
+      CGAL_precondition_code(auto compare_xy = kernel.compare_xy_2_object());
+
+      CGAL_precondition((m_traits.compare_y_at_x_2_object()(p, cv1) == EQUAL) &&
+                        (m_traits.compare_y_at_x_2_object()(p, cv2) == EQUAL));
+
+      CGAL_precondition(compare_xy(cv1.left(), p) == SMALLER &&
+                        compare_xy(cv2.left(), p) == SMALLER);
+
+      // Compare the slopes of the two segments to determine their relative
+      // position immediately to the left of q.
+      // Notice we use the supporting lines in order to compare the slopes,
+      // and that we swap the order of the curves in order to obtain the
+      // correct result to the left of p.
+      return (kernel.compare_slope_2_object()(cv2.line(), cv1.line()));
+    }
+  };
+
+  /*! Obtain a Compare_y_at_x_left_2 functor object. */
+  Compare_y_at_x_left_2 compare_y_at_x_left_2_object() const
+  { return Compare_y_at_x_left_2(*this); }
+
+  class Compare_y_at_x_right_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    /*! The traits (in case it has state) */
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Compare_y_at_x_right_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Compare the y value of two x-monotone curves immediately to the right
+     * of their intersection point.
+     * \param cv1 the first curve.
+     * \param cv2 the second curve.
+     * \param p the intersection point.
+     * \pre the point p lies on both curves, and both of them must be also be
+     *      defined (lexicographically) to its right.
+     * \return the relative position of cv1 with respect to cv2 immediately to
+     *         the right of p: SMALLER, LARGER or EQUAL.
+     */
+    Comparison_result operator()(const X_monotone_curve_2& cv1,
+                                 const X_monotone_curve_2& cv2,
+                                 const Point_2& CGAL_assertion_code(p)) const
+    {
+      const Kernel& kernel = m_traits;
+
+      // Make sure that p lies on both curves, and that both are defined to its
+      // right (so their right endpoint is lexicographically larger than p).
+      CGAL_precondition_code(auto compare_xy = kernel.compare_xy_2_object());
+
+      CGAL_precondition((m_traits.compare_y_at_x_2_object()(p, cv1) == EQUAL) &&
+                        (m_traits.compare_y_at_x_2_object()(p, cv2) == EQUAL));
+
+      CGAL_precondition(compare_xy(cv1.right(), p) == LARGER &&
+                        compare_xy(cv2.right(), p) == LARGER);
+
+      // Compare the slopes of the two segments to determine their relative
+      // position immediately to the left of q.
+      // Notice we use the supporting lines in order to compare the slopes.
+      return (kernel.compare_slope_2_object()(cv1.line(), cv2.line()));
+    }
+  };
+
+  /*! Obtain a Compare_y_at_x_right_2 functor object. */
+  Compare_y_at_x_right_2 compare_y_at_x_right_2_object() const
+  { return Compare_y_at_x_right_2(*this); }
+
+  class Equal_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    /*! The traits (in case it has state) */
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Equal_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Check whether the two x-monotone curves are the same (have the same
+     * graph).
+     * \param cv1 the first curve.
+     * \param cv2 the second curve.
+     * \return (true) if the two curves are the same; (false) otherwise.
+     */
+    bool operator()(const X_monotone_curve_2& cv1,
+                    const X_monotone_curve_2& cv2) const
+    {
+      const Kernel& kernel = m_traits;
+      typename Kernel::Equal_2  equal = kernel.equal_2_object();
+
+      return (equal(cv1.left(), cv2.left()) &&
+              equal(cv1.right(), cv2.right()));
+    }
+
+    /*! Determine whether the two points are the same.
+     * \param p1 the first point.
+     * \param p2 the second point.
+     * \return (true) if the two point are the same; (false) otherwise.
+     */
+    bool operator()(const Point_2& p1, const Point_2& p2) const
+    {
+      const Kernel& kernel = m_traits;
+      return (kernel.equal_2_object()(p1, p2));
+    }
+  };
+
+  /*! Obtain an Equal_2 functor object. */
+  Equal_2 equal_2_object() const { return Equal_2(*this); }
+
+  //@}
+
+  //! \name Intersections, subdivisions, and mergings
+  //@{
+
+  /*! \class Make_x_monotone_2
+   * A functor for subdividing a curve into x-monotone curves.
+   */
+  class Make_x_monotone_2 {
+  public:
+    /*! Subdivide a given curve into x-monotone subcurves and insert them into
+     * a given output iterator. As segments are always x_monotone a single
+     * object is inserted.
+     * \param cv the curve.
+     * \param oi the output iterator for the result. Its dereference type is a
+     *           variant that wraps a \c Point_2 or an \c X_monotone_curve_2
+     *           objects.
+     * \return the past-the-end output iterator.
+     */
+    template <typename OutputIterator>
+    OutputIterator operator()(const Curve_2& cv, OutputIterator oi) const
+    {
+      // Wrap the segment with a variant.
+      typedef boost::variant<Point_2, X_monotone_curve_2>
+        Make_x_monotone_result;
+      *oi++ = Make_x_monotone_result(cv);
+      return oi;
+    }
+  };
+
+  /*! Obtain a Make_x_monotone_2 functor object. */
+  Make_x_monotone_2 make_x_monotone_2_object() const
+  { return Make_x_monotone_2(); }
+
+  class Split_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    /*! The traits (in case it has state) */
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Split_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Split a given x-monotone curve at a given point into two sub-curves.
+     * \param cv the curve to split
+     * \param p the split point.
+     * \param c1 Output: the left resulting subcurve (p is its right endpoint).
+     * \param c2 Output: the right resulting subcurve (p is its left endpoint).
+     * \pre p lies on cv but is not one of its endpoints.
+     */
+    void operator()(const X_monotone_curve_2& cv, const Point_2& p,
+                    X_monotone_curve_2& c1, X_monotone_curve_2& c2) const
+    {
+      // Make sure that p lies on the interior of the curve.
+      CGAL_precondition_code(const Kernel& kernel = m_traits;
+                             auto compare_xy = kernel.compare_xy_2_object());
+
+      CGAL_precondition((m_traits.compare_y_at_x_2_object()(p, cv) == EQUAL) &&
+                        compare_xy(cv.left(), p) == SMALLER &&
+                        compare_xy(cv.right(), p) == LARGER);
+
+      // Perform the split.
+      c1 = cv;
+      c1.set_right(p);
+
+      c2 = cv;
+      c2.set_left(p);
+    }
+  };
+
+  /*! Obtain a Split_2 functor object. */
+  Split_2 split_2_object() const { return Split_2(*this); }
+
+  class Intersect_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    /*! The traits (in case it has state) */
+    const Traits& m_traits;
+
+    /*! Construct
+     * \param traits the traits (in case it has state)
+     */
+    Intersect_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+    // Specialized do_intersect with many tests skipped because at
+    // this point, we already know which point is left / right for
+    // both segments
+    bool do_intersect(const Point_2& A1, const Point_2& A2,
+                      const Point_2& B1, const Point_2& B2) const
+    {
+      const Kernel& kernel = m_traits;
+      auto compare_xy = kernel.compare_xy_2_object();
+      namespace interx = CGAL::Intersections::internal;
+
+      switch(make_certain(compare_xy(A1,B1))) {
+       case SMALLER:
+        switch(make_certain(compare_xy(A2,B1))) {
+         case SMALLER: return false;
+         case EQUAL: return true;
+         default: // LARGER
+          switch(make_certain(compare_xy(A2,B2))) {
+           case SMALLER:
+            return interx::seg_seg_do_intersect_crossing(A1,A2,B1,B2, kernel);
+           case EQUAL: return true;
+           default: // LARGER
+            return interx::seg_seg_do_intersect_contained(A1,A2,B1,B2, kernel);
+          }
+        }
+       case EQUAL: return true;
+       default: // LARGER
+        switch(make_certain(compare_xy(B2,A1))) {
+         case SMALLER: return false;
+         case EQUAL: return true;
+         default: // LARGER
+          switch(make_certain(compare_xy(B2,A2))) {
+           case SMALLER:
+            return interx::seg_seg_do_intersect_crossing(B1,B2,A1,A2, kernel);
+           case EQUAL: return true;
+           default: // LARGER
+            return interx::seg_seg_do_intersect_contained(B1,B2,A1,A2, kernel);
+          }
+        }
+      }
+      CGAL_error();     // never reached
+      return false;
+    }
+
+    /*! Determine whether the bounding boxes of two segments overlap
+     */
+    bool do_bboxes_overlap(const X_monotone_curve_2& cv1,
+                           const X_monotone_curve_2& cv2) const
+    {
+      const Kernel& kernel = m_traits;
+      auto construct_bbox = kernel.construct_bbox_2_object();
+      auto bbox1 = construct_bbox(cv1.source()) + construct_bbox(cv1.target());
+      auto bbox2 = construct_bbox(cv2.source()) + construct_bbox(cv2.target());
+      return CGAL::do_overlap(bbox1, bbox2);
+    }
+
+  public:
+    /*! Find the intersections of the two given curves and insert them into the
+     * given output iterator. As two segments may intersect only once, only a
+     * single intersection will be contained in the iterator.
+     * \param cv1 the first curve.
+     * \param cv2 the second curve.
+     * \param oi the output iterator.
+     * \return the past-the-end iterator.
+     */
+    template <typename OutputIterator>
+    OutputIterator operator()(const X_monotone_curve_2& cv1,
+                              const X_monotone_curve_2& cv2,
+                              OutputIterator oi) const
+    {
+      typedef std::pair<Point_2, Multiplicity>          Intersection_point;
+      typedef boost::variant<Intersection_point, X_monotone_curve_2>
+                                                        Intersection_result;
+
+      // Early ending with Bbox overlapping test
+      if (! do_bboxes_overlap(cv1, cv2)) return oi;
+
+      // Early ending with specialized do_intersect
+      const Kernel& kernel = m_traits;
+      if (! do_intersect(cv1.left(), cv1.right(), cv2.left(), cv2.right()))
+        return oi;
+
+      // An intersection is guaranteed.
+
+      // Intersect the two supporting lines.
+      auto res = kernel.intersect_2_object()(cv1.line(), cv2.line());
+      CGAL_assertion(bool(res));
+
+      // Check if we have a single intersection point.
+      const Point_2* ip = boost::get<Point_2>(&*res);
+      if (ip != nullptr) {
+        CGAL_assertion(cv1.is_vertical() ?
+                       m_traits.is_in_y_range_2_object()(cv1, *ip) :
+                       m_traits.is_in_x_range_2_object()(cv1, *ip));
+        CGAL_assertion(cv2.is_vertical() ?
+                       m_traits.is_in_y_range_2_object()(cv2, *ip) :
+                       m_traits.is_in_x_range_2_object()(cv2, *ip));
+        Intersection_point ip_mult(*ip, 1);
+        *oi++ = Intersection_result(ip_mult);
+        return oi;
+      }
+
+      // In this case, the two supporting lines overlap.
+      // The overlapping segment is therefore [p_l,p_r], where p_l is the
+      // rightmost of the two left endpoints and p_r is the leftmost of the
+      // two right endpoints.
+      auto compare_xy = kernel.compare_xy_2_object();
+      const Point_2& p_l = (compare_xy(cv1.left(), cv2.left()) == SMALLER) ?
+        cv2.left() : cv1.left();
+      const Point_2& p_r = (compare_xy(cv1.right(), cv2.right()) == SMALLER) ?
+        cv1.right() : cv2.right();
+
+      // Examine the resulting segment.
+      const Comparison_result cmp_res = compare_xy(p_l, p_r);
+      if (cmp_res == EQUAL) {
+        // The two segment have the same supporting line, but they just share
+        // a common endpoint. Thus we have an intersection point, but we leave
+        // the multiplicity of this point undefined.
+        Intersection_point ip_mult(p_r, 0);
+        *oi++ = Intersection_result(ip_mult);
+        return oi;
+      }
+
+      CGAL_assertion(cmp_res == SMALLER);
+      // We have discovered an overlapping segment:
+      if (cv1.is_directed_right() == cv2.is_directed_right()) {
+        // cv1 and cv2 have the same directions, maintain this direction
+        // in the overlap segment
+        if (cv1.is_directed_right()) {
+          X_monotone_curve_2 overlap_seg(cv1.line(), p_l, p_r, cv1.m_original_segment_id);
+          *oi++ = Intersection_result(overlap_seg);
+          return oi;
+        }
+        X_monotone_curve_2 overlap_seg(cv1.line(), p_r, p_l, cv1.m_original_segment_id);
+        *oi++ = Intersection_result(overlap_seg);
+        return oi;
+      }
+      // cv1 and cv2 have opposite directions, the overlap segment
+      // will be directed from left to right
+      X_monotone_curve_2 overlap_seg(cv1.line(), p_l, p_r, cv1.m_original_segment_id);
+      *oi++ = Intersection_result(overlap_seg);
+      return oi;
+    }
+  };
+
+  /*! Obtain an Intersect_2 functor object. */
+  Intersect_2 intersect_2_object() const { return Intersect_2(*this); }
+
+  class Are_mergeable_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    /*! The traits (in case it has state) */
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Are_mergeable_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Check whether it is possible to merge two given x-monotone curves.
+     * \param cv1 the first curve.
+     * \param cv2 the second curve.
+     * \return (true) if the two curves are mergeable, that is, if they are
+     *         supported by the same line; (false) otherwise.
+     * \pre cv1 and cv2 share a common endpoint.
+     */
+    bool operator()(const X_monotone_curve_2& cv1,
+                    const X_monotone_curve_2& cv2) const
+    {
+      const Kernel& kernel = m_traits;
+      typename Kernel::Equal_2 equal = kernel.equal_2_object();
+      if (! equal(cv1.right(), cv2.left()) &&
+          ! equal(cv2.right(), cv1.left()))
+        return false;
+
+      // Check whether the two curves have the same supporting line.
+      return (equal(cv1.line(), cv2.line()) ||
+              equal(cv1.line(),
+                    kernel.construct_opposite_line_2_object()(cv2.line())));
+    }
+  };
+
+  /*! Obtain an Are_mergeable_2 functor object. */
+  Are_mergeable_2 are_mergeable_2_object() const
+  { return Are_mergeable_2(*this); }
+
+  /*! \class Merge_2
+   * A functor that merges two x-monotone arcs into one.
+   */
+  class Merge_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    /*! The traits (in case it has state) */
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Merge_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Merge two given x-monotone curves into a single curve (segment).
+     * \param cv1 the first curve.
+     * \param cv2 the second curve.
+     * \param c Output: the merged curve.
+     * \pre the two curves are mergeable.
+     */
+    void operator()(const X_monotone_curve_2& cv1,
+                    const X_monotone_curve_2& cv2,
+                    X_monotone_curve_2& c) const
+    {
+      CGAL_precondition(m_traits.are_mergeable_2_object()(cv1, cv2));
+
+      const Kernel& kernel = m_traits;
+      auto equal = kernel.equal_2_object();
+
+      // Check which curve extends to the right of the other.
+      if (equal(cv1.right(), cv2.left())) {
+        // cv2 extends cv1 to the right.
+        c = cv1;
+        c.set_right(cv2.right());
+        return;
+      }
+
+      CGAL_precondition(equal(cv2.right(), cv1.left()));
+
+      // cv1 extends cv2 to the right.
+      c = cv2;
+      c.set_right(cv1.right());
+    }
+  };
+
+  /*! Obtain a Merge_2 functor object. */
+  Merge_2 merge_2_object() const { return Merge_2(*this); }
+  //@}
+
+  /// \name Functor definitions for the landmarks point-location strategy.
+  //@{
+  typedef double                          Approximate_number_type;
+
+  class Approximate_2 {
+  public:
+    /*! Obtain an approximation of a point coordinate.
+     * \param p the exact point.
+     * \param i the coordinate index (either 0 or 1).
+     * \pre i is either 0 or 1.
+     * \return An approximation of p's x-coordinate (if i == 0), or an
+     *         approximation of p's y-coordinate (if i == 1).
+     */
+    Approximate_number_type operator()(const Point_2& p, int i) const
+    {
+      CGAL_precondition((i == 0) || (i == 1));
+      return (i == 0) ? (CGAL::to_double(p.x())) : (CGAL::to_double(p.y()));
+    }
+  };
+
+  /*! Obtain an Approximate_2 functor object. */
+  Approximate_2 approximate_2_object() const { return Approximate_2(); }
+
+  class Construct_x_monotone_curve_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    //! The traits (in case it has state).
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Construct_x_monotone_curve_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    typedef typename Kernel::Segment_2          Segment_2;
+
+    /*! Obtain an x-monotone curve connecting two given endpoints.
+     * \param source the first point.
+     * \param target the second point.
+     * \pre `source` and `target` must not be equal.
+     * \return a segment connecting `source` and `target`.
+     */
+    X_monotone_curve_2 operator()(const Point_2& source,
+                                  const Point_2& target) const
+    {
+      const Kernel& kernel = m_traits;
+      auto line = kernel.construct_line_2_object()(source, target);
+      Comparison_result res = kernel.compare_xy_2_object()(source, target);
+      auto is_degen = (res == EQUAL);
+      auto is_directed_right = (res == SMALLER);
+      CGAL_precondition_msg(! is_degen,
+                            "Cannot construct a degenerate segment.");
+      auto is_vert = kernel.is_vertical_2_object()(line);
+      return X_monotone_curve_2(line, source, target,
+                                is_directed_right, is_vert, is_degen);
+    }
+
+    /*! Obtain an \f$x\f$-monotone curve given a Kernel segment.
+     * \param seg the segment.
+     * \return the \f$x\f$-monotone curve.
+     * \pre the segment is not degenerate.
+     * \return a segment that is the same as `seg`..
+     */
+    X_monotone_curve_2 operator()(const Segment_2& seg) const
+    {
+      const Kernel& kernel = m_traits;
+      auto line = kernel.construct_line_2_object()(seg);
+      auto vertex_ctr = kernel.construct_vertex_2_object();
+      auto source = vertex_ctr(seg, 0);
+      auto target = vertex_ctr(seg, 1);
+      Comparison_result res = kernel.compare_xy_2_object()(source, target);
+      auto is_degen = (res == EQUAL);
+      auto is_directed_right = (res == SMALLER);
+      CGAL_precondition_msg(! is_degen,
+                            "Cannot construct a degenerate segment.");
+      auto is_vert = kernel.is_vertical_2_object()(seg);
+      return X_monotone_curve_2(line, source, target,
+                                is_directed_right, is_vert, is_degen);
+    }
+
+    /*! Obtain an \f$x\f$-monotone curve given two endpoints and the supporting
+     * line.
+     * \param line the supporting line.
+     * \param  the source point.
+     * \param  the target point.
+     * \pre `ps` and `pt` are not equal and both lie on `line`.
+     */
+    X_monotone_curve_2 operator()(const Line_2& line,
+                                  const Point_2& source,
+                                  const Point_2& target) const
+    {
+      const Kernel& kernel = m_traits;
+      CGAL_precondition
+        (Segment_assertions::_assert_is_point_on(source, line,
+                                                 Has_exact_division()) &&
+         Segment_assertions::_assert_is_point_on(target, line,
+                                                 Has_exact_division()));
+      auto is_vert = kernel.is_vertical_2_object()(line);
+      Comparison_result res = kernel.compare_xy_2_object()(source, target);
+      auto is_degen = (res == EQUAL);
+      auto is_directed_right = (res == SMALLER);
+      CGAL_precondition_msg(! is_degen,
+                            "Cannot construct a degenerate segment.");
+      return X_monotone_curve_2(line, source, target,
+                                is_directed_right, is_vert, is_degen);
+    }
+  };
+
+  /*! Obtain a Construct_x_monotone_curve_2 functor object. */
+  Construct_x_monotone_curve_2 construct_x_monotone_curve_2_object() const
+  { return Construct_x_monotone_curve_2(*this); }
+  //@}
+
+  /// \name Functor definitions for the Boolean set-operation traits.
+  //@{
+
+  class Trim_2 {
+   protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    /*! The traits (in case it has state). */
+    const Traits& m_traits;
+
+    /*! Constructor
+     * \param traits the traits (in case it has state)
+     */
+    Trim_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+    /*! Obtain a trimmed version of a line.
+     * \param xseg the x-monotone segment.
+     * \param src the new start endpoint.
+     * \param tgt the new end endpoint.
+     * \return the trimmed x-monotone segment.
+     * \pre src != tgt
+     * \pre both points must lie on segment
+     */
+  public:
+    X_monotone_curve_2 operator()(const X_monotone_curve_2& xcv,
+                                  const Point_2& src,
+                                  const Point_2& tgt)const
+    {
+      CGAL_precondition_code(Equal_2 equal = m_traits.equal_2_object());
+      CGAL_precondition_code(Compare_y_at_x_2 compare_y_at_x =
+                             m_traits.compare_y_at_x_2_object());
+      Compare_x_2 compare_x_2 = m_traits.compare_x_2_object();
+
+      // check whether source and taget are two distinct points and they lie
+      // on the line.
+      CGAL_precondition(!equal(src, tgt));
+      CGAL_precondition(compare_y_at_x(src, xcv) == EQUAL);
+      CGAL_precondition(compare_y_at_x(tgt, xcv) == EQUAL);
+
+      // exchange src and tgt IF they do not conform with the direction
+      X_monotone_curve_2 trimmed_segment;
+      if (xcv.is_directed_right() && compare_x_2(src, tgt) == LARGER)
+        trimmed_segment = X_monotone_curve_2(tgt, src);
+      else if (! xcv.is_directed_right() && (compare_x_2(src, tgt) == SMALLER))
+        trimmed_segment = X_monotone_curve_2(tgt, src);
+      else trimmed_segment = X_monotone_curve_2(src, tgt);
+      return trimmed_segment;
+    }
+  };
+
+  /*! Obtain a Trim_2 functor object */
+  Trim_2 trim_2_object() const { return Trim_2(*this); }
+
+  class Compare_endpoints_xy_2 {
+  public:
+    /*! Compare the endpoints of an $x$-monotone curve lexicographically.
+     * (assuming the curve has a designated source and target points).
+     * \param cv the curve.
+     * \return SMALLER if the curve is directed right;
+     *         LARGER if the curve is directed left.
+     */
+    Comparison_result operator()(const X_monotone_curve_2& cv) const
+    { return (cv.is_directed_right()) ? (SMALLER) : (LARGER); }
+  };
+
+  /*! Obtain a Compare_endpoints_xy_2 functor object. */
+  Compare_endpoints_xy_2 compare_endpoints_xy_2_object() const
+  { return Compare_endpoints_xy_2(); }
+
+  class Construct_opposite_2 {
+  public:
+    /*! Construct an opposite x-monotone (with swapped source and target).
+     * \param cv the curve.
+     * \return the opposite curve.
+     */
+    X_monotone_curve_2 operator()(const X_monotone_curve_2& cv) const
+    { return (cv.flip()); }
+  };
+
+  /*! Obtain a Construct_opposite_2 functor object. */
+  Construct_opposite_2 construct_opposite_2_object() const
+  { return Construct_opposite_2(); }
+  //@}
+
+  /// \name Utilities.
+  //@{
+
+  class Is_in_x_range_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    //! The traits (in case it has state).
+    const Traits& m_traits;
+
+    /*! Construct
+     * \param traits the traits (in case it has state)
+     */
+    Is_in_x_range_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Determine whether a given point is in the \f$x\f$-range of a given
+     * segment.
+     * \param cv the segment.
+     * \param p the point.
+     * \return true if p is in the \f$x\f$-range of cv; false otherwise.
+     */
+    bool operator()(const X_monotone_curve_2& cv, const Point_2& p) const
+    {
+      const Kernel& kernel = m_traits;
+      auto compare_x = kernel.compare_x_2_object();
+      Comparison_result res1 = compare_x(p, cv.left());
+
+      if (res1 == SMALLER) return false;
+      else if (res1 == EQUAL) return true;
+
+      Comparison_result res2 = compare_x(p, cv.right());
+      return (res2 != LARGER);
+    }
+  };
+
+  /*! Obtain an Is_in_x_range_2 functor object */
+  Is_in_x_range_2 is_in_x_range_2_object() const
+  { return Is_in_x_range_2(*this); }
+
+  class Is_in_y_range_2 {
+  protected:
+    typedef My_arr_segment_traits_2<Kernel>        Traits;
+
+    //! The traits (in case it has state).
+    const Traits& m_traits;
+
+    /*! Construct
+     * \param traits the traits (in case it has state)
+     */
+    Is_in_y_range_2(const Traits& traits) : m_traits(traits) {}
+
+    friend class My_arr_segment_traits_2<Kernel>;
+
+  public:
+    /*! Determine whether a given point is in the \f$y\f$-range of a given
+     * segment.
+     * \param cv the segment.
+     * \param p the point.
+     * \return true if p is in the \f$y\f$-range of cv; false otherwise.
+     */
+    bool operator()(const X_monotone_curve_2& cv, const Point_2& p) const
+    {
+      const Kernel& kernel = m_traits;
+      auto compare_y = kernel.compare_y_2_object();
+      Comparison_result res1 = compare_y(p, cv.left());
+
+      if (res1 == SMALLER) return false;
+      else if (res1 == EQUAL) return true;
+
+      Comparison_result res2 = compare_y(p, cv.right());
+      return (res2 != LARGER);
+    }
+  };
+
+  /*! Obtain an Is_in_y_range_2 functor object */
+  Is_in_y_range_2 is_in_y_range_2_object() const
+  { return Is_in_y_range_2(*this); }
+
+  //@}
+};
+
+// Creation
+
+//! \brief constructs default.
+template <typename Kernel>
+My_arr_segment_traits_2<Kernel>::_Segment_cached_2::_Segment_cached_2() :
+  m_is_directed_right(false),
+  m_is_vert(false),
+  m_is_degen(true)
+{}
+
+//! \brief constructs a segment from a Kernel segment.
+template <typename Kernel>
+My_arr_segment_traits_2<Kernel>::
+_Segment_cached_2::_Segment_cached_2(const Segment_2& seg)
+{
+  Kernel kernel;
+  auto vertex_ctr = kernel.construct_vertex_2_object();
+
+  m_ps = vertex_ctr(seg, 0);
+  m_pt = vertex_ctr(seg, 1);
+
+  Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt);
+  m_is_degen = (res == EQUAL);
+  m_is_directed_right = (res == SMALLER);
+
+  CGAL_precondition_msg(! m_is_degen, "Cannot construct a degenerate segment.");
+
+  m_l = kernel.construct_line_2_object()(seg);
+  m_is_vert = kernel.is_vertical_2_object()(seg);
+}
+
+//! \brief Constructs a segment from two endpoints.
+template <typename Kernel>
+My_arr_segment_traits_2<Kernel>::
+_Segment_cached_2::_Segment_cached_2(const Point_2& source,
+                                     const Point_2& target) :
+  m_ps(source),
+  m_pt(target)
+{
+  Kernel kernel;
+
+  Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt);
+  m_is_degen = (res == EQUAL);
+  m_is_directed_right = (res == SMALLER);
+
+  CGAL_precondition_msg(! m_is_degen, "Cannot construct a degenerate segment.");
+
+  m_l = kernel.construct_line_2_object()(source, target);
+  m_is_vert = kernel.is_vertical_2_object()(m_l);
+}
+
+//! \brief constructs a segment from two endpoints on a supporting line.
+template <typename Kernel>
+My_arr_segment_traits_2<Kernel>::
+_Segment_cached_2::_Segment_cached_2(const Line_2& line,
+                                     const Point_2& source,
+                                     const Point_2& target) :
+  m_l(line),
+  m_ps(source),
+  m_pt(target)
+{
+  Kernel kernel;
+
+  CGAL_precondition
+    (Segment_assertions::_assert_is_point_on(source, m_l,
+                                             Has_exact_division()) &&
+     Segment_assertions::_assert_is_point_on(target, m_l,
+                                             Has_exact_division()));
+
+  m_is_vert = kernel.is_vertical_2_object()(m_l);
+
+  Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt);
+  m_is_degen = (res == EQUAL);
+  m_is_directed_right = (res == SMALLER);
+
+  CGAL_precondition_msg(! m_is_degen, "Cannot construct a degenerate segment.");
+}
+
+//! \brief constructs a segment from all fields.
+template <typename Kernel>
+My_arr_segment_traits_2<Kernel>::_Segment_cached_2::
+_Segment_cached_2(const Line_2& line,
+                  const Point_2& source, const Point_2& target,
+                  bool is_directed_right, bool is_vert, bool is_degen) :
+  m_l(line),
+  m_ps(source),
+  m_pt(target),
+  m_is_directed_right(is_directed_right),
+  m_is_vert(is_vert),
+  m_is_degen(is_degen)
+{}
+
+//! \brief assigns.
+template <typename Kernel>
+const typename My_arr_segment_traits_2<Kernel>::_Segment_cached_2&
+My_arr_segment_traits_2<Kernel>::_Segment_cached_2::operator=(const Segment_2& seg)
+{
+  Kernel kernel;
+  auto vertex_ctr = kernel.construct_vertex_2_object();
+
+  m_ps = vertex_ctr(seg, 0);
+  m_pt = vertex_ctr(seg, 1);
+
+  Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt);
+  m_is_degen = (res == EQUAL);
+  m_is_directed_right = (res == SMALLER);
+
+  CGAL_precondition_msg(! m_is_degen, "Cannot construct a degenerate segment.");
+
+  m_l = kernel.construct_line_2_object()(seg);
+  m_is_vert = kernel.is_vertical_2_object()(seg);
+
+  return (*this);
+}
+
+// Accessors
+
+//! \brief obtains the supporting line.
+template <typename Kernel>
+const typename Kernel::Line_2&
+My_arr_segment_traits_2<Kernel>::_Segment_cached_2::line() const { return m_l; }
+
+//! \brief determines whether the curve is vertical.
+template <typename Kernel>
+bool My_arr_segment_traits_2<Kernel>::_Segment_cached_2::is_vertical() const
+{ return m_is_vert; }
+
+//! \brief determines whether the curve is degenerate.
+template <typename Kernel>
+bool My_arr_segment_traits_2<Kernel>::_Segment_cached_2::is_degenerate() const
+{ return m_is_degen; }
+
+/*! \brief determines whether the curve is lexicographically directed from
+ * left to right
+ */
+template <typename Kernel>
+bool My_arr_segment_traits_2<Kernel>::_Segment_cached_2::is_directed_right() const
+{ return m_is_directed_right; }
+
+//! \brief obtain the segment source.
+template <typename Kernel>
+const typename Kernel::Point_2&
+My_arr_segment_traits_2<Kernel>::_Segment_cached_2::source() const { return m_ps; }
+
+//! \brief obtains the segment target.
+template <typename Kernel>
+const typename Kernel::Point_2&
+My_arr_segment_traits_2<Kernel>::_Segment_cached_2::target() const { return m_pt; }
+
+//! \brief obtains the (lexicographically) left endpoint.
+template <typename Kernel>
+const typename Kernel::Point_2&
+My_arr_segment_traits_2<Kernel>::_Segment_cached_2::left() const
+{ return (m_is_directed_right ? m_ps : m_pt); }
+
+//! \brief obtains the (lexicographically) right endpoint.
+template <typename Kernel>
+const typename Kernel::Point_2&
+My_arr_segment_traits_2<Kernel>::_Segment_cached_2::right() const
+{ return (m_is_directed_right ? m_pt : m_ps); }
+
+// Modifiers
+
+//! \brief sets the (lexicographically) left endpoint.
+template <typename Kernel>
+void My_arr_segment_traits_2<Kernel>::_Segment_cached_2::set_left(const Point_2& p)
+{
+  CGAL_precondition(! m_is_degen);
+  CGAL_precondition_code(Kernel kernel);
+  CGAL_precondition
+    (Segment_assertions::_assert_is_point_on(p, m_l, Has_exact_division()) &&
+     (kernel.compare_xy_2_object()(p, right()) == SMALLER));
+
+  if (m_is_directed_right) m_ps = p;
+  else m_pt = p;
+}
+
+//! \brief sets the (lexicographically) right endpoint.
+template <typename Kernel>
+void My_arr_segment_traits_2<Kernel>::_Segment_cached_2::set_right(const Point_2& p)
+{
+  CGAL_precondition(! m_is_degen);
+  CGAL_precondition_code(Kernel kernel);
+  CGAL_precondition
+    (Segment_assertions::_assert_is_point_on(p, m_l, Has_exact_division()) &&
+     (kernel.compare_xy_2_object()(p, left()) == LARGER));
+
+  if (m_is_directed_right) m_pt = p;
+  else m_ps = p;
+}
+
+//! \brief determines whether the given point is in the x-range of the segment.
+template <typename Kernel>
+bool My_arr_segment_traits_2<Kernel>::_Segment_cached_2::
+is_in_x_range(const Point_2& p) const
+{
+  Kernel kernel;
+  typename Kernel::Compare_x_2 compare_x = kernel.compare_x_2_object();
+  const Comparison_result res1 = compare_x(p, left());
+
+  if (res1 == SMALLER) return false;
+  else if (res1 == EQUAL) return true;
+
+  const Comparison_result res2 = compare_x(p, right());
+  return (res2 != LARGER);
+}
+
+//! \brief determines whether the given point is in the y-range of the segment.
+template <typename Kernel>
+bool My_arr_segment_traits_2<Kernel>::_Segment_cached_2::
+is_in_y_range(const Point_2& p) const
+{
+  Kernel kernel;
+  typename Kernel::Compare_y_2 compare_y = kernel.compare_y_2_object();
+  const Comparison_result res1 = compare_y(p, left());
+
+  if (res1 == SMALLER) return false;
+  else if (res1 == EQUAL) return true;
+
+  const Comparison_result res2 = compare_y(p, right());
+  return (res2 != LARGER);
+}
+
+/*! \class A representation of a segment, as used by the My_arr_segment_traits_2
+ * traits-class.
+ */
+template <typename Kernel_>
+class My_arr_segment_2 : public My_arr_segment_traits_2<Kernel_>::_Segment_cached_2 {
+  typedef Kernel_                                                  Kernel;
+
+  typedef typename My_arr_segment_traits_2<Kernel>::_Segment_cached_2 Base;
+  typedef typename Kernel::Segment_2                               Segment_2;
+  typedef typename Kernel::Point_2                                 Point_2;
+  typedef typename Kernel::Line_2                                  Line_2;
+
+public:
+  /*! Construct default. */
+  My_arr_segment_2();
+
+  /*! Construct a segment from a "kernel" segment.
+   * \param seg the segment.
+   * \pre the segment is not degenerate.
+   */
+  My_arr_segment_2(const Segment_2& seg, int original_segment_id);
+
+  /*! Construct a segment from two endpoints.
+   * \param source the source point.
+   * \param target the target point.
+   * \pre `source` and `target` are not equal.
+   */
+  My_arr_segment_2(const Point_2& source, const Point_2& target,
+                   int original_segment_id);
+
+  /*! Construct a segment from a line and two endpoints.
+   * \param line the supporting line.
+   * \param source the source point.
+   * \param target the target point.
+   * \pre Both `source` and `target` must be on `line`.
+   * \pre `source` and `target` are not equal.
+   */
+  My_arr_segment_2(const Line_2& line,
+                   const Point_2& source, const Point_2& target,
+                   int original_segment_id);
+
+  /*! Construct a segment from all fields.
+   * \param line the supporting line.
+   * \param source the source point.
+   * \param target the target point.
+   * \param is_directed_right is (lexicographically) directed left to right.
+   * \param is_vert is the segment vertical.
+   * \param is_degen is the segment degenerate (a single point).
+   */
+  My_arr_segment_2(const Line_2& line,
+                   const Point_2& source, const Point_2& target,
+                   bool is_directed_right, bool is_vert, bool is_degen,
+                   int original_segment_id);
+
+  int original_segment_id() const
+  { return m_original_segment_id; }
+
+  /*! Cast to a segment.
+   */
+  operator Segment_2() const;
+
+  /*! Flip the segment (swap its source and target).
+   */
+  My_arr_segment_2 flip() const;
+
+  /*! Create a bounding box for the segment.
+   */
+  CGAL::Bbox_2 bbox() const
+  {
+    Kernel kernel;
+    auto construct_bbox = kernel.construct_bbox_2_object();
+    return construct_bbox(this->m_ps) + construct_bbox(this->m_pt);
+  }
+
+  int m_original_segment_id;
+};
+
+//! \brief constructs default.
+template <typename Kernel>
+My_arr_segment_2<Kernel>::My_arr_segment_2() : Base() { }
+
+//! \brief constructs from a "kernel" segment.
+template <typename Kernel>
+My_arr_segment_2<Kernel>::My_arr_segment_2(const Segment_2& seg,
+                                           int original_segment_id) :
+  Base(seg),
+  m_original_segment_id(original_segment_id)
+{}
+
+//! \brief constructs a segment from two end-points.
+template <typename Kernel>
+My_arr_segment_2<Kernel>::My_arr_segment_2(const Point_2& source,
+                                           const Point_2& target,
+                                           int original_segment_id) :
+  Base(source, target),
+  m_original_segment_id(original_segment_id)
+{}
+
+//! \brief constructs a segment from a line and two end-points.
+template <typename Kernel>
+My_arr_segment_2<Kernel>::My_arr_segment_2(const Line_2& line,
+                                           const Point_2& source,
+                                           const Point_2& target,
+                                           int original_segment_id) :
+  Base(line,source, target),
+  m_original_segment_id(original_segment_id)
+{}
+
+//! \brief constructs a segment from all fields.
+template <typename Kernel>
+My_arr_segment_2<Kernel>::My_arr_segment_2(const Line_2& line,
+                                           const Point_2& source,
+                                           const Point_2& target,
+                                           bool is_directed_right,
+                                           bool is_vert, bool is_degen,
+                                           int original_segment_id) :
+  Base(line, source, target, is_directed_right, is_vert, is_degen),
+  m_original_segment_id(original_segment_id)
+{}
+
+//! \brief casts to a segment.
+template <typename Kernel>
+My_arr_segment_2<Kernel>::operator typename Kernel::Segment_2() const
+{
+  Kernel kernel;
+  auto seg_ctr = kernel.construct_segment_2_object();
+  return seg_ctr(this->source(), this->target());
+}
+
+//! \brief flips the segment (swap its source and target).
+template <typename Kernel>
+My_arr_segment_2<Kernel> My_arr_segment_2<Kernel>::flip() const
+{
+  return My_arr_segment_2(this->line(), this->target(), this->source(),
+                          ! (this->is_directed_right()), this->is_vertical(),
+                          this->is_degenerate(), m_original_segment_id);
+}
+
+/*! Exporter for the segment class used by the traits-class.
+ */
+template <typename Kernel, typename OutputStream>
+OutputStream& operator<<(OutputStream& os, const My_arr_segment_2<Kernel>& seg)
+{
+  os << static_cast<typename Kernel::Segment_2>(seg);
+  return (os);
+}
+
+/*! Importer for the segment class used by the traits-class.
+ */
+template <typename Kernel, typename InputStream>
+InputStream& operator>>(InputStream& is, My_arr_segment_2<Kernel>& seg)
+{
+  typename Kernel::Segment_2   kernel_seg;
+  is >> kernel_seg;
+  seg = kernel_seg;
+  return is;
+}
+
+#undef SMALLER
+#undef EQUAL
+#undef LARGER
+
+#include <CGAL/enable_warnings.h>
+
+#endif
diff --git a/src/My_construction_subcurve.h b/src/My_construction_subcurve.h
new file mode 100644
index 0000000000000000000000000000000000000000..9faba448bddd31570a49a55e7b2dbfb7daca47ca
--- /dev/null
+++ b/src/My_construction_subcurve.h
@@ -0,0 +1,184 @@
+// Copyright (c) 2006,2007,2009,2010,2011 Tel-Aviv University (Israel).
+// All rights reserved.
+//
+// This file is part of CGAL (www.cgal.org).
+//
+// $URL$
+// $Id$
+// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
+//
+// Author(s)     : Tali Zvi <talizvi@post.tau.ac.il>
+//                 Baruch Zukerman <baruchzu@post.tau.ac.il>
+
+#ifndef MY_CONSTRUCTION_SUBCURVE_H
+#define MY_CONSTRUCTION_SUBCURVE_H
+
+/*! \file
+ *
+ * Definition of the Arr_construction_subcurve class-template, which is an
+ * extended curve type, referred to as Subcurve, used by the surface-sweep
+ * framework.
+ *
+ * The surface-sweep framework is implemented as a template that is
+ * parameterized, among the other, by the Subcurve and Event types. That is,
+ * instance types of Subcurve and Event must be available when the
+ * surface-sweep template is instantiated.
+ *
+ * Arr_construction_subcurve derives from an instance of the Default_subcurve
+ * class template. The user is allowed to introduce new types that derive from
+ * an instance of the Arr_construction_subcurve class template. However, some of
+ * the fields of this template depends on the Subcurve type.  We use the
+ * curiously recurring template pattern (CRTP) idiom to force the correct
+ * matching of these types.
+ */
+
+#include <CGAL/Surface_sweep_2/Default_subcurve.h>
+#include <CGAL/Default.h>
+#include "Hds.h"
+
+namespace Ss2 = CGAL::Surface_sweep_2;
+
+/*! \class Arr_construction_subcurve_base
+ *
+ * This is the base class of the Arr_construction_subcurve class template used
+ * by the (CRTP) idiom.
+ * \tparam GeometryTraits_2 the geometry traits.
+ * \tparam Event_ the event type.
+ * \tparam Allocator_ a type of an element that is used to acquire/release
+ *                    memory for elements of the event queue and the status
+ *                    structure, and to construct/destroy the elements in that
+ *                    memory. The type must meet the requirements of Allocator.
+ * \tparam Subcurve_ the subcurve actual type.
+ *
+ * The information contained in this class last:
+ * - ishe  event that was handled on the curve.
+ * - The index for a subcurve that may represent a hole
+ * - Indices of all halfedge below the curve that may represent a hole.
+ */
+template <typename GeometryTraits_2, typename Event_, typename Allocator_,
+          typename Subcurve_>
+class My_construction_subcurve_base :
+    public CGAL::Surface_sweep_2::Default_subcurve_base<GeometryTraits_2, Event_, Allocator_, Subcurve_>
+{
+public:
+  typedef GeometryTraits_2                              Geometry_traits_2;
+  typedef Subcurve_                                     Subcurve;
+  typedef Event_                                        Event;
+  typedef Allocator_                                    Allocator;
+
+private:
+  typedef Geometry_traits_2                             Gt2;
+  typedef CGAL::Surface_sweep_2::Default_subcurve_base<Gt2, Event, Allocator, Subcurve>
+                                                        Base;
+
+public:
+  typedef typename Gt2::X_monotone_curve_2              X_monotone_curve_2;
+  typedef Event*                                        Event_ptr;
+
+  /*! Construct default. */
+  My_construction_subcurve_base() :
+    Base(),
+    m_last_event(nullptr),
+    m_original_segment_id(std::numeric_limits<int>::max()),
+    m_hh(nullptr)
+    {}
+
+  /*! Constructor from an x-monotone curve. */
+  My_construction_subcurve_base(X_monotone_curve_2& curve) :
+    Base(curve),
+    m_last_event(nullptr),
+    m_original_segment_id(curve.original_segment_id()),
+    m_hh(nullptr)
+  {}
+
+protected:
+  Event_ptr m_last_event;    // The last event that was handled on the curve.
+  int m_original_segment_id;
+  Halfedge_handle m_hh; // Halfedge_handle of the edge between m_last_event, and lying
+                        // on this curve
+
+public:
+  /*! Initialize the curve. */
+  void init(const X_monotone_curve_2& curve)
+  {
+    Base::init(curve);
+    m_original_segment_id=curve.original_segment_id();
+  }
+
+  /*! Set the event associated with the left end of the subcurve. */
+  template <typename SweepEvent>
+  void set_left_event(SweepEvent* left)
+  {
+    Base::set_left_event(left);
+    set_last_event(left);
+  }
+
+  /*! Set the last event on the subcurve. */
+  void set_last_event(Event_ptr e) { m_last_event = e; }
+
+  /*! Obtain the last event. */
+  Event_ptr last_event() const { return m_last_event; }
+
+  int original_segment_id() const
+  { return m_original_segment_id; }
+  void set_original_segment_id(int id)
+  { m_original_segment_id=id; }
+
+  Halfedge_handle halfedge() const
+  { return m_hh; }
+  void set_halfedge(Halfedge_handle hh)
+  { m_hh=hh; }
+};
+
+/*! \class Arr_construction_subcurve
+ *
+ * This class that holds information about a curve that is added to the
+ * arrangement.  In addition to the information that is contained in
+ * Surface_sweep_subcurve, when an arrangement is constructed, a pointer to the
+ * last handled event on the curve is stored (in the base class). This
+ * information is used to retrieve hints when a subcurve of this curve is
+ * inserted into the planar map.
+ *
+ * Inherits from `Surface_sweep_subcurve`
+ * \sa `Surface_sweep_subcurve`
+ */
+template <typename GeometryTraits_2, typename Event_,
+          typename Allocator_ = CGAL_ALLOCATOR(int),
+          typename Subcurve_ = CGAL::Default>
+class My_construction_subcurve :
+  public My_construction_subcurve_base<
+    GeometryTraits_2, Event_, Allocator_,
+    typename CGAL::Default::Get<Subcurve_,
+                          My_construction_subcurve<GeometryTraits_2, Event_,
+                                                    Allocator_,
+                                                    Subcurve_> >::type>
+{
+public:
+  typedef GeometryTraits_2                              Geometry_traits_2;
+  typedef Event_                                        Event;
+  typedef Allocator_                                    Allocator;
+
+private:
+  typedef Geometry_traits_2                             Gt2;
+  typedef My_construction_subcurve<Gt2, Event, Allocator,
+                                    Subcurve_> Self;
+  typedef typename CGAL::Default::Get<Subcurve_, Self>::type  Subcurve;
+  typedef My_construction_subcurve_base<Gt2, Event, Allocator,
+                                         Subcurve> Base;
+
+public:
+  typedef typename Gt2::X_monotone_curve_2              X_monotone_curve_2;
+
+  typedef typename Base::Event_ptr                      Event_ptr;
+
+  /*! Construct deafult. */
+  My_construction_subcurve() {}
+
+  /*! Constructor from an x-monotone curve. */
+  My_construction_subcurve(X_monotone_curve_2& curve) :
+    Base(curve)
+  {}
+};
+
+
+#endif
diff --git a/src/My_event.h b/src/My_event.h
new file mode 100644
index 0000000000000000000000000000000000000000..631f46aa46ee2636753e59dc8738ea03f08e5381
--- /dev/null
+++ b/src/My_event.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2006,2007,2009,2010,2011 Tel-Aviv University (Israel).
+// All rights reserved.
+//
+// This file is part of CGAL (www.cgal.org).
+//
+// $URL$
+// $Id$
+// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
+//
+// Author(s)     : Tali Zvi <talizvi@post.tau.ac.il>
+//                 Baruch Zukerman <baruchzu@post.tau.ac.il>
+//                 Efi Fogel <efif@post.tau.ac.il>
+
+#ifndef CGAL_MY_EVENT_H
+#define CGAL_MY_EVENT_H
+
+/*! \file
+ *
+ * Definition of the Arr_construction_event_base class-template.
+ */
+
+#include <vector>
+
+#include <CGAL/Surface_sweep_2/Default_event_base.h>
+#include <CGAL/assertions.h>
+#include "Hds.h"
+#include "My_construction_subcurve.h"
+
+/*! \class Arr_construction_event_base
+ *
+ * This template represents an event used by the surface-sweep framework.  It
+ * inherits either from `Default_event_base` (the default) or
+ * 'No_overlap_event_base' depending on whether the curve may overlap or not.
+ * It stores the data associated with an event in addition to the information
+ * stored in its base class. When constructing an arrangement, additional
+ * information is stored, in order to expedite the insertion of curves into the
+ * arrangement.
+ *
+ * The additional infomation contains the following:
+ * - among the left curves of the event, we keep the highest halfedge that
+ *   was inserted into the arrangement at any given time and when there are no
+ *   left curves, we keep the highest halfedge that was inseted to the right.
+ *
+ * \tparam GeometryTraits_2 the geometry traits.
+ * \tparam Allocator_ a type of an element that is used to acquire/release
+ *                    memory for elements of the event queue and the status
+ *                    structure, and to construct/destroy the elements in that
+ *                    memory. The type must meet the requirements of Allocator.
+ * \tparam SurfaceSweepEvent a template, an instance of which is used as the
+ *                           base class.
+ *
+ * \sa `Default_event_base`
+ * \sa `No_overlap_event_base`
+ */
+  template <typename GeometryTraits_2, typename Subcurve_,
+          template <typename, typename>
+          class SurfaceSweepEvent = CGAL::Surface_sweep_2::Default_event_base>
+class My_event_base :
+  public SurfaceSweepEvent<GeometryTraits_2, Subcurve_>
+{
+public:
+  typedef GeometryTraits_2                              Geometry_traits_2;
+  typedef Subcurve_                                     Subcurve;
+
+private:
+  typedef Geometry_traits_2                               Gt2;
+  typedef SurfaceSweepEvent<Gt2, Subcurve>                Base;
+  typedef My_event_base<Gt2, Subcurve, SurfaceSweepEvent> Self;
+
+public:
+  typedef typename Gt2::X_monotone_curve_2              X_monotone_curve_2;
+  typedef typename Gt2::Point_2                         Point_2;
+
+  typedef typename Base::Subcurve_container        Subcurve_container;
+  typedef typename Base::Subcurve_iterator         Subcurve_iterator;
+  typedef typename Base::Subcurve_reverse_iterator Subcurve_reverse_iterator;
+
+protected:
+  Vertex_handle   m_vertex;         // The vertex handle associated with this event.
+  Halfedge_handle m_above_halfedge; // The halfedge handle of the subcurve just above this event.
+  bool            m_before_strip;
+public:
+  /*! Default constructor. */
+  My_event_base(): m_vertex(nullptr), m_above_halfedge(nullptr), m_before_strip(false)
+  {}
+
+  /*! Destructor */
+  ~My_event_base() {}
+
+  /*! Set the vertex handle. */
+  void set_vertex_handle(Vertex_handle vh) { m_vertex=vh; }
+
+  /*! Get the vertex handle. */
+  Vertex_handle vertex_handle() const { return m_vertex; }
+
+  void set_above_halfedge(Halfedge_handle hh)
+  { m_above_halfedge=hh; }
+  Halfedge_handle above_halfedge() const
+  { return m_above_halfedge; }
+
+  bool before_strip() const
+  { return m_before_strip; }
+  void set_before_strip()
+  { m_before_strip=true; }
+};
+
+template <typename GeometryTraits_2,
+          typename Allocator_ = CGAL_ALLOCATOR(int)>
+class My_event :
+    public My_event_base<GeometryTraits_2,
+                         My_construction_subcurve<GeometryTraits_2,
+                                                  My_event<GeometryTraits_2, Allocator_>,
+                                                  Allocator_> >
+{
+public:
+  /*! Construct default. */
+  My_event() {}
+};
+
+#endif
diff --git a/src/My_surface_sweep.h b/src/My_surface_sweep.h
new file mode 100644
index 0000000000000000000000000000000000000000..835e0d089a524dc215a362e719f09de205f748b1
--- /dev/null
+++ b/src/My_surface_sweep.h
@@ -0,0 +1,115 @@
+// 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 MY_SURFACE_SWEEP_H
+#define MY_SURFACE_SWEEP_H
+
+#include <CGAL/Surface_sweep_2.h>
+
+template <typename Visitor_>
+class My_surface_sweep_2:
+  CGAL::Surface_sweep_2::Surface_sweep_2<Visitor_>
+{
+public:
+  typedef My_surface_sweep_2<Visitor_> Self;
+  using Base=CGAL::Surface_sweep_2::Surface_sweep_2<Visitor_>;
+
+  using Geometry_traits_2=typename Base::Geometry_traits_2;
+  using Point_2=typename Base::Point_2;
+  using Event_queue_iterator=typename Base::Event_queue_iterator;
+  using Event_subcurve_iterator=typename Base::Event_subcurve_iterator;
+  using Subcurve=typename Base::Subcurve;
+
+  My_surface_sweep_2(Visitor_* visitor) : Base(visitor) {}
+  My_surface_sweep_2(const Geometry_traits_2* traits, Visitor_* visitor) :
+    Base(traits, visitor) {}
+
+  template <typename CurveInputIterator>
+  void sweep_until(CurveInputIterator curves_begin,
+                   CurveInputIterator curves_end,
+                   const Point_2& p)
+  {
+    this->m_visitor->before_sweep();
+    this->_init_sweep(curves_begin, curves_end);
+    //m_visitor->after_init();
+    this->_sweep_until(p);
+    this->_complete_sweep();
+    this->m_visitor->after_sweep();
+  }
+
+protected:
+  void _sweep_until(const Point_2& p)
+  {
+    // Looping over the events in the queue.
+    Event_queue_iterator eventIter = this->m_queue->begin();
+
+    std::size_t number_of_strips=this->m_visitor->number_of_strips();
+    std::size_t strip_id=this->m_visitor->strip_id();
+    bool before_strip=true;
+    bool after_strip=false;
+
+    if (strip_id==0)
+    {
+      before_strip=false;
+      this->m_visitor->enter_in_strip();
+    }
+
+    while (eventIter != this->m_queue->end()) {
+      // Get the next event from the queue.
+      this->m_currentEvent = *eventIter;
+
+      if (number_of_strips>1)
+      {
+        if (before_strip)
+        {
+          before_strip=(CGAL::compare_x(this->m_currentEvent->point(),
+                                       this->m_visitor->pmin())==CGAL::SMALLER);
+          if (!before_strip)
+          { this->m_visitor->enter_in_strip(); }
+        }
+        if (!after_strip && strip_id<number_of_strips-1)
+        {
+          after_strip=(CGAL::compare_x(this->m_currentEvent->point(),
+                                      this->m_visitor->pmax())!=CGAL::SMALLER);
+          if (after_strip) { this->m_visitor->end_of_strip(); }
+        }
+      }
+
+      if (!after_strip)
+      {
+        this->_handle_left_curves();
+        this->_handle_right_curves();
+      }
+
+      if (this->m_visitor->after_handle_event(this->m_currentEvent,
+                                              this->m_status_line_insert_hint,
+                                              this->m_is_event_on_above))
+      {
+        this->deallocate_event(this->m_currentEvent);
+      }
+
+      this->m_queue->erase(eventIter);
+      eventIter = this->m_queue->begin();
+    }
+
+    this->m_statusLine.clear();
+  }
+};
+
+#endif // MY_SURFACE_SWEEP_H
diff --git a/src/My_visitor.h b/src/My_visitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..dbad32e1230aa77ce31786b3080fdb7278de360f
--- /dev/null
+++ b/src/My_visitor.h
@@ -0,0 +1,319 @@
+// Copyright (c) 2005,2006,2007,2009,2010,2011 Tel-Aviv University (Israel).
+// All rights reserved.
+//
+// This file is part of CGAL (www.cgal.org).
+//
+// $URL$
+// $Id$
+// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
+//
+// Author(s): Baruch Zukerman <baruchzu@post.tau.ac.il>
+//            Efi Fogel       <efif@post.tau.ac.il>
+//            (based on old version by Tali Zvi)
+
+#ifndef CGAL_MY_VISITOR_H
+#define CGAL_MY_VISITOR_H
+
+/*! \file
+ *
+ * Definition of a surface-sweep visitor that reports all maximal x-monotone
+ * non-intersecting x-monotone curves induced by a set of input curves.
+ */
+
+#include <vector>
+
+#include <CGAL/Surface_sweep_2/Default_visitor.h>
+#include <CGAL/Surface_sweep_2/Surface_sweep_2_utils.h>
+#include "Hds.h"
+#include "My_surface_sweep.h"
+#include "My_event.h"
+#include "My_construction_subcurve.h"
+#include "Partial_hds.h"
+
+/*! \class Subcurves_visitor
+ *
+ * A simple sweep-line visitor that reports all maximal x-monotone
+ * non-intersecting x-monotone curves induced by a set of input curves. Used by
+ * compute_subcurves().
+ */
+  template <typename GeometryTraits_2,
+            typename Allocator_ = CGAL_ALLOCATOR(int)>
+class My_visitor :
+    public CGAL::Surface_sweep_2::Default_visitor
+               <My_visitor<GeometryTraits_2, Allocator_>,
+                GeometryTraits_2,
+                Allocator_,
+                My_event<GeometryTraits_2, Allocator_>,
+                My_construction_subcurve<GeometryTraits_2,
+                                         My_event<GeometryTraits_2, Allocator_>,
+                                         Allocator_>
+                >
+{
+public:
+  typedef GeometryTraits_2                              Geometry_traits_2;
+  typedef Allocator_                                    Allocator;
+
+private:
+  typedef Geometry_traits_2                        Gt2;
+  typedef My_visitor<Gt2, Allocator>               Self;
+  typedef CGAL::Surface_sweep_2::Default_visitor
+                        <Self, Gt2, Allocator,
+                         My_event<GeometryTraits_2, Allocator_>,
+                         My_construction_subcurve<GeometryTraits_2,
+                                                  My_event<GeometryTraits_2, Allocator_>,
+                                                  Allocator_>> Base;
+
+public:
+  typedef typename Gt2::X_monotone_curve_2              X_monotone_curve_2;
+  typedef typename Gt2::Point_2                         Point_2;
+
+  typedef typename Base::Event                          Event;
+  typedef typename Base::Subcurve                       Subcurve;
+
+  typedef typename Subcurve::Status_line_iterator       Status_line_iterator;
+
+protected:
+  // Data members:
+  Partial_hds& m_partial_hds;
+  bool m_before_strip, m_after_strip;
+  std::size_t m_nb_intersections;
+
+public:
+  My_visitor(Partial_hds& a_partial_hds) :
+    m_partial_hds(a_partial_hds),
+    m_before_strip(true),
+    m_after_strip(false),
+    m_nb_intersections(0)
+  {}
+
+  template<typename Container>
+  void sweep(const Container& all_segments, bool crop=false, std::size_t id=1)
+  {
+    m_partial_hds.m_nb_input_segments=0;
+    std::vector<X_monotone_curve_2> curves_vec;
+    if (m_partial_hds.number_of_strips()==1)
+    { curves_vec.reserve(all_segments.size()); }
+    else
+    {
+      curves_vec.reserve((2*all_segments.size())/(m_partial_hds.number_of_strips()));
+    }
+
+    bool concerned=false, cropx1, cropx2;
+    EPECK::Line_2 line;
+    double val;
+    ECoord x1, y1;
+    ECoord x2, y2;
+    auto it=all_segments.begin();
+    for (; it!=all_segments.end(); ++id, ++it)
+    {
+      if (it->source()!=it->target())
+      {
+        concerned=false;
+
+        if (it->source().x()<m_partial_hds.m_minx)
+        {
+          if (it->target().x()>=m_partial_hds.m_minx)
+          { concerned=true; }
+        }
+        else
+        {
+          if (it->source().x()<m_partial_hds.m_maxx)
+          { concerned=true; }
+        }
+
+        if (concerned)
+        {
+          if (crop)
+          {
+            if (it->source().x()<m_partial_hds.m_minx) { cropx1=true; }
+            else { cropx1=false; }
+            if (it->target().x()>m_partial_hds.m_maxx) { cropx2=true; }
+            else { cropx2=false; }
+
+            if (cropx1 || cropx2)
+            {
+              line=EPECK::Line_2(EPoint(it->source().x(), it->source().y()),
+                                 EPoint(it->target().x(), it->target().y()));
+              if (cropx1)
+              {
+                val=m_partial_hds.m_minx-
+                    ((m_partial_hds.m_maxx-m_partial_hds.m_minx)/10000.);
+                if (val<it->source().x())
+                { cropx1=false; }
+                else
+                { x1=val; y1=line.y_at_x(x1); } // Exact coordinates
+              }
+              if (cropx2)
+              { x2=m_partial_hds.m_maxx; y2=line.y_at_x(x2); }
+            }
+
+            if (!cropx1)
+            { x1=it->source().x(); y1=it->source().y(); }
+            if (!cropx2)
+            { x2=it->target().x(); y2=it->target().y(); }
+            curves_vec.push_back(X_monotone_curve_2(ESegment(EPoint(x1,y1),
+                                                             EPoint(x2, y2)),
+                                                    id));
+          }
+          else
+          {
+            curves_vec.push_back(X_monotone_curve_2
+                                 (ESegment(EPoint(it->source().x(), it->source().y()),
+                                           EPoint(it->target().x(), it->target().y())),
+                                  id));
+          }
+          ++m_partial_hds.m_nb_input_segments;
+        }
+      }
+    }
+
+    // 2) Perform the sweep.
+    My_surface_sweep_2<Self>* sl = reinterpret_cast<My_surface_sweep_2<Self>*>
+        (this->surface_sweep());
+    sl->sweep_until(curves_vec.begin(), curves_vec.end(),
+                    m_partial_hds.m_max);
+  }
+
+  void enter_in_strip()
+  { m_before_strip=false; }
+
+  void end_of_strip()
+  { m_after_strip=true; }
+
+  HDS& hds()
+  { return m_partial_hds.hds(); }
+
+  const EPoint& pmin() const
+  { return m_partial_hds.pmin(); }
+  const EPoint& pmax() const
+  { return m_partial_hds.pmax(); }
+
+  std::size_t strip_id() const
+  { return m_partial_hds.strip_id(); }
+  std::size_t number_of_strips() const
+  { return m_partial_hds.number_of_strips(); }
+
+  std::size_t number_of_intersections() const
+  { return m_nb_intersections; }
+
+  // Before to process the given event in the sweep line
+  void before_handle_event(Event* event)
+  {
+    assert(event->is_closed());
+    assert(event->vertex_handle()==nullptr);
+
+    if (m_before_strip)
+    { event->set_before_strip(); return; }
+
+    if (m_after_strip) return;
+
+    assert(m_partial_hds.point_in_strip(event->point()));
+    event->set_vertex_handle(hds().create_vertex(event->point()));
+
+    /* print_txt_with_endl("[strip", m_partial_hds.strip_id(),
+                        "] Create inner point for [",event->point()); */
+  }
+
+  // After having proceed the given even in the sweep line
+   bool after_handle_event(Event* event,
+                           Status_line_iterator iter,
+                           bool /*is_event_on_above*/)
+  {
+     // print_txt_with_endl("after_handle_event ", event, " ", event->point());
+     Halfedge_handle prevhh=nullptr;
+     if (event->vertex_handle()!=nullptr)
+     { // Point in strip
+       typename Event::Subcurve_reverse_iterator subcurve_rit;
+       for (subcurve_rit=event->left_curves_rbegin();
+            subcurve_rit!=event->left_curves_rend(); ++subcurve_rit)
+       {
+         hds().set_vertex(hds().opposite((*subcurve_rit)->halfedge()),
+                          event->vertex_handle());
+         prevhh=hds().add_segment_around_vertex
+             (hds().opposite((*subcurve_rit)->halfedge()),
+              event->vertex_handle(), prevhh);
+         if ((*subcurve_rit)->last_event()->vertex_handle()==nullptr)
+         { m_partial_hds.add_left_external_halfedge((*subcurve_rit)->halfedge()); }
+       }
+
+       if (event->is_intersection() || event->is_weak_intersection())
+       { ++m_nb_intersections; }
+     }
+     else if (m_after_strip)
+     {
+       typename Event::Subcurve_reverse_iterator subcurve_rit;
+       for (subcurve_rit=event->left_curves_rbegin();
+            subcurve_rit!=event->left_curves_rend(); ++subcurve_rit)
+       {
+         if ((*subcurve_rit)->last_event()->vertex_handle()!=nullptr ||
+             (*subcurve_rit)->last_event()->before_strip())
+         {
+           /* print_txt_with_endl("right_segment ",
+                               (*subcurve_rit)->last_event()->point(),
+                               " -> ", event->point()); */
+           m_partial_hds.add_right_external_halfedge
+               (hds().opposite((*subcurve_rit)->halfedge()));
+
+           if ((*subcurve_rit)->last_event()->before_strip())
+           { m_partial_hds.add_left_external_halfedge((*subcurve_rit)->halfedge()); }
+         }
+       }
+
+       typename Event::Subcurve_iterator subcurve_it;
+       for (subcurve_it=event->right_curves_begin();
+            subcurve_it!=event->right_curves_end(); ++subcurve_it)
+       { (*subcurve_it)->set_last_event(event); }
+     }
+     else
+     {
+       assert(m_before_strip);
+       typename Event::Subcurve_reverse_iterator subcurve_rit;
+       for (subcurve_rit=event->left_curves_rbegin();
+            subcurve_rit!=event->left_curves_rend(); ++subcurve_rit)
+       {
+         // Case of an edge entirely before the strip: ignore
+         hds().erase_edge((*subcurve_rit)->halfedge());
+         (*subcurve_rit)->set_halfedge(nullptr);
+       }
+     }
+
+     if (!m_after_strip)
+     {
+       typename Event::Subcurve_iterator subcurve_it;
+       for (subcurve_it=event->right_curves_begin();
+            subcurve_it!=event->right_curves_end(); ++subcurve_it)
+       {
+         (*subcurve_it)->set_halfedge
+             (hds().create_edge
+              (event->vertex_handle(), (*subcurve_it)->original_segment_id()));
+         if (event->vertex_handle()!=nullptr)
+         {
+           prevhh=hds().add_segment_around_vertex
+               ((*subcurve_it)->halfedge(), event->vertex_handle(), prevhh);
+         }
+         (*subcurve_it)->set_last_event(event);
+       }
+     }
+
+     if (event->vertex_handle()!=nullptr)
+     {
+       hds().end_of_vertex(event->vertex_handle(), prevhh);
+       // Iter is on the status line just after event
+       Halfedge_handle fatherdart=(iter!=this->status_line_end()?
+             (*iter)->halfedge():nullptr);
+       m_partial_hds.set_above_halfedge(event->vertex_handle(), fatherdart);
+     }
+
+     return (event->number_of_right_curves() == 0);
+   }
+
+   void found_overlap(Subcurve* sc1,
+                      Subcurve* sc2,
+                      Subcurve* ov_sc)
+   {
+     ov_sc->set_original_segment_id(std::min(sc1->original_segment_id(),
+                                             sc2->original_segment_id()));
+   }
+};
+
+#endif
diff --git a/src/Partial_hds.h b/src/Partial_hds.h
new file mode 100644
index 0000000000000000000000000000000000000000..8f7c6675b77abb7aea80dd68e3b4dc82267f02e1
--- /dev/null
+++ b/src/Partial_hds.h
@@ -0,0 +1,336 @@
+// 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 PARTIAL_HDS_H
+#define PARTIAL_HDS_H
+
+#include <iostream>
+#include <thread>
+#include <vector>
+#include <tuple>
+#include <stack>
+#include <map>
+
+#include "Print_txt.h"
+#include "Hds.h"
+#include "Export_xfig.hh"
+
+template <typename GeometryTraits_2, typename Allocator_>
+class My_visitor;
+template <typename Kernel_>
+class My_arr_segment_traits_2;
+class SHds;
+
+////////////////////////////////////////////////////////////////////////////////
+class Partial_hds
+{
+public:
+  using Self=Partial_hds;
+
+  template <typename GeometryTraits_2, typename Allocator_>
+  friend class My_visitor;
+
+  friend class SHds;
+  friend class MySimpleSHDSViewerQt;
+
+  Partial_hds(double x1=0., double y1=0., double x2=0., double y2=0.,
+              std::size_t strip_id=0, std::size_t nb_strips=0):
+    m_minx(x1),
+    m_maxx(x2),
+    m_min(x1, y1),
+    m_max(x2, y2),
+    m_strip_id(strip_id),
+    m_nb_strips(nb_strips),
+    m_nb_input_segments(0)
+  {
+    /*print_txt_with_endl("[Strip ", m_strip_id, "]: ", x1, ", ",
+                        y1, ", ", x2, ", ", y2); */
+  }
+
+  std::size_t strip_id() const
+  { return m_strip_id; }
+  std::size_t number_of_strips() const
+  { return m_nb_strips; }
+
+  ECoord xmin() const
+  { return m_min.x(); }
+  ECoord ymin() const
+  { return m_min.y(); }
+  ECoord xmax() const
+  { return m_max.x(); }
+  ECoord ymax() const
+  { return m_max.y(); }
+
+  const EPoint& pmin() const
+  { return m_min; }
+  const EPoint& pmax() const
+  { return m_max; }
+
+  HDS& hds()
+  { return m_hds; }
+  const HDS& hds() const
+  { return m_hds; }
+
+  std::size_t number_of_left_externals() const
+  { return m_left_external_halfedges.size(); }
+  std::size_t number_of_right_externals() const
+  { return m_right_external_halfedges.size(); }
+  std::size_t number_of_externals() const
+  { return number_of_left_externals()+number_of_right_externals(); }
+  std::size_t number_of_non_externals() const
+  { return hds().number_of_halfedges()-number_of_externals(); }
+  std::size_t number_of_input_segments() const
+  { return m_nb_input_segments; }
+
+  void clear()
+  {
+    m_minx=m_maxx=0;
+    m_min=m_max=CGAL::ORIGIN;
+    m_strip_id=m_nb_strips=0;
+    m_hds.clear();
+    m_left_external_halfedges.clear();
+    m_right_external_halfedges.clear();
+  }
+
+  bool point_in_strip(const EPoint& p) const
+  {
+    // in strip means p.x >= m_min.x && p.x < m_max.x
+    return (CGAL::compare_x(p, m_min)!=CGAL::SMALLER &&
+            CGAL::compare_x(p, m_max)==CGAL::SMALLER);
+  }
+
+  void add_left_external_halfedge(Halfedge_handle hh)
+  {
+    /*print_txt_with_endl("[strip ", strip_id(), "] add_left_external_halfedge ",
+                        hds().edge_id(hh), " ptr=", &*hh);*/
+
+    assert(is_left_external(hh));
+    assert(m_left_external_halfedges.count(hds().edge_id(hh))==0);
+    assert(hds().left_to_right(hh));
+    m_left_external_halfedges.insert(std::make_pair(hds().edge_id(hh), hh));
+  }
+
+  void add_right_external_halfedge(Halfedge_handle hh)
+  {
+    /*print_txt_with_endl("[strip ", strip_id(), "] add_right_external_halfedge ",
+                        -hds().edge_id(hh), " ptr=", &*hh);*/
+
+    assert(is_right_external(hh));
+    assert(m_right_external_halfedges.count(-hds().edge_id(hh))==0);
+    assert(hds().right_to_left(hh));
+
+    m_right_external_halfedges.insert(std::make_pair(-hds().edge_id(hh), hh));
+  }
+
+  void set_above_halfedge(Vertex_handle vh, Halfedge_handle hh)
+  { vh->set_above_halfedge(hh); }
+
+  // @return true iff hh is external, i.e. not linked with an inner point in
+  // this strip.
+  bool is_external(Halfedge_handle hh) const
+  { return hds().vertex(hh)==nullptr; }
+
+  // @return true iff hh is left external, i.e. external and intersect the
+  // left side of the strip (and thus from left to right).
+  bool is_left_external(Halfedge_handle hh) const
+  { return is_external(hh) && hds().left_to_right(hh); }
+
+  // @return true iff hh is right external, i.e. external and intersect the
+  // right side of the strip (and thus from right to left).
+  bool is_right_external(Halfedge_handle hh) const
+  { return is_external(hh) && hds().right_to_left(hh); }
+
+  bool source_in_strip(Halfedge_handle hh) const
+  { return !is_external(hh); }
+  bool target_in_strip(Halfedge_handle hh) const
+  { return !is_external(hds().opposite(hh)); }
+
+  bool is_valid_external_halfedges()
+  {
+    bool res=true;
+
+    if (m_strip_id==0 && !m_left_external_halfedges.empty())
+    {
+      print_txt_with_endl("[strip 0] : ERROR m_left_external_halfedges "
+                          "is not empty.");
+    }
+    if (m_strip_id==m_nb_strips-1 && !m_right_external_halfedges.empty())
+    {
+      print_txt_with_endl("[strip ", strip_id(),
+                          "] (last strip) : ERROR, m_right_external_halfedges "
+                          "is not empty.");
+    }
+
+    for (auto it=hds().halfedges().begin(), itend=hds().halfedges().end();
+         it!=itend; ++it)
+    {
+      if (is_left_external(it))
+      {
+        auto resfind=m_left_external_halfedges.find(hds().edge_id(it));
+        if (resfind==m_left_external_halfedges.end())
+        { print_txt_with_endl("[strip ", strip_id(),
+                              "] : ERROR, halfedge ",
+                              hds().edge_id(it), " is left external but ",
+                              "is not in array m_left_external_halfedges.");
+          res=false;
+        }
+        else
+        {
+          if (resfind->second!=it)
+          { print_txt_with_endl("[strip ", strip_id(),
+                                "] : ERROR, halfedge ",
+                                hds().edge_id(it), " is left external but ",
+                                "its associated halfedge in array ",
+                                "m_left_external_halfedges is different ",
+                                hds().edge_id(resfind->second),
+                                " PTR ", &*(resfind->second), " AND ",
+                                &*(it));
+            res=false;
+          }
+        }
+      }
+      if (is_right_external(it))
+      {
+        auto resfind=m_right_external_halfedges.find(-hds().edge_id(it));
+        if (resfind==m_right_external_halfedges.end())
+        { print_txt_with_endl("[strip ", strip_id(),
+                              "] : ERROR, halfedge ",
+                              hds().edge_id(it), " is right external but ",
+                              "is not in array m_right_external_halfedges.");
+          res=false;
+        }
+        else
+        {
+          if (resfind->second!=it)
+          { print_txt_with_endl("[strip ", strip_id(),
+                                "] : ERROR, halfedge ",
+                                hds().edge_id(it), " is right external but ",
+                                "its associated halfedge in array ",
+                                "m_right_external_halfedges is different ",
+                                hds().edge_id(resfind->second));
+            res=false;
+          }
+        }
+      }
+    }
+    return res;
+  }
+
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const Partial_hds& la)
+  {
+    CGAL::exact(la.m_min); CGAL::exact(la.m_max);
+    os<<std::setprecision(17)
+     <<la.m_minx<<" "<<la.m_maxx<<" "<<la.m_min<<" "<<la.m_max<<" "
+     <<la.m_strip_id<<" "<<la.m_nb_strips<<" "<<la.m_nb_input_segments
+    <<std::endl<<std::endl;
+    os<<la.m_hds<<std::endl;
+
+    os<<la.m_left_external_halfedges.size()<<" "
+     <<la.m_right_external_halfedges.size()<<std::endl;
+
+    for (auto it=la.m_left_external_halfedges.begin(),
+         itend=la.m_left_external_halfedges.end(); it!=itend; ++it)
+    { os<<it->first<<" "<<la.hds().halfedges().index(it->second)<<std::endl; }
+    for (auto it=la.m_right_external_halfedges.begin(),
+         itend=la.m_right_external_halfedges.end(); it!=itend; ++it)
+    { os<<it->first<<" "<<la.hds().halfedges().index(it->second)<<std::endl; }
+
+    return os;
+  }
+
+  friend std::istream& operator>>(std::istream& is,
+                                  Partial_hds& la)
+  {
+    la.clear();
+
+    is>>la.m_minx>>la.m_maxx>>la.m_min>>la.m_max
+        >>la.m_strip_id>>la.m_nb_strips>>la.m_nb_input_segments;
+
+    std::vector<Halfedge_handle> halfedges;
+    std::vector<Vertex_handle> vertices;
+    la.m_hds.load(is, halfedges, vertices);
+
+    std::size_t nb_left, nb_right;
+    std::size_t ind1;
+    int int1;
+
+    is>>nb_left>>nb_right;
+    for (std::size_t i=0; i<nb_left; ++i)
+    {
+      is>>int1>>ind1;
+      la.m_left_external_halfedges[int1]=halfedges[ind1];
+    }
+    for (std::size_t i=0; i<nb_right; ++i)
+    {
+      is>>int1>>ind1;
+      la.m_right_external_halfedges[int1]=halfedges[ind1];
+    }
+    return is;
+  }
+
+  void display_info() const
+  {
+    print_txt_with_endl("[strip ", m_strip_id, "]: (", m_minx, " -> ", m_maxx,
+                        ") #input-segments ", m_nb_input_segments,
+                        " #left-external=", m_left_external_halfedges.size(),
+                        " #right-external=", m_right_external_halfedges.size(),
+                        " #halfedges=", hds().number_of_halfedges(),
+                        " #vertices=", hds().number_of_vertices());
+  }
+
+  void export_to_xfig(Export_xfig& export_xfig,
+                      double dx, double dy,
+                      uint8_t coul_segments,
+                      uint8_t coul_disks,
+                      uint8_t coul_borders,
+                      uint16_t width_segments,
+                      uint16_t radius_disks,
+                      uint16_t width_borders) const
+  {
+    // Border of the strip
+    if (width_borders>0)
+    {
+      export_xfig.rectangle(CGAL::to_double(m_min.x())+dx,
+                            CGAL::to_double(m_min.y())+dy,
+                            CGAL::to_double(m_max.x())+dx,
+                            CGAL::to_double(m_max.y())+dy,
+                            coul_borders, width_borders, false, 200);
+    }
+
+    // HDS
+    hds().export_to_xfig(export_xfig, dx, dy,
+                         coul_segments, coul_disks,
+                         width_segments, radius_disks);
+  }
+
+protected:
+  double m_minx, m_maxx;
+  EPoint m_min, m_max;
+  std::size_t m_strip_id;
+  std::size_t m_nb_strips;
+  std::size_t m_nb_input_segments;
+
+  HDS m_hds;
+  std::unordered_map<int, Halfedge_handle> m_left_external_halfedges;
+  std::unordered_map<int, Halfedge_handle> m_right_external_halfedges;
+};
+////////////////////////////////////////////////////////////////////////////////
+
+#endif // PARTIAL_HDS_H
diff --git a/src/Print_txt.h b/src/Print_txt.h
new file mode 100644
index 0000000000000000000000000000000000000000..2844c34c8fab5e456fbdd0b1b35372dd7e8d8aef
--- /dev/null
+++ b/src/Print_txt.h
@@ -0,0 +1,62 @@
+// 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 PRINT_TXT_H
+#define PRINT_TXT_H
+
+#include <sstream>
+#include <utility>
+#include <chrono>
+
+///////////////////////////////////////////////////////////////////////////////
+template<typename T>
+void put_one_value(std::ostringstream& txt, const T& v)
+{ txt<<v; }
+//----------------------------------------------------------------------------
+template<>
+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/SHds.h b/src/SHds.h
new file mode 100644
index 0000000000000000000000000000000000000000..90229ca773bd884c56bcafdc8b0fac489e21384d
--- /dev/null
+++ b/src/SHds.h
@@ -0,0 +1,1195 @@
+// 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 SHDS_H
+#define SHDS_H
+
+#include <iostream>
+#include <thread>
+#include <vector>
+#include <mutex>
+#include <boost/filesystem.hpp>
+
+#include <CGAL/Compact_container.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+#include "My_construction_subcurve.h"
+#include "My_arr_segment_traits_2.h"
+#include "My_surface_sweep.h"
+#include "My_visitor.h"
+#include "memory.h"
+#include "CGAL_typedefs.h"
+#include "Partial_hds.h"
+#include "Hds.h"
+
+////////////////////////////////////////////////////////////////////////////////
+class SHds
+{
+public:
+  using Self=SHds;
+
+  typedef uint32_t size_type;
+  static const size_type NB_MARKS=Halfedge::NB_MARKS;
+  static const size_type INVALID_MARK=NB_MARKS;
+  class Exception_no_more_available_mark {};
+
+  SHds():
+    m_xmin(0), m_ymin(0), m_xmax(0), m_ymax(0),
+    m_nb_strips(0),
+    m_number_segments(0),
+    m_number_of_halfedges(0),
+    m_nb_finite_faces(0)
+  { init_all_marks(); }
+
+  void init_all_marks()
+  {
+    mnb_used_marks = 0;
+    mmask_marks.reset();
+    for (size_type i=0; i<NB_MARKS; ++i)
+    {
+      mfree_marks_stack[i]        = i;
+      mindex_marks[i]             = i;
+      mnb_marked_halfedges[i]     = 0;
+      mnb_times_reserved_marks[i] = 0;
+    }
+  }
+
+  SHds(const std::string& filename,
+       std::size_t nb_strips,
+       std::size_t nb_threads,
+       bool optimized_strips,
+       std::vector<double>& times,
+       bool crop=false,
+       std::vector<double>* xpos_cuts=nullptr):
+    m_xmin(0), m_ymin(0), m_xmax(0), m_ymax(0),
+    m_nb_strips(nb_strips),
+    m_number_segments(0),
+    m_number_of_halfedges(0),
+    m_nb_finite_faces(0)
+  {
+    init_all_marks();
+
+    if (times.empty())
+    { times.resize(4, 0); }
+
+    // times[0] : global time
+    // times[1] : load and dispatch
+    // times[2] : compute all partial arrangements
+    // times[3] : compute faces
+
+    My_timer global_timer; global_timer.start();
+    My_timer local_timer;
+    local_timer.start();
+
+    std::vector<ISegment> all_segments;
+    std::vector<double>   xpos_strips;
+
+    if (xpos_cuts!=nullptr)
+    { compute_strips_v0(filename, all_segments, xpos_strips, xpos_cuts);}
+    else if (!optimized_strips)
+    { compute_strips_v1(filename, all_segments, xpos_strips); }
+    else
+    { compute_strips_v2(filename, all_segments, xpos_strips); }
+
+    std::cout<<"strips xpos=(";
+    for (std::size_t i=0; i<xpos_strips.size(); ++i)
+    { std::cout<<xpos_strips[i]<<"  "; }
+    std::cout<<")   #size="<<xpos_strips.size()<<std::endl;
+
+    // Test if definition of strips is valid.
+    bool strip_error=(xpos_strips.size()!=number_of_strips()+1);
+    for (std::size_t i=1; i<nb_strips; ++i)
+    {
+      if (xpos_strips[i]<=m_xmin || xpos_strips[i]>=m_xmax ||
+          xpos_strips[i]<=xpos_strips[i-1])
+      { strip_error=true; }
+    }
+    if (xpos_strips.front()!=m_xmin || xpos_strips.back()!=m_xmax)
+    { strip_error=true; }
+    if (strip_error)
+    {
+      std::cerr<<"[ERROR] in definition of strips: #nbstrips="<<number_of_strips()
+              <<std::endl;
+      exit(EXIT_FAILURE);
+    }
+
+    local_timer.stop();
+    times[1]+=local_timer.time();
+
+    // Now compute partial hds, possibly in parallel
+    m_tab_partial_hds.resize(number_of_strips());
+    std::vector<std::thread> tab_threads;
+    tab_threads.reserve(nb_threads);
+
+    std::mutex queue_mutex;
+    std::queue<std::size_t> strips_to_process;
+    for (std::size_t i=0; i<nb_strips; ++i)
+    { strips_to_process.push(i); }
+
+    local_timer.reset();
+    local_timer.start();
+    for (std::size_t i=0; i<nb_threads; ++i)
+    {
+      tab_threads.push_back
+          (std::thread
+           ([i, nb_threads, &queue_mutex, &strips_to_process, &all_segments,
+            &xpos_strips, crop,this]()
+      {
+        std::size_t nb_intersections=0;
+        std::ostringstream ss;
+        My_timer timer; timer.start();
+        std::size_t strip_id;
+        queue_mutex.lock();
+        while(!strips_to_process.empty())
+        {
+          strip_id=strips_to_process.front();
+          strips_to_process.pop();
+          queue_mutex.unlock();
+          ss<<strip_id<<" ";
+
+          m_tab_partial_hds[strip_id]=new Partial_hds
+              (xpos_strips[strip_id], m_ymin, xpos_strips[strip_id+1], m_ymax,
+              strip_id, m_nb_strips);
+
+          typedef My_visitor<My_arr_segment_traits_2<EPECK>> Visitor;
+          My_arr_segment_traits_2<EPECK> m_traits;
+          Visitor visitor(*m_tab_partial_hds[strip_id]);
+          My_surface_sweep_2<Visitor> surface_sweep(&m_traits, &visitor);
+          visitor.sweep(all_segments, crop);
+          nb_intersections+=visitor.number_of_intersections();
+          assert(m_tab_partial_hds[strip_id]->is_valid_external_halfedges());
+          queue_mutex.lock();
+        }
+        queue_mutex.unlock();
+        timer.stop();
+        print_txt(" [Thread ", i, "]: strips=", ss.str(), "; #intersections=",
+                  nb_intersections, "  time=",timer.time());
+      }
+      ));
+    }
+    for (std::size_t i=0; i<tab_threads.size(); ++i)
+    { tab_threads[i].join(); }
+    std::cout<<std::endl;
+
+    local_timer.stop();
+    times[2]+=local_timer.time();
+
+    local_timer.reset();
+    local_timer.start();
+    build_faces_array();
+    local_timer.stop();
+    times[3]+=local_timer.time();
+
+    global_timer.stop();
+    times[0]+=global_timer.time();
+  }
+
+  ~SHds()
+  {
+    for (auto it=m_tab_partial_hds.begin(),
+         itend=m_tab_partial_hds.end(); it!=itend; ++it)
+    { delete *it; *it=nullptr; }
+  }
+
+  std::size_t number_of_strips() const
+  { return m_nb_strips; }
+  std::size_t number_of_faces() const
+  { return m_faces.size(); }
+  std::size_t number_of_finite_faces() const
+  { return m_nb_finite_faces; }
+
+  double xmin() const
+  { return m_xmin; }
+  double ymin() const
+  { return m_ymin; }
+  double xmax() const
+  { return m_xmax; }
+  double ymax() const
+  { return m_ymax; }
+
+  HDS& hds(std::size_t nb)
+  {
+    assert(nb<number_of_strips());
+    return m_tab_partial_hds[nb]->hds();
+  }
+  const HDS& hds(std::size_t nb) const
+  {
+    assert(nb<number_of_strips());
+    return m_tab_partial_hds[nb]->hds();
+  }
+
+  HDS& hds(const Global_halfedge& phe)
+  { return hds(phe.strip_id()); }
+  const HDS& hds(const Global_halfedge& phe) const
+  { return hds(phe.strip_id()); }
+
+  Partial_hds& partial_hds(std::size_t nb)
+  {
+    assert(nb<number_of_strips());
+    return *(m_tab_partial_hds[nb]);
+  }
+  const Partial_hds& partial_hds(std::size_t nb) const
+  {
+    assert(nb<number_of_strips());
+    return *(m_tab_partial_hds[nb]);
+  }
+
+  Partial_hds& partial_hds(const Global_halfedge& phe)
+  { return partial_hds(phe.strip_id()); }
+  const Partial_hds& partial_hds(const Global_halfedge& phe) const
+  { return partial_hds(phe.strip_id()); }
+
+  void clear()
+  {
+    m_xmin=m_ymin=m_xmax=m_ymax=0;
+    m_nb_strips=m_number_segments=m_number_of_halfedges=0;
+    for (auto it=m_tab_partial_hds.begin(),
+         itend=m_tab_partial_hds.end(); it!=itend; ++it)
+    { delete *it; *it=nullptr; }
+    m_faces.clear();
+    init_all_marks();
+  }
+
+  void read_segments_and_compute_bbox(const std::string& filename,
+                                      std::vector<ISegment>& all_segments)
+  {
+    all_segments.clear();
+    all_segments.reserve(number_of_lines(filename));
+
+    CGAL::Bbox_2 bbox;
+    m_number_segments=0;
+    Read_from_file<EPICK> reader(filename);
+    while (reader.ok())
+    {
+      EPICK::Segment_2 s=reader.next_segment();
+      all_segments.push_back(s);
+      if (m_number_segments==0) { bbox=s.bbox(); }
+      else { bbox+=s.bbox(); }
+      ++m_number_segments;
+    }
+    if (m_number_segments==0)
+    {
+      std::cout<<"Empty set of segments for file "<<filename<<", abort."<<std::endl;
+      exit(EXIT_FAILURE);
+    }
+
+    double deltax=(bbox.xmax()-bbox.xmin())/10000.; // 0.01 %
+    double deltay=(bbox.ymax()-bbox.ymin())/10000.; // 0.01 %
+    m_xmin=bbox.xmin()-deltax;
+    m_ymin=bbox.ymin()-deltay;
+    m_xmax=bbox.xmax()+deltax;
+    m_ymax=bbox.ymax()+deltay;
+  }
+
+  void compute_strips_v0(const std::string& filename,
+                        std::vector<ISegment>& all_segments,
+                        std::vector<double>& xpos_strips,
+                        std::vector<double>* xpos_cuts)
+  {
+    if (xpos_cuts==nullptr || xpos_cuts->size()!=number_of_strips()-1)
+    {
+      std::cout<<"Error in compute_strips_v0, switch to default strip computation."<<std::endl;
+      compute_strips_v1(filename, all_segments, xpos_strips);
+      return;
+    }
+
+    read_segments_and_compute_bbox(filename, all_segments);
+
+    xpos_strips.clear();
+    xpos_strips.resize(number_of_strips()+1, 0);
+
+    xpos_strips[0]=m_xmin;
+    for (std::size_t i=0; i<xpos_cuts->size(); ++i)
+    { xpos_strips[i+1]=xpos_cuts->at(i); }
+    xpos_strips[number_of_strips()]=m_xmax;
+  }
+
+  void compute_strips_v1(const std::string& filename,
+                        std::vector<ISegment>& all_segments,
+                        std::vector<double>& xpos_strips)
+  {
+    read_segments_and_compute_bbox(filename, all_segments);
+
+    xpos_strips.clear();
+    xpos_strips.resize(number_of_strips()+1, 0);
+
+    xpos_strips[0]=m_xmin;
+    for (std::size_t i=1; i<number_of_strips(); ++i)
+    { xpos_strips[i]=m_xmin+((m_xmax-m_xmin)*i)/number_of_strips(); }
+    xpos_strips[number_of_strips()]=m_xmax;
+  }
+
+  void compute_strips_v2(const std::string& filename,
+                        std::vector<ISegment>& all_segments,
+                        std::vector<double>& xpos_strips)
+  {
+    constexpr std::size_t array_size=1000;
+
+    read_segments_and_compute_bbox(filename, all_segments);
+
+    // Now compute histogram of segments (only x coordinates)
+    std::vector<std::size_t> nbsegments(array_size,0);
+    std::size_t sum=0;
+    for (std::size_t i=0; i<all_segments.size(); ++i)
+    {
+      ISegment& s=all_segments[i];
+      std::size_t imin=floor((array_size*(s.source().x()-m_xmin))/(m_xmax-m_xmin));
+      std::size_t imax=floor((array_size*(s.target().x()-m_xmin))/(m_xmax-m_xmin));
+      for (; imin<=imax; ++imin)
+      {
+        assert(imin<array_size);
+        ++nbsegments[imin]; ++sum;
+      }
+    }
+
+    // Now we need to dispatch sum parts of segment into number_of_threads strips.
+    std::size_t cursum=0;
+    xpos_strips.clear();
+    xpos_strips.reserve(number_of_strips()+1);
+    xpos_strips.push_back(m_xmin);
+    for (std::size_t i=0; i<array_size && xpos_strips.size()<number_of_strips(); ++i)
+    {
+      if (cursum+nbsegments[i]>sum/number_of_strips())
+      {
+        xpos_strips.push_back(m_xmin+i*(m_xmax-m_xmin)/array_size);
+        cursum=0;
+      }
+      cursum+=nbsegments[i];
+    }
+    xpos_strips.push_back(m_xmax);
+    assert(xpos_strips.size()==number_of_strips()+1);
+  }
+
+  // phe is a left_to_right external halfedge.
+  // Move it in the halfedge with the same id in the left strip.
+  void move_to_same_halfedge_in_left_strip(Global_halfedge& phe) const
+  {
+    assert(partial_hds(phe).is_external(phe.halfedge()));
+    assert(hds(phe).left_to_right(phe.halfedge()));
+    phe.go_to_left_strip();
+    auto find_external=partial_hds(phe).m_right_external_halfedges.find(hds(phe).edge_id(phe.halfedge()));
+    assert(find_external!=partial_hds(phe).m_right_external_halfedges.end());
+    phe.halfedge()=hds(phe).opposite(find_external->second);
+  }
+
+  // phe is a right_to_left external halfedge.
+  // Move it in the halfedge with the same id in the right strip.
+  void move_to_same_halfedge_in_right_strip(Global_halfedge& phe) const
+  {
+    assert(partial_hds(phe).is_external(phe.halfedge()));
+    assert(hds(phe).right_to_left(phe.halfedge()));
+    phe.go_to_right_strip();
+    auto find_external=partial_hds(phe).m_left_external_halfedges.find(-hds(phe).edge_id(phe.halfedge()));
+    assert(find_external!=partial_hds(phe).m_left_external_halfedges.end());
+    phe.halfedge()=hds(phe).opposite(find_external->second);
+  }
+
+  void move_to_same_halfedge_in_adjacent_strip(Global_halfedge& phe) const
+  {
+    assert(partial_hds(phe).is_external(phe.halfedge()));
+    if (hds(phe).left_to_right(phe.halfedge()))
+    { move_to_same_halfedge_in_left_strip(phe); }
+    else
+    { move_to_same_halfedge_in_right_strip(phe); }
+  }
+
+  // phe is a parallel halfedge. If this is a external halfedge, move to the
+  // corresponding non external halfedge.
+  void move_to_non_external(Global_halfedge& phe) const
+  {
+    if (partial_hds(phe).is_external(phe.halfedge()))
+    {
+      if (hds(phe).left_to_right(phe.halfedge()))
+      {
+        do
+        { move_to_same_halfedge_in_left_strip(phe); }
+        while(partial_hds(phe).is_external(phe.halfedge()));
+      }
+      else
+      {
+        do
+        { move_to_same_halfedge_in_right_strip(phe); }
+        while(partial_hds(phe).is_external(phe.halfedge()));
+      }
+    }
+  }
+
+  // The following move_to_xxx methods traverse the shds jumping over external
+  // halfedges. This allows to see the stripped hds like a normal hds.
+  void move_to_previous(Global_halfedge& phe) const
+  {
+    assert(!partial_hds(phe).is_external(phe.halfedge()));
+    hds(phe.strip_id()).move_to_prev_around_vertex(phe.halfedge());
+    move_to_opposite(phe);
+  }
+  void move_to_next(Global_halfedge& phe) const
+  {
+    assert(!partial_hds(phe).is_external(phe.halfedge()));
+    move_to_opposite(phe);
+    hds(phe.strip_id()).move_to_next_around_vertex(phe.halfedge());
+  }
+  void move_to_opposite(Global_halfedge& phe) const
+  {
+    assert(!partial_hds(phe).is_external(phe.halfedge()));
+    hds(phe.strip_id()).move_to_opposite(phe.halfedge());
+    move_to_non_external(phe);
+  }
+
+  Global_halfedge next(const Global_halfedge& phe) const
+  {
+    Global_halfedge res(phe);
+    move_to_next(res);
+    return res;
+  }
+
+  Global_halfedge previous(const Global_halfedge& phe) const
+  {
+    Global_halfedge res(phe);
+    move_to_previous(res);
+    return res;
+  }
+
+  Global_halfedge opposite(const Global_halfedge& phe) const
+  {
+    Global_halfedge res(phe);
+    move_to_opposite(res);
+    return res;
+  }
+
+  // The following local_move_to_xxx methods traverse the hds by considering
+  // also external halfedges (contrary to methods above).
+  void local_move_to_previous(Global_halfedge& phe) const
+  {
+    if (partial_hds(phe).is_external(phe.halfedge()))
+    { move_to_same_halfedge_in_adjacent_strip(phe); }
+    else
+    {
+      hds(phe.strip_id()).move_to_prev_around_vertex(phe.halfedge());
+      hds(phe.strip_id()).move_to_opposite(phe.halfedge());
+    }
+  }
+  void local_move_to_next(Global_halfedge& phe) const
+  {
+    hds(phe.strip_id()).move_to_opposite(phe.halfedge());
+    if(partial_hds(phe).is_external(phe.halfedge()))
+    {
+      move_to_same_halfedge_in_adjacent_strip(phe);
+      hds(phe.strip_id()).move_to_opposite(phe.halfedge());
+    }
+    else
+    {
+      hds(phe.strip_id()).move_to_next_around_vertex(phe.halfedge());
+    }
+  }
+  void local_move_to_opposite(Global_halfedge& phe) const
+  {
+    phe.m_hh=hds(phe.strip_id()).opposite(phe.halfedge());
+  }
+  Global_halfedge local_next(const Global_halfedge& phe) const
+  {
+    Global_halfedge res(phe);
+    local_move_to_next(res);
+    return res;
+  }
+
+  Global_halfedge local_previous(const Global_halfedge& phe) const
+  {
+    Global_halfedge res(phe);
+    local_move_to_previous(res);
+    return res;
+  }
+
+  Global_halfedge local_opposite(const Global_halfedge& phe) const
+  {
+    Global_halfedge res(phe);
+    local_move_to_opposite(res);
+    return res;
+  }
+
+  const EPoint& point(const Global_halfedge& phe) const
+  { return hds(phe.strip_id()).point(phe.halfedge()); }
+
+  Vertex_handle vertex(Halfedge_handle hh)
+  { return hh->m_vertex; }
+  Vertex_handle vertex(const Global_halfedge& phh)
+  { return vertex(phh.halfedge()); }
+
+  Face_handle create_face()
+  { return m_faces.emplace(); }
+  Face_handle face(Halfedge_handle hh)
+  { return hh->m_face; }
+  Face_handle face(const Global_halfedge& phh)
+  { return face(phh.halfedge()); }
+  void set_face(Halfedge_handle hh, Face_handle fh)
+  { hh->m_face=fh; }
+  const CGAL::Compact_container<Face>& faces() const
+  { return m_faces; }
+
+  std::size_t number_of_halfedges() const
+  {
+    std::size_t res=0;
+    for (std::size_t i=0; i<number_of_strips(); ++i)
+    { res+=hds(i).number_of_halfedges(); }
+    return res;
+  }
+
+  std::size_t number_of_non_external_halfedges() const
+  {
+    std::size_t res=0;
+    for (std::size_t i=0; i<number_of_strips(); ++i)
+    { res+=Partial_hds(i).number_of_non_externals(); }
+    return res;
+  }
+
+  std::size_t number_of_external_halfedges() const
+  {
+    std::size_t res=0;
+    for (std::size_t i=0; i<number_of_strips(); ++i)
+    { res+=m_tab_partial_hds[i]->number_of_externals(); }
+    return res;
+  }
+
+  /** Count the number of used marks.
+   * @return the number of used marks.
+   */
+  size_type number_of_used_marks() const
+  { return mnb_used_marks; }
+
+  /** Test if a given mark is reserved.
+   *  @return true iff the mark is reserved (ie in used).
+   */
+  bool is_reserved(size_type amark) const
+  {
+    CGAL_assertion(amark<NB_MARKS);
+    return (mnb_times_reserved_marks[amark]!=0);
+  }
+
+  /**  Count the number of marked halfedges for a given mark.
+   * @param amark the mark index.
+   * @return the number of marked halfedges for amark.
+   */
+  size_type number_of_marked_halfedges(size_type amark) const
+  {
+    CGAL_assertion( is_reserved(amark) );
+    return mnb_marked_halfedges[amark];
+  }
+
+  /**  Count the number of unmarked halfedges for a given mark.
+   * @param amark the mark index.
+   * @return the number of unmarked halfedges for amark.
+   */
+  size_type number_of_unmarked_halfedges(size_type amark) const
+  {
+    CGAL_assertion( is_reserved(amark) );
+    return number_of_halfedges()-number_of_marked_halfedges(amark);
+  }
+
+  /** Test if all the halfedges are unmarked for a given mark.
+   * @param amark the mark index.
+   * @return true iff all the halfedges are unmarked for amark.
+   */
+  bool is_whole_hds_unmarked(size_type amark) const
+  { return number_of_marked_halfedges(amark)==0; }
+
+  /** Test if all the halfedges are marked for a given mark.
+   * @param amark the mark index.
+   * @return true iff all the halfedges are marked for amark.
+   */
+  bool is_whole_hds_marked(size_type amark) const
+  {  return number_of_marked_halfedges(amark)==number_of_halfedges(); }
+
+  /** Reserve a new mark.
+   * Get a new free mark and return its index.
+   * All the halfedges are unmarked for this mark.
+   * @return the index of the new mark.
+   * @pre mnb_used_marks < NB_MARKS
+   */
+  size_type get_new_mark() const
+  {
+    if (mnb_used_marks == NB_MARKS)
+    {
+      std::cerr << "Not enough Boolean marks: "
+        "increase NB_MARKS." << std::endl;
+      std::cerr << "  (exception launched)" << std::endl;
+      throw Exception_no_more_available_mark();
+    }
+
+    size_type m = mfree_marks_stack[mnb_used_marks];
+    mused_marks_stack[mnb_used_marks] = m;
+
+    mindex_marks[m] = mnb_used_marks;
+    mnb_times_reserved_marks[m]=1;
+
+    ++mnb_used_marks;
+    CGAL_assertion(is_whole_hds_unmarked(m));
+
+    return m;
+  }
+
+  /** Increase the number of times a mark is reserved.
+   *  @param amark the mark to share.
+   */
+  void share_a_mark(size_type amark) const
+  {
+    CGAL_assertion( is_reserved(amark) );
+    ++mnb_times_reserved_marks[amark];
+  }
+
+  /** @return the number of times a mark is reserved.
+   *  @param amark the mark to share.
+   */
+  size_type get_number_of_times_mark_reserved(size_type amark) const
+  {
+    CGAL_assertion( amark<NB_MARKS );
+    return mnb_times_reserved_marks[amark];
+  }
+
+  /** Negate the mark of all the halfedges for a given mark.
+   * After this call, all the marked halfedges become unmarked and all the
+   * unmarked halfedges become marked (in constant time operation).
+   * @param amark the mark index
+   */
+  void negate_mark(size_type amark) const
+  {
+    CGAL_assertion( is_reserved(amark) );
+
+    mnb_marked_halfedges[amark] = number_of_halfedges()-mnb_marked_halfedges[amark];
+
+    mmask_marks.flip(amark);
+  }
+
+  /// Return the mark value of he a given mark number.
+  bool get_he_mark(Halfedge_const_handle he, size_type amark) const
+  { return he->get_mark(amark); }
+
+  /// Set the mark of a given mark number to a given value.
+  void set_he_mark(Halfedge_const_handle he, size_type amark, bool avalue) const
+  { he->set_mark(amark, avalue); }
+
+  /// Flip the mark of a given mark number to a given value.
+  void flip_he_mark(Halfedge_const_handle he, size_type amark) const
+  { he->flip_mark(amark); }
+
+  std::bitset<NB_MARKS> get_he_marks(Halfedge_const_handle he) const
+  { return he->get_marks(); }
+  void set_he_marks(Halfedge_const_handle he,
+                    const std::bitset<NB_MARKS>& amarks) const
+  { he->set_marks(amarks); }
+
+  /** Test if a given halfedge is marked for a given mark.
+   * @param he the halfedge to test.
+   * @param amark the given mark.
+   * @return true iff halfedge is marked for the mark amark.
+   */
+  bool is_marked(Halfedge_const_handle he, size_type amark) const
+  {
+    CGAL_assertion( is_reserved(amark) );
+
+    return get_he_mark(he, amark)!=mmask_marks[amark];
+  }
+
+  /** Set the mark of a given halfedge to a state (on or off).
+   * @param ahalfedge the halfedge.
+   * @param amark the given mark.
+   * @param astate the state of the mark (on or off).
+   */
+  void set_mark_to(Halfedge_const_handle he, size_type amark,
+                   bool astate) const
+  {
+    CGAL_assertion(is_reserved(amark));
+
+    if (is_marked(he, amark)!=astate)
+    {
+      if (astate) ++mnb_marked_halfedges[amark];
+      else --mnb_marked_halfedges[amark];
+
+      flip_he_mark(he, amark);
+    }
+  }
+
+  /** Mark the given halfedge.
+   * @param he the halfedge.
+   * @param amark the given mark.
+   */
+  void mark(Halfedge_const_handle he, size_type amark) const
+  {
+    CGAL_assertion(is_reserved(amark));
+
+    if (is_marked(he, amark)) return;
+
+    ++mnb_marked_halfedges[amark];
+    flip_he_mark(he, amark);
+  }
+
+  /** Unmark the given halfedge.
+   * @param he the halfedge.
+   * @param amark the given mark.
+   */
+  void unmark(Halfedge_const_handle he, size_type amark) const
+  {
+    CGAL_assertion(is_reserved(amark));
+
+    if (!is_marked(he, amark)) return;
+
+    --mnb_marked_halfedges[amark];
+    flip_he_mark(he, amark);
+  }
+
+  bool is_marked(const Global_halfedge& phe, size_type amark) const
+  { return is_marked(phe.halfedge(), amark); }
+  void mark(const Global_halfedge& phe, size_type amark) const
+  { mark(phe.halfedge(), amark); }
+  void unmark(const Global_halfedge& phe, size_type amark) const
+  { unmark(phe.halfedge(), amark); }
+
+  /** Unmark all the halfedges of the hds for a given mark.
+   * If all the halfedges are marked or unmarked, this operation takes O(1)
+   * operations, otherwise it traverses all the halfedges of the map.
+   * @param amark the given mark.
+   */
+  void unmark_all(size_type amark) const
+  {
+    CGAL_assertion( is_reserved(amark) );
+
+    if ( is_whole_hds_marked(amark) )
+    { negate_mark(amark); }
+    else if ( !is_whole_hds_unmarked(amark) )
+    {
+      for (std::size_t i=0; i<number_of_strips(); ++i)
+      {
+        for (auto it(hds(i).halfedges().begin()), itend(hds(i).halfedges().end());
+             it!=itend; ++it)
+          unmark(it, amark);
+      }
+    }
+    CGAL_assertion(is_whole_hds_unmarked(amark));
+  }
+
+  /** Free a given mark, previously calling unmark_all.
+   * @param amark the given mark.
+   */
+  void free_mark(size_type amark) const
+  {
+    CGAL_assertion( is_reserved(amark) );
+
+    if ( mnb_times_reserved_marks[amark]>1 )
+    {
+      --mnb_times_reserved_marks[amark];
+      return;
+    }
+
+    unmark_all(amark);
+
+    // 1) We remove amark from the array mused_marks_stack by
+    //    replacing it with the last mark in this array.
+    mused_marks_stack[mindex_marks[amark]] =
+      mused_marks_stack[--mnb_used_marks];
+    mindex_marks[mused_marks_stack[mnb_used_marks]] =
+      mindex_marks[amark];
+
+    // 2) We add amark in the array mfree_marks_stack and update its index.
+    mfree_marks_stack[ mnb_used_marks ] = amark;
+    mindex_marks[amark] = mnb_used_marks;
+
+    mnb_times_reserved_marks[amark]=0;
+  }
+
+  // Build the faces of the given lcc (and the father/son relations between holes)
+  // Return the number of finite faces.
+  std::size_t build_faces_array()
+  {
+    // display_info();
+
+    Face_handle m_root=create_face();
+    m_root->m_finite=false; // Infinite face
+
+    std::size_t finite_faces=0;
+    auto treated=get_new_mark();
+    Face_handle newf, father;
+    Global_halfedge dh, initdh, odh;
+    Halfedge_handle firsthalfedge, fatherhalfedge;
+    std::stack<Global_halfedge> totreat;
+
+    // Iterate through all inner points, ordered from left to right
+    for (std::size_t i=0; i<number_of_strips(); ++i)
+    {
+      for (auto it=hds(i).vertices().begin(),
+           itend=hds(i).vertices().end(); it!=itend; ++it)
+      {
+        if (!Partial_hds(i).is_external(it->first_halfedge()) &&
+            !is_marked(it->first_halfedge(), treated))
+        { // first_halfedge belongs necessarily to one infinite face.
+          firsthalfedge=it->first_halfedge();
+          newf=create_face();
+
+          // std::size_t nbhalfedges=0;
+          initdh.set(i, firsthalfedge);
+          dh=initdh;
+          do
+          {
+            // ++nbhalfedges;
+            mark(dh, treated);
+            set_face(dh.halfedge(), newf);
+            odh=local_opposite(dh);
+            if (!is_marked(odh, treated))
+            { totreat.push(odh); }
+            local_move_to_next(dh);
+          }
+          while(dh!=initdh);
+
+          fatherhalfedge=it->above_halfedge();
+          father=nullptr;
+          if (fatherhalfedge==nullptr)
+          { father=m_root; }
+          else
+          {
+            assert(face(fatherhalfedge)!=nullptr);
+
+            if (face(fatherhalfedge)->m_finite)
+            { // Father is the halfedge of the finite face containing this hole
+              father=face(fatherhalfedge);
+            }
+            else
+            { // Father is a halfedge of another hole, inside the same finite face
+              // This hole was already considered before.
+              assert(face(fatherhalfedge)->m_father!=nullptr);
+              father=face(fatherhalfedge)->m_father;
+            }
+          }
+          assert(father==m_root || father->m_finite);
+          newf->set(i, firsthalfedge, father, false); // Infinite face
+          father->m_son.push_back(newf);
+
+          // Now we iterate through the cc containing it->first_halfedge().
+          // Each new face is necessarily a finite one.
+          while(!totreat.empty())
+          {
+            initdh=totreat.top(); totreat.pop();
+            if (!is_marked(initdh, treated))
+            {
+              newf=create_face();
+              newf->set(initdh.strip_id(), initdh.halfedge(), nullptr, true); // Finite face
+              ++finite_faces;
+
+              // nbhalfedges=0;
+              dh=initdh;
+              do
+              {
+                // ++nbhalfedges;
+                mark(dh, treated);
+                set_face(dh.halfedge(), newf);
+                odh=local_opposite(dh);
+                if (!is_marked(odh, treated))
+                { totreat.push(odh); }
+                local_move_to_next(dh);
+              }
+              while(dh!=initdh);
+            }
+          }
+        }
+      }
+    }
+    assert(is_whole_hds_marked(treated));
+    free_mark(treated);
+
+    m_nb_finite_faces=finite_faces;
+    return finite_faces;
+  }
+
+  std::size_t traverse_all_faces() const
+  {
+    std::size_t nb=0;
+    for (auto itf=faces().begin(), itfend=faces().end(); itf!=itfend; ++itf)
+    {
+      if (itf->finite() || itf==faces().begin())
+      {
+        if (itf!=faces().begin())
+        { // Because the root face does not have any first_halfedge
+          Global_halfedge dhinit(itf->strip_id(), itf->first_halfedge());
+          Global_halfedge dh=dhinit;
+          do
+          {
+            ++nb;
+            move_to_next(dh);
+          }
+          while(dh!=dhinit);
+        }
+        for (auto its=itf->sons().begin(), itsend=itf->sons().end();
+             its!=itsend; ++its)
+        {
+          Global_halfedge dhinit((*its)->strip_id(), (*its)->first_halfedge());
+          Global_halfedge dh=dhinit;
+          do
+          {
+            ++nb;
+            move_to_next(dh);
+          }
+          while(dh!=dhinit);
+        }
+      }
+    }
+    return nb;
+  }
+
+  void display_info() const
+  {
+    std::size_t nbexternal=0, nbleft=0, nbright=0, nbhalfedges=0, nbvertices=0, sumsegments=0;
+
+    std::cout<<"#halfedges, #vertices #input-segments (#left-external, #right-externals) for each strip: "<<std::endl;
+    for (std::size_t i=0; i<number_of_strips(); ++i)
+    {
+      std::cout<<m_tab_partial_hds[i]->hds().number_of_halfedges()
+              <<" "<<m_tab_partial_hds[i]->hds().number_of_vertices()
+             <<" "<<m_tab_partial_hds[i]->number_of_input_segments()
+             <<" ("
+            <<m_tab_partial_hds[i]->number_of_left_externals()
+           <<", "
+           <<m_tab_partial_hds[i]->number_of_right_externals()
+           <<")  | ";
+      nbhalfedges+=m_tab_partial_hds[i]->hds().number_of_halfedges();
+      nbvertices+=m_tab_partial_hds[i]->hds().number_of_vertices();
+      nbleft+=m_tab_partial_hds[i]->m_left_external_halfedges.size();
+      nbright+=m_tab_partial_hds[i]->m_right_external_halfedges.size();
+      nbexternal+=m_tab_partial_hds[i]->number_of_externals();
+      sumsegments+=m_tab_partial_hds[i]->number_of_input_segments();
+    }
+
+    std::cout<<std::endl<<"Total: #halfedges="<<nbhalfedges
+            <<", #vertices="<<nbvertices<<", #faces="<<m_faces.size()
+           <<" (#finite-faces="<<m_nb_finite_faces
+          <<"), #nbexternal="<<nbexternal
+         <<" (left="<<nbleft<<", right="<<nbright<<")"<<std::endl;
+    std::cout<<"Nb input segments: "<<m_number_segments
+            <<", Sum segments in strips: "<<sumsegments<<std::endl;
+     std::cout<<"CURRENT RSS: "<<getCurrentRSS()<<" bytes (i.e. "<<
+               double(getCurrentRSS())/double(1024*1024)<<" mega-bytes and "<<
+                double(getCurrentRSS())/double(1024*1024*1024)<<" giga-bytes)"<<std::endl;
+  }
+
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const SHds& pa)
+  {
+    os<<pa.m_xmin<<" "<<pa.m_ymin<<" "<<pa.m_xmax<<" "<<pa.m_ymax<<" "
+     <<pa.m_nb_strips<<" "<<pa.m_number_segments<<std::endl;
+
+    for (auto it=pa.m_tab_partial_hds.begin(),
+         itend=pa.m_tab_partial_hds.end(); it!=itend; ++it)
+    { os<<**it<<std::endl; }
+
+    return os;
+  }
+
+  friend std::istream& operator>>(std::istream& is,
+                                  SHds& pa)
+  {
+    pa.clear();
+
+    is>>pa.m_xmin>>pa.m_ymin>>pa.m_xmax>>pa.m_ymax
+     >>pa.m_nb_strips>>pa.m_number_segments;
+
+    pa.m_tab_partial_hds.resize(pa.m_nb_strips);
+    for (std::size_t i=0; i<pa.m_nb_strips; ++i)
+    {
+      pa.m_tab_partial_hds[i]=new Partial_hds;
+      is>>*(pa.m_tab_partial_hds[i]);
+    }
+
+    return is;
+  }
+
+  // Load the streamed files; filename contains a % which will be replaced
+  // by the number of the strip.
+  void load_streamed_files(const std::string& filename)
+  {
+    m_xmin=m_ymin=m_xmax=m_ymax=0.;
+    m_number_segments=0;
+    m_number_of_halfedges=0;
+    m_tab_partial_hds.clear();
+
+    std::size_t i=0;
+    std::string real_file=filename;
+    real_file.replace(real_file.find("%"), 1, std::to_string(i));
+    while(boost::filesystem::exists(boost::filesystem::path(real_file)))
+    {
+      m_tab_partial_hds.push_back(new Partial_hds);
+      std::ifstream is(real_file);
+      is>>*(m_tab_partial_hds.back());
+      is.close();
+
+      if (m_tab_partial_hds.size()==1)
+      {
+        m_xmin=CGAL::to_double(m_tab_partial_hds.back()->xmin());
+        m_ymin=CGAL::to_double(m_tab_partial_hds.back()->ymin());
+        m_xmax=CGAL::to_double(m_tab_partial_hds.back()->xmax());
+        m_ymax=CGAL::to_double(m_tab_partial_hds.back()->ymax());
+      }
+      else
+      {
+        m_xmin=std::min(m_xmin, CGAL::to_double(m_tab_partial_hds.back()->xmin()));
+        m_ymin=std::min(m_ymin, CGAL::to_double(m_tab_partial_hds.back()->ymin()));
+        m_xmax=std::max(m_xmax, CGAL::to_double(m_tab_partial_hds.back()->xmax()));
+        m_ymax=std::max(m_ymax, CGAL::to_double(m_tab_partial_hds.back()->ymax()));
+      }
+      m_number_segments+=(m_tab_partial_hds.back()->hds().number_of_halfedges())/2;
+
+      ++i;
+      real_file=filename;
+      real_file.replace(real_file.find("%"), 1, std::to_string(i));
+    }
+
+    m_nb_strips=m_tab_partial_hds.size();
+
+    for (std::size_t i=0; i<m_tab_partial_hds.size(); ++i)
+    {
+      m_tab_partial_hds[i]->m_strip_id=i;
+      m_tab_partial_hds[i]->m_nb_strips=m_nb_strips;
+      m_tab_partial_hds[i]->m_min=EPoint(m_tab_partial_hds[i]->m_minx,
+                                                m_ymin);
+      m_tab_partial_hds[i]->m_max=EPoint(m_tab_partial_hds[i]->m_maxx,
+                                                m_ymax);
+    }
+  }
+
+  // Export the current stripped arrangement into the given filename.
+  // If draw_external draw external edges, otherwise they are not drawn.
+  // if nbstrips!=0, draw only the first nbstrips. Otherwise draw all strips.
+  void export_to_xfig(const std::string& filename,
+                      bool invert_y=true, double xfig_x_size=50000,
+                      std::size_t nbstrips=0,
+                      const CGAL::Color& color_segments=CGAL::Color(40,40,220),
+                      const CGAL::Color& color_disks=CGAL::Color(220,40,40),
+                      const CGAL::Color& color_externals=CGAL::Color(90,190,110),
+                      const CGAL::Color& color_borders=CGAL::Color(150,150,150),
+                      uint16_t width_segments=2, uint16_t radius_disks=30,
+                      uint16_t width_externals=2, uint16_t width_borders=1,
+                      uint16_t space_between_strips=100)
+  {
+    Export_xfig export_xfig(filename, (m_xmax-m_xmin),
+                            xfig_x_size,
+                            invert_y);
+
+    uint8_t coul_segments=export_xfig.add_color(color_segments);
+    uint8_t coul_disks=export_xfig.add_color(color_disks);
+    uint8_t coul_externals=export_xfig.add_color(color_externals);
+    uint8_t coul_borders=export_xfig.add_color(color_borders);
+
+    double dx=-m_xmin;
+    double dy=-m_ymin;
+
+    std::size_t i=0;
+    for (auto it=m_tab_partial_hds.begin(),
+         itend=m_tab_partial_hds.end();
+         (nbstrips==0 || i<nbstrips) && it!=itend; ++it, ++i)
+    {
+      export_xfig.set_x_shift(i*space_between_strips);
+
+      if (width_externals>0)
+      {
+        double x1=CGAL::to_double((*it)->xmin());
+        double y1, x2, y2;
+        for (auto itc=(*it)->m_left_external_halfedges.begin(),
+             itcend=(*it)->m_left_external_halfedges.end(); itc!=itcend; ++itc)
+        {
+          Global_halfedge h1((*it)->strip_id(), itc->second);
+          move_to_non_external(h1);
+          Global_halfedge h2=opposite(h1);
+          move_to_non_external(h2);
+
+          EPECK::Line_2 line(point(h1), point(h2));
+          y1=CGAL::to_double(line.y_at_x((*it)->xmin()));
+
+          if (h2.strip_id()==(*it)->strip_id())
+          { // Non traversing segment
+            x2=CGAL::to_double(point(h2).x());
+            y2=CGAL::to_double(point(h2).y());
+          }
+          else
+          { // Traversing segment
+            x2=CGAL::to_double((*it)->xmax());
+            y2=CGAL::to_double(line.y_at_x((*it)->xmax()));
+          }
+
+          export_xfig.segment(x1+dx, y1+dy, x2+dx, y2+dy,
+                              coul_externals, width_externals, false, 100);
+        }
+
+        x1=CGAL::to_double((*it)->xmax());
+        for (auto itc=(*it)->m_right_external_halfedges.begin(),
+             itcend=(*it)->m_right_external_halfedges.end(); itc!=itcend; ++itc)
+        {
+          Global_halfedge h1((*it)->strip_id(), itc->second);
+          move_to_non_external(h1);
+          Global_halfedge h2=opposite(h1);
+          move_to_non_external(h2);
+
+          EPECK::Line_2 line(point(h1), point(h2));
+          y1=CGAL::to_double(line.y_at_x((*it)->xmax()));
+
+          if (h2.strip_id()==(*it)->strip_id())
+          { // Non traversing segment; traversing segments were alreary drawn above
+            x2=CGAL::to_double(point(h2).x());
+            y2=CGAL::to_double(point(h2).y());
+
+            export_xfig.segment(x1+dx, y1+dy, x2+dx, y2+dy,
+                                coul_externals, width_externals, false, 100);
+          }
+        }
+      }
+
+      (*it)->export_to_xfig(export_xfig,
+                            dx, dy,
+                            coul_segments, coul_disks, coul_borders,
+                            width_segments, radius_disks, width_borders);
+    }
+  }
+
+protected:
+  double m_xmin, m_ymin, m_xmax, m_ymax;
+  std::size_t m_nb_strips;
+  std::size_t m_number_segments;
+  std::size_t m_number_of_halfedges;
+  std::size_t m_nb_finite_faces;
+
+  std::vector<Partial_hds*>     m_tab_partial_hds;
+  CGAL::Compact_container<Face> m_faces;
+
+  /// Number of times each mark is reserved. 0 if the mark is free.
+  mutable size_type mnb_times_reserved_marks[NB_MARKS];
+
+  /// Mask marks to know the value of unmark halfedge, for each index i.
+  mutable std::bitset<NB_MARKS> mmask_marks;
+
+  /// Number of used marks.
+  mutable size_type mnb_used_marks;
+
+  /// Index of each mark, in mfree_marks_stack or in mfree_marks_stack.
+  mutable size_type mindex_marks[NB_MARKS];
+
+  /// "Stack" of free marks.
+  mutable size_type mfree_marks_stack[NB_MARKS];
+
+  /// "Stack" of used marks.
+  mutable size_type mused_marks_stack[NB_MARKS];
+
+  /// Number of marked halfedges for each used marks.
+  mutable size_type mnb_marked_halfedges[NB_MARKS];
+};
+////////////////////////////////////////////////////////////////////////////////
+
+#endif // SHDS_H
diff --git a/src/SHds_to_cgal_arrangement.h b/src/SHds_to_cgal_arrangement.h
new file mode 100644
index 0000000000000000000000000000000000000000..f2907ee95da2bd1a4e43f6040413c7f0eb9a9237
--- /dev/null
+++ b/src/SHds_to_cgal_arrangement.h
@@ -0,0 +1,54 @@
+ // 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 SHDS_TO_CGAL_ARRANGEMENT_H
+#define SHDS_TO_CGAL_ARRANGEMENT_H
+
+#include "SHds.h"
+#include <CGAL/Arrangement_2.h>
+
+// Build a CGAL arrangement from a parallel arrangement.
+template<typename Arr>
+void shds_to_cgal_arrangement(SHds& shds, Arr& arr)
+{
+  arr.clear();
+  std::vector<ESegment> all_segments;
+  all_segments.reserve(shds.number_of_non_external_halfedges()/2);
+
+  Global_halfedge hh;
+  for (std::size_t i=0; i<shds.number_of_strips(); ++i)
+  {
+    for (auto it=shds.hds(i).halfedges().begin(),
+         itend=shds.hds(i).halfedges().end(); it!=itend; ++it)
+    {
+      if (!shds.partial_hds(i).is_external(it))
+      { // First halfedge is it
+        hh=shds.opposite(Global_halfedge(i, it)); // Opposite halfedge, a non critical dart
+        if (it<hh.halfedge()) // To add a segment only once
+        { all_segments.push_back(ESegment(shds.hds(i).point(it),
+                                          shds.hds(hh).point(hh.halfedge()))); }
+      }
+    }
+  }
+
+  CGAL::insert_non_intersecting_curves(arr,
+                                       all_segments.begin(), all_segments.end());
+}
+
+#endif // SHDS_TO_CGAL_ARRANGEMENT_H
diff --git a/src/SHds_to_lcc.h b/src/SHds_to_lcc.h
new file mode 100644
index 0000000000000000000000000000000000000000..12fbb7e1df01e9d094b348ce299426a4e01e4b3b
--- /dev/null
+++ b/src/SHds_to_lcc.h
@@ -0,0 +1,259 @@
+// 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 PARALLEL_ARRANGEMENT_TO_LCC_H
+#define PARALLEL_ARRANGEMENT_TO_LCC_H
+
+#include "SHds.h"
+#include "CGAL_typedefs.h"
+#include <tbb/parallel_for.h>
+#include <tbb/blocked_range.h>
+#include <unordered_map>
+
+template<typename LCC>
+class SHDS_to_LCC
+{
+public:
+  typedef std::unordered_map<Halfedge_handle, typename LCC::Dart_handle> Assoc;
+
+  SHDS_to_LCC(SHds& ashds, LCC& alcc): m_shds(ashds), m_lcc(alcc)
+  {}
+
+  std::size_t shds_to_lcc()
+  {
+    m_lcc.clear();
+    create_darts();
+    set_beta_and_vertices_links();
+    return build_faces_array();
+  }
+
+  typename LCC::Dart_handle halfedge_to_dart(Halfedge_handle hh)
+  {
+    return assoc[hh];
+  }
+
+  void create_darts()
+  {
+    for (std::size_t i=0; i<m_shds.number_of_strips(); ++i)
+    {
+      for (auto it=m_shds.hds(i).halfedges().begin(),
+           itend=m_shds.hds(i).halfedges().end(); it!=itend; ++it)
+      {
+        if (!m_shds.partial_hds(i).is_external(it))
+        { assoc[it]=m_lcc.create_dart(); }
+      }
+    }
+  }
+
+  void set_beta_and_vertices_links()
+  {
+    tbb::parallel_for(tbb::blocked_range<std::size_t>(0, m_shds.number_of_strips()),
+                      [&](tbb::blocked_range<std::size_t> r)
+    {
+      for (std::size_t i=r.begin(); i<r.end(); ++i)
+      {
+        Global_halfedge hh;
+        for (auto it=m_shds.hds(i).halfedges().begin(),
+             itend=m_shds.hds(i).halfedges().end(); it!=itend; ++it)
+        {
+          if (!m_shds.partial_hds(i).is_external(it))
+          { // First halfedge is it
+            hh=m_shds.opposite(Global_halfedge(i, it)); // Opposite halfedge, non external
+            if (it<hh.halfedge())
+            { m_lcc.template basic_link_beta_for_involution<2>
+                  (halfedge_to_dart(it),
+                   halfedge_to_dart(hh.halfedge())); }
+            m_lcc.template basic_link_beta_1
+                (halfedge_to_dart(it),
+                 halfedge_to_dart(hh.halfedge()->next_around_vertex()));
+          }
+        }
+      }
+    }
+    );
+
+
+    // Last step not in parallel to keep vertices in the same order.
+    typename LCC::Dart_handle above=nullptr;
+    for (std::size_t i=0; i<m_shds.number_of_strips(); ++i)
+    {
+      Global_halfedge hh;
+      for (auto it=m_shds.hds(i).vertices().begin(),
+           itend=m_shds.hds(i).vertices().end(); it!=itend; ++it)
+      {
+        above=nullptr;
+        if (it->above_halfedge()!=nullptr)
+        {
+          hh=Global_halfedge(i, it->above_halfedge());
+          m_shds.move_to_non_external(hh);
+          above=halfedge_to_dart(hh.halfedge());
+          assert(above!=nullptr);
+        }
+        m_lcc.set_vertex_attribute(halfedge_to_dart(it->first_halfedge()),
+                                 m_lcc.create_vertex_attribute(m_shds.hds(i).point(it), above));
+      }
+    }
+  }
+
+  // Build the faces of the given lcc (and the father/son relations between holes)
+  // Return the number of finite faces. TODO copy the face array of m_shds
+  // instead of re-compute it.
+  std::size_t build_faces_array()
+  {
+    // display_info();
+
+    auto m_root=m_lcc.template create_attribute<2>();
+    m_root->info().m_finite=true; // Infinite face but considered as finite
+    // to ensure the property: each infinite face is included into a finite one.
+
+    std::size_t finite_faces=0;
+    auto treated=m_lcc.get_new_mark();
+    typename LCC::template Attribute_handle<2>::type newf, father;
+    Dart_handle dh, initdh, firstdart, fatherdart;
+    std::stack<Dart_handle> totreat;
+
+    // Iterate through all inner points, ordered from left to right
+    for (std::size_t i=0; i<m_shds.number_of_strips(); ++i)
+    {
+      for (auto it=m_shds.hds(i).vertices().begin(),
+           itend=m_shds.hds(i).vertices().end(); it!=itend; ++it)
+      {
+        if (!m_shds.partial_hds(i).is_external(it->first_halfedge()) &&
+            !m_lcc.is_marked(halfedge_to_dart(it->first_halfedge()),
+                           treated))
+        { // first_halfedge belongs necessarily to one infinite face.
+          firstdart=halfedge_to_dart(it->first_halfedge());
+          assert(m_lcc.is_dart_used(firstdart));
+
+          newf=m_lcc.template create_attribute<2>();
+          newf->info().m_finite=false; // Infinite face
+
+          // std::size_t nbdarts=0;
+          initdh=dh=firstdart;
+          do
+          {
+            // ++nbdarts;
+            m_lcc.mark(dh, treated);
+            m_lcc.template set_dart_attribute<2>(dh, newf);
+            if (!m_lcc.is_marked(m_lcc.template beta<2>(dh), treated))
+            { totreat.push(m_lcc.template beta<2>(dh)); }
+            dh=m_lcc.template beta<1>(dh);
+          }
+          while(dh!=initdh);
+
+          /* print_txt_with_endl("[Infinite Face ",
+                              m_lcc.template attributes<2>().index(newf), "]: ",
+                              "first segment: ",
+                              m_lcc.point(firstdart), " , ",
+                              m_lcc.point(m_lcc.other_extremity(firstdart)),
+                              ";  #darts=", nbdarts); */
+          fatherdart=m_lcc.template info<0>(firstdart).m_dart_above;
+          father=nullptr;
+          if (fatherdart==nullptr)
+          { father=m_root; }
+          else
+          {
+            assert(m_lcc.is_dart_used(fatherdart));
+            assert(m_lcc.template attribute<2>(fatherdart)!=nullptr);
+            assert(m_lcc.point(fatherdart)<
+                   m_lcc.point(m_lcc.other_extremity(fatherdart)));
+
+            /*print_txt_with_endl("father_of_first_halfedge: ",
+                                m_lcc.point(fatherdart), " , ",
+                                m_lcc.point(m_lcc.other_extremity(fatherdart))); */
+
+            if (m_lcc.template info<2>(fatherdart).m_finite)
+            { // Father is the dart of the finite face containing this hole
+              father=m_lcc.template attribute<2>(fatherdart);
+            }
+            else
+            { // Father is a dart of another hole, inside the same finite face
+              // This hole was already considered before.
+              assert(m_lcc.template info<2>(fatherdart).m_father!=nullptr);
+              father=m_lcc.template info<2>(fatherdart).m_father;
+            }
+          }
+          /* print_txt_with_endl(" Father of face ",
+                              m_lcc.template attributes<2>().index(newf),
+                              " -> ", m_lcc.template attributes<2>().index(father));
+          */
+          assert(father->info().m_finite);
+          newf->info().m_father=father;
+          father->info().m_son.push_back(newf);
+
+          // Now we iterate through the cc containing it->first_halfedge().
+          // Each new face is necessarily a finite one.
+          while(!totreat.empty())
+          {
+            initdh=totreat.top(); totreat.pop();
+            if (!m_lcc.is_marked(initdh, treated))
+            {
+              newf=m_lcc.template create_attribute<2>();
+              newf->info().m_finite=true; // Finite face
+              ++finite_faces;
+
+              // nbdarts=0;
+              dh=initdh;
+              do
+              {
+                // ++nbdarts;
+                m_lcc.mark(dh, treated);
+                m_lcc.template set_dart_attribute<2>(dh, newf);
+                if (!m_lcc.is_marked(m_lcc.template beta<2>(dh), treated))
+                { totreat.push(m_lcc.template beta<2>(dh)); }
+                dh=m_lcc.template beta<1>(dh);
+              }
+              while(dh!=initdh);
+
+              /* print_txt_with_endl("[Finite Face ",
+                                  m_lcc.template attributes<2>().index(newf), "]: ",
+                                  "father: ",
+                                  m_lcc.template attributes<2>().index(father),
+                                  "  first segment: ",
+                                  m_lcc.point(initdh), " , ",
+                                  m_lcc.point(m_lcc.other_extremity(initdh)),
+                                  ";  #darts=", nbdarts); */
+            }
+          }
+        }
+      }
+    }
+    assert(m_lcc.is_whole_map_marked(treated));
+    m_lcc.free_mark(treated);
+
+    return finite_faces;
+  }
+
+protected:
+  SHds& m_shds;
+  LCC&  m_lcc;
+  Assoc assoc;
+};
+
+
+// Build a global lcc from a parallel arrangement.
+// @Return the number of finite faces.
+template<typename LCC>
+std::size_t shds_to_lcc(SHds& ashds, LCC& alcc)
+{
+  SHDS_to_LCC<LCC> shds_to_lcc(ashds, alcc);
+  return shds_to_lcc.shds_to_lcc();
+}
+
+#endif // SHDS_TO_LCC_H
diff --git a/src/Segment_readers.h b/src/Segment_readers.h
new file mode 100644
index 0000000000000000000000000000000000000000..a6a76842ac7cbbbead3bb8f540c9b3de378235e2
--- /dev/null
+++ b/src/Segment_readers.h
@@ -0,0 +1,274 @@
+// 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 SEGMENT_READERS_H
+#define SEGMENT_READERS_H
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <CGAL/Random.h>
+#include <CGAL/point_generators_2.h>
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief The Reader class
+template<typename Kernel>
+class Reader
+{
+public:
+  using FT=typename Kernel::FT;
+  using Point=typename Kernel::Point_2;
+  using Segment=typename Kernel::Segment_2;
+
+  Reader() : m_cur_segment(0), m_split(false)
+  {}
+
+  void split(std::size_t splitLow, std::size_t splitHight)
+  {
+    m_split=true;
+    m_splitLow=splitLow;
+    m_splitHight=splitHight;
+  }
+
+  virtual ~Reader(){}
+  virtual bool reader_ok() const =0;
+  virtual Segment get_the_next_segment() =0;
+
+  bool ok() const
+  { return reader_ok() && (!m_split || m_cur_segment<m_splitHight); }
+
+  Segment next_segment()
+  {
+    Segment res;
+    do
+    {
+      res=get_the_next_segment();
+      ++m_cur_segment;
+    }
+    while(reader_ok() &&
+          (m_split &&
+           (m_cur_segment<m_splitLow || m_cur_segment>m_splitHight)));
+    return res;
+  }
+
+protected:
+  std::size_t m_cur_segment;
+  bool m_split;
+  std::size_t m_splitLow, m_splitHight;
+};
+///////////////////////////////////////////////////////////////////////////////
+template<typename Kernel>
+class Read_from_file: public Reader<Kernel>
+{
+public:
+  using Base=Reader<Kernel>;
+  using Segment=typename Base::Segment;
+  using Point=typename Base::Point;
+
+  Read_from_file(const std::string& filename): ifs(filename)
+  {
+    // std::cout<<"Segment file: "<<filename<<std::endl;
+    if (!ifs.is_open())
+    {
+      std::cerr<<"Error opening file '"<<filename<<"'"<<std::endl;
+    }
+    else if (ifs.peek()==EOF)
+    {
+      std::cerr<<"Error, empty file '"<<filename<<"'"<<std::endl;
+      ifs.close();
+    }
+  }
+
+  bool reader_ok() const
+  { return ifs.is_open(); }
+
+  Segment get_the_next_segment()
+  {
+    Segment s;
+    std::string line;
+    double x1, y1, x2, y2;
+    do
+    {
+      std::getline(ifs, line);
+      if (ifs.good())
+      { line.erase(line.find_last_not_of(" \n\r\t")+1); }
+    }
+    while (!ifs.fail() && line[0]=='#'); // jump over comment lines
+
+    if (ifs.good())
+    {
+      std::istringstream is(line);
+      is>>x1>>y1>>x2>>y2;
+      if (!is.fail())
+      {
+        if (ifs.peek()==EOF) { ifs.close(); }
+        if (x1>x2 || (x1==x2 && y1>y2))
+        { std::swap(x1, x2); std::swap(y1, y2); }
+        return Segment(Point(x1, y1), Point(x2, y2));
+      }
+    }
+    std::cerr<<"Error when reading file."<<std::endl;
+    ifs.close();
+    return Segment(Point(0,0),Point(0,0)); // An error occured.
+  }
+
+protected:
+  std::ifstream ifs;
+};
+///////////////////////////////////////////////////////////////////////////////
+template<typename Kernel>
+class Random_segments: public Reader<Kernel>
+{
+public:
+  using Base=Reader<Kernel>;
+  using Segment=typename Base::Segment;
+  using Point=typename Base::Point;
+  using FT=typename Base::FT;
+
+  Random_segments(std::size_t N, CGAL::Random& random,
+                  bool size, double L) :
+    m_N(N), m_random(random), m_size(size), m_L(L), m_nb_generated(0)
+  {
+    CGAL_assertion(L>0); // Otherwise, crash of Random_points_in_disc_2 constructor
+    std::cout<<"Random seed: "<<random.get_seed();
+    if (size) std::cout<<" with size<="<<L;
+    std::cout<<std::endl;
+  }
+
+  bool reader_ok() const
+  { return m_nb_generated<m_N; }
+
+  Segment get_the_next_segment()
+  {
+    Segment s;
+    Point p2;
+    typedef CGAL::Creator_uniform_2<FT, Point> Creator;
+    CGAL::Random_points_in_disc_2<Point,Creator> rand_in_disk(m_L, m_random);
+    if (m_nb_generated==0)
+    {
+      m_p1=Point(m_random.get_double(0.0, 100.0),
+                m_random.get_double(0.0, 100.0));
+    }
+    if (!m_size)
+    { p2=Point(m_random.get_double(0.0, 100.0),
+                m_random.get_double(0.0, 100.0)); }
+    else
+    {
+      do
+      {
+        p2=(*rand_in_disk); ++rand_in_disk;
+        p2=Point(m_p1.x()+p2.x(), m_p1.y()+p2.y());
+      }
+      while(p2.x()<0.0 || p2.x()>100.0 || p2.y()<0.0 || p2.y()>100.0);
+    }
+    /*    if (random.get_int(0,101)>60 && number_of_segments()>0) // dans 40% des cas
+    { // Get an existing segment
+      std::size_t existing_s=
+          static_cast<std::size_t>(random.get_int
+                                   (0,static_cast<int>(number_of_segments())));
+      double d1=random.get_double(0., 1.);
+      double d2=random.get_double(0., 1.);
+      typename MyKernel::Vector_2 vect
+          (get_segment(existing_s).source(), get_segment(existing_s).target());
+      p1=Point(get_segment(existing_s).source()+vect*d1);
+      p2=Point(get_segment(existing_s).target()-vect*d2);
+    }
+    else if (random.get_int(0,101)>50 && number_of_segments()>0) // dans 50% des cas restants
+    {
+      std::size_t existing_s=
+          static_cast<std::size_t>(random.get_int
+                                   (0,static_cast<int>(number_of_segments())));
+      p1=get_segment(existing_s).target();
+      do
+      {
+        p2=(*rand_in_disk); ++rand_in_disk;
+        p2=Point(p1.x()+p2.x(), p1.y()+p2.y());
+      }
+      while(p2.x()<0.0 || p2.x()>100.0 || p2.y()<0.0 || p2.y()>100.0);
+      }*/
+    Segment res;
+    if (m_p1.x()>p2.x() || (m_p1.x()==p2.x() && m_p1.y()>p2.y()))
+    { res=Segment(p2, m_p1); }
+    else  { res=Segment(m_p1, p2); }
+
+    ++m_nb_generated;
+    m_p1=p2;
+    return res;
+    // std::cout<<"Segment "<<p1<<" -> "<<p2<<std::endl;
+  }
+
+protected:
+  std::size_t m_N;
+  CGAL::Random m_random;
+  bool m_size;
+  double m_L;
+  std::size_t m_nb_generated;
+  Point m_p1;
+};
+///////////////////////////////////////////////////////////////////////////////
+template<typename Kernel>
+class Vector_of_segments: public Reader<Kernel>
+{
+public:
+  using Base=Reader<Kernel>;
+  using Segment=typename Base::Segment;
+  using Point=typename Base::Point;
+
+  Vector_of_segments(const std::vector<Segment>& all_segments) :
+    m_all_segments(all_segments),
+    m_nb_generated(0)
+  {}
+
+  bool reader_ok() const
+  { return m_nb_generated<m_all_segments.size(); }
+
+  Segment get_the_next_segment()
+  { return m_all_segments[m_nb_generated++]; }
+
+protected:
+  const std::vector<Segment>& m_all_segments;
+  std::size_t m_nb_generated;
+};
+///////////////////////////////////////////////////////////////////////////////
+template<typename Kernel>
+inline
+void fill_segment_array(Reader<Kernel>& reader,
+                        std::vector<typename Kernel::Segment_2>& all_segments)
+{
+  all_segments.clear();
+  while (reader.ok())
+  {
+    typename Kernel::Segment_2 s=reader.next_segment();
+    if (s.source()!=s.target())
+    { all_segments.push_back(s); }
+  }
+}
+///////////////////////////////////////////////////////////////////////////////
+inline std::size_t number_of_lines(const std::string& filename)
+{
+  std::ifstream in(filename);
+  std::size_t nb_lignes=0;
+  while(in.ignore(std::numeric_limits<std::streamsize>::max(), '\n'))
+  { ++nb_lignes; }
+  in.close();
+  return nb_lignes;
+}
+///////////////////////////////////////////////////////////////////////////////
+#endif // SEGMENT_READERS_H
diff --git a/src/compute-arrangement-streamed.cpp b/src/compute-arrangement-streamed.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6c14b9c7417f798cff96852dc573e64334614b55
--- /dev/null
+++ b/src/compute-arrangement-streamed.cpp
@@ -0,0 +1,248 @@
+// 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>
+//
+
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <stack>
+#include <tuple>
+#include <list>
+
+#include <CGAL/Memory_sizer.h>
+#include <CGAL/assertions.h>
+#include <CGAL/Surface_sweep_2.h>
+#include <CGAL/Surface_sweep_2_algorithms.h>
+#include <CGAL/Arr_segment_traits_2.h>
+
+#include "CGAL_typedefs.h"
+#include "Segment_readers.h"
+#include "My_visitor.h"
+#include "SHds.h"
+#include "SHds_to_lcc.h"
+#include "SHds_to_cgal_arrangement.h"
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+[[ noreturn ]] void usage(int /*argc*/, char** argv)
+{
+  // Name
+  std::cout<<"Name"<<std::endl;
+  std::cout<<"        "<<argv[0]<<" - a new method to compute arrangement of segments, streamed version";
+  std::cout<<std::endl<<std::endl;
+  // Synopsis
+  std::cout<<"SYNOPSIS"<<std::endl;
+  std::cout<<"        "<<argv[0]<<" [--help|-h|-?] [-t1 filename] [-nbs N]"
+           <<std::endl<<std::endl;
+  // Description
+  std::cout<<"DESCRIPTION"<<std::endl;
+  std::cout<<"        "<<"Compute the arrangement of segments given in the filename."
+           <<std::endl<<std::endl;
+  // Options
+  std::cout<<"        --help, -h, -?"<<std::endl
+           <<"                display this help and exit."
+           <<std::endl<<std::endl;
+  std::cout<<"        -t1 filename"
+           <<std::endl
+           <<"                load the text segment file, and creates the arrangement: required."
+           <<std::endl<<std::endl;
+  std::cout<<"        -nbs N"
+           <<std::endl
+           <<"                fix the number of segments to load for one strip."
+           <<std::endl<<std::endl;
+ // Author
+  std::cout<<"AUTHOR"<<std::endl;
+  std::cout<<"        "<<"Written by Guillaume Damiand."
+           <<std::endl<<std::endl;
+  // Copyright
+  std::cout<<"COPYRIGHT"<<std::endl;
+  std::cout<<"        "<<"Copyright (C) 2020 CNRS and LIRIS' Establishments (France). "
+           <<"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
+           <<std::endl
+           <<"        This is free software: you are free to change and redistribute it under certain conditions. "
+           <<"There is NO WARRANTY, to the extent permitted by law."
+           <<std::endl<<std::endl;
+  // Reporting bugs
+  std::cout<<"REPORTING BUGS"<<std::endl;
+  std::cout<<"        "<<"Email bug reports to Guillaume Damiand ⟨guillaume.damiand@liris.cnrs.fr⟩."
+           <<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,
+                          bool& t1,
+                          std::string& filename,
+                          std::size_t& nbs)
+{
+  t1=false;
+  filename="";
+  nbs=10000;
+
+  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==std::string("-t1"))
+    {
+      t1=true;
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no filename after -t1 option."); }
+      filename=std::string(argv[++i]);
+    }
+   else if (arg==std::string("-nbs"))
+    {
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no number after -nbs option."); }
+      nbs=std::stoi(std::string(argv[++i]));
+    }
+    else if (arg[0]=='-')
+    {
+      std::cout<<"Unknown option "<<arg<<std::endl;
+      helprequired=true;
+    }
+  }
+
+  if (!t1) { std::cout<<"ERROR: missing file name."<<std::endl; }
+  if (helprequired || !t1) { usage(argc, argv); }
+}
+///////////////////////////////////////////////////////////////////////////////
+void process_file(const std::string& filename,  std::size_t nbs)
+{
+  My_timer timer, global_timer, savetimer;
+
+  global_timer.reset();
+  global_timer.start();
+
+  std::vector<double> times(4,0);
+
+  typedef My_visitor<My_arr_segment_traits_2<EPECK>> Visitor;
+  My_arr_segment_traits_2<EPECK> m_traits;
+
+  double strip_xmin=0, strip_xmax=0, strip_ymin=0, strip_ymax=0, xmax=0;
+  bool first_strip=true;
+  std::list<ISegment> all_segments;
+  Read_from_file<EPICK> reader(filename);
+  std::size_t strip_id=0;
+  std::size_t id=1; // segment id
+  while (reader.ok())
+  {
+    // 1) Load new segments
+    timer.reset(); timer.start();
+    for (std::size_t i=0; reader.ok() && i<nbs; ++i)
+    {
+      EPICK::Segment_2 s=reader.next_segment();
+      if (first_strip && all_segments.empty())
+      { strip_xmin=s.source().x()-1.; xmax=s.target().x(); }
+      else { xmax=std::max(xmax, s.target().x()); }
+      strip_xmax=s.source().x();
+
+      // Note that we don't need ymin and ymax !
+      if (all_segments.empty())
+      { strip_ymin=s.source().y(); strip_ymax=strip_ymin;}
+      else
+      {
+        if (s.source().y()<strip_ymin) { strip_ymin=s.source().y(); }
+        if (s.source().y()>strip_ymax) { strip_ymax=s.source().y(); }
+      }
+      if (s.target().y()<strip_ymin) { strip_ymin=s.target().y(); }
+      if (s.target().y()>strip_ymax) { strip_ymax=s.target().y(); }
+
+      all_segments.push_back(s);
+    }
+    if (!reader.ok())
+    { strip_xmax=xmax+1; }
+    timer.stop();
+    times[0]+=timer.time();
+
+    // 2) Now all_segments contains all the segments of the current strip;
+    //    compute the partial hds of this strip.
+    timer.reset(); timer.start();
+    {
+      Partial_hds phds(strip_xmin, strip_ymin, strip_xmax, strip_ymax,
+                       (first_strip?0:(!reader.ok()?2:1)), 3);
+      Visitor visitor(phds);
+      My_surface_sweep_2<Visitor> surface_sweep(&m_traits, &visitor);
+      visitor.sweep(all_segments, false, id);
+      phds.display_info();
+
+      // 3) Save the partial hds
+      savetimer.reset(); savetimer.start();
+      std::ofstream outputfile(std::string("strip-")+std::to_string(strip_id++)+".save");
+      if (outputfile)
+      { outputfile<<phds; }
+      outputfile.close();
+      savetimer.stop();
+      times[2]+=savetimer.time();
+    }
+    timer.stop();
+    times[1]+=(timer.time()-savetimer.time()); // time to compute partial hds without
+    // including the save time; and including the de-allocation of the phds
+    // (reason of the block)
+
+    // 4) Remove all segments no more concerned by the new strip
+    timer.reset(); timer.start();
+    first_strip=false;
+    strip_xmin=strip_xmax; // xmin of the new strip is xmax of the previous strip
+    while (!all_segments.empty() &&
+           (all_segments.begin())->target().x()<strip_xmin)
+    {
+      all_segments.pop_front();
+      ++id; // id is incremented to keep global id the same
+    }
+    timer.stop();
+    times[3]+=timer.time();
+  }
+
+  global_timer.stop();
+
+  print_txt_with_endl("[TIME]: to load segments ", times[0]);
+  print_txt_with_endl("[TIME]: to compute all partial HDS ", times[1]);
+  print_txt_with_endl("[TIME]: to save partial HDS ", times[2]);
+  print_txt_with_endl("[TIME]: to update segments ", times[3]);
+  print_txt_with_endl("[GLOBAL]: time to compute all local arrangements ",
+                      global_timer.time());
+  print_txt_with_endl("[GLOBAL]: time to compute all local arrangements without save/load times ",
+                      times[1]+times[3]);
+}
+///////////////////////////////////////////////////////////////////////////////
+int main(int argc, char** argv)
+{
+  std::string filename;
+  bool t1;
+  std::size_t nbs;
+
+  process_command_line(argc, argv, t1, filename, nbs);
+  process_file(filename, nbs);
+
+  return EXIT_SUCCESS;
+}
+///////////////////////////////////////////////////////////////////////////////
diff --git a/src/draw_shds.h b/src/draw_shds.h
new file mode 100644
index 0000000000000000000000000000000000000000..186d121e1acaf9e0af3f077bf5c87cd2ae30911a
--- /dev/null
+++ b/src/draw_shds.h
@@ -0,0 +1,475 @@
+// 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 DRAW_SHDS_H
+#define DRAW_SHDS_H
+
+#include <CGAL/Qt/Basic_viewer_qt.h>
+
+#ifdef CGAL_USE_BASIC_VIEWER
+
+#include <CGAL/Random.h>
+#include <CGAL/Qt/Basic_viewer_qt.h>
+#include "SHds.h"
+
+// Viewer class for sHDS
+class MySimpleSHDSViewerQt : public CGAL::Basic_viewer_qt
+{
+  typedef CGAL::Basic_viewer_qt Base;
+  typedef typename Base::Local_point Point;
+
+public:
+  /// Construct the viewer.
+  /// @param ashds the sHDS to view
+  /// @param title the title of the window
+  /// @param anofaces if true, do not draw faces (faces are not computed; this can be
+  ///        usefull for very big object where this time could be long)
+  MySimpleSHDSViewerQt(QWidget* parent,
+                       SHds& ashds,
+                       const char* title="Basic Viewer for sHDS",
+                       bool anofaces=false) :
+    // First draw: vertices; edges, faces; multi-color; inverse normal
+    Base(parent, title, true, true, true, false, false),
+    m_shds(ashds),
+    m_nofaces(anofaces),
+    m_random_face_color(true),
+    m_num_face(0),
+    m_draw_grid(true),
+    m_cur_strip(0),
+    m_color_points(10, 10, 255),
+    m_color_grid(220, 220, 220),
+    m_color_selected_he(10,255,10),
+    m_color_above_links(85,210,180)
+  {
+    compute_elements();
+  }
+
+protected:
+  void draw_grid()
+  {
+    for (std::size_t i=0; i<m_shds.number_of_strips(); ++i)
+    {
+      const Partial_hds& la=m_shds.partial_hds(i);
+      add_segment(EPoint(la.xmin(), la.ymin()),
+                  EPoint(la.xmax(), la.ymin()), m_color_grid);
+
+      add_segment(EPoint(la.xmin(), la.ymax()),
+                  EPoint(la.xmax(), la.ymax()), m_color_grid);
+
+      add_segment(EPoint(la.xmin(), la.ymin()),
+                  EPoint(la.xmin(), la.ymax()), m_color_grid);
+    }
+
+    const Partial_hds& la=m_shds.
+      partial_hds(m_shds.number_of_strips()-1);
+    add_segment(EPoint(la.xmax(), la.ymin()),
+                EPoint(la.xmax(), la.ymax()), m_color_grid);
+  }
+
+  void compute_face(const Global_halfedge& dh)
+  {
+    if (m_nofaces) return;
+    assert (m_shds.face(dh)->finite());
+
+    // We fill only closed faces.
+    Global_halfedge cur=dh;
+    Global_halfedge min=dh;
+    do
+    {
+      if (cur<min) min=cur;
+      m_shds.move_to_next(cur);
+    }
+    while(cur!=dh);
+
+    if (m_random_face_color)
+    {
+      CGAL::Random random(m_shds.hds(min).halfedges().index(min.halfedge()));
+      CGAL::Color c=get_random_color(random);
+      face_begin(c);
+    }
+    else
+    { face_begin(); }
+
+    cur=dh;
+    do
+    {
+      add_point_in_face(m_shds.point(cur));
+      m_shds.move_to_next(cur);
+    }
+    while(cur!=dh);
+
+    for (std::size_t i=0; i<m_shds.face(dh)->sons().size(); ++i)
+    {
+      assert(!m_shds.face(dh)->sons()[i]->finite());
+      add_point_in_face(m_shds.point(dh));
+      cur=Global_halfedge(m_shds.face(dh)->sons()[i]->strip_id(),
+                            m_shds.face(dh)->sons()[i]->first_halfedge());
+      min=cur;
+      do
+      {
+        add_point_in_face(m_shds.point(cur));
+        if (m_num_face!=0)
+        { compute_edge(cur); }
+        m_shds.move_to_next(cur);
+      }
+      while(cur!=min);
+      add_point_in_face(m_shds.point(cur));
+    }
+    face_end();
+  }
+
+  void compute_edge(const Global_halfedge& phe)
+  {
+    const auto& p1 = m_shds.point(phe);
+    Global_halfedge d2=m_shds.opposite(phe);
+
+    if (m_cur_she.halfedge()!=nullptr && (phe==m_cur_she || m_cur_she==d2))
+    {
+      add_segment(p1, m_shds.point(d2), m_color_selected_he);
+      return;
+    }
+
+    bool concerned=(m_cur_strip==0?true:false);
+    if (m_cur_strip!=0)
+    {
+      CGAL::Comparison_result c1=CGAL::compare_x(p1, m_shds.partial_hds(m_cur_strip-1).m_min);
+      CGAL::Comparison_result c2=CGAL::compare_x(p1, m_shds.partial_hds(m_cur_strip-1).m_max);
+      if (c1!=CGAL::SMALLER && c2==CGAL::SMALLER) // Point in strip
+      { concerned=true; }
+      else
+      {
+        CGAL::Comparison_result c3=CGAL::compare_x(m_shds.point(d2), m_shds.partial_hds(m_cur_strip-1).m_min);
+        CGAL::Comparison_result c4=CGAL::compare_x(m_shds.point(d2), m_shds.partial_hds(m_cur_strip-1).m_max);
+        if (c3!=CGAL::SMALLER && c4==CGAL::SMALLER) // Point in strip
+        { concerned=true; }
+        else
+        { concerned=(c1==CGAL::SMALLER && c4!=CGAL::SMALLER); }
+      }
+    }
+    if (!concerned) return;
+
+    add_segment(p1, m_shds.point(d2));
+  }
+
+  void compute_vertex(const Global_halfedge& phe)
+  {
+    if (m_cur_she.halfedge()!=nullptr && m_shds.vertex(phe)==m_shds.vertex(m_cur_she))
+    {
+      add_point(m_shds.point(phe), m_color_selected_he);
+
+      Global_halfedge above(phe.strip_id(), m_shds.vertex(phe)->above_halfedge());
+      if (above.halfedge()!=nullptr)
+      {
+        m_shds.move_to_non_external(above);
+        add_segment(m_shds.point(phe), m_shds.point(above), m_color_above_links);
+        add_segment(m_shds.point(phe), m_shds.point(m_shds.opposite(above)),
+                    m_color_above_links);
+      }
+      return;
+    }
+
+    bool concerned=(m_cur_strip==0?true:false);
+    if (m_cur_strip!=0)
+    {
+      CGAL::Comparison_result c1=CGAL::compare_x
+          (m_shds.point(phe), m_shds.partial_hds(m_cur_strip-1).m_min);
+      CGAL::Comparison_result c2=CGAL::compare_x
+          (m_shds.point(phe), m_shds.partial_hds(m_cur_strip-1).m_max);
+      if (c1!=CGAL::SMALLER && c2==CGAL::SMALLER) // Point in strip
+      { concerned=true; }
+    }
+    if (!concerned) return;
+
+    add_point(m_shds.point(phe));
+  }
+
+  void compute_elements()
+  {
+    clear();
+
+    if (m_draw_grid)
+    { draw_grid(); }
+
+    typename SHds::size_type markedges    = m_shds.get_new_mark();
+    typename SHds::size_type markvertices = m_shds.get_new_mark();
+
+    std::size_t n=0;
+    auto it=m_shds.faces().begin(), itend=m_shds.faces().end();
+    for (++it; it!=itend; ++it ) // We need to jump over the first face
+    {
+      if (m_num_face==0 || it->finite())
+      {
+        ++n;
+        if (m_cur_she.halfedge()==nullptr && (m_num_face==0 || m_num_face==n))
+        { m_cur_she.set(it->strip_id(), it->first_halfedge()); }
+        if (m_num_face==0 || m_num_face==n)
+        {
+          assert(it->first_halfedge()!=nullptr);
+          Global_halfedge itf(it->strip_id(), it->first_halfedge());
+          Global_halfedge itfend=itf;
+
+          assert(!m_shds.partial_hds(itf).is_external(itf.halfedge()));
+
+          if (it->finite())
+          { compute_face(itf); }
+
+          do
+          {
+            if (!m_shds.is_marked(itf, markvertices))
+            {
+              compute_vertex(itf);
+              Global_halfedge itv=itf;
+              do
+              {
+                m_shds.mark(itv, markvertices);
+                itv.set_halfedge(m_shds.hds(itv).next_around_vertex(itv.halfedge()));
+              }
+              while(itv!=itf);
+            }
+
+            if (!m_shds.is_marked(itf, markedges))
+            {
+              compute_edge(itf);
+              m_shds.mark(itf, markedges);
+              m_shds.mark(m_shds.opposite(itf), markedges);
+            }
+
+            m_shds.move_to_next(itf);
+          }
+          while(itf!=itfend);
+        }
+      }
+    }
+
+    for (std::size_t i=0; i<m_shds.number_of_strips(); ++i)
+    {
+      for (auto it=m_shds.hds(i).halfedges().begin(),
+           itend=m_shds.hds(i).halfedges().end(); it!=itend; ++it)
+      {
+        m_shds.unmark(it, markvertices);
+        m_shds.unmark(it, markedges);
+      }
+    }
+
+    m_shds.free_mark(markedges);
+    m_shds.free_mark(markvertices);
+  }
+
+  virtual void init()
+  {
+    Base::init();
+
+    setKeyDescription(::Qt::Key_B, "Toggles display grid borders");
+
+    setKeyDescription(::Qt::Key_D, "Move current halfedge by next");
+    setKeyDescription(::Qt::ControlModifier+::Qt::Key_D, "Move current halfedge by previous");
+    setKeyDescription(::Qt::ShiftModifier+::Qt::Key_D, "Move current halfedge by opposite");
+
+    setKeyDescription(::Qt::Key_Z+::Qt::ControlModifier, "Draw all faces");
+    setKeyDescription(::Qt::ControlModifier+::Qt::Key_Left, "Decrement current face drawn");
+    setKeyDescription(::Qt::ControlModifier+::Qt::Key_Right, "Increment current face drawn");
+
+    setKeyDescription(::Qt::Key_T, "Increment current strip drawn");
+    setKeyDescription(::Qt::ShiftModifier+::Qt::Key_T, "Decrement current strip drawn");
+    setKeyDescription(::Qt::Key_T+::Qt::ControlModifier, "Draw all strips");
+
+    setMouseBindingDescription(::Qt::ControlModifier, ::Qt::LeftButton, "Display position of the point");
+  }
+
+  virtual void keyPressEvent(QKeyEvent *e)
+  {
+    const ::Qt::KeyboardModifiers modifiers = e->modifiers();
+    if ((e->key()==::Qt::Key_B) && (modifiers==::Qt::NoButton))
+    {
+      m_draw_grid=!m_draw_grid;
+      displayMessage(QString("Draw grid=%1.").arg(m_draw_grid?"true":"false"));
+      compute_elements();
+      redraw();
+    }
+    else if ((e->key()==::Qt::Key_D) && (modifiers==::Qt::NoButton))
+    {
+      m_shds.move_to_next(m_cur_she);
+      displayMessage(QString("Cur halfedge move by next."));
+      std::cout<<"Dart: "<<m_shds.point(m_cur_she)<<", "
+          <<m_shds.point(m_shds.opposite(m_cur_she))<<std::endl;
+      compute_elements();
+      redraw();
+    }
+    else if ((e->key()==::Qt::Key_D) && (modifiers==::Qt::ControlModifier))
+    {
+      m_shds.move_to_previous(m_cur_she);
+      displayMessage(QString("Cur halfedge move by previous."));
+      std::cout<<"Dart: "<<m_shds.point(m_cur_she)<<", "
+              <<m_shds.point(m_shds.opposite(m_cur_she))<<std::endl;
+      compute_elements();
+      redraw();
+    }
+    else if ((e->key()==::Qt::Key_D) && (modifiers==::Qt::ShiftModifier))
+    {
+      m_shds.move_to_opposite(m_cur_she);
+      std::cout<<"Dart: "<<m_shds.point(m_cur_she)<<", "
+              <<m_shds.point(m_shds.opposite(m_cur_she))<<std::endl;
+      displayMessage(QString("Cur halfedge move by opposite."));
+      compute_elements();
+      redraw();
+    }
+    else if ((e->key()==::Qt::Key_Z) && (modifiers==::Qt::ControlModifier))
+    {
+      m_num_face=0;
+      if (m_cur_she.halfedge()==nullptr && !m_shds.faces().empty())
+      {
+        m_cur_she.set(0, m_shds.hds(0).halfedges().begin());
+        m_cur_she.set(m_shds.faces().begin()->strip_id(),
+                       m_shds.faces().begin()->first_halfedge());
+      }
+      displayMessage(QString("Draw all faces."));
+      compute_elements();
+      redraw();
+    }
+    else if ((e->key()==::Qt::Key_Right) && (modifiers==::Qt::ControlModifier))
+    {
+      ++m_num_face; m_cur_she.set_halfedge(nullptr);
+      if (m_num_face==m_shds.number_of_finite_faces()+1)
+      {
+        m_num_face=0;
+        displayMessage(QString("Draw all faces."));
+      }
+      else
+      {
+        displayMessage(QString("Draw face num %1.").arg(m_num_face));
+      }
+      compute_elements();
+      redraw();
+    }
+    else if ((e->key()==::Qt::Key_Left) && (modifiers==::Qt::ControlModifier))
+    {
+      m_cur_she.set_halfedge(nullptr);
+      if (m_num_face==0)
+      { m_num_face=m_shds.number_of_finite_faces(); }
+      else { --m_num_face; }
+
+      if (m_num_face==0)
+      { displayMessage(QString("Draw all faces.")); }
+      else
+      { displayMessage(QString("Draw face num %1.").arg(m_num_face)); }
+      compute_elements();
+      redraw();
+    }
+    else if ((e->key()==::Qt::Key_T) && (modifiers==::Qt::NoButton))
+    {
+      ++m_cur_strip;
+      if (m_cur_strip==m_shds.number_of_strips()+1)
+      {
+        m_cur_strip=0;
+        displayMessage(QString("Draw all strips."));
+      }
+      else
+      { displayMessage(QString("Draw strip num %1.").arg(m_cur_strip-1)); }
+      compute_elements();
+      redraw();
+    }
+    else if ((e->key()==::Qt::Key_T) && (modifiers==::Qt::ShiftModifier))
+    {
+      if (m_cur_strip==0)
+      { m_cur_strip=m_shds.number_of_strips(); }
+      else { --m_cur_strip; }
+
+      if (m_cur_strip==0)
+      { displayMessage(QString("Draw all strips.")); }
+      else
+      { displayMessage(QString("Draw strip num %1.").arg(m_cur_strip-1)); }
+      compute_elements();
+      redraw();
+    }
+    else if ((e->key()==::Qt::Key_T) && (modifiers==::Qt::ControlModifier))
+    {
+      m_cur_strip=0;
+      displayMessage(QString("Draw all strips."));
+      compute_elements();
+      redraw();
+    }
+    else
+    { Base::keyPressEvent(e); } // Call the base method to process others/classicals key
+
+    // Call: * compute_elements() if the model changed, followed by
+    //       * redraw() if some viewing parameters changed that implies some
+    //                  modifications of the buffers
+    //                  (eg. type of normal, color/mono)
+    //       * update() just to update the drawing
+  }
+
+  void mousePressEvent (QMouseEvent * m)
+  {
+    if (m->modifiers()==Qt::ControlModifier)
+    {
+      CGAL::qglviewer::Vec globalp=camera()->unprojectedCoordinatesOf
+                                   (CGAL::qglviewer::Vec(m->x(), m->y(), 0));
+      displayMessage(QString("Point (%1, %2).").arg(globalp.x).arg(globalp.y));
+    }
+    Base::mousePressEvent(m);
+  }
+
+protected:
+  SHds& m_shds;
+  bool m_nofaces;
+  bool m_random_face_color;
+  std::size_t m_num_face;
+  Global_halfedge m_cur_she;
+  bool m_draw_grid;
+  std::size_t m_cur_strip;
+
+  CGAL::Color m_color_points;
+  CGAL::Color m_color_grid;
+  CGAL::Color m_color_selected_he;
+  CGAL::Color m_color_above_links;
+};
+
+void draw_shds(SHds& ashds,
+               const char* title="Basic Viewer for sHDS",
+               bool nofill=false)
+{
+#if defined(CGAL_TEST_SUITE)
+  bool cgal_test_suite=true;
+#else
+  bool cgal_test_suite=qEnvironmentVariableIsSet("CGAL_TEST_SUITE");
+#endif
+
+  if (!cgal_test_suite)
+  {
+    int argc=1;
+    const char* argv[2]={"hdsviewer","\0"};
+    QApplication app(argc,const_cast<char**>(argv));
+    MySimpleSHDSViewerQt mainwindow(app.activeWindow(), ashds, title, nofill);
+    mainwindow.show();
+    app.exec();
+  }
+}
+
+#else // CGAL_USE_BASIC_VIEWER
+
+void draw_shds(SHds& /*ashds*/,
+               const char* /*title*/="Basic Viewer for sHDS",
+               bool /*nofill*/=false)
+{
+}
+
+
+#endif // CGAL_USE_BASIC_VIEWER
+
+#endif // DRAW_SHDS_H
diff --git a/src/memory.h b/src/memory.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c6715252d38c50e0b22f978b5b7a71022f531cb
--- /dev/null
+++ b/src/memory.h
@@ -0,0 +1,127 @@
+/*
+ * Author:  David Robert Nadeau
+ * Site:    http://NadeauSoftware.com/
+ * License: Creative Commons Attribution 3.0 Unported License
+ *          http://creativecommons.org/licenses/by/3.0/deed.en_US
+ */
+
+#ifndef MEMORY_H
+#define MEMORY_H
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <psapi.h>
+
+#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
+#include <unistd.h>
+#include <sys/resource.h>
+
+#if defined(__APPLE__) && defined(__MACH__)
+#include <mach/mach.h>
+
+#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
+#include <fcntl.h>
+#include <procfs.h>
+
+#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
+#include <stdio.h>
+
+#endif
+
+#else
+#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
+#endif
+
+
+
+
+
+/**
+ * Returns the peak (maximum so far) resident set size (physical
+ * memory use) measured in bytes, or zero if the value cannot be
+ * determined on this OS.
+ */
+size_t getPeakRSS( )
+{
+#if defined(_WIN32)
+    /* Windows -------------------------------------------------- */
+    PROCESS_MEMORY_COUNTERS info;
+    GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
+    return (size_t)info.PeakWorkingSetSize;
+
+#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
+    /* AIX and Solaris ------------------------------------------ */
+    struct psinfo psinfo;
+    int fd = -1;
+    if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 )
+        return (size_t)0L;      /* Can't open? */
+    if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) )
+    {
+        close( fd );
+        return (size_t)0L;      /* Can't read? */
+    }
+    close( fd );
+    return (size_t)(psinfo.pr_rssize * 1024L);
+
+#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
+    /* BSD, Linux, and OSX -------------------------------------- */
+    struct rusage rusage;
+    getrusage( RUSAGE_SELF, &rusage );
+#if defined(__APPLE__) && defined(__MACH__)
+    return (size_t)rusage.ru_maxrss;
+#else
+    return (size_t)(rusage.ru_maxrss * 1024L);
+#endif
+
+#else
+    /* Unknown OS ----------------------------------------------- */
+    return (size_t)0L;          /* Unsupported. */
+#endif
+}
+
+
+
+
+
+/**
+ * Returns the current resident set size (physical memory use) measured
+ * in bytes, or zero if the value cannot be determined on this OS.
+ */
+size_t getCurrentRSS( )
+{
+#if defined(_WIN32)
+    /* Windows -------------------------------------------------- */
+    PROCESS_MEMORY_COUNTERS info;
+    GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
+    return (size_t)info.WorkingSetSize;
+
+#elif defined(__APPLE__) && defined(__MACH__)
+    /* OSX ------------------------------------------------------ */
+    struct mach_task_basic_info info;
+    mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
+    if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO,
+        (task_info_t)&info, &infoCount ) != KERN_SUCCESS )
+        return (size_t)0L;      /* Can't access? */
+    return (size_t)info.resident_size;
+
+#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
+    /* Linux ---------------------------------------------------- */
+    long rss = 0L;
+    FILE* fp = NULL;
+    if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
+        return (size_t)0L;      /* Can't open? */
+    if ( fscanf( fp, "%*s%ld", &rss ) != 1 )
+    {
+        fclose( fp );
+        return (size_t)0L;      /* Can't read? */
+    }
+    fclose( fp );
+    return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);
+
+#else
+    /* AIX, BSD, Solaris, and Unknown OS ------------------------ */
+    return (size_t)0L;          /* Unsupported. */
+#endif
+}
+
+#endif // MEMORY_H
diff --git a/src/parallel-arrangement-bench.cpp b/src/parallel-arrangement-bench.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..164746b6da5a25916bd28c870a828b0d9236edaf
--- /dev/null
+++ b/src/parallel-arrangement-bench.cpp
@@ -0,0 +1,282 @@
+// 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>
+//
+
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <stack>
+#include <tuple>
+#include <thread>
+#include <boost/filesystem.hpp>
+
+#include <CGAL/Memory_sizer.h>
+#include <CGAL/assertions.h>
+#include <CGAL/Surface_sweep_2.h>
+#include <CGAL/Surface_sweep_2_algorithms.h>
+#include <CGAL/Arr_segment_traits_2.h>
+#include <CGAL/Arrangement_2.h>
+#include <CGAL/Arr_consolidated_curve_data_traits_2.h>
+#include <CGAL/Arr_non_caching_segment_basic_traits_2.h>
+
+#include "CGAL_typedefs.h"
+#include "Segment_readers.h"
+#include "My_visitor.h"
+#include "SHds.h"
+#include "SHds_to_lcc.h"
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+[[ noreturn ]] void usage(int /*argc*/, char** argv)
+{
+  // Name
+  std::cout<<"Name"<<std::endl;
+  std::cout<<"        "<<argv[0]<<" - a new method to compute arrangement of segments";
+  std::cout<<std::endl<<std::endl;
+  // Synopsis
+  std::cout<<"SYNOPSIS"<<std::endl;
+  std::cout<<"        "<<argv[0]<<" [--help|-h|-?] "
+           <<"[-t1 filename] [-nbs S] [-nbt N] [-crop] [-optimized-strips] [-cgal]"
+           <<std::endl<<std::endl;
+  // Description
+  std::cout<<"DESCRIPTION"<<std::endl;
+  std::cout<<"        "<<"Compute the arrangement of segments given in the filename."
+           <<std::endl<<std::endl;
+  // Options
+  std::cout<<"        --help, -h, -?"<<std::endl
+           <<"                display this help and exit."
+           <<std::endl<<std::endl;
+  std::cout<<"        -t1 filename"
+           <<std::endl
+           <<"                load the text segment file, and creates the arrangement: required."
+           <<std::endl<<std::endl;
+  std::cout<<"        -nbs S"
+           <<std::endl
+           <<"                number of strips (1 by default)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -nbt N"
+           <<std::endl
+           <<"                number of threads (1 by default)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -crop"
+          <<std::endl
+          <<"                crop the segments to fit in its strip."
+          <<std::endl<<std::endl;
+  std::cout<<"        -repeat R"
+           <<std::endl
+           <<"                repeat each test R times (1 by default)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -optimized-strips"
+           <<std::endl
+           <<"                compute the length of each strips dynamically (by default each strip has the same size) (used only if the number of threads is > 1)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -cgal"
+           <<std::endl
+           <<"                run cgal arrangement (and not our new method)."
+           <<std::endl<<std::endl;
+// Author
+  std::cout<<"AUTHOR"<<std::endl;
+  std::cout<<"        "<<"Written by Guillaume Damiand."
+           <<std::endl<<std::endl;
+  // Copyright
+  std::cout<<"COPYRIGHT"<<std::endl;
+  std::cout<<"        "<<"Copyright (C) 2020 CNRS and LIRIS' Establishments (France). "
+           <<"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
+           <<std::endl
+           <<"        This is free software: you are free to change and redistribute it under certain conditions. "
+           <<"There is NO WARRANTY, to the extent permitted by law."
+           <<std::endl<<std::endl;
+  // Reporting bugs
+  std::cout<<"REPORTING BUGS"<<std::endl;
+  std::cout<<"        "<<"Email bug reports to Guillaume Damiand ⟨guillaume.damiand@liris.cnrs.fr⟩."
+           <<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,
+                          bool& t1,
+                          std::string& filename,
+                          std::size_t& nbstrips,
+                          std::size_t& nbthreads,
+                          std::size_t& repeat,
+                          bool &optimized_strips,
+                          bool &cgal,
+                          bool &crop)
+{
+  t1=false;
+  filename="";
+  nbstrips=1;
+  nbthreads=1;
+  optimized_strips=false;
+  cgal=false;
+  repeat=1;
+  crop=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==std::string("-t1"))
+    {
+      t1=true;
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no filename after -t1 option."); }
+      filename=std::string(argv[++i]);
+    }
+    else if (arg==std::string("-nbs"))
+    {
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no number after -nbs option."); }
+      nbstrips=std::stoi(std::string(argv[++i]));
+    }
+    else if (arg==std::string("-nbt"))
+    {
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no number after -nbt option."); }
+      nbthreads=std::stoi(std::string(argv[++i]));
+    }
+    else if (arg==std::string("-repeat"))
+    {
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no number after -repeat option."); }
+      repeat=std::stoi(std::string(argv[++i]));
+    }
+    else if (arg==std::string("-optimized-strips"))
+    { optimized_strips=true; }
+    else if (arg==std::string("-cgal"))
+    { cgal=true; }
+    else if (arg==std::string("-crop"))
+    { crop=true; }
+    else if (arg[0]=='-')
+    {
+      std::cout<<"Unknown option "<<arg<<std::endl;
+      helprequired=true;
+    }
+  }
+
+  if (nbthreads==0) { nbthreads=1; }
+  if (repeat==0) { repeat=1; }
+  if (!t1) { std::cout<<"ERROR: missing txt file name."<<std::endl; }
+  if (helprequired || !t1) { usage(argc, argv); }
+}
+///////////////////////////////////////////////////////////////////////////////
+int main(int argc, char** argv)
+{
+  std::string filename;
+  bool t1;
+  std::size_t nbstrips, nbthreads, repeat;
+  bool optimized_strips;
+  bool cgal;
+  bool crop;
+
+  process_command_line(argc, argv, t1, filename, nbstrips, nbthreads, repeat,
+                       optimized_strips, cgal, crop);
+
+  std::ofstream ftimes("times.dat", std::ios_base::app);
+  std::ofstream fdetailedtimes("detailed-times.dat", std::ios_base::app);
+  std::ofstream fcells("nbcells.dat", std::ios_base::app);
+  ftimes.setf( std::ios::fixed, std:: ios::floatfield );
+  ftimes.precision(2);
+  fdetailedtimes.setf( std::ios::fixed, std:: ios::floatfield );
+  fdetailedtimes.precision(2);
+
+  boost::filesystem::path p(filename);
+
+  if (cgal)
+  {
+    ftimes<<p.stem()<<'\t';
+    fdetailedtimes<<p.stem()<<'\t';
+    fcells<<"####################"<<p.stem()<<std::endl;
+  }
+
+  if (cgal)
+  {
+    typedef CGAL::Arr_segment_traits_2<EPECK> Traits_2;
+    typedef CGAL::Arrangement_2<Traits_2>  Arrangement_2;
+    std::vector<ESegment> all_segments;
+    all_segments.reserve(number_of_lines(filename));
+    Read_from_file<EPECK> reader(filename);
+    fill_segment_array<EPECK>(reader, all_segments);
+
+    My_timer timer;
+    for (std::size_t i=0; i<repeat; ++i)
+    {
+      timer.start();
+      Arrangement_2 arr;
+      CGAL::insert(arr, all_segments.begin(), all_segments.end());
+      timer.stop();
+
+      if (i==0)
+      {
+        fcells<<arr.number_of_halfedges()<<'\t'
+             <<arr.number_of_vertices()<<'\t'
+            <<arr.number_of_edges()<<'\t'
+           <<arr.number_of_faces()-arr.number_of_unbounded_faces()<<'\t'
+          <<arr.number_of_faces()<<std::endl;
+      }
+    }
+
+    ftimes<<timer.time()/repeat<<'\t';
+  }
+  else
+  {
+    std::vector<double> times;
+    // times[0] : global time
+    // times[1] : load and dispatch
+    // times[2] : compute all local arrangements
+    // times[3] : compute faces
+
+    for (std::size_t i=0; i<repeat; ++i)
+    {
+      SHds shds(filename, nbstrips, nbthreads, optimized_strips, times, crop);
+      if (i==0)
+      {
+        LCC_2 lcc;
+        std::size_t finite_faces=shds_to_lcc(shds, lcc); // TODO NO MORE NEED !!
+         std::vector<unsigned int> nbcells=lcc.count_all_cells();
+
+        fcells<<shds.number_of_halfedges()<<'\t'
+             <<nbcells[0]<<'\t'<<nbcells[1]<<'\t'
+            <<finite_faces<<'\t'<<nbcells[2]
+            <<'\t'<<shds.number_of_external_halfedges()<<std::endl;
+      }
+    }
+
+    ftimes<<(times[0]-times[1])/repeat<<'\t';
+    fdetailedtimes<<times[1]/repeat<<'\t'
+                  <<times[2]/repeat<<'\t'
+                  <<times[3]/repeat<<'\t';
+  }
+
+  return EXIT_SUCCESS;
+}
+///////////////////////////////////////////////////////////////////////////////
diff --git a/src/parallel-arrangement.cpp b/src/parallel-arrangement.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ae895ffb62f24990a9709b5cb4bf868039682a7f
--- /dev/null
+++ b/src/parallel-arrangement.cpp
@@ -0,0 +1,590 @@
+// 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>
+//
+
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <stack>
+#include <tuple>
+#include <thread>
+#include <boost/filesystem.hpp>
+
+#include <CGAL/assertions.h>
+#include <CGAL/Surface_sweep_2.h>
+#include <CGAL/Surface_sweep_2_algorithms.h>
+#include <CGAL/Arr_segment_traits_2.h>
+#include <CGAL/Arrangement_2.h>
+#include <CGAL/Arr_consolidated_curve_data_traits_2.h>
+#include <CGAL/Arr_non_caching_segment_basic_traits_2.h>
+
+#include "CGAL_typedefs.h"
+#include "Segment_readers.h"
+#include "My_visitor.h"
+#include "SHds.h"
+#include "SHds_to_lcc.h"
+#include "SHds_to_cgal_arrangement.h"
+#include "memory.h"
+#include "draw_shds.h"
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+[[ noreturn ]] void usage(int /*argc*/, char** argv)
+{
+  // Name
+  std::cout<<"Name"<<std::endl;
+  std::cout<<"        "<<argv[0]<<" - a new method to compute arrangement of segments";
+  std::cout<<std::endl<<std::endl;
+  // Synopsis
+  std::cout<<"SYNOPSIS"<<std::endl;
+  std::cout<<"        "<<argv[0]<<" [--help|-h|-?] "
+           <<"[-t1 FILENAME] [-t2 FILENAME] [-t3 FILENAME] [-cgal] [-lcc] [-traverse]"
+           <<"[-nbs S] [-nbt N] [-crop] [-optimized-strips] [-xpos X1 X2 ...] "
+           <<"[-export-cgal] [-draw] [-save] [-export-xfig XFIGFILE] "
+           <<"[-export-xfig-sequence] [-xfig-invert-y] [-xfig-x-size S] "
+           <<"[-xfig-width W1 W2 W3 W4 W5] "
+           <<"[-xfig-color R1 G1 B1 R2 G2 B2 R3 G3 B3 R4 G4 B4]"
+           <<std::endl<<std::endl;
+  // Description
+  std::cout<<"DESCRIPTION"<<std::endl;
+  std::cout<<"        "<<"Compute the arrangement of segments given in the FILENAME."
+           <<std::endl<<std::endl;
+  // Options
+  std::cout<<"        --help, -h, -?"<<std::endl
+           <<"                display this help and exit."
+           <<std::endl<<std::endl;
+  std::cout<<"        -t1 FILENAME"
+           <<std::endl
+           <<"                load the text segment file, and creates the arrangement."
+           <<std::endl<<std::endl;
+  std::cout<<"        -t2 FILENAME"
+           <<std::endl
+           <<"                load the sHDS from FILENAME."
+           <<std::endl<<std::endl;
+  std::cout<<"        -t3 FILENAME"
+           <<std::endl
+           <<"                load the sequence of HDS from FILENAME, which must contains % at the position of the number."
+           <<std::endl<<std::endl;
+  std::cout<<"        -cgal"
+           <<std::endl
+           <<"                use CGAL arrangement (and not our method as default)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -lcc"
+           <<std::endl
+           <<"                compute a 2D Linear cell complex from the sHDS."
+           <<std::endl<<std::endl;
+  std::cout<<"        -traverse"
+           <<std::endl
+           <<"                traverse the sHDS and compute time."
+           <<std::endl<<std::endl;
+  std::cout<<"        -nbs S"
+           <<std::endl
+           <<"                number of strips (1 by default)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -nbt N"
+           <<std::endl
+           <<"                number of threads (1 by default)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -crop"
+          <<std::endl
+          <<"                crop the segments to fit in its strip."
+          <<std::endl<<std::endl;
+  std::cout<<"        -optimized-strips"
+           <<std::endl
+           <<"                compute the length of each strips dynamically (by default each strip has the same size) (used only if the number of strips is > 1) (not used if option -xpos is used)."
+           <<std::endl<<std::endl;
+  std::cout<<"        -xpos X1 X2 ..."
+          <<std::endl
+          <<"                gives the x positions of the strips (we must have S-1 numbers, B being the number given after -nbs option, and this option must be used after -nbs option)."
+          <<std::endl<<std::endl;
+  std::cout<<"        -export-cgal"
+           <<std::endl
+           <<"                compute a CGAL arrangement from the sHDS."
+           <<std::endl<<std::endl;
+  std::cout<<"        -draw"
+          <<std::endl
+          <<"                draw the sHDS."
+          <<std::endl<<std::endl;
+  std::cout<<"        -save"
+          <<std::endl
+          <<"                save the sHDS."
+          <<std::endl<<std::endl;
+ std::cout<<"        -export-xfig XFIGFILE"
+         <<std::endl
+         <<"                export the sHDS into the given xfig file."
+         <<std::endl<<std::endl;
+ std::cout<<"        -export-xfig-sequence"
+         <<std::endl
+         <<"                export the strips as a sequence of xfig files."
+         <<std::endl<<std::endl;
+ std::cout<<"        -xfig-invert-y"
+         <<std::endl
+         <<"                invert y axis for the export xfig."
+         <<std::endl<<std::endl;
+ std::cout<<"        -xfig-x-size S"
+         <<std::endl
+         <<"                set the x size of the xfig file to S (default 50000.)."
+         <<std::endl<<std::endl;
+ std::cout<<"        -xfig-width W1 W2 W3 W4 W5"
+         <<std::endl
+         <<"                fix the size of: segments=W1; disks=W2; criticals=W3; borders=W4; "
+         <<"space between strips=W5 (default 2 30 2 1 100) (if one width is 0, corresponding elements are not drawn)."
+         <<std::endl<<std::endl;
+ std::cout<<"        -xfig-color R1 G1 B1 R2 G2 B2 R3 G3 B3 R4 G4 B4"
+         <<std::endl
+         <<"                fix the color of: segments=R1 G1 B1; disks=R2 G2 B2; "
+         <<"criticals=R3 G3 B3; borders=R4 G4 B4 (default 40 40 220  220 40 40  90 190 110  150 150 150)."
+         <<std::endl<<std::endl;
+ // Author
+  std::cout<<"AUTHOR"<<std::endl;
+  std::cout<<"        "<<"Written by Guillaume Damiand."
+           <<std::endl<<std::endl;
+  // Copyright
+  std::cout<<"COPYRIGHT"<<std::endl;
+  std::cout<<"        "<<"Copyright (C) 2020 CNRS and LIRIS' Establishments (France). "
+           <<"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
+           <<std::endl
+           <<"        This is free software: you are free to change and redistribute it under certain conditions. "
+           <<"There is NO WARRANTY, to the extent permitted by law."
+           <<std::endl<<std::endl;
+  // Reporting bugs
+  std::cout<<"REPORTING BUGS"<<std::endl;
+  std::cout<<"        "<<"Email bug reports to Guillaume Damiand ⟨guillaume.damiand@liris.cnrs.fr⟩."
+           <<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& t1,
+                          bool &t2,
+                          bool &t3,
+                          bool &cgal,
+                          bool &lcc,
+                          bool &traverse,
+                          std::size_t& nbstrips,
+                          std::size_t& nbthreads,
+                          bool &crop,
+                          bool &optimized_strips,
+                          std::vector<double>& xpos_cuts,
+                          bool &export_cgal,
+                          bool &draw,
+                          bool &save,
+                          std::string& xfig_file,
+                          bool &export_xfig_sequence,
+                          bool &xfig_invert_y,
+                          double &xfig_x_size,
+                          uint16_t& width_segments,
+                          uint16_t& radius_disks,
+                          uint16_t& width_criticals,
+                          uint16_t& width_borders,
+                          uint16_t& space_between_strips,
+                          CGAL::Color& color_segments,
+                          CGAL::Color& color_disks,
+                          CGAL::Color& color_criticals,
+                          CGAL::Color& color_borders)
+ {
+  t1=false;
+  t2=false;
+  t3=false;
+  cgal=false;
+  lcc=false;
+  traverse=false;
+  filename="";
+  nbstrips=1;
+  nbthreads=1;
+  draw=false;
+  optimized_strips=false;
+  export_cgal=false;
+  save=false;
+  crop=false;
+  xfig_file="";
+  export_xfig_sequence=false;
+  xpos_cuts.clear();
+
+  width_segments=2;
+  radius_disks=30;
+  width_criticals=2;
+  width_borders=1;
+  space_between_strips=100;
+
+  xfig_invert_y=false;
+  xfig_x_size=50000;
+
+  color_segments=CGAL::Color(40,40,220);
+  color_disks=CGAL::Color(220,40,40);
+  color_criticals=CGAL::Color(90,190,110),
+  color_borders=CGAL::Color(150,150,150);
+
+  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==std::string("-t1"))
+    {
+      t1=true;
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no filename after -t1 option."); }
+      filename=std::string(argv[++i]);
+    }
+    else if (arg==std::string("-t2"))
+    {
+      t2=true;
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no filename after -t2 option."); }
+      filename=std::string(argv[++i]);
+    }
+    else if (arg==std::string("-t3"))
+    {
+      t3=true;
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no filename after -t3 option."); }
+      filename=std::string(argv[++i]);
+      if (filename.find("%")==std::string::npos)
+      { error_command_line(argc, argv, "Error: filename after -t3 option does not contain % character."); }
+    }
+    else if (arg==std::string("-cgal"))
+    { cgal=true; }
+    else if (arg==std::string("-lcc"))
+    { lcc=true; }
+    else if (arg==std::string("-traverse"))
+    { traverse=true; }
+    else if (arg==std::string("-nbs"))
+    {
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no number after -nbs option."); }
+      nbstrips=std::stoi(std::string(argv[++i]));
+    }
+    else if (arg==std::string("-nbt"))
+    {
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no number after -nbt option."); }
+      nbthreads=std::stoi(std::string(argv[++i]));
+    }
+    else if (arg==std::string("-crop"))
+    { crop=true; }
+    else if (arg==std::string("-optimized-strips"))
+    { optimized_strips=true; }
+    else if (arg==std::string("-xpos"))
+    {
+      if (nbstrips<=1)
+      { error_command_line(argc, argv, "Error: -xpos option can only be used after-nbs option, and with a number of strips >1."); }
+      if (argc-1-i<nbstrips-1)
+      { error_command_line(argc, argv, "Error: we need (numberofstrips-1) numbers -xpos option."); }
+
+      xpos_cuts.resize(nbstrips-1);
+      for (std::size_t j=0; j<nbstrips-1; ++j)
+      { xpos_cuts[j]=std::stod(std::string(argv[++i])); }
+    }
+    else if (arg==std::string("-export-cgal"))
+    { export_cgal=true; }
+    else if (arg==std::string("-draw"))
+    { draw=true; }
+    else if (arg==std::string("-save"))
+    { save=true; }
+    else if (arg==std::string("-export-xfig"))
+    {
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no number after -export-xfig option."); }
+      xfig_file=std::string(argv[i+1]);
+    }
+    else if (arg==std::string("-export-xfig-sequence"))
+    { export_xfig_sequence=true; }
+    else if (arg==std::string("-xfig-invert-y"))
+    { xfig_invert_y=true; }
+    else if (arg==std::string("-xfig-x-size"))
+    {
+      if (argc-1-i<1)
+      { error_command_line(argc, argv, "Error: no number after -xfig-x-size option."); }
+      xfig_x_size=std::stod(std::string(argv[++i]));
+    }
+    else if (arg==std::string("-xfig-width"))
+    {
+      if (argc-1-i<5)
+      { error_command_line(argc, argv, "Error: we need 5 numbers after -xfig-width option."); }
+      width_segments=std::stoi(std::string(argv[++i]));
+      radius_disks=std::stod(std::string(argv[++i]));
+      width_criticals=std::stoi(std::string(argv[++i]));
+      width_borders=std::stoi(std::string(argv[++i]));
+      space_between_strips=std::stoi(std::string(argv[++i]));
+    }
+    else if (arg==std::string("-xfig-color"))
+    {
+      if (argc-1-i<12)
+      { error_command_line(argc, argv, "Error: we need 12 numbers after -xfig-color option."); }
+      color_segments=CGAL::Color(std::stoi(std::string(argv[++i])),
+          std::stoi(std::string(argv[++i])),
+          std::stoi(std::string(argv[++i])));
+      color_disks=CGAL::Color(std::stoi(std::string(argv[++i])),
+          std::stoi(std::string(argv[++i])),
+          std::stoi(std::string(argv[++i])));
+      color_criticals=CGAL::Color(std::stoi(std::string(argv[++i])),
+          std::stoi(std::string(argv[++i])),
+          std::stoi(std::string(argv[++i])));
+      color_borders=CGAL::Color(std::stoi(std::string(argv[++i])),
+          std::stoi(std::string(argv[++i])),
+          std::stoi(std::string(argv[++i])));
+    }
+    else if (arg[0]=='-')
+    {
+      std::cout<<"Unknown option "<<arg<<std::endl;
+      helprequired=true;
+    }
+  }
+
+  if (nbthreads==0) { nbthreads=1; }
+  if (!t1 && !t2 && !t3) { std::cout<<"ERROR: missing file name (either with -t1 or -t2 or -t3)."<<std::endl; }
+  if (cgal && (t2 || t3))  { std::cout<<"ERROR: -t2 and -t3 option cannot be used with -cgal."<<std::endl; }
+  if (helprequired || (!t1 && !t2 && !t3)) { usage(argc, argv); }
+}
+///////////////////////////////////////////////////////////////////////////////
+void run_cgal_method(const std::string& filename)
+{
+  typedef CGAL::Arr_segment_traits_2<EPECK> Traits_2;
+  typedef CGAL::Arrangement_2<Traits_2>  Arrangement_2;
+
+  My_timer timer;
+  timer.start();
+  Arrangement_2 arr;
+
+  My_timer load_timer;
+  load_timer.start();
+
+  std::vector<ESegment> all_segments;
+  all_segments.reserve(number_of_lines(filename));
+  Read_from_file<EPECK> reader(filename);
+  fill_segment_array<EPECK>(reader, all_segments);
+
+  load_timer.stop();
+
+  CGAL::insert(arr, all_segments.begin(), all_segments.end());
+  timer.stop();
+
+  print_txt_with_endl("Nb input segments: ", all_segments.size());
+  print_txt_with_endl("#halfedges=", arr.number_of_halfedges(), ", #0-cells=",
+                      arr.number_of_vertices(), ", #1-cells=",
+                      arr.number_of_edges(), ", #2-cells=",
+                      arr.number_of_faces(), ", #finite-2-cells=",
+                      arr.number_of_faces()-arr.number_of_unbounded_faces());
+
+  std::cout<<"CURRENT RSS: "<<getCurrentRSS()<<" bytes (i.e. "<<
+    double(getCurrentRSS())/double(1024*1024)<<" mega-bytes and "<<
+    double(getCurrentRSS())/double(1024*1024*1024)<<" giga-bytes)"<<std::endl;
+
+  print_txt_with_endl("[TIME]: to load segments ", load_timer.time());
+  print_txt_with_endl("[GLOBAL]: time to build cgal arrangement ", timer.time());
+}
+///////////////////////////////////////////////////////////////////////////////
+int main(int argc, char** argv)
+{
+  std::string filename;
+  bool t1;
+  bool t2;
+  bool t3;
+  bool cgal;
+  bool lcc;
+  bool traverse;
+  std::size_t nbstrips;
+  std::size_t nbthreads;
+  bool crop;
+  bool optimized_strips;
+  std::vector<double> xpos_cuts;
+  bool export_cgal;
+  bool draw;
+  bool save;
+  std::string xfig_file;
+  bool export_xfig_sequence;
+  bool xfig_invert_y;
+  double xfig_x_size;
+  uint16_t width_segments;
+  uint16_t radius_disks;
+  uint16_t width_criticals;
+  uint16_t width_borders;
+  uint16_t space_between_strips;
+  CGAL::Color color_segments; //(svg::Color::Transparent);
+  CGAL::Color color_disks;
+  CGAL::Color color_criticals;
+  CGAL::Color color_borders;
+
+  std::vector<double> times;
+  process_command_line(argc, argv, filename, t1, t2, t3, cgal, lcc, traverse,
+                       nbstrips, nbthreads, crop, optimized_strips,
+                       xpos_cuts, export_cgal, draw,
+                       save, xfig_file, export_xfig_sequence, xfig_invert_y,
+                       xfig_x_size,  width_segments, radius_disks,
+                       width_criticals, width_borders, space_between_strips,
+                       color_segments, color_disks, color_criticals,
+                       color_borders);
+
+  if (cgal)
+  {
+    run_cgal_method(filename);
+    exit(EXIT_SUCCESS);
+  }
+
+  SHds *shds=nullptr;
+  if (t1)
+  {
+    shds=new SHds(filename, nbstrips, nbthreads,
+                optimized_strips, times, crop,
+                (xpos_cuts.size()>0?&xpos_cuts:nullptr));
+  }
+  else if (t2)
+  {
+    My_timer timer; timer.start();
+    shds=new SHds;
+    std::ifstream inputfile(filename);
+    if (inputfile)
+    { inputfile>>*shds; }
+    inputfile.close();
+    timer.stop();
+    times.push_back(timer.time());
+
+    timer.reset(); timer.start();
+    shds->build_faces_array(); // For now faces are not saved, thus recomputed here
+    timer.stop();
+    times.push_back(timer.time());
+  }
+  else if (t3)
+  {
+    My_timer timer; timer.start();
+    shds=new SHds;
+    shds->load_streamed_files(filename);
+    timer.stop();
+    times.push_back(timer.time());
+
+    timer.reset(); timer.start();
+    shds->build_faces_array(); // For now faces are not saved, thus recomputed here
+    timer.stop();
+    times.push_back(timer.time());
+   }
+
+  shds->display_info();
+
+  // times[0] : global time
+  // times[1] : load and dispatch
+  // times[2] : compute all partial HDS
+  // times[3] : compute faces
+
+  if (t1)
+  {
+    print_txt_with_endl("[TIME]: to load and dispatch segments ", times[1]);
+    print_txt_with_endl("[TIME]: to compute all partial HDS ", times[2]);
+    print_txt_with_endl("[TIME]: to compute faces ", times[3]);
+    print_txt_with_endl("[GLOBAL]: time to compute the sHDS ",
+                        times[0]);
+
+    if (save)
+    {
+      std::ofstream outputfile(filename+"output");
+      if (outputfile)
+      { outputfile<<*shds; }
+      outputfile.close();
+    }
+  }
+  else
+  {
+    print_txt_with_endl("[TIME]: to load the sHDS ", times[0]);
+    print_txt_with_endl("[TIME]: to compute faces ", times[1]);
+  }
+
+  if (traverse)
+  {
+    My_timer local_timer;
+    local_timer.start();
+    std::size_t nb=0;
+    for (int i=0; i<10; ++i)
+    { nb+=shds->traverse_all_faces(); }
+    local_timer.stop();
+    print_txt_with_endl("[TIME]: to traverse the sHDS 10 times ", local_timer.time(),
+                        " (",nb/10," halfedges)");
+  }
+
+  if (xfig_file!="")
+  {
+    if (!export_xfig_sequence)
+    {
+      shds->export_to_xfig(xfig_file, !xfig_invert_y, xfig_x_size, 0,
+                         color_segments, color_disks, color_criticals, color_borders,
+                         width_segments, radius_disks, width_criticals,
+                         width_borders, space_between_strips);
+    }
+    else
+    {
+      for (std::size_t i=0; i<shds->number_of_strips(); ++i)
+      {
+        boost::filesystem::path p1=xfig_file;
+        boost::filesystem::path p2=std::to_string(i)+std::string(".fig");
+        boost::filesystem::path p=p1.replace_extension(p2);
+
+        shds->export_to_xfig(p.string(), !xfig_invert_y, xfig_x_size, i+1,
+                           color_segments, color_disks, color_criticals, color_borders,
+                           width_segments, radius_disks, width_criticals,
+                           width_borders, space_between_strips);
+      }
+    }
+  }
+
+  if (lcc)
+  {
+    My_timer lcc_timer;
+    lcc_timer.start();
+    LCC_2 lcc;
+    std::size_t nb_finite_faces=shds_to_lcc(*shds, lcc);
+    lcc_timer.stop();
+
+    lcc.display_characteristics(std::cout)<<", #finite-2-cells="<<nb_finite_faces
+                                         <<(lcc.is_valid()?", valid.":", NOT VALID.")<<std::endl;
+    print_txt_with_endl("[TIME]: to compute a LCC from the sHDS ", lcc_timer.time());
+  }
+
+  if (export_cgal)
+  {
+    typedef CGAL::Arr_segment_traits_2<EPECK> Traits_2;
+    typedef CGAL::Arrangement_2<Traits_2>  Arrangement_2;
+    My_timer arr_timer;
+    arr_timer.start();
+    Arrangement_2 arr;
+    shds_to_cgal_arrangement(*shds, arr);
+    arr_timer.stop();
+    print_txt_with_endl("[TIME]: to export the sHDS into cgal arrangement ", arr_timer.time());
+    print_txt_with_endl("[GLOBAL]: time to build cgal arrangement from the sHDS ",
+                        times[0]+arr_timer.time());
+  }
+
+  if (draw)
+  { draw_shds(*shds, "Viewer", false); }
+
+  delete shds;
+  return EXIT_SUCCESS;
+}
+///////////////////////////////////////////////////////////////////////////////