mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 14:09:39 +00:00
Fix ConvexHull::extendTowardsNegativeZ
This commit is contained in:
parent
3b3721897d
commit
987306feb9
1 changed files with 90 additions and 68 deletions
|
@ -1831,42 +1831,58 @@ struct ConvexHull
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool shouldBeDeleted(osg::Vec3d vertex, std::set<osg::Vec3d> &extremeVertices)
|
Vertices findInternalEdges(osg::Vec3d mainVertex, Vertices connectedVertices)
|
||||||
{
|
{
|
||||||
// A vertex should be deleted if there is no route -Z-wards to an extreme vertex
|
Vertices internalEdgeVertices;
|
||||||
// equivalent to all -Z-wards vertices being deletable.
|
for (auto vertex : connectedVertices)
|
||||||
if (extremeVertices.find(vertex) != extremeVertices.end())
|
|
||||||
return false;
|
|
||||||
for (Edge edge : _edges)
|
|
||||||
{
|
{
|
||||||
osg::Vec3d otherEnd;
|
osg::Matrixd matrix;
|
||||||
if (edge.first == vertex)
|
osg::Vec3d dir = vertex - mainVertex;
|
||||||
otherEnd = edge.second;
|
matrix.makeLookAt(mainVertex, vertex, dir.z() == 0 ? osg::Vec3d(0, 0, 1) : osg::Vec3d(1, 0, 0));
|
||||||
else if (edge.second == vertex)
|
Vertices testVertices;
|
||||||
otherEnd = edge.first;
|
for (auto testVertex : connectedVertices)
|
||||||
else
|
{
|
||||||
continue;
|
if (vertex != testVertex)
|
||||||
|
testVertices.push_back(testVertex);
|
||||||
if (otherEnd.z() >= vertex.z())
|
}
|
||||||
continue;
|
std::vector<double> bearings;
|
||||||
|
for (auto testVertex : testVertices)
|
||||||
if (!shouldBeDeleted(otherEnd, extremeVertices))
|
{
|
||||||
return false;
|
osg::Vec3d transformedVertex = testVertex * matrix;
|
||||||
|
bearings.push_back(atan2(transformedVertex.y(), transformedVertex.x()));
|
||||||
|
}
|
||||||
|
std::sort(bearings.begin(), bearings.end());
|
||||||
|
bool keep = false;
|
||||||
|
for (auto itr = bearings.begin(); itr + 1 != bearings.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (*itr + osg::PI < *(itr + 1))
|
||||||
|
{
|
||||||
|
keep = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!keep && bearings[0] + osg::PI > bearings.back())
|
||||||
|
keep = true;
|
||||||
|
if (!keep)
|
||||||
|
internalEdgeVertices.push_back(vertex);
|
||||||
}
|
}
|
||||||
|
return internalEdgeVertices;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void extendTowardsNegativeZ()
|
void extendTowardsNegativeZ()
|
||||||
{
|
{
|
||||||
typedef std::set<osg::Vec3d> VertexSet;
|
typedef std::set<osg::Vec3d> VertexSet;
|
||||||
|
|
||||||
|
double lowestPoint = DBL_MAX;
|
||||||
|
|
||||||
// Collect the set of vertices
|
// Collect the set of vertices
|
||||||
VertexSet vertices;
|
VertexSet vertices;
|
||||||
for (Edge edge : _edges)
|
for (Edge edge : _edges)
|
||||||
{
|
{
|
||||||
vertices.insert(edge.first);
|
vertices.insert(edge.first);
|
||||||
vertices.insert(edge.second);
|
vertices.insert(edge.second);
|
||||||
|
lowestPoint = osg::minimum(lowestPoint, edge.first.z());
|
||||||
|
lowestPoint = osg::minimum(lowestPoint, edge.second.z());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertices.size() == 0)
|
if (vertices.size() == 0)
|
||||||
|
@ -1884,70 +1900,76 @@ struct ConvexHull
|
||||||
// Add edge loop to 'seal' the hull
|
// Add edge loop to 'seal' the hull
|
||||||
for (auto itr = extremeVertices.cbegin(); itr != extremeVertices.cend() - 1; ++itr)
|
for (auto itr = extremeVertices.cbegin(); itr != extremeVertices.cend() - 1; ++itr)
|
||||||
finalEdges.push_back(Edge(osg::Vec3d(itr->x(), itr->y(), -DBL_MAX), osg::Vec3d((itr + 1)->x(), (itr + 1)->y(), -DBL_MAX)));
|
finalEdges.push_back(Edge(osg::Vec3d(itr->x(), itr->y(), -DBL_MAX), osg::Vec3d((itr + 1)->x(), (itr + 1)->y(), -DBL_MAX)));
|
||||||
// The convex hull algorithm we are using places a point at both ends of the vector, so we don't need to add the last edge separately.
|
// The convex hull algorithm we are using sometimes places a point at both ends of the vector, so we don't always need to add the last edge separately.
|
||||||
// finalEdges.push_back(Edge(osg::Vec3d(extremeVertices.front().x(), extremeVertices.front().y(), -DBL_MAX), osg::Vec3d(extremeVertices.back().x(), extremeVertices.back().y(), -DBL_MAX)));
|
if (extremeVertices.front() != extremeVertices.back())
|
||||||
|
finalEdges.push_back(Edge(osg::Vec3d(extremeVertices.front().x(), extremeVertices.front().y(), -DBL_MAX), osg::Vec3d(extremeVertices.back().x(), extremeVertices.back().y(), -DBL_MAX)));
|
||||||
|
|
||||||
// Collect the first layer of unneeded vertices and remove the edges connecting them to the rest of the mesh
|
// Just in case using -DBL_MAX upsets some of the maths, we pretend we've only extended the volume by a little bit.
|
||||||
VertexSet deletedVertices;
|
lowestPoint -= 1.0;
|
||||||
for (auto edgeItr = _edges.begin(); edgeItr != _edges.end(); /* nothing */ )
|
// Remove internal edges connected to extreme vertices
|
||||||
|
for (auto vertex : extremeVertices)
|
||||||
{
|
{
|
||||||
if (extremeVerticesSet.find(edgeItr->first) != extremeVerticesSet.end())
|
Vertices connectedVertices;
|
||||||
|
for (Edge edge : _edges)
|
||||||
{
|
{
|
||||||
if (extremeVerticesSet.find(edgeItr->second) == extremeVerticesSet.end())
|
if (edge.first == vertex)
|
||||||
|
connectedVertices.push_back(edge.second);
|
||||||
|
else if (edge.second == vertex)
|
||||||
|
connectedVertices.push_back(edge.first);
|
||||||
|
}
|
||||||
|
connectedVertices.push_back(osg::Vec3d(vertex.x(), vertex.y(), lowestPoint));
|
||||||
|
|
||||||
|
Vertices unwantedEdgeEnds = findInternalEdges(vertex, connectedVertices);
|
||||||
|
for (auto edgeEnd : unwantedEdgeEnds)
|
||||||
|
{
|
||||||
|
for (auto itr = _edges.begin(); itr != _edges.end(); ++itr)
|
||||||
{
|
{
|
||||||
if (edgeItr->first.z() >= edgeItr->second.z())
|
if (*itr == Edge(vertex, edgeEnd))
|
||||||
{
|
{
|
||||||
// If we can travel along edges towards -Z and reach an extreme vertex, the current edge must be kept
|
_edges.erase(itr);
|
||||||
if (shouldBeDeleted(edgeItr->second, extremeVerticesSet))
|
break;
|
||||||
{
|
}
|
||||||
deletedVertices.insert(edgeItr->second);
|
else if (*itr == Edge(edgeEnd, vertex))
|
||||||
edgeItr = _edges.erase(edgeItr);
|
{
|
||||||
continue;
|
_edges.erase(itr);
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (extremeVerticesSet.find(edgeItr->second) != extremeVerticesSet.end())
|
|
||||||
{
|
|
||||||
if (edgeItr->second.z() >= edgeItr->first.z())
|
|
||||||
{
|
|
||||||
if (shouldBeDeleted(edgeItr->first, extremeVerticesSet))
|
|
||||||
{
|
|
||||||
deletedVertices.insert(edgeItr->first);
|
|
||||||
edgeItr = _edges.erase(edgeItr);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++edgeItr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all edges connected to removed vertices
|
// Gather connected vertices
|
||||||
bool modifiedSomething = true;
|
VertexSet unprocessedConnectedVertices(extremeVertices.begin(), extremeVertices.end());
|
||||||
while (modifiedSomething)
|
VertexSet connectedVertices;
|
||||||
|
while (unprocessedConnectedVertices.size() > 0)
|
||||||
{
|
{
|
||||||
modifiedSomething = false;
|
osg::Vec3d vertex = *unprocessedConnectedVertices.begin();
|
||||||
for (auto edgeItr = _edges.begin(); edgeItr != _edges.end(); /* nothing */)
|
unprocessedConnectedVertices.erase(unprocessedConnectedVertices.begin());
|
||||||
|
connectedVertices.insert(vertex);
|
||||||
|
for (Edge edge : _edges)
|
||||||
{
|
{
|
||||||
if (deletedVertices.find(edgeItr->first) != deletedVertices.end())
|
osg::Vec3d otherEnd;
|
||||||
{
|
if (edge.first == vertex)
|
||||||
deletedVertices.insert(edgeItr->second);
|
otherEnd = edge.second;
|
||||||
edgeItr = _edges.erase(edgeItr);
|
else if (edge.second == vertex)
|
||||||
modifiedSomething = true;
|
otherEnd - edge.first;
|
||||||
|
else
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
else if (deletedVertices.find(edgeItr->second) != deletedVertices.end())
|
if (connectedVertices.count(otherEnd))
|
||||||
{
|
|
||||||
deletedVertices.insert(edgeItr->first);
|
|
||||||
edgeItr = _edges.erase(edgeItr);
|
|
||||||
modifiedSomething = true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
++edgeItr;
|
unprocessedConnectedVertices.insert(otherEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_edges.splice(_edges.end(), finalEdges);
|
for (Edge edge : _edges)
|
||||||
|
{
|
||||||
|
if (connectedVertices.count(edge.first) || connectedVertices.count(edge.second))
|
||||||
|
finalEdges.push_back(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
_edges = finalEdges;
|
||||||
}
|
}
|
||||||
|
|
||||||
void transform(const osg::Matrixd& m)
|
void transform(const osg::Matrixd& m)
|
||||||
|
|
Loading…
Reference in a new issue