From 631d4d92a2be089470ddd49ec83dabbd418dc9e2 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Wed, 28 Jun 2017 11:18:28 +0200 Subject: [PATCH 01/26] comment typo --- cgogn/rendering/shaders/shader_texture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgogn/rendering/shaders/shader_texture.cpp b/cgogn/rendering/shaders/shader_texture.cpp index a0f798d7..be6777cc 100644 --- a/cgogn/rendering/shaders/shader_texture.cpp +++ b/cgogn/rendering/shaders/shader_texture.cpp @@ -95,7 +95,7 @@ void ShaderParamTexture::set_vbo(VBO* vbo_pos, VBO* vbo_tc) ogl->glVertexAttribPointer(ShaderTexture::ATTRIB_POS, vbo_pos->vector_dimension(), GL_FLOAT, GL_FALSE, 0, 0); vbo_pos->release(); - // color vbo + // texcoord vbo vbo_tc->bind(); ogl->glEnableVertexAttribArray(ShaderTexture::ATTRIB_TC); ogl->glVertexAttribPointer(ShaderTexture::ATTRIB_TC, vbo_tc->vector_dimension(), GL_FLOAT, GL_FALSE, 0, 0); From 1504c9791dfdd733477644993d652f73421a2339 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Tue, 8 Aug 2017 17:16:41 +0200 Subject: [PATCH 02/26] Add map_quad_render --- cgogn/rendering/CMakeLists.txt | 4 +- cgogn/rendering/map_quad_render.cpp | 86 +++++ cgogn/rendering/map_quad_render.h | 484 ++++++++++++++++++++++++++++ 3 files changed, 573 insertions(+), 1 deletion(-) create mode 100644 cgogn/rendering/map_quad_render.cpp create mode 100644 cgogn/rendering/map_quad_render.h diff --git a/cgogn/rendering/CMakeLists.txt b/cgogn/rendering/CMakeLists.txt index 1bc16088..4cf0fe8b 100644 --- a/cgogn/rendering/CMakeLists.txt +++ b/cgogn/rendering/CMakeLists.txt @@ -51,6 +51,7 @@ set(HEADER_FILES topo_drawer.h volume_drawer.h map_render.h + map_quad_render.h wall_paper.h frame_manipulator.h ${HEADER_SHADERS} @@ -78,6 +79,7 @@ set(SOURCE_FILES topo_drawer.cpp volume_drawer.cpp map_render.cpp + map_quad_render.cpp wall_paper.cpp frame_manipulator.cpp ${SOURCE_SHADERS} @@ -112,4 +114,4 @@ cgogn_create_package("${CMAKE_CURRENT_SOURCE_DIR}" "${CGOGN_SOURCE_DIR}" "includ # VisualStudio nice source organisation source_group("SHADERS" FILES ${HEADER_SHADERS} ${SOURCE_SHADERS}) source_group("SHADERS_TRANSPARENT" FILES ${HEADER_TRANSP_SHADER} ${SOURCE_TRANSP_SHADER}) -set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER cgogn) \ No newline at end of file +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER cgogn) diff --git a/cgogn/rendering/map_quad_render.cpp b/cgogn/rendering/map_quad_render.cpp new file mode 100644 index 00000000..8e873ef1 --- /dev/null +++ b/cgogn/rendering/map_quad_render.cpp @@ -0,0 +1,86 @@ +/******************************************************************************* +* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * +* Copyright (C) 2015, IGG Group, ICube, University of Strasbourg, France * +* * +* This library is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by the * +* Free Software Foundation; either version 2.1 of the License, or (at your * +* option) any later version. * +* * +* This library 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 Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +* Web site: http://cgogn.unistra.fr/ * +* Contact information: cgogn@unistra.fr * +* * +*******************************************************************************/ + + +#include + +namespace cgogn +{ + +namespace rendering +{ + +MapQuadRender::MapQuadRender() +{ + indices_buffers_ = make_unique(QOpenGLBuffer::IndexBuffer); + indices_buffers_->setUsagePattern(QOpenGLBuffer::StaticDraw); +} + +MapQuadRender::~MapQuadRender() +{} + +void +MapQuadRender::draw() +{ + QOpenGLFunctions* ogl = QOpenGLContext::currentContext()->functions(); + indices_buffers_->bind(); + ogl->glDrawElements(GL_LINES_ADJACENCY, nb_indices_, GL_UNSIGNED_INT, 0); + indices_buffers_->release(); +} + +//void MapQuadRender::draw(DrawingType prim) +//{ +// QOpenGLFunctions* ogl = QOpenGLContext::currentContext()->functions(); + +// indices_buffers_[prim]->bind(); +// switch (prim) +// { +// case POINTS: +// ogl->glDrawElements(GL_POINTS, nb_indices_[POINTS], GL_UNSIGNED_INT, 0); +// break; +// case LINES: +// ogl->glDrawElements(GL_LINES, nb_indices_[LINES], GL_UNSIGNED_INT, 0); +// break; +// case TRIANGLES: +// ogl->glDrawElements(GL_TRIANGLES, nb_indices_[TRIANGLES], GL_UNSIGNED_INT, 0); +// break; +// case BOUNDARY: +// switch (boundary_dimension_) +// { +// case 1: +// ogl->glDrawElements(GL_LINES, nb_indices_[BOUNDARY], GL_UNSIGNED_INT, 0); +// break; +// case 2: +// ogl->glDrawElements(GL_TRIANGLES, nb_indices_[TRIANGLES], GL_UNSIGNED_INT, 0); +// break; +// } +// break; +// default: +// break; +// } +// indices_buffers_[prim]->release(); +//} + +} // namespace rendering + +} // namespace cgogn diff --git a/cgogn/rendering/map_quad_render.h b/cgogn/rendering/map_quad_render.h new file mode 100644 index 00000000..cc5a4f79 --- /dev/null +++ b/cgogn/rendering/map_quad_render.h @@ -0,0 +1,484 @@ + +/******************************************************************************* +* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * +* Copyright (C) 2015, IGG Group, ICube, University of Strasbourg, France * +* * +* This library is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by the * +* Free Software Foundation; either version 2.1 of the License, or (at your * +* option) any later version. * +* * +* This library 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 Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +* Web site: http://cgogn.unistra.fr/ * +* Contact information: cgogn@unistra.fr * +* * +*******************************************************************************/ + +#ifndef CGOGN_RENDERING_MAP_RENDER_QUAD_H_ +#define CGOGN_RENDERING_MAP_RENDER_QUAD_H_ + +#include + +#include // impossible to include directly attribute.h ! + +#include + +#include +#include + +#include +#include + +namespace cgogn +{ + +namespace rendering +{ + + +class CGOGN_RENDERING_API MapQuadRender +{ +protected: + +// // indices used for sorting +// std::vector> indices_tri_; +// std::vector indices_points_; + +// std::array, SIZE_BUFFER> indices_buffers_; +// std::array indices_buffers_uptodate_; +// std::array nb_indices_; +// uint8 boundary_dimension_; + + std::unique_ptr indices_buffers_; + uint32 nb_indices_; + +public: + + using Self = MapQuadRender; + + MapQuadRender(); + ~MapQuadRender(); + CGOGN_NOT_COPYABLE_NOR_MOVABLE(MapQuadRender); + + + + + + +// inline bool is_primitive_uptodate(DrawingType prim) { return indices_buffers_uptodate_[prim]; } + +// inline void set_primitive_dirty(DrawingType prim) { indices_buffers_uptodate_[prim] = false; } + +//protected: + +// template +// inline void init_points(const MAP& m, const MASK& mask, std::vector& table_indices) +// { +//// table_indices.reserve(m.get_nb_darts() / 6); +// m.foreach_cell([&] (typename MAP::Vertex v) +// { +// table_indices.push_back(m.embedding(v)); +// }, +// mask); +// } + +// template +// inline void init_lines(const MAP& m, const MASK& mask, std::vector& table_indices) +// { +// using Vertex = typename MAP::Vertex; +// using Edge = typename MAP::Edge; + +//// table_indices.reserve(m.get_nb_darts() / 2); +// m.foreach_cell([&] (Edge e) +// { +// table_indices.push_back(m.embedding(Vertex(e.dart))); +// table_indices.push_back(m.embedding(Vertex(m.phi1(e.dart)))); +// }, +// mask); +// } + +// template +// inline void init_triangles(const MAP& m, const MASK& mask, std::vector& table_indices) +// { +// using Vertex = typename MAP::Vertex; +// using Face = typename MAP::Face; + +// // reserve more ? +//// table_indices.reserve(m.get_nb_darts() / 3); +// m.foreach_cell([&] (Face f) +// { +// Dart d0 = f.dart; +// Dart d1 = m.phi1(d0); +// Dart d2 = m.phi1(d1); +// do +// { +// table_indices.push_back(m.embedding(Vertex(d0))); +// table_indices.push_back(m.embedding(Vertex(d1))); +// table_indices.push_back(m.embedding(Vertex(d2))); +// d1 = d2; +// d2 = m.phi1(d1); +// } while(d2 != d0); +// }, +// mask); +// } + +// template +// inline void init_triangles_ear( +// const MAP& m, +// const MASK& mask, +// std::vector& table_indices, +// const typename MAP::template VertexAttribute* position +// ) +// { +// using Vertex = typename MAP::Vertex; +// using Face = typename MAP::Face; + +// // reserve more ? +//// table_indices.reserve(m.get_nb_darts() / 3); +// m.foreach_cell([&] (Face f) +// { +// if (m.has_codegree(f, 3)) +// { +// table_indices.push_back(m.embedding(Vertex(f.dart))); +// table_indices.push_back(m.embedding(Vertex(m.phi1(f.dart)))); +// table_indices.push_back(m.embedding(Vertex(m.phi1(m.phi1(f.dart))))); +// } +// else +// cgogn::geometry::append_ear_triangulation(m, f, *position, table_indices); +// }, +// mask); +// } + +// template +// inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) +// -> typename std::enable_if::value, void>::type +// { +// using Vertex = typename MAP::Vertex; +// using Edge = typename MAP::Edge; +// using Face = typename MAP::Face; + +// m.foreach_cell([&] (Face f) +// { +// m.foreach_incident_edge(f, [&] (Edge e) +// { +// table_indices.push_back(m.embedding(Vertex(e.dart))); +// table_indices.push_back(m.embedding(Vertex(m.phi1(e.dart)))); +// }); +// }, +// mask); + +// boundary_dimension_ = 1; +// } + +// template +// inline auto init_boundaries(const MAP& m, const MASK& /*mask*/, std::vector& table_indices) +// -> typename std::enable_if::value, void>::type +// { +// // if the given MASK is not a BoundaryCache, build a BoundaryCache and use it +// typename MAP::BoundaryCache bcache(m); +// init_boundaries(m, bcache, table_indices); +// } + +// template +// inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) +// -> typename std::enable_if::value, void>::type +// { +// using Vertex = typename MAP::Vertex; +// using Face = typename MAP::Face; +// using Volume = typename MAP::Volume; + +// m.foreach_cell([&] (Volume v) +// { +// m.foreach_incident_face(v, [&] (Face f) +// { +// Dart d0 = f.dart; +// Dart d1 = m.phi1(d0); +// Dart d2 = m.phi1(d1); +// do +// { +// table_indices.push_back(m.embedding(Vertex(d0))); +// table_indices.push_back(m.embedding(Vertex(d1))); +// table_indices.push_back(m.embedding(Vertex(d2))); +// d1 = d2; +// d2 = m.phi1(d1); +// } while(d2 != d0); +// }); +// }, +// mask); + +// boundary_dimension_ = 2; +// } + +// template +// inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) +// -> typename std::enable_if::value, void>::type +// { +// unused_parameters(mask); +// // if the given MASK is not a BoundaryCache, build a BoundaryCache and use it +// typename MAP::BoundaryCache bcache(m); +// init_boundaries(m, bcache, table_indices); +// } + +//public: + +// inline uint32 nb_indices(DrawingType prim) const +// { +// return nb_indices_[prim]; +// } + + template + inline void init_primitives(const MAP& m/*, const MASK& mask*/) + { + using Vertex = typename MAP::Vertex; + using Face = typename MAP::Face; + + std::vector table_indices; + + m.foreach_cell([&] (Face f) + { + Dart d0 = f.dart; + Dart d1 = m.phi1(d0); + Dart d2 = m.phi1(d1); + Dart d3 = m.phi1(d2); + table_indices.push_back(m.embedding(Vertex(d0))); + table_indices.push_back(m.embedding(Vertex(d1))); + table_indices.push_back(m.embedding(Vertex(d2))); + table_indices.push_back(m.embedding(Vertex(d3))); + } + /*, mask*/ + ); + + if (!indices_buffers_->isCreated()) + indices_buffers_->create(); + + nb_indices_ = uint32(table_indices.size()); + indices_buffers_->bind(); + indices_buffers_->allocate(table_indices.data(), nb_indices_ * sizeof(uint32)); + indices_buffers_->release(); + } + + +// template +// inline void init_primitives( +// const MAP& m, +// const MASK& mask, +// DrawingType prim, +// const typename MAP::template VertexAttribute* position +// ) +// { +// std::vector table_indices; + +// switch (prim) +// { +// case POINTS: +// init_points(m, mask, table_indices); +// indices_points_.clear(); +// break; +// case LINES: +// init_lines(m, mask, table_indices); +// break; +// case TRIANGLES: +// if (position) +// init_triangles_ear(m, mask, table_indices, position); +// else +// init_triangles(m, mask, table_indices); +// indices_tri_.clear(); +// break; +// case BOUNDARY: +// init_boundaries(m, mask, table_indices); +// break; +// default: +// break; +// } + +// if (!indices_buffers_[prim]->isCreated()) +// indices_buffers_[prim]->create(); + +// indices_buffers_uptodate_[prim] = true; +// nb_indices_[prim] = uint32(table_indices.size()); +// indices_buffers_[prim]->bind(); +// indices_buffers_[prim]->allocate(&(table_indices[0]), nb_indices_[prim] * sizeof(uint32)); +// indices_buffers_[prim]->release(); +// } + +// template +// inline void init_primitives( +// const MAP& m, +// DrawingType prim, +// const typename MAP::template VertexAttribute* position +// ) +// { +// init_primitives(m, AllCellsFilter(), prim, position); +// } + +// template +// inline void init_primitives( +// const MAP& m, +// const MASK& mask, +// DrawingType prim +// ) +// { +// std::vector table_indices; + +// switch (prim) +// { +// case POINTS: +// init_points(m, mask, table_indices); +// indices_points_.clear(); +// break; +// case LINES: +// init_lines(m, mask, table_indices); +// break; +// case TRIANGLES: +// init_triangles(m, mask, table_indices); +// indices_tri_.clear(); +// break; +// case BOUNDARY: +// init_boundaries(m, mask, table_indices); +// break; +// default: +// break; +// } + +// if (table_indices.empty()) +// return; + +// if (!indices_buffers_[prim]->isCreated()) +// indices_buffers_[prim]->create(); + +// indices_buffers_uptodate_[prim] = true; +// nb_indices_[prim] = uint32(table_indices.size()); +// indices_buffers_[prim]->bind(); +// indices_buffers_[prim]->allocate(&(table_indices[0]), nb_indices_[prim] * sizeof(uint32)); +// indices_buffers_[prim]->release(); +// } + +// template +// inline void init_primitives( +// const MAP& m, +// DrawingType prim +// ) +// { +// init_primitives(m, AllCellsFilter(), prim); +// } + + void draw(); +// void draw(DrawingType prim); +}; + +///** +// * @brief transform position with modelview matrix +// * @param map +// * @param pos_in input position +// * @param pos_out transformed positions +// * @param view modelview matrix +// */ +//template +//void transform_position(const MAP& map, const typename MAP::template VertexAttribute& pos_in, typename MAP::template VertexAttribute& pos_out, const QMatrix4x4& view) +//{ +// map.template const_attribute_container().parallel_foreach_index( [&] (uint32 i, uint32) +// { +// QVector3D P = view.map(QVector3D(pos_in[i][0],pos_in[i][1],pos_in[i][2])); +// pos_out[i]= VEC3(P[0],P[1],P[2]); +// }); +//} + +///** +// * @brief create embedding indices of vertices and faces for each vertex of each face +// * @param m the map +// * @param position vertex positions use for ear triangulation +// * @param indices1 embedding indices of vertices +// * @param indices2 embedding indices of faces +// */ +//template +//void create_indices_vertices_faces( +// const MAP& m, +// const typename MAP::template VertexAttribute& position, +// std::vector& indices1, +// std::vector& indices2 +//) +//{ +// using Vertex = typename MAP::Vertex; +// using Face = typename MAP::Face; + +// indices1.reserve(m.nb_darts()); +// indices2.reserve(m.nb_darts()); +// indices1.clear(); +// indices2.clear(); + +// //local vector for ear triangulation +// std::vector local_vert_indices; +// local_vert_indices.reserve(256); + +// m.foreach_cell([&] (Face f) +// { +// uint32 ef = m.embedding(Face(f.dart)); +// if (m.has_codegree(f, 3)) +// { +// indices1.push_back(m.embedding(Vertex(f.dart))); +// indices1.push_back(m.embedding(Vertex(m.phi1(f.dart)))); +// indices1.push_back(m.embedding(Vertex(m.phi1(m.phi1(f.dart))))); +// indices2.push_back(ef); +// indices2.push_back(ef); +// indices2.push_back(ef); +// } +// else +// { +// cgogn::geometry::append_ear_triangulation(m, f, position, local_vert_indices); +// for (uint32 i : local_vert_indices) +// { +// indices1.push_back(i); +// indices2.push_back(ef); +// } +// } +// }); +//} + +//template +//void add_to_drawer(const MAP& m, typename MAP::Edge e, const typename MAP::template VertexAttribute& position, DisplayListDrawer* dr) +//{ +// using Vertex = typename MAP::Vertex; + +// dr->vertex3fv(position[Vertex(e.dart)]); +// dr->vertex3fv(position[Vertex(m.phi1(e.dart))]); +//} + +//template +//void add_to_drawer(const MAP& m, typename MAP::Face f, const typename MAP::template VertexAttribute& position, DisplayListDrawer* dr) +//{ +// using Vertex = typename MAP::Vertex; +// using Edge = typename MAP::Edge; + +// m.foreach_incident_edge(f, [&] (Edge e) +// { +// dr->vertex3fv(position[Vertex(e.dart)]); +// dr->vertex3fv(position[Vertex(m.phi1(e.dart))]); +// }); +//} + +//template +//void add_to_drawer(const MAP& m, typename MAP::Volume vo, const typename MAP::template VertexAttribute& position, DisplayListDrawer* dr) +//{ +// using Vertex = typename MAP::Vertex; +// using Edge = typename MAP::Edge; + +// m.foreach_incident_edge(vo, [&] (Edge e) +// { +// dr->vertex3fv(position[Vertex(e.dart)]); +// dr->vertex3fv(position[Vertex(m.phi1(e.dart))]); +// }); +//} + +} // namespace rendering + +} // namespace cgogn + +#endif // CGOGN_RENDERING_MAP_RENDER_QUAD_H_ From 9f9efc608befb2c715340303b924c5ba00f7ee24 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Fri, 11 Aug 2017 08:12:46 +0200 Subject: [PATCH 03/26] Cleanup MapQuadRender --- cgogn/rendering/map_quad_render.cpp | 33 --- cgogn/rendering/map_quad_render.h | 392 +--------------------------- 2 files changed, 3 insertions(+), 422 deletions(-) diff --git a/cgogn/rendering/map_quad_render.cpp b/cgogn/rendering/map_quad_render.cpp index 8e873ef1..685ee6f6 100644 --- a/cgogn/rendering/map_quad_render.cpp +++ b/cgogn/rendering/map_quad_render.cpp @@ -48,39 +48,6 @@ MapQuadRender::draw() indices_buffers_->release(); } -//void MapQuadRender::draw(DrawingType prim) -//{ -// QOpenGLFunctions* ogl = QOpenGLContext::currentContext()->functions(); - -// indices_buffers_[prim]->bind(); -// switch (prim) -// { -// case POINTS: -// ogl->glDrawElements(GL_POINTS, nb_indices_[POINTS], GL_UNSIGNED_INT, 0); -// break; -// case LINES: -// ogl->glDrawElements(GL_LINES, nb_indices_[LINES], GL_UNSIGNED_INT, 0); -// break; -// case TRIANGLES: -// ogl->glDrawElements(GL_TRIANGLES, nb_indices_[TRIANGLES], GL_UNSIGNED_INT, 0); -// break; -// case BOUNDARY: -// switch (boundary_dimension_) -// { -// case 1: -// ogl->glDrawElements(GL_LINES, nb_indices_[BOUNDARY], GL_UNSIGNED_INT, 0); -// break; -// case 2: -// ogl->glDrawElements(GL_TRIANGLES, nb_indices_[TRIANGLES], GL_UNSIGNED_INT, 0); -// break; -// } -// break; -// default: -// break; -// } -// indices_buffers_[prim]->release(); -//} - } // namespace rendering } // namespace cgogn diff --git a/cgogn/rendering/map_quad_render.h b/cgogn/rendering/map_quad_render.h index cc5a4f79..8a43dac1 100644 --- a/cgogn/rendering/map_quad_render.h +++ b/cgogn/rendering/map_quad_render.h @@ -48,15 +48,6 @@ class CGOGN_RENDERING_API MapQuadRender { protected: -// // indices used for sorting -// std::vector> indices_tri_; -// std::vector indices_points_; - -// std::array, SIZE_BUFFER> indices_buffers_; -// std::array indices_buffers_uptodate_; -// std::array nb_indices_; -// uint8 boundary_dimension_; - std::unique_ptr indices_buffers_; uint32 nb_indices_; @@ -68,174 +59,8 @@ class CGOGN_RENDERING_API MapQuadRender ~MapQuadRender(); CGOGN_NOT_COPYABLE_NOR_MOVABLE(MapQuadRender); - - - - - -// inline bool is_primitive_uptodate(DrawingType prim) { return indices_buffers_uptodate_[prim]; } - -// inline void set_primitive_dirty(DrawingType prim) { indices_buffers_uptodate_[prim] = false; } - -//protected: - -// template -// inline void init_points(const MAP& m, const MASK& mask, std::vector& table_indices) -// { -//// table_indices.reserve(m.get_nb_darts() / 6); -// m.foreach_cell([&] (typename MAP::Vertex v) -// { -// table_indices.push_back(m.embedding(v)); -// }, -// mask); -// } - -// template -// inline void init_lines(const MAP& m, const MASK& mask, std::vector& table_indices) -// { -// using Vertex = typename MAP::Vertex; -// using Edge = typename MAP::Edge; - -//// table_indices.reserve(m.get_nb_darts() / 2); -// m.foreach_cell([&] (Edge e) -// { -// table_indices.push_back(m.embedding(Vertex(e.dart))); -// table_indices.push_back(m.embedding(Vertex(m.phi1(e.dart)))); -// }, -// mask); -// } - -// template -// inline void init_triangles(const MAP& m, const MASK& mask, std::vector& table_indices) -// { -// using Vertex = typename MAP::Vertex; -// using Face = typename MAP::Face; - -// // reserve more ? -//// table_indices.reserve(m.get_nb_darts() / 3); -// m.foreach_cell([&] (Face f) -// { -// Dart d0 = f.dart; -// Dart d1 = m.phi1(d0); -// Dart d2 = m.phi1(d1); -// do -// { -// table_indices.push_back(m.embedding(Vertex(d0))); -// table_indices.push_back(m.embedding(Vertex(d1))); -// table_indices.push_back(m.embedding(Vertex(d2))); -// d1 = d2; -// d2 = m.phi1(d1); -// } while(d2 != d0); -// }, -// mask); -// } - -// template -// inline void init_triangles_ear( -// const MAP& m, -// const MASK& mask, -// std::vector& table_indices, -// const typename MAP::template VertexAttribute* position -// ) -// { -// using Vertex = typename MAP::Vertex; -// using Face = typename MAP::Face; - -// // reserve more ? -//// table_indices.reserve(m.get_nb_darts() / 3); -// m.foreach_cell([&] (Face f) -// { -// if (m.has_codegree(f, 3)) -// { -// table_indices.push_back(m.embedding(Vertex(f.dart))); -// table_indices.push_back(m.embedding(Vertex(m.phi1(f.dart)))); -// table_indices.push_back(m.embedding(Vertex(m.phi1(m.phi1(f.dart))))); -// } -// else -// cgogn::geometry::append_ear_triangulation(m, f, *position, table_indices); -// }, -// mask); -// } - -// template -// inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) -// -> typename std::enable_if::value, void>::type -// { -// using Vertex = typename MAP::Vertex; -// using Edge = typename MAP::Edge; -// using Face = typename MAP::Face; - -// m.foreach_cell([&] (Face f) -// { -// m.foreach_incident_edge(f, [&] (Edge e) -// { -// table_indices.push_back(m.embedding(Vertex(e.dart))); -// table_indices.push_back(m.embedding(Vertex(m.phi1(e.dart)))); -// }); -// }, -// mask); - -// boundary_dimension_ = 1; -// } - -// template -// inline auto init_boundaries(const MAP& m, const MASK& /*mask*/, std::vector& table_indices) -// -> typename std::enable_if::value, void>::type -// { -// // if the given MASK is not a BoundaryCache, build a BoundaryCache and use it -// typename MAP::BoundaryCache bcache(m); -// init_boundaries(m, bcache, table_indices); -// } - -// template -// inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) -// -> typename std::enable_if::value, void>::type -// { -// using Vertex = typename MAP::Vertex; -// using Face = typename MAP::Face; -// using Volume = typename MAP::Volume; - -// m.foreach_cell([&] (Volume v) -// { -// m.foreach_incident_face(v, [&] (Face f) -// { -// Dart d0 = f.dart; -// Dart d1 = m.phi1(d0); -// Dart d2 = m.phi1(d1); -// do -// { -// table_indices.push_back(m.embedding(Vertex(d0))); -// table_indices.push_back(m.embedding(Vertex(d1))); -// table_indices.push_back(m.embedding(Vertex(d2))); -// d1 = d2; -// d2 = m.phi1(d1); -// } while(d2 != d0); -// }); -// }, -// mask); - -// boundary_dimension_ = 2; -// } - -// template -// inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) -// -> typename std::enable_if::value, void>::type -// { -// unused_parameters(mask); -// // if the given MASK is not a BoundaryCache, build a BoundaryCache and use it -// typename MAP::BoundaryCache bcache(m); -// init_boundaries(m, bcache, table_indices); -// } - -//public: - -// inline uint32 nb_indices(DrawingType prim) const -// { -// return nb_indices_[prim]; -// } - - template - inline void init_primitives(const MAP& m/*, const MASK& mask*/) + template + inline void init_primitives(const MAP& m) { using Vertex = typename MAP::Vertex; using Face = typename MAP::Face; @@ -252,9 +77,7 @@ class CGOGN_RENDERING_API MapQuadRender table_indices.push_back(m.embedding(Vertex(d1))); table_indices.push_back(m.embedding(Vertex(d2))); table_indices.push_back(m.embedding(Vertex(d3))); - } - /*, mask*/ - ); + }); if (!indices_buffers_->isCreated()) indices_buffers_->create(); @@ -265,218 +88,9 @@ class CGOGN_RENDERING_API MapQuadRender indices_buffers_->release(); } - -// template -// inline void init_primitives( -// const MAP& m, -// const MASK& mask, -// DrawingType prim, -// const typename MAP::template VertexAttribute* position -// ) -// { -// std::vector table_indices; - -// switch (prim) -// { -// case POINTS: -// init_points(m, mask, table_indices); -// indices_points_.clear(); -// break; -// case LINES: -// init_lines(m, mask, table_indices); -// break; -// case TRIANGLES: -// if (position) -// init_triangles_ear(m, mask, table_indices, position); -// else -// init_triangles(m, mask, table_indices); -// indices_tri_.clear(); -// break; -// case BOUNDARY: -// init_boundaries(m, mask, table_indices); -// break; -// default: -// break; -// } - -// if (!indices_buffers_[prim]->isCreated()) -// indices_buffers_[prim]->create(); - -// indices_buffers_uptodate_[prim] = true; -// nb_indices_[prim] = uint32(table_indices.size()); -// indices_buffers_[prim]->bind(); -// indices_buffers_[prim]->allocate(&(table_indices[0]), nb_indices_[prim] * sizeof(uint32)); -// indices_buffers_[prim]->release(); -// } - -// template -// inline void init_primitives( -// const MAP& m, -// DrawingType prim, -// const typename MAP::template VertexAttribute* position -// ) -// { -// init_primitives(m, AllCellsFilter(), prim, position); -// } - -// template -// inline void init_primitives( -// const MAP& m, -// const MASK& mask, -// DrawingType prim -// ) -// { -// std::vector table_indices; - -// switch (prim) -// { -// case POINTS: -// init_points(m, mask, table_indices); -// indices_points_.clear(); -// break; -// case LINES: -// init_lines(m, mask, table_indices); -// break; -// case TRIANGLES: -// init_triangles(m, mask, table_indices); -// indices_tri_.clear(); -// break; -// case BOUNDARY: -// init_boundaries(m, mask, table_indices); -// break; -// default: -// break; -// } - -// if (table_indices.empty()) -// return; - -// if (!indices_buffers_[prim]->isCreated()) -// indices_buffers_[prim]->create(); - -// indices_buffers_uptodate_[prim] = true; -// nb_indices_[prim] = uint32(table_indices.size()); -// indices_buffers_[prim]->bind(); -// indices_buffers_[prim]->allocate(&(table_indices[0]), nb_indices_[prim] * sizeof(uint32)); -// indices_buffers_[prim]->release(); -// } - -// template -// inline void init_primitives( -// const MAP& m, -// DrawingType prim -// ) -// { -// init_primitives(m, AllCellsFilter(), prim); -// } - void draw(); -// void draw(DrawingType prim); }; -///** -// * @brief transform position with modelview matrix -// * @param map -// * @param pos_in input position -// * @param pos_out transformed positions -// * @param view modelview matrix -// */ -//template -//void transform_position(const MAP& map, const typename MAP::template VertexAttribute& pos_in, typename MAP::template VertexAttribute& pos_out, const QMatrix4x4& view) -//{ -// map.template const_attribute_container().parallel_foreach_index( [&] (uint32 i, uint32) -// { -// QVector3D P = view.map(QVector3D(pos_in[i][0],pos_in[i][1],pos_in[i][2])); -// pos_out[i]= VEC3(P[0],P[1],P[2]); -// }); -//} - -///** -// * @brief create embedding indices of vertices and faces for each vertex of each face -// * @param m the map -// * @param position vertex positions use for ear triangulation -// * @param indices1 embedding indices of vertices -// * @param indices2 embedding indices of faces -// */ -//template -//void create_indices_vertices_faces( -// const MAP& m, -// const typename MAP::template VertexAttribute& position, -// std::vector& indices1, -// std::vector& indices2 -//) -//{ -// using Vertex = typename MAP::Vertex; -// using Face = typename MAP::Face; - -// indices1.reserve(m.nb_darts()); -// indices2.reserve(m.nb_darts()); -// indices1.clear(); -// indices2.clear(); - -// //local vector for ear triangulation -// std::vector local_vert_indices; -// local_vert_indices.reserve(256); - -// m.foreach_cell([&] (Face f) -// { -// uint32 ef = m.embedding(Face(f.dart)); -// if (m.has_codegree(f, 3)) -// { -// indices1.push_back(m.embedding(Vertex(f.dart))); -// indices1.push_back(m.embedding(Vertex(m.phi1(f.dart)))); -// indices1.push_back(m.embedding(Vertex(m.phi1(m.phi1(f.dart))))); -// indices2.push_back(ef); -// indices2.push_back(ef); -// indices2.push_back(ef); -// } -// else -// { -// cgogn::geometry::append_ear_triangulation(m, f, position, local_vert_indices); -// for (uint32 i : local_vert_indices) -// { -// indices1.push_back(i); -// indices2.push_back(ef); -// } -// } -// }); -//} - -//template -//void add_to_drawer(const MAP& m, typename MAP::Edge e, const typename MAP::template VertexAttribute& position, DisplayListDrawer* dr) -//{ -// using Vertex = typename MAP::Vertex; - -// dr->vertex3fv(position[Vertex(e.dart)]); -// dr->vertex3fv(position[Vertex(m.phi1(e.dart))]); -//} - -//template -//void add_to_drawer(const MAP& m, typename MAP::Face f, const typename MAP::template VertexAttribute& position, DisplayListDrawer* dr) -//{ -// using Vertex = typename MAP::Vertex; -// using Edge = typename MAP::Edge; - -// m.foreach_incident_edge(f, [&] (Edge e) -// { -// dr->vertex3fv(position[Vertex(e.dart)]); -// dr->vertex3fv(position[Vertex(m.phi1(e.dart))]); -// }); -//} - -//template -//void add_to_drawer(const MAP& m, typename MAP::Volume vo, const typename MAP::template VertexAttribute& position, DisplayListDrawer* dr) -//{ -// using Vertex = typename MAP::Vertex; -// using Edge = typename MAP::Edge; - -// m.foreach_incident_edge(vo, [&] (Edge e) -// { -// dr->vertex3fv(position[Vertex(e.dart)]); -// dr->vertex3fv(position[Vertex(m.phi1(e.dart))]); -// }); -//} - } // namespace rendering } // namespace cgogn From 53c7b8e5d46ee46ee49291e9195985f99f61f4fb Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Mon, 21 Aug 2017 18:47:15 +0200 Subject: [PATCH 04/26] add ParallelogramTiling Topo. Ongoing ... --- cgogn/modeling/CMakeLists.txt | 2 + cgogn/modeling/tiling/parallelogram_grid.cpp | 38 +++++ cgogn/modeling/tiling/parallelogram_grid.h | 163 +++++++++++++++++++ 3 files changed, 203 insertions(+) create mode 100644 cgogn/modeling/tiling/parallelogram_grid.cpp create mode 100644 cgogn/modeling/tiling/parallelogram_grid.h diff --git a/cgogn/modeling/CMakeLists.txt b/cgogn/modeling/CMakeLists.txt index 3e01071a..acdeba35 100644 --- a/cgogn/modeling/CMakeLists.txt +++ b/cgogn/modeling/CMakeLists.txt @@ -19,6 +19,7 @@ set(HEADER_TILING tiling/square_grid.h tiling/square_cylinder.h tiling/square_tore.h + tiling/parallelogram_grid.h ) set(HEADER_DECIMATION decimation/edge_approximator.h @@ -50,6 +51,7 @@ set(SOURCE_TILING tiling/square_cylinder.cpp tiling/square_tore.cpp # tiling/square_cube.h + tiling/parallelogram_grid.cpp ) set(SOURCE_FILES ${SOURCE_ALGOS} ${SOURCE_TILING}) diff --git a/cgogn/modeling/tiling/parallelogram_grid.cpp b/cgogn/modeling/tiling/parallelogram_grid.cpp new file mode 100644 index 00000000..f0494949 --- /dev/null +++ b/cgogn/modeling/tiling/parallelogram_grid.cpp @@ -0,0 +1,38 @@ +/******************************************************************************* +* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * +* Copyright (C) 2015, IGG Group, ICube, University of Strasbourg, France * +* * +* This library is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by the * +* Free Software Foundation; either version 2.1 of the License, or (at your * +* option) any later version. * +* * +* This library 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 Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +* Web site: http://cgogn.unistra.fr/ * +* Contact information: cgogn@unistra.fr * +* * +*******************************************************************************/ + +#define CGOGN_MODELING_TILING_SQUARE_GRID_CPP_ + +#include + +namespace cgogn +{ + +namespace modeling +{ + +template class CGOGN_MODELING_API ParallelogramGrid; + +} // namespace modeling + +} // namespace cgogn diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h new file mode 100644 index 00000000..4f9b3ad0 --- /dev/null +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -0,0 +1,163 @@ +#ifndef CGOGN_MODELING_TILING_PARALLELOGRAM_GRID_H +#define CGOGN_MODELING_TILING_PARALLELOGRAM_GRID_H + +#include +#include + +#include +#include + +namespace cgogn +{ + +namespace modeling +{ + +template + +class ParallelogramGrid : public Tiling +{ + using Map2 = cgogn::CMap2; + + using CDart = typename MAP::CDart; + using Vertex = typename MAP::Vertex; + using Edge = typename MAP::Edge; + using Face = typename MAP::Face; + using Volume = typename MAP::Volume; + + using Vec3 = Eigen::Vector3d; + using Vec2 = Eigen::Vector2d; + + template + using VertexAttribute = Map2::VertexAttribute; + + using MapBuilder = typename MAP::Builder; + +public: + /** + * @brief ParallelogramGrid creates a mesh composed of a tiling of identical parallelograms. + * Parallelograms are defined by two vectors (Ti,Tj). + * The position of the left-bottom corner of one parallelogram is defined as being located at p. + * The tiling is embedded geometrically and fills at least a rectangular area defined by the point RectOrigin and RectDiag. + * @param map the CGoGN map that defines the mesh. + * @param p origin of the reference parallelogram + * @param Ti first vector definining a parallelogram + * @param Tj second vector definining a parallelogram + * @param RectOrigin origin of the rectangle to fill + * @param RectDiag diagonal (starting from RectOrigin) of the rectangle to fill + * + * @pre p must lie in the rectangle defined by #RectOrigin and #RectDiag + * @pre Ti[0] > 0 + * @pre Tj[0] >=0 + * @pre Tj[1] > Ti[1] + */ + ParallelogramGrid(MAP& map, Vec2 p, Vec2 Ti, Vec2 Tj, Vec2 RectOrigin, Vec2 RectDiag): + Tiling(map) + { + map.template add_attribute("position") ; + //map.template add_attribute("edgeType"); + //map.template add_attribute("edges"); + //map.template add_attribute("faces"); + //map.template add_attribute("volumes"); + + MapBuilder mbuild(map); + // TODO reserve vertex table and face table if numbers known. + + //creation of quads and storing vertices + std::vector edges ; // list of edges to treat + // Map2::CellMarker border_edges(map) ; // list of border edges + + // Create face + const Dart d0 = mbuild.add_face_topo_fp(4) ; // phi2 is fixed point + const Vertex v0 = Vertex(d0) ; + const Face f0 = Face(d0) ; + + + // Create new orbit embeddings for all embedded orbits. + // All VERTEX of this face + const bool isVertexEmbedded = map.template is_embedded() ; + map.foreach_incident_vertex(f0, + [&] (Vertex v) + { + this->vertex_table_.push_back(v) ; + if (isVertexEmbedded) + mbuild.new_orbit_embedding(v) ; + }) ; + this->dart_ = this->vertex_table_[0].dart; + + // This FACE + this->face_table_.push_back(f0) ; + if(this->map_.template is_embedded()) + mbuild.new_orbit_embedding(f0) ; + + // All EDGE of this Face + if(this->map_.template is_embedded()) + this->map_.foreach_incident_edge(Face(this->dart_), + [&](Edge e) + { + mbuild.new_orbit_embedding(e); + }); + + // Embed vertices of face + VertexAttribute position = map.template get_attribute("position"); + assert(position.is_valid()); + embed_parallelogram(map, position, f0, p, Ti, Tj) ; + + + // + + // Mark boundary faces + // mbuild.boundary_mark(f) ; + + // close boundary + + + map.check_embedding_integrity() ; + } + + /** + * @brief embed_parallelogram + * @param map + * @param position + * @param f + * @param p0 + * @param Ti + * @param Tj + * @pre f needs to be a quadrilateral. + * @pre position need be a valid vertex attribute. + */ + void embed_parallelogram(MAP& map, typename MAP::template VertexAttribute& position, Face f, const Vec2& p0, const Vec2& Ti, const Vec2& Tj) + { + const Dart d0 = f.dart ; + const Dart d1 = map.phi1(d0) ; + const Dart d2 = map.phi1(d1) ; + const Dart d3 = map.phi1(d2) ; + assert(d0==map.phi1(d3)) ; + + position[Vertex(d0)] = p0 ; + position[Vertex(d1)] = p0 + Ti ; + position[Vertex(d2)] = position[d1] + Tj ; + position[Vertex(d3)] = p0 + Tj ; + + position[Vertex(d0)] = Vec2(1,1) ; + position[Vertex(d1)] = Vec2(2,2) ; + position[Vertex(d2)] = Vec2(3,3) ; + position[Vertex(d3)] = Vec2(0,4) ; + + const Vec2 a = position[Vertex(d0)] ; + Vec2 b = position[Vertex(d1)] ; + Vec2 c = position[Vertex(d2)] ; + Vec2 d = position[Vertex(d3)] ; + + std::cout << &(position[Vertex(d0)][0]) << std::endl ; + std::cout << &(position[Vertex(d1)][0]) << std::endl ; + std::cout << &(position[Vertex(d2)][0]) << std::endl ; + std::cout << &(position[Vertex(d3)][0]) << std::endl ; + } +}; + +} //namespace modeling + +} //namespace cgogn + +#endif // CGOGN_MODELING_TILING_PARALLELOGRAM_GRID_H From 100adff5b3e4238367c60d236d2619002124338f Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Wed, 23 Aug 2017 17:41:14 +0200 Subject: [PATCH 05/26] paralellogram_grid --- cgogn/modeling/CMakeLists.txt | 2 + cgogn/modeling/tiling/parallelogram_grid.cpp | 38 + cgogn/modeling/tiling/parallelogram_grid.h | 693 +++++++++++++++++++ cgogn/rendering/map_quad_render.cpp | 33 - cgogn/rendering/map_quad_render.h | 392 +---------- 5 files changed, 736 insertions(+), 422 deletions(-) create mode 100644 cgogn/modeling/tiling/parallelogram_grid.cpp create mode 100644 cgogn/modeling/tiling/parallelogram_grid.h diff --git a/cgogn/modeling/CMakeLists.txt b/cgogn/modeling/CMakeLists.txt index 3e01071a..acdeba35 100644 --- a/cgogn/modeling/CMakeLists.txt +++ b/cgogn/modeling/CMakeLists.txt @@ -19,6 +19,7 @@ set(HEADER_TILING tiling/square_grid.h tiling/square_cylinder.h tiling/square_tore.h + tiling/parallelogram_grid.h ) set(HEADER_DECIMATION decimation/edge_approximator.h @@ -50,6 +51,7 @@ set(SOURCE_TILING tiling/square_cylinder.cpp tiling/square_tore.cpp # tiling/square_cube.h + tiling/parallelogram_grid.cpp ) set(SOURCE_FILES ${SOURCE_ALGOS} ${SOURCE_TILING}) diff --git a/cgogn/modeling/tiling/parallelogram_grid.cpp b/cgogn/modeling/tiling/parallelogram_grid.cpp new file mode 100644 index 00000000..68c1c4ee --- /dev/null +++ b/cgogn/modeling/tiling/parallelogram_grid.cpp @@ -0,0 +1,38 @@ +/******************************************************************************* +* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * +* Copyright (C) 2015, IGG Group, ICube, University of Strasbourg, France * +* * +* This library is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by the * +* Free Software Foundation; either version 2.1 of the License, or (at your * +* option) any later version. * +* * +* This library 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 Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +* Web site: http://cgogn.unistra.fr/ * +* Contact information: cgogn@unistra.fr * +* * +*******************************************************************************/ + +#define CGOGN_MODELING_TILING_SQUARE_GRID_CPP_ + +#include + +namespace cgogn +{ + +namespace modeling +{ + +template class CGOGN_MODELING_API ParallelogramGrid; + +} // namespace modeling + +} // namespace cgogn diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h new file mode 100644 index 00000000..ed68aaa3 --- /dev/null +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -0,0 +1,693 @@ +#ifndef CGOGN_MODELING_TILING_PARALLELOGRAM_GRID_H +#define CGOGN_MODELING_TILING_PARALLELOGRAM_GRID_H + +#include +#include + +#include +#include + +namespace cgogn +{ + +namespace modeling +{ + +template +class ParallelogramGrid : public Tiling +{ + using Map2 = cgogn::CMap2; + + using CDart = typename MAP::CDart; + using Vertex = typename MAP::Vertex; + using Edge = typename MAP::Edge; + using Face = typename MAP::Face; + using Volume = typename MAP::Volume; + + template + using DartAttribute = Map2::CDartAttribute; + template + using VertexAttribute = Map2::VertexAttribute; + template + using FaceAttribute = Map2::FaceAttribute; + + using MapBuilder = typename MAP::Builder; + using ChunkArrayContainer = MapBaseData::ChunkArrayContainer; + + enum Orient { S=0, E=1, N=2, W=3, INVALID_ORIENT} ; + struct DartOrient + { + Orient value_; + + DartOrient() : value_(INVALID_ORIENT) {} + + friend std::ostream& operator<<(std::ostream& out, const DartOrient&) { return out; } + friend std::istream& operator>>(std::istream& in, const DartOrient&) { return in; } + }; + +protected: + DartAttribute dart_orientation_ ; + VertexAttribute vertex_position_ ; + +public: + /** + * @brief ParallelogramGrid creates a mesh composed of a tiling of identical parallelograms. + * Parallelograms are defined by two vectors (Ti,Tj). + * The position of the left-bottom corner of one parallelogram is defined as being located at p. + * The tiling is embedded geometrically and fills at least a rectangular area defined by the point RectOrigin and RectDiag. + * @param map the CGoGN map that defines the mesh. + * @param p origin of the reference parallelogram + * @param Ti first vector definining a parallelogram + * @param Tj second vector definining a parallelogram + * @param fill_area rectangular area to fill withparallelograms + * + * @pre p must lie in the bounding box #fill_area + * @pre Ti[0] > 0 + * @pre Tj[0] >=0 + * @pre Tj[1] > Ti[1] + */ + ParallelogramGrid(MAP& map, const VEC& p, const VEC& Ti, const VEC& Tj, const geometry::AABB& fill_area): + Tiling(map) + { + cgogn_assert(fill_area.contains(p)) ; + + vertex_position_ = this->map_.template add_attribute("position") ; + dart_orientation_ = this->map_.template add_attribute("dartOrient"); + + MapBuilder mbuild(map); + + // Create face and update orbit embeddings + std::array incidentVertices ; + std::array adjacentFaces ; + const Dart d0 = add_face_topo(mbuild, incidentVertices/*, dart_orientation*/) ; + this->dart_ = d0; + const Face f0 = Face(d0) ; + + // Embed vertices of face + const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, f0, p, Ti, Tj) ; + + std::queue edgeQueue ; // list of edges to treat + queueFreeEdges(f0,edgeQueue, f_bbox, fill_area) ; + + while(!edgeQueue.empty()) + { + // Pop front edge + Edge e = edgeQueue.front() ; + + const Dart d = e.dart ; + if (is_border(d)) // if it lacks a neighbor + { + // get Array of existing adjacent (neighboring) faces + const Face provokingFace = Face(d) ; + const Orient provokingFaceOrient = getOrientOfDart(d/*,provokingFace*/) ; + adjacentFaces = getAdjacentFacesFromProvokingFace(/*dart_orientation,*/provokingFace,provokingFaceOrient/*dart_orientation[e.dart].value_*/) ; + + // Compute which incident vertices are already there + incidentVertices = adjFaces2incVertices(adjacentFaces) ; + + // Add new face, re-using existing vertices if present + const Dart newDart = add_face_topo(mbuild, incidentVertices/*, adjacentFaces, dart_orientation*/) ; + const Face newFace = Face(newDart) ; + + // sew with neighbor faces + sewFaceToAdjacentFaces(mbuild,newFace,adjacentFaces) ; + + // Embed vertices of face + // Get embedding of previous face's reference vertex + VEC p_ref = vertex_position_[getRefVertex(provokingFace)] ; + + // Define embedding of new face's reference vertex + switch(provokingFaceOrient) + { + case(S): + p_ref -= Tj ; + break ; + case(E): + p_ref += Ti ; + break ; + case(N): + p_ref += Tj ; + break ; + case(W): + p_ref -= Ti ; + break ; + case(INVALID_ORIENT): + cgogn_log_error("INVALID_ORIENT in switch") ; + break ; + } + + // Embed new face's geometry + const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, newFace, p_ref, Ti, Tj) ; + // Add edges that are free + queueFreeEdges(newFace, edgeQueue, f_bbox, fill_area) ; + } + + edgeQueue.pop() ; + } + + // Mark boundary faces + // mbuild.boundary_mark(f) ; + + // close boundary + mbuild.close_map() ; + this->map_.check_embedding_integrity() ; + } + + + + + +// Orient sew_FaceEdge(MapBuilder& mbuild, /*const DartAttribute& dart_orientation,*/ const Face& f0, const Edge& e0) +// { +// cgogn_ensure(this->map_.phi2(e0.dart) == e0.dart) ; + +// const DartDir& et = dart_orientation[e0] ; +// Orient fSearchDartDir = INVALID_ORIENT ; +// switch(et.value_) +// { +// case(S): +// fSearchDartDir = N ; +// break ; +// case(E): +// fSearchDartDir = W ; +// break ; +// case(N): +// fSearchDartDir = S ; +// break ; +// case(W): +// fSearchDartDir = E ; +// break ; +// case(INVALID_ORIENT): +// cgogn_ensure(et.value_ != INVALID_ORIENT) ; +// break ; +// } + +// Edge to_sew ; +// this->map_.foreach_incident_edge(f0, +// [&] (Edge e) -> bool +// { +// to_sew = e ; +// return (dart_orientation[e].value_ == fSearchDartDir) ; +// }) ; + +// // sew to_sew and e0 by phi2 +// const Dart& d0 = to_sew.dart ; +// const Dart& d1 = e0.dart ; +// mbuild.phi2_sew(d0,d1) ; +// // ensure embedding +// mbuild.template set_embedding(d1, this->map_.embedding(Vertex(this->map_.phi1(d0)))); + +// return et.value_ ; +// } + +// ------------------------ Mesh construction algorithm -------------------------------- + /** + * @brief queueFreeEdges adds the edges of face #f that are border edges of the mesh to the queue #edgeQueue iff #f_bbox intersects with the area to fill (#fill_area). + * @param f the face + * @param edgeQueue the queue of edges to maintain + * @param f_bbox bounding box of the current face + * @param fill_area the area to fill + * @return + */ + uint queueFreeEdges(const Face& f, std::queue& edgeQueue, const geometry::AABB& f_bbox, const geometry::AABB& fill_area) + { + uint counter = 0 ; + // if current face touches the Rectangle + if (fill_area.intersects(f_bbox)) + { + // add all its edges to list of edges to treat + this->map_.foreach_incident_edge(f, + [&] (Edge e) + { + if (is_border(e.dart)) // if it hasn't been sewed + { + edgeQueue.push(e); + ++counter ; + } + }); + } + + return counter ; + } + +// ------------------------ Tools: Position embedding -------------------------------- + /** + * @brief embed_parallelogram embeds a quad into a parallelogram + * @param position the Vertex position container + * @param f the quad + * @param p0 the reference vertex position + * @param Ti the first vector + * @param Tj the second vector + * @pre f needs to be a quadrilateral and fully sewed + * @pre position need be a valid vertex attribute. + * + * @return the axis-aligned bounding box of the embedded parallelogram + */ + geometry::AABB embed_parallelogram( + typename MAP::template VertexAttribute& position, + //typename MAP::template DartAttribute& dart_orientation, + const Face& f, const VEC& p0, const VEC& Ti, const VEC& Tj) + { + const Dart d0 = f.dart ; + const Dart d1 = this->map_.phi1(d0) ; + const Dart d2 = this->map_.phi1(d1) ; + const Dart d3 = this->map_.phi1(d2) ; + cgogn_ensure(d0==this->map_.phi1(d3)) ; + + position[Vertex(d0)] = p0 ; + position[Vertex(d1)] = p0 + Ti ; + position[Vertex(d2)] = position[d1] + Tj ; + position[Vertex(d3)] = p0 + Tj ; + + geometry::AABB bbox(p0) ; + bbox.add_point(position[d1]) ; + bbox.add_point(position[d2]) ; + bbox.add_point(position[d3]) ; + + return bbox ; + } + +// ------------------------ Tools: Constructing the mesh -------------------------------- + + /** + * @brief add_face_topo creates a new face and updates embeddings topological embedding pointers + * @param mbuild + * @param incidentVertices contains existing vertices to link to, if any (invalid ones otherwise) + * @return + */ + Dart add_face_topo(MapBuilder& mbuild, const std::array& incidentVertices/*, const std::array& adjacentFaces, DartAttribute& dart_orientation*/) + { + ChunkArrayContainer& dart_container = mbuild.template attribute_container(); + ChunkArrayContainer& vertex_container = mbuild.template attribute_container(); + ChunkArrayContainer& face_container = mbuild.template attribute_container(); + + // Create face + const Dart d0 = mbuild.add_face_topo_fp(4u) ; // phi2 is fixed point + const Dart d1 = this->map_.phi1(d0) ; + const Dart d2 = this->map_.phi1(d1) ; + const Dart d3 = this->map_.phi1(d2) ; + + // Create new orbit embeddings for all embedded orbits. + // This FACE + const Face f0 = Face(d0) ; + if(this->map_.template is_embedded()) + { + uint32 nf = face_container.insert_lines<1>(); + mbuild.template set_embedding(f0.dart,nf); + } + + // All DART of this face + if(this->map_.template is_embedded()) + { + this->map_.foreach_dart_of_orbit(f0, [&] (Dart d) + { + uint32 nd = dart_container.insert_lines<1>() ; + mbuild.template set_embedding(d,nd); + }); + } + + // All VERTEX of this face (if not existing) + if(this->map_.template is_embedded()) + { + // if incident vertex exists, reuse, otherwise create new + uint32 nv = incidentVertices[0].is_valid() ? this->map_.embedding(incidentVertices[0]) : vertex_container.insert_lines<1>() ; + mbuild.template set_embedding(d0, nv); + + nv = incidentVertices[1].is_valid() ? this->map_.embedding(incidentVertices[1]) : vertex_container.insert_lines<1>() ; + mbuild.template set_embedding(d1, nv); + + nv = incidentVertices[2].is_valid() ? this->map_.embedding(incidentVertices[2]) : vertex_container.insert_lines<1>() ; + mbuild.template set_embedding(d2, nv); + + nv = incidentVertices[3].is_valid() ? this->map_.embedding(incidentVertices[3]) : vertex_container.insert_lines<1>() ; + mbuild.template set_embedding(d3, nv); + } + +// const bool isVertexEmbedded = this->map_.template is_embedded() ; +// this->map_.foreach_incident_vertex(f0, +// [&] (Vertex v) +// { +// if (isVertexEmbedded) +// { +// uint32 nv = vertex_container.insert_lines<1>(); // TODO, only if not yet existing +// mbuild.template set_embedding(v.dart,nv); +// } +// }) ; + + // Label the darts + dart_orientation_[d0].value_ = S ; + dart_orientation_[d1].value_ = E ; + dart_orientation_[d2].value_ = N ; + dart_orientation_[d3].value_ = W ; + + return d0 ; + } + + + /** + * @brief sewFaceToAdjacentFaces sews face #f0 to the existing non-sewed adjacent faces #adjacentFaces + * @param mbuild + * @param f0 the face to sew + * @param adjacentFaces the adjacent faces, previously obtained by #getAdjacentFacesFromProvokingFace. + */ + void sewFaceToAdjacentFaces(MapBuilder& mbuild,const Face& f0, const std::array& adjacentFaces) + { + Dart d = f0.dart ; + for (uint o = S ; o <= W ; ++o) + { + const Face& fAdj = adjacentFaces[o] ; + if (fAdj.is_valid()) // if there's a face to be sewed in that direction + { + // Take opposite orientation of that face + const Orient oInv = Orient((o+2)%4) ; + const Dart dSew = getDartByOrient(fAdj,oInv) ;//getEdgeOfFace(adjacentFaces[dir],/*dart_orientation,*/(dir+2)%4).dart ; + mbuild.phi2_sew(d,dSew) ; + + // Set Edge embedding to that of the retrieved edge + // mbuild.template set_embedding(d, this->map_.embedding(eSew)); + // Set Vertex embedding to that of the retrieved Vertex + //mbuild.template set_embedding(d, this->map_.embedding(Vertex(this->map_.phi1(dSew)))); // TODO CHECK IF ALREADY DONE. ITS RATHER AN OPTIMISATION AS DOING TWICE DOESNT HURT + } + d = this->map_.phi1(d) ; // go to next + } + } + + // ------------------------ Tools: Find unsewed neighboring topo items -------------------------------- +private: + /** + * @brief getAdjacentFacesFromProvokingFace returns the existing unsewed south, east, north and west faces, respectively. If one of these (usually at least 2) is non-existing, the resturned faces are not valid. + * @param map the map + * @param dart_orientation the DartAttribute with edge type labels + * @param provokingFace one of the adjacent faces, i.e., the one that initiated the creation of the current face + * @param provokingDartDir the edge of #provokingFace to which the current face is neighboring + * @return array of 4 Faces, respectively south, east, north and west of the new face, or invalid faces if they are inexistant. + */ + std::array getAdjacentFacesFromProvokingFace(/*const DartAttribute& dart_orientation,*/ const Face& provokingFace, const Orient& provokingDartDir) + { + std::array neighbFaces ; + + switch(provokingDartDir) + { + case(S): + { + neighbFaces[2] = provokingFace ; // provokingFace is located north + + // Check to the West + const Face fNW = getFaceInOrient(provokingFace,/*dart_orientation,*/W) ; + if (fNW.is_valid()) + { + const Face fW = getFaceInOrient(fNW,/*dart_orientation,*/S) ; + if (fW.is_valid()) + { + neighbFaces[W] = fW ; + } + } + + // Check to the East + const Face fNE = getFaceInOrient(provokingFace,/*dart_orientation,*/E) ; + if (fNE.is_valid()) + { + const Face fE = getFaceInOrient(fNE,/*dart_orientation,*/S) ; + if (fE.is_valid()) + { + neighbFaces[E] = fE ; + } + } + } + break; + case(E): + { + neighbFaces[3] = provokingFace ; // provokingFace is located west + + // Check to the North + const Face fNW = getFaceInOrient(provokingFace,/*dart_orientation,*/N) ; + if (fNW.is_valid()) + { + const Face fN = getFaceInOrient(fNW,/*dart_orientation,*/E) ; + if (fN.is_valid()) + { + neighbFaces[N] = fN ; + } + } + + // Check to the South + const Face fSW = getFaceInOrient(provokingFace,/*dart_orientation,*/S) ; + if (fSW.is_valid()) + { + const Face fS = getFaceInOrient(fSW,/*dart_orientation,*/E) ; + if (fS.is_valid()) + { + neighbFaces[S] = fS ; + } + } + } + break; + case(N): + { + neighbFaces[0] = provokingFace ; // provokingFace is located south + + // Check to the West + const Face fSW = getFaceInOrient(provokingFace,/*dart_orientation,*/W) ; + if (fSW.is_valid()) + { + const Face fW = getFaceInOrient(fSW,/*dart_orientation,*/N) ; + if (fW.is_valid()) + { + neighbFaces[W] = fW ; + } + } + + // Check to the East + const Face fSE = getFaceInOrient(provokingFace,/*dart_orientation,*/E) ; + if (fSE.is_valid()) + { + const Face fE = getFaceInOrient(fSE,/*dart_orientation,*/N) ; + if (fE.is_valid()) + { + neighbFaces[E] = fE ; + } + } + } + break; + case(W): + { + neighbFaces[1] = provokingFace ; // provokingFace is located east + + // Check to the North + const Face fNE = getFaceInOrient(provokingFace,/*dart_orientation,*/N) ; + if (fNE.is_valid()) + { + const Face fN = getFaceInOrient(fNE,/*dart_orientation,*/W) ; + if (fN.is_valid()) + { + neighbFaces[N] = fN ; + } + } + + // Check to the South + const Face fSE = getFaceInOrient(provokingFace,/*dart_orientation,*/S) ; + if (fSE.is_valid()) + { + const Face fS = getFaceInOrient(fSE,/*dart_orientation,*/W) ; + if (fS.is_valid()) + { + neighbFaces[S] = fS ; + } + } + } + break; + case(INVALID_ORIENT): + cgogn_log_error("INVALID_ORIENT in switch") ; + break ; + } + + return neighbFaces ; + } + + /** + * @brief adjFaces2incVertices returns an array of existing (or invalid) vertices for the new face, given its pre-existing adjacent faces + * @param adjacentFaces the pre-existing adjacent faces + * @return array of vertices pre-existing vertices to embed the current face with, or invalid vertices otherwise. In counter-clock numbering order, starting from the reference vertex. + */ + std::array adjFaces2incVertices(const std::array& adjacentFaces) const + { + std::array incVertices ; + + if (adjacentFaces[0].is_valid()) // South + { + incVertices[0] = getVertexByNo(adjacentFaces[0],3) ; // Vx 3 of South face + incVertices[1] = getVertexByNo(adjacentFaces[0],2) ; // Vx 2 of South face + } + if (adjacentFaces[1].is_valid()) // East + { + incVertices[1] = getVertexByNo(adjacentFaces[1],0) ; // Vx 0 of East face + incVertices[2] = getVertexByNo(adjacentFaces[1],3) ; // Vx 3 of East face + } + if (adjacentFaces[2].is_valid()) // North + { + incVertices[2] = getVertexByNo(adjacentFaces[2],1) ; // Vx 1 of North face + incVertices[3] = getVertexByNo(adjacentFaces[2],0) ; // Vx 0 of North face + } + if (adjacentFaces[3].is_valid()) // West + { + incVertices[3] = getVertexByNo(adjacentFaces[3],2) ; // Vx 2 of West face + incVertices[0] = getVertexByNo(adjacentFaces[3],1) ; // Vx 1 of West face + } + + return incVertices ; + } + + // ------------------------ Tools: getR in a Face -------------------------------- +private: + /** + * @brief getRefVertex returns the reference vertex of a given face + * @param f the face + * @return the reference vertex (i.e., vertex 0, by convention). + */ + Vertex getRefVertex(const Face& f) const + { + return getVertexByNo(f,0) ; + } + + // Vertex getLeftBottomVertex(const VertexAttribute& position, const Face& f) + // { + // Vertex lbv = Vertex(f.dart) ; + // this->map_.foreach_incident_vertex(f, + // [&] (Vertex v) + // { + // const VEC& p = position[v] ; + // if (p[1] < position[lbv][1]) + // { + // lbv = v ; + // } + // else if (p[1] == position[lbv][1]) + // { + // if (p[0] < position[lbv][0]) + // { + // lbv = v ; + // } + // } + // }) ; + + // return lbv ; + // } + + /** + * @brief getVertexByNo returns the nth vertex of a face, in counterclockwise numbering starting from the reference vertex + * @param f the face + * @param no the vertex to fetch + * @return the requested vertex + */ + Vertex getVertexByNo(const Face& f, uint no) const + { + assert(no<4) ; + return Vertex(getDartByOrient(f,Orient(no))) ; + } + + /** + * @brief getDartByOrient returns the dart of a face oriented in a given target orientation + * @param f the face + * @param target_orient the orientation for which the dart needs to be returned + * @return the dart corresponding to the requested orientation in face #f + */ + const Dart getDartByOrient(const Face& f, const Orient& target_orient) const + { + Dart res ; + this->map_.foreach_dart_of_orbit(f, [&] (Dart d) -> bool + { + if (dart_orientation_[d].value_ == target_orient) + { + res = d ; + return false ; + } + return true ; + }); + + return res ; +// this->map_.foreach_incident_edge(f, +// [&] (Edge e) +// Dart d = f.dart ; +// for (uint i = 0 ; i < target_orient ; ++i) +// d = this->map_.phi1(d) ; + +// return d ; + } + + /** + * @brief getOrientOfDart tests if a given dart is in face #f, and returns its orientation is yes, INVALID_ORIENT otherwise + * @param d the dart + * @param f the face + * @return the orientation of the face, or INVALID_ORIENT if the dart is not in the face + */ + Orient getOrientOfDart(const Dart& d/*, const Face& f*/) const + { + return dart_orientation_[d].value_ ; + /*Orient res = INVALID_ORIENT ; + + Dart dd = f.dart ; + for (uint i = S ; i < W ; ++i) + { + if (d == dd) + { + res = Orient(i) ; + break ; + } + dd = this->map_.phi1(dd) ; + } + + return res ;*/ + } +// /** +// * @brief getVertexOfFace returns the vertex number vertexNo of Face f. +// * @param f +// * @param vertexNo +// * @return +// */ +// const Vertex getVertexOfFace(const Face& f, uint vertexNo) const +// { +// Dart d = f.dart ; +// for (uint i = 0 ; i < vertexNo ; ++i) +// d = this->map_.phi1(d) ; + +// return Vertex(d) ; +// } + + + // ------------------------ Tools: getR for adjacent Faces -------------------------------- +private: + + /** + * @brief getFaceInOrient tests if a given face #f has a neighboring sewed face to its #DartDirection direction. + * If yes, the Face returned is of the found face + * If no, the Face returned is invalid. + * @param f + * @param dart_orientation + * @param target_type + * @return a valid Face to the face found if it exists, an invalid dart otherwise. + */ + const Face getFaceInOrient(const Face& f/*, const DartAttribute& dart_orientation*/, const Orient& orientation) const + { + Face res ; + + const Dart& dTmp = getDartByOrient(f,orientation) ; /*getEdgeOfFace(f,dart_orientation,DartDirection).dart ;*/ + const Dart& dPhi2 = this->map_.phi2(dTmp) ; + if (dTmp != dPhi2) // if there is a neighboring face there + { + res = Face(dPhi2) ; + } + + return res ; + } + + // ------------------------ Random Tools -------------------------------- + bool is_border(Dart d) const + { + return this->map_.phi2(d) == d ; + } +}; + +} //namespace modeling + +} //namespace cgogn + +#endif // CGOGN_MODELING_TILING_PARALLELOGRAM_GRID_H diff --git a/cgogn/rendering/map_quad_render.cpp b/cgogn/rendering/map_quad_render.cpp index 8e873ef1..685ee6f6 100644 --- a/cgogn/rendering/map_quad_render.cpp +++ b/cgogn/rendering/map_quad_render.cpp @@ -48,39 +48,6 @@ MapQuadRender::draw() indices_buffers_->release(); } -//void MapQuadRender::draw(DrawingType prim) -//{ -// QOpenGLFunctions* ogl = QOpenGLContext::currentContext()->functions(); - -// indices_buffers_[prim]->bind(); -// switch (prim) -// { -// case POINTS: -// ogl->glDrawElements(GL_POINTS, nb_indices_[POINTS], GL_UNSIGNED_INT, 0); -// break; -// case LINES: -// ogl->glDrawElements(GL_LINES, nb_indices_[LINES], GL_UNSIGNED_INT, 0); -// break; -// case TRIANGLES: -// ogl->glDrawElements(GL_TRIANGLES, nb_indices_[TRIANGLES], GL_UNSIGNED_INT, 0); -// break; -// case BOUNDARY: -// switch (boundary_dimension_) -// { -// case 1: -// ogl->glDrawElements(GL_LINES, nb_indices_[BOUNDARY], GL_UNSIGNED_INT, 0); -// break; -// case 2: -// ogl->glDrawElements(GL_TRIANGLES, nb_indices_[TRIANGLES], GL_UNSIGNED_INT, 0); -// break; -// } -// break; -// default: -// break; -// } -// indices_buffers_[prim]->release(); -//} - } // namespace rendering } // namespace cgogn diff --git a/cgogn/rendering/map_quad_render.h b/cgogn/rendering/map_quad_render.h index cc5a4f79..8a43dac1 100644 --- a/cgogn/rendering/map_quad_render.h +++ b/cgogn/rendering/map_quad_render.h @@ -48,15 +48,6 @@ class CGOGN_RENDERING_API MapQuadRender { protected: -// // indices used for sorting -// std::vector> indices_tri_; -// std::vector indices_points_; - -// std::array, SIZE_BUFFER> indices_buffers_; -// std::array indices_buffers_uptodate_; -// std::array nb_indices_; -// uint8 boundary_dimension_; - std::unique_ptr indices_buffers_; uint32 nb_indices_; @@ -68,174 +59,8 @@ class CGOGN_RENDERING_API MapQuadRender ~MapQuadRender(); CGOGN_NOT_COPYABLE_NOR_MOVABLE(MapQuadRender); - - - - - -// inline bool is_primitive_uptodate(DrawingType prim) { return indices_buffers_uptodate_[prim]; } - -// inline void set_primitive_dirty(DrawingType prim) { indices_buffers_uptodate_[prim] = false; } - -//protected: - -// template -// inline void init_points(const MAP& m, const MASK& mask, std::vector& table_indices) -// { -//// table_indices.reserve(m.get_nb_darts() / 6); -// m.foreach_cell([&] (typename MAP::Vertex v) -// { -// table_indices.push_back(m.embedding(v)); -// }, -// mask); -// } - -// template -// inline void init_lines(const MAP& m, const MASK& mask, std::vector& table_indices) -// { -// using Vertex = typename MAP::Vertex; -// using Edge = typename MAP::Edge; - -//// table_indices.reserve(m.get_nb_darts() / 2); -// m.foreach_cell([&] (Edge e) -// { -// table_indices.push_back(m.embedding(Vertex(e.dart))); -// table_indices.push_back(m.embedding(Vertex(m.phi1(e.dart)))); -// }, -// mask); -// } - -// template -// inline void init_triangles(const MAP& m, const MASK& mask, std::vector& table_indices) -// { -// using Vertex = typename MAP::Vertex; -// using Face = typename MAP::Face; - -// // reserve more ? -//// table_indices.reserve(m.get_nb_darts() / 3); -// m.foreach_cell([&] (Face f) -// { -// Dart d0 = f.dart; -// Dart d1 = m.phi1(d0); -// Dart d2 = m.phi1(d1); -// do -// { -// table_indices.push_back(m.embedding(Vertex(d0))); -// table_indices.push_back(m.embedding(Vertex(d1))); -// table_indices.push_back(m.embedding(Vertex(d2))); -// d1 = d2; -// d2 = m.phi1(d1); -// } while(d2 != d0); -// }, -// mask); -// } - -// template -// inline void init_triangles_ear( -// const MAP& m, -// const MASK& mask, -// std::vector& table_indices, -// const typename MAP::template VertexAttribute* position -// ) -// { -// using Vertex = typename MAP::Vertex; -// using Face = typename MAP::Face; - -// // reserve more ? -//// table_indices.reserve(m.get_nb_darts() / 3); -// m.foreach_cell([&] (Face f) -// { -// if (m.has_codegree(f, 3)) -// { -// table_indices.push_back(m.embedding(Vertex(f.dart))); -// table_indices.push_back(m.embedding(Vertex(m.phi1(f.dart)))); -// table_indices.push_back(m.embedding(Vertex(m.phi1(m.phi1(f.dart))))); -// } -// else -// cgogn::geometry::append_ear_triangulation(m, f, *position, table_indices); -// }, -// mask); -// } - -// template -// inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) -// -> typename std::enable_if::value, void>::type -// { -// using Vertex = typename MAP::Vertex; -// using Edge = typename MAP::Edge; -// using Face = typename MAP::Face; - -// m.foreach_cell([&] (Face f) -// { -// m.foreach_incident_edge(f, [&] (Edge e) -// { -// table_indices.push_back(m.embedding(Vertex(e.dart))); -// table_indices.push_back(m.embedding(Vertex(m.phi1(e.dart)))); -// }); -// }, -// mask); - -// boundary_dimension_ = 1; -// } - -// template -// inline auto init_boundaries(const MAP& m, const MASK& /*mask*/, std::vector& table_indices) -// -> typename std::enable_if::value, void>::type -// { -// // if the given MASK is not a BoundaryCache, build a BoundaryCache and use it -// typename MAP::BoundaryCache bcache(m); -// init_boundaries(m, bcache, table_indices); -// } - -// template -// inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) -// -> typename std::enable_if::value, void>::type -// { -// using Vertex = typename MAP::Vertex; -// using Face = typename MAP::Face; -// using Volume = typename MAP::Volume; - -// m.foreach_cell([&] (Volume v) -// { -// m.foreach_incident_face(v, [&] (Face f) -// { -// Dart d0 = f.dart; -// Dart d1 = m.phi1(d0); -// Dart d2 = m.phi1(d1); -// do -// { -// table_indices.push_back(m.embedding(Vertex(d0))); -// table_indices.push_back(m.embedding(Vertex(d1))); -// table_indices.push_back(m.embedding(Vertex(d2))); -// d1 = d2; -// d2 = m.phi1(d1); -// } while(d2 != d0); -// }); -// }, -// mask); - -// boundary_dimension_ = 2; -// } - -// template -// inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) -// -> typename std::enable_if::value, void>::type -// { -// unused_parameters(mask); -// // if the given MASK is not a BoundaryCache, build a BoundaryCache and use it -// typename MAP::BoundaryCache bcache(m); -// init_boundaries(m, bcache, table_indices); -// } - -//public: - -// inline uint32 nb_indices(DrawingType prim) const -// { -// return nb_indices_[prim]; -// } - - template - inline void init_primitives(const MAP& m/*, const MASK& mask*/) + template + inline void init_primitives(const MAP& m) { using Vertex = typename MAP::Vertex; using Face = typename MAP::Face; @@ -252,9 +77,7 @@ class CGOGN_RENDERING_API MapQuadRender table_indices.push_back(m.embedding(Vertex(d1))); table_indices.push_back(m.embedding(Vertex(d2))); table_indices.push_back(m.embedding(Vertex(d3))); - } - /*, mask*/ - ); + }); if (!indices_buffers_->isCreated()) indices_buffers_->create(); @@ -265,218 +88,9 @@ class CGOGN_RENDERING_API MapQuadRender indices_buffers_->release(); } - -// template -// inline void init_primitives( -// const MAP& m, -// const MASK& mask, -// DrawingType prim, -// const typename MAP::template VertexAttribute* position -// ) -// { -// std::vector table_indices; - -// switch (prim) -// { -// case POINTS: -// init_points(m, mask, table_indices); -// indices_points_.clear(); -// break; -// case LINES: -// init_lines(m, mask, table_indices); -// break; -// case TRIANGLES: -// if (position) -// init_triangles_ear(m, mask, table_indices, position); -// else -// init_triangles(m, mask, table_indices); -// indices_tri_.clear(); -// break; -// case BOUNDARY: -// init_boundaries(m, mask, table_indices); -// break; -// default: -// break; -// } - -// if (!indices_buffers_[prim]->isCreated()) -// indices_buffers_[prim]->create(); - -// indices_buffers_uptodate_[prim] = true; -// nb_indices_[prim] = uint32(table_indices.size()); -// indices_buffers_[prim]->bind(); -// indices_buffers_[prim]->allocate(&(table_indices[0]), nb_indices_[prim] * sizeof(uint32)); -// indices_buffers_[prim]->release(); -// } - -// template -// inline void init_primitives( -// const MAP& m, -// DrawingType prim, -// const typename MAP::template VertexAttribute* position -// ) -// { -// init_primitives(m, AllCellsFilter(), prim, position); -// } - -// template -// inline void init_primitives( -// const MAP& m, -// const MASK& mask, -// DrawingType prim -// ) -// { -// std::vector table_indices; - -// switch (prim) -// { -// case POINTS: -// init_points(m, mask, table_indices); -// indices_points_.clear(); -// break; -// case LINES: -// init_lines(m, mask, table_indices); -// break; -// case TRIANGLES: -// init_triangles(m, mask, table_indices); -// indices_tri_.clear(); -// break; -// case BOUNDARY: -// init_boundaries(m, mask, table_indices); -// break; -// default: -// break; -// } - -// if (table_indices.empty()) -// return; - -// if (!indices_buffers_[prim]->isCreated()) -// indices_buffers_[prim]->create(); - -// indices_buffers_uptodate_[prim] = true; -// nb_indices_[prim] = uint32(table_indices.size()); -// indices_buffers_[prim]->bind(); -// indices_buffers_[prim]->allocate(&(table_indices[0]), nb_indices_[prim] * sizeof(uint32)); -// indices_buffers_[prim]->release(); -// } - -// template -// inline void init_primitives( -// const MAP& m, -// DrawingType prim -// ) -// { -// init_primitives(m, AllCellsFilter(), prim); -// } - void draw(); -// void draw(DrawingType prim); }; -///** -// * @brief transform position with modelview matrix -// * @param map -// * @param pos_in input position -// * @param pos_out transformed positions -// * @param view modelview matrix -// */ -//template -//void transform_position(const MAP& map, const typename MAP::template VertexAttribute& pos_in, typename MAP::template VertexAttribute& pos_out, const QMatrix4x4& view) -//{ -// map.template const_attribute_container().parallel_foreach_index( [&] (uint32 i, uint32) -// { -// QVector3D P = view.map(QVector3D(pos_in[i][0],pos_in[i][1],pos_in[i][2])); -// pos_out[i]= VEC3(P[0],P[1],P[2]); -// }); -//} - -///** -// * @brief create embedding indices of vertices and faces for each vertex of each face -// * @param m the map -// * @param position vertex positions use for ear triangulation -// * @param indices1 embedding indices of vertices -// * @param indices2 embedding indices of faces -// */ -//template -//void create_indices_vertices_faces( -// const MAP& m, -// const typename MAP::template VertexAttribute& position, -// std::vector& indices1, -// std::vector& indices2 -//) -//{ -// using Vertex = typename MAP::Vertex; -// using Face = typename MAP::Face; - -// indices1.reserve(m.nb_darts()); -// indices2.reserve(m.nb_darts()); -// indices1.clear(); -// indices2.clear(); - -// //local vector for ear triangulation -// std::vector local_vert_indices; -// local_vert_indices.reserve(256); - -// m.foreach_cell([&] (Face f) -// { -// uint32 ef = m.embedding(Face(f.dart)); -// if (m.has_codegree(f, 3)) -// { -// indices1.push_back(m.embedding(Vertex(f.dart))); -// indices1.push_back(m.embedding(Vertex(m.phi1(f.dart)))); -// indices1.push_back(m.embedding(Vertex(m.phi1(m.phi1(f.dart))))); -// indices2.push_back(ef); -// indices2.push_back(ef); -// indices2.push_back(ef); -// } -// else -// { -// cgogn::geometry::append_ear_triangulation(m, f, position, local_vert_indices); -// for (uint32 i : local_vert_indices) -// { -// indices1.push_back(i); -// indices2.push_back(ef); -// } -// } -// }); -//} - -//template -//void add_to_drawer(const MAP& m, typename MAP::Edge e, const typename MAP::template VertexAttribute& position, DisplayListDrawer* dr) -//{ -// using Vertex = typename MAP::Vertex; - -// dr->vertex3fv(position[Vertex(e.dart)]); -// dr->vertex3fv(position[Vertex(m.phi1(e.dart))]); -//} - -//template -//void add_to_drawer(const MAP& m, typename MAP::Face f, const typename MAP::template VertexAttribute& position, DisplayListDrawer* dr) -//{ -// using Vertex = typename MAP::Vertex; -// using Edge = typename MAP::Edge; - -// m.foreach_incident_edge(f, [&] (Edge e) -// { -// dr->vertex3fv(position[Vertex(e.dart)]); -// dr->vertex3fv(position[Vertex(m.phi1(e.dart))]); -// }); -//} - -//template -//void add_to_drawer(const MAP& m, typename MAP::Volume vo, const typename MAP::template VertexAttribute& position, DisplayListDrawer* dr) -//{ -// using Vertex = typename MAP::Vertex; -// using Edge = typename MAP::Edge; - -// m.foreach_incident_edge(vo, [&] (Edge e) -// { -// dr->vertex3fv(position[Vertex(e.dart)]); -// dr->vertex3fv(position[Vertex(m.phi1(e.dart))]); -// }); -//} - } // namespace rendering } // namespace cgogn From 4bee075db74b5f6624d2b70cab4fcea897e5e0c7 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Thu, 24 Aug 2017 16:36:48 +0200 Subject: [PATCH 06/26] code refactoring on parallelogram_grid --- cgogn/modeling/tiling/parallelogram_grid.cpp | 2 +- cgogn/modeling/tiling/parallelogram_grid.h | 209 ++++++++++--------- 2 files changed, 110 insertions(+), 101 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.cpp b/cgogn/modeling/tiling/parallelogram_grid.cpp index 68c1c4ee..6646d6e5 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.cpp +++ b/cgogn/modeling/tiling/parallelogram_grid.cpp @@ -31,7 +31,7 @@ namespace cgogn namespace modeling { -template class CGOGN_MODELING_API ParallelogramGrid; +//template class CGOGN_MODELING_API ParallelogramGrid; } // namespace modeling diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index 91fa04f4..069af5a0 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -1,11 +1,12 @@ #ifndef CGOGN_MODELING_TILING_PARALLELOGRAM_GRID_H #define CGOGN_MODELING_TILING_PARALLELOGRAM_GRID_H -#include -#include - +#include +#include +#include #include -#include + +#include namespace cgogn { @@ -13,10 +14,15 @@ namespace cgogn namespace modeling { +/** + * @brief The ParallelogramGrid class is a utility class to fill a rectangle with a tiling of parallelograms of a given size. + */ template - -class ParallelogramGrid : public Tiling +class ParallelogramGrid { + CGOGN_NOT_COPYABLE_NOR_MOVABLE(ParallelogramGrid); + +protected: using Map2 = cgogn::CMap2; using CDart = typename MAP::CDart; @@ -47,48 +53,67 @@ class ParallelogramGrid : public Tiling }; protected: + MAP& map_ ; + Dart dart_ ; + const VEC& p_ ; + const VEC& Ti_ ; + const VEC& Tj_ ; + const geometry::AABB& area_ ; + DartAttribute dart_orientation_ ; VertexAttribute vertex_position_ ; public: /** - * @brief ParallelogramGrid creates a mesh composed of a tiling of identical parallelograms. + * @brief ParallelogramGrid is a utility class for creating a tiling of parallelograms. + * @param map the CGoGN map that defines the mesh + * @param fill_area the area to tile + */ + ParallelogramGrid(MAP& map, const geometry::AABB& fill_area): + map_(map), + area_(fill_area) + {} + + /** + * @brief embed_with_parallelograms creates a mesh composed of a tiling of identical parallelograms. * Parallelograms are defined by two vectors (Ti,Tj). * The position of the left-bottom corner of one parallelogram is defined as being located at p. * The tiling is embedded geometrically and fills at least a rectangular area defined by the point RectOrigin and RectDiag. - * @param map the CGoGN map that defines the mesh. * @param p origin of the reference parallelogram * @param Ti first vector definining a parallelogram * @param Tj second vector definining a parallelogram - * @param fill_area rectangular area to fill withparallelograms * - * @pre p must lie in the bounding box #fill_area + * @pre p must lie in the area to fill (defined in the constructor #ParallelogramGrid) * @pre Ti[0] > 0 * @pre Tj[0] >=0 * @pre Tj[1] > Ti[1] + * + * @post the map is embedded with a VertexAttribute called "position". */ - ParallelogramGrid(MAP& map, const VEC& p, const VEC& Ti, const VEC& Tj, const geometry::AABB& fill_area): - Tiling(map) + void embed_with_parallelograms(const VEC& p, const VEC& Ti, const VEC& Tj) { - cgogn_assert(fill_area.contains(p)) ; + p_ = p ; + Ti_ = Ti ; + Tj_ = Tj ; + cgogn_assert(area_.contains(p)) ; - vertex_position_ = this->map_.template add_attribute("position") ; - dart_orientation_ = this->map_.template add_attribute("dartOrient"); + vertex_position_ = map_.template add_attribute("position") ; + dart_orientation_ = map_.template add_attribute("dartOrient"); - MapBuilder mbuild(map); + MapBuilder mbuild(map_); // Create face and update orbit embeddings std::array incidentVertices ; std::array adjacentFaces ; const Dart d0 = add_face_topo(mbuild, incidentVertices/*, dart_orientation*/) ; - this->dart_ = d0; + dart_ = d0; const Face f0 = Face(d0) ; // Embed vertices of face const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, f0, p, Ti, Tj) ; std::queue edgeQueue ; // list of edges to treat - queueFreeEdges(f0,edgeQueue, f_bbox, fill_area) ; + queueFreeEdges(f0,edgeQueue, f_bbox, area_) ; while(!edgeQueue.empty()) { @@ -101,7 +126,7 @@ class ParallelogramGrid : public Tiling // get Array of existing adjacent (neighboring) faces const Face provokingFace = Face(d) ; const Orient provokingFaceOrient = getOrientOfDart(d/*,provokingFace*/) ; - adjacentFaces = getAdjacentFacesFromProvokingFace(/*dart_orientation,*/provokingFace,provokingFaceOrient/*dart_orientation[e.dart].value_*/) ; + adjacentFaces = getAdjacentFacesFromProvokingFace(provokingFace,provokingFaceOrient/*dart_orientation[e.dart].value_*/) ; // Compute which incident vertices are already there incidentVertices = adjFaces2incVertices(adjacentFaces) ; @@ -140,7 +165,7 @@ class ParallelogramGrid : public Tiling // Embed new face's geometry const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, newFace, p_ref, Ti, Tj) ; // Add edges that are free - queueFreeEdges(newFace, edgeQueue, f_bbox, fill_area) ; + queueFreeEdges(newFace, edgeQueue, f_bbox, area_) ; } edgeQueue.pop() ; @@ -148,17 +173,17 @@ class ParallelogramGrid : public Tiling // close boundary mbuild.close_map() ; - cgogn_ensure(this->map_.check_embedding_integrity()) ; + cgogn_ensure(map_.check_embedding_integrity()) ; -// uint nbV = this->map_.template nb_cells(); -// uint nbF = this->map_.template nb_cells(); +// uint nbV = map_.template nb_cells(); +// uint nbF = map_.template nb_cells(); // std::cout << "Nb Vertices: " << nbV << std::endl ; // std::cout << "Nb Faces: " << nbF << std::endl ; } // Orient sew_FaceEdge(MapBuilder& mbuild, /*const DartAttribute& dart_orientation,*/ const Face& f0, const Edge& e0) // { -// cgogn_ensure(this->map_.phi2(e0.dart) == e0.dart) ; +// cgogn_ensure(map_.phi2(e0.dart) == e0.dart) ; // const DartDir& et = dart_orientation[e0] ; // Orient fSearchDartDir = INVALID_ORIENT ; @@ -182,7 +207,7 @@ class ParallelogramGrid : public Tiling // } // Edge to_sew ; -// this->map_.foreach_incident_edge(f0, +// map_.foreach_incident_edge(f0, // [&] (Edge e) -> bool // { // to_sew = e ; @@ -194,28 +219,28 @@ class ParallelogramGrid : public Tiling // const Dart& d1 = e0.dart ; // mbuild.phi2_sew(d0,d1) ; // // ensure embedding -// mbuild.template set_embedding(d1, this->map_.embedding(Vertex(this->map_.phi1(d0)))); +// mbuild.template set_embedding(d1, map_.embedding(Vertex(map_.phi1(d0)))); // return et.value_ ; // } +private: // ------------------------ Mesh construction algorithm -------------------------------- /** - * @brief queueFreeEdges adds the edges of face #f that are border edges of the mesh to the queue #edgeQueue iff #f_bbox intersects with the area to fill (#fill_area). + * @brief queueFreeEdges adds the edges of face #f that are border edges of the mesh to the queue #edgeQueue iff #f_bbox intersects with the area to fill (defined in the constructor). * @param f the face * @param edgeQueue the queue of edges to maintain * @param f_bbox bounding box of the current face - * @param fill_area the area to fill * @return */ - uint queueFreeEdges(const Face& f, std::queue& edgeQueue, const geometry::AABB& f_bbox, const geometry::AABB& fill_area) + uint queueFreeEdges(const Face& f, std::queue& edgeQueue, const geometry::AABB& f_bbox) { uint counter = 0 ; // if current face touches the Rectangle - if (fill_area.intersects(f_bbox)) + if (area_.intersects(f_bbox)) { // add all its edges to list of edges to treat - this->map_.foreach_incident_edge(f, + map_.foreach_incident_edge(f, [&] (Edge e) { if (is_border(e.dart)) // if it hasn't been sewed @@ -235,8 +260,6 @@ class ParallelogramGrid : public Tiling * @param position the Vertex position container * @param f the quad * @param p0 the reference vertex position - * @param Ti the first vector - * @param Tj the second vector * @pre f needs to be a quadrilateral and fully sewed * @pre position need be a valid vertex attribute. * @@ -245,18 +268,18 @@ class ParallelogramGrid : public Tiling geometry::AABB embed_parallelogram( typename MAP::template VertexAttribute& position, //typename MAP::template DartAttribute& dart_orientation, - const Face& f, const VEC& p0, const VEC& Ti, const VEC& Tj) + const Face& f, const VEC& p0) { const Dart d0 = f.dart ; - const Dart d1 = this->map_.phi1(d0) ; - const Dart d2 = this->map_.phi1(d1) ; - const Dart d3 = this->map_.phi1(d2) ; - cgogn_ensure(d0==this->map_.phi1(d3)) ; + const Dart d1 = map_.phi1(d0) ; + const Dart d2 = map_.phi1(d1) ; + const Dart d3 = map_.phi1(d2) ; + cgogn_ensure(d0==map_.phi1(d3)) ; position[Vertex(d0)] = p0 ; - position[Vertex(d1)] = p0 + Ti ; - position[Vertex(d2)] = position[d1] + Tj ; - position[Vertex(d3)] = p0 + Tj ; + position[Vertex(d1)] = p0 + Ti_ ; + position[Vertex(d2)] = position[d1] + Tj_ ; + position[Vertex(d3)] = p0 + Tj_ ; geometry::AABB bbox(p0) ; bbox.add_point(position[d1]) ; @@ -274,7 +297,7 @@ class ParallelogramGrid : public Tiling * @param incidentVertices contains existing vertices to link to, if any (invalid ones otherwise) * @return */ - Dart add_face_topo(MapBuilder& mbuild, const std::array& incidentVertices/*, const std::array& adjacentFaces, DartAttribute& dart_orientation*/) + Dart add_face_topo(MapBuilder& mbuild, const std::array& incidentVertices) { ChunkArrayContainer& dart_container = mbuild.template attribute_container(); ChunkArrayContainer& vertex_container = mbuild.template attribute_container(); @@ -282,23 +305,23 @@ class ParallelogramGrid : public Tiling // Create face const Dart d0 = mbuild.add_face_topo_fp(4u) ; // phi2 is fixed point - const Dart d1 = this->map_.phi1(d0) ; - const Dart d2 = this->map_.phi1(d1) ; - const Dart d3 = this->map_.phi1(d2) ; + const Dart d1 = map_.phi1(d0) ; + const Dart d2 = map_.phi1(d1) ; + const Dart d3 = map_.phi1(d2) ; // Create new orbit embeddings for all embedded orbits. // This FACE const Face f0 = Face(d0) ; - if(this->map_.template is_embedded()) + if(map_.template is_embedded()) { uint32 nf = face_container.insert_lines<1>(); mbuild.template set_embedding(f0.dart,nf); } // All DART of this face - if(this->map_.template is_embedded()) + if(map_.template is_embedded()) { - this->map_.foreach_dart_of_orbit(f0, [&] (Dart d) + map_.foreach_dart_of_orbit(f0, [&] (Dart d) { uint32 nd = dart_container.insert_lines<1>() ; mbuild.template set_embedding(d,nd); @@ -306,24 +329,24 @@ class ParallelogramGrid : public Tiling } // All VERTEX of this face (if not existing) - if(this->map_.template is_embedded()) + if(map_.template is_embedded()) { // if incident vertex exists, reuse, otherwise create new - uint32 nv = incidentVertices[0].is_valid() ? this->map_.embedding(incidentVertices[0]) : vertex_container.insert_lines<1>() ; + uint32 nv = incidentVertices[0].is_valid() ? map_.embedding(incidentVertices[0]) : vertex_container.insert_lines<1>() ; mbuild.template set_embedding(d0, nv); - nv = incidentVertices[1].is_valid() ? this->map_.embedding(incidentVertices[1]) : vertex_container.insert_lines<1>() ; + nv = incidentVertices[1].is_valid() ? map_.embedding(incidentVertices[1]) : vertex_container.insert_lines<1>() ; mbuild.template set_embedding(d1, nv); - nv = incidentVertices[2].is_valid() ? this->map_.embedding(incidentVertices[2]) : vertex_container.insert_lines<1>() ; + nv = incidentVertices[2].is_valid() ? map_.embedding(incidentVertices[2]) : vertex_container.insert_lines<1>() ; mbuild.template set_embedding(d2, nv); - nv = incidentVertices[3].is_valid() ? this->map_.embedding(incidentVertices[3]) : vertex_container.insert_lines<1>() ; + nv = incidentVertices[3].is_valid() ? map_.embedding(incidentVertices[3]) : vertex_container.insert_lines<1>() ; mbuild.template set_embedding(d3, nv); } -// const bool isVertexEmbedded = this->map_.template is_embedded() ; -// this->map_.foreach_incident_vertex(f0, +// const bool isVertexEmbedded = map_.template is_embedded() ; +// map_.foreach_incident_vertex(f0, // [&] (Vertex v) // { // if (isVertexEmbedded) @@ -359,15 +382,15 @@ class ParallelogramGrid : public Tiling { // Take opposite orientation of that face const Orient oInv = Orient((o+2)%4) ; - const Dart dSew = getDartByOrient(fAdj,oInv) ;//getEdgeOfFace(adjacentFaces[dir],/*dart_orientation,*/(dir+2)%4).dart ; + const Dart dSew = getDartByOrient(fAdj,oInv) ; mbuild.phi2_sew(d,dSew) ; // Set Edge embedding to that of the retrieved edge - // mbuild.template set_embedding(d, this->map_.embedding(eSew)); + // mbuild.template set_embedding(d, map_.embedding(eSew)); // Set Vertex embedding to that of the retrieved Vertex - //mbuild.template set_embedding(d, this->map_.embedding(Vertex(this->map_.phi1(dSew)))); // TODO CHECK IF ALREADY DONE. ITS RATHER AN OPTIMISATION AS DOING TWICE DOESNT HURT + //mbuild.template set_embedding(d, map_.embedding(Vertex(map_.phi1(dSew)))); // TODO CHECK IF ALREADY DONE. ITS RATHER AN OPTIMISATION AS DOING TWICE DOESNT HURT } - d = this->map_.phi1(d) ; // go to next + d = map_.phi1(d) ; // go to next } } @@ -381,7 +404,7 @@ class ParallelogramGrid : public Tiling * @param provokingDartDir the edge of #provokingFace to which the current face is neighboring * @return array of 4 Faces, respectively south, east, north and west of the new face, or invalid faces if they are inexistant. */ - std::array getAdjacentFacesFromProvokingFace(/*const DartAttribute& dart_orientation,*/ const Face& provokingFace, const Orient& provokingDartDir) + std::array getAdjacentFacesFromProvokingFace(const Face& provokingFace, const Orient& provokingDartDir) { std::array neighbFaces ; @@ -392,10 +415,10 @@ class ParallelogramGrid : public Tiling neighbFaces[2] = provokingFace ; // provokingFace is located north // Check to the West - const Face fNW = getFaceInOrient(provokingFace,/*dart_orientation,*/W) ; + const Face fNW = getFaceInOrient(provokingFace,W) ; if (fNW.is_valid()) { - const Face fW = getFaceInOrient(fNW,/*dart_orientation,*/S) ; + const Face fW = getFaceInOrient(fNW,S) ; if (fW.is_valid()) { neighbFaces[W] = fW ; @@ -403,10 +426,10 @@ class ParallelogramGrid : public Tiling } // Check to the East - const Face fNE = getFaceInOrient(provokingFace,/*dart_orientation,*/E) ; + const Face fNE = getFaceInOrient(provokingFace,E) ; if (fNE.is_valid()) { - const Face fE = getFaceInOrient(fNE,/*dart_orientation,*/S) ; + const Face fE = getFaceInOrient(fNE,S) ; if (fE.is_valid()) { neighbFaces[E] = fE ; @@ -419,10 +442,10 @@ class ParallelogramGrid : public Tiling neighbFaces[3] = provokingFace ; // provokingFace is located west // Check to the North - const Face fNW = getFaceInOrient(provokingFace,/*dart_orientation,*/N) ; + const Face fNW = getFaceInOrient(provokingFace,N) ; if (fNW.is_valid()) { - const Face fN = getFaceInOrient(fNW,/*dart_orientation,*/E) ; + const Face fN = getFaceInOrient(fNW,E) ; if (fN.is_valid()) { neighbFaces[N] = fN ; @@ -430,10 +453,10 @@ class ParallelogramGrid : public Tiling } // Check to the South - const Face fSW = getFaceInOrient(provokingFace,/*dart_orientation,*/S) ; + const Face fSW = getFaceInOrient(provokingFace,S) ; if (fSW.is_valid()) { - const Face fS = getFaceInOrient(fSW,/*dart_orientation,*/E) ; + const Face fS = getFaceInOrient(fSW,E) ; if (fS.is_valid()) { neighbFaces[S] = fS ; @@ -446,10 +469,10 @@ class ParallelogramGrid : public Tiling neighbFaces[0] = provokingFace ; // provokingFace is located south // Check to the West - const Face fSW = getFaceInOrient(provokingFace,/*dart_orientation,*/W) ; + const Face fSW = getFaceInOrient(provokingFace,W) ; if (fSW.is_valid()) { - const Face fW = getFaceInOrient(fSW,/*dart_orientation,*/N) ; + const Face fW = getFaceInOrient(fSW,N) ; if (fW.is_valid()) { neighbFaces[W] = fW ; @@ -457,10 +480,10 @@ class ParallelogramGrid : public Tiling } // Check to the East - const Face fSE = getFaceInOrient(provokingFace,/*dart_orientation,*/E) ; + const Face fSE = getFaceInOrient(provokingFace,E) ; if (fSE.is_valid()) { - const Face fE = getFaceInOrient(fSE,/*dart_orientation,*/N) ; + const Face fE = getFaceInOrient(fSE,N) ; if (fE.is_valid()) { neighbFaces[E] = fE ; @@ -473,10 +496,10 @@ class ParallelogramGrid : public Tiling neighbFaces[1] = provokingFace ; // provokingFace is located east // Check to the North - const Face fNE = getFaceInOrient(provokingFace,/*dart_orientation,*/N) ; + const Face fNE = getFaceInOrient(provokingFace,N) ; if (fNE.is_valid()) { - const Face fN = getFaceInOrient(fNE,/*dart_orientation,*/W) ; + const Face fN = getFaceInOrient(fNE,W) ; if (fN.is_valid()) { neighbFaces[N] = fN ; @@ -484,10 +507,10 @@ class ParallelogramGrid : public Tiling } // Check to the South - const Face fSE = getFaceInOrient(provokingFace,/*dart_orientation,*/S) ; + const Face fSE = getFaceInOrient(provokingFace,S) ; if (fSE.is_valid()) { - const Face fS = getFaceInOrient(fSE,/*dart_orientation,*/W) ; + const Face fS = getFaceInOrient(fSE,W) ; if (fS.is_valid()) { neighbFaces[S] = fS ; @@ -551,7 +574,7 @@ class ParallelogramGrid : public Tiling // Vertex getLeftBottomVertex(const VertexAttribute& position, const Face& f) // { // Vertex lbv = Vertex(f.dart) ; - // this->map_.foreach_incident_vertex(f, + // map_.foreach_incident_vertex(f, // [&] (Vertex v) // { // const VEC& p = position[v] ; @@ -592,7 +615,7 @@ class ParallelogramGrid : public Tiling const Dart getDartByOrient(const Face& f, const Orient& target_orient) const { Dart res ; - this->map_.foreach_dart_of_orbit(f, [&] (Dart d) -> bool + map_.foreach_dart_of_orbit(f, [&] (Dart d) -> bool { if (dart_orientation_[d].value_ == target_orient) { @@ -603,11 +626,11 @@ class ParallelogramGrid : public Tiling }); return res ; -// this->map_.foreach_incident_edge(f, +// map_.foreach_incident_edge(f, // [&] (Edge e) // Dart d = f.dart ; // for (uint i = 0 ; i < target_orient ; ++i) -// d = this->map_.phi1(d) ; +// d = map_.phi1(d) ; // return d ; } @@ -618,23 +641,9 @@ class ParallelogramGrid : public Tiling * @param f the face * @return the orientation of the face, or INVALID_ORIENT if the dart is not in the face */ - Orient getOrientOfDart(const Dart& d/*, const Face& f*/) const + Orient getOrientOfDart(const Dart& d) const { return dart_orientation_[d].value_ ; - /*Orient res = INVALID_ORIENT ; - - Dart dd = f.dart ; - for (uint i = S ; i < W ; ++i) - { - if (d == dd) - { - res = Orient(i) ; - break ; - } - dd = this->map_.phi1(dd) ; - } - - return res ;*/ } // /** // * @brief getVertexOfFace returns the vertex number vertexNo of Face f. @@ -646,7 +655,7 @@ class ParallelogramGrid : public Tiling // { // Dart d = f.dart ; // for (uint i = 0 ; i < vertexNo ; ++i) -// d = this->map_.phi1(d) ; +// d = map_.phi1(d) ; // return Vertex(d) ; // } @@ -664,12 +673,12 @@ class ParallelogramGrid : public Tiling * @param target_type * @return a valid Face to the face found if it exists, an invalid dart otherwise. */ - const Face getFaceInOrient(const Face& f/*, const DartAttribute& dart_orientation*/, const Orient& orientation) const + const Face getFaceInOrient(const Face& f, const Orient& orientation) const { Face res ; - const Dart& dTmp = getDartByOrient(f,orientation) ; /*getEdgeOfFace(f,dart_orientation,DartDirection).dart ;*/ - const Dart& dPhi2 = this->map_.phi2(dTmp) ; + const Dart& dTmp = getDartByOrient(f,orientation) ; + const Dart& dPhi2 = map_.phi2(dTmp) ; if (dTmp != dPhi2) // if there is a neighboring face there { res = Face(dPhi2) ; @@ -681,7 +690,7 @@ class ParallelogramGrid : public Tiling // ------------------------ Random Tools -------------------------------- bool is_border(Dart d) const { - return this->map_.phi2(d) == d ; + return map_.phi2(d) == d ; } }; From 7e6a4e7d5ef4c8f438ef9c8f4e30c94d8da1bc5b Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Thu, 24 Aug 2017 16:46:01 +0200 Subject: [PATCH 07/26] code refactoring on parallelogram_grid --- cgogn/modeling/tiling/parallelogram_grid.h | 24 ++++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index 069af5a0..2f1c90e5 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -55,11 +55,12 @@ class ParallelogramGrid protected: MAP& map_ ; Dart dart_ ; - const VEC& p_ ; - const VEC& Ti_ ; - const VEC& Tj_ ; const geometry::AABB& area_ ; + VEC p_ ; + VEC Ti_ ; + VEC Tj_ ; + DartAttribute dart_orientation_ ; VertexAttribute vertex_position_ ; @@ -97,8 +98,13 @@ class ParallelogramGrid Tj_ = Tj ; cgogn_assert(area_.contains(p)) ; - vertex_position_ = map_.template add_attribute("position") ; - dart_orientation_ = map_.template add_attribute("dartOrient"); + vertex_position_ = map_.template get_attribute("position") ; + if (!vertex_position_.is_valid()) + vertex_position_ = map_.template add_attribute("position") ; + + dart_orientation_ = map_.template get_attribute("dartOrient"); + if (!dart_orientation_.is_valid()) + dart_orientation_ = map_.template add_attribute("dartOrient"); MapBuilder mbuild(map_); @@ -110,10 +116,10 @@ class ParallelogramGrid const Face f0 = Face(d0) ; // Embed vertices of face - const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, f0, p, Ti, Tj) ; + const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, f0, p) ; std::queue edgeQueue ; // list of edges to treat - queueFreeEdges(f0,edgeQueue, f_bbox, area_) ; + queueFreeEdges(f0,edgeQueue,f_bbox) ; while(!edgeQueue.empty()) { @@ -163,9 +169,9 @@ class ParallelogramGrid } // Embed new face's geometry - const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, newFace, p_ref, Ti, Tj) ; + const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, newFace, p_ref) ; // Add edges that are free - queueFreeEdges(newFace, edgeQueue, f_bbox, area_) ; + queueFreeEdges(newFace, edgeQueue, f_bbox) ; } edgeQueue.pop() ; From 4abd9c55ef3a4e2cdbb1ebfa05ad02dc5bcad419 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Tue, 12 Sep 2017 16:27:00 +0200 Subject: [PATCH 08/26] integrate MapQuadRender into MapRender with an enum QUAD --- cgogn/modeling/tiling/parallelogram_grid.cpp | 2 +- cgogn/modeling/tiling/parallelogram_grid.h | 114 ++++++++++++++++--- cgogn/rendering/map_quad_render.cpp | 53 --------- cgogn/rendering/map_quad_render.h | 98 ---------------- cgogn/rendering/map_render.cpp | 3 + cgogn/rendering/map_render.h | 23 ++++ 6 files changed, 123 insertions(+), 170 deletions(-) delete mode 100644 cgogn/rendering/map_quad_render.cpp delete mode 100644 cgogn/rendering/map_quad_render.h diff --git a/cgogn/modeling/tiling/parallelogram_grid.cpp b/cgogn/modeling/tiling/parallelogram_grid.cpp index 6646d6e5..8efcfa8a 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.cpp +++ b/cgogn/modeling/tiling/parallelogram_grid.cpp @@ -21,7 +21,7 @@ * * *******************************************************************************/ -#define CGOGN_MODELING_TILING_SQUARE_GRID_CPP_ +#define CGOGN_MODELING_TILING_PARALLELOGRAM_GRID_CPP_ #include diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index 2f1c90e5..6b19c505 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -14,6 +14,89 @@ namespace cgogn namespace modeling { +template +class Parallelogram +{ +private: + VEC p_ ; + VEC Ti_ ; + VEC Tj_ ; +public: + Parallelogram() + { + p_ = VEC::Zero() ; + Ti_ = VEC::Zero() ; + Ti_[0] = 1.0 ; + Tj_ = VEC::Zero() ; + Tj_[1] = 1.0 ; + } + + Parallelogram(const VEC& p0, const VEC& p1, const VEC& p2, const VEC& p3) + { + init(p0,p1-p0,p3-p0) ; + } + + Parallelogram(const VEC& p, const VEC& Ti, const VEC& Tj) + { + init(p,Ti,Tj) ; + } + + Parallelogram(const VEC& p, const double& mag_i, const double& alpha_i, const double& mag_j, const double& alpha_j ) + { + VEC Ti,Tj ; + Ti[0] = mag_i*sin(alpha_i) ; + Ti[1] = -mag_i*cos(alpha_i) ; + Tj[0] = mag_j*sin(alpha_j) ; + Tj[1] = -mag_j*cos(alpha_j) ; + init(p,Ti,Tj) ; + } + + const VEC& getRefPos() const + { + return p_ ; + } + + const VEC& getTi() const + { + return Ti_ ; + } + + const VEC& getTj() const + { + return Tj_ ; + } + + uint sample_parallelograms(std::vector& samples, uint p_bins, uint mag_i_bins, uint alpha_i_bins, uint mag_j_bins, uint alpha_j_bins) const + { + samples.clear() ; + + + // TODO + assert(false) ; + + + return samples.size() ; + } + +private: + void init(const VEC& p, const VEC& Ti, const VEC& Tj) + { + p_ = p ; + Ti_ = Ti ; + Tj_ = Tj ; + cgogn_assert(is_valid()) ; + if (!is_valid()) + cgogn_log_error("Parallelogram::init") << "Attempt to create an invalid Parallelogram."; + } + + bool is_valid() const + { + bool res = Ti_[0] > 0 && Tj_[0] >= 0 && Tj_[1] > Ti_[1] ; + cgogn_assert((acos(-Tj_[1] / Tj_.norm()) > acos(-Ti_[1] / Ti_.norm())) == res) ; + return res && p_.norm() > 1e-10 && Ti_.norm() > 1e-10 && Tj_.norm() > 1e-10 ; + } +}; + /** * @brief The ParallelogramGrid class is a utility class to fill a rectangle with a tiling of parallelograms of a given size. */ @@ -21,7 +104,6 @@ template class ParallelogramGrid { CGOGN_NOT_COPYABLE_NOR_MOVABLE(ParallelogramGrid); - protected: using Map2 = cgogn::CMap2; @@ -57,9 +139,7 @@ class ParallelogramGrid Dart dart_ ; const geometry::AABB& area_ ; - VEC p_ ; - VEC Ti_ ; - VEC Tj_ ; + Parallelogram p_ ; DartAttribute dart_orientation_ ; VertexAttribute vertex_position_ ; @@ -91,12 +171,10 @@ class ParallelogramGrid * * @post the map is embedded with a VertexAttribute called "position". */ - void embed_with_parallelograms(const VEC& p, const VEC& Ti, const VEC& Tj) + void embed_with_parallelograms(const VEC& fixed_point, const VEC& Ti, const VEC& Tj) { - p_ = p ; - Ti_ = Ti ; - Tj_ = Tj ; - cgogn_assert(area_.contains(p)) ; + cgogn_assert(area_.contains(fixed_point)) ; + p_ = Parallelogram(fixed_point,Ti,Tj) ; ; vertex_position_ = map_.template get_attribute("position") ; if (!vertex_position_.is_valid()) @@ -116,7 +194,7 @@ class ParallelogramGrid const Face f0 = Face(d0) ; // Embed vertices of face - const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, f0, p) ; + const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, f0, p_.getRefPos()) ; std::queue edgeQueue ; // list of edges to treat queueFreeEdges(f0,edgeQueue,f_bbox) ; @@ -152,16 +230,16 @@ class ParallelogramGrid switch(provokingFaceOrient) { case(S): - p_ref -= Tj ; + p_ref -= p_.getTj() ; break ; case(E): - p_ref += Ti ; + p_ref += p_.getTi() ; break ; case(N): - p_ref += Tj ; + p_ref += p_.getTj() ; break ; case(W): - p_ref -= Ti ; + p_ref -= p_.getTi() ; break ; case(INVALID_ORIENT): cgogn_log_error("INVALID_ORIENT in switch") ; @@ -249,7 +327,7 @@ class ParallelogramGrid map_.foreach_incident_edge(f, [&] (Edge e) { - if (is_border(e.dart)) // if it hasn't been sewed + if (is_border(e.dart)) // if it hasn't been sewed yet { edgeQueue.push(e); ++counter ; @@ -283,9 +361,9 @@ class ParallelogramGrid cgogn_ensure(d0==map_.phi1(d3)) ; position[Vertex(d0)] = p0 ; - position[Vertex(d1)] = p0 + Ti_ ; - position[Vertex(d2)] = position[d1] + Tj_ ; - position[Vertex(d3)] = p0 + Tj_ ; + position[Vertex(d1)] = p0 + p_.getTi() ; + position[Vertex(d2)] = position[d1] + p_.getTj() ; + position[Vertex(d3)] = p0 + p_.getTj() ; geometry::AABB bbox(p0) ; bbox.add_point(position[d1]) ; diff --git a/cgogn/rendering/map_quad_render.cpp b/cgogn/rendering/map_quad_render.cpp deleted file mode 100644 index 685ee6f6..00000000 --- a/cgogn/rendering/map_quad_render.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* -* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * -* Copyright (C) 2015, IGG Group, ICube, University of Strasbourg, France * -* * -* This library is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by the * -* Free Software Foundation; either version 2.1 of the License, or (at your * -* option) any later version. * -* * -* This library 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 Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this library; if not, write to the Free Software Foundation, * -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * -* * -* Web site: http://cgogn.unistra.fr/ * -* Contact information: cgogn@unistra.fr * -* * -*******************************************************************************/ - - -#include - -namespace cgogn -{ - -namespace rendering -{ - -MapQuadRender::MapQuadRender() -{ - indices_buffers_ = make_unique(QOpenGLBuffer::IndexBuffer); - indices_buffers_->setUsagePattern(QOpenGLBuffer::StaticDraw); -} - -MapQuadRender::~MapQuadRender() -{} - -void -MapQuadRender::draw() -{ - QOpenGLFunctions* ogl = QOpenGLContext::currentContext()->functions(); - indices_buffers_->bind(); - ogl->glDrawElements(GL_LINES_ADJACENCY, nb_indices_, GL_UNSIGNED_INT, 0); - indices_buffers_->release(); -} - -} // namespace rendering - -} // namespace cgogn diff --git a/cgogn/rendering/map_quad_render.h b/cgogn/rendering/map_quad_render.h deleted file mode 100644 index 8a43dac1..00000000 --- a/cgogn/rendering/map_quad_render.h +++ /dev/null @@ -1,98 +0,0 @@ - -/******************************************************************************* -* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * -* Copyright (C) 2015, IGG Group, ICube, University of Strasbourg, France * -* * -* This library is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by the * -* Free Software Foundation; either version 2.1 of the License, or (at your * -* option) any later version. * -* * -* This library 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 Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this library; if not, write to the Free Software Foundation, * -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * -* * -* Web site: http://cgogn.unistra.fr/ * -* Contact information: cgogn@unistra.fr * -* * -*******************************************************************************/ - -#ifndef CGOGN_RENDERING_MAP_RENDER_QUAD_H_ -#define CGOGN_RENDERING_MAP_RENDER_QUAD_H_ - -#include - -#include // impossible to include directly attribute.h ! - -#include - -#include -#include - -#include -#include - -namespace cgogn -{ - -namespace rendering -{ - - -class CGOGN_RENDERING_API MapQuadRender -{ -protected: - - std::unique_ptr indices_buffers_; - uint32 nb_indices_; - -public: - - using Self = MapQuadRender; - - MapQuadRender(); - ~MapQuadRender(); - CGOGN_NOT_COPYABLE_NOR_MOVABLE(MapQuadRender); - - template - inline void init_primitives(const MAP& m) - { - using Vertex = typename MAP::Vertex; - using Face = typename MAP::Face; - - std::vector table_indices; - - m.foreach_cell([&] (Face f) - { - Dart d0 = f.dart; - Dart d1 = m.phi1(d0); - Dart d2 = m.phi1(d1); - Dart d3 = m.phi1(d2); - table_indices.push_back(m.embedding(Vertex(d0))); - table_indices.push_back(m.embedding(Vertex(d1))); - table_indices.push_back(m.embedding(Vertex(d2))); - table_indices.push_back(m.embedding(Vertex(d3))); - }); - - if (!indices_buffers_->isCreated()) - indices_buffers_->create(); - - nb_indices_ = uint32(table_indices.size()); - indices_buffers_->bind(); - indices_buffers_->allocate(table_indices.data(), nb_indices_ * sizeof(uint32)); - indices_buffers_->release(); - } - - void draw(); -}; - -} // namespace rendering - -} // namespace cgogn - -#endif // CGOGN_RENDERING_MAP_RENDER_QUAD_H_ diff --git a/cgogn/rendering/map_render.cpp b/cgogn/rendering/map_render.cpp index 70f065d7..46d2ea62 100644 --- a/cgogn/rendering/map_render.cpp +++ b/cgogn/rendering/map_render.cpp @@ -59,6 +59,9 @@ void MapRender::draw(DrawingType prim) case TRIANGLES: ogl->glDrawElements(GL_TRIANGLES, nb_indices_[TRIANGLES], GL_UNSIGNED_INT, 0); break; + case QUAD: + ogl->glDrawElements(GL_LINES_ADJACENCY, nb_indices_[QUAD], GL_UNSIGNED_INT, 0); + break; case BOUNDARY: switch (boundary_dimension_) { diff --git a/cgogn/rendering/map_render.h b/cgogn/rendering/map_render.h index 4b5505da..4e563fe4 100644 --- a/cgogn/rendering/map_render.h +++ b/cgogn/rendering/map_render.h @@ -48,6 +48,7 @@ enum DrawingType POINTS = 0, LINES, TRIANGLES, + QUAD, BOUNDARY, SIZE_BUFFER }; @@ -157,6 +158,26 @@ class CGOGN_RENDERING_API MapRender mask); } + template + inline void init_quad(const MAP& m, const MASK& mask, std::vector& table_indices) + { + using Vertex = typename MAP::Vertex; + using Face = typename MAP::Face; + + m.foreach_cell([&] (Face f) + { + Dart d0 = f.dart; + Dart d1 = m.phi1(d0); + Dart d2 = m.phi1(d1); + Dart d3 = m.phi1(d2); + table_indices.push_back(m.embedding(Vertex(d0))); + table_indices.push_back(m.embedding(Vertex(d1))); + table_indices.push_back(m.embedding(Vertex(d2))); + table_indices.push_back(m.embedding(Vertex(d3))); + }, + mask); + } + template inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) -> typename std::enable_if::value, void>::type @@ -261,6 +282,8 @@ class CGOGN_RENDERING_API MapRender init_triangles(m, mask, table_indices); indices_tri_.clear(); break; + case QUAD: + init_quad(m, mask, table_indices) ; case BOUNDARY: init_boundaries(m, mask, table_indices); break; From ff110a127639f2e5ea858f26162777ebe9d896e9 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Tue, 12 Sep 2017 16:28:35 +0200 Subject: [PATCH 09/26] update CMakeList accordingly --- cgogn/rendering/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/cgogn/rendering/CMakeLists.txt b/cgogn/rendering/CMakeLists.txt index 4cf0fe8b..8cf9fd12 100644 --- a/cgogn/rendering/CMakeLists.txt +++ b/cgogn/rendering/CMakeLists.txt @@ -51,7 +51,6 @@ set(HEADER_FILES topo_drawer.h volume_drawer.h map_render.h - map_quad_render.h wall_paper.h frame_manipulator.h ${HEADER_SHADERS} @@ -79,7 +78,6 @@ set(SOURCE_FILES topo_drawer.cpp volume_drawer.cpp map_render.cpp - map_quad_render.cpp wall_paper.cpp frame_manipulator.cpp ${SOURCE_SHADERS} From ad235541f834cb513e154a5c322372fda2c6e085 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Tue, 12 Sep 2017 17:50:34 +0200 Subject: [PATCH 10/26] add missing break; instruction --- cgogn/rendering/map_render.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cgogn/rendering/map_render.h b/cgogn/rendering/map_render.h index fe9527a6..9a99ef51 100644 --- a/cgogn/rendering/map_render.h +++ b/cgogn/rendering/map_render.h @@ -285,6 +285,7 @@ class CGOGN_RENDERING_API MapRender break; case QUAD: init_quad(m, mask, table_indices) ; + break; case BOUNDARY: init_boundaries(m, mask, table_indices); break; From a099b06242c7c7a2391e32418bf3f43b765ab9ad Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Tue, 12 Sep 2017 18:13:06 +0200 Subject: [PATCH 11/26] change spaces to tabs --- cgogn/modeling/tiling/parallelogram_grid.h | 1498 ++++++++++---------- cgogn/rendering/map_render.cpp | 6 +- cgogn/rendering/map_render.h | 114 +- 3 files changed, 830 insertions(+), 788 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index 6b19c505..e639dff0 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -14,87 +14,129 @@ namespace cgogn namespace modeling { +/** + * @brief The Parallelogram class. + * Defines a parallelogram by a point and two vectors. + */ template class Parallelogram { private: - VEC p_ ; - VEC Ti_ ; - VEC Tj_ ; + VEC p_ ; + VEC Ti_ ; + VEC Tj_ ; public: - Parallelogram() - { - p_ = VEC::Zero() ; - Ti_ = VEC::Zero() ; - Ti_[0] = 1.0 ; - Tj_ = VEC::Zero() ; - Tj_[1] = 1.0 ; - } - - Parallelogram(const VEC& p0, const VEC& p1, const VEC& p2, const VEC& p3) - { - init(p0,p1-p0,p3-p0) ; - } - - Parallelogram(const VEC& p, const VEC& Ti, const VEC& Tj) - { - init(p,Ti,Tj) ; - } - - Parallelogram(const VEC& p, const double& mag_i, const double& alpha_i, const double& mag_j, const double& alpha_j ) - { - VEC Ti,Tj ; - Ti[0] = mag_i*sin(alpha_i) ; - Ti[1] = -mag_i*cos(alpha_i) ; - Tj[0] = mag_j*sin(alpha_j) ; - Tj[1] = -mag_j*cos(alpha_j) ; - init(p,Ti,Tj) ; - } - - const VEC& getRefPos() const - { - return p_ ; - } - - const VEC& getTi() const - { - return Ti_ ; - } - - const VEC& getTj() const - { - return Tj_ ; - } - - uint sample_parallelograms(std::vector& samples, uint p_bins, uint mag_i_bins, uint alpha_i_bins, uint mag_j_bins, uint alpha_j_bins) const - { - samples.clear() ; - - - // TODO - assert(false) ; - - - return samples.size() ; - } + /** + * @brief Parallelogram Default constructor: p(0,0), Ti(1,0) and Tj(0,1). + */ + Parallelogram() + { + p_ = VEC::Zero() ; + Ti_ = VEC::Zero() ; + Ti_[0] = 1.0 ; + Tj_ = VEC::Zero() ; + Tj_[1] = 1.0 ; + } + + /** + * @brief Parallelogram constructor by exhaustively giving all points + * @param p0 + * @param p1 + * @param p2 + * @param p3 + */ + Parallelogram(const VEC& p0, const VEC& p1, const VEC& p2, const VEC& p3) + { + init(p0,p1-p0,p3-p0) ; + } + + /** + * @brief Parallelogram constructor using a point and two vectors + * @param p the anchor point + * @param Ti vector 1 + * @param Tj vector 2 + */ + Parallelogram(const VEC& p, const VEC& Ti, const VEC& Tj) + { + init(p,Ti,Tj) ; + } + + /** + * @brief Parallelogram constructor by giving the anchor point and the magnitudes and angles of the two vectors + * @param p anchor point + * @param mag_i magnitude of vector 1 + * @param alpha_i angle of vector 1 (wrt vertical axis) + * @param mag_j magnitude of vector 2 + * @param alpha_j angle of vector 2 (wrt vertical axis) + * @pre 0 < alpha_i < M_PI + * @pre alpha_i < alpha_j <= M_PI + */ + Parallelogram(const VEC& p, const double& mag_i, const double& alpha_i, const double& mag_j, const double& alpha_j ) + { + VEC Ti,Tj ; + Ti[0] = mag_i*sin(alpha_i) ; + Ti[1] = -mag_i*cos(alpha_i) ; + Tj[0] = mag_j*sin(alpha_j) ; + Tj[1] = -mag_j*cos(alpha_j) ; + init(p,Ti,Tj) ; + } + + /** + * @brief getRefPos returns the anchor point + * @return the anchor point + */ + const VEC& getRefPos() const + { + return p_ ; + } + + /** + * @brief getTi returns the first vector + * @return the first vector in carthesian coordinates + */ + const VEC& getTi() const + { + return Ti_ ; + } + + /** + * @brief getTj returns the second vector + * @return returns the second vector in carthesian coordinates + */ + const VEC& getTj() const + { + return Tj_ ; + } + + uint sample_parallelograms(std::vector& samples, uint p_bins, uint mag_i_bins, uint alpha_i_bins, uint mag_j_bins, uint alpha_j_bins) const + { + samples.clear() ; + + + // TODO + assert(false) ; + + + return samples.size() ; + } private: - void init(const VEC& p, const VEC& Ti, const VEC& Tj) - { - p_ = p ; - Ti_ = Ti ; - Tj_ = Tj ; - cgogn_assert(is_valid()) ; - if (!is_valid()) - cgogn_log_error("Parallelogram::init") << "Attempt to create an invalid Parallelogram."; - } - - bool is_valid() const - { - bool res = Ti_[0] > 0 && Tj_[0] >= 0 && Tj_[1] > Ti_[1] ; - cgogn_assert((acos(-Tj_[1] / Tj_.norm()) > acos(-Ti_[1] / Ti_.norm())) == res) ; - return res && p_.norm() > 1e-10 && Ti_.norm() > 1e-10 && Tj_.norm() > 1e-10 ; - } + void init(const VEC& p, const VEC& Ti, const VEC& Tj) + { + p_ = p ; + Ti_ = Ti ; + Tj_ = Tj ; + cgogn_assert(is_valid()) ; + if (!is_valid()) + cgogn_log_error("Parallelogram::init") << "Attempt to create an invalid Parallelogram."; + } + + bool is_valid() const + { + bool res = Ti_[0] > 0 && Tj_[0] >= 0 && Tj_[1] > Ti_[1] ; + cgogn_assert((acos(-Tj_[1] / Tj_.norm()) > acos(-Ti_[1] / Ti_.norm())) == res) ; + return res && p_.norm() > 1e-10 && Ti_.norm() > 1e-10 && Tj_.norm() > 1e-10 ; + } }; /** @@ -103,679 +145,679 @@ class Parallelogram template class ParallelogramGrid { - CGOGN_NOT_COPYABLE_NOR_MOVABLE(ParallelogramGrid); + CGOGN_NOT_COPYABLE_NOR_MOVABLE(ParallelogramGrid); protected: - using Map2 = cgogn::CMap2; + using Map2 = cgogn::CMap2; - using CDart = typename MAP::CDart; - using Vertex = typename MAP::Vertex; - using Edge = typename MAP::Edge; - using Face = typename MAP::Face; - using Volume = typename MAP::Volume; + using CDart = typename MAP::CDart; + using Vertex = typename MAP::Vertex; + using Edge = typename MAP::Edge; + using Face = typename MAP::Face; + using Volume = typename MAP::Volume; - template - using DartAttribute = Map2::CDartAttribute; - template - using VertexAttribute = Map2::VertexAttribute; - template - using FaceAttribute = Map2::FaceAttribute; + template + using DartAttribute = Map2::CDartAttribute; + template + using VertexAttribute = Map2::VertexAttribute; + template + using FaceAttribute = Map2::FaceAttribute; - using MapBuilder = typename MAP::Builder; - using ChunkArrayContainer = MapBaseData::ChunkArrayContainer; + using MapBuilder = typename MAP::Builder; + using ChunkArrayContainer = MapBaseData::ChunkArrayContainer; - enum Orient { S=0, E=1, N=2, W=3, INVALID_ORIENT} ; - struct DartOrient - { - Orient value_; + enum Orient { S=0, E=1, N=2, W=3, INVALID_ORIENT} ; + struct DartOrient + { + Orient value_; - DartOrient() : value_(INVALID_ORIENT) {} + DartOrient() : value_(INVALID_ORIENT) {} - friend std::ostream& operator<<(std::ostream& out, const DartOrient&) { return out; } - friend std::istream& operator>>(std::istream& in, const DartOrient&) { return in; } - }; + friend std::ostream& operator<<(std::ostream& out, const DartOrient&) { return out; } + friend std::istream& operator>>(std::istream& in, const DartOrient&) { return in; } + }; protected: - MAP& map_ ; - Dart dart_ ; - const geometry::AABB& area_ ; + MAP& map_ ; + Dart dart_ ; + const geometry::AABB& area_ ; - Parallelogram p_ ; + Parallelogram p_ ; - DartAttribute dart_orientation_ ; - VertexAttribute vertex_position_ ; + DartAttribute dart_orientation_ ; + VertexAttribute vertex_position_ ; public: - /** - * @brief ParallelogramGrid is a utility class for creating a tiling of parallelograms. - * @param map the CGoGN map that defines the mesh - * @param fill_area the area to tile - */ - ParallelogramGrid(MAP& map, const geometry::AABB& fill_area): - map_(map), - area_(fill_area) - {} - - /** - * @brief embed_with_parallelograms creates a mesh composed of a tiling of identical parallelograms. - * Parallelograms are defined by two vectors (Ti,Tj). - * The position of the left-bottom corner of one parallelogram is defined as being located at p. - * The tiling is embedded geometrically and fills at least a rectangular area defined by the point RectOrigin and RectDiag. - * @param p origin of the reference parallelogram - * @param Ti first vector definining a parallelogram - * @param Tj second vector definining a parallelogram - * - * @pre p must lie in the area to fill (defined in the constructor #ParallelogramGrid) - * @pre Ti[0] > 0 - * @pre Tj[0] >=0 - * @pre Tj[1] > Ti[1] - * - * @post the map is embedded with a VertexAttribute called "position". - */ - void embed_with_parallelograms(const VEC& fixed_point, const VEC& Ti, const VEC& Tj) - { - cgogn_assert(area_.contains(fixed_point)) ; - p_ = Parallelogram(fixed_point,Ti,Tj) ; ; - - vertex_position_ = map_.template get_attribute("position") ; - if (!vertex_position_.is_valid()) - vertex_position_ = map_.template add_attribute("position") ; - - dart_orientation_ = map_.template get_attribute("dartOrient"); - if (!dart_orientation_.is_valid()) - dart_orientation_ = map_.template add_attribute("dartOrient"); - - MapBuilder mbuild(map_); - - // Create face and update orbit embeddings - std::array incidentVertices ; - std::array adjacentFaces ; - const Dart d0 = add_face_topo(mbuild, incidentVertices/*, dart_orientation*/) ; - dart_ = d0; - const Face f0 = Face(d0) ; - - // Embed vertices of face - const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, f0, p_.getRefPos()) ; - - std::queue edgeQueue ; // list of edges to treat - queueFreeEdges(f0,edgeQueue,f_bbox) ; - - while(!edgeQueue.empty()) - { - // Pop front edge - Edge e = edgeQueue.front() ; - - const Dart d = e.dart ; - if (is_border(d)) // if it lacks a neighbor - { - // get Array of existing adjacent (neighboring) faces - const Face provokingFace = Face(d) ; - const Orient provokingFaceOrient = getOrientOfDart(d/*,provokingFace*/) ; - adjacentFaces = getAdjacentFacesFromProvokingFace(provokingFace,provokingFaceOrient/*dart_orientation[e.dart].value_*/) ; - - // Compute which incident vertices are already there - incidentVertices = adjFaces2incVertices(adjacentFaces) ; - - // Add new face, re-using existing vertices if present - const Dart newDart = add_face_topo(mbuild, incidentVertices/*, adjacentFaces, dart_orientation*/) ; - const Face newFace = Face(newDart) ; - - // sew with neighbor faces - sewFaceToAdjacentFaces(mbuild,newFace,adjacentFaces) ; - - // Embed vertices of face - // Get embedding of previous face's reference vertex - VEC p_ref = vertex_position_[getRefVertex(provokingFace)] ; - - // Define embedding of new face's reference vertex - switch(provokingFaceOrient) - { - case(S): - p_ref -= p_.getTj() ; - break ; - case(E): - p_ref += p_.getTi() ; - break ; - case(N): - p_ref += p_.getTj() ; - break ; - case(W): - p_ref -= p_.getTi() ; - break ; - case(INVALID_ORIENT): - cgogn_log_error("INVALID_ORIENT in switch") ; - break ; - } - - // Embed new face's geometry - const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, newFace, p_ref) ; - // Add edges that are free - queueFreeEdges(newFace, edgeQueue, f_bbox) ; - } - - edgeQueue.pop() ; - } - - // close boundary - mbuild.close_map() ; - cgogn_ensure(map_.check_embedding_integrity()) ; - -// uint nbV = map_.template nb_cells(); -// uint nbF = map_.template nb_cells(); -// std::cout << "Nb Vertices: " << nbV << std::endl ; -// std::cout << "Nb Faces: " << nbF << std::endl ; - } - -// Orient sew_FaceEdge(MapBuilder& mbuild, /*const DartAttribute& dart_orientation,*/ const Face& f0, const Edge& e0) -// { -// cgogn_ensure(map_.phi2(e0.dart) == e0.dart) ; - -// const DartDir& et = dart_orientation[e0] ; -// Orient fSearchDartDir = INVALID_ORIENT ; -// switch(et.value_) -// { -// case(S): -// fSearchDartDir = N ; -// break ; -// case(E): -// fSearchDartDir = W ; -// break ; -// case(N): -// fSearchDartDir = S ; -// break ; -// case(W): -// fSearchDartDir = E ; -// break ; -// case(INVALID_ORIENT): -// cgogn_ensure(et.value_ != INVALID_ORIENT) ; -// break ; -// } - -// Edge to_sew ; -// map_.foreach_incident_edge(f0, -// [&] (Edge e) -> bool -// { -// to_sew = e ; -// return (dart_orientation[e].value_ == fSearchDartDir) ; -// }) ; - -// // sew to_sew and e0 by phi2 -// const Dart& d0 = to_sew.dart ; -// const Dart& d1 = e0.dart ; -// mbuild.phi2_sew(d0,d1) ; -// // ensure embedding -// mbuild.template set_embedding(d1, map_.embedding(Vertex(map_.phi1(d0)))); - -// return et.value_ ; -// } + /** + * @brief ParallelogramGrid is a utility class for creating a tiling of parallelograms. + * @param map the CGoGN map that defines the mesh + * @param fill_area the area to tile + */ + ParallelogramGrid(MAP& map, const geometry::AABB& fill_area): + map_(map), + area_(fill_area) + {} + + /** + * @brief embed_with_parallelograms creates a mesh composed of a tiling of identical parallelograms. + * Parallelograms are defined by two vectors (Ti,Tj). + * The position of the left-bottom corner of one parallelogram is defined as being located at p. + * The tiling is embedded geometrically and fills at least a rectangular area defined by the point RectOrigin and RectDiag. + * @param p origin of the reference parallelogram + * @param Ti first vector definining a parallelogram + * @param Tj second vector definining a parallelogram + * + * @pre p must lie in the area to fill (defined in the constructor #ParallelogramGrid) + * @pre Ti[0] > 0 + * @pre Tj[0] >=0 + * @pre Tj[1] > Ti[1] + * + * @post the map is embedded with a VertexAttribute called "position". + */ + void embed_with_parallelograms(const VEC& fixed_point, const VEC& Ti, const VEC& Tj) + { + cgogn_assert(area_.contains(fixed_point)) ; + p_ = Parallelogram(fixed_point,Ti,Tj) ; ; + + vertex_position_ = map_.template get_attribute("position") ; + if (!vertex_position_.is_valid()) + vertex_position_ = map_.template add_attribute("position") ; + + dart_orientation_ = map_.template get_attribute("dartOrient"); + if (!dart_orientation_.is_valid()) + dart_orientation_ = map_.template add_attribute("dartOrient"); + + MapBuilder mbuild(map_); + + // Create face and update orbit embeddings + std::array incidentVertices ; + std::array adjacentFaces ; + const Dart d0 = add_face_topo(mbuild, incidentVertices/*, dart_orientation*/) ; + dart_ = d0; + const Face f0 = Face(d0) ; + + // Embed vertices of face + const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, f0, p_.getRefPos()) ; + + std::queue edgeQueue ; // list of edges to treat + queueFreeEdges(f0,edgeQueue,f_bbox) ; + + while(!edgeQueue.empty()) + { + // Pop front edge + Edge e = edgeQueue.front() ; + + const Dart d = e.dart ; + if (is_border(d)) // if it lacks a neighbor + { + // get Array of existing adjacent (neighboring) faces + const Face provokingFace = Face(d) ; + const Orient provokingFaceOrient = getOrientOfDart(d/*,provokingFace*/) ; + adjacentFaces = getAdjacentFacesFromProvokingFace(provokingFace,provokingFaceOrient/*dart_orientation[e.dart].value_*/) ; + + // Compute which incident vertices are already there + incidentVertices = adjFaces2incVertices(adjacentFaces) ; + + // Add new face, re-using existing vertices if present + const Dart newDart = add_face_topo(mbuild, incidentVertices/*, adjacentFaces, dart_orientation*/) ; + const Face newFace = Face(newDart) ; + + // sew with neighbor faces + sewFaceToAdjacentFaces(mbuild,newFace,adjacentFaces) ; + + // Embed vertices of face + // Get embedding of previous face's reference vertex + VEC p_ref = vertex_position_[getRefVertex(provokingFace)] ; + + // Define embedding of new face's reference vertex + switch(provokingFaceOrient) + { + case(S): + p_ref -= p_.getTj() ; + break ; + case(E): + p_ref += p_.getTi() ; + break ; + case(N): + p_ref += p_.getTj() ; + break ; + case(W): + p_ref -= p_.getTi() ; + break ; + case(INVALID_ORIENT): + cgogn_log_error("INVALID_ORIENT in switch") ; + break ; + } + + // Embed new face's geometry + const geometry::AABB f_bbox = embed_parallelogram(vertex_position_, newFace, p_ref) ; + // Add edges that are free + queueFreeEdges(newFace, edgeQueue, f_bbox) ; + } + + edgeQueue.pop() ; + } + + // close boundary + mbuild.close_map() ; + cgogn_ensure(map_.check_embedding_integrity()) ; + + // uint nbV = map_.template nb_cells(); + // uint nbF = map_.template nb_cells(); + // std::cout << "Nb Vertices: " << nbV << std::endl ; + // std::cout << "Nb Faces: " << nbF << std::endl ; + } + + // Orient sew_FaceEdge(MapBuilder& mbuild, /*const DartAttribute& dart_orientation,*/ const Face& f0, const Edge& e0) + // { + // cgogn_ensure(map_.phi2(e0.dart) == e0.dart) ; + + // const DartDir& et = dart_orientation[e0] ; + // Orient fSearchDartDir = INVALID_ORIENT ; + // switch(et.value_) + // { + // case(S): + // fSearchDartDir = N ; + // break ; + // case(E): + // fSearchDartDir = W ; + // break ; + // case(N): + // fSearchDartDir = S ; + // break ; + // case(W): + // fSearchDartDir = E ; + // break ; + // case(INVALID_ORIENT): + // cgogn_ensure(et.value_ != INVALID_ORIENT) ; + // break ; + // } + + // Edge to_sew ; + // map_.foreach_incident_edge(f0, + // [&] (Edge e) -> bool + // { + // to_sew = e ; + // return (dart_orientation[e].value_ == fSearchDartDir) ; + // }) ; + + // // sew to_sew and e0 by phi2 + // const Dart& d0 = to_sew.dart ; + // const Dart& d1 = e0.dart ; + // mbuild.phi2_sew(d0,d1) ; + // // ensure embedding + // mbuild.template set_embedding(d1, map_.embedding(Vertex(map_.phi1(d0)))); + + // return et.value_ ; + // } private: -// ------------------------ Mesh construction algorithm -------------------------------- - /** - * @brief queueFreeEdges adds the edges of face #f that are border edges of the mesh to the queue #edgeQueue iff #f_bbox intersects with the area to fill (defined in the constructor). - * @param f the face - * @param edgeQueue the queue of edges to maintain - * @param f_bbox bounding box of the current face - * @return - */ - uint queueFreeEdges(const Face& f, std::queue& edgeQueue, const geometry::AABB& f_bbox) - { - uint counter = 0 ; - // if current face touches the Rectangle - if (area_.intersects(f_bbox)) - { - // add all its edges to list of edges to treat - map_.foreach_incident_edge(f, - [&] (Edge e) - { - if (is_border(e.dart)) // if it hasn't been sewed yet - { - edgeQueue.push(e); - ++counter ; - } - }); - } - - return counter ; - } - -// ------------------------ Tools: Position embedding -------------------------------- - /** - * @brief embed_parallelogram embeds a quad into a parallelogram - * @param position the Vertex position container - * @param f the quad - * @param p0 the reference vertex position - * @pre f needs to be a quadrilateral and fully sewed - * @pre position need be a valid vertex attribute. - * - * @return the axis-aligned bounding box of the embedded parallelogram - */ - geometry::AABB embed_parallelogram( - typename MAP::template VertexAttribute& position, - //typename MAP::template DartAttribute& dart_orientation, - const Face& f, const VEC& p0) - { - const Dart d0 = f.dart ; - const Dart d1 = map_.phi1(d0) ; - const Dart d2 = map_.phi1(d1) ; - const Dart d3 = map_.phi1(d2) ; - cgogn_ensure(d0==map_.phi1(d3)) ; - - position[Vertex(d0)] = p0 ; - position[Vertex(d1)] = p0 + p_.getTi() ; - position[Vertex(d2)] = position[d1] + p_.getTj() ; - position[Vertex(d3)] = p0 + p_.getTj() ; - - geometry::AABB bbox(p0) ; - bbox.add_point(position[d1]) ; - bbox.add_point(position[d2]) ; - bbox.add_point(position[d3]) ; - - return bbox ; - } - -// ------------------------ Tools: Constructing the mesh -------------------------------- - - /** - * @brief add_face_topo creates a new face and updates embeddings topological embedding pointers - * @param mbuild - * @param incidentVertices contains existing vertices to link to, if any (invalid ones otherwise) - * @return - */ - Dart add_face_topo(MapBuilder& mbuild, const std::array& incidentVertices) - { - ChunkArrayContainer& dart_container = mbuild.template attribute_container(); - ChunkArrayContainer& vertex_container = mbuild.template attribute_container(); - ChunkArrayContainer& face_container = mbuild.template attribute_container(); - - // Create face - const Dart d0 = mbuild.add_face_topo_fp(4u) ; // phi2 is fixed point - const Dart d1 = map_.phi1(d0) ; - const Dart d2 = map_.phi1(d1) ; - const Dart d3 = map_.phi1(d2) ; - - // Create new orbit embeddings for all embedded orbits. - // This FACE - const Face f0 = Face(d0) ; - if(map_.template is_embedded()) - { - uint32 nf = face_container.insert_lines<1>(); - mbuild.template set_embedding(f0.dart,nf); - } - - // All DART of this face - if(map_.template is_embedded()) - { - map_.foreach_dart_of_orbit(f0, [&] (Dart d) - { - uint32 nd = dart_container.insert_lines<1>() ; - mbuild.template set_embedding(d,nd); - }); - } - - // All VERTEX of this face (if not existing) - if(map_.template is_embedded()) - { - // if incident vertex exists, reuse, otherwise create new - uint32 nv = incidentVertices[0].is_valid() ? map_.embedding(incidentVertices[0]) : vertex_container.insert_lines<1>() ; - mbuild.template set_embedding(d0, nv); - - nv = incidentVertices[1].is_valid() ? map_.embedding(incidentVertices[1]) : vertex_container.insert_lines<1>() ; - mbuild.template set_embedding(d1, nv); - - nv = incidentVertices[2].is_valid() ? map_.embedding(incidentVertices[2]) : vertex_container.insert_lines<1>() ; - mbuild.template set_embedding(d2, nv); - - nv = incidentVertices[3].is_valid() ? map_.embedding(incidentVertices[3]) : vertex_container.insert_lines<1>() ; - mbuild.template set_embedding(d3, nv); - } - -// const bool isVertexEmbedded = map_.template is_embedded() ; -// map_.foreach_incident_vertex(f0, -// [&] (Vertex v) -// { -// if (isVertexEmbedded) -// { -// uint32 nv = vertex_container.insert_lines<1>(); // TODO, only if not yet existing -// mbuild.template set_embedding(v.dart,nv); -// } -// }) ; - - // Label the darts - dart_orientation_[d0].value_ = S ; - dart_orientation_[d1].value_ = E ; - dart_orientation_[d2].value_ = N ; - dart_orientation_[d3].value_ = W ; - - return d0 ; - } - - - /** - * @brief sewFaceToAdjacentFaces sews face #f0 to the existing non-sewed adjacent faces #adjacentFaces - * @param mbuild - * @param f0 the face to sew - * @param adjacentFaces the adjacent faces, previously obtained by #getAdjacentFacesFromProvokingFace. - */ - void sewFaceToAdjacentFaces(MapBuilder& mbuild,const Face& f0, const std::array& adjacentFaces) - { - Dart d = f0.dart ; - for (uint o = S ; o <= W ; ++o) - { - const Face& fAdj = adjacentFaces[o] ; - if (fAdj.is_valid()) // if there's a face to be sewed in that direction - { - // Take opposite orientation of that face - const Orient oInv = Orient((o+2)%4) ; - const Dart dSew = getDartByOrient(fAdj,oInv) ; - mbuild.phi2_sew(d,dSew) ; - - // Set Edge embedding to that of the retrieved edge - // mbuild.template set_embedding(d, map_.embedding(eSew)); - // Set Vertex embedding to that of the retrieved Vertex - //mbuild.template set_embedding(d, map_.embedding(Vertex(map_.phi1(dSew)))); // TODO CHECK IF ALREADY DONE. ITS RATHER AN OPTIMISATION AS DOING TWICE DOESNT HURT - } - d = map_.phi1(d) ; // go to next - } - } - - // ------------------------ Tools: Find unsewed neighboring topo items -------------------------------- + // ------------------------ Mesh construction algorithm -------------------------------- + /** + * @brief queueFreeEdges adds the edges of face #f that are border edges of the mesh to the queue #edgeQueue iff #f_bbox intersects with the area to fill (defined in the constructor). + * @param f the face + * @param edgeQueue the queue of edges to maintain + * @param f_bbox bounding box of the current face + * @return + */ + uint queueFreeEdges(const Face& f, std::queue& edgeQueue, const geometry::AABB& f_bbox) + { + uint counter = 0 ; + // if current face touches the Rectangle + if (area_.intersects(f_bbox)) + { + // add all its edges to list of edges to treat + map_.foreach_incident_edge(f, + [&] (Edge e) + { + if (is_border(e.dart)) // if it hasn't been sewed yet + { + edgeQueue.push(e); + ++counter ; + } + }); + } + + return counter ; + } + + // ------------------------ Tools: Position embedding -------------------------------- + /** + * @brief embed_parallelogram embeds a quad into a parallelogram + * @param position the Vertex position container + * @param f the quad + * @param p0 the reference vertex position + * @pre f needs to be a quadrilateral and fully sewed + * @pre position need be a valid vertex attribute. + * + * @return the axis-aligned bounding box of the embedded parallelogram + */ + geometry::AABB embed_parallelogram( + typename MAP::template VertexAttribute& position, + //typename MAP::template DartAttribute& dart_orientation, + const Face& f, const VEC& p0) + { + const Dart d0 = f.dart ; + const Dart d1 = map_.phi1(d0) ; + const Dart d2 = map_.phi1(d1) ; + const Dart d3 = map_.phi1(d2) ; + cgogn_ensure(d0==map_.phi1(d3)) ; + + position[Vertex(d0)] = p0 ; + position[Vertex(d1)] = p0 + p_.getTi() ; + position[Vertex(d2)] = position[d1] + p_.getTj() ; + position[Vertex(d3)] = p0 + p_.getTj() ; + + geometry::AABB bbox(p0) ; + bbox.add_point(position[d1]) ; + bbox.add_point(position[d2]) ; + bbox.add_point(position[d3]) ; + + return bbox ; + } + + // ------------------------ Tools: Constructing the mesh -------------------------------- + + /** + * @brief add_face_topo creates a new face and updates embeddings topological embedding pointers + * @param mbuild + * @param incidentVertices contains existing vertices to link to, if any (invalid ones otherwise) + * @return + */ + Dart add_face_topo(MapBuilder& mbuild, const std::array& incidentVertices) + { + ChunkArrayContainer& dart_container = mbuild.template attribute_container(); + ChunkArrayContainer& vertex_container = mbuild.template attribute_container(); + ChunkArrayContainer& face_container = mbuild.template attribute_container(); + + // Create face + const Dart d0 = mbuild.add_face_topo_fp(4u) ; // phi2 is fixed point + const Dart d1 = map_.phi1(d0) ; + const Dart d2 = map_.phi1(d1) ; + const Dart d3 = map_.phi1(d2) ; + + // Create new orbit embeddings for all embedded orbits. + // This FACE + const Face f0 = Face(d0) ; + if(map_.template is_embedded()) + { + uint32 nf = face_container.insert_lines<1>(); + mbuild.template set_embedding(f0.dart,nf); + } + + // All DART of this face + if(map_.template is_embedded()) + { + map_.foreach_dart_of_orbit(f0, [&] (Dart d) + { + uint32 nd = dart_container.insert_lines<1>() ; + mbuild.template set_embedding(d,nd); + }); + } + + // All VERTEX of this face (if not existing) + if(map_.template is_embedded()) + { + // if incident vertex exists, reuse, otherwise create new + uint32 nv = incidentVertices[0].is_valid() ? map_.embedding(incidentVertices[0]) : vertex_container.insert_lines<1>() ; + mbuild.template set_embedding(d0, nv); + + nv = incidentVertices[1].is_valid() ? map_.embedding(incidentVertices[1]) : vertex_container.insert_lines<1>() ; + mbuild.template set_embedding(d1, nv); + + nv = incidentVertices[2].is_valid() ? map_.embedding(incidentVertices[2]) : vertex_container.insert_lines<1>() ; + mbuild.template set_embedding(d2, nv); + + nv = incidentVertices[3].is_valid() ? map_.embedding(incidentVertices[3]) : vertex_container.insert_lines<1>() ; + mbuild.template set_embedding(d3, nv); + } + + // const bool isVertexEmbedded = map_.template is_embedded() ; + // map_.foreach_incident_vertex(f0, + // [&] (Vertex v) + // { + // if (isVertexEmbedded) + // { + // uint32 nv = vertex_container.insert_lines<1>(); // TODO, only if not yet existing + // mbuild.template set_embedding(v.dart,nv); + // } + // }) ; + + // Label the darts + dart_orientation_[d0].value_ = S ; + dart_orientation_[d1].value_ = E ; + dart_orientation_[d2].value_ = N ; + dart_orientation_[d3].value_ = W ; + + return d0 ; + } + + + /** + * @brief sewFaceToAdjacentFaces sews face #f0 to the existing non-sewed adjacent faces #adjacentFaces + * @param mbuild + * @param f0 the face to sew + * @param adjacentFaces the adjacent faces, previously obtained by #getAdjacentFacesFromProvokingFace. + */ + void sewFaceToAdjacentFaces(MapBuilder& mbuild,const Face& f0, const std::array& adjacentFaces) + { + Dart d = f0.dart ; + for (uint o = S ; o <= W ; ++o) + { + const Face& fAdj = adjacentFaces[o] ; + if (fAdj.is_valid()) // if there's a face to be sewed in that direction + { + // Take opposite orientation of that face + const Orient oInv = Orient((o+2)%4) ; + const Dart dSew = getDartByOrient(fAdj,oInv) ; + mbuild.phi2_sew(d,dSew) ; + + // Set Edge embedding to that of the retrieved edge + // mbuild.template set_embedding(d, map_.embedding(eSew)); + // Set Vertex embedding to that of the retrieved Vertex + //mbuild.template set_embedding(d, map_.embedding(Vertex(map_.phi1(dSew)))); // TODO CHECK IF ALREADY DONE. ITS RATHER AN OPTIMISATION AS DOING TWICE DOESNT HURT + } + d = map_.phi1(d) ; // go to next + } + } + + // ------------------------ Tools: Find unsewed neighboring topo items -------------------------------- private: - /** - * @brief getAdjacentFacesFromProvokingFace returns the existing unsewed south, east, north and west faces, respectively. If one of these (usually at least 2) is non-existing, the resturned faces are not valid. - * @param map the map - * @param dart_orientation the DartAttribute with edge type labels - * @param provokingFace one of the adjacent faces, i.e., the one that initiated the creation of the current face - * @param provokingDartDir the edge of #provokingFace to which the current face is neighboring - * @return array of 4 Faces, respectively south, east, north and west of the new face, or invalid faces if they are inexistant. - */ - std::array getAdjacentFacesFromProvokingFace(const Face& provokingFace, const Orient& provokingDartDir) - { - std::array neighbFaces ; - - switch(provokingDartDir) - { - case(S): - { - neighbFaces[2] = provokingFace ; // provokingFace is located north - - // Check to the West - const Face fNW = getFaceInOrient(provokingFace,W) ; - if (fNW.is_valid()) - { - const Face fW = getFaceInOrient(fNW,S) ; - if (fW.is_valid()) - { - neighbFaces[W] = fW ; - } - } - - // Check to the East - const Face fNE = getFaceInOrient(provokingFace,E) ; - if (fNE.is_valid()) - { - const Face fE = getFaceInOrient(fNE,S) ; - if (fE.is_valid()) - { - neighbFaces[E] = fE ; - } - } - } - break; - case(E): - { - neighbFaces[3] = provokingFace ; // provokingFace is located west - - // Check to the North - const Face fNW = getFaceInOrient(provokingFace,N) ; - if (fNW.is_valid()) - { - const Face fN = getFaceInOrient(fNW,E) ; - if (fN.is_valid()) - { - neighbFaces[N] = fN ; - } - } - - // Check to the South - const Face fSW = getFaceInOrient(provokingFace,S) ; - if (fSW.is_valid()) - { - const Face fS = getFaceInOrient(fSW,E) ; - if (fS.is_valid()) - { - neighbFaces[S] = fS ; - } - } - } - break; - case(N): - { - neighbFaces[0] = provokingFace ; // provokingFace is located south - - // Check to the West - const Face fSW = getFaceInOrient(provokingFace,W) ; - if (fSW.is_valid()) - { - const Face fW = getFaceInOrient(fSW,N) ; - if (fW.is_valid()) - { - neighbFaces[W] = fW ; - } - } - - // Check to the East - const Face fSE = getFaceInOrient(provokingFace,E) ; - if (fSE.is_valid()) - { - const Face fE = getFaceInOrient(fSE,N) ; - if (fE.is_valid()) - { - neighbFaces[E] = fE ; - } - } - } - break; - case(W): - { - neighbFaces[1] = provokingFace ; // provokingFace is located east - - // Check to the North - const Face fNE = getFaceInOrient(provokingFace,N) ; - if (fNE.is_valid()) - { - const Face fN = getFaceInOrient(fNE,W) ; - if (fN.is_valid()) - { - neighbFaces[N] = fN ; - } - } - - // Check to the South - const Face fSE = getFaceInOrient(provokingFace,S) ; - if (fSE.is_valid()) - { - const Face fS = getFaceInOrient(fSE,W) ; - if (fS.is_valid()) - { - neighbFaces[S] = fS ; - } - } - } - break; - case(INVALID_ORIENT): - cgogn_log_error("INVALID_ORIENT in switch") ; - break ; - } - - return neighbFaces ; - } - - /** - * @brief adjFaces2incVertices returns an array of existing (or invalid) vertices for the new face, given its pre-existing adjacent faces - * @param adjacentFaces the pre-existing adjacent faces - * @return array of vertices pre-existing vertices to embed the current face with, or invalid vertices otherwise. In counter-clock numbering order, starting from the reference vertex. - */ - std::array adjFaces2incVertices(const std::array& adjacentFaces) const - { - std::array incVertices ; - - if (adjacentFaces[0].is_valid()) // South - { - incVertices[0] = getVertexByNo(adjacentFaces[0],3) ; // Vx 3 of South face - incVertices[1] = getVertexByNo(adjacentFaces[0],2) ; // Vx 2 of South face - } - if (adjacentFaces[1].is_valid()) // East - { - incVertices[1] = getVertexByNo(adjacentFaces[1],0) ; // Vx 0 of East face - incVertices[2] = getVertexByNo(adjacentFaces[1],3) ; // Vx 3 of East face - } - if (adjacentFaces[2].is_valid()) // North - { - incVertices[2] = getVertexByNo(adjacentFaces[2],1) ; // Vx 1 of North face - incVertices[3] = getVertexByNo(adjacentFaces[2],0) ; // Vx 0 of North face - } - if (adjacentFaces[3].is_valid()) // West - { - incVertices[3] = getVertexByNo(adjacentFaces[3],2) ; // Vx 2 of West face - incVertices[0] = getVertexByNo(adjacentFaces[3],1) ; // Vx 1 of West face - } - - return incVertices ; - } - - // ------------------------ Tools: getR in a Face -------------------------------- + /** + * @brief getAdjacentFacesFromProvokingFace returns the existing unsewed south, east, north and west faces, respectively. If one of these (usually at least 2) is non-existing, the resturned faces are not valid. + * @param map the map + * @param dart_orientation the DartAttribute with edge type labels + * @param provokingFace one of the adjacent faces, i.e., the one that initiated the creation of the current face + * @param provokingDartDir the edge of #provokingFace to which the current face is neighboring + * @return array of 4 Faces, respectively south, east, north and west of the new face, or invalid faces if they are inexistant. + */ + std::array getAdjacentFacesFromProvokingFace(const Face& provokingFace, const Orient& provokingDartDir) + { + std::array neighbFaces ; + + switch(provokingDartDir) + { + case(S): + { + neighbFaces[2] = provokingFace ; // provokingFace is located north + + // Check to the West + const Face fNW = getFaceInOrient(provokingFace,W) ; + if (fNW.is_valid()) + { + const Face fW = getFaceInOrient(fNW,S) ; + if (fW.is_valid()) + { + neighbFaces[W] = fW ; + } + } + + // Check to the East + const Face fNE = getFaceInOrient(provokingFace,E) ; + if (fNE.is_valid()) + { + const Face fE = getFaceInOrient(fNE,S) ; + if (fE.is_valid()) + { + neighbFaces[E] = fE ; + } + } + } + break; + case(E): + { + neighbFaces[3] = provokingFace ; // provokingFace is located west + + // Check to the North + const Face fNW = getFaceInOrient(provokingFace,N) ; + if (fNW.is_valid()) + { + const Face fN = getFaceInOrient(fNW,E) ; + if (fN.is_valid()) + { + neighbFaces[N] = fN ; + } + } + + // Check to the South + const Face fSW = getFaceInOrient(provokingFace,S) ; + if (fSW.is_valid()) + { + const Face fS = getFaceInOrient(fSW,E) ; + if (fS.is_valid()) + { + neighbFaces[S] = fS ; + } + } + } + break; + case(N): + { + neighbFaces[0] = provokingFace ; // provokingFace is located south + + // Check to the West + const Face fSW = getFaceInOrient(provokingFace,W) ; + if (fSW.is_valid()) + { + const Face fW = getFaceInOrient(fSW,N) ; + if (fW.is_valid()) + { + neighbFaces[W] = fW ; + } + } + + // Check to the East + const Face fSE = getFaceInOrient(provokingFace,E) ; + if (fSE.is_valid()) + { + const Face fE = getFaceInOrient(fSE,N) ; + if (fE.is_valid()) + { + neighbFaces[E] = fE ; + } + } + } + break; + case(W): + { + neighbFaces[1] = provokingFace ; // provokingFace is located east + + // Check to the North + const Face fNE = getFaceInOrient(provokingFace,N) ; + if (fNE.is_valid()) + { + const Face fN = getFaceInOrient(fNE,W) ; + if (fN.is_valid()) + { + neighbFaces[N] = fN ; + } + } + + // Check to the South + const Face fSE = getFaceInOrient(provokingFace,S) ; + if (fSE.is_valid()) + { + const Face fS = getFaceInOrient(fSE,W) ; + if (fS.is_valid()) + { + neighbFaces[S] = fS ; + } + } + } + break; + case(INVALID_ORIENT): + cgogn_log_error("INVALID_ORIENT in switch") ; + break ; + } + + return neighbFaces ; + } + + /** + * @brief adjFaces2incVertices returns an array of existing (or invalid) vertices for the new face, given its pre-existing adjacent faces + * @param adjacentFaces the pre-existing adjacent faces + * @return array of vertices pre-existing vertices to embed the current face with, or invalid vertices otherwise. In counter-clock numbering order, starting from the reference vertex. + */ + std::array adjFaces2incVertices(const std::array& adjacentFaces) const + { + std::array incVertices ; + + if (adjacentFaces[0].is_valid()) // South + { + incVertices[0] = getVertexByNo(adjacentFaces[0],3) ; // Vx 3 of South face + incVertices[1] = getVertexByNo(adjacentFaces[0],2) ; // Vx 2 of South face + } + if (adjacentFaces[1].is_valid()) // East + { + incVertices[1] = getVertexByNo(adjacentFaces[1],0) ; // Vx 0 of East face + incVertices[2] = getVertexByNo(adjacentFaces[1],3) ; // Vx 3 of East face + } + if (adjacentFaces[2].is_valid()) // North + { + incVertices[2] = getVertexByNo(adjacentFaces[2],1) ; // Vx 1 of North face + incVertices[3] = getVertexByNo(adjacentFaces[2],0) ; // Vx 0 of North face + } + if (adjacentFaces[3].is_valid()) // West + { + incVertices[3] = getVertexByNo(adjacentFaces[3],2) ; // Vx 2 of West face + incVertices[0] = getVertexByNo(adjacentFaces[3],1) ; // Vx 1 of West face + } + + return incVertices ; + } + + // ------------------------ Tools: getR in a Face -------------------------------- private: - /** - * @brief getRefVertex returns the reference vertex of a given face - * @param f the face - * @return the reference vertex (i.e., vertex 0, by convention). - */ - Vertex getRefVertex(const Face& f) const - { - return getVertexByNo(f,0) ; - } - - // Vertex getLeftBottomVertex(const VertexAttribute& position, const Face& f) - // { - // Vertex lbv = Vertex(f.dart) ; - // map_.foreach_incident_vertex(f, - // [&] (Vertex v) - // { - // const VEC& p = position[v] ; - // if (p[1] < position[lbv][1]) - // { - // lbv = v ; - // } - // else if (p[1] == position[lbv][1]) - // { - // if (p[0] < position[lbv][0]) - // { - // lbv = v ; - // } - // } - // }) ; - - // return lbv ; - // } - - /** - * @brief getVertexByNo returns the nth vertex of a face, in counterclockwise numbering starting from the reference vertex - * @param f the face - * @param no the vertex to fetch - * @return the requested vertex - */ - Vertex getVertexByNo(const Face& f, uint no) const - { - assert(no<4) ; - return Vertex(getDartByOrient(f,Orient(no))) ; - } - - /** - * @brief getDartByOrient returns the dart of a face oriented in a given target orientation - * @param f the face - * @param target_orient the orientation for which the dart needs to be returned - * @return the dart corresponding to the requested orientation in face #f - */ - const Dart getDartByOrient(const Face& f, const Orient& target_orient) const - { - Dart res ; - map_.foreach_dart_of_orbit(f, [&] (Dart d) -> bool - { - if (dart_orientation_[d].value_ == target_orient) - { - res = d ; - return false ; - } - return true ; - }); - - return res ; -// map_.foreach_incident_edge(f, -// [&] (Edge e) -// Dart d = f.dart ; -// for (uint i = 0 ; i < target_orient ; ++i) -// d = map_.phi1(d) ; - -// return d ; - } - - /** - * @brief getOrientOfDart tests if a given dart is in face #f, and returns its orientation is yes, INVALID_ORIENT otherwise - * @param d the dart - * @param f the face - * @return the orientation of the face, or INVALID_ORIENT if the dart is not in the face - */ - Orient getOrientOfDart(const Dart& d) const - { - return dart_orientation_[d].value_ ; - } -// /** -// * @brief getVertexOfFace returns the vertex number vertexNo of Face f. -// * @param f -// * @param vertexNo -// * @return -// */ -// const Vertex getVertexOfFace(const Face& f, uint vertexNo) const -// { -// Dart d = f.dart ; -// for (uint i = 0 ; i < vertexNo ; ++i) -// d = map_.phi1(d) ; - -// return Vertex(d) ; -// } - - - // ------------------------ Tools: getR for adjacent Faces -------------------------------- + /** + * @brief getRefVertex returns the reference vertex of a given face + * @param f the face + * @return the reference vertex (i.e., vertex 0, by convention). + */ + Vertex getRefVertex(const Face& f) const + { + return getVertexByNo(f,0) ; + } + + // Vertex getLeftBottomVertex(const VertexAttribute& position, const Face& f) + // { + // Vertex lbv = Vertex(f.dart) ; + // map_.foreach_incident_vertex(f, + // [&] (Vertex v) + // { + // const VEC& p = position[v] ; + // if (p[1] < position[lbv][1]) + // { + // lbv = v ; + // } + // else if (p[1] == position[lbv][1]) + // { + // if (p[0] < position[lbv][0]) + // { + // lbv = v ; + // } + // } + // }) ; + + // return lbv ; + // } + + /** + * @brief getVertexByNo returns the nth vertex of a face, in counterclockwise numbering starting from the reference vertex + * @param f the face + * @param no the vertex to fetch + * @return the requested vertex + */ + Vertex getVertexByNo(const Face& f, uint no) const + { + assert(no<4) ; + return Vertex(getDartByOrient(f,Orient(no))) ; + } + + /** + * @brief getDartByOrient returns the dart of a face oriented in a given target orientation + * @param f the face + * @param target_orient the orientation for which the dart needs to be returned + * @return the dart corresponding to the requested orientation in face #f + */ + const Dart getDartByOrient(const Face& f, const Orient& target_orient) const + { + Dart res ; + map_.foreach_dart_of_orbit(f, [&] (Dart d) -> bool + { + if (dart_orientation_[d].value_ == target_orient) + { + res = d ; + return false ; + } + return true ; + }); + + return res ; + // map_.foreach_incident_edge(f, + // [&] (Edge e) + // Dart d = f.dart ; + // for (uint i = 0 ; i < target_orient ; ++i) + // d = map_.phi1(d) ; + + // return d ; + } + + /** + * @brief getOrientOfDart tests if a given dart is in face #f, and returns its orientation is yes, INVALID_ORIENT otherwise + * @param d the dart + * @param f the face + * @return the orientation of the face, or INVALID_ORIENT if the dart is not in the face + */ + Orient getOrientOfDart(const Dart& d) const + { + return dart_orientation_[d].value_ ; + } + // /** + // * @brief getVertexOfFace returns the vertex number vertexNo of Face f. + // * @param f + // * @param vertexNo + // * @return + // */ + // const Vertex getVertexOfFace(const Face& f, uint vertexNo) const + // { + // Dart d = f.dart ; + // for (uint i = 0 ; i < vertexNo ; ++i) + // d = map_.phi1(d) ; + + // return Vertex(d) ; + // } + + + // ------------------------ Tools: getR for adjacent Faces -------------------------------- private: - /** - * @brief getFaceInOrient tests if a given face #f has a neighboring sewed face to its #DartDirection direction. - * If yes, the Face returned is of the found face - * If no, the Face returned is invalid. - * @param f - * @param dart_orientation - * @param target_type - * @return a valid Face to the face found if it exists, an invalid dart otherwise. - */ - const Face getFaceInOrient(const Face& f, const Orient& orientation) const - { - Face res ; - - const Dart& dTmp = getDartByOrient(f,orientation) ; - const Dart& dPhi2 = map_.phi2(dTmp) ; - if (dTmp != dPhi2) // if there is a neighboring face there - { - res = Face(dPhi2) ; - } - - return res ; - } - - // ------------------------ Random Tools -------------------------------- - bool is_border(Dart d) const - { - return map_.phi2(d) == d ; - } + /** + * @brief getFaceInOrient tests if a given face #f has a neighboring sewed face to its #DartDirection direction. + * If yes, the Face returned is of the found face + * If no, the Face returned is invalid. + * @param f + * @param dart_orientation + * @param target_type + * @return a valid Face to the face found if it exists, an invalid dart otherwise. + */ + const Face getFaceInOrient(const Face& f, const Orient& orientation) const + { + Face res ; + + const Dart& dTmp = getDartByOrient(f,orientation) ; + const Dart& dPhi2 = map_.phi2(dTmp) ; + if (dTmp != dPhi2) // if there is a neighboring face there + { + res = Face(dPhi2) ; + } + + return res ; + } + + // ------------------------ Random Tools -------------------------------- + bool is_border(Dart d) const + { + return map_.phi2(d) == d ; + } }; } //namespace modeling diff --git a/cgogn/rendering/map_render.cpp b/cgogn/rendering/map_render.cpp index 46d2ea62..5e148f08 100644 --- a/cgogn/rendering/map_render.cpp +++ b/cgogn/rendering/map_render.cpp @@ -59,9 +59,9 @@ void MapRender::draw(DrawingType prim) case TRIANGLES: ogl->glDrawElements(GL_TRIANGLES, nb_indices_[TRIANGLES], GL_UNSIGNED_INT, 0); break; - case QUAD: - ogl->glDrawElements(GL_LINES_ADJACENCY, nb_indices_[QUAD], GL_UNSIGNED_INT, 0); - break; + case QUAD: + ogl->glDrawElements(GL_LINES_ADJACENCY, nb_indices_[QUAD], GL_UNSIGNED_INT, 0); + break; case BOUNDARY: switch (boundary_dimension_) { diff --git a/cgogn/rendering/map_render.h b/cgogn/rendering/map_render.h index 9a99ef51..b77643b5 100644 --- a/cgogn/rendering/map_render.h +++ b/cgogn/rendering/map_render.h @@ -48,7 +48,7 @@ enum DrawingType : uint8 POINTS = 0, LINES, TRIANGLES, - QUAD, + QUAD, BOUNDARY, SIZE_BUFFER }; @@ -83,7 +83,7 @@ class CGOGN_RENDERING_API MapRender template inline void init_points(const MAP& m, const MASK& mask, std::vector& table_indices) { -// table_indices.reserve(m.get_nb_darts() / 6); + // table_indices.reserve(m.get_nb_darts() / 6); m.foreach_cell([&] (typename MAP::Vertex v) { table_indices.push_back(m.embedding(v)); @@ -97,7 +97,7 @@ class CGOGN_RENDERING_API MapRender using Vertex = typename MAP::Vertex; using Edge = typename MAP::Edge; -// table_indices.reserve(m.get_nb_darts() / 2); + // table_indices.reserve(m.get_nb_darts() / 2); m.foreach_cell([&] (Edge e) { std::pair vs = m.vertices(e); @@ -114,7 +114,7 @@ class CGOGN_RENDERING_API MapRender using Face = typename MAP::Face; // reserve more ? -// table_indices.reserve(m.get_nb_darts() / 3); + // table_indices.reserve(m.get_nb_darts() / 3); m.foreach_cell([&] (Face f) { Dart d0 = f.dart; @@ -134,17 +134,17 @@ class CGOGN_RENDERING_API MapRender template inline void init_triangles_ear( - const MAP& m, - const MASK& mask, - std::vector& table_indices, - const typename MAP::template VertexAttribute* position - ) + const MAP& m, + const MASK& mask, + std::vector& table_indices, + const typename MAP::template VertexAttribute* position + ) { using Vertex = typename MAP::Vertex; using Face = typename MAP::Face; // reserve more ? -// table_indices.reserve(m.get_nb_darts() / 3); + // table_indices.reserve(m.get_nb_darts() / 3); m.foreach_cell([&] (Face f) { if (m.has_codegree(f, 3)) @@ -159,29 +159,29 @@ class CGOGN_RENDERING_API MapRender mask); } - template - inline void init_quad(const MAP& m, const MASK& mask, std::vector& table_indices) - { - using Vertex = typename MAP::Vertex; - using Face = typename MAP::Face; - - m.foreach_cell([&] (Face f) - { - Dart d0 = f.dart; - Dart d1 = m.phi1(d0); - Dart d2 = m.phi1(d1); - Dart d3 = m.phi1(d2); - table_indices.push_back(m.embedding(Vertex(d0))); - table_indices.push_back(m.embedding(Vertex(d1))); - table_indices.push_back(m.embedding(Vertex(d2))); - table_indices.push_back(m.embedding(Vertex(d3))); - }, - mask); - } + template + inline void init_quad(const MAP& m, const MASK& mask, std::vector& table_indices) + { + using Vertex = typename MAP::Vertex; + using Face = typename MAP::Face; + + m.foreach_cell([&] (Face f) + { + Dart d0 = f.dart; + Dart d1 = m.phi1(d0); + Dart d2 = m.phi1(d1); + Dart d3 = m.phi1(d2); + table_indices.push_back(m.embedding(Vertex(d0))); + table_indices.push_back(m.embedding(Vertex(d1))); + table_indices.push_back(m.embedding(Vertex(d2))); + table_indices.push_back(m.embedding(Vertex(d3))); + }, + mask); + } template inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) - -> typename std::enable_if::value, void>::type + -> typename std::enable_if::value, void>::type { using Vertex = typename MAP::Vertex; using Edge = typename MAP::Edge; @@ -202,7 +202,7 @@ class CGOGN_RENDERING_API MapRender template inline auto init_boundaries(const MAP& m, const MASK& /*mask*/, std::vector& table_indices) - -> typename std::enable_if::value, void>::type + -> typename std::enable_if::value, void>::type { // if the given MASK is not a BoundaryCache, build a BoundaryCache and use it typename MAP::BoundaryCache bcache(m); @@ -211,7 +211,7 @@ class CGOGN_RENDERING_API MapRender template inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) - -> typename std::enable_if::value, void>::type + -> typename std::enable_if::value, void>::type { using Vertex = typename MAP::Vertex; using Face = typename MAP::Face; @@ -241,7 +241,7 @@ class CGOGN_RENDERING_API MapRender template inline auto init_boundaries(const MAP& m, const MASK& mask, std::vector& table_indices) - -> typename std::enable_if::value, void>::type + -> typename std::enable_if::value, void>::type { unused_parameters(mask); // if the given MASK is not a BoundaryCache, build a BoundaryCache and use it @@ -259,11 +259,11 @@ class CGOGN_RENDERING_API MapRender template inline void init_primitives( - const MAP& m, - const MASK& mask, - DrawingType prim, - const typename MAP::template VertexAttribute* position - ) + const MAP& m, + const MASK& mask, + DrawingType prim, + const typename MAP::template VertexAttribute* position + ) { std::vector table_indices; @@ -283,9 +283,9 @@ class CGOGN_RENDERING_API MapRender init_triangles(m, mask, table_indices); indices_tri_.clear(); break; - case QUAD: - init_quad(m, mask, table_indices) ; - break; + case QUAD: + init_quad(m, mask, table_indices) ; + break; case BOUNDARY: init_boundaries(m, mask, table_indices); break; @@ -305,20 +305,20 @@ class CGOGN_RENDERING_API MapRender template inline void init_primitives( - const MAP& m, - DrawingType prim, - const typename MAP::template VertexAttribute* position - ) + const MAP& m, + DrawingType prim, + const typename MAP::template VertexAttribute* position + ) { init_primitives(m, AllCellsFilter(), prim, position); } template inline void init_primitives( - const MAP& m, - const MASK& mask, - DrawingType prim - ) + const MAP& m, + const MASK& mask, + DrawingType prim + ) { std::vector table_indices; @@ -357,9 +357,9 @@ class CGOGN_RENDERING_API MapRender template inline void init_primitives( - const MAP& m, - DrawingType prim - ) + const MAP& m, + DrawingType prim + ) { init_primitives(m, AllCellsFilter(), prim); } @@ -393,11 +393,11 @@ void transform_position(const MAP& map, const typename MAP::template VertexAttri */ template void create_indices_vertices_faces( - const MAP& m, - const typename MAP::template VertexAttribute& position, - std::vector& indices1, - std::vector& indices2 -) + const MAP& m, + const typename MAP::template VertexAttribute& position, + std::vector& indices1, + std::vector& indices2 + ) { using Vertex = typename MAP::Vertex; using Face = typename MAP::Face; From e3d0cc51b077e596a7188b9c0223f2d629ed6769 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Wed, 13 Sep 2017 13:18:08 +0200 Subject: [PATCH 12/26] sampling parallelograms --- cgogn/modeling/tiling/parallelogram_grid.h | 60 +++++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index e639dff0..f97f14e8 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -108,18 +108,56 @@ class Parallelogram return Tj_ ; } - uint sample_parallelograms(std::vector& samples, uint p_bins, uint mag_i_bins, uint alpha_i_bins, uint mag_j_bins, uint alpha_j_bins) const + static + uint sample_parallelograms(std::vector& samples, uint angular_bins, uint magnitude_bins, uint diagonal) { samples.clear() ; + const uint half_diagonal = diagonal / 2 ; - // TODO - assert(false) ; - + const double angular_step = M_PI * (1.0 / angular_bins) ; + for (double alpha_i = angular_step ; alpha_i < M_PI ; alpha_i += angular_step) + { + for (double alpha_j = alpha_i + angular_step ; alpha_j <= M_PI ; alpha_j += angular_step) + { + magnitude_bins = std::min(magnitude_bins,half_diagonal) ; + const uint mag_step = floor(half_diagonal / magnitude_bins) ; + for (uint mag_i = 1 ; mag_i < half_diagonal ; mag_i += mag_step) + { + for (uint mag_j = 1 ; mag_j < half_diagonal ; mag_j += mag_step) + { + VEC p0 = VEC::Zero(); + Parallelogram p(p0,mag_i,alpha_i,mag_j,alpha_j) ; + samples.push_back(p) ; + std::cout << p << std::endl ; + } + } + } + } return samples.size() ; } + inline friend std::ostream& operator<<(std::ostream& o, const Parallelogram& p) + { + o << "p0(" ; + for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime -2ul ; ++i ) + o << p.p_[i] << ","; + o << p.p_[VEC::SizeAtCompileTime -1ul] << "), " ; + + o << "Ti(" ; + for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime -2ul ; ++i ) + o << p.Ti_[i] << ","; + o << p.Ti_[VEC::SizeAtCompileTime -1ul] << "), " ; + + o << "Tj(" ; + for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime -2ul ; ++i ) + o << p.Tj_[i] << ","; + o << p.Tj_[VEC::SizeAtCompileTime -1ul] << ")" ; + + return o; + } + private: void init(const VEC& p, const VEC& Ti, const VEC& Tj) { @@ -133,9 +171,12 @@ class Parallelogram bool is_valid() const { - bool res = Ti_[0] > 0 && Tj_[0] >= 0 && Tj_[1] > Ti_[1] ; - cgogn_assert((acos(-Tj_[1] / Tj_.norm()) > acos(-Ti_[1] / Ti_.norm())) == res) ; - return res && p_.norm() > 1e-10 && Ti_.norm() > 1e-10 && Tj_.norm() > 1e-10 ; + bool res = Ti_[0] > 0 && Tj_[0] >= 0 ; + const double alpha_i = acos(-Ti_[1] / Ti_.norm()) ; + const double alpha_j = acos(-Tj_[1] / Tj_.norm()) ; + res &= (res == (alpha_j > alpha_i)) ; + res &= !almost_equal_absolute(Ti_.norm(),0.0) && !almost_equal_absolute(Tj_.norm(),0.0) ; + return res ; } }; @@ -195,7 +236,10 @@ class ParallelogramGrid ParallelogramGrid(MAP& map, const geometry::AABB& fill_area): map_(map), area_(fill_area) - {} + { + std::vector > samples ; + std::cout << Parallelogram::sample_parallelograms(samples,10,10,fill_area.diag_size()) << std::endl ; + } /** * @brief embed_with_parallelograms creates a mesh composed of a tiling of identical parallelograms. From f50c66f166bcc02e3add4bcfb4d8cc2e3f51d5ff Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Wed, 13 Sep 2017 15:14:52 +0200 Subject: [PATCH 13/26] sample parallelograms --- cgogn/modeling/tiling/parallelogram_grid.h | 54 +++++++++++++++------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index f97f14e8..d5dcc2b6 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -73,7 +73,7 @@ class Parallelogram */ Parallelogram(const VEC& p, const double& mag_i, const double& alpha_i, const double& mag_j, const double& alpha_j ) { - VEC Ti,Tj ; + VEC Ti = VEC::Zero() ,Tj = VEC::Zero() ; Ti[0] = mag_i*sin(alpha_i) ; Ti[1] = -mag_i*cos(alpha_i) ; Tj[0] = mag_j*sin(alpha_j) ; @@ -108,8 +108,35 @@ class Parallelogram return Tj_ ; } - static - uint sample_parallelograms(std::vector& samples, uint angular_bins, uint magnitude_bins, uint diagonal) + /** + * @brief getAlpha returns the angle between the negative y-axis and the vector, in counterclockwise direction + * @param T the vector + * @return an angle in [[0 M_PI]] + */ + static double getAlpha(const VEC& T) + { + return acos(-T[1] / T.norm()) ; + } + + /** + * @brief getAlphaI returns the angle of the first vector Ti using #getAlpha + * @return an angle in ]]0 M_PI[[ + */ + double getAlphaI() const + { + return getAlpha(Ti_) ; + } + + /** + * @brief getAlphaJ returns the angle of the second vector Tj using #getAlpha + * @return an angle in ]]0 M_PI]] + */ + double getAlphaJ() const + { + return getAlpha(Tj_) ; + } + + static uint sample_parallelograms(std::vector& samples, uint angular_bins, uint magnitude_bins, uint diagonal) { samples.clear() ; @@ -141,17 +168,17 @@ class Parallelogram inline friend std::ostream& operator<<(std::ostream& o, const Parallelogram& p) { o << "p0(" ; - for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime -2ul ; ++i ) + for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime - 1ul ; ++i ) o << p.p_[i] << ","; o << p.p_[VEC::SizeAtCompileTime -1ul] << "), " ; o << "Ti(" ; - for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime -2ul ; ++i ) + for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime - 1ul ; ++i ) o << p.Ti_[i] << ","; o << p.Ti_[VEC::SizeAtCompileTime -1ul] << "), " ; o << "Tj(" ; - for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime -2ul ; ++i ) + for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime - 1ul ; ++i ) o << p.Tj_[i] << ","; o << p.Tj_[VEC::SizeAtCompileTime -1ul] << ")" ; @@ -172,9 +199,7 @@ class Parallelogram bool is_valid() const { bool res = Ti_[0] > 0 && Tj_[0] >= 0 ; - const double alpha_i = acos(-Ti_[1] / Ti_.norm()) ; - const double alpha_j = acos(-Tj_[1] / Tj_.norm()) ; - res &= (res == (alpha_j > alpha_i)) ; + res &= (res == (getAlphaJ() > getAlphaI())) ; res &= !almost_equal_absolute(Ti_.norm(),0.0) && !almost_equal_absolute(Tj_.norm(),0.0) ; return res ; } @@ -236,10 +261,7 @@ class ParallelogramGrid ParallelogramGrid(MAP& map, const geometry::AABB& fill_area): map_(map), area_(fill_area) - { - std::vector > samples ; - std::cout << Parallelogram::sample_parallelograms(samples,10,10,fill_area.diag_size()) << std::endl ; - } + {} /** * @brief embed_with_parallelograms creates a mesh composed of a tiling of identical parallelograms. @@ -257,10 +279,10 @@ class ParallelogramGrid * * @post the map is embedded with a VertexAttribute called "position". */ - void embed_with_parallelograms(const VEC& fixed_point, const VEC& Ti, const VEC& Tj) + void embed_with_parallelograms(const Parallelogram& p) { - cgogn_assert(area_.contains(fixed_point)) ; - p_ = Parallelogram(fixed_point,Ti,Tj) ; ; + cgogn_assert(area_.contains(p.getRefPos())) ; + p_ = p ; vertex_position_ = map_.template get_attribute("position") ; if (!vertex_position_.is_valid()) From c12be0ee8de730552f6631850686118edadcc751 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Mon, 18 Sep 2017 18:14:39 +0200 Subject: [PATCH 14/26] Sample parallelograms updated --- cgogn/modeling/tiling/parallelogram_grid.h | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index d5dcc2b6..1eca8efe 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -136,27 +136,31 @@ class Parallelogram return getAlpha(Tj_) ; } - static uint sample_parallelograms(std::vector& samples, uint angular_bins, uint magnitude_bins, uint diagonal) + static uint sample_parallelograms(std::queue& samples, uint angular_bins, uint magnitude_bins, uint diagonal) { - samples.clear() ; - const uint half_diagonal = diagonal / 2 ; const double angular_step = M_PI * (1.0 / angular_bins) ; - for (double alpha_i = angular_step ; alpha_i < M_PI ; alpha_i += angular_step) + magnitude_bins = std::min(magnitude_bins,half_diagonal) ; + const uint mag_step = floor(half_diagonal / magnitude_bins) ; + + for (uint mag_i = mag_step ; mag_i <= half_diagonal ; mag_i += mag_step) { - for (double alpha_j = alpha_i + angular_step ; alpha_j <= M_PI ; alpha_j += angular_step) + for (uint mag_j = mag_step ; mag_j <= half_diagonal ; mag_j += mag_step) { - magnitude_bins = std::min(magnitude_bins,half_diagonal) ; - const uint mag_step = floor(half_diagonal / magnitude_bins) ; - for (uint mag_i = 1 ; mag_i < half_diagonal ; mag_i += mag_step) + double start_alpha = M_PI/2.0 - floor(M_PI/2.0 / angular_step)*angular_step ; // M_PI/2 - n times angular_step so that smallest possible > 0 + for (double alpha_i = start_alpha ; alpha_i <= M_PI ; alpha_i += angular_step) { - for (uint mag_j = 1 ; mag_j < half_diagonal ; mag_j += mag_step) + // if x coordinate of Ti will be 0 + if (mag_i * sin(alpha_i) < 1.0) + continue ; + + for (double alpha_j = M_PI ; alpha_j > alpha_i ; alpha_j -= angular_step) { VEC p0 = VEC::Zero(); Parallelogram p(p0,mag_i,alpha_i,mag_j,alpha_j) ; - samples.push_back(p) ; - std::cout << p << std::endl ; + //Parallelogram p(VEC(0,0,0),VEC(25.5,-44.1673,0),VEC(44.1673,25.5,0)) ; + samples.push(p) ; } } } From c2dcb16cabb02e4e8add490627e9b6ffe4df14f3 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Mon, 18 Sep 2017 18:14:39 +0200 Subject: [PATCH 15/26] Sample parallelograms updated --- cgogn/modeling/tiling/parallelogram_grid.h | 1 - 1 file changed, 1 deletion(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index 1eca8efe..23a1198e 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -159,7 +159,6 @@ class Parallelogram { VEC p0 = VEC::Zero(); Parallelogram p(p0,mag_i,alpha_i,mag_j,alpha_j) ; - //Parallelogram p(VEC(0,0,0),VEC(25.5,-44.1673,0),VEC(44.1673,25.5,0)) ; samples.push(p) ; } } From b0726f535cd64a61655cc16873fcc0fa62ef8693 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Fri, 22 Sep 2017 18:53:34 +0200 Subject: [PATCH 16/26] bug fixing --- cgogn/modeling/tiling/parallelogram_grid.h | 66 ++++++++++++++++------ 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index 23a1198e..14ebcc62 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -108,6 +108,24 @@ class Parallelogram return Tj_ ; } + /** + * @brief getMagI returns the magnitude of the first vector + * @return magnitude of the first vector + */ + typename VEC::Scalar getMagI() const + { + return Ti_.norm() ; + } + + /** + * @brief getMagJ returns the magnitude of the second vector + * @return magnitude of the second vector + */ + typename VEC::Scalar getMagJ() const + { + return Tj_.norm() ; + } + /** * @brief getAlpha returns the angle between the negative y-axis and the vector, in counterclockwise direction * @param T the vector @@ -136,7 +154,7 @@ class Parallelogram return getAlpha(Tj_) ; } - static uint sample_parallelograms(std::queue& samples, uint angular_bins, uint magnitude_bins, uint diagonal) + static uint sample_parallelograms(std::queue& samples, uint angular_bins, uint magnitude_bins, uint pos_bins, uint diagonal) { const uint half_diagonal = diagonal / 2 ; @@ -157,9 +175,26 @@ class Parallelogram for (double alpha_j = M_PI ; alpha_j > alpha_i ; alpha_j -= angular_step) { - VEC p0 = VEC::Zero(); - Parallelogram p(p0,mag_i,alpha_i,mag_j,alpha_j) ; - samples.push(p) ; + if (!almost_equal_absolute(alpha_i,alpha_j,std::min(angular_step,M_PI/16.0))) // If alpha_i and alpha_j are too close + { + const double move_i = double(mag_i)/pos_bins ; + const double move_j = double(mag_j)/pos_bins ; + /*if (move_i < 4 || move_j < 4 ) + continue ;*/ + + VEC p0 = VEC::Zero(); + for (uint pi = 0 ; pi < pos_bins ; ++pi) + { + p0[1] = 0 ; + for (uint pj = 0 ; pj < pos_bins ; ++pj) + { + Parallelogram p(p0,mag_i,alpha_i,mag_j,alpha_j) ; + samples.push(p) ; + p0[1] += move_j ; + } + p0[0] += move_i ; + } + } } } } @@ -172,18 +207,13 @@ class Parallelogram { o << "p0(" ; for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime - 1ul ; ++i ) - o << p.p_[i] << ","; - o << p.p_[VEC::SizeAtCompileTime -1ul] << "), " ; - - o << "Ti(" ; - for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime - 1ul ; ++i ) - o << p.Ti_[i] << ","; - o << p.Ti_[VEC::SizeAtCompileTime -1ul] << "), " ; + o << p.getRefPos()[i] << ","; + o << p.p_[VEC::SizeAtCompileTime -1ul] << ")," ; - o << "Tj(" ; - for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime - 1ul ; ++i ) - o << p.Tj_[i] << ","; - o << p.Tj_[VEC::SizeAtCompileTime -1ul] << ")" ; + o << "Ti(mag=" << p.getTi().norm() ; + o << ",alpha=" << p.getAlphaI() << ")," ; + o << "Tj(mag=" << p.getTj().norm() ; + o << ",alpha=" << p.getAlphaJ() << ")"; return o; } @@ -282,7 +312,7 @@ class ParallelogramGrid * * @post the map is embedded with a VertexAttribute called "position". */ - void embed_with_parallelograms(const Parallelogram& p) + Dart embed_with_parallelograms(const Parallelogram& p) { cgogn_assert(area_.contains(p.getRefPos())) ; p_ = p ; @@ -374,6 +404,8 @@ class ParallelogramGrid // uint nbF = map_.template nb_cells(); // std::cout << "Nb Vertices: " << nbV << std::endl ; // std::cout << "Nb Faces: " << nbF << std::endl ; + + return dart_; } // Orient sew_FaceEdge(MapBuilder& mbuild, /*const DartAttribute& dart_orientation,*/ const Face& f0, const Edge& e0) @@ -476,6 +508,8 @@ class ParallelogramGrid position[Vertex(d2)] = position[d1] + p_.getTj() ; position[Vertex(d3)] = p0 + p_.getTj() ; + + geometry::AABB bbox(p0) ; bbox.add_point(position[d1]) ; bbox.add_point(position[d2]) ; From 49215876abdf62502ae683a485f0008018b9d580 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Fri, 29 Sep 2017 10:25:24 +0200 Subject: [PATCH 17/26] double templates for parallelogram_grid --- cgogn/modeling/tiling/parallelogram_grid.h | 68 +++++++++++++--------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index 14ebcc62..be2ef31f 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -18,10 +18,11 @@ namespace modeling * @brief The Parallelogram class. * Defines a parallelogram by a point and two vectors. */ -template +template class Parallelogram { private: + using VEC = Eigen::Matrix ; VEC p_ ; VEC Ti_ ; VEC Tj_ ; @@ -33,9 +34,9 @@ class Parallelogram { p_ = VEC::Zero() ; Ti_ = VEC::Zero() ; - Ti_[0] = 1.0 ; + Ti_[0] = T(1) ; Tj_ = VEC::Zero() ; - Tj_[1] = 1.0 ; + Tj_[1] = T(1) ; } /** @@ -71,7 +72,7 @@ class Parallelogram * @pre 0 < alpha_i < M_PI * @pre alpha_i < alpha_j <= M_PI */ - Parallelogram(const VEC& p, const double& mag_i, const double& alpha_i, const double& mag_j, const double& alpha_j ) + Parallelogram(const VEC& p, const T& mag_i, const T& alpha_i, const T& mag_j, const T& alpha_j ) { VEC Ti = VEC::Zero() ,Tj = VEC::Zero() ; Ti[0] = mag_i*sin(alpha_i) ; @@ -112,7 +113,7 @@ class Parallelogram * @brief getMagI returns the magnitude of the first vector * @return magnitude of the first vector */ - typename VEC::Scalar getMagI() const + T getMagI() const { return Ti_.norm() ; } @@ -121,26 +122,26 @@ class Parallelogram * @brief getMagJ returns the magnitude of the second vector * @return magnitude of the second vector */ - typename VEC::Scalar getMagJ() const + T getMagJ() const { return Tj_.norm() ; } /** * @brief getAlpha returns the angle between the negative y-axis and the vector, in counterclockwise direction - * @param T the vector + * @param v the vector * @return an angle in [[0 M_PI]] */ - static double getAlpha(const VEC& T) + static T getAlpha(const VEC& v) { - return acos(-T[1] / T.norm()) ; + return acos(-v[1] / v.norm()) ; } /** * @brief getAlphaI returns the angle of the first vector Ti using #getAlpha * @return an angle in ]]0 M_PI[[ */ - double getAlphaI() const + T getAlphaI() const { return getAlpha(Ti_) ; } @@ -149,16 +150,25 @@ class Parallelogram * @brief getAlphaJ returns the angle of the second vector Tj using #getAlpha * @return an angle in ]]0 M_PI]] */ - double getAlphaJ() const + T getAlphaJ() const { return getAlpha(Tj_) ; } - static uint sample_parallelograms(std::queue& samples, uint angular_bins, uint magnitude_bins, uint pos_bins, uint diagonal) + /** + * @brief nb_scalars returns the amount of scalars needed for the internal representation of a parallelogram + * @return the amount of scalars needed for the internal representation of a parallelogram + */ + constexpr static uint nb_scalars() + { + return 3 * VEC::SizeAtCompileTime ; + } + + static uint sample_parallelograms_uniform(std::queue& samples, uint angular_bins, uint magnitude_bins, uint pos_bins, uint diagonal) { const uint half_diagonal = diagonal / 2 ; - const double angular_step = M_PI * (1.0 / angular_bins) ; + const T angular_step = M_PI * (1.0 / angular_bins) ; magnitude_bins = std::min(magnitude_bins,half_diagonal) ; const uint mag_step = floor(half_diagonal / magnitude_bins) ; @@ -166,29 +176,29 @@ class Parallelogram { for (uint mag_j = mag_step ; mag_j <= half_diagonal ; mag_j += mag_step) { - double start_alpha = M_PI/2.0 - floor(M_PI/2.0 / angular_step)*angular_step ; // M_PI/2 - n times angular_step so that smallest possible > 0 - for (double alpha_i = start_alpha ; alpha_i <= M_PI ; alpha_i += angular_step) + T start_alpha = M_PI/2.0 - floor(M_PI/2.0 / angular_step)*angular_step ; // M_PI/2 - n times angular_step so that smallest possible > 0 + for (T alpha_i = start_alpha ; alpha_i <= M_PI ; alpha_i += angular_step) { // if x coordinate of Ti will be 0 if (mag_i * sin(alpha_i) < 1.0) continue ; - for (double alpha_j = M_PI ; alpha_j > alpha_i ; alpha_j -= angular_step) + for (T alpha_j = M_PI ; alpha_j > alpha_i ; alpha_j -= angular_step) { if (!almost_equal_absolute(alpha_i,alpha_j,std::min(angular_step,M_PI/16.0))) // If alpha_i and alpha_j are too close { - const double move_i = double(mag_i)/pos_bins ; - const double move_j = double(mag_j)/pos_bins ; - /*if (move_i < 4 || move_j < 4 ) - continue ;*/ + const T move_i = T(mag_i-1)/pos_bins ; + const T move_j = T(mag_j-1)/pos_bins ; + if (move_i < 2 || move_j < 2 ) + continue ; VEC p0 = VEC::Zero(); for (uint pi = 0 ; pi < pos_bins ; ++pi) { - p0[1] = 0 ; + p0[1] = 0.0 ; for (uint pj = 0 ; pj < pos_bins ; ++pj) { - Parallelogram p(p0,mag_i,alpha_i,mag_j,alpha_j) ; + Parallelogram p(p0,mag_i,alpha_i,mag_j,alpha_j) ; samples.push(p) ; p0[1] += move_j ; } @@ -203,7 +213,7 @@ class Parallelogram return samples.size() ; } - inline friend std::ostream& operator<<(std::ostream& o, const Parallelogram& p) + inline friend std::ostream& operator<<(std::ostream& o, const Parallelogram& p) { o << "p0(" ; for (std::size_t i = 0ul ; i < VEC::SizeAtCompileTime - 1ul ; ++i ) @@ -231,9 +241,11 @@ class Parallelogram bool is_valid() const { - bool res = Ti_[0] > 0 && Tj_[0] >= 0 ; - res &= (res == (getAlphaJ() > getAlphaI())) ; - res &= !almost_equal_absolute(Ti_.norm(),0.0) && !almost_equal_absolute(Tj_.norm(),0.0) ; + bool res = true ; + res &= Ti_[0] > T(0) && Tj_[0] >= T(0) ; // positive X coordinates + res &= (res == (getAlphaJ() > getAlphaI())) ; // 2nd vector above 1st. + //res &= !almost_equal_absolute(Ti_.norm(),T(0)) && !almost_equal_absolute(Tj_.norm(),T(0)) ; // non-zero vectors + return res ; } }; @@ -280,7 +292,7 @@ class ParallelogramGrid Dart dart_ ; const geometry::AABB& area_ ; - Parallelogram p_ ; + Parallelogram p_ ; DartAttribute dart_orientation_ ; VertexAttribute vertex_position_ ; @@ -312,7 +324,7 @@ class ParallelogramGrid * * @post the map is embedded with a VertexAttribute called "position". */ - Dart embed_with_parallelograms(const Parallelogram& p) + Dart embed_with_parallelograms(const Parallelogram& p) { cgogn_assert(area_.contains(p.getRefPos())) ; p_ = p ; From 9717168c311e96ecdd4d8f393de8f763eee61fdb Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Thu, 5 Oct 2017 18:25:28 +0200 Subject: [PATCH 18/26] replace assert by warning --- cgogn/core/container/chunk_array_container.h | 2 -- cgogn/modeling/tiling/parallelogram_grid.h | 35 ++++++++++++++------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/cgogn/core/container/chunk_array_container.h b/cgogn/core/container/chunk_array_container.h index cc8b4e80..08f8b62c 100644 --- a/cgogn/core/container/chunk_array_container.h +++ b/cgogn/core/container/chunk_array_container.h @@ -223,7 +223,6 @@ class ChunkArrayContainer const uint32 index = array_index(name); if (index == UNKNOWN) { - cgogn_log_warning("get_chunk_array") << "Chunk array of name \"" << name << "\" not found."; return nullptr; } @@ -242,7 +241,6 @@ class ChunkArrayContainer const uint32 index = array_index(name); if (index == UNKNOWN) { - cgogn_log_warning("get_chunk_array") << "Chunk array of name \"" << name << "\" not found."; return nullptr; } diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index be2ef31f..962561f9 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -228,17 +228,6 @@ class Parallelogram return o; } -private: - void init(const VEC& p, const VEC& Ti, const VEC& Tj) - { - p_ = p ; - Ti_ = Ti ; - Tj_ = Tj ; - cgogn_assert(is_valid()) ; - if (!is_valid()) - cgogn_log_error("Parallelogram::init") << "Attempt to create an invalid Parallelogram."; - } - bool is_valid() const { bool res = true ; @@ -248,6 +237,30 @@ class Parallelogram return res ; } + + void make_valid() + { +// // alpha2 > alpha1 +// const T& a1 = getAlphaI() ; +// const T& a2 = getAlphaJ() ; +// if (a2 ) + +// // Ti positive x coords +// Ti_[0] = clamp(Ti_[0],1) ; +// Tj_[0] = clamp(Tj_[0],0) ; + assert(false) ; // TODO + } + +private: + void init(const VEC& p, const VEC& Ti, const VEC& Tj) + { + p_ = p ; + Ti_ = Ti ; + Tj_ = Tj ; + if (!is_valid()) + cgogn_log_warning("Parallelogram::init") << "Creating an invalid Parallelogram."; + } + }; /** From 1eb98f469b4ee9e7095e9155bb60669949f06c8e Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Fri, 6 Oct 2017 17:47:28 +0200 Subject: [PATCH 19/26] compil fix --- cgogn/core/container/chunk_array.h | 24 ++++++++++++------------ cgogn/core/container/chunk_array_gen.h | 2 +- cgogn/geometry/functions/area.h | 21 ++++++++++++++++++--- cgogn/geometry/types/aabb.h | 3 ++- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/cgogn/core/container/chunk_array.h b/cgogn/core/container/chunk_array.h index 437cb959..7a568396 100644 --- a/cgogn/core/container/chunk_array.h +++ b/cgogn/core/container/chunk_array.h @@ -347,10 +347,10 @@ class ChunkArray : public ChunkArrayGen } } - void import_element(uint32 idx, std::istream& in) override - { - serialization::parse(in, this->operator [](idx)); - } +// void import_element(uint32 idx, std::istream& in) override +// { +// serialization::parse(in, this->operator [](idx)); +// } const void* element_ptr(uint32 idx) const override { @@ -701,14 +701,14 @@ class ChunkArrayBool : public ChunkArrayGen serialization::ostream_writer(o, this->operator[](idx),binary, little_endian); } - void import_element(uint32 idx, std::istream& in) override - { - std::string val; - in >> val; - val = to_lower(val); - const bool b = (val == "true") || (std::stoi(val) != 0); - set_value(idx,b); - } +// void import_element(uint32 idx, std::istream& in) override +// { +// std::string val; +// in >> val; +// val = to_lower(val); +// const bool b = (val == "true") || (std::stoi(val) != 0); +// set_value(idx,b); +// } const void* element_ptr(uint32) const override { diff --git a/cgogn/core/container/chunk_array_gen.h b/cgogn/core/container/chunk_array_gen.h index 21315998..023dc44b 100644 --- a/cgogn/core/container/chunk_array_gen.h +++ b/cgogn/core/container/chunk_array_gen.h @@ -217,7 +217,7 @@ class ChunkArrayGen * @param idx * @param i */ - virtual void import_element(uint32 idx, std::istream& in) = 0; +// virtual void import_element(uint32 idx, std::istream& in) = 0; /** * @brief element_ptr * @return a generic pointer to the element of index idx. diff --git a/cgogn/geometry/functions/area.h b/cgogn/geometry/functions/area.h index 37cdaae8..12b635e9 100644 --- a/cgogn/geometry/functions/area.h +++ b/cgogn/geometry/functions/area.h @@ -35,13 +35,28 @@ namespace geometry /** * area of the triangle formed by 3 points in 3D */ -template -inline typename vector_traits::Scalar area(const VEC3& p1, const VEC3& p2, const VEC3& p3) +template +inline auto area(const VEC& p1, const VEC& p2, const VEC& p3) + -> typename std::enable_if::SIZE == 3, typename vector_traits::Scalar>::type { - using Scalar = typename vector_traits::Scalar; + using Scalar = typename vector_traits::Scalar; return (Scalar(0.5) * ((p2 - p1).cross(p3 - p1)).norm()); } +/** + * area of the triangle formed by 3 points in 2D + */ +template +inline auto area(const VEC& p1, const VEC& p2, const VEC& p3) + -> typename std::enable_if::SIZE == 2, typename vector_traits::Scalar>::type +{ + using Scalar = typename vector_traits::Scalar; + VEC v1 = p2 - p1; + VEC v2 = p3 - p1; + return (Scalar(0.5) * (v1[0] * v2[1] - v1[1] * v2[0])); +} + + } // namespace geometry } // namespace cgogn diff --git a/cgogn/geometry/types/aabb.h b/cgogn/geometry/types/aabb.h index d06755d7..e4806010 100644 --- a/cgogn/geometry/types/aabb.h +++ b/cgogn/geometry/types/aabb.h @@ -274,8 +274,9 @@ class AABB /// \brief Test if a ray intersectes an axis-aligned box /// \tparam VEC3 the domain of the box. Has to be of dimension 3 + template auto ray_intersect(const Vec& P, const Vec& V) const - -> typename std::enable_if::value == 3, bool>::type + -> typename std::enable_if::value == 3, bool>::type { if (!cgogn::almost_equal_relative(V[2], Scalar(0))) { From 869cc70809712e1fc4e30b06bc7a89434ae0205f Mon Sep 17 00:00:00 2001 From: kvanhoey Date: Mon, 9 Oct 2017 19:38:36 +0200 Subject: [PATCH 20/26] tmp commit --- cgogn/core/container/chunk_array_container.h | 4 ++-- cgogn/modeling/tiling/parallelogram_grid.h | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cgogn/core/container/chunk_array_container.h b/cgogn/core/container/chunk_array_container.h index cc8b4e80..420c658e 100644 --- a/cgogn/core/container/chunk_array_container.h +++ b/cgogn/core/container/chunk_array_container.h @@ -223,7 +223,7 @@ class ChunkArrayContainer const uint32 index = array_index(name); if (index == UNKNOWN) { - cgogn_log_warning("get_chunk_array") << "Chunk array of name \"" << name << "\" not found."; + //cgogn_log_warning("get_chunk_array") << "Chunk array of name \"" << name << "\" not found."; return nullptr; } @@ -242,7 +242,7 @@ class ChunkArrayContainer const uint32 index = array_index(name); if (index == UNKNOWN) { - cgogn_log_warning("get_chunk_array") << "Chunk array of name \"" << name << "\" not found."; + //cgogn_log_warning("get_chunk_array") << "Chunk array of name \"" << name << "\" not found."; return nullptr; } diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index be2ef31f..c89c2c29 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -56,6 +56,8 @@ class Parallelogram * @param p the anchor point * @param Ti vector 1 * @param Tj vector 2 + * @pre Ti[0] > 0 + * @pre Tj[0] >= 0 */ Parallelogram(const VEC& p, const VEC& Ti, const VEC& Tj) { @@ -242,7 +244,8 @@ class Parallelogram bool is_valid() const { bool res = true ; - res &= Ti_[0] > T(0) && Tj_[0] >= T(0) ; // positive X coordinates + res &= Ti_[0] > T(0) && (Tj_[0] > T(-1e-6)) ; // positive X coordinates + //res &= Ti_[0] > T(0) && (Tj_[0] > T(0) || almost_equal_absolute(Tj_[0],0.0,1e-6)) ; // positive X coordinates res &= (res == (getAlphaJ() > getAlphaI())) ; // 2nd vector above 1st. //res &= !almost_equal_absolute(Ti_.norm(),T(0)) && !almost_equal_absolute(Tj_.norm(),T(0)) ; // non-zero vectors From 71ffd9cd2edc78522d349b078e59ef2a37090fd5 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Fri, 27 Oct 2017 15:42:55 +0200 Subject: [PATCH 21/26] adding planarity and convexity tests for faces --- cgogn/geometry/algos/convexity.h | 142 +++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 cgogn/geometry/algos/convexity.h diff --git a/cgogn/geometry/algos/convexity.h b/cgogn/geometry/algos/convexity.h new file mode 100644 index 00000000..10c3f87f --- /dev/null +++ b/cgogn/geometry/algos/convexity.h @@ -0,0 +1,142 @@ +/******************************************************************************* +* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * +* Copyright (C) 2015, IGG Group, ICube, University of Strasbourg, France * +* * +* This library is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by the * +* Free Software Foundation; either version 2.1 of the License, or (at your * +* option) any later version. * +* * +* This library 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 Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +* Web site: http://cgogn.unistra.fr/ * +* Contact information: cgogn@unistra.fr * +* * +*******************************************************************************/ + +#ifndef CGOGN_GEOMETRY_ALGOS_CONVEXITY_H +#define CGOGN_GEOMETRY_ALGOS_CONVEXITY_H + +#include +#include + +#include + +namespace cgogn +{ + +namespace geometry +{ + +/** + * @brief isPlanar verifies if a face is planar: defined by the fact that all coordinates other than the first two (x and y) are constant (up to epsilon) + * @param map the map + * @param f the face + * @param position container of vertex positions + * @param epsilon maximum deviation of each component + * @return true iff planar + */ +template +inline bool isPlanar( + const MAP& map, + const typename MAP::Face f, + const typename MAP::template VertexAttribute& position, + typename vector_traits::Scalar epsilon = Eigen::NumTraits::Scalar>::dummy_precision() +) +{ + using Scalar = typename vector_traits::Scalar; + using Vertex = typename MAP::Vertex; + + if (vector_traits::SIZE < 3) + return true ; + + + using VecN_2 = Eigen::Matrix::SIZE - 2,1> ; + // Init with first vertex + VecN_2 depth0 ; + for (uint i = 0 ; i < vector_traits::SIZE - 2 ; ++i) + depth0[i] = position[Vertex(f.dart)][i+2] ; + + // verify that other vertices do not deviate in coordinates 3 (z) and higher. + bool planar = true ; + map.foreach_incident_vertex(f, [&] (Vertex v) -> bool + { + VecN_2 depth ; + for (uint i = 0 ; i < vector_traits::SIZE - 2 ; ++i) + { + depth[i] = position[v][i+2] ; + if (!depth.isApprox(depth0,epsilon)) + { + planar = false ; + } + } + return planar ; + }); + + return planar ; +} + +/** + * @brief isConvex verifies if a given face is convex (in the plane, not in 3D). + * @param map the map + * @param f the face + * @param position the geometric embedding of the vertices + * @pre If the face is not planar (see #isPlanar), false is returned. + * @return true iff the face is convex. + */ +template +inline bool isConvex( + const MAP& map, + const typename MAP::Face f, + const typename MAP::template VertexAttribute& position +) +{ + if (!isPlanar(map,f,position)) + { + cgogn_log_error("Trying to assess convexity of a face while it's not planar. This is ill-defined") ; + return false ; + } + + using Scalar = typename vector_traits::Scalar; + using Vertex = typename MAP::Vertex; + //using Dart = typename MAP::Dart; + + bool convex = true ; + if (map.codegree(f) >= 3) // true otherwise + { + // Take all two consecutive darts and compute cross products. + // The face is convex iff the z components of all products have the same sign. + bool sign ; + bool first = true ; + map.foreach_dart_of_orbit(f, [&] (Dart d) + { + const VEC d1 = vector_from(map,d,position) ; + const VEC d2 = vector_from(map,map.phi1(d),position) ; + const Scalar zcross = d1[0]*d2[1] - d1[1]*d2[0] ; + if (first) + { + sign = (zcross > Scalar(0)) ; + first = false ; + } + else + { + if (sign != (zcross > Scalar(0))) + convex = false ; + } + }); + } + return convex ; +} + +} // Geometry + +} // CGoGN + +#endif // CGOGN_GEOMETRY_ALGOS_CONVEXITY_H From cbd1ec9cd67eb2feae8d0326f244222eb0b25eb7 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Fri, 27 Oct 2017 17:48:42 +0200 Subject: [PATCH 22/26] add parallelogram::isApprox --- cgogn/modeling/tiling/parallelogram_grid.h | 31 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index 7dbb8c48..b7e62f0b 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -76,14 +76,24 @@ class Parallelogram */ Parallelogram(const VEC& p, const T& mag_i, const T& alpha_i, const T& mag_j, const T& alpha_j ) { - VEC Ti = VEC::Zero() ,Tj = VEC::Zero() ; - Ti[0] = mag_i*sin(alpha_i) ; - Ti[1] = -mag_i*cos(alpha_i) ; - Tj[0] = mag_j*sin(alpha_j) ; - Tj[1] = -mag_j*cos(alpha_j) ; +// VEC Ti = VEC::Zero() ,Tj = VEC::Zero() ; + VEC Ti = mag_alpha2coord(mag_i,alpha_i) ; + VEC Tj = mag_alpha2coord(mag_j,alpha_j) ; +// Ti[0] = mag_i*sin(alpha_i) ; +// Ti[1] = -mag_i*cos(alpha_i) ; +// Tj[0] = mag_j*sin(alpha_j) ; +// Tj[1] = -mag_j*cos(alpha_j) ; init(p,Ti,Tj) ; } + static VEC mag_alpha2coord(const T& mag, const T& alpha) + { + VEC t = VEC::Zero() ; + t[0] = mag*sin(alpha) ; + t[1] = -mag*cos(alpha) ; + return t ; + } + /** * @brief getRefPos returns the anchor point * @return the anchor point @@ -157,6 +167,17 @@ class Parallelogram return getAlpha(Tj_) ; } + /** + * @brief is_approx checks if the current parallelogram is identical to another one (up to epsilon) + * @param p the parallelogram to verify to + * @param eps the precision to tolerate + * @return + */ + bool is_approx(const Parallelogram& p, const T& eps = Eigen::NumTraits::dummy_precision()) const + { + return p_.isApprox(p.getRefPos(),eps) && Ti_.isApprox(p.getTi(),eps) && Tj_.isApprox(p.getTj(),eps) ; + } + /** * @brief nb_scalars returns the amount of scalars needed for the internal representation of a parallelogram * @return the amount of scalars needed for the internal representation of a parallelogram From 082bba6df77f776830991150fe72773dc92adebc Mon Sep 17 00:00:00 2001 From: kvanhoey Date: Fri, 27 Oct 2017 19:02:48 +0200 Subject: [PATCH 23/26] correct snake_case --- cgogn/geometry/CMakeLists.txt | 1 + cgogn/geometry/algos/convexity.h | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cgogn/geometry/CMakeLists.txt b/cgogn/geometry/CMakeLists.txt index e47a72ee..e88cb4ec 100644 --- a/cgogn/geometry/CMakeLists.txt +++ b/cgogn/geometry/CMakeLists.txt @@ -8,6 +8,7 @@ set(HEADER_ALGOS algos/area.h algos/centroid.h algos/curvature.h + algos/convexity.h algos/normal.h algos/ear_triangulation.h algos/picking.h diff --git a/cgogn/geometry/algos/convexity.h b/cgogn/geometry/algos/convexity.h index 10c3f87f..8255355b 100644 --- a/cgogn/geometry/algos/convexity.h +++ b/cgogn/geometry/algos/convexity.h @@ -36,7 +36,7 @@ namespace geometry { /** - * @brief isPlanar verifies if a face is planar: defined by the fact that all coordinates other than the first two (x and y) are constant (up to epsilon) + * @brief is_planar verifies if a face is planar: defined by the fact that all coordinates other than the first two (x and y) are constant (up to epsilon) * @param map the map * @param f the face * @param position container of vertex positions @@ -44,7 +44,7 @@ namespace geometry * @return true iff planar */ template -inline bool isPlanar( +inline bool is_planar( const MAP& map, const typename MAP::Face f, const typename MAP::template VertexAttribute& position, @@ -57,7 +57,6 @@ inline bool isPlanar( if (vector_traits::SIZE < 3) return true ; - using VecN_2 = Eigen::Matrix::SIZE - 2,1> ; // Init with first vertex VecN_2 depth0 ; @@ -84,21 +83,21 @@ inline bool isPlanar( } /** - * @brief isConvex verifies if a given face is convex (in the plane, not in 3D). + * @brief is_convex verifies if a given face is convex (in the plane, not in 3D). * @param map the map * @param f the face * @param position the geometric embedding of the vertices - * @pre If the face is not planar (see #isPlanar), false is returned. + * @note if the face is not planar (see #isPlanar), false is returned. * @return true iff the face is convex. */ template -inline bool isConvex( +inline bool is_convex( const MAP& map, const typename MAP::Face f, const typename MAP::template VertexAttribute& position ) { - if (!isPlanar(map,f,position)) + if (!is_planar(map,f,position)) { cgogn_log_error("Trying to assess convexity of a face while it's not planar. This is ill-defined") ; return false ; From 0cad9417b1521ea7bba78c01fd14716ade61c025 Mon Sep 17 00:00:00 2001 From: kvanhoey Date: Fri, 27 Oct 2017 19:02:48 +0200 Subject: [PATCH 24/26] correct snake_case --- cgogn/geometry/algos/convexity.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgogn/geometry/algos/convexity.h b/cgogn/geometry/algos/convexity.h index 8255355b..16edec87 100644 --- a/cgogn/geometry/algos/convexity.h +++ b/cgogn/geometry/algos/convexity.h @@ -87,7 +87,7 @@ inline bool is_planar( * @param map the map * @param f the face * @param position the geometric embedding of the vertices - * @note if the face is not planar (see #isPlanar), false is returned. + * @note if the face is not planar (see #is_planar), false is returned. * @return true iff the face is convex. */ template From bce8843a281a6e3438cab0dc9b05f9f7110a848e Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Mon, 30 Oct 2017 11:04:40 +0100 Subject: [PATCH 25/26] uint -> uint32 for windows compatibility --- cgogn/modeling/tiling/parallelogram_grid.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index b7e62f0b..a85c8dde 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -18,7 +18,7 @@ namespace modeling * @brief The Parallelogram class. * Defines a parallelogram by a point and two vectors. */ -template +template class Parallelogram { private: @@ -182,22 +182,22 @@ class Parallelogram * @brief nb_scalars returns the amount of scalars needed for the internal representation of a parallelogram * @return the amount of scalars needed for the internal representation of a parallelogram */ - constexpr static uint nb_scalars() + constexpr static uint8 nb_scalars() { return 3 * VEC::SizeAtCompileTime ; } - static uint sample_parallelograms_uniform(std::queue& samples, uint angular_bins, uint magnitude_bins, uint pos_bins, uint diagonal) + static uint32 sample_parallelograms_uniform(std::queue& samples, uint32 angular_bins, uint32 magnitude_bins, uint32 pos_bins, uint32 diagonal) { - const uint half_diagonal = diagonal / 2 ; + const uint32 half_diagonal = diagonal / 2 ; const T angular_step = M_PI * (1.0 / angular_bins) ; magnitude_bins = std::min(magnitude_bins,half_diagonal) ; - const uint mag_step = floor(half_diagonal / magnitude_bins) ; + const uint32 mag_step = floor(half_diagonal / magnitude_bins) ; - for (uint mag_i = mag_step ; mag_i <= half_diagonal ; mag_i += mag_step) + for (uint32 mag_i = mag_step ; mag_i <= half_diagonal ; mag_i += mag_step) { - for (uint mag_j = mag_step ; mag_j <= half_diagonal ; mag_j += mag_step) + for (uint32 mag_j = mag_step ; mag_j <= half_diagonal ; mag_j += mag_step) { T start_alpha = M_PI/2.0 - floor(M_PI/2.0 / angular_step)*angular_step ; // M_PI/2 - n times angular_step so that smallest possible > 0 for (T alpha_i = start_alpha ; alpha_i <= M_PI ; alpha_i += angular_step) @@ -216,10 +216,10 @@ class Parallelogram continue ; VEC p0 = VEC::Zero(); - for (uint pi = 0 ; pi < pos_bins ; ++pi) + for (uint32 pi = 0 ; pi < pos_bins ; ++pi) { p0[1] = 0.0 ; - for (uint pj = 0 ; pj < pos_bins ; ++pj) + for (uint32 pj = 0 ; pj < pos_bins ; ++pj) { Parallelogram p(p0,mag_i,alpha_i,mag_j,alpha_j) ; samples.push(p) ; From af487e93dc5d949e01b574044ffc5d22f0ce0b67 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Mon, 30 Oct 2017 11:04:40 +0100 Subject: [PATCH 26/26] uint -> uint32 for windows compatibility --- cgogn/modeling/tiling/parallelogram_grid.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cgogn/modeling/tiling/parallelogram_grid.h b/cgogn/modeling/tiling/parallelogram_grid.h index a85c8dde..9bbfcb78 100644 --- a/cgogn/modeling/tiling/parallelogram_grid.h +++ b/cgogn/modeling/tiling/parallelogram_grid.h @@ -509,9 +509,9 @@ class ParallelogramGrid * @param f_bbox bounding box of the current face * @return */ - uint queueFreeEdges(const Face& f, std::queue& edgeQueue, const geometry::AABB& f_bbox) + uint32 queueFreeEdges(const Face& f, std::queue& edgeQueue, const geometry::AABB& f_bbox) { - uint counter = 0 ; + uint32 counter = 0 ; // if current face touches the Rectangle if (area_.intersects(f_bbox)) { @@ -653,7 +653,7 @@ class ParallelogramGrid void sewFaceToAdjacentFaces(MapBuilder& mbuild,const Face& f0, const std::array& adjacentFaces) { Dart d = f0.dart ; - for (uint o = S ; o <= W ; ++o) + for (uint8 o = S ; o <= W ; ++o) { const Face& fAdj = adjacentFaces[o] ; if (fAdj.is_valid()) // if there's a face to be sewed in that direction @@ -878,7 +878,7 @@ class ParallelogramGrid * @param no the vertex to fetch * @return the requested vertex */ - Vertex getVertexByNo(const Face& f, uint no) const + Vertex getVertexByNo(const Face& f, uint32 no) const { assert(no<4) ; return Vertex(getDartByOrient(f,Orient(no))) ;