schematex 0.9.11 → 0.9.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/ai/ai-sdk.cjs +9 -8
  2. package/dist/ai/ai-sdk.cjs.map +1 -1
  3. package/dist/ai/ai-sdk.d.cts +3 -3
  4. package/dist/ai/ai-sdk.d.ts +3 -3
  5. package/dist/ai/ai-sdk.js +4 -3
  6. package/dist/ai/ai-sdk.js.map +1 -1
  7. package/dist/ai/index.cjs +18 -17
  8. package/dist/ai/index.cjs.map +1 -1
  9. package/dist/ai/index.d.cts +4 -4
  10. package/dist/ai/index.d.ts +4 -4
  11. package/dist/ai/index.js +5 -4
  12. package/dist/ai/index.js.map +1 -1
  13. package/dist/{api-DAiP83-P.d.ts → api-C9ufsgIb.d.ts} +2 -2
  14. package/dist/{api-DecITB-t.d.cts → api-DAUFeETp.d.cts} +2 -2
  15. package/dist/browser.cjs +10 -9
  16. package/dist/browser.cjs.map +1 -1
  17. package/dist/browser.d.cts +3 -3
  18. package/dist/browser.d.ts +3 -3
  19. package/dist/browser.js +4 -3
  20. package/dist/browser.js.map +1 -1
  21. package/dist/{chunk-4QBC4475.js → chunk-6KW7XSUR.js} +192 -3
  22. package/dist/chunk-6KW7XSUR.js.map +1 -0
  23. package/dist/chunk-IBZKIMT5.cjs +826 -0
  24. package/dist/chunk-IBZKIMT5.cjs.map +1 -0
  25. package/dist/{chunk-RU3N57OB.js → chunk-JLLDJCLW.js} +13138 -13136
  26. package/dist/{chunk-RU3N57OB.js.map → chunk-JLLDJCLW.js.map} +1 -1
  27. package/dist/{chunk-5YTFNOKY.cjs → chunk-MGMR6V6N.cjs} +13139 -13135
  28. package/dist/chunk-MGMR6V6N.cjs.map +1 -0
  29. package/dist/{chunk-YN7EBTWB.cjs → chunk-OGF7QM74.cjs} +2 -2
  30. package/dist/chunk-OGF7QM74.cjs.map +1 -0
  31. package/dist/chunk-PGMKMIGM.js +818 -0
  32. package/dist/chunk-PGMKMIGM.js.map +1 -0
  33. package/dist/{chunk-WTGABYFK.js → chunk-Q5MQLUOH.js} +2 -2
  34. package/dist/chunk-Q5MQLUOH.js.map +1 -0
  35. package/dist/{chunk-6ZTPWE22.cjs → chunk-YLG7S4SM.cjs} +194 -5
  36. package/dist/chunk-YLG7S4SM.cjs.map +1 -0
  37. package/dist/{diagnostics-Bps9pzlF.d.cts → diagnostics-DSxLohjY.d.cts} +1 -1
  38. package/dist/{diagnostics-Bps9pzlF.d.ts → diagnostics-DSxLohjY.d.ts} +1 -1
  39. package/dist/diagrams/blockdiagram/index.d.cts +1 -1
  40. package/dist/diagrams/blockdiagram/index.d.ts +1 -1
  41. package/dist/diagrams/circuit/index.d.cts +1 -1
  42. package/dist/diagrams/circuit/index.d.ts +1 -1
  43. package/dist/diagrams/ecomap/index.d.cts +1 -1
  44. package/dist/diagrams/ecomap/index.d.ts +1 -1
  45. package/dist/diagrams/entity/index.d.cts +1 -1
  46. package/dist/diagrams/entity/index.d.ts +1 -1
  47. package/dist/diagrams/fishbone/index.d.cts +1 -1
  48. package/dist/diagrams/fishbone/index.d.ts +1 -1
  49. package/dist/diagrams/flowchart/index.d.cts +2 -2
  50. package/dist/diagrams/flowchart/index.d.ts +2 -2
  51. package/dist/diagrams/genogram/index.d.cts +1 -1
  52. package/dist/diagrams/genogram/index.d.ts +1 -1
  53. package/dist/diagrams/ladder/index.d.cts +1 -1
  54. package/dist/diagrams/ladder/index.d.ts +1 -1
  55. package/dist/diagrams/logic/index.d.cts +1 -1
  56. package/dist/diagrams/logic/index.d.ts +1 -1
  57. package/dist/diagrams/orgchart/index.d.cts +1 -1
  58. package/dist/diagrams/orgchart/index.d.ts +1 -1
  59. package/dist/diagrams/pedigree/index.d.cts +1 -1
  60. package/dist/diagrams/pedigree/index.d.ts +1 -1
  61. package/dist/diagrams/phylo/index.d.cts +1 -1
  62. package/dist/diagrams/phylo/index.d.ts +1 -1
  63. package/dist/diagrams/siteplan/index.cjs +38 -0
  64. package/dist/diagrams/siteplan/index.cjs.map +1 -0
  65. package/dist/diagrams/siteplan/index.d.cts +122 -0
  66. package/dist/diagrams/siteplan/index.d.ts +122 -0
  67. package/dist/diagrams/siteplan/index.js +5 -0
  68. package/dist/diagrams/siteplan/index.js.map +1 -0
  69. package/dist/diagrams/sld/index.cjs +7 -7
  70. package/dist/diagrams/sld/index.d.cts +1 -1
  71. package/dist/diagrams/sld/index.d.ts +1 -1
  72. package/dist/diagrams/sld/index.js +1 -1
  73. package/dist/diagrams/sociogram/index.d.cts +1 -1
  74. package/dist/diagrams/sociogram/index.d.ts +1 -1
  75. package/dist/diagrams/timing/index.d.cts +1 -1
  76. package/dist/diagrams/timing/index.d.ts +1 -1
  77. package/dist/diagrams/venn/index.d.cts +1 -1
  78. package/dist/diagrams/venn/index.d.ts +1 -1
  79. package/dist/{index-fvBAmlv7.d.cts → index-CDDfbChc.d.cts} +1 -1
  80. package/dist/{index-F6MCisQe.d.ts → index-CZa2pU0T.d.ts} +1 -1
  81. package/dist/index.cjs +52 -39
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.d.cts +10 -5
  84. package/dist/index.d.ts +10 -5
  85. package/dist/index.js +5 -4
  86. package/dist/index.js.map +1 -1
  87. package/dist/react.cjs +4 -3
  88. package/dist/react.cjs.map +1 -1
  89. package/dist/react.d.cts +2 -2
  90. package/dist/react.d.ts +2 -2
  91. package/dist/react.js +3 -2
  92. package/dist/react.js.map +1 -1
  93. package/dist/{tools-vyVK2DHa.d.cts → tools-Bvw6dwIR.d.cts} +2 -2
  94. package/dist/{tools-CdzIw2Az.d.ts → tools-DtuvE-K4.d.ts} +2 -2
  95. package/package.json +6 -1
  96. package/dist/chunk-4QBC4475.js.map +0 -1
  97. package/dist/chunk-5YTFNOKY.cjs.map +0 -1
  98. package/dist/chunk-6ZTPWE22.cjs.map +0 -1
  99. package/dist/chunk-WTGABYFK.js.map +0 -1
  100. package/dist/chunk-YN7EBTWB.cjs.map +0 -1
