Check for overlaps and intersections of planned bridges and tunnels
This commit is contained in:

committed by
Jonathan G Rennison

parent
1899b1877d
commit
a1df69be87
84
src/road.cpp
84
src/road.cpp
@@ -249,7 +249,6 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||
|
||||
static std::vector<TileIndex> _town_centers;
|
||||
static std::vector<TileIndex> _towns_visited_along_the_way;
|
||||
static bool _has_tunnel_in_path;
|
||||
static RoadType _public_road_type;
|
||||
static const uint _public_road_hash_size = 8U; ///< The number of bits the hash for river finding should have.
|
||||
|
||||
@@ -527,6 +526,79 @@ static bool IsValidNeighbourOfPreviousTile(const TileIndex tile, const TileIndex
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool AreParallelOverlapping(const Point &start_a, const Point &end_a, const Point &start_b, const Point &end_b)
|
||||
{
|
||||
// Check parallel overlaps.
|
||||
if (start_a.x == end_a.x && start_b.x == end_b.x && start_a.x == start_b.x) {
|
||||
if ((start_a.y <= start_b.y && end_a.y >= start_b.y) || (start_a.y >= start_b.y && end_a.y <= start_b.y) ||
|
||||
(start_a.y <= end_b.y && end_a.y >= end_b.y) || (start_a.y >= end_b.y && end_a.y <= end_b.y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (start_a.y == end_a.y && start_b.y == end_b.y && start_a.y == start_b.y) {
|
||||
if ((start_a.x <= start_b.x && end_a.x >= start_b.x) || (start_a.x >= start_b.x && end_a.x <= start_b.x) ||
|
||||
(start_a.x <= end_b.x && end_a.x >= end_b.x) || (start_a.x >= end_b.x && end_a.x <= end_b.x)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool AreIntersecting(const Point &start_a, const Point &end_a, const Point &start_b, const Point &end_b)
|
||||
{
|
||||
if (start_a.x == end_a.x && start_b.y == end_b.y) {
|
||||
if ((start_b.x <= start_a.x && end_b.x >= start_a.x) || (start_b.x >= start_a.x && end_b.x <= start_a.x)) {
|
||||
if ((start_a.y <= start_b.y && end_a.y >= start_b.y) || (start_a.y >= start_b.y && end_a.y <= start_b.y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (start_a.y == end_a.y && start_b.x == end_b.x) {
|
||||
if ((start_b.y <= start_a.y && end_b.y >= start_a.y) || (start_b.y >= start_a.y && end_b.y <= start_a.y)) {
|
||||
if ((start_a.x <= start_b.x && end_a.x >= start_b.x) || (start_a.x >= start_b.x && end_a.x <= start_b.x)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsBlockedByPreviousBridgeOrTunnel(OpenListNode *current, TileIndex start_tile, TileIndex end_tile)
|
||||
{
|
||||
PathNode* start = ¤t->path;
|
||||
PathNode* end = current->path.parent;
|
||||
|
||||
while (end != nullptr) {
|
||||
Point start_a {};
|
||||
start_a.x = TileX(start->node.tile);
|
||||
start_a.y = TileY(start->node.tile);
|
||||
Point end_a {};
|
||||
end_a.x = TileX(end->node.tile);
|
||||
end_a.y = TileY(end->node.tile);
|
||||
|
||||
Point start_b {};
|
||||
start_b.x = TileX(start_tile);
|
||||
start_b.y = TileY(start_tile);
|
||||
Point end_b {};
|
||||
end_b.x = TileX(end_tile);
|
||||
end_b.y = TileY(end_tile);
|
||||
|
||||
if (!AreTilesAdjacent(start->node.tile, end->node.tile) &&
|
||||
(AreIntersecting(start_a, end_a, start_b, end_b) || AreParallelOverlapping(start_a, end_a, start_b, end_b))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
start = end;
|
||||
end = start->parent;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** AyStar callback for getting the neighbouring nodes of the given node. */
|
||||
static void PublicRoad_GetNeighbours(AyStar *aystar, OpenListNode *current)
|
||||
{
|
||||
@@ -581,10 +653,11 @@ static void PublicRoad_GetNeighbours(AyStar *aystar, OpenListNode *current)
|
||||
if (current->path.parent != nullptr) {
|
||||
const auto road_direction = DiagdirBetweenTiles(current->path.parent->node.tile, tile);
|
||||
|
||||
if (IsUpwardsSlope(tile, road_direction) && !_has_tunnel_in_path) {
|
||||
if (IsUpwardsSlope(tile, road_direction)) {
|
||||
const auto tunnel_end = BuildTunnel(¤t->path);
|
||||
|
||||
if (tunnel_end != INVALID_TILE &&
|
||||
!IsBlockedByPreviousBridgeOrTunnel(current, current->path.node.tile, tunnel_end) &&
|
||||
!IsSteepSlope(GetTileSlope(tunnel_end)) &&
|
||||
!IsHalftileSlope(GetTileSlope(tunnel_end)) &&
|
||||
(GetTileSlope(tunnel_end) == ComplementSlope(GetTileSlope(current->path.node.tile)))) {
|
||||
@@ -592,13 +665,13 @@ static void PublicRoad_GetNeighbours(AyStar *aystar, OpenListNode *current)
|
||||
aystar->neighbours[aystar->num_neighbours].tile = tunnel_end;
|
||||
aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
|
||||
aystar->num_neighbours++;
|
||||
_has_tunnel_in_path = true;
|
||||
}
|
||||
}
|
||||
else if (IsDownwardsSlope(tile, road_direction)) {
|
||||
const auto bridge_end = BuildBridge(¤t->path, road_direction);
|
||||
|
||||
if (bridge_end != INVALID_TILE &&
|
||||
!IsBlockedByPreviousBridgeOrTunnel(current, current->path.node.tile, bridge_end) &&
|
||||
!IsSteepSlope(GetTileSlope(bridge_end)) &&
|
||||
!IsHalftileSlope(GetTileSlope(bridge_end)) &&
|
||||
(GetTileSlope(bridge_end) == ComplementSlope(GetTileSlope(current->path.node.tile)))) {
|
||||
@@ -614,7 +687,8 @@ static void PublicRoad_GetNeighbours(AyStar *aystar, OpenListNode *current)
|
||||
const auto bridge_end = BuildRiverBridge(¤t->path, road_direction);
|
||||
assert(bridge_end == INVALID_TILE || GetTileSlope(bridge_end) == SLOPE_FLAT);
|
||||
|
||||
if (bridge_end != INVALID_TILE) {
|
||||
if (bridge_end != INVALID_TILE &&
|
||||
!IsBlockedByPreviousBridgeOrTunnel(current, current->path.node.tile, bridge_end)) {
|
||||
assert(IsValidDiagDirection(DiagdirBetweenTiles(tile, bridge_end)));
|
||||
aystar->neighbours[aystar->num_neighbours].tile = bridge_end;
|
||||
aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
|
||||
@@ -719,8 +793,6 @@ bool FindPath(AyStar& finder, const TileIndex from, TileIndex to)
|
||||
finder.max_search_nodes = 1 << 20;
|
||||
|
||||
finder.Init(1 << _public_road_hash_size);
|
||||
|
||||
_has_tunnel_in_path = false;
|
||||
|
||||
AyStarNode start {};
|
||||
start.tile = from;
|
||||
|
Reference in New Issue
Block a user