From 117fa92462cdf2800430ea1685704ba9d393b113 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 17 Apr 2004 16:02:38 +0000 Subject: [PATCH] Further work on simplifier edge collapse code --- src/osgUtil/Simplifier.cpp | 425 +++++++++++++++++++++++-------------- 1 file changed, 269 insertions(+), 156 deletions(-) diff --git a/src/osgUtil/Simplifier.cpp b/src/osgUtil/Simplifier.cpp index de85b716e..39aaf1407 100644 --- a/src/osgUtil/Simplifier.cpp +++ b/src/osgUtil/Simplifier.cpp @@ -38,6 +38,11 @@ class EdgeCollapse { public: + struct Triangle; + struct Edge; + struct Point; + + EdgeCollapse(): _targetNumTriangles(0) {} ~EdgeCollapse() {} @@ -49,14 +54,48 @@ public: unsigned int getNumOfTriangles() { return 0; } - bool collapseMinimumErrorEdge() { return false; } + Point* computeNewPoint(Edge* edge,float r=0.5) const + { + Point* point = new Point; + float r1 = 1.0f-r; + float r2 = r; + Point* p1 = edge->_p1.get(); + Point* p2 = edge->_p2.get(); + point->_vertex = p1->_vertex * r1 + p2->_vertex * r2; + unsigned int s = osg::minimum(p1->_attributes.size(),p2->_attributes.size()); + for(unsigned int i=0;i_attributes.push_back(p1->_attributes[i]*r1 + p2->_attributes[i]*r2); + } + return point; + } + + + bool collapseMinimumErrorEdge() + { +// std::cout<<"collapseMinimumErrorEdge"<(itr->get()); + //if (collapseEdge(edge,edge->_p1.get())) return true; + if (!edge->isAdjacentToBoundary()) + { + osg::ref_ptr pNew = computeNewPoint(edge); + + if (collapseEdge(edge,pNew.get())) return true; + } + } + } + return false; + } void copyBackToGeometry(); - struct Triangle; - struct Edge; - struct Point; - typedef std::vector FloatList; typedef std::set,dereference_less> EdgeSet; typedef std::set< osg::ref_ptr,dereference_less> PointSet; @@ -81,7 +120,22 @@ public: return _attributes < rhs._attributes; } - + + bool isBoundaryPoint() const + { + for(TriangleSet::iterator itr=_triangles.begin(); + itr!=_triangles.end(); + ++itr) + { + const Triangle* triangle = itr->get(); + if ((triangle->_e1->_p1==this || triangle->_e1->_p2==this) && triangle->_e1->isBoundaryEdge()) return true; + if ((triangle->_e2->_p1==this || triangle->_e2->_p2==this) && triangle->_e2->isBoundaryEdge()) return true; + if ((triangle->_e3->_p1==this || triangle->_e3->_p2==this) && triangle->_e3->isBoundaryEdge()) return true; + + //if ((*itr)->isBoundaryTriangle()) return true; + } + return false; + } }; @@ -92,8 +146,7 @@ public: osg::ref_ptr _p1; osg::ref_ptr _p2; - osg::ref_ptr _t1; - osg::ref_ptr _t2; + TriangleSet _triangles; bool _needToRecomputeErrorMetric; float _errorMetric; @@ -113,7 +166,7 @@ public: if (getErrorMetric()getErrorMetric()) return false; } - + if (_p1 < rhs._p1) return true; if (rhs._p1 < _p1) return false; @@ -122,18 +175,18 @@ public: void addTriangle(Triangle* triangle) { - if (!_t1) - { - _t1 = triangle; - } - else if (!_t2) - { - _t2 = triangle; - } - else - { - osg::notify(osg::NOTICE)<<"Warning too many traingles sharing edge"<2) osg::notify(osg::NOTICE)<<"Warning too many traingles ("<<_triangles.size()<<") sharing edge "<isBoundaryPoint() || _p2->isBoundaryPoint(); } }; @@ -160,6 +213,11 @@ public: osg::ref_ptr _e1; osg::ref_ptr _e2; osg::ref_ptr _e3; + + bool isBoundaryTriangle() const + { + return (_e1->isBoundaryEdge() || _e2->isBoundaryEdge() || _e3->isBoundaryEdge()); + } }; @@ -196,6 +254,37 @@ public: return triangle; } + Triangle* addTriangle(Point* p1, Point* p2, Point* p3) + { + // detect if triangle is degenerate. + if (p1==p2 || p2==p3 || p1==p3) return 0; + + Triangle* triangle = new Triangle; + + Point* points[3]; + points[0] = addPoint(triangle, p1); + points[1] = addPoint(triangle, p2); + points[2] = addPoint(triangle, p3); + + // find the lowest value point in the list. + unsigned int lowest = 0; + if (points[1]_p1 = points[lowest]; + triangle->_p2 = points[(lowest+1)%3]; + triangle->_p3 = points[(lowest+2)%3]; + + triangle->_e1 = addEdge(triangle, triangle->_p1.get(), triangle->_p2.get()); + triangle->_e2 = addEdge(triangle, triangle->_p2.get(), triangle->_p3.get()); + triangle->_e3 = addEdge(triangle, triangle->_p3.get(), triangle->_p1.get()); + + _triangleSet.insert(triangle); + + return triangle; + } + void removeTriangle(Triangle* triangle) { if (triangle->_p1.valid()) removePoint(triangle,triangle->_p1.get()); @@ -232,41 +321,60 @@ public: } - bool testTriangle(Triangle* triangle) + unsigned int testTriangle(Triangle* triangle) { - bool result = true; + unsigned int result = 0; if (!(triangle->_p1)) { std::cout<<"testTriangle("<_p1->_triangles.count(triangle)==0) { std::cout<<"testTriangle("<_triangles does not contain triangle"<_p2)) { std::cout<<"testTriangle("<_p2->_triangles.count(triangle)==0) { std::cout<<"testTriangle("<_triangles does not contain triangle"<_p3)) { std::cout<<"testTriangle("<_p3->_triangles.count(triangle)==0) { std::cout<<"testTriangle("<_triangles does not contain triangle"<_e1.get())) + { + ++result; + std::cout<<"testTriangle("<_e2.get())) + { + ++result; + std::cout<<"testTriangle("<_e3.get())) + { + std::cout<<"testTriangle("<(itr->get()))) - { - ++numErrors; - } + numErrors += testTriangle(const_cast(itr->get())); } return numErrors; } @@ -322,16 +427,14 @@ public: EdgeSet::iterator itr = _edgeSet.find(edge); if (itr!=_edgeSet.end()) { - if (edge->_t1==triangle) edge->_t1 = 0; - if (edge->_t2==triangle) edge->_t2 = 0; - - if (!edge->_t1.valid() && !edge->_t2.valid()) + edge->_triangles.erase(triangle); + if (edge->_triangles.empty()) { - edge->_p1 = 0; - edge->_p2 = 0; - // edge no longer in use, so need to delete. _edgeSet.erase(itr); + + edge->_p1 = 0; + edge->_p2 = 0; } } } @@ -380,75 +483,111 @@ public: } - void collapseEdge(Edge* edge, Point* pNew) + + bool collapseEdge(Edge* edge, Point* pNew) { - if (!edge->_t1.valid() || !edge->_t2.valid()) return; + if (edge->_triangles.size()<2) return false; osg::ref_ptr keep_edge_locally_referenced_to_prevent_premature_deletion = edge; osg::ref_ptr keep_point_locally_referenced_to_prevent_premature_deletion = pNew; - - if (edge->_p1 != pNew) + osg::ref_ptr edge_p1 = edge->_p1; + osg::ref_ptr edge_p2 = edge->_p2; + + TriangleList triangles_p1; + TriangleList triangles_p2; + + if (edge_p1 != pNew) { - TriangleSet triangles_p1 = edge->_p1->_triangles; - triangles_p1.erase(edge->_t1.get()); - triangles_p1.erase(edge->_t2.get()); - for(TriangleSet::iterator titr_p1 = triangles_p1.begin(); - titr_p1 != triangles_p1.end(); - ++titr_p1) + for(TriangleSet::iterator itr=edge_p1->_triangles.begin(); + itr!=edge_p1->_triangles.end(); + ++itr) { - replaceTrianglePoint(const_cast(titr_p1->get()),edge->_p1.get(),pNew); + if (edge->_triangles.count(*itr)==0) triangles_p1.push_back(const_cast(itr->get())); } + + //triangles_p1 = edge_p1->_triangles; } - if (edge->_p2 != pNew) + if (edge_p2 != pNew) { - TriangleSet triangles_p2 = edge->_p2->_triangles; - triangles_p2.erase(edge->_t1.get()); - triangles_p2.erase(edge->_t2.get()); - for(TriangleSet::iterator titr_p2 = triangles_p2.begin(); - titr_p2 != triangles_p2.end(); - ++titr_p2) + for(TriangleSet::iterator itr=edge_p2->_triangles.begin(); + itr!=edge_p2->_triangles.end(); + ++itr) { - replaceTrianglePoint(const_cast(titr_p2->get()),edge->_p2.get(),pNew); + if (edge->_triangles.count(*itr)==0) triangles_p2.push_back(const_cast(itr->get())); } + //triangles_p2 = edge_p2->_triangles; } -#if 1 - osg::ref_ptr t1 = edge->_t1; - osg::ref_ptr t2 = edge->_t1; - // remove triangles directly connected to edge - if (edge->_t1.valid()) removeTriangle(edge->_t1.get()); - if (edge->_t2.valid()) removeTriangle(edge->_t2.get()); -#endif + for(TriangleList::iterator titr_p1 = triangles_p1.begin(); + titr_p1 != triangles_p1.end(); + ++titr_p1) + { + removeTriangle(const_cast(titr_p1->get())); + } + + for(TriangleList::iterator titr_p2 = triangles_p2.begin(); + titr_p2 != triangles_p2.end(); + ++titr_p2) + { + removeTriangle(const_cast(titr_p2->get())); + } + + for(TriangleList::iterator titr_p1 = triangles_p1.begin(); + titr_p1 != triangles_p1.end(); + ++titr_p1) + { + Triangle* triangle = const_cast(titr_p1->get()); + Point* p1 = (triangle->_p1==edge_p1 || triangle->_p1==edge_p2)? pNew : triangle->_p1.get(); + Point* p2 = (triangle->_p2==edge_p1 || triangle->_p2==edge_p2)? pNew : triangle->_p2.get(); + Point* p3 = (triangle->_p3==edge_p1 || triangle->_p3==edge_p2)? pNew : triangle->_p3.get(); + addTriangle(p1,p2,p3); + } + + for(TriangleList::iterator titr_p2 = triangles_p2.begin(); + titr_p2 != triangles_p2.end(); + ++titr_p2) + { + Triangle* triangle = const_cast(titr_p2->get()); + Point* p1 = (triangle->_p1==edge_p1 || triangle->_p1==edge_p2)? pNew : triangle->_p1.get(); + Point* p2 = (triangle->_p2==edge_p1 || triangle->_p2==edge_p2)? pNew : triangle->_p2.get(); + Point* p3 = (triangle->_p3==edge_p1 || triangle->_p3==edge_p2)? pNew : triangle->_p3.get(); + addTriangle(p1,p2,p3); + } + + for(TriangleSet::iterator teitr=edge->_triangles.begin(); + teitr!=edge->_triangles.end(); + ++teitr) + { + removeTriangle(const_cast(teitr->get())); + } + + return true; } - unsigned int testEdge(Edge* edge) { unsigned int numErrors = 0; - if (edge->_t1.valid()) + for(TriangleSet::iterator teitr=edge->_triangles.begin(); + teitr!=edge->_triangles.end(); + ++teitr) { - if (!(edge->_t1->_e1 == edge || edge->_t1->_e2 == edge || edge->_t1->_e3 == edge)) + Triangle* triangle = const_cast(teitr->get()); + if (!(triangle->_e1 == edge || triangle->_e2 == edge || triangle->_e3 == edge)) { - std::cout<<"testEdge("<_e1=="<_t1->_e1.get()<_e2=="<_t1->_e2.get()<_e3=="<_t1->_e3.get()<_t2.valid()) - { - if (!(edge->_t2->_e1 == edge || edge->_t2->_e2 == edge || edge->_t2->_e3 == edge)) - { - std::cout<<"testEdge("<_e1=="<_t2->_e1.get()<_e2=="<_t2->_e2.get()<_e3=="<_t2->_e3.get()<_e1=="<_e1.get()<_e2=="<_e2.get()<_e3=="<_e3.get()<_triangles.empty()) + { + std::cout<<"testEdge("<isBoundaryEdge()) ++numBoundaryEdges; + } + return numBoundaryEdges; + } + Point* addPoint(Triangle* triangle, unsigned int p1) { @@ -779,8 +930,11 @@ class CopyPointsToArrayVisitor : public osg::ArrayVisitor for(unsigned int i=0;i<_pointList.size();++i) { - float val = (_pointList[i]->_attributes[_index]); - array[i] = R (val); + if (_index<_pointList[i]->_attributes.size()) + { + float val = (_pointList[i]->_attributes[_index]); + array[i] = R (val); + } } ++_index; @@ -817,7 +971,7 @@ class CopyPointsToArrayVisitor : public osg::ArrayVisitor for(unsigned int i=0;i<_pointList.size();++i) { EdgeCollapse::FloatList& attributes = _pointList[i]->_attributes; - array[i].set(attributes[_index],attributes[_index+1]); + if (_index+1_attributes; - array[i].set(attributes[_index],attributes[_index+1],attributes[_index+2]); + if (_index+2_attributes; - array[i].set(attributes[_index],attributes[_index+1],attributes[_index+2],attributes[_index+3]); + if (_index+3(ditr->get()); - collapseEdge(edge, edge->_p1.get()); - } - } - std::cout<<"Number of errors after edge collapse= "<