const std::vector<boost::shared_ptr<ribi::trim::Cell>> ribi::trim::CellFactory::CreateTestCube() const noexcept
{
    const boost::shared_ptr<Template> my_template {
        Template::CreateTest(1)
    };
    assert(my_template->CountFaces() == 2);
    const int n_layers = 2;
    const boost::shared_ptr<CellsCreator> cells_creator {
        CellsCreatorFactory().Create(my_template,n_layers,1.0 * boost::units::si::meter)
    };
    const std::vector<boost::shared_ptr<Cell>> cells { cells_creator->GetCells() };

    assert(cells.size() == 2 && "A cube consists out of two prisms");
    assert(cells[0]->GetFaces().size() == 8 && "A prism consists out of 8 faces");
    assert(cells[1]->GetFaces().size() == 8 && "A prism consists out of 8 faces");
#ifndef NDEBUG
    for (int i=0; i!=2; ++i)
    {
        const std::vector<boost::shared_ptr<Face>> faces { cells[i]->GetFaces() };
        for (const auto face: faces)
        {
            assert(face);
            assert(face->GetPoints().size() == 3);
        }
    }
#endif

    return cells;
}
std::vector<boost::shared_ptr<ribi::trim::Cell>> ribi::trim::CellFactory::CreateTestCube(
  const CreateVerticalFacesStrategy strategy
) const noexcept
{
  const boost::shared_ptr<Template> my_template {
    Template::CreateTest(1)
  };
  assert(my_template);
  assert(my_template->CountFaces() == 2);
  const int n_cell_layers = 1;
  const bool verbose{false};
  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 && "A cube consists out of two prisms");
  #ifndef NDEBUG
  for (int i=0; i!=2; ++i)
  {
    const std::vector<boost::shared_ptr<Face>> faces { cells[i]->GetFaces() };
    for (const auto& face: faces)
    {
      assert(face);
      assert(face->GetPoints().size() == 3 || face->GetPoints().size() == 4);
    }
  }
  #endif

  return cells;
}
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));
  }
}