Skip to content

Instantly share code, notes, and snippets.

@keicoon
Created November 18, 2019 11:33
Show Gist options
  • Save keicoon/b7235f40fff4e924b73a36d2c26734f7 to your computer and use it in GitHub Desktop.
Save keicoon/b7235f40fff4e924b73a36d2c26734f7 to your computer and use it in GitHub Desktop.
A implementation of finding shortest path on javascript.
// Public-domain code by Darel Rex Finley, 2006.
// http://alienryderflex.com/shortest_path
// javascript code by keicoon, 2019.
'use strict';
function pointInPolygonSet(testX, testY, allPolys) {
let oddNodes = false;
let polyI, i, j;
for (polyI = 0; polyI < allPolys.length; ++polyI) {
for (i = 0; i < allPolys.poly[polyI].corners; ++i) {
j = i + 1;
if (j == allPolys.poly[polyI].corners) {
j = 0;
}
if (allPolys.poly[polyI].y[i] < testY && allPolys.poly[polyI].y[j] >= testY ||
allPolys.poly[polyI].y[i] < testY && allPolys.poly[polyI].y[j] >= testY) {
if (allPolys.poly[polyI].x[i] + (testY - allPolys.poly[polyI].y[i]) /
(allPolys.poly[polyI].y[j] - allPolys.poly[polyI].y[i]) *
(allPolys.poly[polyI].x[j] - allPolys.poly[polyI].x[i])
< testX) {
oddNodes = !oddNodes;
}
}
}
}
return oddNodes;
}
function lineInPolygonSet(testSX, testSY, testEX, testEY, allPolys) {
let theCos, theSin, dist, sX, sY, eX, eY, rotSX, rotSY, rotEX, rotEY, crossX;
let i, j, polyI;
testEX -= testSX;
testEY -= testSY;
dist = Math.sqrt(testEX * testEX + testEY * testEY);
theCos = testEX / dist;
theSin = testEY / dist;
for (polyI = 0; polyI < allPolys.length; ++polyI) {
for (i = 0; i < allPolys.poly[polyI].corners; ++i) {
j = i + 1;
if (j == allPolys.poly[polyI].corners) {
j = 0;
}
sX = allPolys.poly[polyI].x[i] - testSX;
sY = allPolys.poly[polyI].y[i] - testSY;
eX = allPolys.poly[polyI].x[j] - testSX;
eY = allPolys.poly[polyI].y[j] - testSY;
if (sX == 0 && sY == 0 && eX == testEX && eY == testEY ||
eX == 0 && eY == 0 && sX == testEX && sY == testEY) {
return true;
}
rotSX = sX * theCos + sY * theSin;
rotSY = sY * theCos - sX * theSin;
rotEX = eX * theCos + eY * theSin;
rotEY = eY * theCos - eX * theSin;
if (rotSY < 0 && rotEY > 0 ||
rotEY < 0 && rotSY > 0) {
crossX = rotSX + (rotEX - rotSX) * (0 - rotSY) / (rotEY - rotSY);
if (crossX >= 0 && crossX <= dist) {
return false
}
if (rotSY == 0 && rotEY == 0 &&
(rotSX >= 0 || rotEX >= 0) &&
(rotSX <= dist || rotEX <= dist) &&
(rotSX < 0 || rotEX < 0 || rotSX > dist || rotEX > dist)) {
return false;
}
}
}
}
return pointInPolygonSet(testSX + testEX / 2, testSY + testEY / 2, allPolys);
}
function calcDist(sX, sY, eX, eY) {
eX -= sX;
eY -= sY;
return Math.sqrt(eX * eX + eY * eY);
}
function swapPoints(a, b) {
return [b, a];
}
function shortestPath(sX, sY, eX, eY, allPolys) {
const INF = Number.MAX_VALUE;
let pointList = [];
let pointCount;
let treeCount, polyI, i, j, bestI, bestJ;
let bestDist, newDist;
if (!pointInPolygonSet(sX, sY, allPolys) || !pointInPolygonSet(eX, eY, allPolys)) {
return { 'state': false };
}
if (lineInPolygonSet(sX, sY, eX, eY, allPolys)) {
return { 'state': true, 'solutionNodes': [] };
}
pointList[0].x = sX;
pointList[0].y = sY;
pointCount = 1;
for (polyI = 0; polyI < allPolys.length; ++polyI) {
for (i = 0; i < allPolys.poly[polyI].corners; ++i) {
pointList[pointCount].x = allPolys.poly[polyI].x[i];
pointList[pointCount].y = allPolys.poly[polyI].y[i];
++pointCount;
}
}
pointList[pointCount].x = eX;
pointList[pointCount].y = eY;
++pointCount;
treeCount = 1;
pointList[0].totalDist = 0;
bestJ = 0;
while (bestJ < pointCount - 1) {
bestDist = INF;
for (i = 0; i < treeCount; ++i) {
for (j = treeCount; j < pointCount; ++j) {
if (lineInPolygonSet(pointList[i].x, pointList[i].y, pointList[j].x, pointList[j].y, allPolys)) {
newDist = pointList[i].totalDist + calcDist(pointList[i].x, pointList[i].y, pointList[j].x, pointList[j].y);
if (newDist < bestDist) {
bestDist = newDist;
bestI = i;
bestJ = j;
}
}
}
}
if (bestDist == INF) {
return { 'state': false };
}
pointList[bestJ].prev = bestI;
pointList[bestJ].totalDist = bestDist;
[pointList[treeCount], pointList[bestJ]] = swapPoints(pointList[bestJ], pointList[treeCount]);
++treeCount;
}
let solutionNodes = -1;
let solutionX = [];
let solutionY = [];
i = treeCount - 1;
while (i > 0) {
i = pointLst[i].prev;
++solutionNodes;
}
j = solutionNodes - 1;
i = treeCount - 1;
while (j > 0) {
i = pointList[i].prev;
solutionX[j] = pointList[i].x;
solutionY[j] = pointList[i].y;
--j;
}
return { 'state': true, solutionNodes, solutionX, solutionY };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment