From 58041ee123da479cc52a07537f59fc79bf0f5052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zieli=C5=84ski?= Date: Thu, 13 Mar 2025 19:45:28 +0100 Subject: [PATCH] Solution suggested by ChatGPT --- lib/rmg/RmgPath.cpp | 50 ++++++++++++++++++++++------- lib/rmg/RmgPath.h | 3 ++ lib/rmg/modificators/RoadPlacer.cpp | 4 ++- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/lib/rmg/RmgPath.cpp b/lib/rmg/RmgPath.cpp index 0d6dfa0e3..e18415dd0 100644 --- a/lib/rmg/RmgPath.cpp +++ b/lib/rmg/RmgPath.cpp @@ -190,6 +190,43 @@ const Area & Path::getPathArea() const return dPath; } +float Path::nonEuclideanCostFunction(const int3& src, const int3& dst) +{ + // Use non-euclidean metric + int dx = std::abs(src.x - dst.x); + int dy = std::abs(src.y - dst.y); + // int dx = src.x - dst.x; + // int dy = src.y - dst.y; + return std::sqrt(dx * dx + dy * dy) - + 500 * std::sin(dx * dy / 20); +} + +float Path::curvedCost(const int3& src, const int3& dst, const int3& center) +{ + float R = 30.0f; // radius of the zone + float W = 10.0f;// width of the transition area + float A = 0.7f; // sine bias + + // Euclidean step distance: + float dx = dst.x - src.x; + float dy = dst.y - src.y; + float d = std::sqrt(dx*dx + dy*dy); + + // Distance from dst to the zone center: + float rx = dst.x - center.x; + float ry = dst.y - center.y; + float r = std::sqrt(rx*rx + ry*ry); + + // Compute normalized offset inside the zone: + // (R - W) is the inner edge, R is the outer edge. + float t = std::clamp((r - (R - W)) / W, 0.0f, 1.0f); + + // Use sine bias: lowest cost in the middle (t=0.5), higher near edges. + float bias = 1.0f + A * std::sin(M_PI * t); + + return d * bias; +} + Path::MoveCostFunction Path::createCurvedCostFunction(const Area & border) { // Capture by value to ensure the Area object persists @@ -198,17 +235,8 @@ Path::MoveCostFunction Path::createCurvedCostFunction(const Area & border) // Route main roads far from border //float ret = dst.dist2d(src); - auto costFunction = [border](const int3& src, const int3& dst) -> float - { - // Use non-euclidean metric - int dx = std::abs(src.x - dst.x); - int dy = std::abs(src.y - dst.y); - // int dx = src.x - dst.x; - // int dy = src.y - dst.y; - return std::sqrt(dx * dx + dy * dy) - - 500 * std::sin(dx * dy / 20); - }; - float ret = costFunction(src, dst); + //float ret = nonEuclideanCostFunction(src, dst); + float ret = curvedCost(src, dst, border.getCenterOfMass()); float dist = border.distanceSqr(dst); if(dist > 1.0f) diff --git a/lib/rmg/RmgPath.h b/lib/rmg/RmgPath.h index 7707e1abb..5da26eb59 100644 --- a/lib/rmg/RmgPath.h +++ b/lib/rmg/RmgPath.h @@ -18,6 +18,7 @@ VCMI_LIB_NAMESPACE_BEGIN namespace rmg { + class Path { public: @@ -43,6 +44,8 @@ public: const Area & getPathArea() const; static Path invalid(); + static float nonEuclideanCostFunction(const int3& src, const int3& dst); + static float curvedCost(const int3& src, const int3& dst, const int3& center); static MoveCostFunction createCurvedCostFunction(const Area & border); private: diff --git a/lib/rmg/modificators/RoadPlacer.cpp b/lib/rmg/modificators/RoadPlacer.cpp index 53eb8215f..fc73bab1d 100644 --- a/lib/rmg/modificators/RoadPlacer.cpp +++ b/lib/rmg/modificators/RoadPlacer.cpp @@ -93,7 +93,9 @@ bool RoadPlacer::createRoad(const int3 & destination) } } - float ret = dst.dist2d(src); + //float ret = dst.dist2d(src); + //float ret = rmg::Path::nonEuclideanCostFunction(src, dst); + float ret = rmg::Path::curvedCost(src, dst, border.getCenterOfMass()); if (visitableTiles.contains(src) || visitableTiles.contains(dst)) {