/** * שיוך נכסים לבלוקי DRAFT — ישירות מהמפה, כתחליף לשלב OPTASGN באוטוקאד. * * זרימת העבודה (כמו OPTASGN, רק בטאצ'): * 1. מפזרים בלוקי DRAFT — ידנית בהקשה, או אוטומטית ליד כל עמוד/ארון * במפה (בלוקי POLE/ZPOLE/ZBOX/BOX-U מהשרטוט). * 2. במצב "שיוך": מקישים על בלוק (נבחר ומודגש) ואז על נכסים — כל * הקשה נצמדת לטקסט הכתובת הקרוב (ADDR_IBC / ADDR_NAME_NEW) ומותחת * קו שיוך. הקשה ליד בלוק אחר עוברת אליו — בדיוק כמו בפקודה. * 3. ייצוא DXF (R12, רשת ישראל): בלוקי OPTECH_DRAFT + קווי * OPTECH_ASSIGN — מדביקים בסקיצה באוטוקאד וממשיכים ל-OPTFIB; * dxf2complete קורא את זה כמו סקיצה רגילה. * * בלוק שפוזר אוטומטית ולא שויך אליו אף נכס לא מיוצא — כדי לא לזהם את * הסקיצה בקלוז'רים מדומים (בלוק בלי נכסים מסווג קלוז'ר). בלוק שהונח * ידנית מיוצא תמיד (כך מציבים קלוז'רים משניים בכוונה). */ (function (global) { "use strict"; var ASSIGN_ID = "assign_default"; /** שכבות טקסטי נכסים שאליהן נצמדת הקשת-שיוך */ var ADDR_LAYERS = ["ADDR_IBC", "ADR_IBC_LOKAYAM", "ADDR_NAME_NEW"]; /** שמות בלוקים במפת התשתית שלידם מפוזרים בלוקי DRAFT אוטומטית */ var POLE_BLOCKS = ["POLE", "ZPOLE", "ZBOX", "BOX-U"]; var SNAP_ADDR = 6; // מטרים: הקשה→טקסט כתובת (dxf2complete סובל עד 8) var SNAP_DRAFT = 8; // מטרים: הקשה→בחירת בלוק DRAFT var AUTO_OFFSET = 2; // מטרים: הזזת בלוק אוטומטי מהעמוד (שלא יסתיר אותו) var COL_DRAFT = "#e53935"; // אדום — כמו הבלוק ב-optech-draft.lsp var COL_LINK = "#d81b60"; // מג'נטה — כמו שכבת OPTECH_ASSIGN (ACI 6) var COL_ADDR = "#c62828"; // כתובת חדשה — כמו שכבת ADDR_NAME_NEW (ACI 244) function newRecord() { return { id: ASSIGN_ID, isAssign: true, name: "שיוך נכסים", addedAt: new Date().toISOString(), drafts: [], // {pt:[x,y] ITM, auto:bool, used:bool} links: [], // {a:[x,y] נכס, b:[x,y] בלוק} newAddrs: [], // {pt:[x,y], text} — כתובות שלא ברשימות (ADDR_NAME_NEW) entities: [], // נגזר מ-drafts+links+newAddrs לרינדור (rebuild) ops: [], // מחסנית פעולות ל-undo: "draft" | "link" | "addr" | {auto:n} bbox: null, coordSys: "itm", calibration: null, opacity: 1, weight: 2, visible: true, hiddenLayers: [], }; } /** בונה מחדש את ישויות הרינדור מהמצב (drafts+links+newAddrs) */ function rebuild(rec) { rec.newAddrs = rec.newAddrs || []; var ents = []; rec.drafts.forEach(function (d) { ents.push({ type: "point", layer: "OPTECH_DRAFT", pt: d.pt, color: COL_DRAFT, colorDark: COL_DRAFT }); }); rec.links.forEach(function (l) { ents.push({ type: "poly", layer: "OPTECH_ASSIGN", pts: [l.a, l.b], closed: false, color: COL_LINK, colorDark: COL_LINK }); }); rec.newAddrs.forEach(function (na) { // נקודה (נראית בכל זום) + טקסט הכתובת (נראה בהתקרבות) ents.push({ type: "point", layer: "ADDR_NAME_NEW", pt: na.pt, color: COL_ADDR, colorDark: COL_ADDR }); ents.push({ type: "text", layer: "ADDR_NAME_NEW", pt: na.pt, text: na.text, height: 1.2, rotation: 0, color: COL_ADDR, colorDark: COL_ADDR }); }); rec.entities = ents; rec.bbox = global.DXF.bbox(ents); } function dist(p, q) { var dx = p[0] - q[0], dy = p[1] - q[1]; return Math.sqrt(dx * dx + dy * dy); } /** הבלוק הקרוב ביותר לנקודה (או null אם רחוק מ-SNAP_DRAFT) */ function draftNear(rec, itm) { var best = null, bd = SNAP_DRAFT; rec.drafts.forEach(function (d) { var dd = dist(d.pt, itm); if (dd <= bd) { bd = dd; best = d; } }); return best; } /** * טקסט הכתובת הקרוב ביותר להקשה, מבין קבצי DXF טעונים ברשת ישראל. * מחזיר {pt, label} או null. */ function addrNear(files, itm) { var best = null, bd = SNAP_ADDR; files.forEach(function (f) { // שכבת השיוך עצמה נסרקת גם — הכתובות החדשות שנוספו בה הן יעד שיוך if (f.isNotes || f.coordSys !== "itm" || f.visible === false) return; (f.entities || []).forEach(function (e) { if (e.type !== "text" || ADDR_LAYERS.indexOf(e.layer) === -1) return; var dd = dist(e.pt, itm); if (dd <= bd) { bd = dd; best = { pt: e.pt, label: e.text || "" }; } }); }); return best; } /** * נקודות עמודים/ארונות מכל הקבצים הטעונים (ישויות blockref שהפרסר * משמר לבלוקים מוכרים). מחזיר [[x,y], ...] ב-ITM. */ function poleRefs(files) { var pts = []; files.forEach(function (f) { if (f.isAssign || f.isNotes || f.coordSys !== "itm") return; (f.entities || []).forEach(function (e) { if (e.type === "blockref" && POLE_BLOCKS.indexOf((e.block || "").toUpperCase()) !== -1) { pts.push(e.pt); } }); }); return pts; } /** פיזור אוטומטי: בלוק DRAFT ליד כל עמוד/ארון שאין כבר בלוק לידו */ function scatterNearPoles(rec, files) { var added = 0; poleRefs(files).forEach(function (p) { var pt = [p[0] + AUTO_OFFSET, p[1] + AUTO_OFFSET]; var exists = rec.drafts.some(function (d) { return dist(d.pt, pt) < 1; }); if (!exists) { rec.drafts.push({ pt: pt, auto: true, used: false }); added++; } }); if (added) rec.ops.push({ auto: added }); return added; } // ---------- כתיבת DXF (R12, כמו notes.js) ---------- function tag(code, value) { return code + "\n" + value + "\n"; } function fmt(v) { return (Math.round(v * 1000) / 1000).toString(); } /** עברית וכו' בסימון ‎\U+XXXX — הקובץ נשאר ASCII נקי (כמו notes.js) */ function escapeDxfText(s) { return (s || "").replace(/\n/g, " ").replace(/[^\x20-\x7e]/g, function (ch) { var hex = ch.charCodeAt(0).toString(16).toUpperCase(); return "\\U+" + ("0000" + hex).slice(-4); }); } function buildDxf(rec) { var drafts = rec.drafts.filter(function (d) { return !d.auto || d.used; }); var newAddrs = rec.newAddrs || []; var s = ""; s += tag(0, "SECTION") + tag(2, "HEADER"); s += tag(9, "$ACADVER") + tag(1, "AC1009"); s += tag(0, "ENDSEC"); s += tag(0, "SECTION") + tag(2, "TABLES"); s += tag(0, "TABLE") + tag(2, "LTYPE") + tag(70, 1); s += tag(0, "LTYPE") + tag(2, "CONTINUOUS") + tag(70, 0) + tag(3, "Solid line") + tag(72, 65) + tag(73, 0) + tag(40, "0.0"); s += tag(0, "ENDTAB"); s += tag(0, "TABLE") + tag(2, "LAYER") + tag(70, 3); s += tag(0, "LAYER") + tag(2, "OPTECH_DRAFT") + tag(70, 0) + tag(62, 1) + tag(6, "CONTINUOUS"); s += tag(0, "LAYER") + tag(2, "OPTECH_ASSIGN") + tag(70, 0) + tag(62, 6) + tag(6, "CONTINUOUS"); s += tag(0, "LAYER") + tag(2, "ADDR_NAME_NEW") + tag(70, 0) + tag(62, 244) + tag(6, "CONTINUOUS"); s += tag(0, "ENDTAB"); s += tag(0, "TABLE") + tag(2, "STYLE") + tag(70, 2); // LEGEND — הסגנון שסביבת אופטק ממפה לפונט עברי ["STANDARD", "LEGEND"].forEach(function (styleName) { s += tag(0, "STYLE") + tag(2, styleName) + tag(70, 0) + tag(40, "0.0") + tag(41, "1.0") + tag(50, "0.0") + tag(71, 0) + tag(42, "2.5") + tag(3, "txt") + tag(4, ""); }); s += tag(0, "ENDTAB"); s += tag(0, "ENDSEC"); // הגדרת בלוק ה-DRAFT — עיגול + צלב אדומים, כמו ב-optech-draft.lsp s += tag(0, "SECTION") + tag(2, "BLOCKS"); s += tag(0, "BLOCK") + tag(8, "0") + tag(2, "OPTECH_DRAFT") + tag(70, 0) + tag(10, "0.0") + tag(20, "0.0") + tag(30, "0.0") + tag(3, "OPTECH_DRAFT"); s += tag(0, "CIRCLE") + tag(8, "0") + tag(62, 1) + tag(10, "0.0") + tag(20, "0.0") + tag(30, "0.0") + tag(40, "1.5"); s += tag(0, "LINE") + tag(8, "0") + tag(62, 1) + tag(10, "-1.5") + tag(20, "0.0") + tag(30, "0.0") + tag(11, "1.5") + tag(21, "0.0") + tag(31, "0.0"); s += tag(0, "LINE") + tag(8, "0") + tag(62, 1) + tag(10, "0.0") + tag(20, "-1.5") + tag(30, "0.0") + tag(11, "0.0") + tag(21, "1.5") + tag(31, "0.0"); s += tag(0, "ENDBLK") + tag(8, "0"); s += tag(0, "ENDSEC"); s += tag(0, "SECTION") + tag(2, "ENTITIES"); drafts.forEach(function (d) { s += tag(0, "INSERT") + tag(8, "OPTECH_DRAFT") + tag(2, "OPTECH_DRAFT") + tag(10, fmt(d.pt[0])) + tag(20, fmt(d.pt[1])) + tag(30, 0); }); rec.links.forEach(function (l) { s += tag(0, "LINE") + tag(8, "OPTECH_ASSIGN") + tag(10, fmt(l.a[0])) + tag(20, fmt(l.a[1])) + tag(30, 0) + tag(11, fmt(l.b[0])) + tag(21, fmt(l.b[1])) + tag(31, 0); }); newAddrs.forEach(function (na) { s += tag(0, "TEXT") + tag(8, "ADDR_NAME_NEW") + tag(7, "LEGEND") + tag(10, fmt(na.pt[0])) + tag(20, fmt(na.pt[1])) + tag(30, 0) + tag(40, "1.2") + tag(1, escapeDxfText(na.text)); }); s += tag(0, "ENDSEC") + tag(0, "EOF"); return { text: s, nDrafts: drafts.length, nSkipped: rec.drafts.length - drafts.length, nAddrs: newAddrs.length }; } /** ייצוא ושיתוף — כמו בשכבת ההערות */ function exportAndShare(rec) { if (!rec || (!rec.drafts.length && !rec.links.length && !(rec.newAddrs || []).length)) { return Promise.reject(new Error("EMPTY_ASSIGN")); } var built = buildDxf(rec); var stamp = new Date().toISOString().slice(0, 10); var fileName = "optech-assign-" + stamp + ".dxf"; var blob = new Blob([built.text], { type: "application/dxf" }); var file; try { file = new File([blob], fileName, { type: "application/dxf" }); } catch (e) { file = null; } var done; if (file && navigator.canShare && navigator.canShare({ files: [file] })) { done = navigator.share({ files: [file], title: "שיוך נכסים — Optech GIS" }) .catch(function (err) { if (err && err.name === "AbortError") return; download(blob, fileName); }); } else { download(blob, fileName); done = Promise.resolve(); } return done.then(function () { return built; }); } function download(blob, fileName) { var a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = fileName; document.body.appendChild(a); a.click(); setTimeout(function () { URL.revokeObjectURL(a.href); a.remove(); }, 2000); } global.Assign = { ASSIGN_ID: ASSIGN_ID, SNAP_ADDR: SNAP_ADDR, newRecord: newRecord, rebuild: rebuild, draftNear: draftNear, addrNear: addrNear, scatterNearPoles: scatterNearPoles, buildDxf: buildDxf, exportAndShare: exportAndShare, }; })(window);