/**
* Returns all points on the tilegrid within the convex hull of the given positions.
*/
function ConvexPolygonPlacer(points, failFraction = 0)
{
this.polygonVertices = this.getConvexHull(points.map(point => point.clone().round()));
this.failFraction = failFraction;
}
ConvexPolygonPlacer.prototype.place = function(constraint)
{
let points = [];
let count = 0;
let failed = 0;
for (let point of getPointsInBoundingBox(getBoundingBox(this.polygonVertices)))
{
if (this.polygonVertices.some((vertex, i) =>
distanceOfPointFromLine(this.polygonVertices[i], this.polygonVertices[(i + 1) % this.polygonVertices.length], point) > 0))
continue;
++count;
if (g_Map.inMapBounds(point) && constraint.allows(point))
points.push(point);
else
++failed;
}
return failed <= this.failFraction * count ? points : undefined;
};
/**
* Applies the gift-wrapping algorithm.
* Returns a sorted subset of the given points that are the vertices of the convex polygon containing all given points.
*/
ConvexPolygonPlacer.prototype.getConvexHull = function(points)
{
let uniquePoints = [];
for (let point of points)
if (uniquePoints.every(p => p.x != point.x || p.y != point.y))
uniquePoints.push(point);
// Start with the leftmost point
let result = [uniquePoints.reduce((leftMost, point) => point.x < leftMost.x ? point : leftMost, uniquePoints[0])];
// Add the vector most left of the most recently added point until a cycle is reached
while (result.length < uniquePoints.length)
{
let nextLeftmostPoint;
// Of all points, find the one that is leftmost
for (let point of uniquePoints)
{
if (point == result[result.length - 1])
continue;
if (!nextLeftmostPoint || distanceOfPointFromLine(nextLeftmostPoint, result[result.length - 1], point) <= 0)
nextLeftmostPoint = point;
}
// If it was a known one, then the remaining points are inside this hull
if (result.indexOf(nextLeftmostPoint) != -1)
break;
result.push(nextLeftmostPoint);
}
return result;
};