diff --git a/include/Algo/BooleanOperator/mergeVertices.hpp b/include/Algo/BooleanOperator/mergeVertices.hpp index d9ddc531c519ac9cb3fe46f4ebdaa74f824ec459..a330d5d6041cbc76b9a8323a6e4a65fd73777928 100644 --- a/include/Algo/BooleanOperator/mergeVertices.hpp +++ b/include/Algo/BooleanOperator/mergeVertices.hpp @@ -40,15 +40,12 @@ bool isBetween(typename PFP::MAP& map, const VertexAttribute } template -void mergeVertex(typename PFP::MAP& map, VertexAttribute& positions, Dart d, Dart e) +void mergeVertex(typename PFP::MAP& map, VertexAttribute& positions, Dart d, Dart e, int precision) { - assert(Geom::arePointsEquals(positions[d], positions[e]) && !map.sameVertex(d, e)) ; - - typedef typename PFP::VEC3 VEC3; - VEC3 p = positions[d] ; + assert(positions[d].isNear(positions[e], precision) && !map.sameVertex(d, e)) ; bool notempty = true ; - do // while vertex of e contains more than one dart + do // While vertex of e contains more than one dart { Dart e1 = map.alpha1(e) ; // e1 stores next dart of vertex of e if (e1 == e) @@ -72,32 +69,32 @@ void mergeVertex(typename PFP::MAP& map, VertexAttribute& po d = e ; e = e1 ; } while (notempty) ; - - // 0-embed z on the merged vertex - positions[d] = p ; } template -void mergeVertices(typename PFP::MAP& map, VertexAttribute& positions) +void mergeVertices(typename PFP::MAP& map, VertexAttribute& positions, int precision) { // TODO optimiser en triant les sommets - for(Dart d = map.begin() ; d != map.end() ; map.next(d)) + // map.template enableQuickTraversal(); + TraversorV travV1(map) ; + CellMarker vM(map); + for(Dart d1 = travV1.begin() ; d1 != travV1.end() ; d1 = travV1.next()) { - CellMarker vM(map); - vM.mark(d); - for(Dart dd = map.begin() ; dd != map.end() ; map.next(dd)) + vM.mark(d1); + TraversorV travV2(map) ; + for(Dart d2 = travV2.begin() ; d2 != travV2.end() ; d2 = travV2.next()) { - if(!vM.isMarked(dd)) + if(!vM.isMarked(d2)) { - if(Geom::arePointsEquals(positions[d],positions[dd])) + if(positions[d1].isNear(positions[d2], precision)) { - if (map.sameVertex(d,dd)) std::cout << "fusion: sameVertex" << std::endl ; - if (!map.sameVertex(d,dd)) mergeVertex(map,positions,d,dd); -// vM.mark(d); + if (map.sameVertex(d1,d2)) std::cout << "fusion: sameVertex" << std::endl ; + if (!map.sameVertex(d1,d2)) mergeVertex(map,positions,d1,d2,precision); } } } } + // map.template disableQuickTraversal(); } } diff --git a/include/Algo/Import/importSvg.hpp b/include/Algo/Import/importSvg.hpp index 49dd2f444064df2adb0f06fc3bb41e84f905f3d9..26ba2e7cd11bff68c0aa4661b5bc9aad69e4bdf0 100644 --- a/include/Algo/Import/importSvg.hpp +++ b/include/Algo/Import/importSvg.hpp @@ -310,10 +310,9 @@ bool importSVG(typename PFP::MAP& map, const std::string& filename, VertexAttrib //create broken lines DartMarker brokenL(map); - unsigned int nbVertices = 0 ; - + typename std::vector::iterator it; std::vector::iterator itW = allBrokenLinesWidth.begin(); - for(typename std::vector::iterator it = allBrokenLines.begin() ; it != allBrokenLines.end() ; ++it) + for(it = allBrokenLines.begin() ; it != allBrokenLines.end() ; ++it, ++itW) { if(it->size()<2) { @@ -322,74 +321,48 @@ bool importSVG(typename PFP::MAP& map, const std::string& filename, VertexAttrib } else { - nbVertices += it->size() ; + Dart d = map.newPolyLine(it->size()-1); - Dart d = map.newFace(it->size()*2-2,false); - - Dart d1=d; - Dart d_1=map.phi_1(d); - //build a degenerated "line" face - for(unsigned int i = 0; isize() ; ++i) + for(typename POLYGON::iterator emb = it->begin(); emb != it->end() ; emb++) { - brokenL.mark(d1); - brokenL.mark(d_1); - - map.sewFaces(d1,d_1,false) ; + brokenL.mark(d); + brokenL.mark(map.phi2(d)); - edgeWidth[d1] = *itW; + edgeWidth[d] = *itW; if (*itW == 0) std::cout << "importSVG : null path width" << std::endl ; - - d1 = map.phi1(d1); - d_1 = map.phi_1(d_1); - } - -// polygonsFaces.mark(d); - - //embed the line - d1 = d; - for(typename POLYGON::iterator emb = it->begin(); emb != it->end() ; emb++) - { bb->addPoint(*emb); - position[d1] = *emb; - d1 = map.phi1(d1); + position[d] = *emb; + d = map.phi1(d); } } - - itW++; } - - std::cout << "importSVG : broken lines created : " << nbVertices << " vertices"<< std::endl; + std::cout << "importSVG : broken lines created : " << std::endl; ///////////////////////////////////////////////////////////////////////////////////////////// - - Algo::BooleanOperator::mergeVertices(map,position); + // Merge near vertices + Algo::BooleanOperator::mergeVertices(map,position,1); std::cout << "importSVG : Merging of vertices." << std::endl; ///////////////////////////////////////////////////////////////////////////////////////////// //create polygons - typename std::vector::iterator it; for(it = allPoly.begin() ; it != allPoly.end() ; ++it) { - if(it->size()<4) + if(it->size()<3) { it = allPoly.erase(it); } else { Dart d = map.newFace(it->size()); -// std::cout << "newFace1 " << it->size()-1 << std::endl; polygonsFaces.mark(d); - Dart dd = d; - typename POLYGON::iterator emb = it->begin(); - do + for(typename POLYGON::iterator emb = it->begin(); emb != it->end() ; emb++) { bb->addPoint(*emb); - position[dd] = *emb; - emb++; - dd = map.phi1(dd); - } while(dd!=d); + position[d] = *emb; + d = map.phi1(d); + } } } @@ -409,26 +382,6 @@ bool importSVG(typename PFP::MAP& map, const std::string& filename, VertexAttrib std::cout << "importSVG : Polygons generated." << std::endl; - - ///////////////////////////////////////////////////////////////////////////////////////////// - //simplify the edges to have a more regular sampling - float minDist = 20.0f ; - for (Dart d = map.begin() ; d != map.end() ; map.next(d)) - { - if(!polygons.isMarked(d)) - { - bool canSimplify = true ; - while ( canSimplify && ((position[map.phi1(d)] - position[d]).norm() < minDist) ) - { - if (map.vertexDegree(map.phi1(d)) == 2) { - map.uncutEdge(d) ; - } - else canSimplify = false ; - } - } - } - std::cout << "importSVG : Downsampling of vertices." << std::endl; - ///////////////////////////////////////////////////////////////////////////////////////////// //cut the edges to have a more regular sampling float maxDist = 40.0f ; @@ -464,7 +417,26 @@ bool importSVG(typename PFP::MAP& map, const std::string& filename, VertexAttrib } } } - std::cout << "importSVG : Refinement of long edges." << std::endl; + std::cout << "importSVG : Subdivision of long edges." << std::endl; + + ///////////////////////////////////////////////////////////////////////////////////////////// + //simplify the edges to have a more regular sampling + float minDist = 30.0f ; + for (Dart d = map.begin() ; d != map.end() ; map.next(d)) + { + if(!polygons.isMarked(d)) + { + bool canSimplify = true ; + while ( canSimplify && ((position[map.phi1(d)] - position[d]).norm() < minDist) ) + { + if (map.vertexDegree(map.phi1(d)) == 2) { + map.uncutEdge(d) ; + } + else canSimplify = false ; + } + } + } + std::cout << "importSVG : Downsampling of vertices." << std::endl; ///////////////////////////////////////////////////////////////////////////////////////////// //process broken lines diff --git a/include/Geometry/vector_gen.h b/include/Geometry/vector_gen.h index 740aca0665f5141ef1fe9821e8fe77b2abb23413..211cc9f2d93fbd8d9872e17e1bb688e4784ec30c 100644 --- a/include/Geometry/vector_gen.h +++ b/include/Geometry/vector_gen.h @@ -152,13 +152,21 @@ public: */ bool isNormalized(const T& epsilon) const ; + /** + * Tests if current and given vectors are near within 1/precision (equal if precision is zero) + * @param V a vector + * @param epsilon tolerated error + * @return true if orthogonal + */ + bool isNear(const Vector& v, int precision) const ; + /** * Tests if current and given vectors are orthogonal * @param V a vector * @param epsilon tolerated error * @return true if orthogonal */ - bool isOrthogonal(const Vector& V, const T& epsilon = 1e-5) const ; + bool isOrthogonal(const Vector& v, const T& epsilon = 1e-5) const ; /**********************************************/ /* STREAM OPERATORS */ @@ -174,6 +182,22 @@ private: T m_data[DIM] ; } ; +/*** + * Test if x is null within precision. + * Two cases are possible : + * - precision == 0 : x is null if (x == 0) + * - precision > 0 : x is null if (|x| < 1/precision) or (precision * |x| < 1) + */ +template +bool isNull(T x, int precision = 0) ; + +/*** + * Test if the square root of x is null within precision. + * In other words, test if x is null within precision*precision + */ +template +bool isNull2(T x, int precision = 0) ; + template Vector operator*(T a, const Vector& v) ; diff --git a/include/Geometry/vector_gen.hpp b/include/Geometry/vector_gen.hpp index 16702a36831e7d881274d4df13bd51c6bcf1dd99..3c0cb50c92df2cd81ad943c5ddca6073d8853e5b 100644 --- a/include/Geometry/vector_gen.hpp +++ b/include/Geometry/vector_gen.hpp @@ -315,9 +315,23 @@ inline bool Vector::isNormalized(const T& epsilon) const } template -inline bool Vector::isOrthogonal(const Vector& V, const T& epsilon) const +inline bool Vector::isOrthogonal(const Vector& v, const T& epsilon) const { - return (fabs(V * (*this)) < epsilon) ; + return (fabs(v * (*this)) < epsilon) ; +} + +template +inline bool Vector::isNear(const Vector& v, int precision) const +{ + T diff ; + T norm2(0) ; + for (unsigned int i = 0 ; i < DIM ; ++i) + { + diff = m_data[i] - v[i] ; + if (!isNull(diff, precision)) return false ; + norm2 += diff * diff ; + } + return isNull2(norm2, precision) ; } /**********************************************/ @@ -340,6 +354,39 @@ std::istream& operator>>(std::istream& in, Vector& v) return in ; } +/*** + * Test if x is null within precision. + * 3 cases are possible : + * - precision = 0 : x is null <=> (x == 0) + * - precision > 0 : x is null <=> (|x| < precision) + * - precision < 0 : x is null <=> (|x| < 1/precision) <=> (precision * |x| < 1) + */ +template +inline bool isNull(T x, int precision) +{ + if (precision == 0) + return (x == 0) ; + else if (precision > 0) + return (fabs(x) < precision) ; + else + return (precision * fabs(x) < 1) ; +} + +/*** + * Test if the square root of x is null within precision. + * In other words, test if x is null within precision*precision + */ +template +inline bool isNull2(T x, int precision) +{ + if (precision == 0) + return (x == 0) ; + else if (precision > 0) + return (isNull(x, precision * precision)) ; + else + return (isNull(x, - (precision * precision))) ; +} + template inline Vector operator*(T a, const Vector& v) { diff --git a/include/Topology/map/embeddedMap2.h b/include/Topology/map/embeddedMap2.h index 4398332f462246e6d362f99257d6b0e0a18e2591..9e85a4d88a4f78495a161bf99d31114513b8aab9 100644 --- a/include/Topology/map/embeddedMap2.h +++ b/include/Topology/map/embeddedMap2.h @@ -40,7 +40,10 @@ public: typedef Map2 TOPO_MAP; /* - * + */ + virtual Dart newPolyLine(unsigned int nbEdges) ; + + /* */ virtual Dart newFace(unsigned int nbEdges, bool withBoundary = true) ; diff --git a/include/Topology/map/map2.h b/include/Topology/map/map2.h index 2dff409d1613c0f8f126a03df94ad2e9ba726e26..0406e040addd3ed9fc238845ff5904db92b80244 100644 --- a/include/Topology/map/map2.h +++ b/include/Topology/map/map2.h @@ -125,6 +125,12 @@ public: *************************************************************************/ //@{ + //! Create an new polyline of nbEdges, i.e 2*nbEdges darts pairewise sewn by phi2 + /*! @param nbEdges the number of edges + * @return return a dart of the face + */ + virtual Dart newPolyLine(unsigned int nbEdges) ; + //! Create an new face of nbEdges /*! @param nbEdges the number of edges * @param withBoundary create the face and its boundary (default true) diff --git a/src/Topology/map/embeddedMap2.cpp b/src/Topology/map/embeddedMap2.cpp index fe10ddf5fbec671253fddec4669b16fffe981376..4c68d1219dceac0acdb902f35648ef1165f526cf 100644 --- a/src/Topology/map/embeddedMap2.cpp +++ b/src/Topology/map/embeddedMap2.cpp @@ -30,6 +30,37 @@ namespace CGoGN { +Dart EmbeddedMap2::newPolyLine(unsigned int nbEdges) +{ + Dart d = Map2::newPolyLine(nbEdges) ; + + if (isOrbitEmbedded()) + { + Dart e = d ; + for (unsigned int i = 0 ; i <= nbEdges ; ++i) + { + initOrbitEmbeddingNewCell(e) ; + e = this->phi1(e) ; + } + } + + if (isOrbitEmbedded()) + { + Dart e = d ; + for (unsigned int i = 0 ; i < nbEdges ; ++i) + { + initOrbitEmbeddingNewCell(e) ; + e = this->phi1(e) ; + } + } + + if (isOrbitEmbedded()) + { + initOrbitEmbeddingNewCell(d) ; + } + return d ; +} + Dart EmbeddedMap2::newFace(unsigned int nbEdges, bool withBoundary) { Dart d = Map2::newFace(nbEdges, withBoundary); diff --git a/src/Topology/map/map2.cpp b/src/Topology/map/map2.cpp index 4c93c3bfdcbf1b815331d970d3c60e5863bf5e2d..844662be40446f77dbd8fdbae1cefb75d33a3fdf 100644 --- a/src/Topology/map/map2.cpp +++ b/src/Topology/map/map2.cpp @@ -107,6 +107,22 @@ void Map2::compactTopoRelations(const std::vector& oldnew) * To generate or delete faces in a 2-map *************************************************************************/ +Dart Map2::newPolyLine(unsigned int nbEdges) +{ + Dart d = Map1::newCycle(2*nbEdges); + { + Dart it1 = d; + Dart it2 = phi_1(d); + for(unsigned int i = 0; i