1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-09-16 09:26:28 +02:00

Merge pull request #3924 from vcmi/fix_road_routing

Route roads away from zone borders
This commit is contained in:
Ivan Savenko
2024-05-12 16:02:38 +03:00
committed by GitHub
4 changed files with 55 additions and 38 deletions

View File

@@ -254,6 +254,11 @@ bool Area::overlap(const Area & area) const
return overlap(area.getTilesVector()); return overlap(area.getTilesVector());
} }
int Area::distance(const int3 & tile) const
{
return nearest(tile).dist2d(tile);
}
int Area::distanceSqr(const int3 & tile) const int Area::distanceSqr(const int3 & tile) const
{ {
return nearest(tile).dist2dSQ(tile); return nearest(tile).dist2dSQ(tile);

View File

@@ -51,6 +51,7 @@ namespace rmg
bool contains(const Area & area) const; bool contains(const Area & area) const;
bool overlap(const Area & area) const; bool overlap(const Area & area) const;
bool overlap(const std::vector<int3> & tiles) const; bool overlap(const std::vector<int3> & tiles) const;
int distance(const int3 & tile) const;
int distanceSqr(const int3 & tile) const; int distanceSqr(const int3 & tile) const;
int distanceSqr(const Area & area) const; int distanceSqr(const Area & area) const;
int3 nearest(const int3 & tile) const; int3 nearest(const int3 & tile) const;

View File

@@ -64,16 +64,16 @@ const rmg::Area & RoadPlacer::getRoads() const
return roads; return roads;
} }
bool RoadPlacer::createRoad(const int3 & dst) bool RoadPlacer::createRoad(const int3 & destination)
{ {
auto searchArea = zone.areaPossible() + zone.freePaths() + areaRoads + roads; auto searchArea = zone.areaPossible() + zone.freePaths() + areaRoads + roads;
rmg::Area border(zone.area()->getBorder());
rmg::Path path(searchArea); rmg::Path path(searchArea);
path.connect(roads); path.connect(roads);
const float VISITABLE_PENALTY = 1.33f; auto simpleRoutig = [this, &border](const int3& src, const int3& dst)
auto simpleRoutig = [this, VISITABLE_PENALTY](const int3& src, const int3& dst)
{ {
if(areaIsolated().contains(dst)) if(areaIsolated().contains(dst))
{ {
@@ -81,52 +81,28 @@ bool RoadPlacer::createRoad(const int3 & dst)
} }
else else
{ {
float weight = dst.dist2dSQ(src); float ret = dst.dist2d(src);
auto ret = weight * weight;
if (visitableTiles.contains(src) || visitableTiles.contains(dst)) if (visitableTiles.contains(src) || visitableTiles.contains(dst))
{ {
ret *= VISITABLE_PENALTY; ret *= VISITABLE_PENALTY;
} }
float dist = border.distance(dst);
if(dist > 1)
{
ret /= dist;
}
return ret; return ret;
} }
}; };
auto res = path.search(dst, true, simpleRoutig); auto res = path.search(destination, true, simpleRoutig);
if(!res.valid()) if(!res.valid())
{ {
auto desperateRoutig = [this, VISITABLE_PENALTY](const int3& src, const int3& dst) -> float res = createRoadDesperate(path, destination);
if (!res.valid())
{ {
//Do not allow connections straight up through object not visitable from top logGlobal->warn("Failed to create road to node %s", destination.toString());
if(std::abs((src - dst).y) == 1)
{
if(areaIsolated().contains(dst) || areaIsolated().contains(src))
{
return 1e12;
}
}
else
{
if(areaIsolated().contains(dst))
{
return 1e6;
}
}
float weight = dst.dist2dSQ(src);
auto ret = weight * weight;
if (visitableTiles.contains(src) || visitableTiles.contains(dst))
{
ret *= VISITABLE_PENALTY;
}
return ret;
};
res = path.search(dst, false, desperateRoutig);
if(!res.valid())
{
logGlobal->warn("Failed to create road to node %s", dst.toString());
return false; return false;
} }
} }
@@ -135,6 +111,38 @@ bool RoadPlacer::createRoad(const int3 & dst)
} }
rmg::Path RoadPlacer::createRoadDesperate(rmg::Path & path, const int3 & destination)
{
auto desperateRoutig = [this](const int3& src, const int3& dst) -> float
{
//Do not allow connections straight up through object not visitable from top
if(std::abs((src - dst).y) == 1)
{
if(areaIsolated().contains(dst) || areaIsolated().contains(src))
{
return 1e12;
}
}
else
{
if(areaIsolated().contains(dst))
{
return 1e6;
}
}
float weight = dst.dist2dSQ(src);
auto ret = weight * weight; // Still prefer straight paths
if (visitableTiles.contains(src) || visitableTiles.contains(dst))
{
ret *= VISITABLE_PENALTY;
}
return ret;
};
return path.search(destination, false, desperateRoutig);
}
void RoadPlacer::drawRoads(bool secondary) void RoadPlacer::drawRoads(bool secondary)
{ {
//Do not draw roads on underground rock or water //Do not draw roads on underground rock or water

View File

@@ -13,6 +13,8 @@
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
const float VISITABLE_PENALTY = 1.33f;
class RoadPlacer: public Modificator class RoadPlacer: public Modificator
{ {
public: public:
@@ -34,6 +36,7 @@ public:
protected: protected:
bool createRoad(const int3 & dst); bool createRoad(const int3 & dst);
rmg::Path createRoadDesperate(rmg::Path & path, const int3 & destination);
void drawRoads(bool secondary = false); //actually updates tiles void drawRoads(bool secondary = false); //actually updates tiles
protected: protected: