/** * המרות קואורדינטות: רשת ישראל החדשה (ITM / EPSG:2039) ↔ WGS84, * זיהוי אוטומטי של מערכת הקואורדינטות של השרטוט, וכיול ידני * (טרנספורמציית Helmert דו-ממדית משתי נקודות עיגון). */ (function (global) { "use strict"; var ITM = "EPSG:2039"; var WGS = "EPSG:4326"; var ITM_DEF = "+proj=tmerc +lat_0=31.734393611 +lon_0=35.204516944 +k=1.0000067 " + "+x_0=219529.584 +y_0=626907.39 +ellps=GRS80 " + "+towgs84=-24.0024,-17.1032,-17.8444,-0.33077,-1.85269,1.66969,5.4262 " + "+units=m +no_defs"; proj4.defs(ITM, ITM_DEF); // תחום רשת ישראל החדשה (בקירוב, כולל שוליים) var ITM_BOUNDS = { minX: 100000, maxX: 330000, minY: 340000, maxY: 830000 }; function looksLikeITM(bbox) { if (!bbox) return false; return bbox.minX >= ITM_BOUNDS.minX && bbox.maxX <= ITM_BOUNDS.maxX && bbox.minY >= ITM_BOUNDS.minY && bbox.maxY <= ITM_BOUNDS.maxY; } /** * זיהוי מערכת קואורדינטות לפי *רוב* הישויות + סינון חריגים. * קבצים אמיתיים מכילים לפעמים רשומות בודדות עם קואורדינטות שבורות * (הרחק מרשת ישראל) שמפוצצות את ה-bbox ושוברות זיהוי לפי קצוות. * אם ‎≥90% מהישויות בתחום ITM — הקובץ נחשב ITM והחריגים נזרקים. */ function sanitizeParsed(parsed) { function ptIn(p) { return p[0] >= ITM_BOUNDS.minX && p[0] <= ITM_BOUNDS.maxX && p[1] >= ITM_BOUNDS.minY && p[1] <= ITM_BOUNDS.maxY; } function entIn(e) { var pts = e.pts || (e.pt ? [e.pt] : []); for (var i = 0; i < pts.length; i++) if (!ptIn(pts[i])) return false; return pts.length > 0; } var ents = parsed.entities || []; var inCount = 0; ents.forEach(function (e) { if (entIn(e)) inCount++; }); if (ents.length && inCount / ents.length >= 0.9) { var kept = inCount === ents.length ? ents : ents.filter(entIn); return { coordSys: "itm", entities: kept, bbox: global.DXF.bbox(kept), dropped: ents.length - kept.length, }; } return { coordSys: looksLikeITM(parsed.bbox) ? "itm" : "unplaced", entities: ents, bbox: parsed.bbox, dropped: 0, }; } function itmToWgs(pt) { var r = proj4(ITM, WGS, [pt[0], pt[1]]); return [r[1], r[0]]; // Leaflet: [lat, lng] } function wgsToItm(latlng) { return proj4(WGS, ITM, [latlng[1], latlng[0]]); // [E, N] } /** * Helmert דו-ממדי (דמיון: קנה-מידה + סיבוב + הזזה) משתי נקודות: * src (קואורדינטות שרטוט) → dst (ITM במטרים). * מחזיר פונקציה pt→pt או null אם הנקודות מנוונות. */ function helmertFrom2(src1, dst1, src2, dst2) { var sx = src2[0] - src1[0], sy = src2[1] - src1[1]; var dx = dst2[0] - dst1[0], dy = dst2[1] - dst1[1]; var d2 = sx * sx + sy * sy; if (d2 < 1e-12) return null; // z_dst = a*z_src + b (מרוכבים): a = dz/sz var a_re = (dx * sx + dy * sy) / d2; var a_im = (dy * sx - dx * sy) / d2; var b_re = dst1[0] - (a_re * src1[0] - a_im * src1[1]); var b_im = dst1[1] - (a_im * src1[0] + a_re * src1[1]); var fn = function (pt) { return [ a_re * pt[0] - a_im * pt[1] + b_re, a_im * pt[0] + a_re * pt[1] + b_im, ]; }; fn.params = { a_re: a_re, a_im: a_im, b_re: b_re, b_im: b_im }; fn.scale = Math.sqrt(a_re * a_re + a_im * a_im); fn.rotationDeg = Math.atan2(a_im, a_re) * 180 / Math.PI; return fn; } function helmertFromParams(p) { return function (pt) { return [ p.a_re * pt[0] - p.a_im * pt[1] + p.b_re, p.a_im * pt[0] + p.a_re * pt[1] + p.b_im, ]; }; } /** * בונה פונקציית טרנספורמציה שרטוט→ITM ‏[E,N] לפי מצב הקובץ: * - 'itm': הקואורדינטות כבר ב-ITM (זהות) * - 'calibrated': Helmert (params) → ITM * - 'unplaced': הנחה זמנית — ממקם את השרטוט סביב נקודת עוגן * (עד שהמשתמש יכייל), שומר יחידות מטרים 1:1. */ function buildItmTransform(file, fallbackAnchorItm) { if (file.coordSys === "itm") return function (pt) { return pt; }; if (file.coordSys === "calibrated" && file.calibration) { return helmertFromParams(file.calibration); } // unplaced: מרכז ה-bbox → עוגן, יחידה=מטר var b = file.bbox; var cx = (b.minX + b.maxX) / 2, cy = (b.minY + b.maxY) / 2; var anchor = fallbackAnchorItm || [219529, 626907]; // ירושלים כברירת מחדל // אם השרטוט ענק ביחידות לא-מטריות, מכווצים לק"מ אחד var w = Math.max(b.maxX - b.minX, b.maxY - b.minY, 1); var scale = w > 50000 ? 1000 / w : 1; return function (pt) { return [anchor[0] + (pt[0] - cx) * scale, anchor[1] + (pt[1] - cy) * scale]; }; } /** שרטוט → [lat,lng] (להצגה ב-Leaflet) */ function buildTransform(file, fallbackAnchorItm) { var toItm = buildItmTransform(file, fallbackAnchorItm); if (file.coordSys === "itm") return itmToWgs; return function (pt) { return itmToWgs(toItm(pt)); }; } global.Geo = { ITM: ITM, ITM_DEF: ITM_DEF, looksLikeITM: looksLikeITM, sanitizeParsed: sanitizeParsed, itmToWgs: itmToWgs, wgsToItm: wgsToItm, helmertFrom2: helmertFrom2, buildTransform: buildTransform, buildItmTransform: buildItmTransform, }; })(window);