Fix catenary layer toggles, tooltip collision, side rail rendering, and typed interruption signs
Deploy & Release / build-and-deploy (push) Failing after 14s

This commit is contained in:
m4xx1m committed 2026-10-21 05:12:42 +03:00
1 parent 68d5058106
commit 0301fde1a9
5 files changed
+202 -91

No files matched your search

+90 -48
View File
@@ -565,6 +565,35 @@ export function testTooltip(cursorX, cursorY){
}
if(finalTooltip != '') return finalTooltip;
// 1. Catenary Point badges (substations, neutrals, interruptions) with clamped screen radius
if(layers.catenary && layers.catenarySubstations && view.scale >= 0.012){
let subRadius = Math.min(22 / view.scale, 40);
for(const sub of catenarySubstations){
if(Math.pow(sub.x - cursorX, 2) + Math.pow(sub.z - cursorY, 2) <= subRadius * subRadius){
return sub.tooltip;
}
}
}
if(layers.catenary && layers.catenaryNeutrals && view.scale >= 0.012){
let neutralRadius = Math.min(30 / view.scale, 45);
for(const n of catenaryNeutrals){
if(Math.pow(n.center.x - cursorX, 2) + Math.pow(n.center.z - cursorY, 2) <= neutralRadius * neutralRadius){
return n.tooltip;
}
}
}
if(layers.catenary && layers.catenaryInterruptions && view.scale >= 0.018){
let interRadius = Math.min(18 / view.scale, 35);
for(const inter of catenaryInterruptions){
if(Math.pow(inter.center.x - cursorX, 2) + Math.pow(inter.center.z - cursorY, 2) <= interRadius * interRadius){
return inter.tooltip;
}
}
}
// 2. Static Markers (stations, POIs, speed signs, grade arrows, yards)
for(const marker of markers){
if(!marker.visible) continue;
if(marker.boundsCheck != null){
@@ -591,38 +620,35 @@ export function testTooltip(cursorX, cursorY){
}
if(finalTooltip != '') return finalTooltip;
if(layers.catenary && layers.catenarySubstations){
for(const sub of catenarySubstations){
let radius = 24 / view.scale;
if(Math.pow(sub.x - cursorX, 2) + Math.pow(sub.z - cursorY, 2) <= radius * radius){
return sub.tooltip;
// 2. Rail tracks curve check
let bestDistance = Infinity;
let trackTooltip = '';
let boundsPadding = 40 / view.scale;
for(const railTrack of railTracks){
if(cursorX >= railTrack.bounds.min.x - boundsPadding && cursorX <= railTrack.bounds.max.x + boundsPadding && cursorY >= railTrack.bounds.min.z - boundsPadding && cursorY <= railTrack.bounds.max.z + boundsPadding){
for(const curve of railTrack.curves){
if(cursorX >= curve.bounds.min.x - boundsPadding && cursorX <= curve.bounds.max.x + boundsPadding && cursorY >= curve.bounds.min.z - boundsPadding && cursorY <= curve.bounds.max.z + boundsPadding){
let test = Bezier.getNearestPoint2D(curve.start, curve.h1, curve.h2, curve.end, {x:cursorX, y:cursorY}, Math.floor(curve.length*2));
if(test.distance < bestDistance){
bestDistance = test.distance;
trackTooltip = curve.tooltip;
testPoint = test.point;
}
}
}
}
}
let trackHit = bestDistance <= Math.min(Math.max(0.9, 12 / view.scale), 120);
if(layers.catenary && layers.catenaryNeutrals){
for(const n of catenaryNeutrals){
let radius = 35 / view.scale;
if(Math.pow(n.center.x - cursorX, 2) + Math.pow(n.center.z - cursorY, 2) <= radius * radius){
return n.tooltip;
}
}
}
if(layers.catenary && layers.catenaryInterruptions){
for(const inter of catenaryInterruptions){
let radius = 24 / view.scale;
if(Math.pow(inter.center.x - cursorX, 2) + Math.pow(inter.center.z - cursorY, 2) <= radius * radius){
return inter.tooltip;
}
}
}
if(layers.catenary && layers.catenaryWires){
// 3. Catenary wire check
let wireTooltip = '';
let wireTooltipCompact = '';
if(layers.catenary && (layers.catenaryWires || layers.catenaryNeutrals)){
let bestWireDistSq = Infinity;
let wireTooltip = '';
let wireBoundsPadding = 25 / view.scale;
for(const poly of catenaryPolylines){
if(poly.is_neutral && !layers.catenaryNeutrals) continue;
if(!poly.is_neutral && !layers.catenaryWires) continue;
let b = poly.bounds;
if(cursorX >= b[0] - wireBoundsPadding && cursorX <= b[2] + wireBoundsPadding && cursorY >= b[1] - wireBoundsPadding && cursorY <= b[3] + wireBoundsPadding){
let pts = poly.points;
@@ -631,35 +657,30 @@ export function testTooltip(cursorX, cursorY){
if(d2 < bestWireDistSq){
bestWireDistSq = d2;
wireTooltip = poly.tooltip;
wireTooltipCompact = poly.tooltipCompact || poly.tooltip;
}
}
}
}
let maxWireDist = Math.min(Math.max(1.2, 12 / view.scale), 80);
if(bestWireDistSq <= maxWireDist * maxWireDist){
return wireTooltip;
let maxWireDist = Math.min(Math.max(1.2, 12 / view.scale), 50);
if(bestWireDistSq > maxWireDist * maxWireDist){
wireTooltip = '';
wireTooltipCompact = '';
}
}
let bestDistance = Infinity;
let test = {};
let boundsPadding = 40/view.scale;
for(const railTrack of railTracks){
if(cursorX >= railTrack.bounds.min.x - boundsPadding && cursorX <= railTrack.bounds.max.x + boundsPadding && cursorY >= railTrack.bounds.min.z - boundsPadding && cursorY <= railTrack.bounds.max.z + boundsPadding){
for(const curve of railTrack.curves){
if(cursorX >= curve.bounds.min.x - boundsPadding && cursorX <= curve.bounds.max.x + boundsPadding && cursorY >= curve.bounds.min.z - boundsPadding && cursorY <= curve.bounds.max.z + boundsPadding){
test = Bezier.getNearestPoint2D(curve.start, curve.h1, curve.h2, curve.end, {x:cursorX, y:cursorY}, Math.floor(curve.length*2));
if(test.distance < bestDistance){
bestDistance = test.distance;
finalTooltip = curve.tooltip;
testPoint = test.point;
}
}
}
}
// 4. Combined or individual resolution
if(trackHit && wireTooltipCompact){
return `${trackTooltip}\n<hr style="margin: 4px 0;">\n${wireTooltipCompact}`;
}
if(trackHit){
return trackTooltip;
}
if(wireTooltip){
return wireTooltip;
}
return bestDistance <= Math.min(Math.max(0.9, 12/view.scale), 120) ? finalTooltip : '';
return '';
}
export function setTrackColorMode(mode){
@@ -797,9 +818,27 @@ export function addCatenaryData(data){
}
for(const inter of catenaryInterruptions){
inter.tooltip = `<h1>⤓ Прерывание контактной сети</h1>` +
`Знаки: ${(inter.signs || []).join(', ')}\n` +
`Внимание: Опустить токоприемники (Drop Pantographs)!`;
let hasDrop = (inter.signs || []).some(s => s.includes('Drop') && !s.includes('Warning'));
let hasRaise = (inter.signs || []).some(s => s.includes('Raise'));
let hasWarn = (inter.signs || []).some(s => s.includes('Warning'));
let title = '⤓ Прерывание контактной сети';
let action = 'Опустить токоприемники (Drop Pantographs)!';
if(hasWarn && !hasDrop && !hasRaise){
title = '⚠ Предупреждение: Разрыв контактной сети';
action = 'Внимание: Подготовиться к опусканию токоприемников (Drop Warning ahead)!';
inter.kind = 'warning';
} else if(hasRaise && !hasDrop){
title = '⤒ Конец прерывания контактной сети';
action = 'Конец обесточенного участка: Поднять токоприемники (Raise Pantographs)!';
inter.kind = 'raise';
} else {
inter.kind = 'drop';
}
inter.tooltip = `<h1>${title}</h1>` +
`Действие: ${action}\n` +
`Знаки: ${(inter.signs || []).join(', ')}`;
}
for(const p of catenaryPolylines){
@@ -814,6 +853,9 @@ export function addCatenaryData(data){
`Тип подвески: ${catDesc}\n` +
`Тяговая подстанция: ${p.substation}\n` +
`Длина участка: ${p.length} м (${p.wire_count} звеньев)`;
p.tooltipCompact = `<div style="font-weight:bold;color:${p.is_neutral ? '#e63946' : '#00d2ff'}">⚡ Контактная сеть: ${p.is_neutral ? 'Токораздел (0 В)' : p.voltage + ' В DC'}</div>` +
`Подвеска: ${catDesc}\nПодстанция: ${p.substation} | Длина: ${p.length} м`;
}
setCatenaryColorMode(catenaryColorMode);