7d40c7258f
New methods osg::Geometry::containsDeprecatedData() and osg::Geometry::fixDeprecatedData() provide a means for converting geometries that still use the array indices and BIND_PER_PRIMITIVE across to complient versions. Cleaned up the rest of the OSG where use of array indices and BIND_PER_PRIMITIVE were accessed or used.
490 lines
13 KiB
C++
490 lines
13 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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 <osgUtil/EdgeCollector>
|
|
#include <osgUtil/ConvertVec>
|
|
|
|
#include <osg/TriangleIndexFunctor>
|
|
|
|
namespace osgUtil
|
|
{
|
|
|
|
bool EdgeCollector::Point::isBoundaryPoint() const
|
|
{
|
|
if (_protected) return true;
|
|
|
|
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;
|
|
}
|
|
|
|
void EdgeCollector::Edge::clear()
|
|
{
|
|
_p1 = 0;
|
|
_p2 = 0;
|
|
_op1 = 0;
|
|
_op2 = 0;
|
|
_triangles.clear();
|
|
}
|
|
|
|
|
|
|
|
bool EdgeCollector::Edge::operator < ( const Edge& rhs) const
|
|
{
|
|
if (dereference_check_less(_p1,rhs._p1)) return true;
|
|
if (dereference_check_less(rhs._p1,_p1)) return false;
|
|
|
|
return dereference_check_less(_p2,rhs._p2);
|
|
}
|
|
|
|
bool EdgeCollector::Edge::operator == ( const Edge& rhs) const
|
|
{
|
|
if (&rhs==this) return true;
|
|
if (*this<rhs) return false;
|
|
if (rhs<*this) return false;
|
|
return true;
|
|
}
|
|
|
|
bool EdgeCollector::Edge::operator != ( const Edge& rhs) const
|
|
{
|
|
if (&rhs==this) return false;
|
|
if (*this<rhs) return true;
|
|
if (rhs<*this) return true;
|
|
return false;
|
|
}
|
|
|
|
void EdgeCollector::Edge::setOrderedPoints(Point* p1, Point* p2)
|
|
{
|
|
if (dereference_check_less(p1, p2))
|
|
{
|
|
_p1 = _op1 = p1;
|
|
_p2 = _op2 = p2;
|
|
}
|
|
else
|
|
{
|
|
_p1 = _op2 = p2;
|
|
_p2 = _op1 = p1;
|
|
}
|
|
}
|
|
|
|
void EdgeCollector::Triangle::clear()
|
|
{
|
|
_p1 = 0;
|
|
_p2 = 0;
|
|
_p3 = 0;
|
|
|
|
_op1 = 0;
|
|
_op2 = 0;
|
|
_op3 = 0;
|
|
|
|
_e1 = 0;
|
|
_e2 = 0;
|
|
_e3 = 0;
|
|
}
|
|
|
|
bool EdgeCollector::Triangle::operator < (const Triangle& rhs) const
|
|
{
|
|
if (dereference_check_less(_p1,rhs._p1)) return true;
|
|
if (dereference_check_less(rhs._p1,_p1)) return false;
|
|
|
|
|
|
const Point* lhs_lower = dereference_check_less(_p2,_p3) ? _p2.get() : _p3.get();
|
|
const Point* rhs_lower = dereference_check_less(rhs._p2,rhs._p3) ? rhs._p2.get() : rhs._p3.get();
|
|
|
|
if (dereference_check_less(lhs_lower,rhs_lower)) return true;
|
|
if (dereference_check_less(rhs_lower,lhs_lower)) return false;
|
|
|
|
const Point* lhs_upper = dereference_check_less(_p2,_p3) ? _p3.get() : _p2.get();
|
|
const Point* rhs_upper = dereference_check_less(rhs._p2,rhs._p3) ? rhs._p3.get() : rhs._p2.get();
|
|
|
|
return dereference_check_less(lhs_upper,rhs_upper);
|
|
}
|
|
|
|
|
|
void EdgeCollector::Triangle::setOrderedPoints(Point* p1, Point* p2, Point* p3)
|
|
{
|
|
Point* points[3];
|
|
|
|
_op1 = points[0] = p1;
|
|
_op2 = points[1] = p2;
|
|
_op3 = points[2] = p3;
|
|
|
|
// find the lowest value point in the list.
|
|
unsigned int lowest = 0;
|
|
if (dereference_check_less(points[1],points[lowest])) lowest = 1;
|
|
if (dereference_check_less(points[2],points[lowest])) lowest = 2;
|
|
|
|
_p1 = points[lowest];
|
|
_p2 = points[(lowest+1)%3];
|
|
_p3 = points[(lowest+2)%3];
|
|
|
|
_plane.set(_op1->_vertex,_op2->_vertex,_op3->_vertex);
|
|
}
|
|
|
|
|
|
|
|
|
|
osg::UIntArray * EdgeCollector::Edgeloop::toIndexArray() const
|
|
{
|
|
osg::UIntArray * indexArray = new osg::UIntArray;
|
|
|
|
EdgeList::const_iterator it = _edgeList.begin(), end = _edgeList.end();
|
|
|
|
for (;it != end; ++it)
|
|
indexArray->push_back((*it)->_op1->_index);
|
|
|
|
return indexArray;
|
|
}
|
|
|
|
EdgeCollector::Triangle* EdgeCollector::addTriangle(unsigned int p1, unsigned int p2, unsigned int p3)
|
|
{
|
|
//OSG_NOTICE<<"addTriangle("<<p1<<","<<p2<<","<<p3<<")"<<std::endl;
|
|
|
|
// detect if triangle is degenerate.
|
|
if (p1==p2 || p2==p3 || p1==p3) return 0;
|
|
if ((_originalPointList[p1]->_vertex == _originalPointList[p2]->_vertex) ||
|
|
(_originalPointList[p2]->_vertex == _originalPointList[p3]->_vertex) ||
|
|
(_originalPointList[p3]->_vertex == _originalPointList[p1]->_vertex)) return 0;
|
|
|
|
Triangle* triangle = new Triangle;
|
|
|
|
triangle->setOrderedPoints(addPoint(triangle, p1), addPoint(triangle, p2), addPoint(triangle, p3));
|
|
|
|
triangle->_e1 = addEdge(triangle, triangle->_op1.get(), triangle->_op2.get());
|
|
triangle->_e2 = addEdge(triangle, triangle->_op2.get(), triangle->_op3.get());
|
|
triangle->_e3 = addEdge(triangle, triangle->_op3.get(), triangle->_op1.get());
|
|
|
|
_triangleSet.insert(triangle);
|
|
|
|
return triangle;
|
|
}
|
|
|
|
EdgeCollector::Triangle* EdgeCollector::addTriangle(Point* p1, Point* p2, Point* p3)
|
|
{
|
|
// OSG_NOTICE<<" addTriangle("<<p1<<","<<p2<<","<<p3<<")"<<std::endl;
|
|
|
|
// detect if triangle is degenerate.
|
|
if (p1==p2 || p2==p3 || p1==p3) return 0;
|
|
if ((p1->_vertex == p2->_vertex) ||
|
|
(p2->_vertex == p3->_vertex) ||
|
|
(p3->_vertex == p1->_vertex)) return 0;
|
|
|
|
Triangle* triangle = new Triangle;
|
|
|
|
triangle->setOrderedPoints(addPoint(triangle, p1), addPoint(triangle, p2), addPoint(triangle, p3));
|
|
|
|
triangle->_e1 = addEdge(triangle, triangle->_op1.get(), triangle->_op2.get());
|
|
triangle->_e2 = addEdge(triangle, triangle->_op2.get(), triangle->_op3.get());
|
|
triangle->_e3 = addEdge(triangle, triangle->_op3.get(), triangle->_op1.get());
|
|
|
|
_triangleSet.insert(triangle);
|
|
|
|
return triangle;
|
|
}
|
|
|
|
|
|
EdgeCollector::Edge* EdgeCollector::addEdge(Triangle* triangle, Point* p1, Point* p2)
|
|
{
|
|
// OSG_NOTICE<<" addEdge("<<p1<<","<<p2<<")"<<std::endl;
|
|
osg::ref_ptr<Edge> edge = new Edge;
|
|
edge->setOrderedPoints(p1,p2);
|
|
|
|
EdgeSet::iterator itr = _edgeSet.find(edge);
|
|
if (itr==_edgeSet.end())
|
|
{
|
|
// OSG_NOTICE<<" addEdge("<<edge.get()<<") edge->_p1="<<edge->_p1.get()<<" _p2="<<edge->_p2.get()<<std::endl;
|
|
_edgeSet.insert(edge);
|
|
}
|
|
else
|
|
{
|
|
// OSG_NOTICE<<" reuseEdge("<<edge.get()<<") edge->_p1="<<edge->_p1.get()<<" _p2="<<edge->_p2.get()<<std::endl;
|
|
edge = *itr;
|
|
}
|
|
|
|
edge->addTriangle(triangle);
|
|
|
|
return edge.get();
|
|
}
|
|
|
|
|
|
|
|
|
|
EdgeCollector::Point* EdgeCollector::addPoint(Triangle* triangle, Point* point)
|
|
{
|
|
|
|
PointSet::iterator itr = _pointSet.find(point);
|
|
if (itr==_pointSet.end())
|
|
{
|
|
//OSG_NOTICE<<" addPoint("<<point.get()<<")"<<std::endl;
|
|
_pointSet.insert(point);
|
|
}
|
|
else
|
|
{
|
|
point = const_cast<Point*>(itr->get());
|
|
//OSG_NOTICE<<" reusePoint("<<point.get()<<")"<<std::endl;
|
|
}
|
|
|
|
point->_triangles.insert(triangle);
|
|
|
|
return point;
|
|
}
|
|
|
|
void EdgeCollector::getBoundaryEdgeList(EdgeList & el)
|
|
{
|
|
for (EdgeSet::iterator it = _edgeSet.begin(), end = _edgeSet.end(); it != end; ++it)
|
|
{
|
|
if ((*it)->isBoundaryEdge()) el.push_back(*it);
|
|
}
|
|
}
|
|
|
|
bool EdgeCollector::extractBoundaryEdgeloop(EdgeList & el, Edgeloop & edgeloop)
|
|
{
|
|
if (el.empty()) return false;
|
|
|
|
|
|
osg::ref_ptr<Edge> current = el.back();
|
|
el.pop_back();
|
|
|
|
// ** init the Edgeloop
|
|
edgeloop._edgeList.push_back(current.get());
|
|
|
|
|
|
|
|
bool done = false;
|
|
while (!done)
|
|
{
|
|
bool found = false;
|
|
EdgeList::iterator it = el.begin(), end = el.end();
|
|
while (it != end && !found)
|
|
{
|
|
if (current->endConnected(*(it->get())))
|
|
{
|
|
found = true;
|
|
}
|
|
else
|
|
{
|
|
++it;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
OSG_WARN << "extractBoundaryEdgeloop : unable to close edge loop" << std::endl;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
edgeloop._edgeList.push_back(it->get());
|
|
current = it->get();
|
|
el.erase(it);
|
|
|
|
if (edgeloop.isClosed()) done = true;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool EdgeCollector::extractBoundaryEdgeloopList(EdgeList & el, EdgeloopList & edgeloopList)
|
|
{
|
|
while (!el.empty())
|
|
{
|
|
osg::ref_ptr<Edgeloop> edgeloop(new Edgeloop);
|
|
|
|
if (extractBoundaryEdgeloop(el, *edgeloop))
|
|
edgeloopList.push_back(edgeloop);
|
|
else
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct CollectTriangleOperator
|
|
{
|
|
|
|
CollectTriangleOperator():_ec(0) {}
|
|
|
|
void setEdgeCollector(EdgeCollector* ec) { _ec = ec; }
|
|
|
|
EdgeCollector* _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<CollectTriangleOperator> CollectTriangleIndexFunctor;
|
|
|
|
class CopyVertexArrayToPointsVisitor : public osg::ArrayVisitor
|
|
{
|
|
public:
|
|
CopyVertexArrayToPointsVisitor(EdgeCollector::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 EdgeCollector::Point;
|
|
_pointList[i]->_index = i;
|
|
|
|
osgUtil::ConvertVec<osg::Vec2, osg::Vec3d>::convert(array[i], _pointList[i]->_vertex);
|
|
}
|
|
}
|
|
|
|
virtual void apply(osg::Vec3Array& array)
|
|
{
|
|
if (_pointList.size()!=array.size()) return;
|
|
|
|
for(unsigned int i=0;i<_pointList.size();++i)
|
|
{
|
|
_pointList[i] = new EdgeCollector::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 EdgeCollector::Point;
|
|
_pointList[i]->_index = i;
|
|
|
|
osgUtil::ConvertVec<osg::Vec4, osg::Vec3d>::convert(array[i], _pointList[i]->_vertex);
|
|
}
|
|
}
|
|
|
|
virtual void apply(osg::Vec2dArray& array)
|
|
{
|
|
if (_pointList.size()!=array.size()) return;
|
|
|
|
for(unsigned int i=0;i<_pointList.size();++i)
|
|
{
|
|
_pointList[i] = new EdgeCollector::Point;
|
|
_pointList[i]->_index = i;
|
|
|
|
osgUtil::ConvertVec<osg::Vec2d, osg::Vec3d>::convert(array[i], _pointList[i]->_vertex);
|
|
}
|
|
}
|
|
|
|
virtual void apply(osg::Vec3dArray& array)
|
|
{
|
|
if (_pointList.size()!=array.size()) return;
|
|
|
|
for(unsigned int i=0;i<_pointList.size();++i)
|
|
{
|
|
_pointList[i] = new EdgeCollector::Point;
|
|
_pointList[i]->_index = i;
|
|
|
|
_pointList[i]->_vertex = array[i];
|
|
}
|
|
}
|
|
|
|
virtual void apply(osg::Vec4dArray& array)
|
|
{
|
|
if (_pointList.size()!=array.size()) return;
|
|
|
|
for(unsigned int i=0;i<_pointList.size();++i)
|
|
{
|
|
_pointList[i] = new EdgeCollector::Point;
|
|
_pointList[i]->_index = i;
|
|
|
|
osgUtil::ConvertVec<osg::Vec4d, osg::Vec3d>::convert(array[i], _pointList[i]->_vertex);
|
|
}
|
|
}
|
|
|
|
EdgeCollector::PointList& _pointList;
|
|
|
|
protected:
|
|
|
|
CopyVertexArrayToPointsVisitor& operator = (const CopyVertexArrayToPointsVisitor&) { return *this; }
|
|
};
|
|
|
|
EdgeCollector::~EdgeCollector()
|
|
{
|
|
std::for_each(_edgeSet.begin(),_edgeSet.end(),dereference_clear());
|
|
|
|
std::for_each(_triangleSet.begin(),_triangleSet.end(),dereference_clear());
|
|
std::for_each(_pointSet.begin(),_pointSet.end(),dereference_clear());
|
|
std::for_each(_originalPointList.begin(),_originalPointList.end(),dereference_clear());
|
|
}
|
|
|
|
|
|
void EdgeCollector::setGeometry(osg::Geometry* geometry)
|
|
{
|
|
_geometry = geometry;
|
|
|
|
unsigned int numVertices = geometry->getVertexArray()->getNumElements();
|
|
|
|
_originalPointList.resize(numVertices);
|
|
|
|
// copy vertices across to local point list
|
|
CopyVertexArrayToPointsVisitor copyVertexArrayToPoints(_originalPointList);
|
|
_geometry->getVertexArray()->accept(copyVertexArrayToPoints);
|
|
|
|
CollectTriangleIndexFunctor collectTriangles;
|
|
collectTriangles.setEdgeCollector(this);
|
|
|
|
_geometry->accept(collectTriangles);
|
|
}
|
|
|
|
// ** search BoundaryEdgeloop in the geometry, extrude this loop
|
|
// ** and create primitiveSet to link original loop and extruded loop
|
|
void EdgeCollector::getEdgeloopIndexList(IndexArrayList & ial)
|
|
{
|
|
// ** collect Boundary Edge
|
|
EdgeList edgeList;
|
|
getBoundaryEdgeList(edgeList);
|
|
|
|
// ** collect Edgeloop
|
|
EdgeloopList edgeloopList;
|
|
if (extractBoundaryEdgeloopList(edgeList, edgeloopList) == false)
|
|
{
|
|
OSG_WARN << "EdgeCollector: fail to collect Edgeloop.\n\n\n" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// ** get IndexArray of each Edgeloop
|
|
EdgeloopList::iterator elIt, elEnd = edgeloopList.end();
|
|
for (elIt = edgeloopList.begin(); elIt != elEnd; ++elIt)
|
|
{
|
|
ial.push_back((*elIt)->toIndexArray());
|
|
}
|
|
}
|
|
|
|
} // end of osgUtil namespace
|