Added fusing of ends of lines

This commit is contained in:
Robert Osfield
2005-10-03 16:13:26 +00:00
parent 550bb4b74e
commit ba5c7cdc91

View File

@@ -2209,6 +2209,255 @@ struct TriangleIntersectOperator
}
lineList.swap(newLines);
}
struct LinePair
{
LinePair(osg::Vec3Array* line):
_line(line),
_lineEnd(0),
_neighbourLine(0),
_neighbourLineEnd(0) {}
bool operator < (const LinePair& linePair) const
{
return _distance < linePair._distance;
}
void consider(osg::Vec3Array* testline)
{
if (_neighbourLine.valid())
{
float distance = ((*_line)[0]-(*testline)[0]).length();
if (distance<_distance)
{
_lineEnd = 0;
_neighbourLine = testline;
_neighbourLineEnd = 0;
_distance = distance;
}
distance = ((*_line)[0]-(*testline)[testline->size()-1]).length();
if (distance<_distance)
{
_lineEnd = 0;
_neighbourLine = testline;
_neighbourLineEnd = testline->size()-1;
_distance = distance;
}
distance = ((*_line)[_line->size()-1]-(*testline)[0]).length();
if (distance<_distance)
{
_lineEnd = _line->size()-1;
_neighbourLine = testline;
_neighbourLineEnd = 0;
_distance = distance;
}
distance = ((*_line)[_line->size()-1]-(*testline)[testline->size()-1]).length();
if (distance<_distance)
{
_lineEnd = _line->size()-1;
_neighbourLine = testline;
_neighbourLineEnd = testline->size()-1;
_distance = distance;
}
}
else
{
_neighbourLine = testline;
if (_neighbourLine==_line)
{
_lineEnd = 0;
_neighbourLineEnd = _neighbourLine->size()-1;
_distance = ((*_line)[_lineEnd]-(*_neighbourLine)[_neighbourLineEnd]).length();
}
else
{
_distance = ((*_line)[0]-(*_neighbourLine)[0]).length();
_lineEnd = 0;
_neighbourLineEnd = 0;
float distance = ((*_line)[0]-(*_neighbourLine)[_neighbourLine->size()-1]).length();
if (distance<_distance)
{
_lineEnd = 0;
_neighbourLineEnd = _neighbourLine->size()-1;
_distance = distance;
}
distance = ((*_line)[_line->size()-1]-(*_neighbourLine)[0]).length();
if (distance<_distance)
{
_lineEnd = _line->size()-1;
_neighbourLineEnd = 0;
_distance = distance;
}
distance = ((*_line)[_line->size()-1]-(*_neighbourLine)[_neighbourLine->size()-1]).length();
if (distance<_distance)
{
_lineEnd = _line->size()-1;
_neighbourLineEnd = _neighbourLine->size()-1;
_distance = distance;
}
}
}
};
bool contains(osg::Vec3Array* line) const
{
return _line==line || _neighbourLine==line;
}
osg::ref_ptr<osg::Vec3Array> _line;
unsigned int _lineEnd;
osg::ref_ptr<osg::Vec3Array> _neighbourLine;
unsigned int _neighbourLineEnd;
float _distance;
};
void fuseEnds(float fuseDistance)
{
SphereSegment::LineList fusedLines;
SphereSegment::LineList unfusedLines;
// first seperat the already fused lines from the unfused ones.
for(SphereSegment::LineList::iterator itr = _generatedLines.begin();
itr != _generatedLines.end();
++itr)
{
osg::Vec3Array* line = itr->get();
if (line->size()>=2)
{
if ((*line)[0]==(*line)[line->size()-1])
{
fusedLines.push_back(line);
}
else
{
unfusedLines.push_back(line);
}
}
}
while (unfusedLines.size()>=1)
{
// generate a set of line pairs to establish which
// line pair has the minimum distance.
typedef std::multiset<LinePair> LinePairSet;
LinePairSet linePairs;
for(unsigned int i=0; i<unfusedLines.size(); ++i)
{
LinePair linePair(unfusedLines[i].get());
for(unsigned int j=i; j<unfusedLines.size(); ++j)
{
linePair.consider(unfusedLines[j].get());
}
linePairs.insert(linePair);
}
for(LinePairSet::iterator itr = linePairs.begin();
itr != linePairs.end();
++itr)
{
osg::notify(osg::NOTICE)<<"Line "<<itr->_line.get()<<" "<<itr->_lineEnd<<" neighbour "<<itr->_neighbourLine.get()<<" "<<itr->_neighbourLineEnd<<" distance="<<itr->_distance<<std::endl;
}
LinePair linePair = *linePairs.begin();
if (linePair._distance > fuseDistance)
{
osg::notify(osg::NOTICE)<<"Completed work, shortest distance left is "<<linePair._distance<<std::endl;
break;
}
if (linePair._line == linePair._neighbourLine)
{
osg::notify(osg::NOTICE)<<"Fusing line to itself"<<std::endl;
osg::Vec3Array* line = linePair._line.get();
osg::Vec3 average = ((*line)[0]+(*line)[line->size()-1])*0.5f;
(*line)[0] = average;
(*line)[line->size()-1] = average;
fusedLines.push_back(line);
SphereSegment::LineList::iterator fitr = std::find(unfusedLines.begin(), unfusedLines.end(), line);
if (fitr != unfusedLines.end())
{
unfusedLines.erase(fitr);
}
else
{
osg::notify(osg::NOTICE)<<"Error couldn't find line in unfused list, exiting fusing loop."<<std::endl;
break;
}
}
else
{
osg::Vec3Array* line1 = linePair._line.get();
int fuseEnd1 = linePair._lineEnd;
int openEnd1 = fuseEnd1==0 ? line1->size()-1 : 0;
int direction1 = openEnd1<fuseEnd1 ? 1 : -1;
osg::Vec3Array* line2 = linePair._neighbourLine.get();
int fuseEnd2 = linePair._neighbourLineEnd;
int openEnd2 = fuseEnd2==0 ? line2->size()-1 : 0;
int direction2 = fuseEnd2<openEnd2 ? 1 : -1;
osg::Vec3Array* newline = new osg::Vec3Array;
// copy across all but fuse end of line1
for(int i=openEnd1;
i != fuseEnd1;
i += direction1)
{
newline->push_back((*line1)[i]);
}
// add the average of the two fused ends
osg::Vec3 average = ((*line1)[fuseEnd1] + (*line2)[fuseEnd2])*0.5f;
newline->push_back(average);
// copy across from the next point in from fuseEnd2 to the openEnd2.
for(int j=fuseEnd2 + direction2;
j != openEnd2 + direction2;
j += direction2)
{
newline->push_back((*line2)[j]);
}
// remove line1 from unfused list.
SphereSegment::LineList::iterator fitr = std::find(unfusedLines.begin(), unfusedLines.end(), line1);
if (fitr != unfusedLines.end())
{
unfusedLines.erase(fitr);
}
// remove line2 from unfused list.
fitr = std::find(unfusedLines.begin(), unfusedLines.end(), line2);
if (fitr != unfusedLines.end())
{
unfusedLines.erase(fitr);
}
// add the newline into the unfused for further processing.
unfusedLines.push_back(newline);
osg::notify(osg::NOTICE)<<"Fusing two seperate lines "<<newline<<std::endl;
}
_generatedLines = fusedLines;
_generatedLines.insert(_generatedLines.end(), unfusedLines.begin(), unfusedLines.end());
}
}
void joinEnds(float joinDistance)
{
}
};
bool computeQuadraticSolution(double a, double b, double c, double& s1, double& s2)
@@ -2836,6 +3085,17 @@ osg::Node* SphereSegment::computeIntersectionSubgraph(const osg::Matrixd& matrix
tif._generatedLines.insert(tif._generatedLines.end(), elevMinLines.begin(), elevMinLines.end());
tif._generatedLines.insert(tif._generatedLines.end(), elevMaxLines.begin(), elevMaxLines.end());
osg::notify(osg::NOTICE)<<"number of seperate lines = "<<tif._generatedLines.size()<<std::endl;
float fuseDistance = 1.0;
tif.fuseEnds(fuseDistance);
osg::notify(osg::NOTICE)<<"number of seperate lines after fuse = "<<tif._generatedLines.size()<<std::endl;
float joinDistance = 1e8;
tif.joinEnds(joinDistance);
osg::notify(osg::NOTICE)<<"number of seperate lines after join = "<<tif._generatedLines.size()<<std::endl;
osg::Geode* geode = new osg::Geode;
geode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);