1/* assets/planner/region-router.js */ 2(function () { 3 "use strict"; 4 5 function num(v) { 6 const n = Number(v); 7 return Number.isFinite(n) ? n : null; 8 } 9 10 function inBbox(lat, lng, b) { 11 if (!b) return false; 12 const minLat = num(b.minLat), maxLat = num(b.maxLat); 13 const minLng = num(b.minLng), maxLng = num(b.maxLng); 14 if (minLat === null || maxLat === null || minLng === null || maxLng === null) return false; 15 return lat >= minLat && lat <= maxLat && lng >= minLng && lng <= maxLng; 16 } 17 18 // Robustnà detekce: 19 // 1) preferuj FINISH (nejÄastÄjšà oÄekávánÃ) 20 // 2) pak START 21 // 3) pak centroid (fallback) 22 // 4) a jako pojistka: pokud centroid nevycházÃ, zkus "any-point match" 23 function detect(points, defaultRegion, regionBounds) { 24 try { 25 const fallback = (defaultRegion || "cee").toString(); 26 const bounds = (regionBounds && typeof regionBounds === "object") ? regionBounds : {}; 27 const keys = Object.keys(bounds); 28 29 if (!Array.isArray(points) || points.length < 1 || keys.length < 1) return fallback; 30 31 // --- helpers --- 32 function getLatLng(p) { 33 if (!p) return null; 34 const lat = num(p.lat); 35 const lng = num((p.lng !== undefined) ? p.lng : p.lon); 36 if (lat === null || lng === null) return null; 37 return { lat, lng }; 38 } 39 40 function bboxNums(b) { 41 if (!b) return null; 42 const minLat = num(b.minLat), maxLat = num(b.maxLat); 43 const minLng = num(b.minLng), maxLng = num(b.maxLng); 44 if (minLat === null || maxLat === null || minLng === null || maxLng === null) return null; 45 return { minLat, maxLat, minLng, maxLng }; 46 } 47 48 function marginInside(lat, lng, bb) { 49 // vracà >=0 pouze když je bod uvnitÅ; ÄÃm vyššÃ, tÃm vÃc "uvnitÅ" 50 if (lat < bb.minLat || lat > bb.maxLat || lng < bb.minLng || lng > bb.maxLng) return -1; 51 return Math.min( 52 lat - bb.minLat, 53 bb.maxLat - lat, 54 lng - bb.minLng, 55 bb.maxLng - lng 56 ); 57 } 58 59 function distToBbox(lat, lng, bb) { 60 // vzdálenost bodu k obdélnÃku (0 pokud uvnitÅ) 61 const dLat = (lat < bb.minLat) ? (bb.minLat - lat) : (lat > bb.maxLat ? (lat - bb.maxLat) : 0); 62 const dLng = (lng < bb.minLng) ? (bb.minLng - lng) : (lng > bb.maxLng ? (lng - bb.maxLng) : 0); 63 return Math.hypot(dLat, dLng); 64 } 65 66 // normalizuj body 67 const pts = []; 68 for (const p of points) { 69 const ll = getLatLng(p); 70 if (ll) pts.push(ll); 71 } 72 if (!pts.length) return fallback; 73 74 // referenÄnà bod: START = prvnà validnà bod 75 const start = pts[0]; 76 const finish = pts[pts.length - 1]; 77 78 // pÅedpoÄÃtej bbox ÄÃsla 79 const bboxMap = {}; 80 for (const slug of keys) { 81 const bb = bboxNums(bounds[slug]); 82 if (bb) bboxMap[String(slug)] = bb; 83 } 84 const slugs = Object.keys(bboxMap); 85 if (!slugs.length) return fallback; 86 87 // --- scoring --- 88 // váhy: START a FINISH majà vÄtšà váhu než VIA 89 // (nepÅepÃná to chaoticky pÅi pÅidánà VIA) 90 const scores = {}; 91 const bestMargin = {}; 92 93 function addVote(slug, weight, margin) { 94 scores[slug] = (scores[slug] || 0) + weight; 95 const m = (margin > 0 ? margin : 0); 96 bestMargin[slug] = Math.max(bestMargin[slug] || 0, m); 97 // malé zvýhodnÄnà "hloubky uvnitÅ" (aby v pÅekryvu nevyhrál region jen poÅadÃm) 98 scores[slug] += m * 0.01; 99 } 100 101 // START (váha 3) 102 for (const slug of slugs) { 103 const bb = bboxMap[slug]; 104 const m = marginInside(start.lat, start.lng, bb); 105 if (m >= 0) addVote(slug, 3, m); 106 } 107 108 // FINISH (váha 3) 109 if (finish && (finish.lat !== start.lat || finish.lng !== start.lng)) { 110 for (const slug of slugs) { 111 const bb = bboxMap[slug]; 112 const m = marginInside(finish.lat, finish.lng, bb); 113 if (m >= 0) addVote(slug, 3, m); 114 } 115 } 116 117 // VIA body (váha 1) 118 if (pts.length > 2) { 119 for (let i = 1; i < pts.length - 1; i++) { 120 const p = pts[i]; 121 for (const slug of slugs) { 122 const bb = bboxMap[slug]; 123 const m = marginInside(p.lat, p.lng, bb); 124 if (m >= 0) addVote(slug, 1, m); 125 } 126 } 127 } 128 129 // 1) pokud máme alespoÅ jeden hit, vyber nejlepšà score 130 let bestSlug = null; 131 let bestScore = -Infinity; 132 for (const slug of slugs) { 133 const s = (scores[slug] !== undefined) ? scores[slug] : -Infinity; 134 if (s > bestScore) { 135 bestScore = s; 136 bestSlug = slug; 137 } 138 } 139 if (bestSlug && Number.isFinite(bestScore) && bestScore > -Infinity) { 140 // pokud vůbec nebyl žádný bod uvnitŠžádného bboxu, score zůstane -Infinity 141 if (scores[bestSlug] !== undefined) return bestSlug; 142 } 143 144 // 2) pojistka proti "hluchému mÃstu": vyber nejbližšà bbox podle START 145 let nearest = null; 146 let nearestD = Infinity; 147 for (const slug of slugs) { 148 const d = distToBbox(start.lat, start.lng, bboxMap[slug]); 149 if (d < nearestD) { 150 nearestD = d; 151 nearest = slug; 152 } 153 } 154 return nearest || fallback; 155 } catch (e) { 156 return (defaultRegion || "cee").toString(); 157 } 158} 159
160function detectWithMeta(points, defaultRegion, regionBounds) { 161 const primary = detect(points, defaultRegion, regionBounds); 162 163 // zjisti, zda je START uvnitÅ alespoÅ jednoho bboxu 164 let inCoverage = false; 165 let start = null; 166 167 if (Array.isArray(points) && points.length) { 168 for (const p of points) { 169 if (!p) continue; 170 const lat = num(p.lat); 171 const lng = num((p.lng !== undefined) ? p.lng : p.lon); 172 if (lat !== null && lng !== null) { 173 start = { lat, lng }; 174 break; 175 } 176 } 177 } 178 179 if (start) { 180 for (const slug in regionBounds) { 181 const b = regionBounds[slug]; 182 const minLat = num(b.minLat), maxLat = num(b.maxLat); 183 const minLng = num(b.minLng), maxLng = num(b.maxLng); 184 if ( 185 minLat !== null && maxLat !== null && 186 minLng !== null && maxLng !== null && 187 start.lat >= minLat && start.lat <= maxLat && 188 start.lng >= minLng && start.lng <= maxLng 189 ) { 190 inCoverage = true; 191 break; 192 } 193 } 194 } 195 196 return { 197 primary: primary, 198 inCoverage: inCoverage 199 }; 200} 201 202 window.RBG_REGION_ROUTER = window.RBG_REGION_ROUTER || {}; 203 window.RBG_REGION_ROUTER.detect = detect; 204 window.RBG_REGION_ROUTER.detectWithMeta = detectWithMeta; 205 206})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.