1
0
Fork 0
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:
AnyOldName3 2018-08-16 23:48:19 +01:00
parent 3b3721897d
commit 987306feb9

View file

@ -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)