Reroute (↪): only detour when a nogo is actually ahead on the route
The button built a detour unconditionally and picked the target from the globally
nearest route point + 1500m, which on loops/off-route jumped to the start ('first
waypoint'). Now: find current progress on the route, use the compass bearing to pick
travel direction, and only reroute when a nogo sits on the route ahead within a
lookahead window - else toast 'впереди затыка нет'. Target is the first point clear
of nogos past the blockage.
This commit is contained in:
parent
80ddff9b72
commit
ac37f36a06
1 changed files with 46 additions and 15 deletions
|
|
@ -3603,25 +3603,54 @@ function _offsetLatLon(lat, lon, brDeg, d) {
|
|||
// sits on the route (<=150 m), else the current position's nearest route point. Target = a
|
||||
// route point ~1.5 km further along; on failure step further (up to the route end).
|
||||
// Returns { points:[{lat,lon}], target:{lat,lon} } or null.
|
||||
// Reroute back onto the active route PAST a blockage ahead. Only acts when a nogo
|
||||
// actually sits on the route ahead of the current progress point (in the travel
|
||||
// direction) — otherwise returns {noBlockage:true} and builds nothing (pressing it
|
||||
// with no blockage used to route to a bogus far point). Returns {points,target} on
|
||||
// success, null if a detour couldn't be built, {noBlockage:true} if nothing to do.
|
||||
async function rejoinReroute(cur, bearingDeg, routePts, nogos) {
|
||||
if (!cur || !routePts || routePts.length < 2) return null;
|
||||
let cum = [0];
|
||||
for (let i = 1; i < routePts.length; i++) cum[i] = cum[i-1] + GPS.distance(routePts[i-1].lat, routePts[i-1].lon, routePts[i].lat, routePts[i].lon);
|
||||
let nearestRouteDist = (pt) => { let d = Infinity; for (let p of routePts) { let dd = GPS.distance(pt.lat, pt.lon, p.lat, p.lon); if (dd < d) d = dd; } return d; };
|
||||
// reference point of the blockage
|
||||
let ref = cur;
|
||||
if (nogos && nogos.length) {
|
||||
let best = null, bestD = Infinity;
|
||||
for (let n of nogos) if (nearestRouteDist(n) <= 150) { let dc = GPS.distance(cur.lat, cur.lon, n.lat, n.lon); if (dc < bestD) { bestD = dc; best = n; } }
|
||||
if (best) ref = best;
|
||||
let inNogo = (p) => nogos && nogos.some(n => GPS.distance(p.lat, p.lon, n.lat, n.lon) <= (n.radius || 25) + 15);
|
||||
|
||||
// current progress = nearest route point to the current position
|
||||
let curIdx = 0, curD = Infinity;
|
||||
for (let i = 0; i < routePts.length; i++) { let d = GPS.distance(cur.lat, cur.lon, routePts[i].lat, routePts[i].lon); if (d < curD) { curD = d; curIdx = i; } }
|
||||
|
||||
// travel direction along the route: increasing index unless the compass bearing
|
||||
// clearly points the other way (handles routes ridden in reverse / loops).
|
||||
let step = 1;
|
||||
if (bearingDeg != null && !isNaN(bearingDeg)) {
|
||||
let ja = Math.min(routePts.length - 1, curIdx + 1), jb = Math.max(0, curIdx - 1);
|
||||
if (ja !== jb) {
|
||||
let fb = GPS.bearing(routePts[jb].lat, routePts[jb].lon, routePts[ja].lat, routePts[ja].lon);
|
||||
let diff = Math.abs(((bearingDeg - fb + 540) % 360) - 180); // 0 = aligned w/ increasing idx, 180 = opposite
|
||||
if (diff > 90) step = -1; // travelling against increasing index → forward is decreasing idx
|
||||
}
|
||||
}
|
||||
let refIdx = 0, refD = Infinity;
|
||||
for (let i = 0; i < routePts.length; i++) { let d = GPS.distance(ref.lat, ref.lon, routePts[i].lat, routePts[i].lon); if (d < refD) { refD = d; refIdx = i; } }
|
||||
|
||||
// blockage: first route point within a nogo AHEAD, within a lookahead window
|
||||
const LOOKAHEAD = 2500;
|
||||
let blocked = null;
|
||||
for (let i = curIdx; i >= 0 && i < routePts.length; i += step) {
|
||||
if (Math.abs(cum[i] - cum[curIdx]) > LOOKAHEAD) break;
|
||||
if (inNogo(routePts[i])) { blocked = i; break; }
|
||||
}
|
||||
if (blocked == null) return { noBlockage: true };
|
||||
|
||||
// rejoin target: first route point clear of every nogo AND >= margin past the blockage
|
||||
const CLEAR_MARGIN = 300;
|
||||
let ti = blocked;
|
||||
while (ti >= 0 && ti < routePts.length) {
|
||||
if (!inNogo(routePts[ti]) && Math.abs(cum[ti] - cum[blocked]) >= CLEAR_MARGIN) break;
|
||||
ti += step;
|
||||
}
|
||||
if (ti < 0 || ti >= routePts.length) ti = step > 0 ? routePts.length - 1 : 0;
|
||||
|
||||
let helper = (bearingDeg != null && !isNaN(bearingDeg)) ? _offsetLatLon(cur.lat, cur.lon, bearingDeg, 40) : null;
|
||||
let skip = 1500;
|
||||
for (let attempt = 0; attempt < 8; attempt++) {
|
||||
let want = cum[refIdx] + skip, ti = refIdx;
|
||||
while (ti < routePts.length - 1 && cum[ti] < want) ti++;
|
||||
let jump = Math.max(1, Math.round(routePts.length / 50));
|
||||
for (let attempt = 0; attempt < 6; attempt++) {
|
||||
let target = routePts[ti];
|
||||
let straight = GPS.distance(cur.lat, cur.lon, target.lat, target.lon);
|
||||
let wps = helper ? [[cur.lon, cur.lat], [helper.lon, helper.lat], [target.lon, target.lat]] : [[cur.lon, cur.lat], [target.lon, target.lat]];
|
||||
|
|
@ -3633,8 +3662,9 @@ async function rejoinReroute(cur, bearingDeg, routePts, nogos) {
|
|||
if (rlen <= Math.max(500, straight * 3)) return { points: rp.map(p => ({ lat: p.lat, lon: p.lon })), target: { lat: target.lat, lon: target.lon } };
|
||||
}
|
||||
} catch (e) { /* try a further rejoin point */ }
|
||||
if (ti >= routePts.length - 1) break;
|
||||
skip += 1500;
|
||||
let next = ti + step * jump;
|
||||
if (next < 0 || next >= routePts.length) break;
|
||||
ti = next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -5132,6 +5162,7 @@ async function renderRecordingInline(container) {
|
|||
let ng = await getNogosForRouter();
|
||||
let bearing = (typeof smoothedHeading === "number") ? smoothedHeading : null;
|
||||
let res = await rejoinReroute(cur, bearing, route.points, ng);
|
||||
if (res && res.noBlockage) { showToast("Впереди затыка нет (нет nogo на маршруте)"); rerouteBtn.classList.remove("active"); return; }
|
||||
if (!res) { showToast("Объезд не найден"); rerouteBtn.classList.remove("active"); return; }
|
||||
if (rerouteLayer) { map.removeLayer(rerouteLayer); rerouteLayer = null; }
|
||||
let ll = res.points.map(p => [p.lat, p.lon]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue