This commit is contained in:
@@ -33,6 +33,31 @@
|
||||
return inside;
|
||||
}
|
||||
|
||||
function distPointToSegment(px, py, x1, y1, x2, y2) {
|
||||
const dx = x2 - x1;
|
||||
const dy = y2 - y1;
|
||||
const lenSq = dx * dx + dy * dy;
|
||||
if (lenSq === 0) return Math.hypot(px - x1, py - y1);
|
||||
let t = ((px - x1) * dx + (py - y1) * dy) / lenSq;
|
||||
t = Math.max(0, Math.min(1, t));
|
||||
return Math.hypot(px - (x1 + t * dx), py - (y1 + t * dy));
|
||||
}
|
||||
|
||||
function pointNearPolyline(px, py, points, halfWidth, tolerance = 4) {
|
||||
if (!points?.length || points.length < 2) return false;
|
||||
const limit = halfWidth + tolerance;
|
||||
for (let j = 0; j < points.length - 1; j++) {
|
||||
const p1 = points[j];
|
||||
const p2 = points[j + 1];
|
||||
if (distPointToSegment(px, py, p1.x, p1.y, p2.x, p2.y) <= limit) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isLineGeometry(z) {
|
||||
return z?.geometry === "line";
|
||||
}
|
||||
|
||||
function isPlannerZoneType(type) {
|
||||
return PLANNER_TYPES.has(type);
|
||||
}
|
||||
@@ -42,46 +67,50 @@
|
||||
}
|
||||
|
||||
/** Topmost planner zones containing image pixel (newest wins for overlaps). */
|
||||
function zonesAtPoint(zones, px, py) {
|
||||
function zonesAtPoint(zones, px, py, mapMeta = null) {
|
||||
const list = Array.isArray(zones) ? zones : [];
|
||||
const hits = [];
|
||||
const linePx = (z) => window.MapObjects?.zoneLineWidthPx(z, mapMeta) ?? 8;
|
||||
for (let i = list.length - 1; i >= 0; i--) {
|
||||
const z = list[i];
|
||||
if (!isPlannerZoneType(z?.type) || !z.points?.length) continue;
|
||||
if (pointInPolygon(px, py, z.points)) hits.push(z);
|
||||
if (isLineGeometry(z)) {
|
||||
const half = linePx(z) / 2;
|
||||
if (pointNearPolyline(px, py, z.points, half)) hits.push(z);
|
||||
} else if (pointInPolygon(px, py, z.points)) hits.push(z);
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
function pixelCost(zones, px, py) {
|
||||
const hits = zonesAtPoint(zones, px, py);
|
||||
function pixelCost(zones, px, py, mapMeta = null) {
|
||||
const hits = zonesAtPoint(zones, px, py, mapMeta);
|
||||
if (hits.some((z) => z.type === TYPES.forbidden)) return COST.forbidden;
|
||||
if (hits.some((z) => z.type === TYPES.unpreferred)) return COST.unpreferred;
|
||||
if (hits.some((z) => z.type === TYPES.preferred)) return COST.preferred;
|
||||
return COST.neutral;
|
||||
}
|
||||
|
||||
function classifyPoint(zones, px, py) {
|
||||
const hits = zonesAtPoint(zones, px, py);
|
||||
function classifyPoint(zones, px, py, mapMeta = null) {
|
||||
const hits = zonesAtPoint(zones, px, py, mapMeta);
|
||||
return {
|
||||
forbidden: hits.some((z) => z.type === TYPES.forbidden),
|
||||
preferred: hits.some((z) => z.type === TYPES.preferred),
|
||||
unpreferred: hits.some((z) => z.type === TYPES.unpreferred),
|
||||
zones: hits,
|
||||
cost: pixelCost(zones, px, py),
|
||||
cost: pixelCost(zones, px, py, mapMeta),
|
||||
};
|
||||
}
|
||||
|
||||
function isPathBlocked(zones, pathPoints) {
|
||||
function isPathBlocked(zones, pathPoints, mapMeta = null) {
|
||||
const pts = Array.isArray(pathPoints) ? pathPoints : [];
|
||||
return pts.some((p) => pixelCost(zones, p.x, p.y) === COST.forbidden);
|
||||
return pts.some((p) => pixelCost(zones, p.x, p.y, mapMeta) === COST.forbidden);
|
||||
}
|
||||
|
||||
function pathCost(zones, pathPoints) {
|
||||
function pathCost(zones, pathPoints, mapMeta = null) {
|
||||
const pts = Array.isArray(pathPoints) ? pathPoints : [];
|
||||
let sum = 0;
|
||||
for (const p of pts) {
|
||||
const c = pixelCost(zones, p.x, p.y);
|
||||
const c = pixelCost(zones, p.x, p.y, mapMeta);
|
||||
if (!Number.isFinite(c)) return Infinity;
|
||||
sum += c;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user