mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-11-08 10:09:16 +00:00
Search the closest water point among boundary points only
Area.getClosestPointTo scans every point of the water search area, and it was called up to count * retryFactor times in placeDocks. The nearest point of a set to a point outside of it is always a boundary point, so compute the boundary once and scan only that. The logic lives in two small helpers, getBoundaryPoints (Uint8Array mask based) and getClosestPointInList, so it can be reused and read apart from placeDocks. getBoundaryPoints returns the original point objects, while getClosestPointInList returns a clone of the point it finds, so callers cannot mutate the points stored in the list.
This commit is contained in:
1 parent
a8ba4945e9
commit
f08832b60d
1 file changed
+52
-2
@@ -262,6 +262,53 @@ function createDecoration(objects, counts, constraint)
|
||||
5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the points of the given list that have at least one 4-neighbour outside of the list.
|
||||
* The closest point of a set to a point outside of it always lies on the set's boundary,
|
||||
* since a point with all four neighbours in the set always has a strictly closer neighbour.
|
||||
*
|
||||
* @param {Vector2D[]} points - Integer tile positions within the map.
|
||||
* @param {number} mapSize - The side length of the map in tiles.
|
||||
* @returns {Vector2D[]}
|
||||
*/
|
||||
function getBoundaryPoints(points, mapSize)
|
||||
{
|
||||
const inSet = new Uint8Array(mapSize * mapSize);
|
||||
for (const p of points)
|
||||
inSet[p.x * mapSize + p.y] = 1;
|
||||
|
||||
const contains = (x, y) => x >= 0 && y >= 0 && x < mapSize && y < mapSize && inSet[x * mapSize + y] === 1;
|
||||
|
||||
return points.filter(p =>
|
||||
!contains(p.x - 1, p.y) || !contains(p.x + 1, p.y) ||
|
||||
!contains(p.x, p.y - 1) || !contains(p.x, p.y + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the point of the given list that is closest to the given position.
|
||||
*
|
||||
* @param {Vector2D[]} points - Must not be empty.
|
||||
* @param {Vector2D} position
|
||||
* @returns {Vector2D}
|
||||
*/
|
||||
function getClosestPointInList(points, position)
|
||||
{
|
||||
let best;
|
||||
let bestDistSquared = Infinity;
|
||||
for (const p of points)
|
||||
{
|
||||
const dx = p.x - position.x;
|
||||
const dy = p.y - position.y;
|
||||
const distSquared = dx * dx + dy * dy;
|
||||
if (distSquared < bestDistSquared)
|
||||
{
|
||||
bestDistSquared = distSquared;
|
||||
best = p;
|
||||
}
|
||||
}
|
||||
return best.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Places docks in situations where the location of land and water is not known in advance.
|
||||
* Do determine the position, it picks a random point on the land, find the closest, significantly large body of water,
|
||||
@@ -288,7 +335,8 @@ function placeDocks(template, playerID, count, tileClassWater, tileClassDock, he
|
||||
undefined,
|
||||
stayClasses(tileClassWater, 20));
|
||||
|
||||
if (!areaSearchEnd || !areaSearchEnd.getPoints().length)
|
||||
const endPoints = areaSearchEnd?.getPoints();
|
||||
if (!endPoints?.length)
|
||||
return;
|
||||
|
||||
g_Map.log("Marking dock search start area");
|
||||
@@ -301,6 +349,8 @@ function placeDocks(template, playerID, count, tileClassWater, tileClassDock, he
|
||||
if (!startPoints?.length)
|
||||
return;
|
||||
|
||||
const boundaryPoints = getBoundaryPoints(endPoints, g_Map.getSize());
|
||||
|
||||
// TODO: computing the exact intersection with the waterplane would both not require us to pass reasonable heights and be more precise
|
||||
const constraint = new AndConstraint(constraints);
|
||||
g_Map.log("Placing docks");
|
||||
@@ -308,7 +358,7 @@ function placeDocks(template, playerID, count, tileClassWater, tileClassDock, he
|
||||
for (let tries = 0; tries < retryFactor; ++tries)
|
||||
{
|
||||
const positionLand = pickRandom(startPoints);
|
||||
const positionWaterLarge = areaSearchEnd.getClosestPointTo(positionLand);
|
||||
const positionWaterLarge = getClosestPointInList(boundaryPoints, positionLand);
|
||||
const positionDock = findLocationInDirectionBasedOnHeight(positionWaterLarge, positionLand, heightMin, heightMax, offset);
|
||||
if (!positionDock)
|
||||
continue;
|
||||
|
||||
Reference in new issue
Block a user