mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 17:51:24 +01:00
refactor: curve and shorten 2-points routes
This commit is contained in:
parent
bbf8871e70
commit
03809e56ab
3 changed files with 48 additions and 7 deletions
|
|
@ -1,11 +1,12 @@
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
|
|
||||||
|
import {getNormal} from "utils/lineUtils";
|
||||||
import {round} from "utils/stringUtils";
|
import {round} from "utils/stringUtils";
|
||||||
|
|
||||||
const lineGenTypeMap: {[key in IRoute["type"]]: d3.CurveFactory | d3.CurveFactoryLineOnly} = {
|
const lineGenTypeMap: {[key in IRoute["type"]]: d3.CurveFactory | d3.CurveFactoryLineOnly} = {
|
||||||
road: d3.curveCatmullRom.alpha(0.1),
|
road: d3.curveCatmullRom.alpha(0.1),
|
||||||
trail: d3.curveCatmullRom.alpha(0.1),
|
trail: d3.curveCatmullRom.alpha(0.1),
|
||||||
sea: d3.curveBundle.beta(1)
|
sea: d3.curveBasis
|
||||||
};
|
};
|
||||||
|
|
||||||
export function drawRoutes() {
|
export function drawRoutes() {
|
||||||
|
|
@ -22,7 +23,7 @@ export function drawRoutes() {
|
||||||
|
|
||||||
for (const {i, type, cells} of pack.routes) {
|
for (const {i, type, cells} of pack.routes) {
|
||||||
if (type !== "sea") straightenPathAngles(cells); // mutates points
|
if (type !== "sea") straightenPathAngles(cells); // mutates points
|
||||||
const pathPoints = cells.map(cellId => points[cellId]);
|
const pathPoints = getPathPoints(cells);
|
||||||
|
|
||||||
lineGen.curve(lineGenTypeMap[type]);
|
lineGen.curve(lineGenTypeMap[type]);
|
||||||
const path = round(lineGen(pathPoints)!, 1);
|
const path = round(lineGen(pathPoints)!, 1);
|
||||||
|
|
@ -79,4 +80,40 @@ export function drawRoutes() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPathPoints(cellIds: number[]): TPoints {
|
||||||
|
const pathPoints = cellIds.map(cellId => points[cellId]);
|
||||||
|
|
||||||
|
if (pathPoints.length === 2) {
|
||||||
|
// curve and shorten 2-points line
|
||||||
|
const [[x1, y1], [x2, y2]] = pathPoints;
|
||||||
|
|
||||||
|
const middleX = (x1 + x2) / 2;
|
||||||
|
const middleY = (y1 + y2) / 2;
|
||||||
|
|
||||||
|
// add shifted point at the middle to curve the line a bit
|
||||||
|
const NORMAL_LENGTH = 0.3;
|
||||||
|
const normal = getNormal([x1, y1], [x2, y2]);
|
||||||
|
const sign = cellIds[0] % 2 ? 1 : -1;
|
||||||
|
const normalX = middleX + NORMAL_LENGTH * Math.cos(normal) * sign;
|
||||||
|
const normalY = middleY + NORMAL_LENGTH * Math.sin(normal) * sign;
|
||||||
|
|
||||||
|
// make line shorter to avoid overlapping with other lines
|
||||||
|
const SHORT_LINE_LENGTH_MODIFIER = 0.8;
|
||||||
|
const distX = x2 - x1;
|
||||||
|
const distY = y2 - y1;
|
||||||
|
const nx1 = x1 + distX * SHORT_LINE_LENGTH_MODIFIER;
|
||||||
|
const ny1 = y1 + distY * SHORT_LINE_LENGTH_MODIFIER;
|
||||||
|
const nx2 = x2 - distX * SHORT_LINE_LENGTH_MODIFIER;
|
||||||
|
const ny2 = y2 - distY * SHORT_LINE_LENGTH_MODIFIER;
|
||||||
|
|
||||||
|
return [
|
||||||
|
[nx1, ny1],
|
||||||
|
[normalX, normalY],
|
||||||
|
[nx2, ny2]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathPoints;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
// utils to be used for debugging (not in PROD)
|
// utils to be used for debugging (not in PROD)
|
||||||
|
|
||||||
|
import {getNormal} from "./lineUtils";
|
||||||
|
|
||||||
export function drawPoint([x, y]: TPoint, {radius = 1, color = "red"} = {}) {
|
export function drawPoint([x, y]: TPoint, {radius = 1, color = "red"} = {}) {
|
||||||
debug.append("circle").attr("cx", x).attr("cy", y).attr("r", radius).attr("fill", color);
|
debug.append("circle").attr("cx", x).attr("cy", y).attr("r", radius).attr("fill", color);
|
||||||
}
|
}
|
||||||
|
|
@ -10,7 +12,7 @@ export function drawPolygon(
|
||||||
) {
|
) {
|
||||||
debug
|
debug
|
||||||
.append("polyline")
|
.append("polyline")
|
||||||
.attr("points", [...points, points[0]])
|
.attr("points", [...points, points[0]].join(" "))
|
||||||
.attr("fill", fill)
|
.attr("fill", fill)
|
||||||
.attr("fill-opacity", fillOpacity)
|
.attr("fill-opacity", fillOpacity)
|
||||||
.attr("stroke", stroke)
|
.attr("stroke", stroke)
|
||||||
|
|
@ -28,10 +30,8 @@ export function drawLine([x1, y1]: TPoint, [x2, y2]: TPoint, {stroke = "#444", s
|
||||||
.attr("stroke-width", strokeWidth);
|
.attr("stroke-width", strokeWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function drawArrow([x1, y1]: TPoint, [x2, y2]: TPoint, {width = 1, color = "#444"} = {}): void {
|
export function drawArrow([x1, y1]: TPoint, [x2, y2]: TPoint, {width = 1, color = "#444"} = {}) {
|
||||||
const angle = Math.atan2(y2 - y1, x2 - x1);
|
const normal = getNormal([x1, y1], [x2, y2]);
|
||||||
const normal = angle + Math.PI / 2;
|
|
||||||
|
|
||||||
const [xMid, yMid] = [(x1 + x2) / 2, (y1 + y2) / 2];
|
const [xMid, yMid] = [(x1 + x2) / 2, (y1 + y2) / 2];
|
||||||
|
|
||||||
const [xLeft, yLeft] = [xMid + width * Math.cos(normal), yMid + width * Math.sin(normal)];
|
const [xLeft, yLeft] = [xMid + width * Math.cos(normal), yMid + width * Math.sin(normal)];
|
||||||
|
|
|
||||||
|
|
@ -74,3 +74,7 @@ export function filterOutOfCanvasPoints(points: TPoints) {
|
||||||
|
|
||||||
return points.filter((_, i) => filterOutCanvasPoint(i));
|
return points.filter((_, i) => filterOutCanvasPoint(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getNormal([x1, y1]: TPoint, [x2, y2]: TPoint) {
|
||||||
|
return Math.atan2(y1 - y2, x1 - x2) + Math.PI / 2;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue