Last active
June 19, 2020 14:44
-
-
Save murraco/d389ce29efe737137c68106496166b45 to your computer and use it in GitHub Desktop.
Custom Code Challenge from Logement 3D: getClosestPointInsidePolygon
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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