载入中...
搜索中...
未找到
TerrainPolygonMask.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5#include <utility>
6#include <vector>
9
10namespace eve::procgen {
11using namespace raster_detail;
12
14 struct Node {
15 double x, z;
17 };
18 std::vector<Node> nodes;
19};
20
21TerrainPolygonMask::TerrainPolygonMask() : impl_(std::make_unique<Impl>()) {}
24TerrainPolygonMask& TerrainPolygonMask::operator=(TerrainPolygonMask&&) noexcept = default;
25
26Result<int> TerrainPolygonMask::addNode(double worldX, double worldZ, float radius, float strength) {
27 if (!impl_ || !std::isfinite(worldX) || !std::isfinite(worldZ) || !std::isfinite(radius) || radius <= 0 ||
28 !std::isfinite(strength))
29 return invalid("terrain.polyMask: finite position/strength and positive radius required");
30 auto candidate = impl_->nodes;
31 candidate.push_back({worldX, worldZ, radius, strength});
32 impl_->nodes.swap(candidate);
33 return Result<int>::success(static_cast<int>(impl_->nodes.size()));
34}
35
37 if (impl_) impl_->nodes.clear();
38}
39
41 return impl_ ? static_cast<int>(impl_->nodes.size()) : 0;
42}
43
46 if (!impl_ || !validRaster(target) || !validRaster(brush) || target.getWidth() != grid.width ||
47 target.getHeight() != grid.height || !std::isfinite(grid.originX) || !std::isfinite(grid.originZ) ||
48 !std::isfinite(grid.spacingX) || !std::isfinite(grid.spacingZ) || grid.spacingX <= 0 || grid.spacingZ <= 0 ||
49 type < TerrainPolygonMaskType::Open || type > TerrainPolygonMaskType::Closed)
50 return invalid("terrain.polyMask.rasterize: finite compatible rasters, grid and topology required");
51
52 auto inside = [&](double x, double z) {
53 bool hit = false;
54 for (size_t i = 0, j = impl_->nodes.size() - 1; i < impl_->nodes.size(); j = i++) {
55 const auto& a = impl_->nodes[i];
56 const auto& b = impl_->nodes[j];
57 if ((a.z > z) != (b.z > z) && x < (b.x - a.x) * (z - a.z) / (b.z - a.z) + a.x) hit = !hit;
58 }
59 return hit;
60 };
61
62 std::vector<float> output(target.data().size(), 0.0F);
63 for (int z = 0; z < target.getHeight(); ++z)
64 for (int x = 0; x < target.getWidth(); ++x) {
65 const double wx = grid.originX + x * grid.spacingX;
66 const double wz = grid.originZ + z * grid.spacingZ;
67 double value = type == TerrainPolygonMaskType::Closed && impl_->nodes.size() > 2 && inside(wx, wz) ? 1 : 0;
68 for (const auto& node : impl_->nodes) {
69 const double u = (wx - (node.x - node.radius)) / (2 * node.radius);
70 const double v = (wz - (node.z - node.radius)) / (2 * node.radius);
71 if (u >= 0 && u <= 1 && v >= 0 && v <= 1) value += textureSample(brush, u, v);
72 value = std::min(value, 1.0);
73 if (value < 0.25) value = 0;
74 }
75 output[size_t(z) * target.getWidth() + x] = static_cast<float>(value);
76 }
77 return publish(target, std::move(output));
78}
79} // namespace eve::procgen
LogicalId target
double value
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
std::string output
float u
Definition Grass.cpp:233
float v
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float radius
bool hit
const RoadNode * node
std::vector< char > inside
float wz
float wx
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
In-memory terrain heightmap: a dense float grid (row-major, index = y * width + x) materialized from ...
Definition Heightmap.h:21
Own ordered Pcg-style PolyMask nodes and rasterize them into a caller-owned scalar grid....
int getNodeCount() const noexcept
Return the current node count.
TerrainPolygonMask()
Terrain polygon mask.
void clear()
Remove every owned node.
Result< int > rasterize(Heightmap &target, const Heightmap &brush, const TerrainSampleGrid &grid, TerrainPolygonMaskType type) const
Rasterize closed fill and ordered additive brush strokes atomically.
~TerrainPolygonMask()
Terrain polygon mask.
double textureSample(const Heightmap &map, double u, double v)
Texture sample.
Result< int > publish(Heightmap &target, std::vector< float > candidate)
Publish.
bool validRaster(const Heightmap &map)
Valid raster.
Result< int > invalid(std::string message)
Invalid.
TerrainPolygonMaskType
Pcg PolyMask topology: open strokes only, or closed flood fill plus strokes.
World X/Z positions of height sample centers, with positive spacing and dimensions.