@crystaldesign/planner-2d-core 26.11.0-beta.10

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 (78) hide show
  1. package/README.md +44 -0
  2. package/build/cjs/index.js +3402 -0
  3. package/build/esm/index.js +3357 -0
  4. package/build/types/planner-2d-core/src/collision/geometry.d.ts +21 -0
  5. package/build/types/planner-2d-core/src/collision/geometry.d.ts.map +1 -0
  6. package/build/types/planner-2d-core/src/core/logger.d.ts +12 -0
  7. package/build/types/planner-2d-core/src/core/logger.d.ts.map +1 -0
  8. package/build/types/planner-2d-core/src/core/units.d.ts +6 -0
  9. package/build/types/planner-2d-core/src/core/units.d.ts.map +1 -0
  10. package/build/types/planner-2d-core/src/core/vectors.d.ts +35 -0
  11. package/build/types/planner-2d-core/src/core/vectors.d.ts.map +1 -0
  12. package/build/types/planner-2d-core/src/docking/DockingPoint.d.ts +38 -0
  13. package/build/types/planner-2d-core/src/docking/DockingPoint.d.ts.map +1 -0
  14. package/build/types/planner-2d-core/src/docking/DockingPointHandler.d.ts +74 -0
  15. package/build/types/planner-2d-core/src/docking/DockingPointHandler.d.ts.map +1 -0
  16. package/build/types/planner-2d-core/src/docking/PlannerElement2D.d.ts +38 -0
  17. package/build/types/planner-2d-core/src/docking/PlannerElement2D.d.ts.map +1 -0
  18. package/build/types/planner-2d-core/src/docking/types.d.ts +26 -0
  19. package/build/types/planner-2d-core/src/docking/types.d.ts.map +1 -0
  20. package/build/types/planner-2d-core/src/index.d.ts +29 -0
  21. package/build/types/planner-2d-core/src/index.d.ts.map +1 -0
  22. package/build/types/planner-2d-core/src/stretch/axis.d.ts +38 -0
  23. package/build/types/planner-2d-core/src/stretch/axis.d.ts.map +1 -0
  24. package/build/types/planner-2d-core/src/stretch/elementTransform.d.ts +8 -0
  25. package/build/types/planner-2d-core/src/stretch/elementTransform.d.ts.map +1 -0
  26. package/build/types/planner-2d-core/src/stretch/normalize.d.ts +19 -0
  27. package/build/types/planner-2d-core/src/stretch/normalize.d.ts.map +1 -0
  28. package/build/types/planner-2d-core/src/stretch/pathTransform.d.ts +17 -0
  29. package/build/types/planner-2d-core/src/stretch/pathTransform.d.ts.map +1 -0
  30. package/build/types/planner-2d-core/src/stretch/points.d.ts +12 -0
  31. package/build/types/planner-2d-core/src/stretch/points.d.ts.map +1 -0
  32. package/build/types/planner-2d-core/src/stretch/resize.d.ts +7 -0
  33. package/build/types/planner-2d-core/src/stretch/resize.d.ts.map +1 -0
  34. package/build/types/planner-2d-core/src/stretch/rounding.d.ts +5 -0
  35. package/build/types/planner-2d-core/src/stretch/rounding.d.ts.map +1 -0
  36. package/build/types/planner-2d-core/src/stretch/state.d.ts +7 -0
  37. package/build/types/planner-2d-core/src/stretch/state.d.ts.map +1 -0
  38. package/build/types/planner-2d-core/src/stretch/stretchAreas.d.ts +7 -0
  39. package/build/types/planner-2d-core/src/stretch/stretchAreas.d.ts.map +1 -0
  40. package/build/types/planner-2d-core/src/stretch/stretchArticleSvg.d.ts +10 -0
  41. package/build/types/planner-2d-core/src/stretch/stretchArticleSvg.d.ts.map +1 -0
  42. package/build/types/planner-2d-core/src/stretch/types.d.ts +54 -0
  43. package/build/types/planner-2d-core/src/stretch/types.d.ts.map +1 -0
  44. package/build/types/planner-2d-core/src/stretch/viewBoxFix.d.ts +7 -0
  45. package/build/types/planner-2d-core/src/stretch/viewBoxFix.d.ts.map +1 -0
  46. package/build/types/planner-2d-core/src/svg/articleSvgParser.d.ts +54 -0
  47. package/build/types/planner-2d-core/src/svg/articleSvgParser.d.ts.map +1 -0
  48. package/build/types/planner-2d-core/src/svg/dom.d.ts +16 -0
  49. package/build/types/planner-2d-core/src/svg/dom.d.ts.map +1 -0
  50. package/build/types/planner-2d-core/src/svg/pathBoundingBox.d.ts +19 -0
  51. package/build/types/planner-2d-core/src/svg/pathBoundingBox.d.ts.map +1 -0
  52. package/build/types/planner-2d-core/src/svg/types.d.ts +32 -0
  53. package/build/types/planner-2d-core/src/svg/types.d.ts.map +1 -0
  54. package/build/types/planner-2d-core/src/testbed/DockingScene.d.ts +47 -0
  55. package/build/types/planner-2d-core/src/testbed/DockingScene.d.ts.map +1 -0
  56. package/build/types/planner-2d-core/src/testbed/SimplePlannerElement.d.ts +64 -0
  57. package/build/types/planner-2d-core/src/testbed/SimplePlannerElement.d.ts.map +1 -0
  58. package/build/types/planner-2d-core/src/tests/collision.test.d.ts +2 -0
  59. package/build/types/planner-2d-core/src/tests/collision.test.d.ts.map +1 -0
  60. package/build/types/planner-2d-core/src/tests/docking.test.d.ts +2 -0
  61. package/build/types/planner-2d-core/src/tests/docking.test.d.ts.map +1 -0
  62. package/build/types/planner-2d-core/src/tests/dockingScene.test.d.ts +2 -0
  63. package/build/types/planner-2d-core/src/tests/dockingScene.test.d.ts.map +1 -0
  64. package/build/types/planner-2d-core/src/tests/fixtures.d.ts +14 -0
  65. package/build/types/planner-2d-core/src/tests/fixtures.d.ts.map +1 -0
  66. package/build/types/planner-2d-core/src/tests/pathBoundingBox.test.d.ts +2 -0
  67. package/build/types/planner-2d-core/src/tests/pathBoundingBox.test.d.ts.map +1 -0
  68. package/build/types/planner-2d-core/src/tests/realArticleSvgs.test.d.ts +2 -0
  69. package/build/types/planner-2d-core/src/tests/realArticleSvgs.test.d.ts.map +1 -0
  70. package/build/types/planner-2d-core/src/tests/stretchDeviations.test.d.ts +2 -0
  71. package/build/types/planner-2d-core/src/tests/stretchDeviations.test.d.ts.map +1 -0
  72. package/build/types/planner-2d-core/src/tests/stretchRegression.test.d.ts +2 -0
  73. package/build/types/planner-2d-core/src/tests/stretchRegression.test.d.ts.map +1 -0
  74. package/build/types/planner-2d-core/src/tests/svgParser.test.d.ts +2 -0
  75. package/build/types/planner-2d-core/src/tests/svgParser.test.d.ts.map +1 -0
  76. package/build/types/planner-2d-core/src/transform/computeDockedTransform.d.ts +24 -0
  77. package/build/types/planner-2d-core/src/transform/computeDockedTransform.d.ts.map +1 -0
  78. package/package.json +24 -0