@@ -0,0 +1,826 @@
1
+ 'use strict';
2
+
3
+ var chunk7OOUU6BL_cjs = require('./chunk-7OOUU6BL.cjs');
4
+ var chunk3WNW5Y7P_cjs = require('./chunk-3WNW5Y7P.cjs');
5
+
6
+ // src/diagrams/siteplan/parser.ts
7
+ var SiteplanParseError = class extends Error {
8
+ line;
9
+ constructor(message, line2) {
10
+ super(`line ${line2}: ${message}`);
11
+ this.name = "SiteplanParseError";
12
+ this.line = line2;
13
+ }
14
+ };
15
+ var POLYGON_ROLES = ["parcel", "structure", "zone", "landscape", "parking"];
16
+ var PATH_ROLES = ["road", "driveway", "walkway", "trail"];
17
+ var LINE_ROLES = ["setback", "easement", "fence", "utility", "frontage", "dimension", "boundary"];
18
+ var MARKER_KINDS = ["tree", "car", "pin", "entry", "hydrant", "well"];
19
+ function normalizeQuotes(line2) {
20
+ return line2.replace(/[“”「」『』]/g, '"').replace(/[‘’]/g, "'");
21
+ }
22
+ function stripComment(line2) {
23
+ let quoted = false;
24
+ for (let i = 0; i < line2.length; i++) {
25
+ const ch = line2[i];
26
+ if (ch === '"') quoted = !quoted;
27
+ if (!quoted && ch === "#" && !/^#[0-9a-fA-F]{3,8}\b/.test(line2.slice(i))) return line2.slice(0, i);
28
+ }
29
+ return line2;
30
+ }
31
+ function tokenize(line2) {
32
+ const out = [];
33
+ const re = /"([^"]*)"|(\S+)/g;
34
+ let m;
35
+ while (m = re.exec(line2)) {
36
+ if (m[1] !== void 0) out.push({ str: m[1] });
37
+ else out.push({ word: m[2] });
38
+ }
39
+ return out;
40
+ }
41
+ var isWord = (t, w) => t !== void 0 && "word" in t && (w === void 0 || t.word.toLowerCase() === w);
42
+ var isStr = (t) => t !== void 0 && "str" in t;
43
+ function tokenText(t) {
44
+ return "word" in t ? t.word : t.str;
45
+ }
46
+ function shiftStringIfNext(tok) {
47
+ const first = tok[0];
48
+ if (!isStr(first)) return void 0;
49
+ tok.shift();
50
+ return first.str;
51
+ }
52
+ function parseNum(t, what, line2) {
53
+ if (!isWord(t)) throw new SiteplanParseError(`expected a number for ${what}`, line2);
54
+ const n = Number(t.word);
55
+ if (!Number.isFinite(n)) throw new SiteplanParseError(`expected a number for ${what}, got "${t.word}"`, line2);
56
+ return n;
57
+ }
58
+ function parsePointToken(t, what, line2) {
59
+ if (!isWord(t)) throw new SiteplanParseError(`expected "x,y" for ${what}`, line2);
60
+ const m = /^(-?\d*\.?\d+),(-?\d*\.?\d+)$/.exec(t.word);
61
+ if (!m) throw new SiteplanParseError(`expected "x,y" for ${what}, got "${t.word}"`, line2);
62
+ return { x: Number(m[1]), y: Number(m[2]) };
63
+ }
64
+ function parseDimsToken(t, what, line2) {
65
+ if (!isWord(t)) throw new SiteplanParseError(`expected "WxH" for ${what}`, line2);
66
+ const m = /^(\d*\.?\d+)[x×](\d*\.?\d+)$/i.exec(t.word);
67
+ if (!m) throw new SiteplanParseError(`expected "WxH" for ${what}, got "${t.word}"`, line2);
68
+ return { w: Number(m[1]), h: Number(m[2]) };
69
+ }
70
+ function parseId(t, what, line2) {
71
+ if (!isWord(t)) throw new SiteplanParseError(`expected ${what}`, line2);
72
+ return t.word;
73
+ }
74
+ function parsePoints(tok, line2, min = 2) {
75
+ const points = [];
76
+ while (tok.length && isWord(tok[0]) && /^-?\d*\.?\d+,-?\d*\.?\d+$/.test(tok[0].word)) {
77
+ points.push(parsePointToken(tok.shift(), "points", line2));
78
+ }
79
+ if (points.length < min) {
80
+ throw new SiteplanParseError(`expected at least ${min} point${min === 1 ? "" : "s"}`, line2);
81
+ }
82
+ return points;
83
+ }
84
+ function parseOptionalLabel(tok, obj) {
85
+ const label = shiftStringIfNext(tok);
86
+ if (label !== void 0) obj.label = label;
87
+ }
88
+ function parseHeader(tok, ast, line2) {
89
+ while (tok.length) {
90
+ const t = tok.shift();
91
+ if (isStr(t)) ast.title = t.str;
92
+ else if (isWord(t, "unit")) {
93
+ const unit = parseId(tok.shift(), "unit (ft|m)", line2).toLowerCase();
94
+ if (unit !== "ft" && unit !== "m") throw new SiteplanParseError(`unit must be "ft" or "m", got "${unit}"`, line2);
95
+ ast.unit = unit;
96
+ } else throw new SiteplanParseError(`siteplan: unexpected token "${tokenText(t)}"`, line2);
97
+ }
98
+ }
99
+ function parsePolygon(role, tok, line2) {
100
+ const poly = { role, id: parseId(tok.shift(), `${role} id`, line2), points: [], line: line2 };
101
+ parseOptionalLabel(tok, poly);
102
+ if (!isWord(tok.shift(), "points")) throw new SiteplanParseError(`${role}: expected "points"`, line2);
103
+ poly.points = parsePoints(tok, line2, 3);
104
+ while (tok.length) {
105
+ const t = tok.shift();
106
+ if (!isWord(t)) throw new SiteplanParseError(`${role}: unexpected string "${tokenText(t)}"`, line2);
107
+ if (t.word === "fill") poly.fill = parseId(tok.shift(), "fill color", line2);
108
+ else if (t.word === "label") {
109
+ const label = shiftStringIfNext(tok);
110
+ if (label !== void 0) poly.label = label;
111
+ else throw new SiteplanParseError(`${role}: label expects a quoted string`, line2);
112
+ } else throw new SiteplanParseError(`${role}: unexpected token "${t.word}"`, line2);
113
+ }
114
+ return poly;
115
+ }
116
+ function parsePath(role, tok, line2) {
117
+ const path2 = { role, id: parseId(tok.shift(), `${role} id`, line2), points: [], width: role === "road" ? 20 : 8, line: line2 };
118
+ parseOptionalLabel(tok, path2);
119
+ const head = tok.shift();
120
+ if (isWord(head, "from")) {
121
+ path2.points = [parsePointToken(tok.shift(), "from", line2)];
122
+ if (!isWord(tok.shift(), "to")) throw new SiteplanParseError(`${role}: expected "to"`, line2);
123
+ path2.points.push(parsePointToken(tok.shift(), "to", line2));
124
+ } else if (isWord(head, "points")) {
125
+ path2.points = parsePoints(tok, line2, 2);
126
+ } else throw new SiteplanParseError(`${role}: expected "from" or "points"`, line2);
127
+ while (tok.length) {
128
+ const t = tok.shift();
129
+ if (!isWord(t)) throw new SiteplanParseError(`${role}: unexpected string "${tokenText(t)}"`, line2);
130
+ if (t.word === "width") path2.width = parseNum(tok.shift(), "width", line2);
131
+ else if (t.word === "label") {
132
+ const label = shiftStringIfNext(tok);
133
+ if (label !== void 0) path2.label = label;
134
+ else throw new SiteplanParseError(`${role}: label expects a quoted string`, line2);
135
+ } else throw new SiteplanParseError(`${role}: unexpected token "${t.word}"`, line2);
136
+ }
137
+ return path2;
138
+ }
139
+ function parseLine(role, tok, line2) {
140
+ const ln = { role, id: parseId(tok.shift(), `${role} id`, line2), points: [], line: line2 };
141
+ parseOptionalLabel(tok, ln);
142
+ const head = tok.shift();
143
+ if (isWord(head, "from")) {
144
+ ln.points = [parsePointToken(tok.shift(), "from", line2)];
145
+ if (!isWord(tok.shift(), "to")) throw new SiteplanParseError(`${role}: expected "to"`, line2);
146
+ ln.points.push(parsePointToken(tok.shift(), "to", line2));
147
+ } else if (isWord(head, "points")) {
148
+ ln.points = parsePoints(tok, line2, 2);
149
+ } else throw new SiteplanParseError(`${role}: expected "from" or "points"`, line2);
150
+ while (tok.length) {
151
+ const t = tok.shift();
152
+ if (!isWord(t)) throw new SiteplanParseError(`${role}: unexpected string "${tokenText(t)}"`, line2);
153
+ if (t.word === "label") {
154
+ const label = shiftStringIfNext(tok);
155
+ if (label !== void 0) ln.label = label;
156
+ else throw new SiteplanParseError(`${role}: label expects a quoted string`, line2);
157
+ } else throw new SiteplanParseError(`${role}: unexpected token "${t.word}"`, line2);
158
+ }
159
+ return ln;
160
+ }
161
+ function parseMarker(kind, tok, line2) {
162
+ let id = `${kind}${line2}`;
163
+ const first = tok[0];
164
+ if (first && "word" in first && first.word.toLowerCase() !== "at") {
165
+ tok.shift();
166
+ id = first.word;
167
+ }
168
+ const marker = { kind, id, at: { x: 0, y: 0 }, size: kind === "car" ? 16 : 8, rotate: 0, line: line2 };
169
+ parseOptionalLabel(tok, marker);
170
+ while (tok.length) {
171
+ const t = tok.shift();
172
+ if (!isWord(t)) marker.label = tokenText(t);
173
+ else if (t.word === "at") marker.at = parsePointToken(tok.shift(), "at", line2);
174
+ else if (t.word === "size") {
175
+ const next = tok.shift();
176
+ if (isWord(next) && /[x×]/i.test(next.word)) {
177
+ const d = parseDimsToken(next, "size", line2);
178
+ marker.size = Math.max(d.w, d.h);
179
+ } else marker.size = parseNum(next, "size", line2);
180
+ } else if (t.word === "rotate") marker.rotate = parseNum(tok.shift(), "rotate", line2);
181
+ else if (t.word === "label") {
182
+ const label = shiftStringIfNext(tok);
183
+ if (label !== void 0) marker.label = label;
184
+ else throw new SiteplanParseError(`${kind}: label expects a quoted string`, line2);
185
+ } else throw new SiteplanParseError(`${kind}: unexpected token "${t.word}"`, line2);
186
+ }
187
+ return marker;
188
+ }
189
+ function parseCallout(tok, line2) {
190
+ const first = tok.shift();
191
+ if (!isStr(first)) throw new SiteplanParseError(`callout: expected quoted label`, line2);
192
+ if (!isWord(tok.shift(), "at")) throw new SiteplanParseError(`callout: expected "at"`, line2);
193
+ const at = parsePointToken(tok.shift(), "at", line2);
194
+ if (!isWord(tok.shift(), "to")) throw new SiteplanParseError(`callout: expected "to"`, line2);
195
+ return { label: first.str, at, to: parsePointToken(tok.shift(), "to", line2), line: line2 };
196
+ }
197
+ function parseDimension(tok, line2) {
198
+ let label = "";
199
+ label = shiftStringIfNext(tok) ?? label;
200
+ if (!isWord(tok.shift(), "from")) throw new SiteplanParseError(`dimension: expected "from"`, line2);
201
+ const from = parsePointToken(tok.shift(), "from", line2);
202
+ if (!isWord(tok.shift(), "to")) throw new SiteplanParseError(`dimension: expected "to"`, line2);
203
+ const to = parsePointToken(tok.shift(), "to", line2);
204
+ while (tok.length) {
205
+ const t = tok.shift();
206
+ if (isWord(t, "label")) {
207
+ const next = shiftStringIfNext(tok);
208
+ if (next !== void 0) label = next;
209
+ else throw new SiteplanParseError(`dimension: label expects a quoted string`, line2);
210
+ } else throw new SiteplanParseError(`dimension: unexpected token`, line2);
211
+ }
212
+ return { label, from, to, line: line2 };
213
+ }
214
+ function parseSiteplan(text2) {
215
+ const ast = {
216
+ type: "siteplan",
217
+ title: "Site Plan",
218
+ unit: "ft",
219
+ legend: true,
220
+ polygons: [],
221
+ paths: [],
222
+ lines: [],
223
+ markers: [],
224
+ callouts: [],
225
+ dimensions: []
226
+ };
227
+ const lines = text2.split(/\r?\n/);
228
+ let sawHeader = false;
229
+ for (let i = 0; i < lines.length; i++) {
230
+ const lineNo = i + 1;
231
+ const raw = stripComment(normalizeQuotes(lines[i] ?? "")).trim();
232
+ if (!raw) continue;
233
+ const tok = tokenize(raw);
234
+ const head = tok.shift();
235
+ if (!isWord(head)) throw new SiteplanParseError(`unexpected string at line start`, lineNo);
236
+ const keyword = head.word.toLowerCase();
237
+ if (!sawHeader) {
238
+ if (keyword !== "siteplan" && keyword !== "plotplan" && keyword !== "parcelmap" && keyword !== "propertymap") {
239
+ throw new SiteplanParseError(`expected siteplan header`, lineNo);
240
+ }
241
+ parseHeader(tok, ast, lineNo);
242
+ sawHeader = true;
243
+ continue;
244
+ }
245
+ if (POLYGON_ROLES.includes(keyword)) {
246
+ ast.polygons.push(parsePolygon(keyword, tok, lineNo));
247
+ } else if (PATH_ROLES.includes(keyword)) {
248
+ ast.paths.push(parsePath(keyword, tok, lineNo));
249
+ } else if (LINE_ROLES.includes(keyword)) {
250
+ ast.lines.push(parseLine(keyword, tok, lineNo));
251
+ } else if (MARKER_KINDS.includes(keyword)) {
252
+ ast.markers.push(parseMarker(keyword, tok, lineNo));
253
+ } else if (keyword === "callout") {
254
+ ast.callouts.push(parseCallout(tokenize(raw).slice(1), lineNo));
255
+ } else if (keyword === "dim" || keyword === "measure") {
256
+ ast.dimensions.push(parseDimension(tok, lineNo));
257
+ } else if (keyword === "north") {
258
+ ast.north = tok.length ? parseNum(tok.shift(), "north", lineNo) : 0;
259
+ } else if (keyword === "scale") {
260
+ ast.scale = parseNum(tok.shift(), "scale", lineNo);
261
+ } else if (keyword === "legend") {
262
+ const v = parseId(tok.shift(), "legend (on|off)", lineNo).toLowerCase();
263
+ ast.legend = v !== "off";
264
+ } else {
265
+ throw new SiteplanParseError(`unknown siteplan keyword "${keyword}"`, lineNo);
266
+ }
267
+ }
268
+ if (!sawHeader) throw new SiteplanParseError(`missing siteplan header`, 1);
269
+ return ast;
270
+ }
271
+
272
+ // src/diagrams/siteplan/layout.ts
273
+ var EMPTY_BOUNDS = { minX: 0, minY: 0, maxX: 100, maxY: 70 };
274
+ function includePoint(bounds, p, pad = 0) {
275
+ bounds.minX = Math.min(bounds.minX, p.x - pad);
276
+ bounds.minY = Math.min(bounds.minY, p.y - pad);
277
+ bounds.maxX = Math.max(bounds.maxX, p.x + pad);
278
+ bounds.maxY = Math.max(bounds.maxY, p.y + pad);
279
+ }
280
+ function polygonArea(points) {
281
+ let sum = 0;
282
+ for (let i = 0; i < points.length; i++) {
283
+ const a = points[i];
284
+ const b = points[(i + 1) % points.length];
285
+ sum += a.x * b.y - b.x * a.y;
286
+ }
287
+ return Math.abs(sum) / 2;
288
+ }
289
+ function legendItems(ast) {
290
+ const seen = /* @__PURE__ */ new Set();
291
+ const items = [];
292
+ const add = (key, label) => {
293
+ if (seen.has(key)) return;
294
+ seen.add(key);
295
+ items.push({ key, label });
296
+ };
297
+ for (const p of ast.polygons) add(p.role, p.role === "parcel" ? "Parcel boundary" : p.role);
298
+ for (const p of ast.paths) add(p.role, p.role);
299
+ for (const l of ast.lines) add(l.role, l.role);
300
+ for (const m of ast.markers) add(m.kind, m.kind);
301
+ return items;
302
+ }
303
+ function layoutSiteplan(ast) {
304
+ const bounds = { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity };
305
+ const warnings = [];
306
+ for (const p of ast.polygons) {
307
+ for (const pt of p.points) includePoint(bounds, pt);
308
+ if (p.points.length >= 3 && polygonArea(p.points) < 1) {
309
+ warnings.push(`${p.role} "${p.id}" has very small area \u2014 check point order or units`);
310
+ }
311
+ }
312
+ for (const p of ast.paths) for (const pt of p.points) includePoint(bounds, pt, p.width / 2);
313
+ for (const l of ast.lines) for (const pt of l.points) includePoint(bounds, pt, 2);
314
+ for (const m of ast.markers) includePoint(bounds, m.at, m.size / 2);
315
+ for (const c of ast.callouts) {
316
+ includePoint(bounds, c.at, 8);
317
+ includePoint(bounds, c.to);
318
+ }
319
+ for (const d of ast.dimensions) {
320
+ includePoint(bounds, d.from, 5);
321
+ includePoint(bounds, d.to, 5);
322
+ }
323
+ const finalBounds = Number.isFinite(bounds.minX) ? bounds : { ...EMPTY_BOUNDS };
324
+ return {
325
+ title: ast.title,
326
+ unit: ast.unit,
327
+ north: ast.north,
328
+ scale: ast.scale,
329
+ legend: ast.legend,
330
+ polygons: ast.polygons,
331
+ paths: ast.paths,
332
+ lines: ast.lines,
333
+ markers: ast.markers,
334
+ callouts: ast.callouts,
335
+ dimensions: ast.dimensions,
336
+ bounds: finalBounds,
337
+ warnings,
338
+ legendItems: legendItems(ast)
339
+ };
340
+ }
341
+ function formatSiteLength(n, unit) {
342
+ if (unit === "ft") return `${Math.round(n)} ft`;
343
+ return `${Math.round(n * 10) / 10} m`;
344
+ }
345
+
346
+ // src/diagrams/siteplan/renderer.ts
347
+ var PAPER = "#ffffff";
348
+ var INK = "#111827";
349
+ var MUTED = "#5f6b7a";
350
+ var PLAN_LINE = "#1f2937";
351
+ var FAINT_LINE = "#d6dbe3";
352
+ var LEGEND_COLS = 1;
353
+ var LEGEND_LIMIT = 9;
354
+ var SIDE_PANEL_W = 188;
355
+ var SIDE_PANEL_GAP = 24;
356
+ var r2 = (n) => Math.round(n * 100) / 100;
357
+ function renderSiteplan(text2, config) {
358
+ return renderSiteplanLayout(layoutSiteplan(parseSiteplan(text2)), config);
359
+ }
360
+ function polyPoints(points, sx, sy) {
361
+ return points.map((p) => `${sx(p.x).toFixed(1)},${sy(p.y).toFixed(1)}`).join(" ");
362
+ }
363
+ function pathD(points, sx, sy) {
364
+ return points.map((p, i) => `${i === 0 ? "M" : "L"}${sx(p.x).toFixed(1)} ${sy(p.y).toFixed(1)}`).join(" ");
365
+ }
366
+ function centroid(points) {
367
+ let x = 0;
368
+ let y = 0;
369
+ for (const p of points) {
370
+ x += p.x;
371
+ y += p.y;
372
+ }
373
+ return { x: x / points.length, y: y / points.length };
374
+ }
375
+ function renderSiteplanLayout(lay, config) {
376
+ const fontFamily = config?.fontFamily ?? chunk7OOUU6BL_cjs.DEFAULT_FONT_FAMILY;
377
+ const pad = config?.padding ?? 28;
378
+ const titleBand = lay.title ? 34 : 14;
379
+ const hasPanel = lay.legend && lay.legendItems.length > 0 || lay.north !== void 0 || lay.scale !== void 0;
380
+ const panelW = hasPanel ? SIDE_PANEL_W : 0;
381
+ const panelGap = hasPanel ? SIDE_PANEL_GAP : 0;
382
+ const targetW = 980;
383
+ const targetH = 660;
384
+ const spanX = Math.max(1, lay.bounds.maxX - lay.bounds.minX);
385
+ const spanY = Math.max(1, lay.bounds.maxY - lay.bounds.minY);
386
+ const drawingMaxW = targetW - pad * 2 - panelW - panelGap;
387
+ const drawingMaxH = targetH - pad * 2 - titleBand;
388
+ const scale = Math.min(drawingMaxW / spanX, drawingMaxH / spanY);
389
+ const drawingW = spanX * scale;
390
+ const drawingH = spanY * scale;
391
+ const contentW = drawingW + panelW + panelGap;
392
+ const width = Math.max(520, contentW + pad * 2);
393
+ const height = Math.max(420, drawingH + pad * 2 + titleBand);
394
+ const contentX = pad + Math.max(0, (width - pad * 2 - contentW) / 2);
395
+ const plotY = titleBand + pad + Math.max(0, (height - titleBand - pad * 2 - drawingH) / 2);
396
+ const panelX = contentX + drawingW + panelGap;
397
+ const ox = contentX - lay.bounds.minX * scale;
398
+ const oy = plotY - lay.bounds.minY * scale;
399
+ const sx = (n) => ox + n * scale;
400
+ const sy = (n) => oy + n * scale;
401
+ const len = (n) => n * scale;
402
+ const style = chunk3WNW5Y7P_cjs.el(
403
+ "style",
404
+ {},
405
+ `
406
+ .sx-sp-bg { fill: ${PAPER}; }
407
+ .sx-sp-sheet { fill: none; stroke: ${PLAN_LINE}; stroke-width: 1; }
408
+ .sx-sp-sheet-rule { stroke: ${FAINT_LINE}; stroke-width: 1; }
409
+ .sx-sp-title { fill: ${INK}; font-size: 15px; font-weight: ${chunk7OOUU6BL_cjs.TITLE.weight}; letter-spacing: 0; }
410
+ .sx-sp-note { fill: ${MUTED}; font-size: 11px; }
411
+ .sx-sp-parcel { stroke: #111827; stroke-width: 2.2; }
412
+ .sx-sp-structure { stroke: #253041; stroke-width: 1.6; }
413
+ .sx-sp-roofline { fill: none; stroke: #9aa4b2; stroke-width: 0.75; }
414
+ .sx-sp-zone { stroke: #9aa4b2; stroke-width: 1; stroke-dasharray: 7 4; }
415
+ .sx-sp-landscape { stroke: #899481; stroke-width: 0.9; }
416
+ .sx-sp-parking { stroke: #8e99a8; stroke-width: 0.9; }
417
+ .sx-sp-road { fill: none; stroke: #f1f3f6; stroke-linecap: butt; stroke-linejoin: round; }
418
+ .sx-sp-road-center { fill: none; stroke: #9aa4b2; stroke-width: 0.9; stroke-linecap: butt; stroke-linejoin: round; }
419
+ .sx-sp-driveway-edge { fill: none; stroke: #aeb8c4; stroke-linecap: round; stroke-linejoin: round; }
420
+ .sx-sp-driveway { fill: none; stroke: #d8dde5; stroke-linecap: round; stroke-linejoin: round; }
421
+ .sx-sp-driveway-mark { fill: none; stroke: ${PAPER}; stroke-width: 1.15; stroke-linecap: butt; stroke-dasharray: 7 7; }
422
+ .sx-sp-driveway-arrow { fill: ${PAPER}; stroke: #8a94a3; stroke-width: 0.35; }
423
+ .sx-sp-walkway, .sx-sp-trail { fill: none; stroke: #d7d0c3; stroke-linecap: round; stroke-linejoin: round; }
424
+ .sx-sp-setback { fill: none; stroke: #6b7280; stroke-width: 1; stroke-dasharray: 8 5; }
425
+ .sx-sp-easement { fill: none; stroke: #6b7280; stroke-width: 1; stroke-dasharray: 2 5; }
426
+ .sx-sp-fence { fill: none; stroke: #344054; stroke-width: 1; stroke-dasharray: 8 3 1.5 3; }
427
+ .sx-sp-utility { fill: none; stroke: #2563eb; stroke-width: 1; stroke-dasharray: 2 5; }
428
+ .sx-sp-frontage { fill: none; stroke: #111827; stroke-width: 1.7; }
429
+ .sx-sp-boundary { fill: none; stroke: #111827; stroke-width: 1.8; }
430
+ .sx-sp-dim { fill: none; stroke: #475467; stroke-width: 0.9; }
431
+ .sx-sp-callout { fill: none; stroke: #344054; stroke-width: 0.9; marker-end: url(#sx-sp-arrow); }
432
+ .sx-sp-label { fill: ${INK}; font-size: 10.2px; font-weight: 600; paint-order: stroke; stroke: ${PAPER}; stroke-width: 3.4px; stroke-linejoin: round; }
433
+ .sx-sp-small { fill: ${INK}; font-size: 8.8px; paint-order: stroke; stroke: ${PAPER}; stroke-width: 2.8px; stroke-linejoin: round; }
434
+ .sx-sp-marker { fill: #fbfdf8; stroke: #3f684b; stroke-width: 1.05; }
435
+ .sx-sp-marker-line { fill: none; stroke: #3f684b; stroke-width: 0.7; }
436
+ .sx-sp-car { fill: #fafafa; stroke: #667085; stroke-width: 0.9; }
437
+ .sx-sp-pin { fill: #ffffff; stroke: #b42318; stroke-width: 1; }
438
+ .sx-sp-entry { fill: #ffffff; stroke: #475467; stroke-width: 1; }
439
+ .sx-sp-legend-box { fill: ${PAPER}; stroke: #cfd5dd; stroke-width: 0.9; }
440
+ .sx-sp-legend-title { fill: ${INK}; font-size: 10px; font-weight: 700; }
441
+ .sx-sp-legend-text { fill: ${MUTED}; font-size: 9.4px; }
442
+ `.trim()
443
+ );
444
+ const children = [
445
+ chunk3WNW5Y7P_cjs.title(lay.title),
446
+ chunk3WNW5Y7P_cjs.desc(`Site plan with ${lay.polygons.length} polygons, ${lay.paths.length} paths, ${lay.lines.length} line features, and ${lay.markers.length} markers.`),
447
+ chunk3WNW5Y7P_cjs.defs([
448
+ chunk3WNW5Y7P_cjs.el("marker", { id: "sx-sp-arrow", markerWidth: 8, markerHeight: 8, refX: 7, refY: 4, orient: "auto" }, [
449
+ chunk3WNW5Y7P_cjs.path({ d: "M1 1 L7 4 L1 7 Z", fill: "#344054" })
450
+ ]),
451
+ chunk3WNW5Y7P_cjs.el("pattern", { id: "sx-sp-structure-hatch", patternUnits: "userSpaceOnUse", width: 7, height: 7 }, [
452
+ chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width: 7, height: 7, fill: "#fbfcfd" }),
453
+ chunk3WNW5Y7P_cjs.path({ d: "M-2 7 L7 -2 M2 9 L9 2", stroke: "#d6dbe3", "stroke-width": 0.65 })
454
+ ]),
455
+ chunk3WNW5Y7P_cjs.el("pattern", { id: "sx-sp-parking-hatch", patternUnits: "userSpaceOnUse", width: 24, height: 18 }, [
456
+ chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width: 24, height: 18, fill: "#f4f6f8" }),
457
+ chunk3WNW5Y7P_cjs.path({ d: "M4 18 L4 6 M12 18 L12 6 M20 18 L20 6", stroke: "#c5ccd6", "stroke-width": 0.8 })
458
+ ]),
459
+ chunk3WNW5Y7P_cjs.el("pattern", { id: "sx-sp-landscape-dot", patternUnits: "userSpaceOnUse", width: 12, height: 12 }, [
460
+ chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width: 12, height: 12, fill: "#fcfdf9" }),
461
+ chunk3WNW5Y7P_cjs.circle({ cx: 3, cy: 4, r: 0.8, fill: "#a6b99d" }),
462
+ chunk3WNW5Y7P_cjs.circle({ cx: 9, cy: 9, r: 0.8, fill: "#a6b99d" })
463
+ ])
464
+ ]),
465
+ style,
466
+ chunk3WNW5Y7P_cjs.rect({ x: 0, y: 0, width, height, class: "sx-sp-bg" }),
467
+ chunk3WNW5Y7P_cjs.rect({ x: 8, y: 8, width: r2(width - 16), height: r2(height - 16), class: "sx-sp-sheet" })
468
+ ];
469
+ if (lay.title) {
470
+ children.push(chunk3WNW5Y7P_cjs.text({ x: pad, y: 26, class: "sx-sp-title", "font-family": fontFamily, "text-anchor": "start" }, lay.title));
471
+ children.push(chunk3WNW5Y7P_cjs.line({ x1: pad, y1: titleBand, x2: r2(width - pad), y2: titleBand, class: "sx-sp-sheet-rule" }));
472
+ }
473
+ const roads = [];
474
+ const surfaces = [];
475
+ const structures = [];
476
+ const paths = [];
477
+ const overlays = [];
478
+ const dims = [];
479
+ const markers = [];
480
+ const callouts = [];
481
+ const labels = [];
482
+ for (const p of lay.paths.filter((p2) => p2.role === "road")) {
483
+ roads.push(renderPath(p, sx, sy, len, true));
484
+ if (p.label) labels.push(labelOnLine(p.points, p.label, sx, sy, fontFamily, "sx-sp-small", -4));
485
+ }
486
+ for (const p of lay.polygons) {
487
+ if (p.role === "structure") structures.push(renderPolygon(p, sx, sy, fontFamily));
488
+ else surfaces.push(renderPolygon(p, sx, sy, fontFamily));
489
+ }
490
+ for (const p of lay.paths.filter((p2) => p2.role !== "road")) {
491
+ paths.push(renderPath(p, sx, sy, len, false));
492
+ if (p.label) labels.push(labelOnLine(p.points, p.label, sx, sy, fontFamily, "sx-sp-small", -5));
493
+ }
494
+ for (const l of lay.lines) {
495
+ const d = pathD(l.points, sx, sy);
496
+ overlays.push(chunk3WNW5Y7P_cjs.path({ d, class: `sx-sp-${l.role}`, "data-line": l.id }));
497
+ if (l.label) labels.push(labelOnLine(l.points, l.label, sx, sy, fontFamily, "sx-sp-small", l.role === "frontage" ? 11 : -5));
498
+ }
499
+ for (const d of lay.dimensions) dims.push(renderDimension(d.from, d.to, d.label, sx, sy, fontFamily));
500
+ for (const m of lay.markers) markers.push(renderMarker(m.kind, sx(m.at.x), sy(m.at.y), len(m.size), m.rotate, m.label, fontFamily));
501
+ for (const c of lay.callouts) {
502
+ callouts.push(chunk3WNW5Y7P_cjs.path({ d: `M${r2(sx(c.at.x))} ${r2(sy(c.at.y))} L${r2(sx(c.to.x))} ${r2(sy(c.to.y))}`, class: "sx-sp-callout" }));
503
+ callouts.push(chunk3WNW5Y7P_cjs.text({ x: sx(c.at.x), y: sy(c.at.y) - 5, class: "sx-sp-small", "font-family": fontFamily, "text-anchor": "middle" }, c.label));
504
+ }
505
+ const scene = [
506
+ chunk3WNW5Y7P_cjs.group({ class: "sx-sp-roads" }, roads),
507
+ chunk3WNW5Y7P_cjs.group({ class: "sx-sp-surfaces" }, surfaces),
508
+ chunk3WNW5Y7P_cjs.group({ class: "sx-sp-structures" }, structures),
509
+ chunk3WNW5Y7P_cjs.group({ class: "sx-sp-paths" }, paths),
510
+ chunk3WNW5Y7P_cjs.group({ class: "sx-sp-overlays" }, overlays),
511
+ chunk3WNW5Y7P_cjs.group({ class: "sx-sp-dimensions" }, dims),
512
+ chunk3WNW5Y7P_cjs.group({ class: "sx-sp-markers" }, markers),
513
+ chunk3WNW5Y7P_cjs.group({ class: "sx-sp-callouts" }, callouts),
514
+ chunk3WNW5Y7P_cjs.group({ class: "sx-sp-labels" }, labels)
515
+ ];
516
+ children.push(chunk3WNW5Y7P_cjs.group({ class: "sx-siteplan-scene" }, scene));
517
+ if (hasPanel) {
518
+ children.push(chunk3WNW5Y7P_cjs.line({ x1: r2(panelX - 12), y1: titleBand + 14, x2: r2(panelX - 12), y2: r2(height - pad), class: "sx-sp-sheet-rule" }));
519
+ const panelParts = [];
520
+ let cursorY = titleBand + pad + 36;
521
+ if (lay.north !== void 0) {
522
+ panelParts.push(renderNorth(panelX + panelW / 2, cursorY, lay.north, fontFamily));
523
+ cursorY += 72;
524
+ }
525
+ if (lay.legend && lay.legendItems.length) {
526
+ panelParts.push(renderLegend(lay, panelX, cursorY, panelW, fontFamily));
527
+ cursorY += 34 + Math.ceil(Math.min(lay.legendItems.length, LEGEND_LIMIT) / LEGEND_COLS) * 20;
528
+ }
529
+ if (lay.scale) {
530
+ const scaleWidth = Math.min(Math.max(52, len(lay.scale)), panelW - 18);
531
+ panelParts.push(renderScaleBar(panelX + 4, Math.max(cursorY + 26, height - pad - 34), scaleWidth, formatSiteLength(lay.scale, lay.unit), fontFamily));
532
+ }
533
+ children.push(chunk3WNW5Y7P_cjs.group({ class: "sx-sp-accessories" }, panelParts));
534
+ }
535
+ return chunk3WNW5Y7P_cjs.svgRoot({ width: Math.round(width), height: Math.round(height), viewBox: `0 0 ${Math.round(width)} ${Math.round(height)}`, class: "sx-sp", role: "img" }, children);
536
+ }
537
+ function renderPolygon(p, sx, sy, fontFamily) {
538
+ const c = centroid(p.points);
539
+ const attrs = {
540
+ points: polyPoints(p.points, sx, sy),
541
+ class: `sx-sp-${p.role}`,
542
+ "data-polygon": p.id,
543
+ fill: p.fill ?? defaultPolygonFill(p.role)
544
+ };
545
+ return chunk3WNW5Y7P_cjs.group({ class: "sx-sp-polygon" }, [
546
+ chunk3WNW5Y7P_cjs.polygon(attrs),
547
+ ...p.role === "structure" ? renderRoofLines(p.points, sx, sy) : [],
548
+ ...p.label ? [chunk3WNW5Y7P_cjs.text({ x: sx(c.x), y: sy(c.y), class: "sx-sp-label", "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "central" }, p.label)] : []
549
+ ]);
550
+ }
551
+ function defaultPolygonFill(role) {
552
+ switch (role) {
553
+ case "parcel":
554
+ return "#fffefd";
555
+ case "structure":
556
+ return "url(#sx-sp-structure-hatch)";
557
+ case "zone":
558
+ return "#fbfdf8";
559
+ case "landscape":
560
+ return "url(#sx-sp-landscape-dot)";
561
+ case "parking":
562
+ return "url(#sx-sp-parking-hatch)";
563
+ }
564
+ }
565
+ function renderRoofLines(points, sx, sy) {
566
+ if (points.length < 4 || points.length > 8) return [];
567
+ const c = centroid(points);
568
+ return points.map((p) => chunk3WNW5Y7P_cjs.line({ x1: sx(c.x), y1: sy(c.y), x2: sx(p.x), y2: sy(p.y), class: "sx-sp-roofline" }));
569
+ }
570
+ function renderPath(p, sx, sy, len, road) {
571
+ const d = pathD(p.points, sx, sy);
572
+ const ratio = road ? 0.44 : p.role === "driveway" ? 0.42 : 0.34;
573
+ const maxWidth = road ? 44 : p.role === "driveway" ? 24 : 16;
574
+ const visualWidth = Math.min(Math.max(2.5, len(p.width) * ratio), maxWidth);
575
+ if (p.role === "driveway") {
576
+ const parts2 = [
577
+ chunk3WNW5Y7P_cjs.path({ d, class: "sx-sp-driveway-edge", "stroke-width": r2(visualWidth + 1.8), "data-path": p.id }),
578
+ chunk3WNW5Y7P_cjs.path({ d, class: "sx-sp-driveway", "stroke-width": visualWidth })
579
+ ];
580
+ if (p.width >= 12) parts2.push(chunk3WNW5Y7P_cjs.path({ d, class: "sx-sp-driveway-mark" }));
581
+ if (p.width >= 14) parts2.push(...renderDrivewayArrows(p.points, sx, sy, visualWidth));
582
+ return chunk3WNW5Y7P_cjs.group({ class: "sx-sp-path sx-sp-path-driveway" }, parts2);
583
+ }
584
+ const parts = [chunk3WNW5Y7P_cjs.path({ d, class: `sx-sp-${p.role}`, "stroke-width": visualWidth, "data-path": p.id })];
585
+ if (road) parts.push(chunk3WNW5Y7P_cjs.path({ d, class: "sx-sp-road-center" }));
586
+ return chunk3WNW5Y7P_cjs.group({ class: `sx-sp-path sx-sp-path-${p.role}` }, parts);
587
+ }
588
+ function screenPoints(points, sx, sy) {
589
+ return points.map((p) => ({ x: sx(p.x), y: sy(p.y) }));
590
+ }
591
+ function polylineLength(points) {
592
+ let total = 0;
593
+ for (let i = 0; i < points.length - 1; i++) {
594
+ const a = points[i];
595
+ const b = points[i + 1];
596
+ total += Math.hypot(b.x - a.x, b.y - a.y);
597
+ }
598
+ return total;
599
+ }
600
+ function samplePolyline(points, distance) {
601
+ let walked = 0;
602
+ for (let i = 0; i < points.length - 1; i++) {
603
+ const a2 = points[i];
604
+ const b2 = points[i + 1];
605
+ const dx = b2.x - a2.x;
606
+ const dy = b2.y - a2.y;
607
+ const seg = Math.hypot(dx, dy);
608
+ if (walked + seg >= distance) {
609
+ const t = seg === 0 ? 0 : (distance - walked) / seg;
610
+ return {
611
+ x: a2.x + dx * t,
612
+ y: a2.y + dy * t,
613
+ angle: Math.atan2(dy, dx) * 180 / Math.PI
614
+ };
615
+ }
616
+ walked += seg;
617
+ }
618
+ const a = points[Math.max(0, points.length - 2)];
619
+ const b = points[points.length - 1];
620
+ return { x: b.x, y: b.y, angle: Math.atan2(b.y - a.y, b.x - a.x) * 180 / Math.PI };
621
+ }
622
+ function renderDrivewayArrows(points, sx, sy, visualWidth) {
623
+ const screen = screenPoints(points, sx, sy);
624
+ const total = polylineLength(screen);
625
+ if (total < 64) return [];
626
+ const count = Math.min(3, Math.max(1, Math.floor(total / 180)));
627
+ const size = Math.min(Math.max(visualWidth * 0.44, 7), 12);
628
+ const arrows = [];
629
+ for (let i = 0; i < count; i++) {
630
+ const f = count === 1 ? 0.52 : (i + 1) / (count + 1);
631
+ const s = samplePolyline(screen, total * f);
632
+ arrows.push(renderDrivewayArrow(s.x, s.y, s.angle, size));
633
+ }
634
+ return arrows;
635
+ }
636
+ function renderDrivewayArrow(x, y, angle, size) {
637
+ const s = size;
638
+ const d = `M${r2(-s * 0.55)} ${r2(-s * 0.18)} L${r2(s * 0.12)} ${r2(-s * 0.18)} L${r2(s * 0.12)} ${r2(-s * 0.4)} L${r2(s * 0.62)} 0 L${r2(s * 0.12)} ${r2(s * 0.4)} L${r2(s * 0.12)} ${r2(s * 0.18)} L${r2(-s * 0.55)} ${r2(s * 0.18)} Z`;
639
+ return chunk3WNW5Y7P_cjs.group({ class: "sx-sp-driveway-arrow-g", transform: `translate(${r2(x)},${r2(y)}) rotate(${r2(angle)})` }, [
640
+ chunk3WNW5Y7P_cjs.path({ d, class: "sx-sp-driveway-arrow" })
641
+ ]);
642
+ }
643
+ function labelOnLine(points, label, sx, sy, fontFamily, cls, yOffset) {
644
+ let best = { a: points[0], b: points[Math.min(1, points.length - 1)], dist: -1 };
645
+ for (let i = 0; i < points.length - 1; i++) {
646
+ const a = points[i];
647
+ const b = points[i + 1];
648
+ const dx2 = sx(b.x) - sx(a.x);
649
+ const dy2 = sy(b.y) - sy(a.y);
650
+ const dist2 = Math.hypot(dx2, dy2);
651
+ if (dist2 > best.dist) best = { a, b, dist: dist2 };
652
+ }
653
+ const ax = sx(best.a.x);
654
+ const ay = sy(best.a.y);
655
+ const bx = sx(best.b.x);
656
+ const by = sy(best.b.y);
657
+ const dx = bx - ax;
658
+ const dy = by - ay;
659
+ const dist = Math.max(1, Math.hypot(dx, dy));
660
+ let angle = Math.atan2(dy, dx) * 180 / Math.PI;
661
+ if (angle > 90) angle -= 180;
662
+ if (angle < -90) angle += 180;
663
+ const x = r2((ax + bx) / 2 + -dy / dist * yOffset);
664
+ const y = r2((ay + by) / 2 + dx / dist * yOffset);
665
+ return chunk3WNW5Y7P_cjs.text(
666
+ {
667
+ x,
668
+ y,
669
+ class: cls,
670
+ "font-family": fontFamily,
671
+ "text-anchor": "middle",
672
+ "dominant-baseline": "central",
673
+ transform: Math.abs(angle) > 3 ? `rotate(${r2(angle)} ${x} ${y})` : void 0
674
+ },
675
+ label
676
+ );
677
+ }
678
+ function renderDimension(from, to, label, sx, sy, fontFamily) {
679
+ const x1 = sx(from.x);
680
+ const y1 = sy(from.y);
681
+ const x2 = sx(to.x);
682
+ const y2 = sy(to.y);
683
+ const vertical = Math.abs(y2 - y1) > Math.abs(x2 - x1);
684
+ const tick = 3.8;
685
+ const tickA = (x, y) => chunk3WNW5Y7P_cjs.line({ x1: r2(x - tick), y1: r2(y + tick), x2: r2(x + tick), y2: r2(y - tick), class: "sx-sp-dim" });
686
+ const midX = r2((x1 + x2) / 2);
687
+ const midY = r2((y1 + y2) / 2);
688
+ const textAttrs = {
689
+ class: "sx-sp-small",
690
+ "font-family": fontFamily,
691
+ "text-anchor": "middle"
692
+ };
693
+ return chunk3WNW5Y7P_cjs.group({ class: "sx-sp-measure" }, [
694
+ chunk3WNW5Y7P_cjs.line({ x1, y1, x2, y2, class: "sx-sp-dim" }),
695
+ tickA(x1, y1),
696
+ tickA(x2, y2),
697
+ chunk3WNW5Y7P_cjs.text(
698
+ vertical ? { ...textAttrs, x: r2(midX - 6), y: midY, transform: `rotate(-90 ${r2(midX - 6)} ${midY})` } : { ...textAttrs, x: midX, y: r2(midY - 5) },
699
+ label
700
+ )
701
+ ]);
702
+ }
703
+ function renderMarker(kind, x, y, sizePx, rotate, label, fontFamily) {
704
+ const s = Math.max(8, sizePx);
705
+ const parts = [];
706
+ if (kind === "tree") {
707
+ parts.push(chunk3WNW5Y7P_cjs.circle({ cx: x, cy: y, r: s / 2, class: "sx-sp-marker", "data-marker": kind }));
708
+ parts.push(chunk3WNW5Y7P_cjs.circle({ cx: x, cy: y, r: s * 0.28, class: "sx-sp-marker" }));
709
+ parts.push(chunk3WNW5Y7P_cjs.line({ x1: x - s * 0.42, y1: y, x2: x + s * 0.42, y2: y, class: "sx-sp-marker-line" }));
710
+ parts.push(chunk3WNW5Y7P_cjs.line({ x1: x, y1: y - s * 0.42, x2: x, y2: y + s * 0.42, class: "sx-sp-marker-line" }));
711
+ } else if (kind === "car") {
712
+ parts.push(
713
+ chunk3WNW5Y7P_cjs.group({ transform: `translate(${x},${y}) rotate(${rotate})`, "data-marker": kind }, [
714
+ chunk3WNW5Y7P_cjs.rect({ x: -s * 0.28, y: -s * 0.5, width: s * 0.56, height: s, rx: s * 0.12, class: "sx-sp-car" }),
715
+ chunk3WNW5Y7P_cjs.line({ x1: -s * 0.2, y1: -s * 0.2, x2: s * 0.2, y2: -s * 0.2, class: "sx-sp-car" }),
716
+ chunk3WNW5Y7P_cjs.line({ x1: -s * 0.2, y1: s * 0.22, x2: s * 0.2, y2: s * 0.22, class: "sx-sp-car" })
717
+ ])
718
+ );
719
+ } else {
720
+ const cls = kind === "entry" ? "sx-sp-entry" : kind === "pin" ? "sx-sp-pin" : "sx-sp-marker";
721
+ parts.push(chunk3WNW5Y7P_cjs.circle({ cx: x, cy: y, r: s / 3, class: cls, "data-marker": kind }));
722
+ }
723
+ if (label) parts.push(chunk3WNW5Y7P_cjs.text({ x, y: y - s / 2 - 5, class: "sx-sp-small", "font-family": fontFamily, "text-anchor": "middle" }, label));
724
+ return chunk3WNW5Y7P_cjs.group({ class: `sx-sp-marker-${kind}` }, parts);
725
+ }
726
+ function renderNorth(x, y, deg, fontFamily) {
727
+ return chunk3WNW5Y7P_cjs.group({ class: "sx-sp-north", transform: `translate(${x},${y})` }, [
728
+ chunk3WNW5Y7P_cjs.circle({ cx: 0, cy: 0, r: 17, fill: "none", stroke: "#475467", "stroke-width": 0.9 }),
729
+ chunk3WNW5Y7P_cjs.group({ transform: `rotate(${deg})` }, [
730
+ chunk3WNW5Y7P_cjs.path({ d: "M0 -14 L5 5 L0 1 L-5 5 Z", fill: "#344054" }),
731
+ chunk3WNW5Y7P_cjs.line({ x1: 0, y1: 1, x2: 0, y2: 13, stroke: "#344054", "stroke-width": 1.1 })
732
+ ]),
733
+ chunk3WNW5Y7P_cjs.text({ x: 0, y: -22, class: "sx-sp-small", "font-family": fontFamily, "text-anchor": "middle" }, "N")
734
+ ]);
735
+ }
736
+ function renderScaleBar(x, y, w, label, fontFamily) {
737
+ const ww = Math.max(36, w);
738
+ const seg = ww / 4;
739
+ const bars = [0, 1, 2, 3].map(
740
+ (i) => chunk3WNW5Y7P_cjs.rect({ x: r2(x + seg * i), y: r2(y - 4), width: r2(seg), height: 8, fill: i % 2 === 0 ? "#111827" : PAPER, stroke: "#111827", "stroke-width": 0.7 })
741
+ );
742
+ return chunk3WNW5Y7P_cjs.group({ class: "sx-sp-scale" }, [
743
+ ...bars,
744
+ chunk3WNW5Y7P_cjs.text({ x: r2(x + ww / 2), y: r2(y - 10), class: "sx-sp-small", "font-family": fontFamily, "text-anchor": "middle" }, label),
745
+ chunk3WNW5Y7P_cjs.text({ x, y: r2(y + 17), class: "sx-sp-small", "font-family": fontFamily, "text-anchor": "middle" }, "0")
746
+ ]);
747
+ }
748
+ function renderLegend(lay, x, y, availableWidth, fontFamily) {
749
+ const parts = [];
750
+ const colW = Math.max(160, availableWidth / LEGEND_COLS);
751
+ const rowH = 20;
752
+ const items = lay.legendItems.slice(0, LEGEND_LIMIT);
753
+ const rows = Math.ceil(items.length / LEGEND_COLS);
754
+ const boxH = 26 + rows * rowH + 10;
755
+ parts.push(chunk3WNW5Y7P_cjs.rect({ x, y: r2(y - 16), width: availableWidth, height: boxH, rx: 3, class: "sx-sp-legend-box" }));
756
+ parts.push(chunk3WNW5Y7P_cjs.text({ x: x + 10, y, class: "sx-sp-legend-title", "font-family": fontFamily }, "Legend"));
757
+ for (const [i, item] of items.entries()) {
758
+ const cx = x + i % LEGEND_COLS * colW;
759
+ const cy = y + 24 + Math.floor(i / LEGEND_COLS) * rowH;
760
+ parts.push(renderLegendSymbol(item.key, cx + 10, cy - 4));
761
+ parts.push(chunk3WNW5Y7P_cjs.text({ x: cx + 48, y: cy, class: "sx-sp-legend-text", "font-family": fontFamily }, item.label));
762
+ }
763
+ return chunk3WNW5Y7P_cjs.group({ class: "sx-sp-legend" }, parts);
764
+ }
765
+ function renderLegendSymbol(key, x, y) {
766
+ if (key === "tree") return chunk3WNW5Y7P_cjs.circle({ cx: x + 14, cy: y - 1, r: 6, class: "sx-sp-marker" });
767
+ if (key === "pin" || key === "entry" || key === "hydrant" || key === "well") {
768
+ return chunk3WNW5Y7P_cjs.circle({ cx: x + 14, cy: y - 1, r: 5, class: `sx-sp-${key === "pin" ? "pin" : "entry"}` });
769
+ }
770
+ if (["road", "driveway", "walkway", "trail"].includes(key)) {
771
+ const width = key === "road" ? 7 : key === "driveway" ? 5 : 4;
772
+ if (key === "driveway") {
773
+ return chunk3WNW5Y7P_cjs.group({ class: "sx-sp-legend-driveway" }, [
774
+ chunk3WNW5Y7P_cjs.line({ x1: x, y1: y, x2: x + 28, y2: y, class: "sx-sp-driveway-edge", "stroke-width": width + 2 }),
775
+ chunk3WNW5Y7P_cjs.line({ x1: x, y1: y, x2: x + 28, y2: y, class: "sx-sp-driveway", "stroke-width": width }),
776
+ chunk3WNW5Y7P_cjs.line({ x1: x + 3, y1: y, x2: x + 25, y2: y, class: "sx-sp-driveway-mark" })
777
+ ]);
778
+ }
779
+ return chunk3WNW5Y7P_cjs.line({ x1: x, y1: y, x2: x + 28, y2: y, class: `sx-sp-${key}`, "stroke-width": width });
780
+ }
781
+ if (["setback", "easement", "fence", "utility", "frontage", "boundary"].includes(key)) {
782
+ return chunk3WNW5Y7P_cjs.line({ x1: x, y1: y, x2: x + 28, y2: y, class: `sx-sp-${key}` });
783
+ }
784
+ const fill = key === "parcel" ? "#fffefd" : key === "structure" ? "url(#sx-sp-structure-hatch)" : key === "parking" ? "url(#sx-sp-parking-hatch)" : key === "landscape" ? "url(#sx-sp-landscape-dot)" : "#fffefd";
785
+ return chunk3WNW5Y7P_cjs.rect({ x, y: y - 7, width: 28, height: 12, rx: 1, class: `sx-sp-${key}`, fill });
786
+ }
787
+
788
+ // src/diagrams/siteplan/index.ts
789
+ var siteplan = {
790
+ type: "siteplan",
791
+ detect(text2) {
792
+ for (const raw of text2.split(/\r?\n/)) {
793
+ const t = raw.trim();
794
+ if (!t || t.startsWith("#") || t.startsWith("//")) continue;
795
+ return /^(siteplan|plotplan|parcelmap|propertymap)\b/i.test(t);
796
+ }
797
+ return false;
798
+ },
799
+ parse: parseSiteplan,
800
+ render(text2, config) {
801
+ return renderSiteplan(text2, config);
802
+ },
803
+ lint(text2) {
804
+ try {
805
+ const lay = layoutSiteplan(parseSiteplan(text2));
806
+ return lay.warnings.map((message) => ({
807
+ severity: "warning",
808
+ code: "siteplan/warning",
809
+ message,
810
+ fatal: false
811
+ }));
812
+ } catch {
813
+ return [];
814
+ }
815
+ }
816
+ };
817
+
818
+ exports.SiteplanParseError = SiteplanParseError;
819
+ exports.formatSiteLength = formatSiteLength;
820
+ exports.layoutSiteplan = layoutSiteplan;
821
+ exports.parseSiteplan = parseSiteplan;
822
+ exports.renderSiteplan = renderSiteplan;
823
+ exports.renderSiteplanLayout = renderSiteplanLayout;
824
+ exports.siteplan = siteplan;
825
+ //# sourceMappingURL=chunk-IBZKIMT5.cjs.map
826
+ //# sourceMappingURL=chunk-IBZKIMT5.cjs.map