summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--game/geoData.cpp43
-rw-r--r--game/geoData.h5
-rw-r--r--test/test-geoData.cpp11
3 files changed, 37 insertions, 22 deletions
diff --git a/game/geoData.cpp b/game/geoData.cpp
index cd0be29..f43e231 100644
--- a/game/geoData.cpp
+++ b/game/geoData.cpp
@@ -66,7 +66,7 @@ GeoData::loadFromAsciiGrid(const std::filesystem::path & input)
});
}
}
- mesh.update_vertex_normals_only();
+ mesh.updateAllVertexNormals();
return mesh;
};
@@ -105,7 +105,7 @@ GeoData::createFlat(GlobalPosition2D lower, GlobalPosition2D upper, GlobalDistan
}
}
- mesh.update_vertex_normals_only();
+ mesh.updateAllVertexNormals();
return mesh;
}
@@ -377,23 +377,28 @@ GeoData::centre(const HalfedgeHandle heh) const
}
void
-GeoData::update_vertex_normals_only()
+GeoData::updateAllVertexNormals()
{
- update_vertex_normals_only(vertices_sbegin());
+ updateAllVertexNormals(vertices());
}
+template<std::ranges::range R>
void
-GeoData::update_vertex_normals_only(VertexIter start)
+GeoData::updateAllVertexNormals(const R & range)
{
- std::for_each(start, vertices_end(), [this](const auto vh) {
- if (normal(vh) == Normal3D {}) {
- Normal3D n;
- calc_vertex_normal_correct(vh, n);
- this->set_normal(vh, glm::normalize(n));
- }
+ std::ranges::for_each(range, [this](const auto vertex) {
+ updateVertexNormal(vertex);
});
}
+void
+GeoData::updateVertexNormal(VertexHandle vertex)
+{
+ Normal3D n;
+ calc_vertex_normal_correct(vertex, n);
+ set_normal(vertex, glm::normalize(n));
+}
+
bool
GeoData::triangleOverlapsTriangle(const Triangle<2> & a, const Triangle<2> & b)
{
@@ -420,14 +425,18 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const
lowerExtent.z = std::min(upperExtent.z, stripMinMax.min.z);
upperExtent.z = std::max(upperExtent.z, stripMinMax.max.z);
- const auto initialVertexCount = static_cast<unsigned int>(n_vertices());
-
const auto vertexDistFrom = [this](GlobalPosition2D p) {
return [p, this](const VertexHandle v) {
return std::make_pair(v, glm::length(difference(this->point(v).xy(), p)));
};
};
+ std::set<VertexHandle> newOrChangedVerts;
+ auto addVertexForNormalUpdate = [this, &newOrChangedVerts](const VertexHandle vertex) {
+ newOrChangedVerts.emplace(vertex);
+ std::ranges::copy(vv_range(vertex), std::inserter(newOrChangedVerts, newOrChangedVerts.end()));
+ };
+
// New vertices for each vertex in triangleStrip
std::vector<VertexHandle> newVerts;
newVerts.reserve(newVerts.size());
@@ -443,6 +452,7 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const
}
return split(face, tsPoint);
});
+ std::ranges::for_each(newVerts, addVertexForNormalUpdate);
// Create temporary triangles from triangleStrip
std::vector<Triangle<3>> strip;
@@ -464,7 +474,7 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const
// Cut along each edge of triangleStrip AB, AC, BC, BD, CD, CE etc
std::map<VertexHandle, const Triangle<3> *> boundaryTriangles;
- auto doBoundaryPart = [this, &boundaryTriangles, &newVerts, &vertexDistFrom, &opts](
+ auto doBoundaryPart = [this, &boundaryTriangles, &newVerts, &vertexDistFrom, &opts, &addVertexForNormalUpdate](
VertexHandle start, VertexHandle end, const Triangle<3> & triangle) {
boundaryTriangles.emplace(start, &triangle);
const auto endPoint = point(end);
@@ -491,6 +501,7 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const
else {
start = split(edge_handle(next), positionOnTriangle(*intersection, triangle));
}
+ addVertexForNormalUpdate(start);
boundaryTriangles.emplace(start, &triangle);
return true;
}
@@ -530,6 +541,7 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const
}
if (toTriangle) { // point within the new strip, adjust vertically by triangle
toPoint.z = positionOnTriangle(toPoint, *toTriangle).z;
+ addVertexForNormalUpdate(toVertex);
todoOutHalfEdges(toVertex);
}
else if (!toTriangle) { // point without the new strip, adjust vertically by limit
@@ -537,6 +549,7 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const
const auto newHeight = std::clamp(toPoint.z, fromPoint.z - maxOffset, fromPoint.z + maxOffset);
if (newHeight != toPoint.z) {
toPoint.z = newHeight;
+ addVertexForNormalUpdate(toVertex);
std::copy_if(voh_begin(toVertex), voh_end(toVertex), std::inserter(todo, todo.end()),
[this, &boundaryTriangles](const auto & heh) {
return !boundaryTriangles.contains(to_vertex_handle(heh));
@@ -559,5 +572,5 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const
};
surfaceStripWalk(surfaceStripWalk, findPoint(strip.front().centroid()));
- update_vertex_normals_only(VertexIter {*this, vertex_handle(initialVertexCount), true});
+ updateAllVertexNormals(newOrChangedVerts);
}
diff --git a/game/geoData.h b/game/geoData.h
index c28dd14..71ec85f 100644
--- a/game/geoData.h
+++ b/game/geoData.h
@@ -200,8 +200,9 @@ protected:
[[nodiscard]] RelativeDistance length(const HalfedgeHandle) const;
[[nodiscard]] GlobalPosition3D centre(const HalfedgeHandle) const;
- void update_vertex_normals_only();
- void update_vertex_normals_only(VertexIter start);
+ void updateAllVertexNormals();
+ template<std::ranges::range R> void updateAllVertexNormals(const R &);
+ void updateVertexNormal(VertexHandle);
private:
GlobalPosition3D lowerExtent {}, upperExtent {};
diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp
index 17e1741..2f3d215 100644
--- a/test/test-geoData.cpp
+++ b/test/test-geoData.cpp
@@ -31,11 +31,9 @@ BOOST_AUTO_TEST_CASE(loadSuccess)
BOOST_AUTO_TEST_CASE(normalsAllPointUp)
{
- BOOST_CHECK_EQUAL(std::count_if(vertices_begin(), vertices_end(),
- [this](auto && vh) {
- return normal(vh).z > 0;
- }),
- n_vertices());
+ BOOST_CHECK(std::ranges::all_of(vertices(), [this](auto && vertex) {
+ return normal(vertex).z > 0;
+ }));
}
BOOST_AUTO_TEST_CASE(trianglesContainsPoints)
@@ -233,6 +231,9 @@ BOOST_DATA_TEST_CASE(deform, loadFixtureJson<DeformTerrainData>("geoData/deform/
surface.colorBias = RGB {0, 0, 1};
auto gd = std::make_shared<GeoData>(GeoData::createFlat({0, 0}, {1000000, 1000000}, 100));
BOOST_CHECK_NO_THROW(gd->setHeights(points, {.surface = surface}));
+ BOOST_CHECK(std::ranges::all_of(gd->vertices(), [&gd](auto && vertex) {
+ return gd->normal(vertex).z > 0;
+ }));
ApplicationBase ab;
TestMainWindow tmw;