This commit is contained in:
33333-33333 2026-05-29 23:49:02 +09:00
commit 440dba2f09
5 changed files with 2626 additions and 347 deletions

View file

@ -645,6 +645,71 @@ function getDisplayBorderSegments(map, fieldName, precomputedSegments, mode) {
return Array.isArray(precomputedSegments) ? precomputedSegments : [];
}
function borderSegmentMidpoint(seg) {
return { x: ((seg?.[0]?.[0] || 0) + (seg?.[1]?.[0] || 0)) * 0.5, y: ((seg?.[0]?.[1] || 0) + (seg?.[1]?.[1] || 0)) * 0.5 };
}
function borderSegmentOrientation(seg) {
return Math.atan2((seg?.[1]?.[1] || 0) - (seg?.[0]?.[1] || 0), (seg?.[1]?.[0] || 0) - (seg?.[0]?.[0] || 0));
}
function borderAngleDistance(a, b) {
let d = Math.abs(a - b) % Math.PI;
if (d > Math.PI / 2) d = Math.PI - d;
return d;
}
function borderPointSegmentDistance(px, py, ax, ay, bx, by) {
const dx = bx - ax, dy = by - ay;
const len2 = dx * dx + dy * dy;
if (len2 <= 1e-9) return Math.hypot(px - ax, py - ay);
const t = Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / len2));
return Math.hypot(px - (ax + dx * t), py - (ay + dy * t));
}
function borderSegmentsNear(a, b, tolerance = 1.35) {
if (!a || !b) return false;
if (borderAngleDistance(borderSegmentOrientation(a), borderSegmentOrientation(b)) > 0.72) return false;
const am = borderSegmentMidpoint(a);
const bm = borderSegmentMidpoint(b);
if (Math.hypot(am.x - bm.x, am.y - bm.y) <= tolerance) return true;
const ax = a?.[0]?.[0] || 0, ay = a?.[0]?.[1] || 0;
const bx = a?.[1]?.[0] || 0, by = a?.[1]?.[1] || 0;
const cx = b?.[0]?.[0] || 0, cy = b?.[0]?.[1] || 0;
const dx = b?.[1]?.[0] || 0, dy = b?.[1]?.[1] || 0;
return Math.min(
borderPointSegmentDistance(ax, ay, cx, cy, dx, dy),
borderPointSegmentDistance(bx, by, cx, cy, dx, dy),
borderPointSegmentDistance(cx, cy, ax, ay, bx, by),
borderPointSegmentDistance(dx, dy, ax, ay, bx, by)
) <= tolerance;
}
function suppressMunicipalBordersNearPrefectures(adminSegments, prefectureSegments) {
if (!adminSegments?.length || !prefectureSegments?.length) return adminSegments || [];
const tolerance = 1.35;
const cellSize = tolerance;
const grid = new Map();
const cell = (v) => Math.floor(v / cellSize);
for (const seg of prefectureSegments) {
const m = borderSegmentMidpoint(seg);
const key = `${cell(m.x)},${cell(m.y)}`;
const bucket = grid.get(key) || [];
bucket.push(seg);
grid.set(key, bucket);
}
const out = [];
for (const seg of adminSegments) {
const m = borderSegmentMidpoint(seg);
const gx = cell(m.x), gy = cell(m.y);
let near = false;
for (let yy = gy - 2; yy <= gy + 2 && !near; yy++) {
for (let xx = gx - 2; xx <= gx + 2 && !near; xx++) {
for (const pref of grid.get(`${xx},${yy}`) || []) {
if (borderSegmentsNear(seg, pref, tolerance)) { near = true; break; }
}
}
}
if (!near) out.push(seg);
}
return out;
}
function drawRiverPath(ctx, map, path, color, widthFn, alpha = 1) {
if (!path || path.length < 2) return;
ctx.save();
@ -1123,8 +1188,9 @@ export function drawMap(canvas, map, options) {
const showPrefectureRegions = ["all", "admin", "borders-debug"].includes(mode);
if (showPrefectureRegions) drawPrefectureRegionFill(ctx, map, mode);
const adminBorderSegments = getDisplayBorderSegments(map, "adminId", map.adminBorders, mode);
const prefectureBorderSegments = getDisplayBorderSegments(map, "prefectureRegionId", map.regionalPrefectureBorders, mode);
const rawAdminBorderSegments = getDisplayBorderSegments(map, "adminId", map.adminBorders, mode);
const adminBorderSegments = mode === "borders-debug" ? rawAdminBorderSegments : suppressMunicipalBordersNearPrefectures(rawAdminBorderSegments, prefectureBorderSegments);
if (showAdmin && adminBorderSegments?.length) {
drawVectorSegments(ctx, adminBorderSegments, "rgba(255, 255, 255, 0.8)", 2.8, false, { iterations: 1, tolerance: 0.05, offsetX: -0.5, offsetY: -0.5 });
drawVectorSegments(ctx, adminBorderSegments, "rgba(150, 140, 150, 0.9)", 1.2, true, { iterations: 1, tolerance: 0.05, offsetX: -0.5, offsetY: -0.5 });