Skip to content

Instantly share code, notes, and snippets.

@murraco
Last active June 19, 2020 14:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save murraco/d389ce29efe737137c68106496166b45 to your computer and use it in GitHub Desktop.
Save murraco/d389ce29efe737137c68106496166b45 to your computer and use it in GitHub Desktop.
Custom Code Challenge from Logement 3D: getClosestPointInsidePolygon
interface Point {
x: number;
y: number;
}
function getClosestPointInsidePolygon(poly: Point[], c: Point): Point {
const fixPrecision = (x: number) => Number(x.toPrecision(12));
let min: number = Number.MAX_SAFE_INTEGER;
let minP: Point = { x: Number.MAX_SAFE_INTEGER, y: Number.MAX_SAFE_INTEGER };
// Assume point i(x) is connected to i(x+1) and i(n) is connected to i(0)
// For each line (pair of points: A & B)
for (let i = 0; i < poly.length; i += 1) {
const a: Point = poly[i];
const b: Point = poly[(i + 1) % poly.length];
// Calculate distance from given point C to A
const dca: number = Math.sqrt((c.y - a.y) ** 2 + (c.x - a.x) ** 2);
// Calculate distance from C to intersection of AB in perpendicular direction
// step 1: Calculate line AB slope
let m: number = fixPrecision((b.y - a.y) / (b.x - a.x));
m = isFinite(m) ? m : 1; // If it's not a vertical line
// step 2: Calculate line AB y-intercept
const abB = fixPrecision(a.y - m * a.x);
// step 3: Calculate perpendicular slope (pM)
let pM: number = fixPrecision(-1 / m);
pM = isFinite(pM) ? pM : m;
// step 4: Calculate line CD y-intercept: b
const cdB: number = fixPrecision(c.y - pM * c.x);
// step 5: Calculate x value for D
const dX: number = fixPrecision((cdB - abB) / (m - pM));
// step 6: Calculate y value for D
const dY: number = fixPrecision(pM * dX + cdB);
// step 7: Calculate distance from C to D
const dcd: number = fixPrecision(Math.sqrt((c.x - dX) ** 2 + (c.y - dY) ** 2));
// Get min distance between dab and dcd
const curMin = Math.min(dca, dcd);
if (curMin < min) {
min = curMin;
minP = { x: dX, y: dY };
}
}
return minP;
}
let poly = [{ x: 0, y: 0 }, { x: 100, y: 0 }, { x: 100, y: 100 }, { x: 0, y: 100 }];
let point = { x: 150, y: 50 };
console.log(getClosestPointInsidePolygon(poly, point));
// should return { x: 100, y: 50 }
poly = [{ x: 3, y: 2 }, { x: 7, y: 4 }];
point = { x: 8, y: -2 };
console.log(getClosestPointInsidePolygon(poly, point));
// should return { x: 5.4, y: 3.2 }
poly = [{ x: 5, y: 3 }, { x: 1, y: 4.5 }, { x: 1, y: 1.6 }, { x: 9, y: 2.9 }, { x: 8.9, y: 7 }, { x: 8, y: 7 }];
point = { x: 1, y: 3 };
console.log(getClosestPointInsidePolygon(poly, point));
// should return { x: 0.25, y: 3.75 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment