Added tests for the consistency of points, edges and triangles.

This commit is contained in:
Robert Osfield 2004-04-15 09:37:10 +00:00
parent 9286df61ec
commit 3b4e0a419a

View File

@ -87,22 +87,33 @@ public:
struct Edge : public osg::Referenced
{
Edge():_errorMetric(0.0f) {}
Edge():_needToRecomputeErrorMetric(true), _errorMetric(0.0f) {}
osg::ref_ptr<Point> _p1;
osg::ref_ptr<Point> _p2;
osg::ref_ptr<Triangle> _t1;
osg::ref_ptr<Triangle> _t2;
bool _needToRecomputeErrorMetric;
float _errorMetric;
void setErrorMetric(float errorMetric) { _errorMetric = errorMetric; }
float getErrorMetric() const { return _errorMetric; }
bool operator < ( const Edge& rhs) const
{
if (getErrorMetric()<rhs.getErrorMetric()) return true;
else if (rhs.getErrorMetric()>getErrorMetric()) return false;
// edge that need to be recomputed are always first.
if (_needToRecomputeErrorMetric && !rhs._needToRecomputeErrorMetric) return true;
if (!_needToRecomputeErrorMetric && rhs._needToRecomputeErrorMetric) return false;
if (!_needToRecomputeErrorMetric && !rhs._needToRecomputeErrorMetric)
{
// both error metrics are computed
if (getErrorMetric()<rhs.getErrorMetric()) return true;
else if (rhs.getErrorMetric()>getErrorMetric()) return false;
}
if (_p1 < rhs._p1) return true;
if (rhs._p1 < _p1) return false;
@ -125,7 +136,6 @@ public:
}
}
float _errorMetric;
};
struct Triangle : public osg::Referenced
@ -188,17 +198,93 @@ public:
void removeTriangle(Triangle* triangle)
{
removePoint(triangle,triangle->_p1.get());
removePoint(triangle,triangle->_p2.get());
removePoint(triangle,triangle->_p3.get());
if (triangle->_p1.valid()) removePoint(triangle,triangle->_p1.get());
if (triangle->_p2.valid()) removePoint(triangle,triangle->_p2.get());
if (triangle->_p3.valid()) removePoint(triangle,triangle->_p3.get());
removeEdge(triangle,triangle->_e1.get());
removeEdge(triangle,triangle->_e2.get());
removeEdge(triangle,triangle->_e3.get());
if (triangle->_e1.valid()) removeEdge(triangle,triangle->_e1.get());
if (triangle->_e2.valid()) removeEdge(triangle,triangle->_e2.get());
if (triangle->_e3.valid()) removeEdge(triangle,triangle->_e3.get());
_triangleSet.erase(triangle);
}
void replaceTrianglePoint(Triangle* triangle, Point* pOriginal, Point* pNew)
{
if (triangle->_p1==pOriginal || triangle->_p2==pOriginal || triangle->_p3==pOriginal)
{
// fix the corner points to use the new point
if (triangle->_p1==pOriginal) triangle->_p1=pNew;
if (triangle->_p2==pOriginal) triangle->_p2=pNew;
if (triangle->_p3==pOriginal) triangle->_p3=pNew;
// fixes the edges so they point to use the new point
triangle->_e1 = replaceEdgePoint(triangle->_e1.get(),pOriginal,pNew);
triangle->_e2 = replaceEdgePoint(triangle->_e2.get(),pOriginal,pNew);
triangle->_e3 = replaceEdgePoint(triangle->_e3.get(),pOriginal,pNew);
// remove the triangle form the orignal point, and possibly the point if its the last triangle to use it
removePoint(triangle, pOriginal);
// add the triangle to that point
addPoint(triangle,pNew);
}
}
bool testTriangle(Triangle* triangle)
{
bool result = true;
if (!(triangle->_p1))
{
std::cout<<"testTriangle("<<triangle<<") _p1==NULL"<<std::endl;
result = false;
}
else if (triangle->_p1->_triangles.count(triangle)==0)
{
std::cout<<"testTriangle("<<triangle<<") _p1->_triangles does not contain triangle"<<std::endl;
result = false;
}
if (!(triangle->_p2))
{
std::cout<<"testTriangle("<<triangle<<") _p2==NULL"<<std::endl;
result = false;
}
else if (triangle->_p2->_triangles.count(triangle)==0)
{
std::cout<<"testTriangle("<<triangle<<") _p2->_triangles does not contain triangle"<<std::endl;
result = false;
}
if (!(triangle->_p3))
{
std::cout<<"testTriangle("<<triangle<<") _p3==NULL"<<std::endl;
result = false;
}
else if (triangle->_p3->_triangles.count(triangle)==0)
{
std::cout<<"testTriangle("<<triangle<<") _p3->_triangles does not contain triangle"<<std::endl;
result = false;
}
return result;
}
unsigned int testAllTriangles()
{
unsigned int numErrors = 0;
for(TriangleSet::iterator itr=_triangleSet.begin();
itr!=_triangleSet.end();
++itr)
{
if (!testTriangle(const_cast<Triangle*>(itr->get())))
{
++numErrors;
}
}
return numErrors;
}
Edge* addEdge(Triangle* triangle, Point* p1, Point* p2)
{
//std::cout<<"addEdge("<<p1<<","<<p2<<")"<<std::endl;
@ -250,11 +336,143 @@ public:
}
}
Edge* replaceEdgePoint(Edge* edge, Point* pOriginal, Point* pNew)
{
if (edge->_p1==pOriginal || edge->_p2==pOriginal)
{
EdgeSet::iterator itr = _edgeSet.find(edge);
if (itr!=_edgeSet.end())
{
// remove the edge from the list, as its positoin in the list
// may need to change once its values have been ammended
_edgeSet.erase(itr);
}
// modify its values
if (edge->_p1==pOriginal) edge->_p1=pNew;
if (edge->_p2==pOriginal) edge->_p2=pNew;
if (edge->_p2 > edge->_p1)
{
// swap to ensure that lowest ptr value of p1, p2 pair is first.
osg::ref_ptr<Point> tmp = edge->_p1;
edge->_p1 = edge->_p2;
edge->_p2 = tmp;
}
itr = _edgeSet.find(edge);
if (itr!=_edgeSet.end())
{
// reuse existing edge.
edge = const_cast<Edge*>(itr->get());
}
else
{
// put it back in.
_edgeSet.insert(edge);
}
return edge;
}
else
{
return edge;
}
}
void collapseEdge(Edge* edge, Point* pNew)
{
if (!edge->_t1.valid() || !edge->_t2.valid()) return;
osg::ref_ptr<Edge> keep_edge_locally_referenced_to_prevent_premature_deletion = edge;
osg::ref_ptr<Point> keep_point_locally_referenced_to_prevent_premature_deletion = pNew;
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)
{
replaceTrianglePoint(const_cast<Triangle*>(titr_p1->get()),edge->_p1.get(),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)
{
replaceTrianglePoint(const_cast<Triangle*>(titr_p2->get()),edge->_p2.get(),pNew);
}
}
#if 1
osg::ref_ptr<Triangle> t1 = edge->_t1;
osg::ref_ptr<Triangle> 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
}
unsigned int testEdge(Edge* edge)
{
unsigned int numErrors = 0;
if (edge->_t1.valid())
{
if (!(edge->_t1->_e1 == edge || edge->_t1->_e2 == edge || edge->_t1->_e3 == edge))
{
std::cout<<"testEdge("<<edge<<")._t1 != point back to this edge"<<std::endl;
std::cout<<" _t1->_e1=="<<edge->_t1->_e1.get()<<std::endl;
std::cout<<" _t1->_e2=="<<edge->_t1->_e2.get()<<std::endl;
std::cout<<" _t1->_e3=="<<edge->_t1->_e3.get()<<std::endl;
++numErrors;
}
}
if (edge->_t2.valid())
{
if (!(edge->_t2->_e1 == edge || edge->_t2->_e2 == edge || edge->_t2->_e3 == edge))
{
std::cout<<"testEdge("<<edge<<")._t2 != point back to this edge"<<std::endl;
std::cout<<" _t2->_e1=="<<edge->_t2->_e1.get()<<std::endl;
std::cout<<" _t2->_e2=="<<edge->_t2->_e2.get()<<std::endl;
std::cout<<" _t2->_e3=="<<edge->_t2->_e3.get()<<std::endl;
++numErrors;
}
}
return numErrors;
}
unsigned int testAllEdges()
{
unsigned int numErrors = 0;
for(EdgeSet::iterator itr = _edgeSet.begin();
itr!=_edgeSet.end();
++itr)
{
numErrors += testEdge(const_cast<Edge*>(itr->get()));
}
return numErrors;
}
Point* addPoint(Triangle* triangle, unsigned int p1)
{
osg::ref_ptr<Point> point = _originalPointList[p1];
return addPoint(triangle,_originalPointList[p1].get());
}
Point* addPoint(Triangle* triangle, Point* point)
{
PointSet::iterator itr = _pointSet.find(point);
if (itr==_pointSet.end())
{
@ -263,13 +481,13 @@ public:
}
else
{
point = *itr;
point = const_cast<Point*>(itr->get());
//std::cout<<" reusePoint("<<point.get()<<")"<<std::endl;
}
point->_triangles.insert(triangle);
return point.get();
return point;
}
void removePoint(Triangle* triangle, Point* point)
@ -288,6 +506,40 @@ public:
}
unsigned int testPoint(Point* point)
{
unsigned int numErrors = 0;
for(TriangleSet::iterator itr=point->_triangles.begin();
itr!=point->_triangles.end();
++itr)
{
Triangle* triangle = const_cast<Triangle*>(itr->get());
if (!(triangle->_p1 == point || triangle->_p2 == point || triangle->_p3 == point))
{
std::cout<<"testPoint("<<point<<") error, triangle "<<triangle<<" does not point back to this point"<<std::endl;
std::cout<<" triangle->_p1 "<<triangle->_p1.get()<<std::endl;
std::cout<<" triangle->_p2 "<<triangle->_p2.get()<<std::endl;
std::cout<<" triangle->_p3 "<<triangle->_p3.get()<<std::endl;
++numErrors;
}
}
return numErrors;
}
unsigned int testAllPoints()
{
unsigned int numErrors = 0;
for(PointSet::iterator itr = _pointSet.begin();
itr!=_pointSet.end();
++itr)
{
numErrors += testPoint(const_cast<Point*>(itr->get()));
}
return numErrors;
}
protected:
typedef std::vector< osg::ref_ptr<osg::Array> > ArrayList;
@ -644,6 +896,50 @@ class CopyPointsToVertexArrayVisitor : public osg::ArrayVisitor
void EdgeCollapse::copyBackToGeometry()
{
std::cout<<"Number of triangle errors before edge collapse= "<<testAllTriangles()<<std::endl;
std::cout<<"Number of edge errors before edge collapse= "<<testAllEdges()<<std::endl;
std::cout<<"Number of point errors before edge collapse= "<<testAllPoints()<<std::endl;
#if 1
{
float sampleRatio = 0.8;
unsigned int numAccepted = 0;
unsigned int numDeleted = 0;
typedef std::vector< osg::ref_ptr<Edge> > EdgeList;
EdgeList toDelete;
for(EdgeSet::iterator eitr=_edgeSet.begin();
eitr!=_edgeSet.end();
++eitr)
{
float r = (numAccepted>0) ? (float)numAccepted / (float)(numAccepted+numDeleted) : 0.0f;
if (r>sampleRatio)
{
Edge* edge = const_cast<Edge*>(eitr->get());
toDelete.push_back(edge);
++numDeleted;
}
else
{
++numAccepted;
}
}
for(EdgeList::iterator ditr=toDelete.begin();
ditr!=toDelete.end();
++ditr)
{
Edge* edge = const_cast<Edge*>(ditr->get());
collapseEdge(edge, edge->_p1.get());
}
}
std::cout<<"Number of errors after edge collapse= "<<testAllTriangles()<<std::endl;
std::cout<<"Number of edge errors before edge collapse= "<<testAllEdges()<<std::endl;
std::cout<<"Number of point errors after edge collapse= "<<testAllPoints()<<std::endl;
#else
// do decimation of triangles to test
{
TriangleList toDelete;
float sampleRatio = 0.1;
@ -675,7 +971,7 @@ void EdgeCollapse::copyBackToGeometry()
//_triangleSet.erase(triangle);
}
}
#endif
// rebuild the _pointList from the _pointSet
_originalPointList.clear();