@@ -0,0 +1,3402 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
6
+ var _createClass = require('@babel/runtime/helpers/createClass');
7
+ var _defineProperty = require('@babel/runtime/helpers/defineProperty');
8
+ var serialize = require('w3c-xmlserializer');
9
+ var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
10
+ var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
11
+
12
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
+
14
+ var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck);
15
+ var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass);
16
+ var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty);
17
+ var serialize__default = /*#__PURE__*/_interopDefaultLegacy(serialize);
18
+ var _slicedToArray__default = /*#__PURE__*/_interopDefaultLegacy(_slicedToArray);
19
+ var _toConsumableArray__default = /*#__PURE__*/_interopDefaultLegacy(_toConsumableArray);
20
+
21
+ (function() {
22
+ const env = {"STAGE":"production"};
23
+ try {
24
+ if (process) {
25
+ process.env = Object.assign({}, process.env);
26
+ Object.assign(process.env, env);
27
+ return;
28
+ }
29
+ } catch (e) {} // avoid ReferenceError: process is not defined
30
+ globalThis.process = { env:env };
31
+ })();
32
+
33
+ /**
34
+ * SVG user units per centimeter in DIVA planner SVGs. Hand-synced copy of DivaUtils.UnitRecalc in
35
+ * @crystaldesign/diva-utils, not recomputed from 72/25.4 (which would differ); keep both values equal.
36
+ */
37
+ var UNIT_RECALC = 2.834637306;
38
+
39
+ /** 2D vector in planner coordinates. The math must stay identical to web-planner-logic's wcVectors — docking positions depend on it. */
40
+ var Vector2 = /*#__PURE__*/function () {
41
+ function Vector2(x, y) {
42
+ _classCallCheck__default["default"](this, Vector2);
43
+ _defineProperty__default["default"](this, "x", void 0);
44
+ _defineProperty__default["default"](this, "y", void 0);
45
+ this.x = x;
46
+ this.y = y;
47
+ }
48
+ return _createClass__default["default"](Vector2, [{
49
+ key: "toString",
50
+ value: function toString() {
51
+ return 'x: ' + this.x + ', y: ' + this.y;
52
+ }
53
+ }], [{
54
+ key: "add",
55
+ value: function add(vec1, vec2) {
56
+ return new Vector2(vec1.x + vec2.x, vec1.y + vec2.y);
57
+ }
58
+
59
+ /** Direction vector pointing from fromVec to toVec — note the reversed argument order. */
60
+ }, {
61
+ key: "getDirection",
62
+ value: function getDirection(toVec, fromVec) {
63
+ return new Vector2(toVec.x - fromVec.x, toVec.y - fromVec.y);
64
+ }
65
+ }, {
66
+ key: "getDistance",
67
+ value: function getDistance(vec1, vec2) {
68
+ return Math.sqrt(Math.pow(vec2.x - vec1.x, 2) + Math.pow(vec2.y - vec1.y, 2));
69
+ }
70
+ }, {
71
+ key: "getLength",
72
+ value: function getLength(vec) {
73
+ return Math.sqrt(Math.pow(vec.x, 2) + Math.pow(vec.y, 2));
74
+ }
75
+ }, {
76
+ key: "divNum",
77
+ value: function divNum(vec1, num) {
78
+ return new Vector2(vec1.x / num, vec1.y / num);
79
+ }
80
+ }, {
81
+ key: "mulNum",
82
+ value: function mulNum(vec1, num) {
83
+ return new Vector2(vec1.x * num, vec1.y * num);
84
+ }
85
+
86
+ /** Normalized dot product (cosine of the enclosed angle). */
87
+ }, {
88
+ key: "dotProduct",
89
+ value: function dotProduct(vec1, vec2) {
90
+ var magVec1 = Math.sqrt(vec1.x * vec1.x + vec1.y * vec1.y);
91
+ var magVec2 = Math.sqrt(vec2.x * vec2.x + vec2.y * vec2.y);
92
+ return (vec1.x * vec2.x + vec1.y * vec2.y) / (magVec1 * magVec2);
93
+ }
94
+
95
+ /** Rotates a position around the coordinate-system origin, angle in degrees. */
96
+ }, {
97
+ key: "rotateOrigin",
98
+ value: function rotateOrigin(vec, angleDeg) {
99
+ var angleRad = angleDeg * (Math.PI / 180);
100
+ var result = new Vector2(0, 0);
101
+ result.x = Math.cos(angleRad) * vec.x - Math.sin(angleRad) * vec.y;
102
+ result.y = Math.sin(angleRad) * vec.x + Math.cos(angleRad) * vec.y;
103
+ return result;
104
+ }
105
+
106
+ /** Enclosed angle between the two vectors in radians. */
107
+ }, {
108
+ key: "angleRad",
109
+ value: function angleRad(vec1, vec2) {
110
+ return Math.acos(this.dotProduct(vec1, vec2));
111
+ }
112
+
113
+ /** Enclosed angle between the two vectors in degrees. */
114
+ }, {
115
+ key: "angleDeg",
116
+ value: function angleDeg(vec1, vec2) {
117
+ return this.angleRad(vec1, vec2) * 180 / Math.PI;
118
+ }
119
+ }, {
120
+ key: "normalize",
121
+ value: function normalize(vec1) {
122
+ var distance = Math.sqrt(Math.pow(vec1.x, 2) + Math.pow(vec1.y, 2));
123
+ return new Vector2(vec1.x / distance, vec1.y / distance);
124
+ }
125
+ }]);
126
+ }();
127
+
128
+ /** 3D vector in planner world coordinates (x/z = ground plane, y = height). */
129
+ var Vector3 = /*#__PURE__*/function () {
130
+ function Vector3(x, y, z) {
131
+ _classCallCheck__default["default"](this, Vector3);
132
+ _defineProperty__default["default"](this, "x", void 0);
133
+ _defineProperty__default["default"](this, "y", void 0);
134
+ _defineProperty__default["default"](this, "z", void 0);
135
+ this.x = x;
136
+ this.y = y;
137
+ this.z = z;
138
+ }
139
+ return _createClass__default["default"](Vector3, [{
140
+ key: "toString",
141
+ value: function toString() {
142
+ return 'Vector3 x: ' + this.x + ', y: ' + this.y + ', z: ' + this.z;
143
+ }
144
+ }], [{
145
+ key: "add",
146
+ value: function add(vec1, vec2) {
147
+ return new Vector3(vec1.x + vec2.x, vec1.y + vec2.y, vec1.z + vec2.z);
148
+ }
149
+ }, {
150
+ key: "divNum",
151
+ value: function divNum(vec1, num) {
152
+ return new Vector3(vec1.x / num, vec1.y / num, vec1.z / num);
153
+ }
154
+ }, {
155
+ key: "mulNum",
156
+ value: function mulNum(vec1, num) {
157
+ return new Vector3(vec1.x * num, vec1.y * num, vec1.z * num);
158
+ }
159
+ }]);
160
+ }();
161
+
162
+ /** Logging surface this package emits to; matches the shape of loggers created by DivaUtils.initLog. */
163
+
164
+ var noopLogger = {
165
+ trace: function trace() {
166
+ return undefined;
167
+ },
168
+ debug: function debug() {
169
+ return undefined;
170
+ },
171
+ info: function info() {
172
+ return undefined;
173
+ },
174
+ warn: function warn() {
175
+ return undefined;
176
+ },
177
+ error: function error() {
178
+ return undefined;
179
+ }
180
+ };
181
+ var activeLogger = noopLogger;
182
+
183
+ /** Injects the logger used by this package. Defaults to a no-op, so the package has no logging dependency. */
184
+ function setPlanner2DLogger(logger) {
185
+ activeLogger = logger;
186
+ }
187
+ function getPlanner2DLogger() {
188
+ return activeLogger;
189
+ }
190
+
191
+ /** Minimal DOM services this package needs — satisfied by browser globals and by a jsdom window. */
192
+
193
+ var configuredDom;
194
+
195
+ /** Provides the DOM implementation used for XML parsing. Optional in Node: without a call, jsdom is loaded lazily as fallback. */
196
+ function configureDom(services) {
197
+ configuredDom = services;
198
+ }
199
+
200
+ /** Lazily loads a jsdom window in Node. The indirect require keeps browser bundlers from following/bundling jsdom. */
201
+ function tryLoadJsdomServices() {
202
+ if (typeof window !== 'undefined') return undefined;
203
+ try {
204
+ var nodeRequire = eval('require');
205
+ var _nodeRequire = nodeRequire('jsdom'),
206
+ JSDOM = _nodeRequire.JSDOM;
207
+ var jsdomWindow = new JSDOM('').window;
208
+ return {
209
+ DOMParser: jsdomWindow.DOMParser,
210
+ XMLSerializer: jsdomWindow.XMLSerializer
211
+ };
212
+ } catch (_unused) {
213
+ return undefined;
214
+ }
215
+ }
216
+ function resolveDomParser() {
217
+ var _configuredDom;
218
+ if ((_configuredDom = configuredDom) !== null && _configuredDom !== void 0 && _configuredDom.DOMParser) return configuredDom.DOMParser;
219
+ if (typeof DOMParser !== 'undefined') return DOMParser;
220
+ var jsdomServices = tryLoadJsdomServices();
221
+ if (jsdomServices) {
222
+ configuredDom = jsdomServices;
223
+ return jsdomServices.DOMParser;
224
+ }
225
+ throw new Error("planner-2d-core: no DOMParser available — in Node install jsdom or call configureDom(new JSDOM('').window) once at startup");
226
+ }
227
+ function parseXml(content) {
228
+ var mimeType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'application/xml';
229
+ var Parser = resolveDomParser();
230
+ return new Parser().parseFromString(content, mimeType);
231
+ }
232
+ function serializeXml(document) {
233
+ var _configuredDom$XMLSer, _configuredDom2;
234
+ var Serializer = (_configuredDom$XMLSer = (_configuredDom2 = configuredDom) === null || _configuredDom2 === void 0 ? void 0 : _configuredDom2.XMLSerializer) !== null && _configuredDom$XMLSer !== void 0 ? _configuredDom$XMLSer : typeof XMLSerializer !== 'undefined' ? XMLSerializer : undefined;
235
+ if (Serializer) return new Serializer().serializeToString(document);
236
+ return serialize__default["default"](document);
237
+ }
238
+
239
+ /** Every connector type the planner knows. */
240
+ var DOCKING_TYPES = ['AVR', 'AVL', 'AVC', 'AVO', 'AVU', 'AVS', 'AVN'];
241
+ /** Narrows an untrusted string to a DockingType. */
242
+ function isDockingType(value) {
243
+ return typeof value === 'string' && DOCKING_TYPES.includes(value);
244
+ }
245
+
246
+ /** A raw AV docking line as drawn in an article SVG (SVG user units, not yet minBorder-corrected). */
247
+
248
+ /** Minimum x/y over all non-AV geometry of an SVG — the offset docking-point coordinates are corrected by. */
249
+
250
+ function _createForOfIteratorHelper$7(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$7(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
251
+ function _unsupportedIterableToArray$7(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$7(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$7(r, a) : void 0; } }
252
+ function _arrayLikeToArray$7(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
253
+ var COMMAND_PARAM_COUNT = {
254
+ M: 2,
255
+ L: 2,
256
+ H: 1,
257
+ V: 1,
258
+ C: 6,
259
+ S: 4,
260
+ Q: 4,
261
+ T: 2,
262
+ A: 7,
263
+ Z: 0
264
+ };
265
+
266
+ /** Parameter indices (within one A group) that are single-digit flags per SVG spec. */
267
+ var ARC_FLAG_INDICES = [3, 4];
268
+ var NUMBER_PATTERN = /^[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/;
269
+ function isSeparator(ch) {
270
+ return ch === ' ' || ch === ',' || ch === '\t' || ch === '\n' || ch === '\r' || ch === '\f';
271
+ }
272
+ function isCommandLetter(ch) {
273
+ return ch.toUpperCase() in COMMAND_PARAM_COUNT;
274
+ }
275
+
276
+ /**
277
+ * Tokenizes an SVG path `d` attribute into absolute/relative commands with their numeric parameters, covering
278
+ * the full command set, implicit command repetition, scientific notation and unspaced arc flags.
279
+ * Throws on unknown commands and malformed numbers.
280
+ */
281
+ function parsePathCommands(d) {
282
+ var commands = [];
283
+ var i = 0;
284
+ var pendingCommand = '';
285
+ var skipSeparators = function skipSeparators() {
286
+ while (i < d.length && isSeparator(d[i])) i++;
287
+ };
288
+ var readNumber = function readNumber(isFlag) {
289
+ skipSeparators();
290
+ if (isFlag) {
291
+ var ch = d[i];
292
+ if (ch !== '0' && ch !== '1') throw new Error("invalid arc flag '".concat(ch, "' at position ").concat(i, " in path data"));
293
+ i++;
294
+ return Number(ch);
295
+ }
296
+ var match = NUMBER_PATTERN.exec(d.substring(i));
297
+ if (!match) throw new Error("expected number at position ".concat(i, " in path data"));
298
+ i += match[0].length;
299
+ return Number(match[0]);
300
+ };
301
+ while (i < d.length) {
302
+ skipSeparators();
303
+ if (i >= d.length) break;
304
+ var ch = d[i];
305
+ if (isCommandLetter(ch)) {
306
+ pendingCommand = ch;
307
+ i++;
308
+ if (ch.toUpperCase() === 'Z') {
309
+ commands.push({
310
+ command: ch,
311
+ params: []
312
+ });
313
+ pendingCommand = '';
314
+ }
315
+ continue;
316
+ }
317
+ if (/[a-zA-Z]/.test(ch)) throw new Error("unsupported path command '".concat(ch, "' at position ").concat(i));
318
+ if (!pendingCommand) throw new Error("number without a preceding command at position ".concat(i, " in path data"));
319
+ var paramCount = COMMAND_PARAM_COUNT[pendingCommand.toUpperCase()];
320
+ var isArc = pendingCommand.toUpperCase() === 'A';
321
+ var params = [];
322
+ for (var p = 0; p < paramCount; p++) {
323
+ params.push(readNumber(isArc && ARC_FLAG_INDICES.includes(p)));
324
+ }
325
+ commands.push({
326
+ command: pendingCommand,
327
+ params: params
328
+ });
329
+
330
+ // Per spec, further coordinate groups after M/m continue as L/l; all other commands repeat themselves.
331
+ if (pendingCommand === 'M') pendingCommand = 'L';else if (pendingCommand === 'm') pendingCommand = 'l';
332
+ }
333
+ return commands;
334
+ }
335
+ function cubicAxisExtrema(p0, p1, p2, p3) {
336
+ // The derivative of a cubic Bezier is the quadratic a*t^2 + b*t + c.
337
+ var a = -p0 + 3 * p1 - 3 * p2 + p3;
338
+ var b = 2 * (p0 - 2 * p1 + p2);
339
+ var c = p1 - p0;
340
+ var roots = [];
341
+ if (Math.abs(a) < 1e-12) {
342
+ if (Math.abs(b) > 1e-12) roots.push(-c / b);
343
+ } else {
344
+ var discriminant = b * b - 4 * a * c;
345
+ if (discriminant >= 0) {
346
+ var sqrtD = Math.sqrt(discriminant);
347
+ roots.push((-b + sqrtD) / (2 * a), (-b - sqrtD) / (2 * a));
348
+ }
349
+ }
350
+ return roots.filter(function (t) {
351
+ return t > 0 && t < 1;
352
+ });
353
+ }
354
+ function cubicAxisValue(t, p0, p1, p2, p3) {
355
+ var mt = 1 - t;
356
+ return mt * mt * mt * p0 + 3 * mt * mt * t * p1 + 3 * mt * t * t * p2 + t * t * t * p3;
357
+ }
358
+ function quadraticAxisExtremum(p0, p1, p2) {
359
+ var denominator = p0 - 2 * p1 + p2;
360
+ if (Math.abs(denominator) < 1e-12) return undefined;
361
+ var t = (p0 - p1) / denominator;
362
+ return t > 0 && t < 1 ? t : undefined;
363
+ }
364
+ function quadraticAxisValue(t, p0, p1, p2) {
365
+ var mt = 1 - t;
366
+ return mt * mt * p0 + 2 * mt * t * p1 + t * t * p2;
367
+ }
368
+ var TWO_PI = Math.PI * 2;
369
+ function normalizeAngle(angle) {
370
+ var result = angle % TWO_PI;
371
+ if (result < 0) result += TWO_PI;
372
+ return result;
373
+ }
374
+
375
+ /** Expands the bounds by the extrema of an elliptical arc (SVG endpoint parameterization, spec section F.6.5). */
376
+ function expandArcBounds(from, rx, ry, rotationDeg, largeArc, sweep, to, expand) {
377
+ rx = Math.abs(rx);
378
+ ry = Math.abs(ry);
379
+ if (rx === 0 || ry === 0) return; // degenerate arc is a straight line - endpoints already expanded
380
+
381
+ var phi = rotationDeg * Math.PI / 180;
382
+ var cosPhi = Math.cos(phi);
383
+ var sinPhi = Math.sin(phi);
384
+ var dx2 = (from.x - to.x) / 2;
385
+ var dy2 = (from.y - to.y) / 2;
386
+ var x1p = cosPhi * dx2 + sinPhi * dy2;
387
+ var y1p = -sinPhi * dx2 + cosPhi * dy2;
388
+
389
+ // Scale up radii that are too small to span the endpoints (spec F.6.6).
390
+ var lambda = x1p * x1p / (rx * rx) + y1p * y1p / (ry * ry);
391
+ if (lambda > 1) {
392
+ var scale = Math.sqrt(lambda);
393
+ rx *= scale;
394
+ ry *= scale;
395
+ }
396
+ var rxSq = rx * rx;
397
+ var rySq = ry * ry;
398
+ var radicand = rxSq * rySq - rxSq * y1p * y1p - rySq * x1p * x1p;
399
+ if (radicand < 0) radicand = 0;
400
+ var coefficient = (largeArc !== sweep ? 1 : -1) * Math.sqrt(radicand / (rxSq * y1p * y1p + rySq * x1p * x1p));
401
+ var cxp = coefficient * (rx * y1p) / ry;
402
+ var cyp = coefficient * (-ry * x1p) / rx;
403
+ var cx = cosPhi * cxp - sinPhi * cyp + (from.x + to.x) / 2;
404
+ var cy = sinPhi * cxp + cosPhi * cyp + (from.y + to.y) / 2;
405
+ var angleOf = function angleOf(vx, vy) {
406
+ return Math.atan2(vy, vx);
407
+ };
408
+ var theta1 = angleOf((x1p - cxp) / rx, (y1p - cyp) / ry);
409
+ var theta2 = angleOf((-x1p - cxp) / rx, (-y1p - cyp) / ry);
410
+ var deltaTheta = theta2 - theta1;
411
+ if (sweep === 0 && deltaTheta > 0) deltaTheta -= TWO_PI;else if (sweep === 1 && deltaTheta < 0) deltaTheta += TWO_PI;
412
+ var isOnArc = function isOnArc(theta) {
413
+ if (deltaTheta >= 0) return normalizeAngle(theta - theta1) <= deltaTheta;
414
+ return normalizeAngle(theta1 - theta) <= -deltaTheta;
415
+ };
416
+ var pointAt = function pointAt(theta) {
417
+ return {
418
+ x: cx + rx * Math.cos(theta) * cosPhi - ry * Math.sin(theta) * sinPhi,
419
+ y: cy + rx * Math.cos(theta) * sinPhi + ry * Math.sin(theta) * cosPhi
420
+ };
421
+ };
422
+
423
+ // Angles where dx/dtheta = 0 resp. dy/dtheta = 0 (extrema of the rotated ellipse).
424
+ var thetaXExtremum = Math.atan2(-ry * sinPhi, rx * cosPhi);
425
+ var thetaYExtremum = Math.atan2(ry * cosPhi, rx * sinPhi);
426
+ var candidates = [thetaXExtremum, thetaXExtremum + Math.PI, thetaYExtremum, thetaYExtremum + Math.PI];
427
+ for (var _i = 0, _candidates = candidates; _i < _candidates.length; _i++) {
428
+ var theta = _candidates[_i];
429
+ if (!isOnArc(theta)) continue;
430
+ var point = pointAt(theta);
431
+ expand(point.x, point.y);
432
+ }
433
+ }
434
+
435
+ /** Exact bounding box of an SVG path `d` attribute, honoring Bezier extrema and elliptical arcs. Undefined for empty path data. */
436
+ function pathBoundingBox(d) {
437
+ var commands = parsePathCommands(d);
438
+ if (commands.length === 0) return undefined;
439
+ var minX = Number.POSITIVE_INFINITY;
440
+ var minY = Number.POSITIVE_INFINITY;
441
+ var maxX = Number.NEGATIVE_INFINITY;
442
+ var maxY = Number.NEGATIVE_INFINITY;
443
+ var expand = function expand(x, y) {
444
+ if (x < minX) minX = x;
445
+ if (y < minY) minY = y;
446
+ if (x > maxX) maxX = x;
447
+ if (y > maxY) maxY = y;
448
+ };
449
+ var current = {
450
+ x: 0,
451
+ y: 0
452
+ };
453
+ var subpathStart = {
454
+ x: 0,
455
+ y: 0
456
+ };
457
+ var previousCubicControl;
458
+ var previousQuadraticControl;
459
+ var previousCommand = '';
460
+ var hasGeometry = false;
461
+ var _iterator = _createForOfIteratorHelper$7(commands),
462
+ _step;
463
+ try {
464
+ var _loop = function _loop() {
465
+ var _step$value = _step.value,
466
+ command = _step$value.command,
467
+ params = _step$value.params;
468
+ var upper = command.toUpperCase();
469
+ var isRelative = command !== upper;
470
+ var absolute = function absolute(index, axisBase) {
471
+ return isRelative ? axisBase + params[index] : params[index];
472
+ };
473
+ var nextCubicControl;
474
+ var nextQuadraticControl;
475
+ switch (upper) {
476
+ case 'M':
477
+ {
478
+ current = {
479
+ x: absolute(0, current.x),
480
+ y: absolute(1, current.y)
481
+ };
482
+ subpathStart = current;
483
+ expand(current.x, current.y);
484
+ hasGeometry = true;
485
+ break;
486
+ }
487
+ case 'L':
488
+ {
489
+ expand(current.x, current.y);
490
+ current = {
491
+ x: absolute(0, current.x),
492
+ y: absolute(1, current.y)
493
+ };
494
+ expand(current.x, current.y);
495
+ hasGeometry = true;
496
+ break;
497
+ }
498
+ case 'H':
499
+ {
500
+ expand(current.x, current.y);
501
+ current = {
502
+ x: isRelative ? current.x + params[0] : params[0],
503
+ y: current.y
504
+ };
505
+ expand(current.x, current.y);
506
+ hasGeometry = true;
507
+ break;
508
+ }
509
+ case 'V':
510
+ {
511
+ expand(current.x, current.y);
512
+ current = {
513
+ x: current.x,
514
+ y: isRelative ? current.y + params[0] : params[0]
515
+ };
516
+ expand(current.x, current.y);
517
+ hasGeometry = true;
518
+ break;
519
+ }
520
+ case 'C':
521
+ case 'S':
522
+ {
523
+ var control1;
524
+ var control2;
525
+ var end;
526
+ if (upper === 'C') {
527
+ control1 = {
528
+ x: absolute(0, current.x),
529
+ y: absolute(1, current.y)
530
+ };
531
+ control2 = {
532
+ x: absolute(2, current.x),
533
+ y: absolute(3, current.y)
534
+ };
535
+ end = {
536
+ x: absolute(4, current.x),
537
+ y: absolute(5, current.y)
538
+ };
539
+ } else {
540
+ var reflects = previousCommand === 'C' || previousCommand === 'S';
541
+ control1 = reflects && previousCubicControl ? {
542
+ x: 2 * current.x - previousCubicControl.x,
543
+ y: 2 * current.y - previousCubicControl.y
544
+ } : {
545
+ x: current.x,
546
+ y: current.y
547
+ };
548
+ control2 = {
549
+ x: absolute(0, current.x),
550
+ y: absolute(1, current.y)
551
+ };
552
+ end = {
553
+ x: absolute(2, current.x),
554
+ y: absolute(3, current.y)
555
+ };
556
+ }
557
+ expand(current.x, current.y);
558
+ expand(end.x, end.y);
559
+ var _iterator2 = _createForOfIteratorHelper$7(cubicAxisExtrema(current.x, control1.x, control2.x, end.x)),
560
+ _step2;
561
+ try {
562
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
563
+ var t = _step2.value;
564
+ expand(cubicAxisValue(t, current.x, control1.x, control2.x, end.x), cubicAxisValue(t, current.y, control1.y, control2.y, end.y));
565
+ }
566
+ } catch (err) {
567
+ _iterator2.e(err);
568
+ } finally {
569
+ _iterator2.f();
570
+ }
571
+ var _iterator3 = _createForOfIteratorHelper$7(cubicAxisExtrema(current.y, control1.y, control2.y, end.y)),
572
+ _step3;
573
+ try {
574
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
575
+ var _t = _step3.value;
576
+ expand(cubicAxisValue(_t, current.x, control1.x, control2.x, end.x), cubicAxisValue(_t, current.y, control1.y, control2.y, end.y));
577
+ }
578
+ } catch (err) {
579
+ _iterator3.e(err);
580
+ } finally {
581
+ _iterator3.f();
582
+ }
583
+ nextCubicControl = control2;
584
+ current = end;
585
+ hasGeometry = true;
586
+ break;
587
+ }
588
+ case 'Q':
589
+ case 'T':
590
+ {
591
+ var control;
592
+ var _end;
593
+ if (upper === 'Q') {
594
+ control = {
595
+ x: absolute(0, current.x),
596
+ y: absolute(1, current.y)
597
+ };
598
+ _end = {
599
+ x: absolute(2, current.x),
600
+ y: absolute(3, current.y)
601
+ };
602
+ } else {
603
+ var _reflects = previousCommand === 'Q' || previousCommand === 'T';
604
+ control = _reflects && previousQuadraticControl ? {
605
+ x: 2 * current.x - previousQuadraticControl.x,
606
+ y: 2 * current.y - previousQuadraticControl.y
607
+ } : {
608
+ x: current.x,
609
+ y: current.y
610
+ };
611
+ _end = {
612
+ x: absolute(0, current.x),
613
+ y: absolute(1, current.y)
614
+ };
615
+ }
616
+ expand(current.x, current.y);
617
+ expand(_end.x, _end.y);
618
+ var tx = quadraticAxisExtremum(current.x, control.x, _end.x);
619
+ if (tx !== undefined) expand(quadraticAxisValue(tx, current.x, control.x, _end.x), quadraticAxisValue(tx, current.y, control.y, _end.y));
620
+ var ty = quadraticAxisExtremum(current.y, control.y, _end.y);
621
+ if (ty !== undefined) expand(quadraticAxisValue(ty, current.x, control.x, _end.x), quadraticAxisValue(ty, current.y, control.y, _end.y));
622
+ nextQuadraticControl = control;
623
+ current = _end;
624
+ hasGeometry = true;
625
+ break;
626
+ }
627
+ case 'A':
628
+ {
629
+ var _end2 = {
630
+ x: absolute(5, current.x),
631
+ y: absolute(6, current.y)
632
+ };
633
+ expand(current.x, current.y);
634
+ expand(_end2.x, _end2.y);
635
+ expandArcBounds(current, params[0], params[1], params[2], params[3], params[4], _end2, expand);
636
+ current = _end2;
637
+ hasGeometry = true;
638
+ break;
639
+ }
640
+ case 'Z':
641
+ {
642
+ current = subpathStart;
643
+ break;
644
+ }
645
+ }
646
+ previousCommand = upper;
647
+ previousCubicControl = nextCubicControl;
648
+ previousQuadraticControl = nextQuadraticControl;
649
+ };
650
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
651
+ _loop();
652
+ }
653
+ } catch (err) {
654
+ _iterator.e(err);
655
+ } finally {
656
+ _iterator.f();
657
+ }
658
+ if (!hasGeometry) return undefined;
659
+ return {
660
+ minX: minX,
661
+ minY: minY,
662
+ maxX: maxX,
663
+ maxY: maxY
664
+ };
665
+ }
666
+
667
+ function _createForOfIteratorHelper$6(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$6(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
668
+ function _unsupportedIterableToArray$6(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$6(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$6(r, a) : void 0; } }
669
+ function _arrayLikeToArray$6(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
670
+ /** XPathResult.ORDERED_NODE_SNAPSHOT_TYPE — used numerically because XML documents do not always expose the constant. */
671
+ var ORDERED_NODE_SNAPSHOT_TYPE = 7;
672
+
673
+ /** All elements whose id starts with the given prefix, in document order. */
674
+ function snapshotByIdPrefix(xmlDocument, idPrefix) {
675
+ var result = xmlDocument.evaluate("//*[starts-with(@id,'".concat(idPrefix, "')]"), xmlDocument, null, ORDERED_NODE_SNAPSHOT_TYPE, null);
676
+ var elements = [];
677
+ for (var i = 0; i < result.snapshotLength; i++) elements.push(result.snapshotItem(i));
678
+ return elements;
679
+ }
680
+
681
+ /**
682
+ * Extracts all AV docking lines of an article SVG, AVL sorted first (the planner relies on that order).
683
+ * Throws for AV elements that are not `<line>`.
684
+ */
685
+ function getDockingPointLines(content) {
686
+ var dockingPointLines = [];
687
+ var xmlDocument = parseXml(content);
688
+ var _iterator = _createForOfIteratorHelper$6(snapshotByIdPrefix(xmlDocument, 'AV')),
689
+ _step;
690
+ try {
691
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
692
+ var _element$getAttribute, _element$getAttribute2;
693
+ var element = _step.value;
694
+ if (element.nodeName !== 'line') throw new Error('nodename type: ' + element.nodeName + ' not implemented');
695
+ dockingPointLines.push({
696
+ x1: Number(element.getAttribute('x1')),
697
+ y1: Number(element.getAttribute('y1')),
698
+ x2: Number(element.getAttribute('x2')),
699
+ y2: Number(element.getAttribute('y2')),
700
+ dockingName: (_element$getAttribute = element.getAttribute('id')) !== null && _element$getAttribute !== void 0 ? _element$getAttribute : '',
701
+ dockingType: ((_element$getAttribute2 = element.getAttribute('id')) !== null && _element$getAttribute2 !== void 0 ? _element$getAttribute2 : '').substring(0, 3)
702
+ });
703
+ }
704
+
705
+ // Deliberately non-transitive comparator: the order it produces is a planner contract.
706
+ } catch (err) {
707
+ _iterator.e(err);
708
+ } finally {
709
+ _iterator.f();
710
+ }
711
+ dockingPointLines.sort(function (a, b) {
712
+ if (a.dockingType === 'AVL') return -1;
713
+ if (a.dockingType === 'AVR' && ['AVR', 'AVC', 'AVU', 'AVO', 'AVS', 'AVN'].includes(b.dockingType)) return -1;
714
+ return 0;
715
+ });
716
+ return dockingPointLines;
717
+ }
718
+
719
+ /**
720
+ * Returns the points of the single `<polygon>` whose id starts with idPrefix: undefined when zero or more
721
+ * than one id matches, empty array when the match is not a polygon.
722
+ */
723
+ function getPolygonPoints(content, idPrefix) {
724
+ var points = [];
725
+ var xmlDocument = parseXml(content);
726
+ var matches = snapshotByIdPrefix(xmlDocument, idPrefix);
727
+ if (matches.length !== 1) return undefined;
728
+ var element = matches[0];
729
+ if (element.nodeName === 'polygon') {
730
+ var pointsAsString = element.getAttribute('points');
731
+ if (!pointsAsString) return undefined;
732
+ var _iterator2 = _createForOfIteratorHelper$6(pointsAsString.split(' ')),
733
+ _step2;
734
+ try {
735
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
736
+ var pair = _step2.value;
737
+ var xAndY = pair.split(',');
738
+ if (xAndY.length !== 2) continue;
739
+ points.push(new Vector2(Number(xAndY[0]), Number(xAndY[1])));
740
+ }
741
+ } catch (err) {
742
+ _iterator2.e(err);
743
+ } finally {
744
+ _iterator2.f();
745
+ }
746
+ }
747
+ return points;
748
+ }
749
+ function getBoundingBoxOfPoints(points) {
750
+ var xValues = points.map(function (point) {
751
+ return point.x;
752
+ });
753
+ var yValues = points.map(function (point) {
754
+ return point.y;
755
+ });
756
+ var minX = Math.min.apply(Math, _toConsumableArray__default["default"](xValues));
757
+ var minY = Math.min.apply(Math, _toConsumableArray__default["default"](yValues));
758
+ return {
759
+ minX: minX,
760
+ minY: minY,
761
+ width: Math.max.apply(Math, _toConsumableArray__default["default"](xValues)) - minX,
762
+ height: Math.max.apply(Math, _toConsumableArray__default["default"](yValues)) - minY
763
+ };
764
+ }
765
+ function parsePointsAttribute(pointsAttribute) {
766
+ return pointsAttribute.split(/\s+/).reduce(function (accumulator, pair) {
767
+ var _pair$split = pair.split(','),
768
+ _pair$split2 = _slicedToArray__default["default"](_pair$split, 2),
769
+ x = _pair$split2[0],
770
+ y = _pair$split2[1];
771
+ if (x != null && y != null && x !== '') accumulator.push(new Vector2(Number(x), Number(y)));
772
+ return accumulator;
773
+ }, []);
774
+ }
775
+ function geometryOfFirstShape(content, idPrefix) {
776
+ var xmlDocument = parseXml(content);
777
+ var _iterator3 = _createForOfIteratorHelper$6(snapshotByIdPrefix(xmlDocument, idPrefix)),
778
+ _step3;
779
+ try {
780
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
781
+ var element = _step3.value;
782
+ warnOnTransform(element, "".concat(idPrefix, " geometry"));
783
+ if (element.nodeName === 'rect') {
784
+ var _element$getAttribute3, _element$getAttribute4, _element$getAttribute5, _element$getAttribute6;
785
+ return {
786
+ minX: parseFloat((_element$getAttribute3 = element.getAttribute('x')) !== null && _element$getAttribute3 !== void 0 ? _element$getAttribute3 : '0'),
787
+ minY: parseFloat((_element$getAttribute4 = element.getAttribute('y')) !== null && _element$getAttribute4 !== void 0 ? _element$getAttribute4 : '0'),
788
+ width: parseFloat((_element$getAttribute5 = element.getAttribute('width')) !== null && _element$getAttribute5 !== void 0 ? _element$getAttribute5 : '0'),
789
+ height: parseFloat((_element$getAttribute6 = element.getAttribute('height')) !== null && _element$getAttribute6 !== void 0 ? _element$getAttribute6 : '0')
790
+ };
791
+ }
792
+ if (element.nodeName === 'polygon') {
793
+ var pointsAttribute = element.getAttribute('points');
794
+ if (!pointsAttribute) continue;
795
+ var points = parsePointsAttribute(pointsAttribute);
796
+ if (points.length) return getBoundingBoxOfPoints(points);
797
+ }
798
+ if (element.nodeName === 'path') {
799
+ var bounds = safePathBounds(element);
800
+ if (bounds) return {
801
+ minX: bounds.minX,
802
+ minY: bounds.minY,
803
+ width: bounds.maxX - bounds.minX,
804
+ height: bounds.maxY - bounds.minY
805
+ };
806
+ }
807
+ }
808
+ } catch (err) {
809
+ _iterator3.e(err);
810
+ } finally {
811
+ _iterator3.f();
812
+ }
813
+ return undefined;
814
+ }
815
+
816
+ /**
817
+ * Returns the OLF geometry from SVG attributes (untransformed) — rect, polygon and path.
818
+ * A `<g id="OLF…">` wrapper yields undefined: only shape elements are measured, never a group's children.
819
+ * Widening that would change which articles get an OLF offset.
820
+ */
821
+ function getOlfGeometry(content) {
822
+ return geometryOfFirstShape(content, 'OLF');
823
+ }
824
+
825
+ /** Returns the OLT geometry from SVG attributes (untransformed) — rect, polygon and path. A `<g id="OLT…">` wrapper yields undefined. */
826
+ function getOltGeometry(content) {
827
+ var geometry = geometryOfFirstShape(content, 'OLT');
828
+ if (!geometry) return undefined;
829
+ return {
830
+ x: geometry.minX,
831
+ y: geometry.minY,
832
+ width: geometry.width,
833
+ height: geometry.height
834
+ };
835
+ }
836
+
837
+ /** Removes all VIF and OLF nodes so only the OLT view remains. */
838
+ function removeOlf(content) {
839
+ var xmlDocument = parseXml(content);
840
+ for (var _i = 0, _arr = [].concat(_toConsumableArray__default["default"](snapshotByIdPrefix(xmlDocument, 'VIF')), _toConsumableArray__default["default"](snapshotByIdPrefix(xmlDocument, 'OLF'))); _i < _arr.length; _i++) {
841
+ var _element$parentElemen;
842
+ var element = _arr[_i];
843
+ (_element$parentElemen = element.parentElement) === null || _element$parentElemen === void 0 || _element$parentElemen.removeChild(element);
844
+ }
845
+ return serializeXml(xmlDocument);
846
+ }
847
+
848
+ /**
849
+ * Removes `<mask>` elements and every node carrying a mask attribute. Uses DOM traversal rather than XPath
850
+ * because jsdom's XPath engine does not support local-name() comparisons.
851
+ */
852
+ function removeMask(content) {
853
+ if (content.toLowerCase().indexOf('<mask') < 0) return content;
854
+ var xmlDocument = parseXml(content, 'image/svg+xml');
855
+ var allElements = _toConsumableArray__default["default"](xmlDocument.getElementsByTagName('*'));
856
+ var _iterator4 = _createForOfIteratorHelper$6(allElements),
857
+ _step4;
858
+ try {
859
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
860
+ var element = _step4.value;
861
+ if (element.localName === 'mask' || element.hasAttribute('mask')) {
862
+ var _element$parentElemen2;
863
+ (_element$parentElemen2 = element.parentElement) === null || _element$parentElemen2 === void 0 || _element$parentElemen2.removeChild(element);
864
+ }
865
+ }
866
+ } catch (err) {
867
+ _iterator4.e(err);
868
+ } finally {
869
+ _iterator4.f();
870
+ }
871
+ return serializeXml(xmlDocument);
872
+ }
873
+ var NON_GEOMETRY_CONTAINERS = ['defs', 'mask', 'clipPath', 'symbol', 'style', 'title', 'desc', 'metadata'];
874
+
875
+ /** Measures a path defensively: malformed decorative path data must not break article parsing. */
876
+ function safePathBounds(element) {
877
+ var d = element.getAttribute('d');
878
+ if (!d) return undefined;
879
+ try {
880
+ return pathBoundingBox(d);
881
+ } catch (error) {
882
+ var _element$getAttribute7;
883
+ getPlanner2DLogger().warn("planner-2d-core: skipping unparsable path (id: ".concat((_element$getAttribute7 = element.getAttribute('id')) !== null && _element$getAttribute7 !== void 0 ? _element$getAttribute7 : '-', "): ").concat(error.message));
884
+ return undefined;
885
+ }
886
+ }
887
+ /**
888
+ * Warns when a measured element sits under a `transform`. Planner article SVGs are exported with baked-in
889
+ * coordinates, and this package reads attributes directly, so a transform would silently displace every
890
+ * measurement taken from it — the connector positions above all. fabric used to apply it, so this is the one
891
+ * place where "no transforms" changes from an assumption into something the caller hears about.
892
+ */
893
+ function warnOnTransform(element, measurement) {
894
+ var node = element;
895
+ while (node) {
896
+ if (node.getAttribute('transform')) {
897
+ var _node$getAttribute;
898
+ getPlanner2DLogger().warn("planner-2d-core: ".concat(measurement, " ignores the transform on <").concat(node.nodeName, " id=\"").concat((_node$getAttribute = node.getAttribute('id')) !== null && _node$getAttribute !== void 0 ? _node$getAttribute : '-', "\">; ") + 'article SVGs are expected to use untransformed coordinates');
899
+ return;
900
+ }
901
+ node = node.parentElement;
902
+ }
903
+ }
904
+ function elementBounds(element) {
905
+ var attr = function attr(name) {
906
+ var _element$getAttribute8;
907
+ return parseFloat((_element$getAttribute8 = element.getAttribute(name)) !== null && _element$getAttribute8 !== void 0 ? _element$getAttribute8 : '0');
908
+ };
909
+ switch (element.nodeName) {
910
+ case 'rect':
911
+ {
912
+ var x = attr('x');
913
+ var y = attr('y');
914
+ return {
915
+ minX: x,
916
+ minY: y,
917
+ maxX: x + attr('width'),
918
+ maxY: y + attr('height')
919
+ };
920
+ }
921
+ case 'image':
922
+ case 'use':
923
+ {
924
+ // A <use>/<image> without width/height is a symbol reference and describes no geometry: counting it
925
+ // as a (0,0) box would drag the content bounds to the origin and shift every docking-point position.
926
+ var width = attr('width');
927
+ var height = attr('height');
928
+ if (!width && !height) return undefined;
929
+ var _x = attr('x');
930
+ var _y = attr('y');
931
+ return {
932
+ minX: _x,
933
+ minY: _y,
934
+ maxX: _x + width,
935
+ maxY: _y + height
936
+ };
937
+ }
938
+ case 'line':
939
+ return {
940
+ minX: Math.min(attr('x1'), attr('x2')),
941
+ minY: Math.min(attr('y1'), attr('y2')),
942
+ maxX: Math.max(attr('x1'), attr('x2')),
943
+ maxY: Math.max(attr('y1'), attr('y2'))
944
+ };
945
+ case 'polygon':
946
+ case 'polyline':
947
+ {
948
+ var _element$getAttribute9;
949
+ var points = parsePointsAttribute((_element$getAttribute9 = element.getAttribute('points')) !== null && _element$getAttribute9 !== void 0 ? _element$getAttribute9 : '');
950
+ if (!points.length) return undefined;
951
+ var bbox = getBoundingBoxOfPoints(points);
952
+ return {
953
+ minX: bbox.minX,
954
+ minY: bbox.minY,
955
+ maxX: bbox.minX + bbox.width,
956
+ maxY: bbox.minY + bbox.height
957
+ };
958
+ }
959
+ case 'circle':
960
+ return {
961
+ minX: attr('cx') - attr('r'),
962
+ minY: attr('cy') - attr('r'),
963
+ maxX: attr('cx') + attr('r'),
964
+ maxY: attr('cy') + attr('r')
965
+ };
966
+ case 'ellipse':
967
+ return {
968
+ minX: attr('cx') - attr('rx'),
969
+ minY: attr('cy') - attr('ry'),
970
+ maxX: attr('cx') + attr('rx'),
971
+ maxY: attr('cy') + attr('ry')
972
+ };
973
+ case 'path':
974
+ return safePathBounds(element);
975
+ default:
976
+ return undefined;
977
+ }
978
+ }
979
+
980
+ /** Reads a presentation attribute from the element, its `style` or the nearest ancestor that sets it. */
981
+ function inheritedPresentation(element, name) {
982
+ for (var node = element; node; node = node.parentElement) {
983
+ var attribute = node.getAttribute(name);
984
+ if (attribute) return attribute;
985
+ var style = node.getAttribute('style');
986
+ var match = style ? new RegExp("(?:^|;)\\s*".concat(name, "\\s*:\\s*([^;]+)")).exec(style) : null;
987
+ if (match) return match[1].trim();
988
+ }
989
+ return undefined;
990
+ }
991
+
992
+ /**
993
+ * Half the stroke width, i.e. how far a shape's painted edge lies outside its geometry. fabric anchored every
994
+ * parsed object on that edge and applied a default width of 1 even to shapes declaring no stroke; minBorder feeds
995
+ * every docking-point position, so it must keep reporting the same edge or connectors drift by half a stroke.
996
+ */
997
+ function strokeOverhang(element) {
998
+ var declared = inheritedPresentation(element, 'stroke-width');
999
+ var width = declared === undefined ? 1 : parseFloat(declared);
1000
+ return Number.isFinite(width) ? width / 2 : 0.5;
1001
+ }
1002
+ function collectBounds(content, includeElement, options) {
1003
+ var xmlDocument = parseXml(content);
1004
+ var minX = Number.POSITIVE_INFINITY;
1005
+ var minY = Number.POSITIVE_INFINITY;
1006
+ var maxX = Number.NEGATIVE_INFINITY;
1007
+ var maxY = Number.NEGATIVE_INFINITY;
1008
+ var _visit = function visit(element) {
1009
+ if (NON_GEOMETRY_CONTAINERS.includes(element.nodeName)) return;
1010
+ if (includeElement(element)) {
1011
+ if (options !== null && options !== void 0 && options.measurement) warnOnTransform(element, options.measurement);
1012
+ var raw = elementBounds(element);
1013
+ var overhang = raw && options !== null && options !== void 0 && options.includeStroke ? strokeOverhang(element) : 0;
1014
+ var bounds = raw && overhang ? {
1015
+ minX: raw.minX - overhang,
1016
+ minY: raw.minY - overhang,
1017
+ maxX: raw.maxX + overhang,
1018
+ maxY: raw.maxY + overhang
1019
+ } : raw;
1020
+ if (bounds) {
1021
+ if (bounds.minX < minX) minX = bounds.minX;
1022
+ if (bounds.minY < minY) minY = bounds.minY;
1023
+ if (bounds.maxX > maxX) maxX = bounds.maxX;
1024
+ if (bounds.maxY > maxY) maxY = bounds.maxY;
1025
+ }
1026
+ }
1027
+ for (var i = 0; i < element.children.length; i++) _visit(element.children[i]);
1028
+ };
1029
+ if (xmlDocument.documentElement) _visit(xmlDocument.documentElement);
1030
+ if (!Number.isFinite(minX) || !Number.isFinite(minY)) return undefined;
1031
+ return {
1032
+ minX: minX,
1033
+ minY: minY,
1034
+ maxX: maxX,
1035
+ maxY: maxY
1036
+ };
1037
+ }
1038
+
1039
+ /**
1040
+ * Minimum x/y over all non-AV geometry — the offset that docking-point coordinates are corrected by.
1041
+ * `transform` attributes are not applied; an element carrying one is reported through the package logger
1042
+ * rather than measured wrongly in silence.
1043
+ */
1044
+ function getMinBorder(content) {
1045
+ // Stroke-inclusive on purpose: this is the origin the planner anchors docking points against.
1046
+ var bounds = collectBounds(content, function (element) {
1047
+ var _element$getAttribute10;
1048
+ return !((_element$getAttribute10 = element.getAttribute('id')) !== null && _element$getAttribute10 !== void 0 ? _element$getAttribute10 : '').startsWith('AV');
1049
+ }, {
1050
+ includeStroke: true,
1051
+ measurement: 'getMinBorder'
1052
+ });
1053
+ if (!bounds) return {
1054
+ minX: 0,
1055
+ minY: 0
1056
+ };
1057
+ return {
1058
+ minX: bounds.minX,
1059
+ minY: bounds.minY
1060
+ };
1061
+ }
1062
+
1063
+ /**
1064
+ * Bounding box over ALL drawing geometry including AV lines — the ink extent of the article.
1065
+ * This is not an article's width/depth: use {@link getRootSize} for that.
1066
+ */
1067
+ function getContentBounds(content) {
1068
+ return collectBounds(content, function () {
1069
+ return true;
1070
+ });
1071
+ }
1072
+
1073
+ /** The declared canvas size of the SVG root in user units — the value an article's width/depth is derived from. */
1074
+ function getRootSize(content) {
1075
+ var _root$getAttribute, _root$getAttribute2;
1076
+ var root = parseXml(content).documentElement;
1077
+ if (!root) return undefined;
1078
+ var width = parseFloat((_root$getAttribute = root.getAttribute('width')) !== null && _root$getAttribute !== void 0 ? _root$getAttribute : '');
1079
+ var height = parseFloat((_root$getAttribute2 = root.getAttribute('height')) !== null && _root$getAttribute2 !== void 0 ? _root$getAttribute2 : '');
1080
+ if (!Number.isFinite(width) || !Number.isFinite(height)) return undefined;
1081
+ return {
1082
+ width: width,
1083
+ height: height
1084
+ };
1085
+ }
1086
+
1087
+ function _createForOfIteratorHelper$5(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$5(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
1088
+ function _unsupportedIterableToArray$5(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$5(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$5(r, a) : void 0; } }
1089
+ function _arrayLikeToArray$5(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
1090
+ /**
1091
+ * Polygon `points` tokenizer: the pair separator is ',' when the string contains one, ' ' otherwise, so both
1092
+ * "x,y x,y" and "x y x y" parse. An all-comma list keeps the legacy misparse on purpose.
1093
+ */
1094
+ function parsePolygonPoints(pointsText) {
1095
+ var points = [];
1096
+ var separator = pointsText.includes(',') ? ',' : ' ';
1097
+ var text = pointsText.trim();
1098
+ var readingX = true;
1099
+ var x = '';
1100
+ var y = '';
1101
+ var _iterator = _createForOfIteratorHelper$5(text),
1102
+ _step;
1103
+ try {
1104
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1105
+ var character = _step.value;
1106
+ if (!readingX && character === ' ') {
1107
+ if (x !== '') {
1108
+ points.push({
1109
+ x: parseFloat(x),
1110
+ y: parseFloat(y)
1111
+ });
1112
+ x = '';
1113
+ y = '';
1114
+ readingX = true;
1115
+ }
1116
+ continue;
1117
+ }
1118
+ if (character === separator) {
1119
+ readingX = false;
1120
+ continue;
1121
+ }
1122
+ if (readingX) x += character;else y += character;
1123
+ }
1124
+ } catch (err) {
1125
+ _iterator.e(err);
1126
+ } finally {
1127
+ _iterator.f();
1128
+ }
1129
+ if (x !== '') points.push({
1130
+ x: parseFloat(x),
1131
+ y: parseFloat(y)
1132
+ });
1133
+ return points;
1134
+ }
1135
+
1136
+ /** Legacy points format: "x,y " pairs with a trailing space. */
1137
+ function serializePolygonPoints(points) {
1138
+ var result = '';
1139
+ var _iterator2 = _createForOfIteratorHelper$5(points),
1140
+ _step2;
1141
+ try {
1142
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1143
+ var point = _step2.value;
1144
+ result += point.x + ',' + point.y + ' ';
1145
+ }
1146
+ } catch (err) {
1147
+ _iterator2.e(err);
1148
+ } finally {
1149
+ _iterator2.f();
1150
+ }
1151
+ return result;
1152
+ }
1153
+
1154
+ /** Coordinate rounding to 3 decimals — every transformed coordinate goes through this. */
1155
+ function round3(value) {
1156
+ return Math.round(value * 1000) / 1000;
1157
+ }
1158
+
1159
+ /** Result rounding to 2 decimals — used for the root size and the viewBox. */
1160
+ function round2(value) {
1161
+ return Math.round(value * 100) / 100;
1162
+ }
1163
+
1164
+ function _createForOfIteratorHelper$4(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$4(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
1165
+ function _unsupportedIterableToArray$4(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$4(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$4(r, a) : void 0; } }
1166
+ function _arrayLikeToArray$4(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
1167
+
1168
+ /** One stretch area projected onto the active axis; end is pre-rounded, as the legacy engine rounded it. */
1169
+
1170
+ /**
1171
+ * Which scale factor applies to each param of a command, case-insensitively. `null` marks a param that is
1172
+ * not a coordinate: an arc's x-axis-rotation and its two flags. `z` carries no params at all.
1173
+ */
1174
+ var SCALE_PARAM_AXES = {
1175
+ m: ['x', 'y'],
1176
+ l: ['x', 'y'],
1177
+ h: ['x'],
1178
+ v: ['y'],
1179
+ c: ['x', 'y', 'x', 'y', 'x', 'y'],
1180
+ s: ['x', 'y', 'x', 'y'],
1181
+ q: ['x', 'y', 'x', 'y'],
1182
+ t: ['x', 'y'],
1183
+ a: ['x', 'y', null, null, null, 'x', 'y'],
1184
+ z: []
1185
+ };
1186
+
1187
+ /** Index of an arc's x-axis-rotation param; a rotated arc cannot be scaled exactly along separate axes. */
1188
+ var ARC_ROTATION_PARAM = 2;
1189
+
1190
+ /** Legacy `d` format: bare command letters, params joined with ',', no separators between commands. */
1191
+ function serializePathCommands(commands) {
1192
+ return commands.map(function (command) {
1193
+ return command.command + command.params.join(',');
1194
+ }).join('');
1195
+ }
1196
+ function parsePathSafely(d, warn) {
1197
+ try {
1198
+ return parsePathCommands(d);
1199
+ } catch (error) {
1200
+ warn("stretch: unparsable path data left untouched (".concat(error instanceof Error ? error.message : String(error), ")"));
1201
+ return undefined;
1202
+ }
1203
+ }
1204
+
1205
+ /**
1206
+ * Applies the stretch-area shifts of one axis to a path `d` attribute, including the legacy relative-command
1207
+ * quirks. Commands that do not move the pen along this axis (H/h vertically, V/v horizontally, Z/z) carry no
1208
+ * mapping and are skipped; the parser has already rejected anything that is not a valid SVG command.
1209
+ */
1210
+ function stretchPathData(d, areas, axis, warn) {
1211
+ var commands = parsePathSafely(d, warn);
1212
+ if (!commands) return d;
1213
+ var _iterator = _createForOfIteratorHelper$4(areas),
1214
+ _step;
1215
+ try {
1216
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1217
+ var area = _step.value;
1218
+ var delta = area.end - area.begin;
1219
+ // NaN start reproduces the legacy undefined `last` (all comparisons false, arithmetic stays NaN until an absolute command).
1220
+ var last = Number.NaN;
1221
+ var _iterator2 = _createForOfIteratorHelper$4(commands),
1222
+ _step2;
1223
+ try {
1224
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1225
+ var _step2$value = _step2.value,
1226
+ command = _step2$value.command,
1227
+ params = _step2$value.params;
1228
+ var absolute = axis.absolute[command];
1229
+ if (absolute) {
1230
+ var value = params[absolute.track];
1231
+ if (value > area.begin) {
1232
+ var _iterator3 = _createForOfIteratorHelper$4(absolute.shift),
1233
+ _step3;
1234
+ try {
1235
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1236
+ var index = _step3.value;
1237
+ params[index] = round3(params[index] + delta);
1238
+ }
1239
+ } catch (err) {
1240
+ _iterator3.e(err);
1241
+ } finally {
1242
+ _iterator3.f();
1243
+ }
1244
+ }
1245
+ last = value;
1246
+ continue;
1247
+ }
1248
+ var relative = axis.relative[command];
1249
+ if (relative) {
1250
+ var help = params[relative.help];
1251
+ if ((!relative.requireNonNegativeForward || help >= 0) && last < area.begin && last + help > area.begin) {
1252
+ var _iterator4 = _createForOfIteratorHelper$4(relative.shift),
1253
+ _step4;
1254
+ try {
1255
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
1256
+ var _index = _step4.value;
1257
+ params[_index] = round3(params[_index] + delta);
1258
+ }
1259
+ } catch (err) {
1260
+ _iterator4.e(err);
1261
+ } finally {
1262
+ _iterator4.f();
1263
+ }
1264
+ } else if (help < 0 && last >= area.begin && last + params[relative.backwardProbe] < area.begin) {
1265
+ var _iterator5 = _createForOfIteratorHelper$4(relative.shift),
1266
+ _step5;
1267
+ try {
1268
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
1269
+ var _index2 = _step5.value;
1270
+ params[_index2] = round3(params[_index2] + relative.backwardSign * delta);
1271
+ }
1272
+ } catch (err) {
1273
+ _iterator5.e(err);
1274
+ } finally {
1275
+ _iterator5.f();
1276
+ }
1277
+ }
1278
+ last += help;
1279
+ continue;
1280
+ }
1281
+ }
1282
+ } catch (err) {
1283
+ _iterator2.e(err);
1284
+ } finally {
1285
+ _iterator2.f();
1286
+ }
1287
+ }
1288
+ } catch (err) {
1289
+ _iterator.e(err);
1290
+ } finally {
1291
+ _iterator.f();
1292
+ }
1293
+ return serializePathCommands(commands);
1294
+ }
1295
+
1296
+ /** Scales all path coordinates by per-axis factors — rounded for the global-scale mode, unrounded for the viewBox normalization. */
1297
+ function scalePathData(d, widthFactor, heightFactor, roundResults, warn) {
1298
+ var commands = parsePathSafely(d, warn);
1299
+ if (!commands) return d;
1300
+ var _iterator6 = _createForOfIteratorHelper$4(commands),
1301
+ _step6;
1302
+ try {
1303
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1304
+ var _step6$value = _step6.value,
1305
+ command = _step6$value.command,
1306
+ params = _step6$value.params;
1307
+ var paramAxes = SCALE_PARAM_AXES[command.toLowerCase()];
1308
+ if (command.toLowerCase() === 'a' && params[ARC_ROTATION_PARAM] !== 0 && widthFactor !== heightFactor) {
1309
+ // A rotated ellipse under different x/y factors is no longer an ellipse with these radii; scaling them
1310
+ // separately is an approximation, so it is worth saying out loud rather than drifting silently.
1311
+ warn("stretch: rotated arc scaled with different x/y factors \u2014 its radii are approximated");
1312
+ }
1313
+ for (var i = 0; i < paramAxes.length; i++) {
1314
+ if (paramAxes[i] === null) continue;
1315
+ var scaled = params[i] * (paramAxes[i] === 'x' ? widthFactor : heightFactor);
1316
+ params[i] = roundResults ? round3(scaled) : scaled;
1317
+ }
1318
+ }
1319
+ } catch (err) {
1320
+ _iterator6.e(err);
1321
+ } finally {
1322
+ _iterator6.f();
1323
+ }
1324
+ return serializePathCommands(commands);
1325
+ }
1326
+
1327
+ /** Creates the initial pipeline state for one stretch run. */
1328
+ function createStretchState(document, root, useGlobalScale, targetWidthOlt, targetHeightOlt) {
1329
+ return {
1330
+ document: document,
1331
+ root: root,
1332
+ useGlobalScale: useGlobalScale,
1333
+ targetWidthOlt: targetWidthOlt,
1334
+ targetHeightOlt: targetHeightOlt,
1335
+ widthOlt: 0,
1336
+ heightOlt: 0,
1337
+ widthOlf: 0,
1338
+ heightOlf: 0,
1339
+ startWidthOlt: 0,
1340
+ startHeightOlt: 0,
1341
+ startWidthOlf: 0,
1342
+ startHeightOlf: 0,
1343
+ hasOlf: false,
1344
+ deltaOlfWidth: 0,
1345
+ deltaOlfHeight: 0,
1346
+ origOltWidth: 0,
1347
+ origOltHeight: 0,
1348
+ sah: [],
1349
+ sav: [],
1350
+ ratioSah: [],
1351
+ ratioSav: [],
1352
+ // NaN mirrors the legacy undefined factors: a pass with only one changed dimension propagates NaN the same way.
1353
+ globalScaleFactorWidth: Number.NaN,
1354
+ globalScaleFactorHeight: Number.NaN,
1355
+ warnings: [],
1356
+ warned: new Set()
1357
+ };
1358
+ }
1359
+
1360
+ /** Records a warning once (deduplicated per run) and mirrors it to the package logger. */
1361
+ function addWarning(state, message) {
1362
+ if (state.warned.has(message)) return;
1363
+ state.warned.add(message);
1364
+ state.warnings.push(message);
1365
+ getPlanner2DLogger().warn(message);
1366
+ }
1367
+ function currentSizes(state) {
1368
+ return {
1369
+ widthOLT: state.widthOlt,
1370
+ heightOLT: state.heightOlt,
1371
+ widthOLF: state.widthOlf,
1372
+ heightOLF: state.heightOlf
1373
+ };
1374
+ }
1375
+
1376
+ function _createForOfIteratorHelper$3(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$3(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
1377
+ function _unsupportedIterableToArray$3(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$3(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$3(r, a) : void 0; } }
1378
+ function _arrayLikeToArray$3(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
1379
+
1380
+ /** ViewBox-to-attribute scale of the root element (1:1 for planner-conform articles). */
1381
+
1382
+ /** Legacy length parsing: mm converts to user units, px strips the suffix, anything else parses as-is. */
1383
+ function parseSvgLength(text) {
1384
+ if (text.indexOf('mm') > 0) return parseFloat(text.substring(0, text.length - 2)) * UNIT_RECALC;
1385
+ if (text.indexOf('px') > 0) return parseFloat(text.substring(0, text.length - 2));
1386
+ return parseFloat(text);
1387
+ }
1388
+
1389
+ /** Derives missing width/height from the viewBox, normalizes units and defaults the viewBox. */
1390
+ function normalizeRootSize(root) {
1391
+ var viewBox = root.getAttribute('viewBox');
1392
+ if (viewBox && root.getAttribute('width') == null) root.setAttribute('width', viewBox.split(' ')[2]);
1393
+ if (viewBox && root.getAttribute('height') == null) root.setAttribute('height', viewBox.split(' ')[3]);
1394
+ var widthText = root.getAttribute('width');
1395
+ var heightText = root.getAttribute('height');
1396
+ if (widthText == null || heightText == null) {
1397
+ throw new Error('stretchArticleSvg: root <svg> carries neither width/height attributes nor a viewBox');
1398
+ }
1399
+ var width = parseSvgLength(widthText);
1400
+ var height = parseSvgLength(heightText);
1401
+ root.setAttribute('width', width.toString());
1402
+ root.setAttribute('height', height.toString());
1403
+ if (!viewBox) root.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
1404
+ }
1405
+ function viewBoxScaleFactor(root) {
1406
+ var viewBox = root.getAttribute('viewBox');
1407
+ if (viewBox == null) return {
1408
+ x: 1,
1409
+ y: 1
1410
+ };
1411
+ var pieces = viewBox.split(' ');
1412
+ return {
1413
+ x: Number(root.getAttribute('width')) / Number(pieces[2]),
1414
+ y: Number(root.getAttribute('height')) / Number(pieces[3])
1415
+ };
1416
+ }
1417
+
1418
+ /** Rewrites the viewBox with ceiled root size and origin. */
1419
+ function rewriteViewBoxToCeiledInts(root) {
1420
+ var _root$getAttribute, _root$getAttribute2;
1421
+ if (root.getAttribute('viewBox') == null) return;
1422
+ var width = Math.ceil(parseFloat((_root$getAttribute = root.getAttribute('width')) !== null && _root$getAttribute !== void 0 ? _root$getAttribute : ''));
1423
+ var height = Math.ceil(parseFloat((_root$getAttribute2 = root.getAttribute('height')) !== null && _root$getAttribute2 !== void 0 ? _root$getAttribute2 : ''));
1424
+ var xText = root.getAttribute('x');
1425
+ var yText = root.getAttribute('y');
1426
+ var originX = xText ? Math.ceil(parseSvgLength(xText)) : 0;
1427
+ var originY = yText ? Math.ceil(parseSvgLength(yText)) : 0;
1428
+ root.setAttribute('viewBox', originX + ' ' + originY + ' ' + width + ' ' + height);
1429
+ }
1430
+ function scaleRectAttributes(rect, scale) {
1431
+ var _rect$getAttribute, _rect$getAttribute2, _rect$getAttribute3, _rect$getAttribute4;
1432
+ var x = (_rect$getAttribute = rect.getAttribute('x')) !== null && _rect$getAttribute !== void 0 ? _rect$getAttribute : '0';
1433
+ var y = (_rect$getAttribute2 = rect.getAttribute('y')) !== null && _rect$getAttribute2 !== void 0 ? _rect$getAttribute2 : '0';
1434
+ rect.setAttribute('x', String(parseFloat(x) * scale.x));
1435
+ rect.setAttribute('y', String(parseFloat(y) * scale.y));
1436
+ rect.setAttribute('width', String(parseFloat((_rect$getAttribute3 = rect.getAttribute('width')) !== null && _rect$getAttribute3 !== void 0 ? _rect$getAttribute3 : '') * scale.x));
1437
+ rect.setAttribute('height', String(parseFloat((_rect$getAttribute4 = rect.getAttribute('height')) !== null && _rect$getAttribute4 !== void 0 ? _rect$getAttribute4 : '') * scale.y));
1438
+ }
1439
+ function scaleLineAttributes(line, scale) {
1440
+ var _line$getAttribute, _line$getAttribute2, _line$getAttribute3, _line$getAttribute4;
1441
+ var x1 = (_line$getAttribute = line.getAttribute('x1')) !== null && _line$getAttribute !== void 0 ? _line$getAttribute : '0';
1442
+ var y1 = (_line$getAttribute2 = line.getAttribute('y1')) !== null && _line$getAttribute2 !== void 0 ? _line$getAttribute2 : '0';
1443
+ line.setAttribute('x1', String(parseFloat(x1) * scale.x));
1444
+ line.setAttribute('y1', String(parseFloat(y1) * scale.y));
1445
+ line.setAttribute('x2', String(parseFloat((_line$getAttribute3 = line.getAttribute('x2')) !== null && _line$getAttribute3 !== void 0 ? _line$getAttribute3 : '') * scale.x));
1446
+ line.setAttribute('y2', String(parseFloat((_line$getAttribute4 = line.getAttribute('y2')) !== null && _line$getAttribute4 !== void 0 ? _line$getAttribute4 : '') * scale.y));
1447
+ }
1448
+ function scalePolygonAttributes(polygon, scale) {
1449
+ var _polygon$getAttribute;
1450
+ var points = parsePolygonPoints((_polygon$getAttribute = polygon.getAttribute('points')) !== null && _polygon$getAttribute !== void 0 ? _polygon$getAttribute : '');
1451
+ var _iterator = _createForOfIteratorHelper$3(points),
1452
+ _step;
1453
+ try {
1454
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1455
+ var point = _step.value;
1456
+ point.x *= scale.x;
1457
+ point.y *= scale.y;
1458
+ }
1459
+ } catch (err) {
1460
+ _iterator.e(err);
1461
+ } finally {
1462
+ _iterator.f();
1463
+ }
1464
+ polygon.setAttribute('points', serializePolygonPoints(points));
1465
+ }
1466
+
1467
+ /** Numeric width/height declarations inside a `<style>` scale with the viewBox factors. */
1468
+ function scaleStyleDimension(part, property, factor) {
1469
+ var propertyIndex = part.indexOf(property);
1470
+ if (propertyIndex < 0) return part;
1471
+ var value = '';
1472
+ var startIndex = -1;
1473
+ var endIndex = -1;
1474
+ for (var i = propertyIndex + property.length; i < part.length; i++) {
1475
+ var character = part[i];
1476
+ if (character === ';' || character === '}') {
1477
+ endIndex = i;
1478
+ break;
1479
+ }
1480
+ if (startIndex > -1) value += character;
1481
+ if (character === ':') startIndex = i;
1482
+ }
1483
+ return part.substring(0, startIndex + 1) + parseFloat(value) * factor + part.substring(endIndex);
1484
+ }
1485
+ function scaleStyleElement(styleElement, scale) {
1486
+ var _styleElement$textCon;
1487
+ var parts = ((_styleElement$textCon = styleElement.textContent) !== null && _styleElement$textCon !== void 0 ? _styleElement$textCon : '').split('{');
1488
+ var result = '';
1489
+ for (var i = 0; i < parts.length; i++) {
1490
+ var part = scaleStyleDimension(parts[i], 'width', scale.x);
1491
+ part = scaleStyleDimension(part, 'height', scale.y);
1492
+ result += part;
1493
+ if (i < parts.length - 1) result += '{';
1494
+ }
1495
+ styleElement.textContent = result;
1496
+ }
1497
+
1498
+ /**
1499
+ * Scales all drawing geometry from viewBox units into root-attribute units. Every element — SAH/SAV rects
1500
+ * included — is scaled exactly once, unlike the legacy engine, which double-scaled the stretch-area rects.
1501
+ */
1502
+ function applyViewBoxScale(state, scale) {
1503
+ if (scale.x === 1 && scale.y === 1) return;
1504
+ var _visit = function visit(parent) {
1505
+ var _child$getAttribute;
1506
+ var children = parent.children;
1507
+ if (!children) return;
1508
+ for (var i = 0; i < children.length; i++) {
1509
+ var child = children[i];
1510
+ switch (child.tagName) {
1511
+ case 'rect':
1512
+ scaleRectAttributes(child, scale);
1513
+ break;
1514
+ case 'polygon':
1515
+ scalePolygonAttributes(child, scale);
1516
+ break;
1517
+ case 'path':
1518
+ child.setAttribute('d', scalePathData((_child$getAttribute = child.getAttribute('d')) !== null && _child$getAttribute !== void 0 ? _child$getAttribute : '', scale.x, scale.y, false, function (message) {
1519
+ return addWarning(state, message);
1520
+ }));
1521
+ break;
1522
+ case 'line':
1523
+ scaleLineAttributes(child, scale);
1524
+ break;
1525
+ case 'style':
1526
+ scaleStyleElement(child, scale);
1527
+ break;
1528
+ }
1529
+ _visit(child);
1530
+ }
1531
+ };
1532
+ _visit(state.root);
1533
+ }
1534
+
1535
+ /** Tags the technical group as TE when missing and hides every TE group. */
1536
+ function ensureTeDisplayNone(document) {
1537
+ var teElements = snapshotByIdPrefix(document, 'TE');
1538
+ if (teElements.length === 0) {
1539
+ var _iterator2 = _createForOfIteratorHelper$3(snapshotByIdPrefix(document, 'OLT')),
1540
+ _step2;
1541
+ try {
1542
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1543
+ var olt = _step2.value;
1544
+ if (olt.nodeName === 'g') continue;
1545
+ var parent = olt.parentElement;
1546
+ if ((parent === null || parent === void 0 ? void 0 : parent.tagName) === 'g') parent.setAttribute('id', 'TE');
1547
+ }
1548
+ } catch (err) {
1549
+ _iterator2.e(err);
1550
+ } finally {
1551
+ _iterator2.f();
1552
+ }
1553
+ teElements = snapshotByIdPrefix(document, 'TE');
1554
+ }
1555
+ var _iterator3 = _createForOfIteratorHelper$3(teElements),
1556
+ _step3;
1557
+ try {
1558
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1559
+ var teElement = _step3.value;
1560
+ if (teElement.nodeName === 'g') teElement.setAttribute('display', 'none');
1561
+ }
1562
+ } catch (err) {
1563
+ _iterator3.e(err);
1564
+ } finally {
1565
+ _iterator3.f();
1566
+ }
1567
+ }
1568
+
1569
+ /** Per-axis parameter routing for an absolute path command. */
1570
+
1571
+ /** Per-axis routing for a relative path command, including the legacy branch quirks. */
1572
+
1573
+ /** Everything the element and path transformers need to work on one axis ('x' = SAH passes, 'y' = SAV passes). */
1574
+
1575
+ var HORIZONTAL_AXIS = {
1576
+ axis: 'x',
1577
+ pos: 'x',
1578
+ size: 'width',
1579
+ linePoint1: 'x1',
1580
+ linePoint2: 'x2',
1581
+ pointKey: 'x',
1582
+ absolute: {
1583
+ M: {
1584
+ track: 0,
1585
+ shift: [0]
1586
+ },
1587
+ L: {
1588
+ track: 0,
1589
+ shift: [0]
1590
+ },
1591
+ H: {
1592
+ track: 0,
1593
+ shift: [0]
1594
+ },
1595
+ C: {
1596
+ track: 4,
1597
+ shift: [4, 0, 2]
1598
+ },
1599
+ S: {
1600
+ track: 2,
1601
+ shift: [0, 2]
1602
+ },
1603
+ Q: {
1604
+ track: 2,
1605
+ shift: [0, 2]
1606
+ },
1607
+ T: {
1608
+ track: 0,
1609
+ shift: [0]
1610
+ },
1611
+ // Params 0/1 of an arc are radii, not positions: displacing an arc moves its endpoint and keeps its shape.
1612
+ A: {
1613
+ track: 5,
1614
+ shift: [5]
1615
+ }
1616
+ },
1617
+ relative: {
1618
+ m: {
1619
+ help: 0,
1620
+ shift: [0],
1621
+ requireNonNegativeForward: true,
1622
+ backwardProbe: 0,
1623
+ backwardSign: -1
1624
+ },
1625
+ l: {
1626
+ help: 0,
1627
+ shift: [0],
1628
+ requireNonNegativeForward: true,
1629
+ backwardProbe: 0,
1630
+ backwardSign: -1
1631
+ },
1632
+ h: {
1633
+ help: 0,
1634
+ shift: [0],
1635
+ requireNonNegativeForward: true,
1636
+ backwardProbe: 0,
1637
+ backwardSign: -1
1638
+ },
1639
+ c: {
1640
+ help: 4,
1641
+ shift: [4, 0, 2],
1642
+ requireNonNegativeForward: false,
1643
+ backwardProbe: 0,
1644
+ backwardSign: 1
1645
+ },
1646
+ s: {
1647
+ help: 2,
1648
+ shift: [0, 2],
1649
+ requireNonNegativeForward: false,
1650
+ backwardProbe: 0,
1651
+ backwardSign: -1
1652
+ },
1653
+ q: {
1654
+ help: 2,
1655
+ shift: [0, 2],
1656
+ requireNonNegativeForward: false,
1657
+ backwardProbe: 2,
1658
+ backwardSign: -1
1659
+ },
1660
+ t: {
1661
+ help: 0,
1662
+ shift: [0],
1663
+ requireNonNegativeForward: false,
1664
+ backwardProbe: 0,
1665
+ backwardSign: -1
1666
+ },
1667
+ a: {
1668
+ help: 5,
1669
+ shift: [5],
1670
+ requireNonNegativeForward: false,
1671
+ backwardProbe: 5,
1672
+ backwardSign: -1
1673
+ }
1674
+ }
1675
+ };
1676
+ var VERTICAL_AXIS = {
1677
+ axis: 'y',
1678
+ pos: 'y',
1679
+ size: 'height',
1680
+ linePoint1: 'y1',
1681
+ linePoint2: 'y2',
1682
+ pointKey: 'y',
1683
+ absolute: {
1684
+ M: {
1685
+ track: 1,
1686
+ shift: [1]
1687
+ },
1688
+ L: {
1689
+ track: 1,
1690
+ shift: [1]
1691
+ },
1692
+ V: {
1693
+ track: 0,
1694
+ shift: [0]
1695
+ },
1696
+ C: {
1697
+ track: 5,
1698
+ shift: [5, 1, 3]
1699
+ },
1700
+ S: {
1701
+ track: 3,
1702
+ shift: [1, 3]
1703
+ },
1704
+ Q: {
1705
+ track: 3,
1706
+ shift: [1, 3]
1707
+ },
1708
+ T: {
1709
+ track: 1,
1710
+ shift: [1]
1711
+ },
1712
+ A: {
1713
+ track: 6,
1714
+ shift: [6]
1715
+ }
1716
+ },
1717
+ relative: {
1718
+ m: {
1719
+ help: 1,
1720
+ shift: [1],
1721
+ requireNonNegativeForward: false,
1722
+ backwardProbe: 1,
1723
+ backwardSign: -1
1724
+ },
1725
+ l: {
1726
+ help: 1,
1727
+ shift: [1],
1728
+ requireNonNegativeForward: false,
1729
+ backwardProbe: 1,
1730
+ backwardSign: -1
1731
+ },
1732
+ v: {
1733
+ help: 0,
1734
+ shift: [0],
1735
+ requireNonNegativeForward: false,
1736
+ backwardProbe: 0,
1737
+ backwardSign: -1
1738
+ },
1739
+ c: {
1740
+ help: 5,
1741
+ shift: [5, 1, 3],
1742
+ requireNonNegativeForward: false,
1743
+ backwardProbe: 0,
1744
+ backwardSign: -1
1745
+ },
1746
+ s: {
1747
+ help: 3,
1748
+ shift: [1, 3],
1749
+ requireNonNegativeForward: false,
1750
+ backwardProbe: 0,
1751
+ backwardSign: -1
1752
+ },
1753
+ q: {
1754
+ help: 3,
1755
+ shift: [1, 3],
1756
+ requireNonNegativeForward: false,
1757
+ backwardProbe: 3,
1758
+ backwardSign: -1
1759
+ },
1760
+ t: {
1761
+ help: 1,
1762
+ shift: [1],
1763
+ requireNonNegativeForward: false,
1764
+ backwardProbe: 1,
1765
+ backwardSign: -1
1766
+ },
1767
+ a: {
1768
+ help: 6,
1769
+ shift: [6],
1770
+ requireNonNegativeForward: false,
1771
+ backwardProbe: 6,
1772
+ backwardSign: -1
1773
+ }
1774
+ }
1775
+ };
1776
+
1777
+ function _createForOfIteratorHelper$2(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$2(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
1778
+ function _unsupportedIterableToArray$2(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$2(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$2(r, a) : void 0; } }
1779
+ function _arrayLikeToArray$2(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
1780
+ /** Elements that carry coordinates but have no transformer — they keep their position, which is worth a warning. */
1781
+ var UNTRANSFORMED_COORDINATE_ELEMENTS = ['circle', 'ellipse', 'text', 'tspan', 'use'];
1782
+
1783
+ /** The stretch areas of one axis projected to begin/end ranges. */
1784
+ function areaRanges(state, axis) {
1785
+ var areas = axis.axis === 'x' ? state.sah : state.sav;
1786
+ return areas.map(function (area) {
1787
+ var _area$getAttribute, _area$getAttribute2;
1788
+ var begin = parseFloat((_area$getAttribute = area.getAttribute(axis.pos)) !== null && _area$getAttribute !== void 0 ? _area$getAttribute : '');
1789
+ return {
1790
+ begin: begin,
1791
+ end: round3(begin + parseFloat((_area$getAttribute2 = area.getAttribute(axis.size)) !== null && _area$getAttribute2 !== void 0 ? _area$getAttribute2 : ''))
1792
+ };
1793
+ });
1794
+ }
1795
+ function stretchRect(rect, ranges, axis) {
1796
+ var _iterator = _createForOfIteratorHelper$2(ranges),
1797
+ _step;
1798
+ try {
1799
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1800
+ var _rect$getAttribute, _rect$getAttribute2;
1801
+ var range = _step.value;
1802
+ var rectBegin = parseFloat((_rect$getAttribute = rect.getAttribute(axis.pos)) !== null && _rect$getAttribute !== void 0 ? _rect$getAttribute : '');
1803
+ var rectEnd = round3(rectBegin + parseFloat((_rect$getAttribute2 = rect.getAttribute(axis.size)) !== null && _rect$getAttribute2 !== void 0 ? _rect$getAttribute2 : ''));
1804
+ if (rectBegin <= range.begin && rectEnd >= range.begin) {
1805
+ rect.setAttribute(axis.size, String(round3(rectEnd - rectBegin + (range.end - range.begin))));
1806
+ } else if (rectBegin > range.begin) {
1807
+ rect.setAttribute(axis.pos, String(round3(rectBegin + (range.end - range.begin))));
1808
+ }
1809
+ }
1810
+ } catch (err) {
1811
+ _iterator.e(err);
1812
+ } finally {
1813
+ _iterator.f();
1814
+ }
1815
+ }
1816
+ function scaleRect(rect, state) {
1817
+ var _rect$getAttribute3, _rect$getAttribute4, _rect$getAttribute5, _rect$getAttribute6;
1818
+ var x = parseFloat((_rect$getAttribute3 = rect.getAttribute('x')) !== null && _rect$getAttribute3 !== void 0 ? _rect$getAttribute3 : '');
1819
+ var width = parseFloat((_rect$getAttribute4 = rect.getAttribute('width')) !== null && _rect$getAttribute4 !== void 0 ? _rect$getAttribute4 : '');
1820
+ var y = parseFloat((_rect$getAttribute5 = rect.getAttribute('y')) !== null && _rect$getAttribute5 !== void 0 ? _rect$getAttribute5 : '');
1821
+ var height = parseFloat((_rect$getAttribute6 = rect.getAttribute('height')) !== null && _rect$getAttribute6 !== void 0 ? _rect$getAttribute6 : '');
1822
+ rect.setAttribute('x', String(round3(x * state.globalScaleFactorWidth)));
1823
+ rect.setAttribute('width', String(round3(width * state.globalScaleFactorWidth)));
1824
+ rect.setAttribute('y', String(round3(y * state.globalScaleFactorHeight)));
1825
+ rect.setAttribute('height', String(round3(height * state.globalScaleFactorHeight)));
1826
+ }
1827
+ function stretchLine(line, ranges, axis) {
1828
+ var _iterator2 = _createForOfIteratorHelper$2(ranges),
1829
+ _step2;
1830
+ try {
1831
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1832
+ var _line$getAttribute, _line$getAttribute2;
1833
+ var range = _step2.value;
1834
+ var point1 = parseFloat((_line$getAttribute = line.getAttribute(axis.linePoint1)) !== null && _line$getAttribute !== void 0 ? _line$getAttribute : '');
1835
+ var point2 = parseFloat((_line$getAttribute2 = line.getAttribute(axis.linePoint2)) !== null && _line$getAttribute2 !== void 0 ? _line$getAttribute2 : '');
1836
+ if (point1 > range.begin) {
1837
+ line.setAttribute(axis.linePoint1, String(round3(point1 + (range.end - range.begin))));
1838
+ line.setAttribute(axis.linePoint2, String(round3(point2 + (range.end - range.begin))));
1839
+ } else if (point1 < range.begin && point2 > range.begin) {
1840
+ line.setAttribute(axis.linePoint2, String(round3(point2 + (range.end - range.begin))));
1841
+ }
1842
+ }
1843
+ } catch (err) {
1844
+ _iterator2.e(err);
1845
+ } finally {
1846
+ _iterator2.f();
1847
+ }
1848
+ }
1849
+ function scaleLine(line, state) {
1850
+ var _line$getAttribute3, _line$getAttribute4, _line$getAttribute5, _line$getAttribute6;
1851
+ var x1 = parseFloat((_line$getAttribute3 = line.getAttribute('x1')) !== null && _line$getAttribute3 !== void 0 ? _line$getAttribute3 : '');
1852
+ var x2 = parseFloat((_line$getAttribute4 = line.getAttribute('x2')) !== null && _line$getAttribute4 !== void 0 ? _line$getAttribute4 : '');
1853
+ var y1 = parseFloat((_line$getAttribute5 = line.getAttribute('y1')) !== null && _line$getAttribute5 !== void 0 ? _line$getAttribute5 : '');
1854
+ var y2 = parseFloat((_line$getAttribute6 = line.getAttribute('y2')) !== null && _line$getAttribute6 !== void 0 ? _line$getAttribute6 : '');
1855
+ line.setAttribute('x1', String(round3(x1 * state.globalScaleFactorWidth)));
1856
+ line.setAttribute('x2', String(round3(x2 * state.globalScaleFactorWidth)));
1857
+ line.setAttribute('y1', String(round3(y1 * state.globalScaleFactorHeight)));
1858
+ line.setAttribute('y2', String(round3(y2 * state.globalScaleFactorHeight)));
1859
+ }
1860
+ function transformPoints(element, mode, state) {
1861
+ var _element$getAttribute;
1862
+ var points = parsePolygonPoints((_element$getAttribute = element.getAttribute('points')) !== null && _element$getAttribute !== void 0 ? _element$getAttribute : '');
1863
+ if (mode === 'GLOBAL_SCALE') {
1864
+ var _iterator3 = _createForOfIteratorHelper$2(points),
1865
+ _step3;
1866
+ try {
1867
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1868
+ var point = _step3.value;
1869
+ point.x *= state.globalScaleFactorWidth;
1870
+ point.y *= state.globalScaleFactorHeight;
1871
+ }
1872
+ } catch (err) {
1873
+ _iterator3.e(err);
1874
+ } finally {
1875
+ _iterator3.f();
1876
+ }
1877
+ } else {
1878
+ var axis = mode === 'SAH' ? HORIZONTAL_AXIS : VERTICAL_AXIS;
1879
+ var _iterator4 = _createForOfIteratorHelper$2(areaRanges(state, axis)),
1880
+ _step4;
1881
+ try {
1882
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
1883
+ var range = _step4.value;
1884
+ var _iterator5 = _createForOfIteratorHelper$2(points),
1885
+ _step5;
1886
+ try {
1887
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
1888
+ var _point = _step5.value;
1889
+ if (_point[axis.pointKey] > range.begin) _point[axis.pointKey] += range.end - range.begin;
1890
+ }
1891
+ } catch (err) {
1892
+ _iterator5.e(err);
1893
+ } finally {
1894
+ _iterator5.f();
1895
+ }
1896
+ }
1897
+ } catch (err) {
1898
+ _iterator4.e(err);
1899
+ } finally {
1900
+ _iterator4.f();
1901
+ }
1902
+ }
1903
+ element.setAttribute('points', serializePolygonPoints(points));
1904
+ }
1905
+
1906
+ /** Legacy image handling: never moves x/y, resizes via the OLT target ratio, and has no global-scale branch. */
1907
+ function transformImage(image, mode, state) {
1908
+ image.setAttribute('preserveAspectRatio', 'none');
1909
+ if (mode === 'SAH') {
1910
+ var _image$getAttribute;
1911
+ var width = parseInt((_image$getAttribute = image.getAttribute('width')) !== null && _image$getAttribute !== void 0 ? _image$getAttribute : '', 10);
1912
+ image.setAttribute('width', Math.round(width * (state.targetWidthOlt / state.origOltWidth)) + 'px');
1913
+ } else if (mode === 'SAV') {
1914
+ var _image$getAttribute2;
1915
+ var height = parseInt((_image$getAttribute2 = image.getAttribute('height')) !== null && _image$getAttribute2 !== void 0 ? _image$getAttribute2 : '', 10);
1916
+ image.setAttribute('height', Math.round(height * (state.targetHeightOlt / state.origOltHeight)) + 'px');
1917
+ }
1918
+ }
1919
+ function transformPathElement(element, mode, state) {
1920
+ var _element$getAttribute2;
1921
+ var d = (_element$getAttribute2 = element.getAttribute('d')) !== null && _element$getAttribute2 !== void 0 ? _element$getAttribute2 : '';
1922
+ var warn = function warn(message) {
1923
+ return addWarning(state, message);
1924
+ };
1925
+ if (mode === 'GLOBAL_SCALE') {
1926
+ element.setAttribute('d', scalePathData(d, state.globalScaleFactorWidth, state.globalScaleFactorHeight, true, warn));
1927
+ return;
1928
+ }
1929
+ var axis = mode === 'SAH' ? HORIZONTAL_AXIS : VERTICAL_AXIS;
1930
+ element.setAttribute('d', stretchPathData(d, areaRanges(state, axis), axis, warn));
1931
+ }
1932
+ function transformElement(element, id, mode, outline, state) {
1933
+ switch (element.localName) {
1934
+ case 'g':
1935
+ return;
1936
+ case 'rect':
1937
+ {
1938
+ if (id.substring(0, 3) === 'SAV' || id.substring(0, 3) === 'SAH') return;
1939
+ if (mode === 'GLOBAL_SCALE') {
1940
+ scaleRect(element, state);
1941
+ return;
1942
+ }
1943
+ var axis = mode === 'SAH' ? HORIZONTAL_AXIS : VERTICAL_AXIS;
1944
+ stretchRect(element, areaRanges(state, axis), axis);
1945
+ return;
1946
+ }
1947
+ case 'path':
1948
+ transformPathElement(element, mode, state);
1949
+ return;
1950
+ case 'line':
1951
+ {
1952
+ // Legacy quirk: docking-point lines move only in the OLT pass, every other line in both passes.
1953
+ if (id.substring(0, 2) === 'AV' && outline !== 'OLT') return;
1954
+ if (mode === 'GLOBAL_SCALE') {
1955
+ scaleLine(element, state);
1956
+ return;
1957
+ }
1958
+ var _axis = mode === 'SAH' ? HORIZONTAL_AXIS : VERTICAL_AXIS;
1959
+ stretchLine(element, areaRanges(state, _axis), _axis);
1960
+ return;
1961
+ }
1962
+ case 'polygon':
1963
+ case 'polyline':
1964
+ transformPoints(element, mode, state);
1965
+ return;
1966
+ case 'image':
1967
+ transformImage(element, mode, state);
1968
+ return;
1969
+ default:
1970
+ if (UNTRANSFORMED_COORDINATE_ELEMENTS.includes(element.localName)) {
1971
+ addWarning(state, "stretch: <".concat(element.localName, "> has no stretch transformer and keeps its position"));
1972
+ }
1973
+ }
1974
+ }
1975
+
1976
+ /**
1977
+ * One resize pass over the DOM: OLT passes ignore the OLF/VIF subtrees, OLF passes ignore OLT/VIT —
1978
+ * geometry outside those subtrees is deliberately processed in BOTH passes.
1979
+ */
1980
+ function applyStretchPass(state, mode, outline) {
1981
+ var ignoredViewId = outline === 'OLT' ? 'VIF' : 'VIT';
1982
+ var ignoredOutlineId = outline === 'OLT' ? 'OLF' : 'OLT';
1983
+ var _walk = function walk(parent) {
1984
+ var children = parent.children;
1985
+ for (var i = 0; i < children.length; i++) {
1986
+ var child = children[i];
1987
+ var id = child.getAttribute('id');
1988
+ if (id === ignoredViewId || id === ignoredOutlineId) continue;
1989
+ transformElement(child, id !== null && id !== void 0 ? id : '', mode, outline, state);
1990
+ _walk(child);
1991
+ }
1992
+ };
1993
+ _walk(state.root);
1994
+ }
1995
+
1996
+ function setOutlineWidth(state, outline, width) {
1997
+ if (outline === 'OLT') state.widthOlt = width;else state.widthOlf = width;
1998
+ }
1999
+ function setOutlineHeight(state, outline, height) {
2000
+ if (outline === 'OLT') state.heightOlt = height;else state.heightOlf = height;
2001
+ }
2002
+
2003
+ /**
2004
+ * Lays the stretch areas out for the new size (SAV first, then SAH) and runs the element passes; in
2005
+ * global-scale mode it scales instead. Called once for the OLT and, when present, once for the OLF.
2006
+ */
2007
+ function resizeOutline(state, newWidth, newHeight, outline) {
2008
+ var currentWidth = outline === 'OLT' ? state.widthOlt : state.widthOlf;
2009
+ var currentHeight = outline === 'OLT' ? state.heightOlt : state.heightOlf;
2010
+ if (!state.useGlobalScale && state.sav.length > 0 && newHeight !== currentHeight) {
2011
+ setOutlineHeight(state, outline, newHeight);
2012
+ var deltaY = round3(newHeight - currentHeight);
2013
+ var offset = 0;
2014
+ for (var i = 0; i < state.sav.length; i++) {
2015
+ var _area$getAttribute;
2016
+ var area = state.sav[i];
2017
+ // Legacy quirk: SAV positions shift in the OLT AND the OLF pass, SAH positions only in the OLT pass.
2018
+ area.setAttribute('y', String(round3(parseFloat((_area$getAttribute = area.getAttribute('y')) !== null && _area$getAttribute !== void 0 ? _area$getAttribute : '') + offset)));
2019
+ area.setAttribute('height', String(round3(deltaY * state.ratioSav[i])));
2020
+ offset += round3(deltaY * state.ratioSav[i]);
2021
+ }
2022
+ applyStretchPass(state, 'SAV', outline);
2023
+ }
2024
+ if (!state.useGlobalScale && newWidth !== currentWidth && state.sah.length > 0) {
2025
+ setOutlineWidth(state, outline, newWidth);
2026
+ var deltaX = round3(newWidth - currentWidth);
2027
+ var _offset = 0;
2028
+ for (var _i = 0; _i < state.sah.length; _i++) {
2029
+ var _area = state.sah[_i];
2030
+ if (outline === 'OLT') {
2031
+ var _area$getAttribute2;
2032
+ _area.setAttribute('x', String(round3(parseFloat((_area$getAttribute2 = _area.getAttribute('x')) !== null && _area$getAttribute2 !== void 0 ? _area$getAttribute2 : '') + _offset)));
2033
+ _offset += round3(deltaX * state.ratioSah[_i]);
2034
+ }
2035
+ _area.setAttribute('width', String(round3(deltaX * state.ratioSah[_i])));
2036
+ }
2037
+ applyStretchPass(state, 'SAH', outline);
2038
+ }
2039
+ var scale = false;
2040
+ if (state.useGlobalScale && newHeight !== currentHeight) {
2041
+ state.globalScaleFactorHeight = newHeight / currentHeight;
2042
+ scale = true;
2043
+ setOutlineHeight(state, outline, newHeight);
2044
+ }
2045
+ if (state.useGlobalScale && newWidth !== currentWidth) {
2046
+ state.globalScaleFactorWidth = newWidth / currentWidth;
2047
+ scale = true;
2048
+ setOutlineWidth(state, outline, newWidth);
2049
+ }
2050
+ if (scale) applyStretchPass(state, 'GLOBAL_SCALE', outline);
2051
+ }
2052
+
2053
+ function _createForOfIteratorHelper$1(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$1(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
2054
+ function _unsupportedIterableToArray$1(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$1(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$1(r, a) : void 0; } }
2055
+ function _arrayLikeToArray$1(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
2056
+ /** Replaces a polygon stretch area by its bounding rect; only the id is carried over. */
2057
+ function convertPolygonToRect(polygon, document) {
2058
+ var _polygon$getAttribute, _polygon$getAttribute2, _polygon$parentElemen, _polygon$parentElemen2;
2059
+ var points = parsePolygonPoints((_polygon$getAttribute = polygon.getAttribute('points')) !== null && _polygon$getAttribute !== void 0 ? _polygon$getAttribute : '');
2060
+ if (points.length === 0) return undefined;
2061
+ var rect = document.createElementNS(polygon.namespaceURI, 'rect');
2062
+ rect.setAttribute('id', (_polygon$getAttribute2 = polygon.getAttribute('id')) !== null && _polygon$getAttribute2 !== void 0 ? _polygon$getAttribute2 : '');
2063
+ var minX = points[0].x;
2064
+ var maxX = points[0].x;
2065
+ var minY = points[0].y;
2066
+ var maxY = points[0].y;
2067
+ var _iterator = _createForOfIteratorHelper$1(points),
2068
+ _step;
2069
+ try {
2070
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
2071
+ var point = _step.value;
2072
+ if (point.x < minX) minX = point.x;else if (point.x > maxX) maxX = point.x;
2073
+ if (point.y < minY) minY = point.y;else if (point.y > maxY) maxY = point.y;
2074
+ }
2075
+ } catch (err) {
2076
+ _iterator.e(err);
2077
+ } finally {
2078
+ _iterator.f();
2079
+ }
2080
+ rect.setAttribute('x', String(minX));
2081
+ rect.setAttribute('y', String(minY));
2082
+ rect.setAttribute('width', String(maxX - minX));
2083
+ rect.setAttribute('height', String(maxY - minY));
2084
+ (_polygon$parentElemen = polygon.parentElement) === null || _polygon$parentElemen === void 0 || _polygon$parentElemen.appendChild(rect);
2085
+ (_polygon$parentElemen2 = polygon.parentElement) === null || _polygon$parentElemen2 === void 0 || _polygon$parentElemen2.removeChild(polygon);
2086
+ return rect;
2087
+ }
2088
+
2089
+ /**
2090
+ * Normalizes one stretch-area element to a rect. Unsupported representations (e.g. a `<path>` stretch area,
2091
+ * which drove the legacy math into NaN) are ignored with a warning instead.
2092
+ */
2093
+ function normalizeStretchArea(element, state) {
2094
+ var rect = element;
2095
+ if (element.nodeName === 'polygon') rect = convertPolygonToRect(element, state.document);
2096
+ if (rect === undefined || rect.nodeName !== 'rect') {
2097
+ var _element$getAttribute;
2098
+ addWarning(state, "stretch: stretch area '".concat((_element$getAttribute = element.getAttribute('id')) !== null && _element$getAttribute !== void 0 ? _element$getAttribute : '', "' is an unsupported <").concat(element.nodeName, "> and is ignored"));
2099
+ return undefined;
2100
+ }
2101
+ rect.setAttribute('style', 'fill:none;');
2102
+ return rect;
2103
+ }
2104
+
2105
+ /** Legacy selection sort, kept because it is NOT stable and the resulting stretch-area order is position-relevant. */
2106
+ function selectionSortByAttribute(elements, attribute) {
2107
+ for (var j = 0; j < elements.length; j++) {
2108
+ var minPos = j;
2109
+ for (var i = j + 1; i < elements.length; i++) {
2110
+ var _elements$i$getAttrib, _elements$minPos$getA;
2111
+ if (parseFloat((_elements$i$getAttrib = elements[i].getAttribute(attribute)) !== null && _elements$i$getAttrib !== void 0 ? _elements$i$getAttrib : '') < parseFloat((_elements$minPos$getA = elements[minPos].getAttribute(attribute)) !== null && _elements$minPos$getA !== void 0 ? _elements$minPos$getA : '')) minPos = i;
2112
+ }
2113
+ if (minPos > j) {
2114
+ var swap = elements[j];
2115
+ elements[j] = elements[minPos];
2116
+ elements[minPos] = swap;
2117
+ }
2118
+ }
2119
+ }
2120
+
2121
+ /** Measures one OLT/OLF element (rect, polygon, path or the first child of a group). */
2122
+ function measureOutline(element, name, state) {
2123
+ switch (element.localName) {
2124
+ case 'rect':
2125
+ {
2126
+ var _element$getAttribute2, _element$getAttribute3;
2127
+ // Legacy quirk: only a missing x attribute is defaulted (the y check was dead code), positions are not recorded.
2128
+ if (!element.hasAttribute('x')) element.setAttribute('x', '0');
2129
+ var width = parseFloat((_element$getAttribute2 = element.getAttribute('width')) !== null && _element$getAttribute2 !== void 0 ? _element$getAttribute2 : '');
2130
+ var height = parseFloat((_element$getAttribute3 = element.getAttribute('height')) !== null && _element$getAttribute3 !== void 0 ? _element$getAttribute3 : '');
2131
+ if (name === 'OLT') {
2132
+ state.widthOlt = width;
2133
+ state.heightOlt = height;
2134
+ } else {
2135
+ state.widthOlf = width;
2136
+ state.heightOlf = height;
2137
+ }
2138
+ return;
2139
+ }
2140
+ case 'polygon':
2141
+ {
2142
+ var _element$getAttribute4;
2143
+ var points = parsePolygonPoints((_element$getAttribute4 = element.getAttribute('points')) !== null && _element$getAttribute4 !== void 0 ? _element$getAttribute4 : '');
2144
+ // Legacy quirk: max starts at 0 (not at the first point), so all-negative outlines measure against 0.
2145
+ var maxX = 0;
2146
+ var maxY = 0;
2147
+ var minX = Number.NaN;
2148
+ var minY = Number.NaN;
2149
+ if (points[0]) {
2150
+ minX = points[0].x;
2151
+ minY = points[0].y;
2152
+ }
2153
+ var _iterator2 = _createForOfIteratorHelper$1(points),
2154
+ _step2;
2155
+ try {
2156
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
2157
+ var point = _step2.value;
2158
+ if (point.x > maxX) maxX = point.x;
2159
+ if (point.y > maxY) maxY = point.y;
2160
+ if (point.x < minX) minX = point.x;
2161
+ if (point.y < minY) minY = point.y;
2162
+ }
2163
+ } catch (err) {
2164
+ _iterator2.e(err);
2165
+ } finally {
2166
+ _iterator2.f();
2167
+ }
2168
+ if (name === 'OLT') {
2169
+ state.widthOlt = maxX - minX;
2170
+ state.heightOlt = maxY - minY;
2171
+ state.startWidthOlt = minX;
2172
+ state.startHeightOlt = minY;
2173
+ } else {
2174
+ state.widthOlf = maxX - minX;
2175
+ state.heightOlf = maxY - minY;
2176
+ state.startWidthOlf = minX;
2177
+ state.startHeightOlf = minY;
2178
+ }
2179
+ return;
2180
+ }
2181
+ case 'path':
2182
+ {
2183
+ // A malformed OLT/OLF `d` must skip the outline measurement, never throw out of the article load.
2184
+ var bounds;
2185
+ try {
2186
+ var _element$getAttribute5;
2187
+ bounds = pathBoundingBox((_element$getAttribute5 = element.getAttribute('d')) !== null && _element$getAttribute5 !== void 0 ? _element$getAttribute5 : '');
2188
+ } catch (error) {
2189
+ var _element$getAttribute6;
2190
+ addWarning(state, "stretch: outline '".concat((_element$getAttribute6 = element.getAttribute('id')) !== null && _element$getAttribute6 !== void 0 ? _element$getAttribute6 : '', "' has unparsable path data and is ignored: ").concat(error.message));
2191
+ return;
2192
+ }
2193
+ if (!bounds) return;
2194
+ if (name === 'OLT') {
2195
+ state.widthOlt = bounds.maxX - bounds.minX;
2196
+ state.heightOlt = bounds.maxY - bounds.minY;
2197
+ } else {
2198
+ state.widthOlf = bounds.maxX - bounds.minX;
2199
+ state.heightOlf = bounds.maxY - bounds.minY;
2200
+ }
2201
+ return;
2202
+ }
2203
+ case 'g':
2204
+ {
2205
+ var children = element.children;
2206
+ element.setAttribute('id', '');
2207
+ // Legacy quirk: only the FIRST child of a wrapper group is inspected.
2208
+ for (var i = 0; i < children.length; i++) {
2209
+ switch (children[i].localName) {
2210
+ case 'rect':
2211
+ case 'path':
2212
+ case 'polygon':
2213
+ children[i].setAttribute('id', name);
2214
+ measureOutline(children[i], name, state);
2215
+ break;
2216
+ }
2217
+ break;
2218
+ }
2219
+ return;
2220
+ }
2221
+ }
2222
+ }
2223
+
2224
+ /**
2225
+ * Collects and normalizes the SAH/SAV areas, measures OLT/OLF, sorts the areas by position, derives their
2226
+ * stretch ratios and zeroes their sizes — the resize passes re-grow them by the delta.
2227
+ */
2228
+ function prepareStretchGeometry(state) {
2229
+ var sahWidth = 0;
2230
+ var _iterator3 = _createForOfIteratorHelper$1(snapshotByIdPrefix(state.document, 'SAH')),
2231
+ _step3;
2232
+ try {
2233
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
2234
+ var _rect$getAttribute;
2235
+ var element = _step3.value;
2236
+ var rect = normalizeStretchArea(element, state);
2237
+ if (!rect) continue;
2238
+ sahWidth += parseFloat((_rect$getAttribute = rect.getAttribute('width')) !== null && _rect$getAttribute !== void 0 ? _rect$getAttribute : '');
2239
+ state.sah.push(rect);
2240
+ }
2241
+ } catch (err) {
2242
+ _iterator3.e(err);
2243
+ } finally {
2244
+ _iterator3.f();
2245
+ }
2246
+ var savHeight = 0;
2247
+ var _iterator4 = _createForOfIteratorHelper$1(snapshotByIdPrefix(state.document, 'SAV')),
2248
+ _step4;
2249
+ try {
2250
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
2251
+ var _rect$getAttribute2;
2252
+ var _element = _step4.value;
2253
+ var _rect = normalizeStretchArea(_element, state);
2254
+ if (!_rect) continue;
2255
+ savHeight += parseFloat((_rect$getAttribute2 = _rect.getAttribute('height')) !== null && _rect$getAttribute2 !== void 0 ? _rect$getAttribute2 : '');
2256
+ state.sav.push(_rect);
2257
+ }
2258
+ } catch (err) {
2259
+ _iterator4.e(err);
2260
+ } finally {
2261
+ _iterator4.f();
2262
+ }
2263
+ var _iterator5 = _createForOfIteratorHelper$1(snapshotByIdPrefix(state.document, 'OLF')),
2264
+ _step5;
2265
+ try {
2266
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
2267
+ var _element2 = _step5.value;
2268
+ state.hasOlf = true;
2269
+ measureOutline(_element2, 'OLF', state);
2270
+ }
2271
+ } catch (err) {
2272
+ _iterator5.e(err);
2273
+ } finally {
2274
+ _iterator5.f();
2275
+ }
2276
+ var oltElements = snapshotByIdPrefix(state.document, 'OLT');
2277
+ var _iterator6 = _createForOfIteratorHelper$1(oltElements),
2278
+ _step6;
2279
+ try {
2280
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
2281
+ var _element3$parentEleme;
2282
+ var _element3 = _step6.value;
2283
+ if (oltElements.length > 1 && ((_element3$parentEleme = _element3.parentElement) === null || _element3$parentEleme === void 0 ? void 0 : _element3$parentEleme.getAttribute('id')) !== 'TE') continue;
2284
+ measureOutline(_element3, 'OLT', state);
2285
+ }
2286
+ } catch (err) {
2287
+ _iterator6.e(err);
2288
+ } finally {
2289
+ _iterator6.f();
2290
+ }
2291
+ if (state.hasOlf) {
2292
+ state.deltaOlfWidth = state.widthOlf - state.widthOlt;
2293
+ state.deltaOlfHeight = state.heightOlf - state.heightOlt;
2294
+ }
2295
+ state.origOltWidth = state.widthOlt;
2296
+ state.origOltHeight = state.heightOlt;
2297
+ selectionSortByAttribute(state.sah, 'x');
2298
+ selectionSortByAttribute(state.sav, 'y');
2299
+ if (sahWidth > 0) state.ratioSah = state.sah.map(function (area) {
2300
+ var _area$getAttribute;
2301
+ return parseFloat((_area$getAttribute = area.getAttribute('width')) !== null && _area$getAttribute !== void 0 ? _area$getAttribute : '') / sahWidth;
2302
+ });
2303
+ if (savHeight > 0) state.ratioSav = state.sav.map(function (area) {
2304
+ var _area$getAttribute2;
2305
+ return parseFloat((_area$getAttribute2 = area.getAttribute('height')) !== null && _area$getAttribute2 !== void 0 ? _area$getAttribute2 : '') / savHeight;
2306
+ });
2307
+ var _iterator7 = _createForOfIteratorHelper$1(state.sah),
2308
+ _step7;
2309
+ try {
2310
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
2311
+ var area = _step7.value;
2312
+ area.setAttribute('width', '0');
2313
+ }
2314
+ } catch (err) {
2315
+ _iterator7.e(err);
2316
+ } finally {
2317
+ _iterator7.f();
2318
+ }
2319
+ var _iterator8 = _createForOfIteratorHelper$1(state.sav),
2320
+ _step8;
2321
+ try {
2322
+ for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
2323
+ var _area = _step8.value;
2324
+ _area.setAttribute('height', '0');
2325
+ }
2326
+ } catch (err) {
2327
+ _iterator8.e(err);
2328
+ } finally {
2329
+ _iterator8.f();
2330
+ }
2331
+ }
2332
+
2333
+ /**
2334
+ * Writes the stretched extent (max of OLT and OLF span) into the root size, shifts the viewBox origin by the
2335
+ * minBorder and mirrors the viewBox into enable-background/style.
2336
+ */
2337
+ function fixViewBox(state, minBorderX, minBorderY) {
2338
+ var root = state.root;
2339
+ var oltExtentX = state.startWidthOlt + state.widthOlt;
2340
+ var oltExtentY = state.startHeightOlt + state.heightOlt;
2341
+ var olfExtentX = state.startWidthOlf + state.widthOlf;
2342
+ var olfExtentY = state.startHeightOlf + state.heightOlf;
2343
+ var maxWidth = olfExtentX > oltExtentX ? olfExtentX : oltExtentX;
2344
+ var maxHeight = olfExtentY > oltExtentY ? olfExtentY : oltExtentY;
2345
+ root.setAttribute('height', String(round2(maxHeight)));
2346
+ root.setAttribute('width', String(round2(maxWidth)));
2347
+ var borderX = round2(minBorderX);
2348
+ var borderY = round2(minBorderY);
2349
+ var viewBox;
2350
+ if (root.hasAttribute('x') && root.hasAttribute('y')) {
2351
+ var _root$getAttribute, _root$getAttribute2;
2352
+ // Legacy quirk: the root x/y values lose their last two characters (the 'px' suffix of planner exports).
2353
+ var xText = (_root$getAttribute = root.getAttribute('x')) !== null && _root$getAttribute !== void 0 ? _root$getAttribute : '';
2354
+ var yText = (_root$getAttribute2 = root.getAttribute('y')) !== null && _root$getAttribute2 !== void 0 ? _root$getAttribute2 : '';
2355
+ viewBox = "".concat(Number.parseFloat(xText.substring(0, xText.length - 2)) + borderX, " ").concat(Number.parseFloat(yText.substring(0, yText.length - 2)) + borderY, " ").concat(round2(maxWidth), " ").concat(round2(maxHeight));
2356
+ } else {
2357
+ var _root$getAttribute3;
2358
+ var pieces = ((_root$getAttribute3 = root.getAttribute('viewBox')) !== null && _root$getAttribute3 !== void 0 ? _root$getAttribute3 : '').split(' ');
2359
+ // Legacy quirk: without stretch areas on an axis the old viewBox extent is kept (pure scaling display).
2360
+ viewBox = "".concat(Number.parseFloat(pieces[0]) + borderX, " ").concat(Number.parseFloat(pieces[1]) + borderY);
2361
+ viewBox += ' ' + (state.sah.length > 0 ? String(round2(maxWidth)) : pieces[2]);
2362
+ viewBox += ' ' + (state.sav.length > 0 ? String(round2(maxHeight)) : pieces[3]);
2363
+ }
2364
+ root.setAttribute('x', String(borderX));
2365
+ root.setAttribute('y', String(borderY));
2366
+ root.setAttribute('viewBox', viewBox);
2367
+ root.setAttribute('enable-background', 'new ' + viewBox);
2368
+ root.setAttribute('style', 'enable-background:new ' + viewBox + ';');
2369
+ }
2370
+
2371
+ /**
2372
+ * Stretches a planner article SVG to the given OLT target size (cm) by widening its SAH/SAV stretch areas,
2373
+ * or by scaling uniformly with `useGlobalScale`. Behavior-faithful to the legacy ccCheckStretchAreas engine
2374
+ * including its OLT-then-OLF double pass and rounding rules. Deliberate deviations — unknown path commands
2375
+ * survive untransformed, unsupported stretch-area elements are ignored, viewBox-scaled documents are
2376
+ * normalized exactly once — are reported in `warnings`.
2377
+ */
2378
+ function stretchArticleSvg(svg, targetWidthCm, targetDepthCm) {
2379
+ var _root$getAttribute, _root$getAttribute2, _root$getAttribute3, _root$getAttribute4, _options$minBorderX, _options$minBorderY;
2380
+ var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
2381
+ var xmlDocument = parseXml(svg);
2382
+ var root = xmlDocument.documentElement;
2383
+ if (!root) throw new Error('stretchArticleSvg: the SVG has no root element');
2384
+ var state = createStretchState(xmlDocument, root, options.useGlobalScale === true, targetWidthCm * UNIT_RECALC, targetDepthCm * UNIT_RECALC);
2385
+ normalizeRootSize(root);
2386
+ var viewBoxScale = viewBoxScaleFactor(root);
2387
+ rewriteViewBoxToCeiledInts(root);
2388
+ // Geometry is normalized to root units exactly once, and the target stays in root units.
2389
+ applyViewBoxScale(state, viewBoxScale);
2390
+ var origWidthCm = round2(parseFloat((_root$getAttribute = root.getAttribute('width')) !== null && _root$getAttribute !== void 0 ? _root$getAttribute : '') / UNIT_RECALC);
2391
+ var origDepthCm = round2(parseFloat((_root$getAttribute2 = root.getAttribute('height')) !== null && _root$getAttribute2 !== void 0 ? _root$getAttribute2 : '') / UNIT_RECALC);
2392
+ // Legacy zero-target quirks, kept verbatim including their asymmetry.
2393
+ if (state.targetWidthOlt === 0) origWidthCm = parseFloat((_root$getAttribute3 = root.getAttribute('width')) !== null && _root$getAttribute3 !== void 0 ? _root$getAttribute3 : '');
2394
+ if (state.targetHeightOlt === 0) state.targetHeightOlt = parseFloat((_root$getAttribute4 = root.getAttribute('height')) !== null && _root$getAttribute4 !== void 0 ? _root$getAttribute4 : '');
2395
+ ensureTeDisplayNone(xmlDocument);
2396
+ prepareStretchGeometry(state);
2397
+ if (targetWidthCm === origWidthCm && targetDepthCm === origDepthCm) {
2398
+ return {
2399
+ svg: serializeXml(xmlDocument),
2400
+ sizes: currentSizes(state),
2401
+ warnings: state.warnings
2402
+ };
2403
+ }
2404
+ resizeOutline(state, state.targetWidthOlt, state.targetHeightOlt, 'OLT');
2405
+ if (state.hasOlf) resizeOutline(state, state.targetWidthOlt + state.deltaOlfWidth, state.targetHeightOlt + state.deltaOlfHeight, 'OLF');
2406
+ fixViewBox(state, (_options$minBorderX = options.minBorderX) !== null && _options$minBorderX !== void 0 ? _options$minBorderX : 0, (_options$minBorderY = options.minBorderY) !== null && _options$minBorderY !== void 0 ? _options$minBorderY : 0);
2407
+ return {
2408
+ svg: serializeXml(xmlDocument),
2409
+ sizes: currentSizes(state),
2410
+ warnings: state.warnings
2411
+ };
2412
+ }
2413
+
2414
+ /**
2415
+ * One AV connector of a planner element. Name parsing supports the legacy underscore form (AVC_2) and the
2416
+ * IDM form (AVC2); AVR/AVL and names containing _IL always ignore the layer check.
2417
+ */
2418
+ var DockingPoint = /*#__PURE__*/function () {
2419
+ function DockingPoint(elementId, type, name, localPos, rotDeg, layer, plannerConfig, filter) {
2420
+ _classCallCheck__default["default"](this, DockingPoint);
2421
+ _defineProperty__default["default"](this, "dockingPoint", void 0);
2422
+ _defineProperty__default["default"](this, "layer", void 0);
2423
+ _defineProperty__default["default"](this, "isDisabled", void 0);
2424
+ _defineProperty__default["default"](this, "plannerConfig", void 0);
2425
+ this.plannerConfig = plannerConfig;
2426
+ this.isDisabled = false;
2427
+ var number = -1;
2428
+ var splittedAV = name.split('_');
2429
+ if (splittedAV.length >= 2) {
2430
+ for (var i = 1; i < splittedAV.length; i++) {
2431
+ var part = parseInt(splittedAV[i]);
2432
+ if (!isNaN(part)) {
2433
+ number = part;
2434
+ break;
2435
+ }
2436
+ }
2437
+ } else if (name.length > 3) {
2438
+ var _part = parseInt(name.substring(3));
2439
+ if (!isNaN(_part)) {
2440
+ number = _part;
2441
+ }
2442
+ }
2443
+ this.dockingPoint = {
2444
+ dpId: type + '_' + name,
2445
+ elementId: elementId,
2446
+ type: type,
2447
+ name: name,
2448
+ ignoreLayer: type === 'AVR' || type === 'AVL' || name.indexOf('_IL') >= 0,
2449
+ localWorldPos: localPos,
2450
+ rotDeg: rotDeg,
2451
+ isDocking: false,
2452
+ dpFilter: filter
2453
+ };
2454
+ if (number >= 0) {
2455
+ this.dockingPoint.number = number;
2456
+ }
2457
+ this.layer = layer;
2458
+ }
2459
+
2460
+ /** Clones the docking point including its docking state. */
2461
+ return _createClass__default["default"](DockingPoint, [{
2462
+ key: "clone",
2463
+ value: function clone() {
2464
+ var dpClone = new DockingPoint(this.dockingPoint.elementId, this.dockingPoint.type, this.dockingPoint.name, this.dockingPoint.localWorldPos, this.dockingPoint.rotDeg, this.layer, this.plannerConfig, this.dockingPoint.dpFilter);
2465
+ dpClone.dockingPoint.dpId = this.dockingPoint.dpId;
2466
+ dpClone.dockingPoint.ignoreLayer = this.dockingPoint.ignoreLayer;
2467
+ dpClone.dockingPoint.isDocking = this.dockingPoint.isDocking;
2468
+ dpClone.dockingPoint.number = this.dockingPoint.number;
2469
+ dpClone.dockingPoint.onDP = this.dockingPoint.onDP;
2470
+ dpClone.dockingPoint.onElementId = this.dockingPoint.onElementId;
2471
+ return dpClone;
2472
+ }
2473
+ }, {
2474
+ key: "ElementId",
2475
+ get: function get() {
2476
+ return this.dockingPoint.elementId;
2477
+ }
2478
+ }, {
2479
+ key: "Name",
2480
+ get: function get() {
2481
+ return this.dockingPoint.name;
2482
+ }
2483
+ }, {
2484
+ key: "LocalWorldPos",
2485
+ get: function get() {
2486
+ return this.dockingPoint.localWorldPos;
2487
+ }
2488
+ }, {
2489
+ key: "RotDeg",
2490
+ get: function get() {
2491
+ return this.dockingPoint.rotDeg;
2492
+ }
2493
+ }, {
2494
+ key: "Type",
2495
+ get: function get() {
2496
+ return this.dockingPoint.type;
2497
+ }
2498
+ }, {
2499
+ key: "IsDocking",
2500
+ get: function get() {
2501
+ return this.dockingPoint.isDocking;
2502
+ }
2503
+ }, {
2504
+ key: "Layer",
2505
+ get: function get() {
2506
+ return this.layer;
2507
+ }
2508
+ }, {
2509
+ key: "IgnoreLayer",
2510
+ get: function get() {
2511
+ return this.dockingPoint.ignoreLayer;
2512
+ }
2513
+ }, {
2514
+ key: "HasNumber",
2515
+ get: function get() {
2516
+ return this.dockingPoint.number != undefined;
2517
+ }
2518
+ }, {
2519
+ key: "Number",
2520
+ get: function get() {
2521
+ return this.dockingPoint.number;
2522
+ }
2523
+ }, {
2524
+ key: "PlannerConfig",
2525
+ get: function get() {
2526
+ return this.plannerConfig;
2527
+ }
2528
+ }, {
2529
+ key: "IsDisabled",
2530
+ get: function get() {
2531
+ return this.isDisabled;
2532
+ }
2533
+ }, {
2534
+ key: "DPFilter",
2535
+ get: function get() {
2536
+ return this.dockingPoint.dpFilter;
2537
+ }
2538
+
2539
+ /** Marks this docking point as docked onto refDockingPoint of the element refElementId. */
2540
+ }, {
2541
+ key: "doDock",
2542
+ value: function doDock(refDockingPoint, refElementId) {
2543
+ this.dockingPoint.isDocking = true;
2544
+ this.dockingPoint.onDP = refDockingPoint;
2545
+ this.dockingPoint.onElementId = refElementId;
2546
+ }
2547
+ }, {
2548
+ key: "undock",
2549
+ value: function undock() {
2550
+ this.dockingPoint.isDocking = false;
2551
+ this.dockingPoint.onDP = undefined;
2552
+ this.dockingPoint.onElementId = undefined;
2553
+ }
2554
+
2555
+ /** Temporarily disables the docking point so the planner ignores it. */
2556
+ }, {
2557
+ key: "disableDP",
2558
+ value: function disableDP(doDisable) {
2559
+ this.isDisabled = doDisable;
2560
+ }
2561
+ }, {
2562
+ key: "OnDP",
2563
+ get: function get() {
2564
+ return this.dockingPoint.onDP;
2565
+ }
2566
+ }, {
2567
+ key: "OnElementId",
2568
+ get: function get() {
2569
+ return this.dockingPoint.onElementId;
2570
+ }
2571
+ }, {
2572
+ key: "DpId",
2573
+ get: function get() {
2574
+ return this.dockingPoint.dpId;
2575
+ }
2576
+ }]);
2577
+ }();
2578
+
2579
+ /** A dockable pair found by an area search, with its ground-plane distance in cm. */
2580
+
2581
+ /** Stateless docking domain logic: AV line parsing, pairing rules and dock/undock bookkeeping. */
2582
+ var DockingPointHandler = /*#__PURE__*/function () {
2583
+ function DockingPointHandler() {
2584
+ _classCallCheck__default["default"](this, DockingPointHandler);
2585
+ }
2586
+ return _createClass__default["default"](DockingPointHandler, [{
2587
+ key: "getRotOfDP",
2588
+ value: /** Clockwise rotation in degrees of the vector pos1 -> pos2, where 0 points downwards: down 0, left 90, up 180, right 270. */
2589
+ function getRotOfDP(pos1, pos2) {
2590
+ var directionVec = Vector2.getDirection(pos2, pos1);
2591
+ var refDirection = new Vector2(0, 1);
2592
+ var smallAngle = Vector2.angleDeg(refDirection, directionVec);
2593
+ if (directionVec.x > 0) {
2594
+ return 360 - smallAngle;
2595
+ }
2596
+ return smallAngle;
2597
+ }
2598
+
2599
+ /** The counterpart type a docking point type pairs with: AVR<->AVL, AVO<->AVU, AVS<->AVN, AVC<->AVC. */
2600
+ }, {
2601
+ key: "getReferenceDPType",
2602
+ value: function getReferenceDPType(dpType) {
2603
+ switch (dpType) {
2604
+ case 'AVR':
2605
+ return 'AVL';
2606
+ case 'AVL':
2607
+ return 'AVR';
2608
+ case 'AVO':
2609
+ return 'AVU';
2610
+ case 'AVU':
2611
+ return 'AVO';
2612
+ case 'AVC':
2613
+ return 'AVC';
2614
+ case 'AVS':
2615
+ return 'AVN';
2616
+ case 'AVN':
2617
+ return 'AVS';
2618
+ }
2619
+ return '';
2620
+ }
2621
+ }, {
2622
+ key: "sortDockingPoints",
2623
+ value: function sortDockingPoints(dir, dockingPoints) {
2624
+ if (dir === 'LEFT_TO_RIGHT') return dockingPoints.sort(function (a, b) {
2625
+ return a.LocalWorldPos.x > b.LocalWorldPos.x ? 1 : -1;
2626
+ });
2627
+ return dockingPoints.sort(function (a, b) {
2628
+ return a.LocalWorldPos.x < b.LocalWorldPos.x ? 1 : -1;
2629
+ });
2630
+ }
2631
+ }, {
2632
+ key: "checkDPAVLFilterDoMatch",
2633
+ value: function checkDPAVLFilterDoMatch(plannerElement1, plannerElement2) {
2634
+ var avrFilter1 = plannerElement1.FilterAVR;
2635
+ var avlFilter2 = plannerElement2.FilterAVL;
2636
+
2637
+ // An empty filter on either side means "no connector restriction" -> always dockable.
2638
+ if (avlFilter2.length === 0 || avrFilter1.length === 0) return true;
2639
+ for (var i = 0; i < avrFilter1.length; i++) {
2640
+ for (var j = 0; j < avlFilter2.length; j++) {
2641
+ if (avrFilter1[i] === avlFilter2[j]) {
2642
+ return true;
2643
+ }
2644
+ }
2645
+ }
2646
+ return false;
2647
+ }
2648
+ }, {
2649
+ key: "checkDPAVRFilterDoMatch",
2650
+ value: function checkDPAVRFilterDoMatch(plannerElement1, plannerElement2) {
2651
+ var avlFilter1 = plannerElement1.FilterAVL;
2652
+ var avrFilter2 = plannerElement2.FilterAVR;
2653
+
2654
+ // An empty filter on either side means "no connector restriction" -> always dockable.
2655
+ if (avlFilter1.length === 0 || avrFilter2.length === 0) return true;
2656
+ for (var i = 0; i < avlFilter1.length; i++) {
2657
+ for (var j = 0; j < avrFilter2.length; j++) {
2658
+ if (avlFilter1[i] === avrFilter2[j]) {
2659
+ return true;
2660
+ }
2661
+ }
2662
+ }
2663
+ return false;
2664
+ }
2665
+
2666
+ /**
2667
+ * The central pairing gate: connector filters, counterpart type, both points free, layer inequality
2668
+ * (with the catalog overrides ignoreLayerAVC / ignoreLayerAVOAVU / ignoreLayerAVNAVS) and number equality.
2669
+ */
2670
+ }, {
2671
+ key: "checkDPsDoMatch",
2672
+ value: function checkDPsDoMatch(dp1, dp2, sourcePlannerElement, targetElement) {
2673
+ var avrDockable = this.checkDPAVRFilterDoMatch(sourcePlannerElement, targetElement);
2674
+ var avlDockable = this.checkDPAVLFilterDoMatch(sourcePlannerElement, targetElement);
2675
+ var refDPType = this.getReferenceDPType(dp1.Type);
2676
+ if (refDPType === 'AVL' && !avlDockable) {
2677
+ return false;
2678
+ }
2679
+ if (refDPType === 'AVR' && !avrDockable) {
2680
+ return false;
2681
+ }
2682
+ if (dp2.Type !== refDPType) {
2683
+ return false;
2684
+ }
2685
+ if (dp1.IsDocking || dp2.IsDocking) {
2686
+ return false;
2687
+ }
2688
+ if (!dp1.IgnoreLayer || !dp2.IgnoreLayer) {
2689
+ var doCheckLayer = true;
2690
+ if (dp1.PlannerConfig.ignoreLayerAVC && (dp1.Type === 'AVC' || dp2.Type === 'AVC')) {
2691
+ doCheckLayer = false;
2692
+ }
2693
+ if (dp1.PlannerConfig.ignoreLayerAVOAVU && (dp1.Type === 'AVO' || dp1.Type === 'AVU') && (dp2.Type === 'AVO' || dp2.Type === 'AVU')) {
2694
+ doCheckLayer = false;
2695
+ }
2696
+ if (dp1.PlannerConfig.ignoreLayerAVNAVS && (dp1.Type === 'AVN' || dp1.Type === 'AVS') && (dp2.Type === 'AVN' || dp2.Type === 'AVS')) {
2697
+ doCheckLayer = false;
2698
+ }
2699
+ if (doCheckLayer && dp2.Layer === dp1.Layer) {
2700
+ return false;
2701
+ }
2702
+ }
2703
+ if (!dp1.PlannerConfig.ignoreDockingNumber && dp1.HasNumber && dp2.HasNumber && dp1.Number !== dp2.Number) {
2704
+ return false;
2705
+ }
2706
+ return true;
2707
+ }
2708
+ }, {
2709
+ key: "doDock",
2710
+ value: function doDock(dp1, dp2, elemId1, elemId2) {
2711
+ dp1.doDock(dp2, elemId2);
2712
+ dp2.doDock(dp1, elemId1);
2713
+ }
2714
+
2715
+ /**
2716
+ * (Re-)initializes all docking points of an element from its SVG AV lines: saves the current docking state for
2717
+ * later redocking, converts line coordinates to minBorder-corrected cm and derives each point's rotation.
2718
+ */
2719
+ }, {
2720
+ key: "initDockingPointsFromSvg",
2721
+ value: function initDockingPointsFromSvg(plannerElement, dockingVectors, minBorder, plannerConfig) {
2722
+ plannerElement.saveCurrentDPState();
2723
+ this.removeDockingPointRelations(plannerElement);
2724
+ plannerElement.clearAllDockingPoints();
2725
+ for (var i = 0; i < dockingVectors.length; i++) {
2726
+ var dockingVector = dockingVectors[i];
2727
+ var localWorldPos1 = new Vector2((dockingVector.x1 - minBorder.minX) / UNIT_RECALC, (dockingVector.y1 - minBorder.minY) / UNIT_RECALC);
2728
+ var localWorldPos2 = new Vector2((dockingVector.x2 - minBorder.minX) / UNIT_RECALC, (dockingVector.y2 - minBorder.minY) / UNIT_RECALC);
2729
+ var angle = this.getRotOfDP(localWorldPos1, localWorldPos2);
2730
+ var dockingFilter = undefined;
2731
+ if (dockingVector.dockingType === 'AVL') dockingFilter = plannerElement.getFilterAVL();else if (dockingVector.dockingType === 'AVR') dockingFilter = plannerElement.getFilterAVR();
2732
+ var dockingPoint = new DockingPoint(plannerElement.getElementId(), dockingVector.dockingType, dockingVector.dockingName, new Vector3(localWorldPos1.x, 0, localWorldPos1.y), angle, plannerElement.Layer, plannerConfig, dockingFilter);
2733
+ plannerElement.addDockingPoint(dockingPoint);
2734
+ }
2735
+ }
2736
+
2737
+ /** Removes all docking relations of the element, also on the docked counterparts (used when deleting an element). */
2738
+ }, {
2739
+ key: "removeDockingPointRelations",
2740
+ value: function removeDockingPointRelations(plannerElement) {
2741
+ var dockingPoints = plannerElement.getDockingPoints();
2742
+ for (var i = 0; i < dockingPoints.length; i++) {
2743
+ var dockingPoint = dockingPoints[i];
2744
+ if (dockingPoint.IsDocking) {
2745
+ var refDockingPoint = dockingPoint.OnDP;
2746
+ refDockingPoint.undock();
2747
+ dockingPoint.undock();
2748
+ }
2749
+ }
2750
+ }
2751
+
2752
+ /**
2753
+ * Removes all docking relations of the given types, also on the docked counterparts.
2754
+ * @returns the element ids that lost a relation
2755
+ */
2756
+ }, {
2757
+ key: "removeDockingPointRelationsByType",
2758
+ value: function removeDockingPointRelationsByType(plannerElement, dpTypeList) {
2759
+ var undockedFromElements = [];
2760
+ var dockingPoints = plannerElement.getDockingPoints();
2761
+ for (var i = 0; i < dockingPoints.length; i++) {
2762
+ var dockingPoint = dockingPoints[i];
2763
+ if (dpTypeList.indexOf(dockingPoint.Type) > -1 && dockingPoint.IsDocking) {
2764
+ var refDockingPoint = dockingPoint.OnDP;
2765
+ undockedFromElements.push(refDockingPoint.ElementId);
2766
+ refDockingPoint.undock();
2767
+ dockingPoint.undock();
2768
+ }
2769
+ }
2770
+ return undockedFromElements;
2771
+ }
2772
+
2773
+ /**
2774
+ * Searches all dockable pairs between the source element and the targets within the given ground-plane distance,
2775
+ * keeping only the nearest pair per source docking point type.
2776
+ * @param autoDockingDistance 0 -> never dock, Infinity -> dock at any distance
2777
+ */
2778
+ }, {
2779
+ key: "searchDockableElementsInArea",
2780
+ value: function searchDockableElementsInArea(sourceElement, targetElements, autoDockingDistance) {
2781
+ var sourceDPs = sourceElement.getAllDockingPoints();
2782
+ var dockableDPPairs = new Map();
2783
+ for (var i = 0; i < targetElements.length; i++) {
2784
+ var targetElement = targetElements[i];
2785
+ if (sourceElement.getElementId() === targetElement.getElementId()) continue;
2786
+ for (var di = 0; di < sourceDPs.length; di++) {
2787
+ var sourceDP = sourceDPs[di];
2788
+ var targetType = this.getReferenceDPType(sourceDP.Type);
2789
+ var targetDPs = targetElement.getFreeDockingPointsByType(targetType);
2790
+ for (var j = 0; j < targetDPs.length; j++) {
2791
+ var targetDP = targetDPs[j];
2792
+ if (!this.checkDPsDoMatch(sourceDP, targetDP, sourceElement, targetElement)) continue;
2793
+ var worldPosSourceDP = sourceElement.getWorldPosOfDP(sourceDP.DpId);
2794
+ var worldPosTargetDP = targetElement.getWorldPosOfDP(targetDP.DpId);
2795
+ var distance = Math.sqrt(Math.pow(worldPosSourceDP.x - worldPosTargetDP.x, 2) + Math.pow(worldPosSourceDP.z - worldPosTargetDP.z, 2));
2796
+ if (autoDockingDistance !== 0 && (autoDockingDistance === Infinity || distance < autoDockingDistance)) {
2797
+ var existingPair = dockableDPPairs.get(sourceDP.Type);
2798
+ if (!existingPair || distance < existingPair.distance) {
2799
+ dockableDPPairs.set(sourceDP.Type, {
2800
+ sourceDP: sourceDP,
2801
+ targetDP: targetDP,
2802
+ distance: distance
2803
+ });
2804
+ }
2805
+ }
2806
+ }
2807
+ }
2808
+ }
2809
+ return dockableDPPairs;
2810
+ }
2811
+
2812
+ /**
2813
+ * Tries to dock the source element with a docking point of the given type onto any of the target elements.
2814
+ * Non-accessories never dock onto foreign accessories; accessories only dock onto articles listing their codex.
2815
+ * @returns the docked source docking point, or false
2816
+ */
2817
+ }, {
2818
+ key: "tryDockElement",
2819
+ value: function tryDockElement(sourcePlannerElement, sourceDPType, targetElements) {
2820
+ var dockingPoints = sourcePlannerElement.getDockingPointsByType(sourceDPType);
2821
+ if (!dockingPoints) {
2822
+ return false;
2823
+ }
2824
+ var refDPType = this.getReferenceDPType(sourceDPType);
2825
+ for (var i = 0; i < targetElements.length; i++) {
2826
+ var targetElement = targetElements[i];
2827
+ if (targetElement.ElementId === sourcePlannerElement.ElementId) continue;
2828
+ if (!sourcePlannerElement.IsAccessoire && targetElement.IsAccessoire && targetElement.getParentElementId() !== sourcePlannerElement.getElementId()) continue;
2829
+ if (sourcePlannerElement.IsAccessoire && !targetElement.getAccessoires().includes(sourcePlannerElement.ArticleCodex)) continue;
2830
+ var targetDockingPoints = targetElement.getDockingPointsByType(refDPType);
2831
+ if (sourcePlannerElement.getIsDockedAccessoire() || sourcePlannerElement.IsAccessoire) {
2832
+ targetDockingPoints = this.sortDockingPoints('LEFT_TO_RIGHT', targetDockingPoints);
2833
+ }
2834
+ if (!targetDockingPoints) continue;
2835
+ for (var j = 0; j < targetDockingPoints.length; j++) {
2836
+ var targetDockingPoint = targetDockingPoints[j];
2837
+ for (var dpNr = 0; dpNr < dockingPoints.length; dpNr++) {
2838
+ var dockingPoint = dockingPoints[dpNr];
2839
+ if (this.checkDPsDoMatch(dockingPoint, targetDockingPoint, sourcePlannerElement, targetElement)) {
2840
+ this.doDock(dockingPoint, targetDockingPoint, sourcePlannerElement.ElementId, targetElement.ElementId);
2841
+ return dockingPoint;
2842
+ }
2843
+ }
2844
+ }
2845
+ }
2846
+ return false;
2847
+ }
2848
+
2849
+ /**
2850
+ * Tries to dock the source element onto one specific docking point of the target element.
2851
+ * @returns the docked source docking point, or false
2852
+ */
2853
+ }, {
2854
+ key: "tryDockElementToDP",
2855
+ value: function tryDockElementToDP(sourcePlannerElement, targetElement, targetDP) {
2856
+ var sourceDPType = this.getReferenceDPType(targetDP.Type);
2857
+ var dockingPoints = sourcePlannerElement.getFreeDockingPointsByType(sourceDPType);
2858
+ if (!dockingPoints) {
2859
+ return false;
2860
+ }
2861
+ for (var i = 0; i < dockingPoints.length; i++) {
2862
+ if (this.checkDPsDoMatch(dockingPoints[i], targetDP, sourcePlannerElement, targetElement)) {
2863
+ this.doDock(dockingPoints[i], targetDP, sourcePlannerElement.ElementId, targetElement.ElementId);
2864
+ return dockingPoints[i];
2865
+ }
2866
+ }
2867
+ return false;
2868
+ }
2869
+
2870
+ /** Tries to dock one specific pair of docking points. */
2871
+ }, {
2872
+ key: "tryDockElementDPToDP",
2873
+ value: function tryDockElementDPToDP(sourcePlannerElement, targetElement, sourceDP, targetDP) {
2874
+ if (this.checkDPsDoMatch(sourceDP, targetDP, sourcePlannerElement, targetElement)) {
2875
+ this.doDock(sourceDP, targetDP, sourcePlannerElement.getElementId(), targetElement.getElementId());
2876
+ return true;
2877
+ }
2878
+ return false;
2879
+ }
2880
+
2881
+ /**
2882
+ * Restores docking relations after one or more SVGs were reloaded, based on the state saved by
2883
+ * saveCurrentDPState, including the fallback for changed docking point numbers.
2884
+ * @returns the elements that lost their docking relation
2885
+ */
2886
+ }, {
2887
+ key: "updateDockingRelations",
2888
+ value: function updateDockingRelations(plannerElements) {
2889
+ var sortedPlannerElementsByPosNr = [];
2890
+ var accessoryElements = [];
2891
+ plannerElements.forEach(function (plannerElement) {
2892
+ if (!plannerElement.IsDockedAccessoire) {
2893
+ sortedPlannerElementsByPosNr[plannerElement.PosNr - 1] = plannerElement;
2894
+ } else {
2895
+ accessoryElements.push(plannerElement);
2896
+ }
2897
+ });
2898
+ sortedPlannerElementsByPosNr = sortedPlannerElementsByPosNr.concat(accessoryElements);
2899
+ var elementsLostDockingRelation = [];
2900
+ for (var i = 0; i < sortedPlannerElementsByPosNr.length; i++) {
2901
+ if (!sortedPlannerElementsByPosNr[i]) continue;
2902
+ var element = sortedPlannerElementsByPosNr[i];
2903
+ var tempDPs = element.getTempDockingPoints();
2904
+ for (var j = 0; j < tempDPs.length; j++) {
2905
+ var tempDP = tempDPs[j];
2906
+ if (!tempDP.IsDocking || !tempDP.OnElementId) continue;
2907
+ var dp = element.getDockingPointById(tempDP.DpId);
2908
+ if (dp == undefined) {
2909
+ // The previously docked point no longer exists after the reload.
2910
+ var targetElement = plannerElements.get(tempDP.OnElementId);
2911
+
2912
+ // A resize can renumber connectors (AVO_1/AVU_1 becoming AVO_2/AVU_2), so when both sides have
2913
+ // exactly one free point of the type, redock those.
2914
+ var dockingPointsCurElement = element.getFreeDockingPointsByType(tempDP.Type);
2915
+ if (dockingPointsCurElement.length === 1) {
2916
+ var dockingPointsToDockElement = targetElement === null || targetElement === void 0 ? void 0 : targetElement.getFreeDockingPointsByType(this.getReferenceDPType(tempDP.Type));
2917
+ if (targetElement && (dockingPointsToDockElement === null || dockingPointsToDockElement === void 0 ? void 0 : dockingPointsToDockElement.length) === 1) {
2918
+ this.tryDockElementDPToDP(element, targetElement, dockingPointsCurElement[0], dockingPointsToDockElement[0]);
2919
+ continue;
2920
+ }
2921
+ }
2922
+ if (targetElement) elementsLostDockingRelation.push(targetElement);
2923
+ continue;
2924
+ }
2925
+ if (plannerElements.has(tempDP.OnElementId)) {
2926
+ var _targetElement = plannerElements.get(tempDP.OnElementId);
2927
+ var targetDP = tempDP.OnDP ? _targetElement === null || _targetElement === void 0 ? void 0 : _targetElement.getDockingPointById(tempDP.OnDP.DpId) : undefined;
2928
+ if (_targetElement && targetDP) this.tryDockElementDPToDP(element, _targetElement, dp, targetDP);
2929
+ }
2930
+ }
2931
+ }
2932
+ for (var _i = 0; _i < sortedPlannerElementsByPosNr.length; _i++) {
2933
+ if (sortedPlannerElementsByPosNr[_i]) sortedPlannerElementsByPosNr[_i].clearTempDockingPoints();
2934
+ }
2935
+ return elementsLostDockingRelation;
2936
+ }
2937
+
2938
+ /**
2939
+ * Docks the source's free docking point of the given type to the nearest matching point of the target element
2940
+ * (used when initializing a planning where only the pair of elements and the type are known).
2941
+ */
2942
+ }, {
2943
+ key: "initDockingPointRelationByArea",
2944
+ value: function initDockingPointRelationByArea(sourcePlannerElement, targetPlannerElement, sourceDPType) {
2945
+ var freeSourceDPs = sourcePlannerElement.getFreeDockingPointsByType(sourceDPType);
2946
+ if (freeSourceDPs.length === 0) return;
2947
+ var allDockingPairs = this.searchDockableElementsInArea(sourcePlannerElement, [targetPlannerElement], Infinity);
2948
+ var dockingPair = allDockingPairs.get(sourceDPType);
2949
+ if (!dockingPair) return;
2950
+ var success = this.tryDockElementDPToDP(sourcePlannerElement, targetPlannerElement, dockingPair.sourceDP, dockingPair.targetDP);
2951
+ if (!success) {
2952
+ getPlanner2DLogger().debug('Error when initializing docking Points. Two dockingpoints could not be matched. sourceDP: ' + dockingPair.sourceDP.DpId + '; sourceElementId: ' + dockingPair.sourceDP.ElementId + '; targetDP: ' + dockingPair.targetDP.DpId + ' targetElemId: ' + dockingPair.targetDP.ElementId);
2953
+ }
2954
+ }
2955
+
2956
+ /** True when the two elements are docked to each other. */
2957
+ }, {
2958
+ key: "checkElementsAreDocking",
2959
+ value: function checkElementsAreDocking(element1, element2) {
2960
+ var allDockingDockingPoints = element1.getDockingDockingPoints();
2961
+ for (var i = 0; i < allDockingDockingPoints.length; i++) {
2962
+ if (allDockingDockingPoints[i].OnElementId === element2.getElementId()) return true;
2963
+ }
2964
+ return false;
2965
+ }
2966
+ }]);
2967
+ }();
2968
+
2969
+ /** Shared instance; the handler carries no state, so one serves all scenes. */
2970
+ var dockingPointHandler = new DockingPointHandler();
2971
+
2972
+ /** The transform-relevant surface of a planner element. */
2973
+
2974
+ /**
2975
+ * World transform of an element after docking its point `dp` onto `refDP` of `refElement`: the rotation is
2976
+ * refElement.RotDeg + refDP.RotDeg - dp.RotDeg, the position aligns the two docking points via their rotated
2977
+ * local vectors. A docking point's LocalWorldPos is OLF-corner-relative when the element has an OLF polygon,
2978
+ * hence the OLT-corner conversion for the ignore-OLF variant.
2979
+ */
2980
+ function computeDockedTransform(refElement, refDP, element, dp) {
2981
+ var refDPLocalOlt = refElement.HasOLFPolygon ? new Vector2(refDP.LocalWorldPos.x - refElement.getOltLeft(), refDP.LocalWorldPos.z - refElement.getOltTop()) : new Vector2(refDP.LocalWorldPos.x, refDP.LocalWorldPos.z);
2982
+ var newDPLocalOlt = element.HasOLFPolygon ? new Vector2(dp.LocalWorldPos.x - element.getOltLeft(), dp.LocalWorldPos.z - element.getOltTop()) : new Vector2(dp.LocalWorldPos.x, dp.LocalWorldPos.z);
2983
+ var rotatedLocalRefDP = Vector2.rotateOrigin(new Vector2(refDP.LocalWorldPos.x, refDP.LocalWorldPos.z), refElement.RotDeg);
2984
+ var rotDeg = refElement.RotDeg + refDP.RotDeg - dp.RotDeg;
2985
+ var refWorldPosCor = refElement.WorldPosCorner;
2986
+ // Without an OLF there is no OLF/OLT split, so both alignments share the same corner.
2987
+ var refWorldPosCorIgnoreOLF = refElement.HasOLFPolygon ? refElement.WorldPosCornerIgnoreOLF : refWorldPosCor;
2988
+ var rotatedLocalDP2D = Vector2.rotateOrigin(new Vector2(dp.LocalWorldPos.x, dp.LocalWorldPos.z), rotDeg);
2989
+ var worldPosCorner = new Vector3(refWorldPosCor.x + rotatedLocalRefDP.x - rotatedLocalDP2D.x, refWorldPosCor.y + refDP.LocalWorldPos.y - dp.LocalWorldPos.y, refWorldPosCor.z + rotatedLocalRefDP.y - rotatedLocalDP2D.y);
2990
+ var rotatedRefDPOlt = Vector2.rotateOrigin(refDPLocalOlt, refElement.RotDeg);
2991
+ var rotatedNewDPOlt = Vector2.rotateOrigin(newDPLocalOlt, rotDeg);
2992
+ var worldPosCornerIgnoreOLF = new Vector3(refWorldPosCorIgnoreOLF.x + rotatedRefDPOlt.x - rotatedNewDPOlt.x, refWorldPosCorIgnoreOLF.y + refDP.LocalWorldPos.y - dp.LocalWorldPos.y, refWorldPosCorIgnoreOLF.z + rotatedRefDPOlt.y - rotatedNewDPOlt.y);
2993
+ return {
2994
+ rotDeg: rotDeg,
2995
+ worldPosCorner: worldPosCorner,
2996
+ worldPosCornerIgnoreOLF: worldPosCornerIgnoreOLF
2997
+ };
2998
+ }
2999
+
3000
+ /**
3001
+ * True when the two segments properly intersect, endpoint touches included. Parallel and collinear-overlapping
3002
+ * segments report false on purpose (fabric reported those as 'Parallel'/'Coincident'), perpendicular corner
3003
+ * touches count as an intersection.
3004
+ */
3005
+ function segmentsIntersect(a1, a2, b1, b2) {
3006
+ var uaT = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x);
3007
+ var ubT = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x);
3008
+ var uB = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
3009
+ if (uB === 0) return false;
3010
+ var ua = uaT / uB;
3011
+ var ub = ubT / uB;
3012
+ return ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1;
3013
+ }
3014
+
3015
+ /** True when any edge of polygon1 intersects any edge of polygon2. */
3016
+ function polygonEdgesIntersect(polygonPoints1, polygonPoints2) {
3017
+ for (var i = 0; i < polygonPoints1.length; i++) {
3018
+ var start1 = polygonPoints1[i];
3019
+ var end1 = polygonPoints1[(i + 1) % polygonPoints1.length];
3020
+ for (var j = 0; j < polygonPoints2.length; j++) {
3021
+ var start2 = polygonPoints2[j];
3022
+ var end2 = polygonPoints2[(j + 1) % polygonPoints2.length];
3023
+ if (segmentsIntersect(start1, end1, start2, end2)) {
3024
+ return true;
3025
+ }
3026
+ }
3027
+ }
3028
+ return false;
3029
+ }
3030
+
3031
+ /**
3032
+ * True when polygon1 lies completely inside polygon2 (ray casting with a horizontal ray per vertex),
3033
+ * including the legacy early exit as soon as vertices fall on both sides.
3034
+ */
3035
+ function polygonInsidePolygon(polygonPoints1, polygonPoints2) {
3036
+ var pointOutsideCount = 0;
3037
+ var pointInsideCount = 0;
3038
+ for (var i = 0; i < polygonPoints1.length; i++) {
3039
+ var start1 = polygonPoints1[i];
3040
+ var end1 = new Vector2(start1.x + 999999, start1.y);
3041
+ var intersectionCount = 0;
3042
+ for (var j = 0; j < polygonPoints2.length; j++) {
3043
+ var start2 = polygonPoints2[j];
3044
+ var end2 = polygonPoints2[(j + 1) % polygonPoints2.length];
3045
+ if (segmentsIntersect(start1, end1, start2, end2)) intersectionCount++;
3046
+ }
3047
+ if (intersectionCount % 2 === 0) {
3048
+ pointOutsideCount++;
3049
+ } else {
3050
+ pointInsideCount++;
3051
+ }
3052
+ if (pointOutsideCount > 0 && pointInsideCount > 0) return false;
3053
+ }
3054
+ return pointInsideCount === polygonPoints1.length;
3055
+ }
3056
+
3057
+ /**
3058
+ * Core collision decision of the 2D planner: when the bounding-box outlines intersect, the detail polygons
3059
+ * decide; otherwise one outline lying completely inside the other counts as collision. Layer filtering
3060
+ * stays with the caller.
3061
+ */
3062
+ function outlinesCollide(bboxOutline1, bboxOutline2, detailPolygon1, detailPolygon2) {
3063
+ if (polygonEdgesIntersect(bboxOutline1, bboxOutline2)) {
3064
+ return polygonEdgesIntersect(detailPolygon1, detailPolygon2);
3065
+ }
3066
+ return polygonInsidePolygon(bboxOutline1, bboxOutline2);
3067
+ }
3068
+
3069
+ /** Article-level data of a testbed element. */
3070
+
3071
+ /**
3072
+ * Reference implementation of the element surface the docking logic needs — no DivaSet, no engine.
3073
+ * WorldPosCorner is the world position of the SVG's minBorder-corrected local origin, matching how docking
3074
+ * point LocalWorldPos values are stored; the ignore-OLF corner tracks the OLT origin.
3075
+ */
3076
+ var SimplePlannerElement = /*#__PURE__*/function () {
3077
+ function SimplePlannerElement(elementId, data) {
3078
+ var _data$layer, _data$articleCodex, _data$isAccessoire, _data$filterAVL, _data$filterAVR, _data$parentElementId, _data$accessoires;
3079
+ _classCallCheck__default["default"](this, SimplePlannerElement);
3080
+ _defineProperty__default["default"](this, "ElementId", void 0);
3081
+ _defineProperty__default["default"](this, "Layer", void 0);
3082
+ _defineProperty__default["default"](this, "ArticleCodex", void 0);
3083
+ _defineProperty__default["default"](this, "IsAccessoire", void 0);
3084
+ _defineProperty__default["default"](this, "FilterAVL", void 0);
3085
+ _defineProperty__default["default"](this, "FilterAVR", void 0);
3086
+ _defineProperty__default["default"](this, "PosNr", void 0);
3087
+ _defineProperty__default["default"](this, "IsDockedAccessoire", false);
3088
+ _defineProperty__default["default"](this, "RotDeg", 0);
3089
+ _defineProperty__default["default"](this, "WorldPosCorner", new Vector3(0, 0, 0));
3090
+ _defineProperty__default["default"](this, "WorldPosCornerIgnoreOLF", new Vector3(0, 0, 0));
3091
+ _defineProperty__default["default"](this, "HasOLFPolygon", false);
3092
+ _defineProperty__default["default"](this, "oltLeftCm", 0);
3093
+ _defineProperty__default["default"](this, "oltTopCm", 0);
3094
+ _defineProperty__default["default"](this, "parentElementId", void 0);
3095
+ _defineProperty__default["default"](this, "accessoires", void 0);
3096
+ _defineProperty__default["default"](this, "dockingPoints", []);
3097
+ _defineProperty__default["default"](this, "tempDockingPoints", []);
3098
+ this.ElementId = elementId;
3099
+ this.PosNr = elementId;
3100
+ this.Layer = (_data$layer = data === null || data === void 0 ? void 0 : data.layer) !== null && _data$layer !== void 0 ? _data$layer : 0;
3101
+ this.ArticleCodex = (_data$articleCodex = data === null || data === void 0 ? void 0 : data.articleCodex) !== null && _data$articleCodex !== void 0 ? _data$articleCodex : "ARTICLE-".concat(elementId);
3102
+ this.IsAccessoire = (_data$isAccessoire = data === null || data === void 0 ? void 0 : data.isAccessoire) !== null && _data$isAccessoire !== void 0 ? _data$isAccessoire : false;
3103
+ this.FilterAVL = (_data$filterAVL = data === null || data === void 0 ? void 0 : data.filterAVL) !== null && _data$filterAVL !== void 0 ? _data$filterAVL : [];
3104
+ this.FilterAVR = (_data$filterAVR = data === null || data === void 0 ? void 0 : data.filterAVR) !== null && _data$filterAVR !== void 0 ? _data$filterAVR : [];
3105
+ this.parentElementId = (_data$parentElementId = data === null || data === void 0 ? void 0 : data.parentElementId) !== null && _data$parentElementId !== void 0 ? _data$parentElementId : -1;
3106
+ this.accessoires = (_data$accessoires = data === null || data === void 0 ? void 0 : data.accessoires) !== null && _data$accessoires !== void 0 ? _data$accessoires : [];
3107
+ }
3108
+
3109
+ /** Registers the OLT origin offset within the OLF (cm) and flags the element as OLF-carrying. */
3110
+ return _createClass__default["default"](SimplePlannerElement, [{
3111
+ key: "setupOlfOffset",
3112
+ value: function setupOlfOffset(oltLeftCm, oltTopCm) {
3113
+ this.HasOLFPolygon = true;
3114
+ this.oltLeftCm = oltLeftCm;
3115
+ this.oltTopCm = oltTopCm;
3116
+ }
3117
+ }, {
3118
+ key: "getElementId",
3119
+ value: function getElementId() {
3120
+ return this.ElementId;
3121
+ }
3122
+ }, {
3123
+ key: "getParentElementId",
3124
+ value: function getParentElementId() {
3125
+ return this.parentElementId;
3126
+ }
3127
+ }, {
3128
+ key: "getAccessoires",
3129
+ value: function getAccessoires() {
3130
+ return this.accessoires;
3131
+ }
3132
+ }, {
3133
+ key: "getIsDockedAccessoire",
3134
+ value: function getIsDockedAccessoire() {
3135
+ return this.IsDockedAccessoire;
3136
+ }
3137
+ }, {
3138
+ key: "saveCurrentDPState",
3139
+ value: function saveCurrentDPState() {
3140
+ if (this.dockingPoints.length === 0) return;
3141
+ this.tempDockingPoints = this.dockingPoints.map(function (dockingPoint) {
3142
+ return dockingPoint.clone();
3143
+ });
3144
+ }
3145
+ }, {
3146
+ key: "clearAllDockingPoints",
3147
+ value: function clearAllDockingPoints() {
3148
+ this.dockingPoints = [];
3149
+ }
3150
+ }, {
3151
+ key: "addDockingPoint",
3152
+ value: function addDockingPoint(dockingPoint) {
3153
+ this.dockingPoints.push(dockingPoint);
3154
+ }
3155
+ }, {
3156
+ key: "getDockingPoints",
3157
+ value: function getDockingPoints() {
3158
+ return this.dockingPoints;
3159
+ }
3160
+ }, {
3161
+ key: "getAllDockingPoints",
3162
+ value: function getAllDockingPoints() {
3163
+ return this.dockingPoints;
3164
+ }
3165
+ }, {
3166
+ key: "getDockingPointsByType",
3167
+ value: function getDockingPointsByType(type) {
3168
+ return this.dockingPoints.filter(function (dockingPoint) {
3169
+ return dockingPoint.Type === type;
3170
+ });
3171
+ }
3172
+ }, {
3173
+ key: "getFreeDockingPointsByType",
3174
+ value: function getFreeDockingPointsByType(type) {
3175
+ return this.dockingPoints.filter(function (dockingPoint) {
3176
+ return dockingPoint.Type === type && !dockingPoint.IsDocking;
3177
+ });
3178
+ }
3179
+ }, {
3180
+ key: "getDockingPointById",
3181
+ value: function getDockingPointById(dpId) {
3182
+ return this.dockingPoints.find(function (dockingPoint) {
3183
+ return dockingPoint.DpId === dpId;
3184
+ });
3185
+ }
3186
+ }, {
3187
+ key: "getDockingDockingPoints",
3188
+ value: function getDockingDockingPoints() {
3189
+ return this.dockingPoints.filter(function (dockingPoint) {
3190
+ return dockingPoint.IsDocking;
3191
+ });
3192
+ }
3193
+ }, {
3194
+ key: "getFilterAVL",
3195
+ value: function getFilterAVL() {
3196
+ return this.FilterAVL.length ? this.FilterAVL : undefined;
3197
+ }
3198
+ }, {
3199
+ key: "getFilterAVR",
3200
+ value: function getFilterAVR() {
3201
+ return this.FilterAVR.length ? this.FilterAVR : undefined;
3202
+ }
3203
+ }, {
3204
+ key: "getWorldPosOfDP",
3205
+ value: function getWorldPosOfDP(dpId) {
3206
+ var dockingPoint = this.getDockingPointById(dpId);
3207
+ if (!dockingPoint) return new Vector3(0, 0, 0);
3208
+ var rotated = Vector2.rotateOrigin(new Vector2(dockingPoint.LocalWorldPos.x, dockingPoint.LocalWorldPos.z), this.RotDeg);
3209
+ return new Vector3(this.WorldPosCorner.x + rotated.x, this.WorldPosCorner.y, this.WorldPosCorner.z + rotated.y);
3210
+ }
3211
+ }, {
3212
+ key: "getTempDockingPoints",
3213
+ value: function getTempDockingPoints() {
3214
+ return this.tempDockingPoints;
3215
+ }
3216
+ }, {
3217
+ key: "clearTempDockingPoints",
3218
+ value: function clearTempDockingPoints() {
3219
+ this.tempDockingPoints = [];
3220
+ }
3221
+ }, {
3222
+ key: "getOltLeft",
3223
+ value: function getOltLeft() {
3224
+ return this.oltLeftCm;
3225
+ }
3226
+ }, {
3227
+ key: "getOltTop",
3228
+ value: function getOltTop() {
3229
+ return this.oltTopCm;
3230
+ }
3231
+ }]);
3232
+ }();
3233
+
3234
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
3235
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
3236
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
3237
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3238
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty__default["default"](e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3239
+ var DEFAULT_DOCKING_CONFIG = {
3240
+ ignoreLayerAVC: false,
3241
+ ignoreLayerAVOAVU: false,
3242
+ ignoreLayerAVNAVS: false,
3243
+ ignoreDockingNumber: false
3244
+ };
3245
+ var DOCK_TYPE_TRY_ORDER = ['AVL', 'AVR', 'AVO', 'AVU', 'AVN', 'AVS', 'AVC'];
3246
+
3247
+ /**
3248
+ * Standalone docking testbed: article SVGs in, docking points, pairings and world positions out. No catalog
3249
+ * API, no browser, no engine. In Node a jsdom window is loaded lazily; configureDom is only needed for a custom DOM.
3250
+ */
3251
+ var DockingScene = /*#__PURE__*/function () {
3252
+ function DockingScene(options) {
3253
+ _classCallCheck__default["default"](this, DockingScene);
3254
+ _defineProperty__default["default"](this, "handler", new DockingPointHandler());
3255
+ _defineProperty__default["default"](this, "dockingConfig", void 0);
3256
+ _defineProperty__default["default"](this, "elements", new Map());
3257
+ _defineProperty__default["default"](this, "nextElementId", 1);
3258
+ this.dockingConfig = _objectSpread(_objectSpread({}, DEFAULT_DOCKING_CONFIG), options === null || options === void 0 ? void 0 : options.dockingConfig);
3259
+ }
3260
+
3261
+ /** Parses the article SVG (docking lines, minBorder, OLT/OLF geometry) and adds it as a new element at the world origin. */
3262
+ return _createClass__default["default"](DockingScene, [{
3263
+ key: "addArticle",
3264
+ value: function addArticle(svg, data) {
3265
+ var element = new SimplePlannerElement(this.nextElementId++, data);
3266
+ var olt = getOltGeometry(svg);
3267
+ var olf = getOlfGeometry(svg);
3268
+ if (olt && olf) {
3269
+ element.setupOlfOffset((olt.x - olf.minX) / UNIT_RECALC, (olt.y - olf.minY) / UNIT_RECALC);
3270
+ }
3271
+ this.handler.initDockingPointsFromSvg(element, getDockingPointLines(svg), getMinBorder(svg), this.dockingConfig);
3272
+ this.elements.set(element.ElementId, element);
3273
+ return element;
3274
+ }
3275
+ }, {
3276
+ key: "getElement",
3277
+ value: function getElement(elementId) {
3278
+ return this.elements.get(elementId);
3279
+ }
3280
+ }, {
3281
+ key: "getElements",
3282
+ value: function getElements() {
3283
+ return _toConsumableArray__default["default"](this.elements.values());
3284
+ }
3285
+
3286
+ /**
3287
+ * Tries to dock the source element onto the target and, on success, moves the source to its docked world transform.
3288
+ * Without an explicit sourceDpType all types are tried in planner order (AVL first).
3289
+ */
3290
+ }, {
3291
+ key: "tryDock",
3292
+ value: function tryDock(source, target, sourceDpType) {
3293
+ var typesToTry = sourceDpType ? [sourceDpType] : DOCK_TYPE_TRY_ORDER;
3294
+ for (var _i = 0, _typesToTry = typesToTry; _i < _typesToTry.length; _i++) {
3295
+ var type = _typesToTry[_i];
3296
+ var sourceDP = this.handler.tryDockElement(source, type, [target]);
3297
+ if (!sourceDP) continue;
3298
+ var targetDP = sourceDP.OnDP;
3299
+ var transform = computeDockedTransform(target, targetDP, source, sourceDP);
3300
+ source.RotDeg = transform.rotDeg;
3301
+ source.WorldPosCorner = transform.worldPosCorner;
3302
+ source.WorldPosCornerIgnoreOLF = transform.worldPosCornerIgnoreOLF;
3303
+ return {
3304
+ docked: true,
3305
+ dockingType: sourceDP.Type,
3306
+ sourceDpId: sourceDP.DpId,
3307
+ targetDpId: targetDP.DpId,
3308
+ rotDeg: transform.rotDeg,
3309
+ worldPosCorner: transform.worldPosCorner
3310
+ };
3311
+ }
3312
+ return {
3313
+ docked: false
3314
+ };
3315
+ }
3316
+
3317
+ /** All free (not yet docked) docking points of the element. */
3318
+ }, {
3319
+ key: "freeDockingPoints",
3320
+ value: function freeDockingPoints(element) {
3321
+ return element.getAllDockingPoints().filter(function (dockingPoint) {
3322
+ return !dockingPoint.IsDocking;
3323
+ });
3324
+ }
3325
+
3326
+ /** All docked pairs in the scene, one entry per relation; the source side is the element that docked onto the other. */
3327
+ }, {
3328
+ key: "dockedPairs",
3329
+ value: function dockedPairs() {
3330
+ var pairs = [];
3331
+ var seen = new Set();
3332
+ var _iterator = _createForOfIteratorHelper(this.elements.values()),
3333
+ _step;
3334
+ try {
3335
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
3336
+ var element = _step.value;
3337
+ var _iterator2 = _createForOfIteratorHelper(element.getDockingDockingPoints()),
3338
+ _step2;
3339
+ try {
3340
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
3341
+ var _dockingPoint$OnDP, _dockingPoint$OnDP2;
3342
+ var dockingPoint = _step2.value;
3343
+ var key = [element.ElementId, dockingPoint.DpId, dockingPoint.OnElementId, (_dockingPoint$OnDP = dockingPoint.OnDP) === null || _dockingPoint$OnDP === void 0 ? void 0 : _dockingPoint$OnDP.DpId].join('|');
3344
+ var reverseKey = [dockingPoint.OnElementId, (_dockingPoint$OnDP2 = dockingPoint.OnDP) === null || _dockingPoint$OnDP2 === void 0 ? void 0 : _dockingPoint$OnDP2.DpId, element.ElementId, dockingPoint.DpId].join('|');
3345
+ if (seen.has(reverseKey)) continue;
3346
+ seen.add(key);
3347
+ pairs.push({
3348
+ sourceElementId: element.ElementId,
3349
+ sourceDpId: dockingPoint.DpId,
3350
+ targetElementId: dockingPoint.OnElementId,
3351
+ targetDpId: dockingPoint.OnDP.DpId
3352
+ });
3353
+ }
3354
+ } catch (err) {
3355
+ _iterator2.e(err);
3356
+ } finally {
3357
+ _iterator2.f();
3358
+ }
3359
+ }
3360
+ } catch (err) {
3361
+ _iterator.e(err);
3362
+ } finally {
3363
+ _iterator.f();
3364
+ }
3365
+ return pairs;
3366
+ }
3367
+ }]);
3368
+ }();
3369
+
3370
+ exports.DOCKING_TYPES = DOCKING_TYPES;
3371
+ exports.DockingPoint = DockingPoint;
3372
+ exports.DockingPointHandler = DockingPointHandler;
3373
+ exports.DockingScene = DockingScene;
3374
+ exports.SimplePlannerElement = SimplePlannerElement;
3375
+ exports.UNIT_RECALC = UNIT_RECALC;
3376
+ exports.Vector2 = Vector2;
3377
+ exports.Vector3 = Vector3;
3378
+ exports.computeDockedTransform = computeDockedTransform;
3379
+ exports.configureDom = configureDom;
3380
+ exports.dockingPointHandler = dockingPointHandler;
3381
+ exports.getBoundingBoxOfPoints = getBoundingBoxOfPoints;
3382
+ exports.getContentBounds = getContentBounds;
3383
+ exports.getDockingPointLines = getDockingPointLines;
3384
+ exports.getMinBorder = getMinBorder;
3385
+ exports.getOlfGeometry = getOlfGeometry;
3386
+ exports.getOltGeometry = getOltGeometry;
3387
+ exports.getPlanner2DLogger = getPlanner2DLogger;
3388
+ exports.getPolygonPoints = getPolygonPoints;
3389
+ exports.getRootSize = getRootSize;
3390
+ exports.isDockingType = isDockingType;
3391
+ exports.outlinesCollide = outlinesCollide;
3392
+ exports.parsePathCommands = parsePathCommands;
3393
+ exports.parseXml = parseXml;
3394
+ exports.pathBoundingBox = pathBoundingBox;
3395
+ exports.polygonEdgesIntersect = polygonEdgesIntersect;
3396
+ exports.polygonInsidePolygon = polygonInsidePolygon;
3397
+ exports.removeMask = removeMask;
3398
+ exports.removeOlf = removeOlf;
3399
+ exports.segmentsIntersect = segmentsIntersect;
3400
+ exports.serializeXml = serializeXml;
3401
+ exports.setPlanner2DLogger = setPlanner2DLogger;
3402
+ exports.stretchArticleSvg = stretchArticleSvg;