diff --git a/modules/routes-generator.js b/modules/routes-generator.js
index 24b4f02d..96315e11 100644
--- a/modules/routes-generator.js
+++ b/modules/routes-generator.js
@@ -1,3 +1,6 @@
+const ROUTES_SHARP_ANGLE = 135;
+const ROUTES_VERY_SHARP_ANGLE = 115;
+
window.Routes = (function () {
function generate() {
const {capitalsByFeature, burgsByFeature, portsByFeature} = sortBurgsByFeature(pack.burgs);
@@ -7,7 +10,7 @@ window.Routes = (function () {
const trails = generateTrails();
const seaRoutes = generateSeaRoutes();
- pack.routes = combineRoutes();
+ pack.routes = createRoutesData();
pack.cells.routes = buildLinks(pack.routes);
function sortBurgsByFeature(burgs) {
@@ -121,22 +124,26 @@ window.Routes = (function () {
return segments;
}
- function combineRoutes() {
+ function createRoutesData() {
const routes = [];
+ const pointsArray = preparePointsArray();
for (const {feature, cells, merged} of mergeRoutes(mainRoads)) {
if (merged) continue;
- routes.push({i: routes.length, group: "roads", feature, cells});
+ const points = getPoints("roads", cells, pointsArray);
+ routes.push({i: routes.length, group: "roads", feature, points});
}
for (const {feature, cells, merged} of mergeRoutes(trails)) {
if (merged) continue;
- routes.push({i: routes.length, group: "trails", feature, cells});
+ const points = getPoints("trails", cells, pointsArray);
+ routes.push({i: routes.length, group: "trails", feature, points});
}
for (const {feature, cells, merged} of mergeRoutes(seaRoutes)) {
if (merged) continue;
- routes.push({i: routes.length, group: "searoutes", feature, cells});
+ const points = getPoints("searoutes", cells, pointsArray);
+ routes.push({i: routes.length, group: "searoutes", feature, points});
}
return routes;
@@ -165,14 +172,68 @@ window.Routes = (function () {
return routesMerged > 1 ? mergeRoutes(routes) : routes;
}
+ function preparePointsArray() {
+ const {cells, burgs} = pack;
+ return cells.p.map(([x, y], cellId) => {
+ const burgId = cells.burg[cellId];
+ if (burgId) return [burgs[burgId].x, burgs[burgId].y];
+ return [x, y];
+ });
+ }
+
+ function getPoints(group, cells, points) {
+ const data = cells.map(cellId => [...points[cellId], cellId]);
+
+ // resolve sharp angles
+ if (group !== "searoutes") {
+ for (let i = 1; i < cells.length - 1; i++) {
+ const cellId = cells[i];
+ if (pack.cells.burg[cellId]) continue;
+
+ const [prevX, prevY] = data[i - 1];
+ const [currX, currY] = data[i];
+ const [nextX, nextY] = data[i + 1];
+
+ const dAx = prevX - currX;
+ const dAy = prevY - currY;
+ const dBx = nextX - currX;
+ const dBy = nextY - currY;
+ const angle = Math.abs((Math.atan2(dAx * dBy - dAy * dBx, dAx * dBx + dAy * dBy) * 180) / Math.PI);
+
+ if (angle < ROUTES_SHARP_ANGLE) {
+ const middleX = (prevX + nextX) / 2;
+ const middleY = (prevY + nextY) / 2;
+ let newX, newY;
+
+ if (angle < ROUTES_VERY_SHARP_ANGLE) {
+ newX = rn((currX + middleX * 2) / 3, 2);
+ newY = rn((currY + middleY * 2) / 3, 2);
+ } else {
+ newX = rn((currX + middleX) / 2, 2);
+ newY = rn((currY + middleY) / 2, 2);
+ }
+
+ if (findCell(newX, newY) === cellId) {
+ data[i] = [newX, newY, cellId];
+ points[cellId] = [data[i][0], data[i][1]]; // change cell coordinate for all routes
+ }
+ }
+ }
+ }
+
+ return data; // [[x, y, cell], [x, y, cell]];
+ }
+
function buildLinks(routes) {
const links = {};
- for (const {cells, i: routeId} of routes) {
+ for (const {points, i: routeId} of routes) {
+ const cells = points.map(p => p[2]);
+
for (let i = 0; i < cells.length; i++) {
const cellId = cells[i];
const nextCellId = cells[i + 1];
- if (nextCellId) {
+ if (nextCellId && cellId !== nextCellId) {
if (!links[cellId]) links[cellId] = {};
links[cellId][nextCellId] = routeId;
@@ -527,8 +588,8 @@ window.Routes = (function () {
searoutes: {"sea route": 5, lane: 2, passage: 1, seaway: 1}
};
- function generateName({group, cells}) {
- if (cells.length < 4) return "Unnamed route segment";
+ function generateName({group, points}) {
+ if (points.length < 4) return "Unnamed route segment";
const model = rw(models[group]);
const suffix = rw(suffixes[group]);
@@ -540,8 +601,8 @@ window.Routes = (function () {
return "Unnamed route";
function getBurgName() {
- const priority = [cells.at(-1), cells.at(0), cells.slice(1, -1).reverse()];
- for (const cellId of priority) {
+ const priority = [points.at(-1), points.at(0), points.slice(1, -1).reverse()];
+ for (const [x, y, cellId] of priority) {
const burgId = pack.cells.burg[cellId];
if (burgId) return getAdjective(pack.burgs[burgId].name);
}
@@ -549,58 +610,6 @@ window.Routes = (function () {
}
}
- function preparePointsArray() {
- const {cells, burgs} = pack;
- return cells.p.map(([x, y], cellId) => {
- const burgId = cells.burg[cellId];
- if (burgId) return [burgs[burgId].x, burgs[burgId].y];
- return [x, y];
- });
- }
-
- function getPoints(route, points) {
- if (route.points) return route.points;
- const routePoints = route.cells.map(cellId => points[cellId]);
-
- if (route.group !== "searoutes2") {
- for (let i = 1; i < route.cells.length - 1; i++) {
- const cellId = route.cells[i];
- if (pack.cells.burg[cellId]) continue;
-
- const [prevX, prevY] = routePoints[i - 1];
- const [currX, currY] = routePoints[i];
- const [nextX, nextY] = routePoints[i + 1];
-
- const dAx = prevX - currX;
- const dAy = prevY - currY;
- const dBx = nextX - currX;
- const dBy = nextY - currY;
- const angle = Math.abs((Math.atan2(dAx * dBy - dAy * dBx, dAx * dBx + dAy * dBy) * 180) / Math.PI);
-
- if (angle < ROUTES_SHARP_ANGLE) {
- const middleX = (prevX + nextX) / 2;
- const middleY = (prevY + nextY) / 2;
- let newX, newY;
-
- if (angle < ROUTES_VERY_SHARP_ANGLE) {
- newX = rn((currX + middleX * 2) / 3, 2);
- newY = rn((currY + middleY * 2) / 3, 2);
- } else {
- newX = rn((currX + middleX) / 2, 2);
- newY = rn((currY + middleY) / 2, 2);
- }
-
- if (findCell(newX, newY) === cellId) {
- routePoints[i] = [newX, newY];
- points[cellId] = routePoints[i]; // change cell coordinate for all routes
- }
- }
- }
- }
-
- return routePoints;
- }
-
function getLength(routeId) {
const path = routes.select("#route" + routeId).node();
return path.getTotalLength();
@@ -609,7 +618,9 @@ window.Routes = (function () {
function remove(route) {
const routes = pack.cells.routes;
- for (const from of route.cells) {
+ for (const point of route.points) {
+ const from = point[2];
+
for (const [to, routeId] of Object.entries(routes[from])) {
if (routeId === route.i) {
delete routes[from][to];
@@ -633,8 +644,6 @@ window.Routes = (function () {
hasRoad,
isCrossroad,
generateName,
- preparePointsArray,
- getPoints,
getLength,
remove
};
diff --git a/modules/ui/layers.js b/modules/ui/layers.js
index d6aefff5..4bae98f7 100644
--- a/modules/ui/layers.js
+++ b/modules/ui/layers.js
@@ -1643,13 +1643,11 @@ function drawRoutes() {
const routePaths = {};
const lineGen = d3.line();
- let points = Routes.preparePointsArray();
-
for (const route of pack.routes) {
const {i, group} = route;
lineGen.curve(ROUTE_CURVES[group] || ROUTE_CURVES.default);
- const routePoints = Routes.getPoints(route, points);
- const path = round(lineGen(routePoints), 1);
+ const points = route.points.map(p => [p[0], p[1]]);
+ const path = round(lineGen(points), 1);
if (!routePaths[group]) routePaths[group] = [];
routePaths[group].push(`
`);
@@ -1663,11 +1661,6 @@ function drawRoutes() {
TIME && console.timeEnd("drawRoutes");
}
-const ROUTES_SHARP_ANGLE = 135;
-const ROUTES_VERY_SHARP_ANGLE = 115;
-
-function drawRoute() {}
-
function toggleMilitary() {
if (!layerIsOn("toggleMilitary")) {
turnButtonOn("toggleMilitary");
diff --git a/modules/ui/route-group-editor.js b/modules/ui/route-group-editor.js
index 9c2e0f24..370058c1 100644
--- a/modules/ui/route-group-editor.js
+++ b/modules/ui/route-group-editor.js
@@ -63,6 +63,8 @@ function editRouteGroups() {
.attr("stroke-linecap", "butt");
byId("routeGroup")?.options.add(new Option(group, group));
addLines();
+
+ byId("routeCreatorGroupSelect").options.add(new Option(group, group));
});
}
diff --git a/modules/ui/routes-creator.js b/modules/ui/routes-creator.js
index cecbba1e..0be3f277 100644
--- a/modules/ui/routes-creator.js
+++ b/modules/ui/routes-creator.js
@@ -10,9 +10,10 @@ function createRoute(defaultGroup) {
tip("Click to add route point, click again to remove", true);
debug.append("g").attr("id", "controlCells");
- viewbox.style("cursor", "crosshair").on("click", onCellClick);
+ debug.append("g").attr("id", "controlPoints");
+ viewbox.style("cursor", "crosshair").on("click", onClick);
- createRoute.cells = [];
+ createRoute.points = [];
const body = byId("routeCreatorBody");
// update route groups
@@ -32,85 +33,106 @@ function createRoute(defaultGroup) {
modules.createRoute = true;
// add listeners
+ byId("routeCreatorGroupSelect").on("change", () => drawRoute(createRoute.points));
byId("routeCreatorGroupEdit").on("click", editRouteGroups);
byId("routeCreatorComplete").on("click", completeCreation);
byId("routeCreatorCancel").on("click", () => $("#routeCreator").dialog("close"));
body.on("click", ev => {
- if (ev.target.classList.contains("icon-trash-empty")) removeCell(+ev.target.parentNode.dataset.cell);
+ if (ev.target.classList.contains("icon-trash-empty")) removePoint(ev.target.parentNode.dataset.point);
});
- function onCellClick() {
- const cell = findCell(...d3.mouse(this));
+ function onClick() {
+ const [x, y] = d3.mouse(this);
+ const cellId = findCell(x, y);
+ const point = [rn(x, 2), rn(y, 2), cellId];
+ createRoute.points.push(point);
- if (createRoute.cells.includes(cell)) removeCell(cell);
- else addCell(cell);
+ drawRoute(createRoute.points);
+
+ body.innerHTML += `
+ Cell: ${cellId}
+ X: ${point[0]}
+ Y: ${point[1]}
+
+
`;
}
- function addCell(cell) {
- createRoute.cells.push(cell);
- drawCells(createRoute.cells);
-
- body.innerHTML += `
- Cell ${cell}
-
- `;
+ function removePoint(pointString) {
+ createRoute.points = createRoute.points.filter(p => p.join("-") !== pointString);
+ drawRoute(createRoute.points);
+ body.querySelector(`[data-point='${pointString}']`)?.remove();
}
- function removeCell(cell) {
- createRoute.cells = createRoute.cells.filter(c => c !== cell);
- drawCells(createRoute.cells);
- body.querySelector(`[data-cell='${cell}']`)?.remove();
- }
-
- function drawCells(cells) {
+ function drawRoute(points) {
debug
.select("#controlCells")
.selectAll("polygon")
- .data(cells)
+ .data(points)
.join("polygon")
- .attr("points", getPackPolygon)
+ .attr("points", p => getPackPolygon(p[2]))
.attr("class", "current");
- }
- function completeCreation() {
- const routeCells = createRoute.cells;
- if (routeCells.length < 2) return tip("Add at least 2 cells", false, "error");
+ debug
+ .select("#controlPoints")
+ .selectAll("circle")
+ .data(points)
+ .join("circle")
+ .attr("cx", d => d[0])
+ .attr("cy", d => d[1])
+ .attr("r", 0.6);
- const routeId = Math.max(...pack.routes.map(route => route.i)) + 1;
const group = byId("routeCreatorGroupSelect").value;
- const feature = pack.cells.f[routeCells[0]];
- const route = {cells: routeCells, group, feature, i: routeId};
- pack.routes.push(route);
-
- const links = pack.cells.routes;
- for (let i = 0; i < routeCells.length; i++) {
- const cellId = routeCells[i];
- const nextCellId = routeCells[i + 1];
- if (nextCellId) {
- if (!links[cellId]) links[cellId] = {};
- links[cellId][nextCellId] = routeId;
-
- if (!links[nextCellId]) links[nextCellId] = {};
- links[nextCellId][cellId] = routeId;
- }
- }
-
const lineGen = d3.line();
lineGen.curve(ROUTE_CURVES[group] || ROUTE_CURVES.default);
- const routePoints = Routes.getPoints(route, Routes.preparePointsArray());
- const path = round(lineGen(routePoints), 1);
+ const path = round(lineGen(points), 1);
+
+ routes.select("#routeTemp").remove();
routes
.select("#" + group)
.append("path")
.attr("d", path)
- .attr("id", "route" + routeId);
+ .attr("id", "routeTemp");
+ }
+ function completeCreation() {
+ const points = createRoute.points;
+ if (points.length < 2) return tip("Add at least 2 points", false, "error");
+
+ const routeId = Math.max(...pack.routes.map(route => route.i)) + 1;
+ const group = byId("routeCreatorGroupSelect").value;
+ const feature = pack.cells.f[points[0][2]];
+ const route = {points, group, feature, i: routeId};
+ pack.routes.push(route);
+
+ const links = pack.cells.routes;
+ for (let i = 0; i < points.length; i++) {
+ const point = points[i];
+ const nextPoint = points[i + 1];
+
+ if (nextPoint) {
+ const cellId = point[2];
+ const nextId = nextPoint[2];
+
+ if (!links[cellId]) links[cellId] = {};
+ links[cellId][nextId] = routeId;
+
+ if (!links[nextId]) links[nextId] = {};
+ links[nextId][cellId] = routeId;
+ }
+ }
+
+ routes.select("#routeTemp").attr("id", "route" + routeId);
editRoute("route" + routeId);
}
function closeRouteCreator() {
body.innerHTML = "";
debug.select("#controlCells").remove();
+ debug.select("#controlPoints").remove();
+ routes.select("#routeTemp").remove();
+
restoreDefaultEvents();
clearMainTip();
diff --git a/modules/ui/routes-editor.js b/modules/ui/routes-editor.js
index 3717af7c..9e05242a 100644
--- a/modules/ui/routes-editor.js
+++ b/modules/ui/routes-editor.js
@@ -18,11 +18,12 @@ function editRoute(id) {
debug.append("g").attr("id", "controlCells");
debug.append("g").attr("id", "controlPoints");
- updateRouteData();
-
- const route = getRoute();
- drawControlPoints(Routes.getPoints(route, Routes.preparePointsArray()));
- drawCells();
+ {
+ const route = getRoute();
+ updateRouteData(route);
+ drawControlPoints(route.points);
+ drawCells(route.points);
+ }
$("#routeEditor").dialog({
title: "Edit Route",
@@ -52,9 +53,7 @@ function editRoute(id) {
return pack.routes.find(route => route.i === routeId);
}
- function updateRouteData() {
- const route = getRoute();
-
+ function updateRouteData(route) {
route.name = route.name || Routes.generateName(route);
byId("routeName").value = route.name;
@@ -66,7 +65,7 @@ function editRoute(id) {
updateRouteLength(route);
- const isWater = route.cells.some(cell => pack.cells.h[cell] < 20);
+ const isWater = route.points.some(([x, y, cellId]) => pack.cells.h[cellId] < 20);
byId("routeElevationProfile").style.display = isWater ? "none" : "inline-block";
}
@@ -88,55 +87,58 @@ function editRoute(id) {
.on("click", handleControlPointClick);
}
- function drawCells() {
- const {cells} = getRoute();
- debug.select("#controlCells").selectAll("polygon").data(cells).join("polygon").attr("points", getPackPolygon);
+ function drawCells(points) {
+ debug
+ .select("#controlCells")
+ .selectAll("polygon")
+ .data(points)
+ .join("polygon")
+ .attr("points", p => getPackPolygon(p[2]));
}
function dragControlPoint() {
- const initCell = findCell(d3.event.x, d3.event.y);
const route = getRoute();
- const cellIndex = route.cells.indexOf(initCell);
+ const initCell = d3.event.subject[2];
+ const pointIndex = route.points.indexOf(d3.event.subject);
d3.event.on("drag", function () {
this.setAttribute("cx", d3.event.x);
this.setAttribute("cy", d3.event.y);
- this.__data__ = [rn(d3.event.x, 2), rn(d3.event.y, 2)];
- redrawRoute();
- drawCells();
+ const x = rn(d3.event.x, 2);
+ const y = rn(d3.event.y, 2);
+ const cellId = findCell(x, y);
+
+ this.__data__ = route.points[pointIndex] = [x, y, cellId];
+ redrawRoute(route);
+ drawCells(route.points);
});
d3.event.on("end", () => {
const movedToCell = findCell(d3.event.x, d3.event.y);
if (movedToCell !== initCell) {
- route.cells[cellIndex] = movedToCell;
-
- const prevCell = route.cells[cellIndex - 1];
- if (prevCell) {
- removeConnection(initCell, prevCell);
- addConnection(movedToCell, prevCell, route.i);
+ const prev = route.points[pointIndex - 1];
+ if (prev) {
+ removeConnection(initCell, prev[2]);
+ addConnection(movedToCell, prev[2], route.i);
}
- const nextCell = route.cells[cellIndex + 1];
- if (nextCell) {
- removeConnection(initCell, nextCell);
- addConnection(movedToCell, nextCell, route.i);
+ const next = route.points[pointIndex + 1];
+ if (next) {
+ removeConnection(initCell, next[2]);
+ addConnection(movedToCell, next[2], route.i);
}
}
});
}
- function redrawRoute() {
- const route = getRoute();
- route.points = debug.selectAll("#controlPoints > *").data();
- route.cells = unique(route.points.map(([x, y]) => findCell(x, y)));
-
+ function redrawRoute(route) {
const lineGen = d3.line();
lineGen.curve(ROUTE_CURVES[route.group] || ROUTE_CURVES.default);
- const path = round(lineGen(route.points), 1);
+ const points = route.points.map(p => [p[0], p[1]]);
+ const path = round(lineGen(points), 1);
elSelected.attr("d", path);
updateRouteLength(route);
@@ -144,69 +146,70 @@ function editRoute(id) {
}
function addControlPoint() {
- const [x, y] = d3.mouse(this);
const route = getRoute();
- if (!route.points) route.points = debug.selectAll("#controlPoints > *").data();
+ const [x, y] = d3.mouse(this);
+ const cellId = findCell(x, y);
+
+ const point = [rn(x, 2), rn(y, 2), cellId];
+ const isNewCell = !route.points.some(p => p[2] === cellId);
- const point = [rn(x, 2), rn(y, 2)];
const index = getSegmentId(route.points, point, 2);
route.points.splice(index, 0, point);
- const cellId = findCell(x, y);
- if (!route.cells.includes(cellId)) {
- route.cells = unique(route.points.map(([x, y]) => findCell(x, y)));
- const cellIndex = route.cells.indexOf(cellId);
+ // check if added point is in new cell
+ if (isNewCell) {
+ const prev = route.points[index - 1];
+ const next = route.points[index + 1];
- const prev = route.cells[cellIndex - 1];
- const next = route.cells[cellIndex + 1];
+ if (!prev) ERROR && console.error("Can't add control point to the start of the route");
+ if (!next) ERROR && console.error("Can't add control point to the end of the route");
+ if (!prev || !next) return;
- removeConnection(prev, next);
- addConnection(prev, cellId, route.i);
- addConnection(cellId, next, route.i);
+ removeConnection(prev[2], next[2]);
+ addConnection(prev[2], cellId, route.i);
+ addConnection(cellId, next[2], route.i);
- drawCells();
+ drawCells(route.points);
}
drawControlPoints(route.points);
- redrawRoute();
+ redrawRoute(route);
}
function handleControlPointClick() {
const controlPoint = d3.select(this);
+ const point = controlPoint.datum();
+ const route = getRoute();
+ const index = route.points.indexOf(point);
+
const isSplitMode = byId("routeSplit").classList.contains("pressed");
- if (isSplitMode) return splitRoute(controlPoint);
+ return isSplitMode ? splitRoute() : removeControlPoint(controlPoint);
- return removeControlPoint(controlPoint);
-
- function splitRoute(controlPoint) {
- const allPoints = debug.selectAll("#controlPoints > *").data();
- const pointIndex = allPoints.indexOf(controlPoint.datum());
-
- const oldRoutePoints = allPoints.slice(0, pointIndex + 1);
- const newRoutePoints = allPoints.slice(pointIndex);
+ function splitRoute() {
+ const oldRoutePoints = route.points.slice(0, index + 1);
+ const newRoutePoints = route.points.slice(index);
// update old route
- const oldRoute = getRoute();
- oldRoute.points = oldRoutePoints;
- oldRoute.cells = unique(oldRoute.points.map(([x, y]) => findCell(x, y)));
- drawControlPoints(oldRoute.points);
- drawCells();
- redrawRoute();
+ route.points = oldRoutePoints;
+ drawControlPoints(route.points);
+ drawCells(route.points);
+ redrawRoute(route);
// create new route
const newRoute = {
- ...oldRoute,
i: Math.max(...pack.routes.map(route => route.i)) + 1,
- cells: unique(newRoutePoints.map(([x, y]) => findCell(x, y))),
+ group: route.group,
+ feature: route.feature,
+ name: route.name,
points: newRoutePoints
};
pack.routes.push(newRoute);
- for (let i = 0; i < newRoute.cells.length; i++) {
- const cellId = newRoute.cells[i];
- const nextCellId = newRoute.cells[i + 1];
- if (nextCellId) addConnection(cellId, nextCellId, newRoute.i);
+ for (let i = 0; i < newRoute.points.length; i++) {
+ const cellId = newRoute.points[i][2];
+ const nextPoint = newRoute.points[i + 1];
+ if (nextPoint) addConnection(cellId, nextPoint[2], newRoute.i);
}
const lineGen = d3.line();
@@ -214,50 +217,42 @@ function editRoute(id) {
routes
.select("#" + newRoute.group)
.append("path")
- .attr("d", round(lineGen(Routes.getPoints(newRoute, newRoutePoints)), 1))
+ .attr("d", round(lineGen(newRoutePoints), 1))
.attr("id", "route" + newRoute.i);
byId("routeSplit").classList.remove("pressed");
}
function removeControlPoint(controlPoint) {
- const route = getRoute();
-
- if (!route.points) route.points = debug.selectAll("#controlPoints > *").data();
- const cellId = findCell(...controlPoint.datum());
- const routeAllCells = route.points.map(([x, y]) => findCell(x, y));
-
- const isOnlyPointInCell = routeAllCells.filter(cell => cell === cellId).length === 1;
+ const isOnlyPointInCell = route.points.filter(p => p[2] === point[2]).length === 1;
if (isOnlyPointInCell) {
- const index = route.cells.indexOf(cellId);
- const prev = route.cells[index - 1];
- const next = route.cells[index + 1];
- if (prev) removeConnection(prev, cellId);
- if (next) removeConnection(cellId, next);
- if (prev && next) addConnection(prev, next, route.i);
+ const prev = route.points[index - 1];
+ const next = route.points[index + 1];
+ if (prev) removeConnection(prev[2], point[2]);
+ if (next) removeConnection(point[2], next[2]);
+ if (prev && next) addConnection(prev[2], next[2], route.i);
}
controlPoint.remove();
- route.points = debug.selectAll("#controlPoints > *").data();
- route.cells = unique(route.points.map(([x, y]) => findCell(x, y)));
+ route.points = route.points.filter(p => p !== point);
- drawCells();
- redrawRoute();
+ drawCells(route.points);
+ redrawRoute(route);
}
}
function openJoinRoutesDialog() {
const route = getRoute();
- const firstCell = route.cells.at(0);
- const lastCell = route.cells.at(-1);
+ const firstCell = route.points.at(0)[2];
+ const lastCell = route.points.at(-1)[2];
const candidateRoutes = pack.routes.filter(r => {
if (r.i === route.i) return false;
if (r.group !== route.group) return false;
- if (r.cells.at(0) === lastCell) return true;
- if (r.cells.at(-1) === firstCell) return true;
- if (r.cells.at(0) === firstCell) return true;
- if (r.cells.at(-1) === lastCell) return true;
+ if (r.points.at(0)[2] === lastCell) return true;
+ if (r.points.at(-1)[2] === firstCell) return true;
+ if (r.points.at(0)[2] === firstCell) return true;
+ if (r.points.at(-1)[2] === lastCell) return true;
return false;
});
@@ -275,7 +270,7 @@ function editRoute(id) {
$("#alert").dialog({
title: "Join routes",
width: fitContent(),
- position: {my: "center", at: "center", of: "svg"},
+ position: {my: "left top", at: "left+10 top+150", of: "#map"},
buttons: {
Cancel: () => {
$("#alert").dialog("close");
@@ -295,37 +290,30 @@ function editRoute(id) {
}
function joinRoutes(route, joinedRoute) {
- if (!route.points) route.points = debug.selectAll("#controlPoints > *").data();
- if (!joinedRoute.points) joinedRoute.points = Routes.getPoints(joinedRoute, Routes.preparePointsArray());
-
- if (route.cells.at(-1) === joinedRoute.cells.at(0)) {
+ if (route.points.at(-1)[2] === joinedRoute.points.at(0)[2]) {
// joinedRoute starts at the end of current route
- route.cells = [...route.cells, ...joinedRoute.cells.slice(1)];
route.points = [...route.points, ...joinedRoute.points.slice(1)];
- } else if (route.cells.at(0) === joinedRoute.cells.at(-1)) {
+ } else if (route.points.at(0)[2] === joinedRoute.points.at(-1)[2]) {
// joinedRoute ends at the start of current route
- route.cells = [...joinedRoute.cells, ...route.cells.slice(1)];
route.points = [...joinedRoute.points, ...route.points.slice(1)];
- } else if (route.cells.at(0) === joinedRoute.cells.at(0)) {
+ } else if (route.points.at(0)[2] === joinedRoute.points.at(0)[2]) {
// joinedRoute and current route both start at the same cell
- route.cells = [...route.cells.reverse(), ...joinedRoute.cells.slice(1)];
route.points = [...route.points.reverse(), ...joinedRoute.points.slice(1)];
- } else if (route.cells.at(-1) === joinedRoute.cells.at(-1)) {
+ } else if (route.points.at(-1)[2] === joinedRoute.points.at(-1)[2]) {
// joinedRoute and current route both end at the same cell
- route.cells = [...route.cells, ...joinedRoute.cells.reverse().slice(1)];
route.points = [...route.points, ...joinedRoute.points.reverse().slice(1)];
}
- for (let i = 0; i < route.cells.length; i++) {
- const cellId = route.cells[i];
- const nextCellId = route.cells[i + 1];
- if (nextCellId) addConnection(cellId, nextCellId, route.i);
+ for (let i = 0; i < route.points.length; i++) {
+ const point = route.points[i];
+ const nextPoint = route.points[i + 1];
+ if (nextPoint) addConnection(point[2], nextPoint[2], route.i);
}
Routes.remove(joinedRoute);
drawControlPoints(route.points);
- drawCells();
- redrawRoute();
+ redrawRoute(route);
+ drawCells(route.points);
}
function showCreationDialog() {
@@ -371,7 +359,11 @@ function editRoute(id) {
function showRouteElevationProfile() {
const route = getRoute();
const length = rn(route.length * distanceScale);
- showElevationProfile(route.cells, length, false);
+ showElevationProfile(
+ route.points.map(p => p[2]),
+ length,
+ false
+ );
}
function editRouteLegend() {
diff --git a/utils/commonUtils.js b/utils/commonUtils.js
index 309d7f7d..910cc95d 100644
--- a/utils/commonUtils.js
+++ b/utils/commonUtils.js
@@ -9,7 +9,6 @@ function clipPoly(points, secure = 0) {
// get segment of any point on polyline
function getSegmentId(points, point, step = 10) {
if (points.length === 2) return 1;
- const d2 = (p1, p2) => (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2;
let minSegment = 1;
let minDist = Infinity;
@@ -18,7 +17,7 @@ function getSegmentId(points, point, step = 10) {
const p1 = points[i];
const p2 = points[i + 1];
- const length = Math.sqrt(d2(p1, p2));
+ const length = Math.sqrt(dist2(p1, p2));
const segments = Math.ceil(length / step);
const dx = (p2[0] - p1[0]) / segments;
const dy = (p2[1] - p1[1]) / segments;
@@ -26,10 +25,10 @@ function getSegmentId(points, point, step = 10) {
for (let s = 0; s < segments; s++) {
const x = p1[0] + s * dx;
const y = p1[1] + s * dy;
- const dist2 = d2(point, [x, y]);
+ const dist = dist2(point, [x, y]);
- if (dist2 >= minDist) continue;
- minDist = dist2;
+ if (dist >= minDist) continue;
+ minDist = dist;
minSegment = i + 1;
}
}
diff --git a/utils/functionUtils.js b/utils/functionUtils.js
index 83813cdb..12570b40 100644
--- a/utils/functionUtils.js
+++ b/utils/functionUtils.js
@@ -27,5 +27,5 @@ function nest(values, map, reduce, keys) {
}
function dist2([x1, y1], [x2, y2]) {
- return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
+ return (x1 - x2) ** 2 + (y1 - y2) ** 2;
}