Added tests for the consistency of points, edges and triangles.
This commit is contained in:
parent
9286df61ec
commit
3b4e0a419a
@ -87,7 +87,7 @@ public:
|
|||||||
|
|
||||||
struct Edge : public osg::Referenced
|
struct Edge : public osg::Referenced
|
||||||
{
|
{
|
||||||
Edge():_errorMetric(0.0f) {}
|
Edge():_needToRecomputeErrorMetric(true), _errorMetric(0.0f) {}
|
||||||
|
|
||||||
osg::ref_ptr<Point> _p1;
|
osg::ref_ptr<Point> _p1;
|
||||||
osg::ref_ptr<Point> _p2;
|
osg::ref_ptr<Point> _p2;
|
||||||
@ -95,13 +95,24 @@ public:
|
|||||||
osg::ref_ptr<Triangle> _t1;
|
osg::ref_ptr<Triangle> _t1;
|
||||||
osg::ref_ptr<Triangle> _t2;
|
osg::ref_ptr<Triangle> _t2;
|
||||||
|
|
||||||
|
bool _needToRecomputeErrorMetric;
|
||||||
|
float _errorMetric;
|
||||||
|
|
||||||
void setErrorMetric(float errorMetric) { _errorMetric = errorMetric; }
|
void setErrorMetric(float errorMetric) { _errorMetric = errorMetric; }
|
||||||
float getErrorMetric() const { return _errorMetric; }
|
float getErrorMetric() const { return _errorMetric; }
|
||||||
|
|
||||||
bool operator < ( const Edge& rhs) const
|
bool operator < ( const Edge& rhs) const
|
||||||
{
|
{
|
||||||
if (getErrorMetric()<rhs.getErrorMetric()) return true;
|
// edge that need to be recomputed are always first.
|
||||||
else if (rhs.getErrorMetric()>getErrorMetric()) return false;
|
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 (_p1 < rhs._p1) return true;
|
||||||
if (rhs._p1 < _p1) return false;
|
if (rhs._p1 < _p1) return false;
|
||||||
@ -125,7 +136,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float _errorMetric;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Triangle : public osg::Referenced
|
struct Triangle : public osg::Referenced
|
||||||
@ -188,17 +198,93 @@ public:
|
|||||||
|
|
||||||
void removeTriangle(Triangle* triangle)
|
void removeTriangle(Triangle* triangle)
|
||||||
{
|
{
|
||||||
removePoint(triangle,triangle->_p1.get());
|
if (triangle->_p1.valid()) removePoint(triangle,triangle->_p1.get());
|
||||||
removePoint(triangle,triangle->_p2.get());
|
if (triangle->_p2.valid()) removePoint(triangle,triangle->_p2.get());
|
||||||
removePoint(triangle,triangle->_p3.get());
|
if (triangle->_p3.valid()) removePoint(triangle,triangle->_p3.get());
|
||||||
|
|
||||||
removeEdge(triangle,triangle->_e1.get());
|
if (triangle->_e1.valid()) removeEdge(triangle,triangle->_e1.get());
|
||||||
removeEdge(triangle,triangle->_e2.get());
|
if (triangle->_e2.valid()) removeEdge(triangle,triangle->_e2.get());
|
||||||
removeEdge(triangle,triangle->_e3.get());
|
if (triangle->_e3.valid()) removeEdge(triangle,triangle->_e3.get());
|
||||||
|
|
||||||
_triangleSet.erase(triangle);
|
_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)
|
Edge* addEdge(Triangle* triangle, Point* p1, Point* p2)
|
||||||
{
|
{
|
||||||
//std::cout<<"addEdge("<<p1<<","<<p2<<")"<<std::endl;
|
//std::cout<<"addEdge("<<p1<<","<<p2<<")"<<std::endl;
|
||||||
@ -250,10 +336,142 @@ 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)
|
Point* addPoint(Triangle* triangle, unsigned int p1)
|
||||||
{
|
{
|
||||||
|
return addPoint(triangle,_originalPointList[p1].get());
|
||||||
|
}
|
||||||
|
|
||||||
osg::ref_ptr<Point> point = _originalPointList[p1];
|
Point* addPoint(Triangle* triangle, Point* point)
|
||||||
|
{
|
||||||
|
|
||||||
PointSet::iterator itr = _pointSet.find(point);
|
PointSet::iterator itr = _pointSet.find(point);
|
||||||
if (itr==_pointSet.end())
|
if (itr==_pointSet.end())
|
||||||
@ -263,13 +481,13 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
point = *itr;
|
point = const_cast<Point*>(itr->get());
|
||||||
//std::cout<<" reusePoint("<<point.get()<<")"<<std::endl;
|
//std::cout<<" reusePoint("<<point.get()<<")"<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
point->_triangles.insert(triangle);
|
point->_triangles.insert(triangle);
|
||||||
|
|
||||||
return point.get();
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removePoint(Triangle* triangle, Point* 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:
|
protected:
|
||||||
|
|
||||||
typedef std::vector< osg::ref_ptr<osg::Array> > ArrayList;
|
typedef std::vector< osg::ref_ptr<osg::Array> > ArrayList;
|
||||||
@ -644,6 +896,50 @@ class CopyPointsToVertexArrayVisitor : public osg::ArrayVisitor
|
|||||||
|
|
||||||
void EdgeCollapse::copyBackToGeometry()
|
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;
|
TriangleList toDelete;
|
||||||
float sampleRatio = 0.1;
|
float sampleRatio = 0.1;
|
||||||
@ -675,7 +971,7 @@ void EdgeCollapse::copyBackToGeometry()
|
|||||||
//_triangleSet.erase(triangle);
|
//_triangleSet.erase(triangle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// rebuild the _pointList from the _pointSet
|
// rebuild the _pointList from the _pointSet
|
||||||
_originalPointList.clear();
|
_originalPointList.clear();
|
||||||
|
Loading…
Reference in New Issue
Block a user