void ribi::trim::CellFactory::Test() noexcept
{
    {
        static bool is_tested = false;
        if (is_tested) return;
        is_tested = true;
    }
    TRACE("Starting ribi::trim::CellFactory::Test");
    //Create prism
    {
        const boost::shared_ptr<Cell> prism {
            CellFactory().CreateTestPrism()
        };
        assert(prism->GetFaces().size() == 8 && "A prism has 8 faces (as the vertical faces are split into 2 triangle)");
    }
    //Create cube
    {
        const std::vector<boost::shared_ptr<Cell>> cube {
            CellFactory().CreateTestCube()
        };
        assert(cube.size() == 2 && "A cube consists of two prisms");
        assert(cube[0]->GetFaces().size() == 8 && "A prism has 8 faces (as the vertical faces are split into 2 triangle)");
        assert(cube[1]->GetFaces().size() == 8 && "A prism has 8 faces (as the vertical faces are split into 2 triangle)");

    }
    TRACE("Finished ribi::trim::CellFactory::Test successfully");
}
const boost::shared_ptr<ribi::trim::Cell> ribi::trim::CellFactory::CreateTestPrism() const noexcept
{
    const std::vector<boost::shared_ptr<Face> > faces {
        FaceFactory().CreateTestPrism()
    };
    const boost::shared_ptr<Cell> prism {
        CellFactory().Create(faces)
    };
    assert(prism);
    return prism;
}
void ribi::trim::CellsCreator::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  CellFactory();
  FaceFactory();

  const TestTimer test_timer(__func__,__FILE__,1.0);
  const bool verbose{false};

  /*
  if (testing_depth > 1)
  {
    if (verbose) { TRACE("Trying out to build cells from the hardest testing templates"); }
    {
      //This is the longest test by far
      //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,1.0);
      for (CreateVerticalFacesStrategy strategy: CreateVerticalFacesStrategies().GetAll())
      {
        const boost::shared_ptr<Template> my_template {
          Template::CreateTest(3)
        };

        const int n_cell_layers = 2;
        const boost::shared_ptr<CellsCreator> cells_creator {
          CellsCreatorFactory().Create(
            my_template,
            n_cell_layers,
            1.0 * boost::units::si::meter,
            strategy,
            verbose
          )
        };
        const std::vector<boost::shared_ptr<Cell>> cells { cells_creator->GetCells() };
        assert(cells.size() > 0);
      }
    }
  }
  */
  if (verbose) { TRACE("Specific: check if a Face really loses its neighbour: remove a prism from a cube"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,1.0);
    for (CreateVerticalFacesStrategy strategy: CreateVerticalFacesStrategies().GetAll())
    {
      //Create a 2x1 cell block
      const boost::shared_ptr<Template> my_template {
        Template::CreateTest(1)
      };
      assert(my_template->CountFaces() == 2);
      const int n_cell_layers = 1;
      const boost::shared_ptr<CellsCreator> cells_creator {
        CellsCreatorFactory().Create(
          my_template,
          n_cell_layers,
          1.0 * boost::units::si::meter,
          strategy,
          verbose
        )
      };
      const std::vector<boost::shared_ptr<Cell>> cells { cells_creator->GetCells() };
      assert(cells.size() == 2);
      const std::vector<boost::shared_ptr<Face>> faces_1 { cells[0]->GetFaces() };
      const std::vector<boost::shared_ptr<Face>> faces_2 { cells[1]->GetFaces() };
      //Find the one/two Faces that have a neighbour
      {
        const int n_faces_with_neighbour {
          static_cast<int>(
            std::count_if(faces_1.begin(),faces_1.end(),
              [](const boost::shared_ptr<Face> face)
              {
                return face->GetNeighbour().get();
              }
            )
          )
        };
        assert(
             (strategy == CreateVerticalFacesStrategy::one_face_per_square
               && n_faces_with_neighbour == 1)
          || (strategy == CreateVerticalFacesStrategy::two_faces_per_square
               && n_faces_with_neighbour == 2)
        );
      }
      {
        const int n_faces_with_neighbour {
          static_cast<int>(
            std::count_if(faces_2.begin(),faces_2.end(),
              [](const boost::shared_ptr<Face> face)
              {
                return face->GetNeighbour().get();
              }
            )
          )
        };
        assert(
             (strategy == CreateVerticalFacesStrategy::one_face_per_square
               && n_faces_with_neighbour == 1)
          || (strategy == CreateVerticalFacesStrategy::two_faces_per_square
               && n_faces_with_neighbour == 2)
        );
      }
      if (verbose) { TRACE("Creating internal faces 1"); }

      Helper::FaceSet internal_faces_1 = Helper().CreateEmptyFaceSet();
      if (verbose) { TRACE("Creating internal faces 1, std::copy_if"); }
      std::copy_if(
        faces_1.begin(),faces_1.end(),
        std::inserter(internal_faces_1,internal_faces_1.begin()),
        [](const boost::shared_ptr<Face> face)
        {
          assert(face);
          const bool do_copy = face->GetNeighbour().get();
          return do_copy;
        }
      );

      if (verbose) { TRACE("Creating internal faces 2"); }
      Helper::FaceSet internal_faces_2 = Helper().CreateEmptyFaceSet();
      std::copy_if(faces_2.begin(),faces_2.end(),std::inserter(internal_faces_2,internal_faces_2.begin()),
        [](const boost::shared_ptr<Face> face)
        {
          return face->GetNeighbour().get();
        }
      );
      if (verbose) { TRACE("Creating internal faces 1"); }
      assert(
        std::equal(
          internal_faces_1.begin(),internal_faces_1.end(),
          internal_faces_2.begin(),
          [](boost::shared_ptr<Face> lhs, boost::shared_ptr<Face> rhs) { return *lhs == *rhs; }
        )
      );
    }
  }
  if (verbose) { TRACE("Create Face, from bug"); }
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,1.0);
    /*
    (1.17557,2.35781,5.0)
    (2.35114,3.23607,5.0)
    (1.17557,2.35781,6.0)
    (2.35114,3.23607,6.0)
    */
    //Ordering cannot be known for sure to be convex from these indices
    typedef boost::geometry::model::d2::point_xy<double> Coordinat2D;
    std::vector<boost::shared_ptr<Point>> face_points {
      PointFactory().Create(boost::make_shared<Coordinat2D>(1.17557,2.35781)),
      PointFactory().Create(boost::make_shared<Coordinat2D>(2.35114,3.23607)),
      PointFactory().Create(boost::make_shared<Coordinat2D>(1.17557,2.35781)),
      PointFactory().Create(boost::make_shared<Coordinat2D>(2.35114,3.23607))
    };
    face_points[0]->SetZ(5.0 * boost::units::si::meter);
    face_points[1]->SetZ(5.0 * boost::units::si::meter);
    face_points[2]->SetZ(6.0 * boost::units::si::meter);
    face_points[3]->SetZ(6.0 * boost::units::si::meter);

    //Order face_points
    if (!Helper().IsConvex(face_points)) { Helper().MakeConvex(face_points); }

    #ifndef NDEBUG
    if (!Helper().IsConvex(face_points))
    {
      TRACE("ERROR");
      for (const auto& p: face_points) { TRACE(*p); }
      TRACE("BREAK");
    }
    #endif

    assert(Helper().IsConvex(face_points));

    //Cannot order face winding yet, need Cells for this
    const boost::shared_ptr<Face> face {
      FaceFactory().Create(
        face_points,
        FaceOrientation::vertical,
        verbose
      )
    };
  }

  //From bug
  {
    //const TestTimer test_timer(boost::lexical_cast<std::string>(__LINE__),__FILE__,1.0);
    typedef boost::geometry::model::d2::point_xy<double> Coordinat2D;
    const double x1 = 0.0004035051226622692510832834944523028752882964909076690673828125;
    const double y1 = 0.00023296416881187433805568132161312178141088224947452545166015625;
    const double z1 = 0; //left out the '.0' intentionally

    const double x2 = 0.000403505141811931846741734464245610070065595209598541259765625;
    const double y2 = 0.00023296414405748076185791173298156309101614169776439666748046875;
    const double z2 = 0; //left out the '.0' intentionally

    const double x3 = 0.0004035051226622692510832834944523028752882964909076690673828125;
    const double y3 = 0.00023296416881187433805568132161312178141088224947452545166015625;
    const double z3 = 0.00025000000000000000520417042793042128323577344417572021484375;

    const double x4 = 0.000403505141811931846741734464245610070065595209598541259765625;
    const double y4 = 0.00023296414405748076185791173298156309101614169776439666748046875;
    const double z4 = 0.00025000000000000000520417042793042128323577344417572021484375;
    const auto c1 = boost::make_shared<Coordinat2D>(x1,y1);
    const auto c2 = boost::make_shared<Coordinat2D>(x2,y2);
    const auto c3 = boost::make_shared<Coordinat2D>(x3,y3);
    const auto c4 = boost::make_shared<Coordinat2D>(x4,y4);
    const auto p1 = PointFactory().Create(c1);
    const auto p2 = PointFactory().Create(c2);
    const auto p3 = PointFactory().Create(c3);
    const auto p4 = PointFactory().Create(c4);
    p1->SetZ(z1 * boost::units::si::meter);
    p2->SetZ(z2 * boost::units::si::meter);
    p3->SetZ(z3 * boost::units::si::meter);
    p4->SetZ(z4 * boost::units::si::meter);
    std::vector<boost::shared_ptr<Point>> face_points;
    face_points.push_back(p1);
    face_points.push_back(p2);
    face_points.push_back(p3);
    face_points.push_back(p4);
    assert(IsPlane(face_points));
  }
}
std::vector<boost::shared_ptr<ribi::trim::Cell>> ribi::trim::CellsCreator::CreateCells(
  const boost::shared_ptr<const Template> t,
  const int n_face_layers,
  const boost::units::quantity<boost::units::si::length> layer_height,
  const CreateVerticalFacesStrategy strategy,
  const bool verbose
) noexcept
{
  assert(t);

  if (n_face_layers < 2
    || t->GetPoints().empty()
  )
  {
    std::vector<boost::shared_ptr<ribi::trim::Cell>> no_cells; return no_cells;
  }
  assert(n_face_layers >= 2);

  if (verbose)
  {
    std::clog << __FILE__ << "(" <<  (__LINE__) <<  ") : "
      << "Create points" << std::endl
    ;
  }
  const std::vector<boost::shared_ptr<Point>> all_points
    = CreatePoints(t,n_face_layers,layer_height);

  if (verbose)
  {
    std::clog << __FILE__ << "(" <<  (__LINE__) <<  ") : "
      << "Create horizontal faces" << std::endl
    ;
  }
  const std::vector<boost::shared_ptr<Face>> hor_faces
    = CreateHorizontalFaces(t,all_points,n_face_layers);

  if (verbose)
  {
    std::clog << __FILE__ << "(" <<  (__LINE__) <<  ") : "
      << "Create vertical faces" << std::endl
    ;
  }

  const std::vector<boost::shared_ptr<Face>> ver_faces
    = CreateVerticalFaces(t,all_points,n_face_layers,layer_height,strategy,verbose);

  if (verbose)
  {
    std::clog << __FILE__ << "(" <<  (__LINE__) <<  ") : "
      << "Created " << ver_faces.size() << " vertical faces" << std::endl
    ;
  }

  if (ver_faces.empty())
  {
    std::vector<boost::shared_ptr<ribi::trim::Cell>> no_cells;
    return no_cells;
  }

  #ifndef NDEBUG
  for(const auto f:ver_faces) { assert(f); }
  #endif

  const int n_hor_faces_per_layer = static_cast<int>(t->GetFaces().size());
  const int n_cells_per_layer = n_hor_faces_per_layer;

  if (verbose)
  {
    std::clog << __FILE__ << "(" <<  (__LINE__) <<  ") : "
      << "Creating cells" << std::endl
    ;
  }
  std::vector<boost::shared_ptr<Cell>> cells;
  for (int layer=0; layer!=n_face_layers-1; ++layer) //-1 because there are no points above the top layer
  {
    if (verbose) { std::clog << "."; }
    for (int i=0; i!=n_cells_per_layer; ++i)
    {

      const int bottom_face_index = ((layer + 0) * n_hor_faces_per_layer) + i;
      const int top_face_index    = ((layer + 1) * n_hor_faces_per_layer) + i;
      assert(bottom_face_index >= 0);
      assert(top_face_index    >= 0);
      assert(bottom_face_index < static_cast<int>(hor_faces.size()));
      assert(top_face_index    < static_cast<int>(hor_faces.size()));
      const std::vector<boost::shared_ptr<Face>> these_ver_faces {
        FindKnownFacesBetween(
          hor_faces[bottom_face_index],
          hor_faces[top_face_index]
        )
      };

      if (strategy == CreateVerticalFacesStrategy::one_face_per_square )
      {
        #ifndef NDEBUG
        if (these_ver_faces.size() != 3)
        {
          TRACE("BREAK");
        }
        #endif
        assert(these_ver_faces.size() == 3);
        assert(hor_faces[bottom_face_index]);
        assert(hor_faces[top_face_index]);
        assert(these_ver_faces[0]);
        assert(these_ver_faces[1]);
        assert(these_ver_faces[2]);
        const boost::shared_ptr<Cell> cell(
          CellFactory().Create(
            {
              hor_faces[bottom_face_index],
              hor_faces[top_face_index],
              these_ver_faces[0],
              these_ver_faces[1],
              these_ver_faces[2]
            },
            strategy
          )
        );
        assert(hor_faces[bottom_face_index]);
        assert(hor_faces[top_face_index]);
        assert(Helper().IsHorizontal(*hor_faces[bottom_face_index]));
        assert(Helper().IsHorizontal(*hor_faces[top_face_index]));
        assert(Helper().IsVertical(*these_ver_faces[0]));
        assert(Helper().IsVertical(*these_ver_faces[1]));
        assert(Helper().IsVertical(*these_ver_faces[2]));

        cells.push_back(cell);
      }
      else
      {
        assert(these_ver_faces.size() == 6);
        const boost::shared_ptr<Cell> cell {
          CellFactory().Create(
            {
              hor_faces[bottom_face_index],
              hor_faces[top_face_index],
              these_ver_faces[0],
              these_ver_faces[1],
              these_ver_faces[2],
              these_ver_faces[3],
              these_ver_faces[4],
              these_ver_faces[5]
            },
            strategy
          )
        };
        assert(hor_faces[bottom_face_index]);
        assert(hor_faces[top_face_index]);
        assert(Helper().IsHorizontal(*hor_faces[bottom_face_index]));
        assert(Helper().IsHorizontal(*hor_faces[top_face_index]));
        assert(Helper().IsVertical(*these_ver_faces[0]));
        assert(Helper().IsVertical(*these_ver_faces[1]));
        assert(Helper().IsVertical(*these_ver_faces[2]));
        assert(Helper().IsVertical(*these_ver_faces[3]));
        assert(Helper().IsVertical(*these_ver_faces[4]));
        assert(Helper().IsVertical(*these_ver_faces[5]));

        cells.push_back(cell);
      }
    }
  }
  #ifndef NDEBUG
  if (verbose)
  {
    std::clog << __FILE__ << "(" <<  (__LINE__) <<  ") : "
      << "Checking cells" << std::endl
    ;
  }
  CheckCells(cells);
  #endif // NDEBUG
  if (verbose)
  {
    std::clog << __FILE__ << "(" <<  (__LINE__) <<  ") : "
      << "Done creating cells" << std::endl
    ;
  }
  return cells;
}