/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include using namespace osgUtil; struct dereference_less { template inline bool operator() (const T& lhs,const T& rhs) const { return *lhs < *rhs; } }; class EdgeCollapse { public: struct Triangle; struct Edge; struct Point; EdgeCollapse(): _targetNumTriangles(0) {} ~EdgeCollapse() {} void setGeometry(osg::Geometry* geometry); osg::Geometry* getGeometry() { return _geometry; } void setTargetNumOfTriangles(unsigned int num) { _targetNumTriangles = num; } unsigned int getNumOfTriangles() { return 0; } Point* computeInterpolatedPoint(Edge* edge,float r) const { Point* point = new Point; float r1 = 1.0f-r; float r2 = r; Point* p1 = edge->_p1.get(); Point* p2 = edge->_p2.get(); if (p1==0 || p2==0) { std::cout<<"Error computeInterpolatedPoint("<_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; } Point* computeOptimalPoint(Edge* edge) const { return computeInterpolatedPoint(edge,0.5f); } float computeErrorMetric(Edge* edge,Point* point) const { typedef std::set< osg::ref_ptr > LocalTriangleSet ; LocalTriangleSet triangles; std::copy( edge->_p1->_triangles.begin(), edge->_p1->_triangles.end(), std::inserter(triangles,triangles.begin())); std::copy( edge->_p2->_triangles.begin(), edge->_p2->_triangles.end(), std::inserter(triangles,triangles.begin())); const osg::Vec3& vertex = point->_vertex; float error = 0.0f; for(LocalTriangleSet::iterator itr=triangles.begin(); itr!=triangles.end(); ++itr) { error += fabs( (*itr)->distance(vertex) ); } return error; } void updateErrorMetricForEdge(Edge* edge) { if (!edge->_p1 || !edge->_p2) { std::cout<<"Error updateErrorMetricForEdge("< keep_local_reference_to_edge(edge); if (_edgeSet.count(keep_local_reference_to_edge)!=0) { _edgeSet.erase(keep_local_reference_to_edge); } edge->_proposedPoint = computeOptimalPoint(edge); edge->setErrorMetric( computeErrorMetric( edge, edge->_proposedPoint.get())); _edgeSet.insert(keep_local_reference_to_edge); } void updateErrorMetricForAllEdges() { typedef std::vector< osg::ref_ptr > LocalEdgeList ; LocalEdgeList edges; std::copy( _edgeSet.begin(), _edgeSet.end(), std::back_inserter(edges)); _edgeSet.clear(); for(LocalEdgeList::iterator itr=edges.begin(); itr!=edges.end(); ++itr) { Edge* edge = itr->get(); edge->_proposedPoint = computeOptimalPoint(edge); edge->setErrorMetric( computeErrorMetric( edge, edge->_proposedPoint.get())); _edgeSet.insert(edge); } } bool collapseMinimumErrorEdge() { if (!_edgeSet.empty()) { for(EdgeSet::iterator itr=_edgeSet.begin(); itr!=_edgeSet.end(); ++itr) { Edge* edge = const_cast(itr->get()); if (!edge->isAdjacentToBoundary()) { osg::ref_ptr pNew = edge->_proposedPoint.valid()? edge->_proposedPoint : computeInterpolatedPoint(edge,0.5f); if (collapseEdge(edge,pNew.get())) return true; } } } return false; } void copyBackToGeometry(); typedef std::vector FloatList; typedef std::set,dereference_less> EdgeSet; typedef std::set< osg::ref_ptr,dereference_less> PointSet; typedef std::vector< osg::ref_ptr > PointList; typedef std::list< osg::ref_ptr > TriangleList; typedef std::set< osg::ref_ptr > TriangleSet; struct Point : public osg::Referenced { Point():_index(0) {} unsigned int _index; osg::Vec3 _vertex; FloatList _attributes; TriangleSet _triangles; bool operator < ( const Point& rhs) const { if (_vertex < rhs._vertex) return true; if (rhs._vertex < _vertex) return false; return _attributes < rhs._attributes; } bool isBoundaryPoint() const { for(TriangleSet::const_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; } }; struct Edge : public osg::Referenced { Edge(): _errorMetric(0.0f) {} osg::ref_ptr _p1; osg::ref_ptr _p2; TriangleSet _triangles; float _errorMetric; osg::ref_ptr _proposedPoint; void setErrorMetric(float errorMetric) { _errorMetric = errorMetric; } float getErrorMetric() const { return _errorMetric; } bool operator < ( const Edge& rhs) const { // both error metrics are computed if (getErrorMetric()2) osg::notify(osg::NOTICE)<<"Warning too many traingles ("<<_triangles.size()<<") sharing edge "<isBoundaryPoint() || _p2->isBoundaryPoint(); } }; struct Triangle : public osg::Referenced { Triangle() {} inline bool operator < (const Triangle& rhs) const { 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); } 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; void update() { _plane.set(_p1->_vertex,_p2->_vertex,_p3->_vertex); } float distance(const osg::Vec3& vertex) const { return _plane.distance(vertex); } bool isBoundaryTriangle() const { return (_e1->isBoundaryEdge() || _e2->isBoundaryEdge() || _e3->isBoundaryEdge()); } }; Triangle* addTriangle(unsigned int p1, unsigned int p2, unsigned int p3) { //std::cout<<"addTriangle("<_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()); triangle->update(); _triangleSet.insert(triangle); return triangle; } Triangle* addTriangle(Point* p1, Point* p2, Point* p3) { // std::cout<<"addTriangle("<_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()); triangle->update(); _triangleSet.insert(triangle); return triangle; } void removeTriangle(Triangle* triangle) { 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()); 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); } } unsigned int testTriangle(Triangle* triangle) { 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())); } return numErrors; } Edge* addEdge(Triangle* triangle, Point* p1, Point* p2) { //std::cout<<"addEdge("< edge = new Edge; if (p1_p1 = p1; edge->_p2 = p2; } else { edge->_p1 = p2; edge->_p2 = p1; } EdgeSet::iterator itr = _edgeSet.find(edge); if (itr==_edgeSet.end()) { //std::cout<<" addEdge("<addTriangle(triangle); return edge.get(); } void removeEdge(Triangle* triangle, Edge* edge) { EdgeSet::iterator itr = _edgeSet.find(edge); if (itr!=_edgeSet.end()) { edge->_triangles.erase(triangle); if (edge->_triangles.empty()) { // edge no longer in use, so need to delete. _edgeSet.erase(itr); edge->_p1 = 0; edge->_p2 = 0; } } } 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 tmp = edge->_p1; edge->_p1 = edge->_p2; edge->_p2 = tmp; } itr = _edgeSet.find(edge); if (itr!=_edgeSet.end()) { // reuse existing edge. edge = const_cast(itr->get()); } else { // put it back in. _edgeSet.insert(edge); } return edge; } else { return edge; } } bool collapseEdge(Edge* edge, Point* pNew) { if (edge->_triangles.size()<2) return false; typedef std::set< osg::ref_ptr > LocalEdgeList; osg::ref_ptr keep_edge_locally_referenced_to_prevent_premature_deletion = edge; osg::ref_ptr keep_point_locally_referenced_to_prevent_premature_deletion = pNew; osg::ref_ptr edge_p1 = edge->_p1; osg::ref_ptr edge_p2 = edge->_p2; TriangleList triangles_p1; TriangleList triangles_p2; LocalEdgeList oldEdges; if (edge_p1 != pNew) { for(TriangleSet::iterator itr=edge_p1->_triangles.begin(); itr!=edge_p1->_triangles.end(); ++itr) { if (edge->_triangles.count(*itr)==0) { Triangle* triangle = const_cast(itr->get()); triangles_p1.push_back(triangle); oldEdges.insert(triangle->_e1); oldEdges.insert(triangle->_e2); oldEdges.insert(triangle->_e3); } } //triangles_p1 = edge_p1->_triangles; } if (edge_p2 != pNew) { for(TriangleSet::iterator itr=edge_p2->_triangles.begin(); itr!=edge_p2->_triangles.end(); ++itr) { if (edge->_triangles.count(*itr)==0) { Triangle* triangle = const_cast(itr->get()); triangles_p2.push_back(triangle); oldEdges.insert(triangle->_e1); oldEdges.insert(triangle->_e2); oldEdges.insert(triangle->_e3); } } //triangles_p2 = edge_p2->_triangles; } for(LocalEdgeList::iterator oeitr=oldEdges.begin(); oeitr!=oldEdges.end(); ++oeitr) { _edgeSet.erase(*oeitr); const_cast(oeitr->get())->setErrorMetric(0.0f); _edgeSet.insert(*oeitr); } 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(TriangleSet::iterator teitr=edge->_triangles.begin(); teitr!=edge->_triangles.end(); ++teitr) { removeTriangle(const_cast(teitr->get())); } LocalEdgeList newEdges; 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(); Triangle* newTri = addTriangle(p1,p2,p3); newEdges.insert(newTri->_e1); newEdges.insert(newTri->_e2); 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; } unsigned int testEdge(Edge* edge) { unsigned int numErrors = 0; for(TriangleSet::iterator teitr=edge->_triangles.begin(); teitr!=edge->_triangles.end(); ++teitr) { Triangle* triangle = const_cast(teitr->get()); if (!(triangle->_e1 == edge || triangle->_e2 == edge || triangle->_e3 == edge)) { std::cout<<"testEdge("<_e1=="<_e1.get()<_e2=="<_e2.get()<_e3=="<_e3.get()<_triangles.empty()) { std::cout<<"testEdge("<(itr->get())); } return numErrors; } unsigned int computeNumBoundaryEdges() { unsigned int numBoundaryEdges = 0; for(EdgeSet::iterator itr = _edgeSet.begin(); itr!=_edgeSet.end(); ++itr) { if ((*itr)->isBoundaryEdge()) ++numBoundaryEdges; } return numBoundaryEdges; } Point* addPoint(Triangle* triangle, unsigned int p1) { return addPoint(triangle,_originalPointList[p1].get()); } Point* addPoint(Triangle* triangle, Point* point) { PointSet::iterator itr = _pointSet.find(point); if (itr==_pointSet.end()) { //std::cout<<" addPoint("<(itr->get()); //std::cout<<" reusePoint("<_triangles.insert(triangle); return point; } void removePoint(Triangle* triangle, Point* point) { PointSet::iterator itr = _pointSet.find(point); if (itr!=_pointSet.end()) { point->_triangles.erase(triangle); if (point->_triangles.empty()) { // point no longer in use, so need to delete. _pointSet.erase(itr); } } } 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(itr->get()); if (!(triangle->_p1 == point || triangle->_p2 == point || triangle->_p3 == point)) { std::cout<<"testPoint("<_p1 "<_p1.get()<_p2 "<_p2.get()<_p3 "<_p3.get()<(itr->get())); } return numErrors; } protected: typedef std::vector< osg::ref_ptr > ArrayList; osg::Geometry* _geometry; ArrayList _arrayList; unsigned int _targetNumTriangles; EdgeSet _edgeSet; TriangleSet _triangleSet; PointSet _pointSet; PointList _originalPointList; }; struct CollectTriangleOperator { CollectTriangleOperator():_ec(0) {} void setEdgeCollapse(EdgeCollapse* ec) { _ec = ec; } EdgeCollapse* _ec; // for use in the triangle functor. inline void operator()(unsigned int p1, unsigned int p2, unsigned int p3) { _ec->addTriangle(p1,p2,p3); } }; typedef osg::TriangleIndexFunctor CollectTriangleIndexFunctor; class CopyArrayToPointsVisitor : public osg::ArrayVisitor { public: CopyArrayToPointsVisitor(EdgeCollapse::PointList& pointList): _pointList(pointList) {} template void copy(T& array) { if (_pointList.size()!=array.size()) return; for(unsigned int i=0;i<_pointList.size();++i) _pointList[i]->_attributes.push_back((float)array[i]); } virtual void apply(osg::Array&) {} virtual void apply(osg::ByteArray& array) { copy(array); } virtual void apply(osg::ShortArray& array) { copy(array); } virtual void apply(osg::IntArray& array) { copy(array); } virtual void apply(osg::UByteArray& array) { copy(array); } virtual void apply(osg::UShortArray& array) { copy(array); } virtual void apply(osg::UIntArray& array) { copy(array); } virtual void apply(osg::FloatArray& array) { copy(array); } virtual void apply(osg::UByte4Array& array) { if (_pointList.size()!=array.size()) return; for(unsigned int i=0;i<_pointList.size();++i) { osg::UByte4& value = array[i]; EdgeCollapse::FloatList& attributes = _pointList[i]->_attributes; attributes.push_back((float)value.r()); attributes.push_back((float)value.g()); attributes.push_back((float)value.b()); attributes.push_back((float)value.a()); } } virtual void apply(osg::Vec2Array& array) { if (_pointList.size()!=array.size()) return; for(unsigned int i=0;i<_pointList.size();++i) { osg::Vec2& value = array[i]; EdgeCollapse::FloatList& attributes = _pointList[i]->_attributes; attributes.push_back(value.x()); attributes.push_back(value.y()); } } virtual void apply(osg::Vec3Array& array) { if (_pointList.size()!=array.size()) return; for(unsigned int i=0;i<_pointList.size();++i) { osg::Vec3& value = array[i]; EdgeCollapse::FloatList& attributes = _pointList[i]->_attributes; attributes.push_back(value.x()); attributes.push_back(value.y()); attributes.push_back(value.z()); } } virtual void apply(osg::Vec4Array& array) { if (_pointList.size()!=array.size()) return; for(unsigned int i=0;i<_pointList.size();++i) { osg::Vec4& value = array[i]; EdgeCollapse::FloatList& attributes = _pointList[i]->_attributes; attributes.push_back(value.x()); attributes.push_back(value.y()); attributes.push_back(value.z()); attributes.push_back(value.w()); } } EdgeCollapse::PointList& _pointList; }; class CopyVertexArrayToPointsVisitor : public osg::ArrayVisitor { public: CopyVertexArrayToPointsVisitor(EdgeCollapse::PointList& pointList): _pointList(pointList) {} virtual void apply(osg::Vec2Array& array) { if (_pointList.size()!=array.size()) return; for(unsigned int i=0;i<_pointList.size();++i) { _pointList[i] = new EdgeCollapse::Point; _pointList[i]->_index = i; osg::Vec2& value = array[i]; osg::Vec3& vertex = _pointList[i]->_vertex; vertex.set(value.x(),value.y(),0.0f); } } virtual void apply(osg::Vec3Array& array) { if (_pointList.size()!=array.size()) return; for(unsigned int i=0;i<_pointList.size();++i) { _pointList[i] = new EdgeCollapse::Point; _pointList[i]->_index = i; _pointList[i]->_vertex = array[i]; } } virtual void apply(osg::Vec4Array& array) { if (_pointList.size()!=array.size()) return; for(unsigned int i=0;i<_pointList.size();++i) { _pointList[i] = new EdgeCollapse::Point; _pointList[i]->_index = i; osg::Vec4& value = array[i]; osg::Vec3& vertex = _pointList[i]->_vertex; vertex.set(value.x()/value.w(),value.y()/value.w(),value.z()/value.w()); } } EdgeCollapse::PointList& _pointList; }; void EdgeCollapse::setGeometry(osg::Geometry* geometry) { _geometry = geometry; // check to see if vertex attributes indices exists, if so expand them to remove them if (_geometry->suitableForOptimization()) { // removing coord indices osg::notify(osg::INFO)<<"EdgeCollapse::setGeometry(..): Removing attribute indices"<copyToAndOptimize(*_geometry); } unsigned int numVertices = geometry->getVertexArray()->getNumElements(); _originalPointList.resize(numVertices); // copy vertices across to local point list CopyVertexArrayToPointsVisitor copyVertexArrayToPoints(_originalPointList); _geometry->getVertexArray()->accept(copyVertexArrayToPoints); // copy other per vertex attributes across to local point list. CopyArrayToPointsVisitor copyArrayToPoints(_originalPointList); for(unsigned int ti=0;ti<_geometry->getNumTexCoordArrays();++ti) { if (_geometry->getTexCoordArray(ti)) geometry->getTexCoordArray(ti)->accept(copyArrayToPoints); } if (_geometry->getNormalArray() && _geometry->getNormalBinding()==osg::Geometry::BIND_PER_VERTEX) geometry->getNormalArray()->accept(copyArrayToPoints); if (_geometry->getColorArray() && _geometry->getColorBinding()==osg::Geometry::BIND_PER_VERTEX) geometry->getColorArray()->accept(copyArrayToPoints); if (_geometry->getSecondaryColorArray() && _geometry->getSecondaryColorBinding()==osg::Geometry::BIND_PER_VERTEX) geometry->getSecondaryColorArray()->accept(copyArrayToPoints); if (_geometry->getFogCoordArray() && _geometry->getFogCoordBinding()==osg::Geometry::BIND_PER_VERTEX) geometry->getFogCoordArray()->accept(copyArrayToPoints); for(unsigned int vi=0;vi<_geometry->getNumVertexAttribArrays();++vi) { if (_geometry->getVertexAttribArray(vi) && _geometry->getVertexAttribBinding(vi)==osg::Geometry::BIND_PER_VERTEX) geometry->getVertexAttribArray(vi)->accept(copyArrayToPoints); } CollectTriangleIndexFunctor collectTriangles; collectTriangles.setEdgeCollapse(this); _geometry->accept(collectTriangles); } class CopyPointsToArrayVisitor : public osg::ArrayVisitor { public: CopyPointsToArrayVisitor(EdgeCollapse::PointList& pointList): _pointList(pointList), _index(0) {} template void copy(T& array) { array.resize(_pointList.size()); for(unsigned int i=0;i<_pointList.size();++i) { if (_index<_pointList[i]->_attributes.size()) { float val = (_pointList[i]->_attributes[_index]); array[i] = R (val); } } ++_index; } virtual void apply(osg::Array&) {} virtual void apply(osg::ByteArray& array) { copy(array); } virtual void apply(osg::ShortArray& array) { copy(array); } virtual void apply(osg::IntArray& array) { copy(array); } virtual void apply(osg::UByteArray& array) { copy(array); } virtual void apply(osg::UShortArray& array) { copy(array); } virtual void apply(osg::UIntArray& array) { copy(array); } virtual void apply(osg::FloatArray& array) { copy(array); } virtual void apply(osg::UByte4Array& array) { array.resize(_pointList.size()); for(unsigned int i=0;i<_pointList.size();++i) { EdgeCollapse::FloatList& attributes = _pointList[i]->_attributes; array[i].set((unsigned char)attributes[_index], (unsigned char)attributes[_index+1], (unsigned char)attributes[_index+2], (unsigned char)attributes[_index+3]); } _index += 4; } virtual void apply(osg::Vec2Array& array) { array.resize(_pointList.size()); for(unsigned int i=0;i<_pointList.size();++i) { EdgeCollapse::FloatList& attributes = _pointList[i]->_attributes; if (_index+1_attributes; if (_index+2_attributes; if (_index+3_index = i; osg::Vec3& vertex = _pointList[i]->_vertex; array[i].set(vertex.x(),vertex.y()); } } virtual void apply(osg::Vec3Array& array) { array.resize(_pointList.size()); for(unsigned int i=0;i<_pointList.size();++i) { _pointList[i]->_index = i; array[i] = _pointList[i]->_vertex; } } virtual void apply(osg::Vec4Array& array) { array.resize(_pointList.size()); for(unsigned int i=0;i<_pointList.size();++i) { _pointList[i]->_index = i; osg::Vec3& vertex = _pointList[i]->_vertex; array[i].set(vertex.x(),vertex.y(),vertex.z(),1.0f); } } EdgeCollapse::PointList& _pointList; }; void EdgeCollapse::copyBackToGeometry() { #if 1 updateErrorMetricForAllEdges(); #endif std::cout<<"******* BEFORE EDGE COLLAPSE ********"<<_triangleSet.size()<