mirror of
https://github.com/vcmi/vcmi.git
synced 2026-06-19 22:57:37 +02:00
Bend path close to Bezier curve
This commit is contained in:
+18
-2
@@ -24,9 +24,25 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void replaceWithCurvedPath(rmg::Path & path, const Zone & zone, const int3 & src, bool onlyStraight /* = true */)
|
||||
void replaceWithCurvedPath(rmg::Path & path, Zone & zone, const int3 & src, bool onlyStraight /* = true */)
|
||||
{
|
||||
auto costFunction = rmg::Path::createCurvedCostFunction(zone.area()->getBorder());
|
||||
// Get random control points from within the zone
|
||||
auto & rng = zone.getRand();
|
||||
const auto & tiles = zone.area()->getTilesVector();
|
||||
|
||||
if(tiles.size() < 2)
|
||||
{
|
||||
logGlobal->warn("Zone too small for curved path");
|
||||
return;
|
||||
}
|
||||
|
||||
// Pick two random control points (Q1, Q2) from zone tiles
|
||||
int3 control1 = tiles[rng.nextInt(0, static_cast<int>(tiles.size()) - 1)];
|
||||
int3 control2 = tiles[rng.nextInt(0, static_cast<int>(tiles.size()) - 1)];
|
||||
|
||||
// Create Bezier cost function: Q0=start, Q1=control1, Q2=control2, Q3=src
|
||||
auto costFunction = rmg::Path::createBezierCostFunction(src, control1, control2, zone.getPos());
|
||||
|
||||
auto pathArea = zone.areaForRoads();
|
||||
rmg::Path curvedPath(pathArea);
|
||||
curvedPath.connect(zone.freePaths().get());
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void replaceWithCurvedPath(rmg::Path & path, const Zone & zone, const int3 & src, bool onlyStraight = true);
|
||||
void replaceWithCurvedPath(rmg::Path & path, Zone & zone, const int3 & src, bool onlyStraight = true);
|
||||
|
||||
rmg::Tileset collectDistantTiles(const Zone & zone, int distance);
|
||||
|
||||
|
||||
@@ -229,4 +229,55 @@ Path::MoveCostFunction Path::createCurvedCostFunction(const Area & border)
|
||||
};
|
||||
}
|
||||
|
||||
float Path::distanceToCubicBezier(const int3 & point, const int3 & p0, const int3 & p1, const int3 & p2, const int3 & p3)
|
||||
{
|
||||
// Approximate distance to cubic Bezier curve by sampling
|
||||
// B(t) = (1-t)³P0 + 3(1-t)²tP1 + 3(1-t)t²P2 + t³P3
|
||||
constexpr int SAMPLES = 20;
|
||||
float minDistSq = std::numeric_limits<float>::max();
|
||||
|
||||
for(int i = 0; i <= SAMPLES; ++i)
|
||||
{
|
||||
float t = static_cast<float>(i) / SAMPLES;
|
||||
float oneMinusT = 1.0f - t;
|
||||
float oneMinusT2 = oneMinusT * oneMinusT;
|
||||
float oneMinusT3 = oneMinusT2 * oneMinusT;
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
|
||||
// Cubic Bezier formula
|
||||
float bx = oneMinusT3 * p0.x + 3.0f * oneMinusT2 * t * p1.x + 3.0f * oneMinusT * t2 * p2.x + t3 * p3.x;
|
||||
float by = oneMinusT3 * p0.y + 3.0f * oneMinusT2 * t * p1.y + 3.0f * oneMinusT * t2 * p2.y + t3 * p3.y;
|
||||
|
||||
float dx = point.x - bx;
|
||||
float dy = point.y - by;
|
||||
float distSq = dx * dx + dy * dy;
|
||||
|
||||
if(distSq < minDistSq)
|
||||
minDistSq = distSq;
|
||||
}
|
||||
|
||||
//return std::sqrt(minDistSq);
|
||||
return minDistSq;
|
||||
}
|
||||
|
||||
Path::MoveCostFunction Path::createBezierCostFunction(const int3 & p0, const int3 & p1, const int3 & p2, const int3 & p3)
|
||||
{
|
||||
// p0: start point (Q0)
|
||||
// p1: first control point (Q1) - any tile in zone
|
||||
// p2: second control point (Q2) - any tile in zone
|
||||
// p3: end point (Q3)
|
||||
return [p0, p1, p2, p3](const int3 & src, const int3 & dst) -> float
|
||||
{
|
||||
|
||||
// Distance from destination tile to the Bezier curve
|
||||
float distToCurve = distanceToCubicBezier(dst, p0, p1, p2, p3);
|
||||
|
||||
// Penalize tiles far from the curve
|
||||
// Square for stronger effect
|
||||
return distToCurve * distToCurve;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
@@ -45,7 +45,9 @@ public:
|
||||
|
||||
static Path invalid();
|
||||
static MoveCostFunction createCurvedCostFunction(const Area & border);
|
||||
static MoveCostFunction createBezierCostFunction(const int3 & p0, const int3 & p1, const int3 & p2, const int3 & p3);
|
||||
static float nonEuclideanCostFunction(const int3& src, const int3& dst, const int3& center);
|
||||
static float distanceToCubicBezier(const int3 & point, const int3 & p0, const int3 & p1, const int3 & p2, const int3 & p3);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user