1
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
3
* This library is open source and may be redistributed and/or modified under
4
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5
* (at your option) any later version. The full license is in LICENSE file
6
* included with this distribution, and on the openscenegraph.org website.
8
* This library is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* OpenSceneGraph Public License for more details.
14
#include <osgUtil/EdgeCollector>
15
#include <osgUtil/ConvertVec>
17
#include <osg/TriangleIndexFunctor>
22
bool EdgeCollector::Point::isBoundaryPoint() const
24
if (_protected) return true;
26
for(TriangleSet::const_iterator itr=_triangles.begin();
27
itr!=_triangles.end();
30
const Triangle* triangle = itr->get();
31
if ((triangle->_e1->_p1==this || triangle->_e1->_p2==this) && triangle->_e1->isBoundaryEdge()) return true;
32
if ((triangle->_e2->_p1==this || triangle->_e2->_p2==this) && triangle->_e2->isBoundaryEdge()) return true;
33
if ((triangle->_e3->_p1==this || triangle->_e3->_p2==this) && triangle->_e3->isBoundaryEdge()) return true;
35
//if ((*itr)->isBoundaryTriangle()) return true;
40
void EdgeCollector::Edge::clear()
51
bool EdgeCollector::Edge::operator < ( const Edge& rhs) const
53
if (dereference_check_less(_p1,rhs._p1)) return true;
54
if (dereference_check_less(rhs._p1,_p1)) return false;
56
return dereference_check_less(_p2,rhs._p2);
59
bool EdgeCollector::Edge::operator == ( const Edge& rhs) const
61
if (&rhs==this) return true;
62
if (*this<rhs) return false;
63
if (rhs<*this) return false;
67
bool EdgeCollector::Edge::operator != ( const Edge& rhs) const
69
if (&rhs==this) return false;
70
if (*this<rhs) return true;
71
if (rhs<*this) return true;
75
void EdgeCollector::Edge::setOrderedPoints(Point* p1, Point* p2)
77
if (dereference_check_less(p1, p2))
89
void EdgeCollector::Triangle::clear()
104
bool EdgeCollector::Triangle::operator < (const Triangle& rhs) const
106
if (dereference_check_less(_p1,rhs._p1)) return true;
107
if (dereference_check_less(rhs._p1,_p1)) return false;
110
const Point* lhs_lower = dereference_check_less(_p2,_p3) ? _p2.get() : _p3.get();
111
const Point* rhs_lower = dereference_check_less(rhs._p2,rhs._p3) ? rhs._p2.get() : rhs._p3.get();
113
if (dereference_check_less(lhs_lower,rhs_lower)) return true;
114
if (dereference_check_less(rhs_lower,lhs_lower)) return false;
116
const Point* lhs_upper = dereference_check_less(_p2,_p3) ? _p3.get() : _p2.get();
117
const Point* rhs_upper = dereference_check_less(rhs._p2,rhs._p3) ? rhs._p3.get() : rhs._p2.get();
119
return dereference_check_less(lhs_upper,rhs_upper);
123
void EdgeCollector::Triangle::setOrderedPoints(Point* p1, Point* p2, Point* p3)
127
_op1 = points[0] = p1;
128
_op2 = points[1] = p2;
129
_op3 = points[2] = p3;
131
// find the lowest value point in the list.
132
unsigned int lowest = 0;
133
if (dereference_check_less(points[1],points[lowest])) lowest = 1;
134
if (dereference_check_less(points[2],points[lowest])) lowest = 2;
136
_p1 = points[lowest];
137
_p2 = points[(lowest+1)%3];
138
_p3 = points[(lowest+2)%3];
140
_plane.set(_op1->_vertex,_op2->_vertex,_op3->_vertex);
146
osg::UIntArray * EdgeCollector::Edgeloop::toIndexArray() const
148
osg::UIntArray * indexArray = new osg::UIntArray;
150
EdgeList::const_iterator it = _edgeList.begin(), end = _edgeList.end();
152
for (;it != end; ++it)
153
indexArray->push_back((*it)->_op1->_index);
158
EdgeCollector::Triangle* EdgeCollector::addTriangle(unsigned int p1, unsigned int p2, unsigned int p3)
160
//osg::notify(osg::NOTICE)<<"addTriangle("<<p1<<","<<p2<<","<<p3<<")"<<std::endl;
162
// detect if triangle is degenerate.
163
if (p1==p2 || p2==p3 || p1==p3) return 0;
164
if ((_originalPointList[p1]->_vertex == _originalPointList[p2]->_vertex) ||
165
(_originalPointList[p2]->_vertex == _originalPointList[p3]->_vertex) ||
166
(_originalPointList[p3]->_vertex == _originalPointList[p1]->_vertex)) return 0;
168
Triangle* triangle = new Triangle;
170
triangle->setOrderedPoints(addPoint(triangle, p1), addPoint(triangle, p2), addPoint(triangle, p3));
172
triangle->_e1 = addEdge(triangle, triangle->_op1.get(), triangle->_op2.get());
173
triangle->_e2 = addEdge(triangle, triangle->_op2.get(), triangle->_op3.get());
174
triangle->_e3 = addEdge(triangle, triangle->_op3.get(), triangle->_op1.get());
176
_triangleSet.insert(triangle);
181
EdgeCollector::Triangle* EdgeCollector::addTriangle(Point* p1, Point* p2, Point* p3)
183
// osg::notify(osg::NOTICE)<<" addTriangle("<<p1<<","<<p2<<","<<p3<<")"<<std::endl;
185
// detect if triangle is degenerate.
186
if (p1==p2 || p2==p3 || p1==p3) return 0;
187
if ((p1->_vertex == p2->_vertex) ||
188
(p2->_vertex == p3->_vertex) ||
189
(p3->_vertex == p1->_vertex)) return 0;
191
Triangle* triangle = new Triangle;
193
triangle->setOrderedPoints(addPoint(triangle, p1), addPoint(triangle, p2), addPoint(triangle, p3));
195
triangle->_e1 = addEdge(triangle, triangle->_op1.get(), triangle->_op2.get());
196
triangle->_e2 = addEdge(triangle, triangle->_op2.get(), triangle->_op3.get());
197
triangle->_e3 = addEdge(triangle, triangle->_op3.get(), triangle->_op1.get());
199
_triangleSet.insert(triangle);
205
EdgeCollector::Edge* EdgeCollector::addEdge(Triangle* triangle, Point* p1, Point* p2)
207
// osg::notify(osg::NOTICE)<<" addEdge("<<p1<<","<<p2<<")"<<std::endl;
208
osg::ref_ptr<Edge> edge = new Edge;
209
edge->setOrderedPoints(p1,p2);
211
EdgeSet::iterator itr = _edgeSet.find(edge);
212
if (itr==_edgeSet.end())
214
// osg::notify(osg::NOTICE)<<" addEdge("<<edge.get()<<") edge->_p1="<<edge->_p1.get()<<" _p2="<<edge->_p2.get()<<std::endl;
215
_edgeSet.insert(edge);
219
// osg::notify(osg::NOTICE)<<" reuseEdge("<<edge.get()<<") edge->_p1="<<edge->_p1.get()<<" _p2="<<edge->_p2.get()<<std::endl;
223
edge->addTriangle(triangle);
231
EdgeCollector::Point* EdgeCollector::addPoint(Triangle* triangle, Point* point)
234
PointSet::iterator itr = _pointSet.find(point);
235
if (itr==_pointSet.end())
237
//osg::notify(osg::NOTICE)<<" addPoint("<<point.get()<<")"<<std::endl;
238
_pointSet.insert(point);
242
point = const_cast<Point*>(itr->get());
243
//osg::notify(osg::NOTICE)<<" reusePoint("<<point.get()<<")"<<std::endl;
246
point->_triangles.insert(triangle);
251
void EdgeCollector::getBoundaryEdgeList(EdgeList & el)
253
for (EdgeSet::iterator it = _edgeSet.begin(), end = _edgeSet.end(); it != end; ++it)
255
if ((*it)->isBoundaryEdge()) el.push_back(*it);
259
bool EdgeCollector::extractBoundaryEdgeloop(EdgeList & el, Edgeloop & edgeloop)
261
if (el.empty()) return false;
264
osg::ref_ptr<Edge> current = el.back();
267
// ** init the Edgeloop
268
edgeloop._edgeList.push_back(current.get());
276
EdgeList::iterator it = el.begin(), end = el.end();
277
while (it != end && !found)
279
if (current->endConnected(*(it->get())))
291
osg::notify(osg::WARN) << "extractBoundaryEdgeloop : unable to close edge loop" << std::endl;
296
edgeloop._edgeList.push_back(it->get());
300
if (edgeloop.isClosed()) done = true;
306
bool EdgeCollector::extractBoundaryEdgeloopList(EdgeList & el, EdgeloopList & edgeloopList)
310
osg::ref_ptr<Edgeloop> edgeloop(new Edgeloop);
312
if (extractBoundaryEdgeloop(el, *edgeloop))
313
edgeloopList.push_back(edgeloop);
326
struct CollectTriangleOperator
329
CollectTriangleOperator():_ec(0) {}
331
void setEdgeCollector(EdgeCollector* ec) { _ec = ec; }
335
// for use in the triangle functor.
336
inline void operator()(unsigned int p1, unsigned int p2, unsigned int p3)
338
_ec->addTriangle(p1,p2,p3);
344
typedef osg::TriangleIndexFunctor<CollectTriangleOperator> CollectTriangleIndexFunctor;
346
class CopyVertexArrayToPointsVisitor : public osg::ArrayVisitor
349
CopyVertexArrayToPointsVisitor(EdgeCollector::PointList& pointList):
350
_pointList(pointList) {}
352
virtual void apply(osg::Vec2Array& array)
354
if (_pointList.size()!=array.size()) return;
356
for(unsigned int i=0;i<_pointList.size();++i)
358
_pointList[i] = new EdgeCollector::Point;
359
_pointList[i]->_index = i;
361
osgUtil::ConvertVec<osg::Vec2, osg::Vec3d>::convert(array[i], _pointList[i]->_vertex);
365
virtual void apply(osg::Vec3Array& array)
367
if (_pointList.size()!=array.size()) return;
369
for(unsigned int i=0;i<_pointList.size();++i)
371
_pointList[i] = new EdgeCollector::Point;
372
_pointList[i]->_index = i;
374
_pointList[i]->_vertex = array[i];
378
virtual void apply(osg::Vec4Array& array)
380
if (_pointList.size()!=array.size()) return;
382
for(unsigned int i=0;i<_pointList.size();++i)
384
_pointList[i] = new EdgeCollector::Point;
385
_pointList[i]->_index = i;
387
osgUtil::ConvertVec<osg::Vec4, osg::Vec3d>::convert(array[i], _pointList[i]->_vertex);
391
virtual void apply(osg::Vec2dArray& array)
393
if (_pointList.size()!=array.size()) return;
395
for(unsigned int i=0;i<_pointList.size();++i)
397
_pointList[i] = new EdgeCollector::Point;
398
_pointList[i]->_index = i;
400
osgUtil::ConvertVec<osg::Vec2d, osg::Vec3d>::convert(array[i], _pointList[i]->_vertex);
404
virtual void apply(osg::Vec3dArray& array)
406
if (_pointList.size()!=array.size()) return;
408
for(unsigned int i=0;i<_pointList.size();++i)
410
_pointList[i] = new EdgeCollector::Point;
411
_pointList[i]->_index = i;
413
_pointList[i]->_vertex = array[i];
417
virtual void apply(osg::Vec4dArray& array)
419
if (_pointList.size()!=array.size()) return;
421
for(unsigned int i=0;i<_pointList.size();++i)
423
_pointList[i] = new EdgeCollector::Point;
424
_pointList[i]->_index = i;
426
osgUtil::ConvertVec<osg::Vec4d, osg::Vec3d>::convert(array[i], _pointList[i]->_vertex);
430
EdgeCollector::PointList& _pointList;
433
EdgeCollector::~EdgeCollector()
435
std::for_each(_edgeSet.begin(),_edgeSet.end(),dereference_clear());
437
std::for_each(_triangleSet.begin(),_triangleSet.end(),dereference_clear());
438
std::for_each(_pointSet.begin(),_pointSet.end(),dereference_clear());
439
std::for_each(_originalPointList.begin(),_originalPointList.end(),dereference_clear());
443
void EdgeCollector::setGeometry(osg::Geometry* geometry)
445
_geometry = geometry;
447
// check to see if vertex attributes indices exists, if so expand them to remove them
448
if (_geometry->suitableForOptimization())
450
// removing coord indices
451
osg::notify(osg::INFO)<<"EdgeCollector::setGeometry(..): Removing attribute indices"<<std::endl;
452
_geometry->copyToAndOptimize(*_geometry);
455
unsigned int numVertices = geometry->getVertexArray()->getNumElements();
457
_originalPointList.resize(numVertices);
459
// copy vertices across to local point list
460
CopyVertexArrayToPointsVisitor copyVertexArrayToPoints(_originalPointList);
461
_geometry->getVertexArray()->accept(copyVertexArrayToPoints);
463
CollectTriangleIndexFunctor collectTriangles;
464
collectTriangles.setEdgeCollector(this);
466
_geometry->accept(collectTriangles);
469
// ** search BoundaryEdgeloop in the geometry, extrude this loop
470
// ** and create primitiveSet to link original loop and extruded loop
471
void EdgeCollector::getEdgeloopIndexList(IndexArrayList & ial)
473
// ** collect Boundary Edge
475
getBoundaryEdgeList(edgeList);
477
// ** collect Edgeloop
478
EdgeloopList edgeloopList;
479
if (extractBoundaryEdgeloopList(edgeList, edgeloopList) == false)
481
osg::notify(osg::WARN) << "EdgeCollector: fail to collect Edgeloop.\n\n\n" << std::endl;
485
// ** get IndexArray of each Edgeloop
486
EdgeloopList::iterator elIt, elEnd = edgeloopList.end();
487
for (elIt = edgeloopList.begin(); elIt != elEnd; ++elIt)
489
ial.push_back((*elIt)->toIndexArray());
493
} // end of osgUtil namespace