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; }
boost::shared_ptr<ribi::trim::Template> ribi::trim::Template::CreateTest3x3() noexcept { std::vector<boost::shared_ptr<Face>> faces; std::vector<std::vector<int>> face_point_indices; std::vector<boost::shared_ptr<Point>> points; const int width{3}; const int height{3}; const int n_points{width * height}; const bool verbose{false}; points.reserve(n_points); //Create points { for(int i=0; i!=n_points; ++i) { const double x{static_cast<double>(i % width)}; const double y{static_cast<double>(i / width)}; const std::string boundary_type = "three_times_three"; const boost::shared_ptr<const ConstCoordinat2D> bottom{ new ConstCoordinat2D(x,y) }; const auto point = PointFactory().Create(bottom); points.push_back(point); } } #ifndef NDEBUG //Check that there is no coordinat present twice { for (int i=0; i!=n_points; ++i) { const boost::shared_ptr<const ConstCoordinat2D> a { points[i]->GetCoordinat() }; for (int j=0; j!=n_points; ++j) { const boost::shared_ptr<const ConstCoordinat2D> b { points[j]->GetCoordinat() }; if (a == b) { assert(boost::geometry::distance(*a,*b) < 0.001); } else { assert(boost::geometry::distance(*a,*b) > 0.001); } } } } #endif //Load and translate faces face_point_indices = { { 0,1,3 }, { 1,2,4 }, { 1,3,4 }, { 2,4,5 }, { 3,4,6 }, { 4,5,7 }, { 4,6,7 }, { 5,7,8 } }; const std::vector<std::pair<int,int>> edges { { 0,1 }, { 0,3 }, { 1,2 }, { 1,3 }, { 1,4 }, { 2,4 }, { 2,5 }, { 3,4 }, { 3,6 }, { 4,5 }, { 4,6 }, { 4,7 }, { 5,7 }, { 5,8 }, { 6,7 }, { 7,8 } }; { for(const auto v: face_point_indices) { assert(v.size() == 3); //I do not correct for one-base Triangle.exe output const int point1 = v[0]; const int point2 = v[1]; const int point3 = v[2]; assert(point1 >= 0); assert(point2 >= 0); assert(point3 >= 0); const std::vector<int> face_point_indices { point1, point2, point3 }; std::vector<boost::shared_ptr<Point>> face_points { points[point1], points[point2], points[point3] }; if (!Helper().IsClockwiseHorizontal(face_points)) { std::reverse(face_points.begin(),face_points.end()); } assert(Helper().IsClockwiseHorizontal(face_points)); const boost::shared_ptr<Face> face { FaceFactory().Create( face_points, FaceOrientation::horizontal, verbose ) }; faces.push_back(face); } } #ifndef NDEBUG const int n_faces = static_cast<int>(faces.size()); assert(faces.size() == face_point_indices.size()); for (int i=0; i!=n_faces; ++i) { const auto face = faces[i]; const auto indices = face_point_indices[i]; assert(face->GetPoints().size() == indices.size()); /* const int n_points = static_cast<int>(indices.size()); for (int j=0; j!=n_points; ++j) { //Only true when points are not reversed assert(face->GetPoints()[j] == points[ indices[j] ]); } */ } #endif assert(faces.size() == 8 && "2x2 adjacent squares consist of 8 triangles"); assert(edges.size() == 16 && "2x2 adjacent squares (with diagonals) have 16 edges"); assert(points.size() == 9 && "2x2 adjacent squares have 9 nodes"); const boost::shared_ptr<Template> my_template { new Template( edges, faces, face_point_indices, points ) }; assert(my_template); return my_template; }
void ribi::trim::Template::Test() noexcept { { static bool is_tested{false}; if (is_tested) return; is_tested = true; } PointFactory(); FaceFactory(); const TestTimer test_timer(__func__,__FILE__,1.0); const bool verbose{false}; if (verbose) { TRACE("IsClockWise, confirmation"); } { /* Cartesian plane | | A = (0,1) /|\ / | \ ---+--+--+---- / | \ C----+----B | | */ //12 o'clock const boost::shared_ptr<const ConstCoordinat2D> a { new ConstCoordinat2D(0.0,1.0) }; //4 o'clock const boost::shared_ptr<const ConstCoordinat2D> b { new ConstCoordinat2D(0.83,-0.5) }; //8 o'clock const boost::shared_ptr<const ConstCoordinat2D> c { new ConstCoordinat2D(-0.83,-0.5) }; std::vector<boost::shared_ptr<Point>> points { PointFactory().Create(a), PointFactory().Create(b), PointFactory().Create(c) }; points[0]->SetZ(1.0 * boost::units::si::meter); points[1]->SetZ(1.0 * boost::units::si::meter); points[2]->SetZ(1.0 * boost::units::si::meter); assert( Helper().IsClockwiseHorizontal(points)); std::reverse(points.begin(),points.end()); assert(!Helper().IsClockwiseHorizontal(points)); } if (verbose) { TRACE("IsClockWise, rejection"); } { /* Cartesian plane | | A = (0,1) /|\ / | \ ---+--+--+---- / | \ B----+----C | | */ //12 o'clock const boost::shared_ptr<const ConstCoordinat2D> a { new ConstCoordinat2D(0.0,1.0) }; //8 o'clock const boost::shared_ptr<const ConstCoordinat2D> b { new ConstCoordinat2D(-0.83,-0.5) }; //4 o'clock const boost::shared_ptr<const ConstCoordinat2D> c { new ConstCoordinat2D(0.83,-0.5) }; std::vector<boost::shared_ptr<Point>> points { PointFactory().Create(a), PointFactory().Create(b), PointFactory().Create(c) }; points[0]->SetZ(1.0 * boost::units::si::meter); points[1]->SetZ(1.0 * boost::units::si::meter); points[2]->SetZ(1.0 * boost::units::si::meter); assert(!Helper().IsClockwiseHorizontal(points)); std::reverse(points.begin(),points.end()); assert(Helper().IsClockwiseHorizontal(points)); } for (int i=0; i!=4; ++i) { const boost::shared_ptr<Template> my_template { CreateTest(i) }; assert(my_template); for (const auto& face: my_template->GetFaces()) { if (!Helper().IsClockwiseHorizontal(face->GetPoints())) { TRACE("BREAK"); } assert(Helper().IsClockwiseHorizontal(face->GetPoints())); } } }
boost::shared_ptr<ribi::trim::Template> ribi::trim::Template::CreateTestTriangle2x2() noexcept { std::vector<boost::shared_ptr<Face>> faces; std::vector<std::vector<int>> face_point_indices; std::vector<boost::shared_ptr<Point>> points; const int width{2}; //const int height = 2; const int n_points{3}; //Triangle const bool verbose{false}; points.reserve(n_points); //Create points { for(int i=0; i!=n_points; ++i) { const double x = static_cast<double>(i % width); const double y = static_cast<double>(i / width); const std::string boundary_type{"two_times_two"}; const boost::shared_ptr<const ConstCoordinat2D> bottom { new ConstCoordinat2D(x,y) }; const boost::shared_ptr<Point> point { PointFactory().Create(bottom) }; points.push_back(point); } } #ifndef NDEBUG //Check that there is no coordinat present twice { for (int i=0; i!=n_points; ++i) { const boost::shared_ptr<const ConstCoordinat2D> a { points[i]->GetCoordinat() }; for (int j=0; j!=n_points; ++j) { const boost::shared_ptr<const ConstCoordinat2D> b { points[j]->GetCoordinat() }; if (a == b) { assert(boost::geometry::distance(*a,*b) < 0.001); } else { assert(boost::geometry::distance(*a,*b) > 0.001); } } } } #endif //Load and translate faces face_point_indices = { { 0,1,2 } }; const std::vector<std::pair<int,int>> edges { { 0,1 }, { 0,2 }, { 1,2 } }; { for(const auto v: face_point_indices) { assert(v.size() == 3); //I do not correct for one-base Triangle.exe output assert(v[0] >= 0); assert(v[1] >= 0); assert(v[2] >= 0); std::vector<boost::shared_ptr<Point>> face_points { points[ v[0] ], points[ v[1] ], points[ v[2] ] }; if (!Helper().IsClockwiseHorizontal(face_points)) { std::reverse(face_points.begin(),face_points.end()); } #ifndef NDEBUG if (!Helper().IsClockwiseHorizontal(face_points)) { TRACE("ERROR"); TRACE(*face_points[0]); TRACE(*face_points[1]); TRACE(*face_points[2]); TRACE("BREAK"); } #endif assert(Helper().IsClockwiseHorizontal(face_points)); const boost::shared_ptr<Face> face { FaceFactory().Create( face_points, FaceOrientation::horizontal, verbose ) }; faces.push_back(face); } } #ifndef NDEBUG const int n_faces = static_cast<int>(faces.size()); assert(faces.size() == face_point_indices.size()); for (int i=0; i!=n_faces; ++i) { const auto face = faces[i]; const auto indices = face_point_indices[i]; assert(face->GetPoints().size() == indices.size()); } #endif assert(faces.size() == 1 && "A triangle is only 1 triangle"); assert(edges.size() == 3 && "A triangle has 3 edges"); assert(points.size() == 3 && "A triangle has 3 nodes"); const boost::shared_ptr<Template> my_template { new Template( edges, faces, face_point_indices, points ) }; assert(my_template); return my_template; }
ribi::trim::Template::Template( const std::string& filename_node, const std::string& filename_ele, const bool verbose ) : m_edges{}, m_faces{}, m_face_point_indices{}, m_points{} { #ifndef NDEBUG Test(); #endif if (verbose) { TRACE("Load the points and faces created by Triangle"); } { const std::vector<std::string> v { ribi::fileio::FileIo().FileToVector( filename_node ) }; const int sz = v.size(); const int percent = sz / 100 ? sz / 100: 1; for(int n=0; n!=sz; ++n) { if (verbose) { if (n % percent == 0) std::clog << '%'; } const std::string line = v[n]; if(n==0) continue; //No idea why this has to be skipped const std::vector<std::string> w { CleanAndSplitString(ConvertNumbersToEnglish(line)) }; if (w.empty() || w[0].empty() || w[0] == "#") { //The final comment line continue; } assert(w.size() == 4); assert(CanLexicalCast<int>(w[0])); assert(CanLexicalCast<double>(w[1])); #ifndef NDEBUG if (!CanLexicalCast<double>(w[2])) { TRACE("ERROR"); TRACE(line); TRACE(w[0]); TRACE(w[1]); TRACE(w[2]); TRACE(w[3]); TRACE("BREAK"); } #endif assert(CanLexicalCast<double>(w[2])); assert(CanLexicalCast<int>(w[3])); const double x = boost::lexical_cast<double>(w[1]); const double y = boost::lexical_cast<double>(w[2]); const boost::shared_ptr<const ConstCoordinat2D> bottom( new ConstCoordinat2D(x,y) ); const boost::shared_ptr<Point> node { PointFactory().Create(bottom) }; m_points.push_back(node); } } if (verbose) { TRACE("Load and translate faces"); } { const std::vector<std::string> v = ribi::fileio::FileIo().FileToVector(filename_ele); const int sz = v.size(); const int percent = sz / 100 ? sz / 100: 1; for(int n=0; n!=sz; ++n) { if (verbose) { if (n % percent == 0) { std::clog << '%'; } } const std::string line = v[n]; if(n==0) continue; const std::vector<std::string> w { CleanAndSplitString(line) }; if (w.empty() || w[0].empty() || w[0] == "#") { //The final comment line continue; } assert(w.size() == 4); assert(CanLexicalCast<int>(w[0])); assert(CanLexicalCast<int>(w[1])); assert(CanLexicalCast<int>(w[2])); assert(CanLexicalCast<int>(w[3])); //I hope that I made the Triangle.exe output start at index 0.. const int point1 = boost::lexical_cast<int>(w[1]); const int point2 = boost::lexical_cast<int>(w[2]); const int point3 = boost::lexical_cast<int>(w[3]); assert(point1 >= 0); //Start at index 0 assert(point2 >= 0); //Start at index 0 assert(point3 >= 0); //Start at index 0 assert(point1 - 0 < static_cast<int>(m_points.size())); assert(point2 - 0 < static_cast<int>(m_points.size())); assert(point3 - 0 < static_cast<int>(m_points.size())); const std::vector<int> face_point_indices { point1-0, //Start at index 0 point2-0, //Start at index 0 point3-0 //Start at index 0 }; m_edges.push_back(std::make_pair(face_point_indices[0],face_point_indices[1])); m_edges.push_back(std::make_pair(face_point_indices[0],face_point_indices[2])); m_edges.push_back(std::make_pair(face_point_indices[1],face_point_indices[2])); std::vector<boost::shared_ptr<Point>> face_points { m_points[point1-0], //Start at index 0 m_points[point2-0], //Start at index 0 m_points[point3-0] //Start at index 0 }; if (!Helper().IsClockwiseHorizontal(face_points)) { std::reverse(face_points.begin(),face_points.end()); } assert(Helper().IsClockwiseHorizontal(face_points)); if (!Helper().IsConvex(face_points)) { Helper().MakeConvex(face_points); } assert(Helper().IsConvex(face_points) && "FaceFactory only accepts convex ordered points"); const boost::shared_ptr<Face> face { FaceFactory().Create( face_points, FaceOrientation::horizontal, verbose ) }; m_faces.push_back(face); m_face_point_indices.push_back(face_point_indices); assert(std::unique(m_face_point_indices.begin(),m_face_point_indices.end()) == m_face_point_indices.end() && "Every face should have unique point indices"); } } #ifndef NDEBUG if (verbose) { TRACE("Checking the result"); } const int n_faces = static_cast<int>(m_faces.size()); assert(m_faces.size() == m_face_point_indices.size()); for (int i=0; i!=n_faces; ++i) { const auto face = m_faces[i]; const auto indices = m_face_point_indices[i]; assert(face->GetPoints().size() == indices.size()); } #endif for (auto& p: m_edges) { if (p.first > p.second) std::swap(p.first,p.second); assert(p.first < p.second); } std::sort(m_edges.begin(),m_edges.end()); auto new_end = std::unique(m_edges.begin(),m_edges.end()); m_edges.erase(new_end,m_edges.end()); if (verbose) { TRACE("Done checking the result"); } }
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::Face>> ribi::trim::CellsCreator::CreateVerticalFaces( const boost::shared_ptr<const Template> t, const std::vector<boost::shared_ptr<Point>>& all_points, const int n_face_layers, const boost::units::quantity<boost::units::si::length> layer_height, const CreateVerticalFacesStrategy strategy, const bool verbose ) noexcept { assert(t); assert(n_face_layers > 0); if (n_face_layers < 2) { if (verbose) { std::clog << __FILE__ << "(" << (__LINE__) << ") : " << "Too few layers to create vertical faces" << std::endl ; } std::vector<boost::shared_ptr<ribi::trim::Face>> no_faces; return no_faces; } #ifndef NDEBUG const FaceFactory face_factory; if (verbose) { std::clog << __FILE__ << "(" << (__LINE__) << ") : " << "Checking points" << std::endl ; } for (const auto& point: all_points) { assert(point); } if (verbose) { std::clog << __FILE__ << "(" << (__LINE__) << ") : " << "Get edges" << std::endl ; } #endif const std::vector<std::pair<int,int>> edges = t->GetEdges(); assert(!edges.empty()); const int n_edges = static_cast<int>(edges.size()); const int n_points_per_layer = static_cast<int>(t->GetPoints().size()); assert(n_points_per_layer > 0); const int n_ver_faces = strategy == CreateVerticalFacesStrategy::one_face_per_square ? 1 * n_edges : 2 * n_edges //For every horizontal edge, two triangles are used instead ; std::vector<boost::shared_ptr<Face>> v; #ifndef NDEBUG const int n_reserve = n_ver_faces * (n_face_layers - 1); #endif assert(n_reserve > 0); assert(n_reserve < static_cast<int>(v.max_size())); v.reserve(n_ver_faces * (n_face_layers - 1)); assert(n_face_layers > 0); if (n_face_layers == 1) { std::vector<boost::shared_ptr<ribi::trim::Face>> no_faces; return no_faces; } if (verbose) { std::clog << __FILE__ << "(" << (__LINE__) << ") : " << "Start building " << (n_face_layers-1) //Number of cell layers << " layers" << std::endl ; } for (int layer=0; layer!=n_face_layers-1; ++layer) //-1 because there are no points above the top layer { if (verbose) { std::clog << __FILE__ << "(" << (__LINE__) << ") : " << (layer+1) //Human-based << "/" << (n_face_layers-1) //Number of cell layers << std::endl ; } const int points_offset = n_points_per_layer * layer; assert(points_offset >= 0); const auto z_here = static_cast<double>(layer + 0) * layer_height; const auto z_above = static_cast<double>(layer + 1) * layer_height; for (const std::pair<int,int>& edge: edges) { assert(edge.first < edge.second); assert(points_offset + edge.first < static_cast<int>(all_points.size())); assert(points_offset + edge.second < static_cast<int>(all_points.size())); assert(points_offset + edge.first + n_points_per_layer < static_cast<int>(all_points.size())); assert(points_offset + edge.second + n_points_per_layer < static_cast<int>(all_points.size())); if (strategy == CreateVerticalFacesStrategy::one_face_per_square) { //Ordering cannot be known for sure to be convex from these indices assert(all_points[points_offset + edge.first]); assert(all_points[points_offset + edge.second]); assert(all_points[points_offset + edge.first + n_points_per_layer]); assert(all_points[points_offset + edge.second + n_points_per_layer]); std::vector<boost::shared_ptr<Point>> face_points; face_points.push_back(all_points[points_offset + edge.first]); face_points.push_back(all_points[points_offset + edge.second]); face_points.push_back(all_points[points_offset + edge.first + n_points_per_layer]); face_points.push_back(all_points[points_offset + edge.second + n_points_per_layer]); assert(face_points.size() == 4); assert(face_points[0]); assert(face_points[1]); assert(face_points[2]); assert(face_points[3]); assert(face_points[0] != face_points[1]); assert(face_points[0] != face_points[2]); assert(face_points[0] != face_points[3]); assert(face_points[1] != face_points[2]); assert(face_points[1] != face_points[3]); assert(face_points[2] != face_points[3]); face_points[0]->SetZ(z_here); face_points[1]->SetZ(z_here); face_points[2]->SetZ(z_above); face_points[3]->SetZ(z_above); #ifndef NDEBUG if(!IsPlane(face_points)) { TRACE("ERROR"); std::stringstream s; s << face_points.size() << '\n' << std::setprecision(99) ; for (const auto& point: face_points) { s << (*point) << " "; } TRACE(s.str()); TRACE("BREAK"); } #endif assert(IsPlane(face_points)); //Order face_points if (!Helper().IsConvex(face_points)) { Helper().MakeConvex(face_points); } 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 ) }; assert(face); v.push_back(face); } else { assert(all_points[points_offset + edge.first]); assert(all_points[points_offset + edge.second]); assert(all_points[points_offset + edge.first + n_points_per_layer]); const std::vector<boost::shared_ptr<Point>> face_points_1 { all_points[points_offset + edge.first], all_points[points_offset + edge.second], all_points[points_offset + edge.first + n_points_per_layer] }; assert(face_points_1[0] != face_points_1[1]); assert(face_points_1[0] != face_points_1[2]); assert(face_points_1[1] != face_points_1[2]); face_points_1[0]->SetZ(z_here); face_points_1[1]->SetZ(z_here); face_points_1[2]->SetZ(z_above); assert(Helper().IsConvex(face_points_1) && "FaceFactory expects convex ordered points"); //Cannot order face winding yet, need Cells for this const boost::shared_ptr<Face> face_1 { FaceFactory().Create( face_points_1, FaceOrientation::vertical, verbose ) }; assert(face_1); v.push_back(face_1); assert(all_points[points_offset + edge.second]); assert(all_points[points_offset + edge.second + n_points_per_layer]); assert(all_points[points_offset + edge.first + n_points_per_layer]); std::vector<boost::shared_ptr<Point>> face_points_2 { all_points[points_offset + edge.second], all_points[points_offset + edge.second + n_points_per_layer], all_points[points_offset + edge.first + n_points_per_layer] }; assert(face_points_2[0] != face_points_2[1]); assert(face_points_2[0] != face_points_2[2]); assert(face_points_2[1] != face_points_2[2]); face_points_2[0]->SetZ(z_here ); face_points_2[1]->SetZ(z_above); face_points_2[2]->SetZ(z_above); #ifndef NDEBUG if (!Helper().IsConvex(face_points_2)) { TRACE("ERROR"); for (const auto& point:face_points_2) { TRACE(Geometry().ToStr(point->GetCoordinat3D())); } } #endif assert(Helper().IsConvex(face_points_2) && "FaceFactory expects convex ordered points"); const boost::shared_ptr<Face> face_2 { FaceFactory().Create( face_points_2, FaceOrientation::vertical, verbose ) }; assert(face_2); v.push_back(face_2); } } } assert(n_ver_faces * (n_face_layers - 1) == static_cast<int>(v.size())); if (verbose) { std::clog << __FILE__ << "(" << (__LINE__) << ") : " << "Done building " << (n_face_layers-1) //Number of cell layers << " layers" << std::endl ; } return v; }
std::vector<boost::shared_ptr<ribi::trim::Face>> ribi::trim::CellsCreator::CreateHorizontalFaces( const boost::shared_ptr<const Template> t, const std::vector<boost::shared_ptr<Point>>& all_points, const int n_face_layers ) { const bool verbose{false}; std::vector<boost::shared_ptr<Face>> v; assert(t); #ifndef NDEBUG if (all_points.empty()) { TRACE("ERROR"); TRACE("BREAK"); } #endif assert(!all_points.empty()); const int n_points_per_layer{static_cast<int>(t->GetPoints().size())}; #ifndef NDEBUG const int n_faces_per_layer{static_cast<int>(t->GetFaces().size())}; assert(n_face_layers > 0); #endif v.reserve(n_face_layers * n_points_per_layer); for (int layer=0; layer!=n_face_layers; ++layer) { const int point_offset{n_points_per_layer * layer}; for (const std::vector<int>& face_point_indices: t->GetFacePointIndices()) { #ifndef NDEBUG const int face_index{static_cast<int>(v.size())}; assert(face_point_indices.size() == 3); //Triangulation #endif std::vector<boost::shared_ptr<Point>> face_points; for (int point_index: face_point_indices) { assert(point_index + point_offset < static_cast<int>(all_points.size())); face_points.push_back(all_points[point_index + point_offset]); #ifndef NDEBUG if (face_points.size() >= 2 && face_points[0]->CanGetZ()) { assert(face_points.front()->GetZ() == face_points.back()->GetZ()); } #endif } assert(layer == 0 || face_index - n_faces_per_layer >= 0); assert(layer == 0 || face_index - n_faces_per_layer < static_cast<int>(v.size())); if ( (layer % 2 == 0 && !Helper().IsClockwiseHorizontal(face_points)) || (layer % 2 == 1 && Helper().IsClockwiseHorizontal(face_points)) ) { std::reverse(face_points.begin(),face_points.end()); } if(!Helper().IsConvex(face_points)) { Helper().MakeConvex(face_points); } assert(Helper().IsConvex(face_points)); //const FaceFactory face_factory; const boost::shared_ptr<Face> face { FaceFactory().Create( face_points, FaceOrientation::horizontal, verbose ) }; v.push_back(face); } } return v; }