From f72e9befc175d995c1075ae8814f5005f855b681 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 19 Apr 2004 20:06:26 +0000 Subject: [PATCH] Added support for detecting edge collapses which will overturn the local triangles. --- src/osgUtil/Simplifier.cpp | 181 +++++++++++++++++++++++++++++++++---- 1 file changed, 161 insertions(+), 20 deletions(-) diff --git a/src/osgUtil/Simplifier.cpp b/src/osgUtil/Simplifier.cpp index f868edd29..74feecc7d 100644 --- a/src/osgUtil/Simplifier.cpp +++ b/src/osgUtil/Simplifier.cpp @@ -92,6 +92,8 @@ public: const osg::Vec3& vertex = point->_vertex; float error = 0.0f; + if (triangles.empty()) return 0.0f; + for(LocalTriangleSet::iterator itr=triangles.begin(); itr!=triangles.end(); ++itr) @@ -99,6 +101,9 @@ public: error += fabs( (*itr)->distance(vertex) ); } + // use average of error + error /= (float)triangles.size(); + return error; } @@ -120,6 +125,7 @@ public: edge->_proposedPoint = computeOptimalPoint(edge); + edge->updateMaxNormalDeviationOnEdgeCollapse(); edge->setErrorMetric( computeErrorMetric( edge, edge->_proposedPoint.get())); _edgeSet.insert(keep_local_reference_to_edge); @@ -140,6 +146,7 @@ public: Edge* edge = itr->get(); edge->_proposedPoint = computeOptimalPoint(edge); + edge->updateMaxNormalDeviationOnEdgeCollapse(); edge->setErrorMetric( computeErrorMetric( edge, edge->_proposedPoint.get())); _edgeSet.insert(edge); @@ -174,6 +181,7 @@ public: typedef std::vector< osg::ref_ptr > PointList; typedef std::list< osg::ref_ptr > TriangleList; typedef std::set< osg::ref_ptr > TriangleSet; + typedef std::map< osg::ref_ptr, unsigned int, dereference_less > TriangleMap; struct Point : public osg::Referenced { @@ -213,7 +221,7 @@ public: struct Edge : public osg::Referenced { - Edge(): _errorMetric(0.0f) {} + Edge(): _errorMetric(0.0f), _maximumDeviation(1.0f) {} osg::ref_ptr _p1; osg::ref_ptr _p2; @@ -221,6 +229,7 @@ public: TriangleSet _triangles; float _errorMetric; + float _maximumDeviation; osg::ref_ptr _proposedPoint; @@ -234,7 +243,7 @@ public: else if (rhs.getErrorMetric()2) osg::notify(osg::NOTICE)<<"Warning too many traingles ("<<_triangles.size()<<") sharing edge "<2) osg::notify(osg::NOTICE)<<"Warning too many traingles ("<<_triangles.size()<<") sharing edge "<isBoundaryPoint() || _p2->isBoundaryPoint(); } + + void updateMaxNormalDeviationOnEdgeCollapse() + { + //std::cout<<"updateMaxNormalDeviationOnEdgeCollapse()"<_triangles.begin(); + itr1!=_p1->_triangles.end(); + ++itr1) + { + if (_triangles.count(*itr1)==0) + { + _maximumDeviation = osg::maximum(_maximumDeviation, (*itr1)->computeNormalDeviationOnEdgeCollapse(this,_proposedPoint.get())); + } + } + for(TriangleSet::iterator itr2=_p2->_triangles.begin(); + itr2!=_p2->_triangles.end(); + ++itr2) + { + if (_triangles.count(*itr2)==0) + { + _maximumDeviation = osg::maximum(_maximumDeviation, (*itr2)->computeNormalDeviationOnEdgeCollapse(this,_proposedPoint.get())); + } + } + } + + float getMaxNormalDeviationOnEdgeCollapse() const { return _maximumDeviation; } + }; struct Triangle : public osg::Referenced @@ -282,27 +318,67 @@ public: if (_p1 < rhs._p1) return true; if (rhs._p1 < _p1) return false; - if (_p2 < rhs._p2) return true; - if (rhs._p2 < _p2) return false; - return (_p3 < rhs._p3); + const Point* lhs_lower = _p2<_p3 ? _p2.get() : _p3.get(); + const Point* rhs_lower = rhs._p2 _p1; - osg::ref_ptr _p2; - osg::ref_ptr _p3; - - osg::ref_ptr _e1; - osg::ref_ptr _e2; - osg::ref_ptr _e3; - - osg::Plane _plane; + + void setOrderedPoints(Point* p1, Point* p2, Point* p3) + { + Point* points[3]; + points[0] = p1; + points[1] = p2; + points[2] = p3; + + // find the lowest value point in the list. + unsigned int lowest = 0; + if (points[1]_vertex,_p2->_vertex,_p3->_vertex); + } + osg::Plane computeNewPlaneOnEdgeCollapse(Edge* edge,Point* pNew) const + { + const Point* p1 = (_p1==edge->_p1 || _p1==edge->_p2) ? pNew : _p1.get(); + const Point* p2 = (_p2==edge->_p1 || _p2==edge->_p2) ? pNew : _p2.get(); + const Point* p3 = (_p3==edge->_p1 || _p3==edge->_p2) ? pNew : _p3.get(); + + return osg::Plane(p1->_vertex,p2->_vertex,p3->_vertex); + } + + // note return 1 - dotproduct, so that deviation is in the range of 0.0 to 2.0, where 0 is coincendent, 1.0 is 90 degrees, and 2.0 is 180 degrees. + float computeNormalDeviationOnEdgeCollapse(Edge* edge,Point* pNew) const + { + const Point* p1 = (_p1==edge->_p1 || _p1==edge->_p2) ? pNew : _p1.get(); + const Point* p2 = (_p2==edge->_p1 || _p2==edge->_p2) ? pNew : _p2.get(); + const Point* p3 = (_p3==edge->_p1 || _p3==edge->_p2) ? pNew : _p3.get(); + + osg::Vec3 new_normal = (p2->_vertex - p1->_vertex) ^ (p3->_vertex - p2->_vertex); + new_normal.normalize(); + + float result = 1.0f - (new_normal.x() * _plane[0] + new_normal.y() * _plane[1] + new_normal.z() * _plane[2]); + return result; + } + float distance(const osg::Vec3& vertex) const { return _plane.distance(vertex); @@ -312,6 +388,18 @@ public: { return (_e1->isBoundaryEdge() || _e2->isBoundaryEdge() || _e3->isBoundaryEdge()); } + + + osg::ref_ptr _p1; + osg::ref_ptr _p2; + osg::ref_ptr _p3; + + osg::ref_ptr _e1; + osg::ref_ptr _e2; + osg::ref_ptr _e3; + + osg::Plane _plane; + }; @@ -512,13 +600,13 @@ public: EdgeSet::iterator itr = _edgeSet.find(edge); if (itr==_edgeSet.end()) { - //std::cout<<" addEdge("<_p1="<_p1.get()<<" _p2="<_p2.get()<_p1="<_p1.get()<<" _p2="<_p2.get()<addTriangle(triangle); @@ -591,6 +679,18 @@ public: bool collapseEdge(Edge* edge, Point* pNew) { if (edge->_triangles.size()<2) return false; + if (edge->_triangles.size()>2) return false; + + if (edge->getMaxNormalDeviationOnEdgeCollapse()>1.0) + { + std::cout<<"collapseEdge("<getMaxNormalDeviationOnEdgeCollapse() = "<getMaxNormalDeviationOnEdgeCollapse()<getMaxNormalDeviationOnEdgeCollapse() = "<getMaxNormalDeviationOnEdgeCollapse()< > LocalEdgeList; @@ -599,10 +699,12 @@ public: osg::ref_ptr edge_p1 = edge->_p1; osg::ref_ptr edge_p2 = edge->_p2; + TriangleMap triangleMap; TriangleList triangles_p1; TriangleList triangles_p2; LocalEdgeList oldEdges; + if (edge_p1 != pNew) { for(TriangleSet::iterator itr=edge_p1->_triangles.begin(); @@ -665,23 +767,29 @@ public: removeTriangle(const_cast(titr_p2->get())); } + //std::cout<<" pNew="<_triangles.begin(); teitr!=edge->_triangles.end(); ++teitr) { - removeTriangle(const_cast(teitr->get())); + Triangle* triangle = const_cast(teitr->get()); + //std::cout<<" edge removed T("<_p1.get()<<"\t"<_p2.get()<<"\t"<_p3.get()<<")"<(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(); + Triangle* newTri = addTriangle(p1,p2,p3); newEdges.insert(newTri->_e1); @@ -689,23 +797,27 @@ public: newEdges.insert(newTri->_e3); } + 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(); + Triangle* newTri = addTriangle(p1,p2,p3); newEdges.insert(newTri->_e1); newEdges.insert(newTri->_e2); newEdges.insert(newTri->_e3); + } -#if 1 + // std::cout<<"Edges to recalibarate "<get()<<")"<(itr->get())); } -#endif + return true; } @@ -1158,6 +1270,28 @@ class CopyPointsToArrayVisitor : public osg::ArrayVisitor unsigned int _index; }; +class NormalizeArrayVisitor : public osg::ArrayVisitor +{ + public: + NormalizeArrayVisitor() {} + + template + void normalize(Itr begin, Itr end) + { + for(Itr itr = begin; + itr != end; + ++itr) + { + itr->normalize(); + } + } + + virtual void apply(osg::Vec2Array& array) { normalize(array.begin(),array.end()); } + virtual void apply(osg::Vec3Array& array) { normalize(array.begin(),array.end()); } + virtual void apply(osg::Vec4Array& array) { normalize(array.begin(),array.end()); } + +}; + class CopyPointsToVertexArrayVisitor : public osg::ArrayVisitor { public: @@ -1202,6 +1336,7 @@ class CopyPointsToVertexArrayVisitor : public osg::ArrayVisitor EdgeCollapse::PointList& _pointList; }; + void EdgeCollapse::copyBackToGeometry() { #if 1 @@ -1258,7 +1393,13 @@ void EdgeCollapse::copyBackToGeometry() } if (_geometry->getNormalArray() && _geometry->getNormalBinding()==osg::Geometry::BIND_PER_VERTEX) + { _geometry->getNormalArray()->accept(copyArrayToPoints); + + // now normalize the normals. + NormalizeArrayVisitor nav; + _geometry->getNormalArray()->accept(nav); + } if (_geometry->getColorArray() && _geometry->getColorBinding()==osg::Geometry::BIND_PER_VERTEX) _geometry->getColorArray()->accept(copyArrayToPoints);