mirror of https://github.com/OpenMW/openmw.git
Support terrain sample size greater than cell size
parent
2a49919b53
commit
8e7fe44514
@ -0,0 +1,366 @@
|
||||
#include <components/esmterrain/gridsampling.hpp>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace ESMTerrain
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using namespace testing;
|
||||
|
||||
struct Sample
|
||||
{
|
||||
std::size_t mCellX = 0;
|
||||
std::size_t mCellY = 0;
|
||||
std::size_t mLocalX = 0;
|
||||
std::size_t mLocalY = 0;
|
||||
std::size_t mVertexX = 0;
|
||||
std::size_t mVertexY = 0;
|
||||
};
|
||||
|
||||
auto tie(const Sample& v)
|
||||
{
|
||||
return std::tie(v.mCellX, v.mCellY, v.mLocalX, v.mLocalY, v.mVertexX, v.mVertexY);
|
||||
}
|
||||
|
||||
bool operator==(const Sample& l, const Sample& r)
|
||||
{
|
||||
return tie(l) == tie(r);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Sample& v)
|
||||
{
|
||||
return stream << "Sample{.mCellX = " << v.mCellX << ", .mCellY = " << v.mCellY
|
||||
<< ", .mLocalX = " << v.mLocalX << ", .mLocalY = " << v.mLocalY
|
||||
<< ", .mVertexX = " << v.mVertexX << ", .mVertexY = " << v.mVertexY << "}";
|
||||
}
|
||||
|
||||
struct Collect
|
||||
{
|
||||
std::vector<Sample>& mSamples;
|
||||
|
||||
void operator()(std::size_t cellX, std::size_t cellY, std::size_t localX, std::size_t localY,
|
||||
std::size_t vertexX, std::size_t vertexY)
|
||||
{
|
||||
mSamples.push_back(Sample{
|
||||
.mCellX = cellX,
|
||||
.mCellY = cellY,
|
||||
.mLocalX = localX,
|
||||
.mLocalY = localY,
|
||||
.mVertexX = vertexX,
|
||||
.mVertexY = vertexY,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportCellSizeLessThanTwo)
|
||||
{
|
||||
const std::size_t cellSize = 2;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, 0, 0, 0, 0, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportCellSizeMinusOneNotPowerOfTwo)
|
||||
{
|
||||
const std::size_t cellSize = 4;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, 0, 0, 0, 0, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportZeroSampleSize)
|
||||
{
|
||||
const std::size_t cellSize = 1;
|
||||
const std::size_t sampleSize = 0;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, sampleSize, 0, 0, 0, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportSampleSizeNotPowerOfTwo)
|
||||
{
|
||||
const std::size_t cellSize = 1;
|
||||
const std::size_t sampleSize = 3;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, sampleSize, 0, 0, 0, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportCountLessThanTwo)
|
||||
{
|
||||
const std::size_t cellSize = 1;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t distance = 2;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, sampleSize, 0, 0, distance, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportCountMinusOneNotPowerOfTwo)
|
||||
{
|
||||
const std::size_t cellSize = 1;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t distance = 4;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, sampleSize, 0, 0, distance, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, sampleSizeOneShouldProduceNumberOfSamplesEqualToCellSize)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 3;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, countShouldLimitScope)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 2;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginXAndCountShouldLimitScope)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 1;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 2;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginYAndCountShouldLimitScope)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 1;
|
||||
const std::size_t distance = 2;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 1, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginAndCountShouldLimitScope)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 1;
|
||||
const std::size_t beginY = 1;
|
||||
const std::size_t distance = 2;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginAndCountShouldLimitScopeInTheMiddleOfCell)
|
||||
{
|
||||
const std::size_t cellSize = 5;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 1;
|
||||
const std::size_t beginY = 1;
|
||||
const std::size_t distance = 2;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginXWithCountLessThanCellSizeShouldLimitScopeAcrossCellBorder)
|
||||
{
|
||||
const std::size_t cellSize = 5;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 3;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 3;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 3, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 4, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 3, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 4, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 3, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 4, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginXWithCountEqualToCellSizeShouldLimitScopeAcrossCellBorder)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 1;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 3;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginXWithCountGreaterThanCellSizeShouldLimitScopeAcrossCellBorder)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 1;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 5;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 3, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 3, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 3, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 2, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 4, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 2, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 4, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 2, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 4, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 3 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 3 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 1, .mLocalY = 2, .mVertexX = 0, .mVertexY = 4 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 4 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 1, .mLocalY = 1, .mVertexX = 2, .mVertexY = 3 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 2, .mLocalY = 1, .mVertexX = 3, .mVertexY = 3 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 1, .mLocalY = 2, .mVertexX = 2, .mVertexY = 4 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 3, .mVertexY = 4 },
|
||||
Sample{ .mCellX = 2, .mCellY = 1, .mLocalX = 1, .mLocalY = 1, .mVertexX = 4, .mVertexY = 3 },
|
||||
Sample{ .mCellX = 2, .mCellY = 1, .mLocalX = 1, .mLocalY = 2, .mVertexX = 4, .mVertexY = 4 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, sampleSizeGreaterThanOneShouldSkipPoints)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 2;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 3;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, shouldGroupByCell)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 2;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 5;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, sampleSizeGreaterThanCellSizeShouldPickSinglePointPerCell)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 4;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 9;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 3, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 3, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 3, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 3, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 3, .mCellY = 3, .mLocalX = 2, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, sampleSizeGreaterThan2CellSizeShouldSkipCells)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 8;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 9;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 3, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 3, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 3, .mCellY = 3, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
#ifndef OPENMW_COMPONENTS_ESMTERRAIN_GRIDSAMPLING_H
|
||||
#define OPENMW_COMPONENTS_ESMTERRAIN_GRIDSAMPLING_H
|
||||
|
||||
#include <components/misc/mathutil.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace ESMTerrain
|
||||
{
|
||||
inline std::pair<std::size_t, std::size_t> toCellAndLocal(
|
||||
std::size_t begin, std::size_t global, std::size_t cellSize)
|
||||
{
|
||||
std::size_t cell = global / (cellSize - 1);
|
||||
std::size_t local = global & (cellSize - 2);
|
||||
if (global != begin && local == 0)
|
||||
{
|
||||
--cell;
|
||||
local = cellSize - 1;
|
||||
}
|
||||
return { cell, local };
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void sampleGrid(
|
||||
std::size_t sampleSize, std::size_t beginX, std::size_t beginY, std::size_t endX, std::size_t endY, F&& f)
|
||||
{
|
||||
std::size_t vertY = 0;
|
||||
for (std::size_t y = beginY; y < endY; y += sampleSize)
|
||||
{
|
||||
std::size_t vertX = 0;
|
||||
for (std::size_t x = beginX; x < endX; x += sampleSize)
|
||||
f(x, y, vertX++, vertY);
|
||||
++vertY;
|
||||
}
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void sampleCellGridSimple(std::size_t cellSize, std::size_t sampleSize, std::size_t beginX, std::size_t beginY,
|
||||
std::size_t endX, std::size_t endY, F&& f)
|
||||
{
|
||||
assert(cellSize > 1);
|
||||
assert(Misc::isPowerOfTwo(cellSize - 1));
|
||||
assert(sampleSize != 0);
|
||||
|
||||
sampleGrid(sampleSize, beginX, beginY, endX, endY,
|
||||
[&](std::size_t globalX, std::size_t globalY, std::size_t vertX, std::size_t vertY) {
|
||||
const auto [cellX, x] = toCellAndLocal(beginX, globalX, cellSize);
|
||||
const auto [cellY, y] = toCellAndLocal(beginY, globalY, cellSize);
|
||||
f(cellX, cellY, x, y, vertX, vertY);
|
||||
});
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void sampleCellGrid(std::size_t cellSize, std::size_t sampleSize, std::size_t beginX, std::size_t beginY,
|
||||
std::size_t distance, F&& f)
|
||||
{
|
||||
if (cellSize < 2 || !Misc::isPowerOfTwo(cellSize - 1))
|
||||
throw std::invalid_argument("Invalid cell size for cell grid sampling: " + std::to_string(cellSize));
|
||||
|
||||
if (sampleSize == 0 || !Misc::isPowerOfTwo(sampleSize))
|
||||
throw std::invalid_argument("Invalid sample size for cell grid sampling: " + std::to_string(sampleSize));
|
||||
|
||||
if (distance < 2 || !Misc::isPowerOfTwo(distance - 1))
|
||||
throw std::invalid_argument("Invalid count for cell grid sampling: " + std::to_string(distance));
|
||||
|
||||
const std::size_t endX = beginX + distance;
|
||||
const std::size_t endY = beginY + distance;
|
||||
|
||||
if (distance < cellSize || sampleSize > cellSize - 1)
|
||||
return sampleCellGridSimple(cellSize, sampleSize, beginX, beginY, endX, endY, f);
|
||||
|
||||
const std::size_t beginCellX = beginX / (cellSize - 1);
|
||||
const std::size_t beginCellY = beginY / (cellSize - 1);
|
||||
const std::size_t endCellX = endX / (cellSize - 1);
|
||||
const std::size_t endCellY = endY / (cellSize - 1);
|
||||
|
||||
std::size_t baseVertY = 0;
|
||||
|
||||
for (std::size_t cellY = beginCellY; cellY < endCellY; ++cellY)
|
||||
{
|
||||
const std::size_t offsetY = cellY * (cellSize - 1);
|
||||
const std::size_t globalBeginY = offsetY <= beginY ? beginY : offsetY + sampleSize;
|
||||
const std::size_t globalEndY = endY <= offsetY + cellSize ? endY : offsetY + cellSize;
|
||||
|
||||
assert(globalBeginY < globalEndY);
|
||||
|
||||
std::size_t baseVertX = 0;
|
||||
std::size_t vertY = baseVertY;
|
||||
|
||||
for (std::size_t cellX = beginCellX; cellX < endCellX; ++cellX)
|
||||
{
|
||||
const std::size_t offsetX = cellX * (cellSize - 1);
|
||||
const std::size_t globalBeginX = offsetX <= beginX ? beginX : offsetX + sampleSize;
|
||||
const std::size_t globalEndX = endX <= offsetX + cellSize ? endX : offsetX + cellSize;
|
||||
|
||||
assert(globalBeginX < globalEndX);
|
||||
|
||||
vertY = baseVertY;
|
||||
std::size_t vertX = baseVertX;
|
||||
|
||||
sampleGrid(sampleSize, globalBeginX, globalBeginY, globalEndX, globalEndY,
|
||||
[&](std::size_t globalX, std::size_t globalY, std::size_t localVertX, std::size_t localVertY) {
|
||||
vertX = baseVertX + localVertX;
|
||||
vertY = baseVertY + localVertY;
|
||||
f(cellX, cellY, globalX - offsetX, globalY - offsetY, vertX, vertY);
|
||||
});
|
||||
|
||||
baseVertX = vertX + 1;
|
||||
}
|
||||
|
||||
baseVertY = vertY + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue