kitchen-simulator 11.30.3 → 11.32.0
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.
- package/es/assets/img/svg/accessories.svg +4 -4
- package/es/assets/img/svg/bottombar/elevation-back.svg +6 -6
- package/es/assets/img/svg/bottombar/elevation-front.svg +6 -6
- package/es/assets/img/svg/bottombar/elevation-left.svg +6 -6
- package/es/assets/img/svg/bottombar/elevation-right.svg +7 -7
- package/es/assets/img/svg/bottombar/elevation.svg +13 -13
- package/es/assets/img/svg/detail.svg +77 -77
- package/es/assets/img/svg/filtersActive.svg +19 -19
- package/es/assets/img/svg/invert.svg +12 -12
- package/es/assets/img/svg/menubar/login.svg +84 -84
- package/es/assets/img/svg/menubar/my_projects.svg +85 -85
- package/es/assets/img/svg/menubar/new_project.svg +110 -110
- package/es/assets/img/svg/menubar/save_project.svg +84 -84
- package/es/assets/img/svg/options.svg +3 -3
- package/es/assets/img/svg/positioning.svg +3 -3
- package/es/assets/img/svg/toggleFilters.svg +19 -19
- package/es/assets/img/svg/toolbar/shopping-cart.svg +13 -13
- package/es/assets/img/svg/wizardstep/detail_view.svg +87 -87
- package/es/assets/img/svg/wizardstep/tile_view.svg +95 -95
- package/es/catalog/utils/exporter.js +2 -0
- package/es/catalog/utils/item-loader.js +9 -4
- package/es/class/item.js +1 -0
- package/es/components/viewer3d/camera-controls-module/camera-controls.module.js +556 -556
- package/es/components/viewer3d/scene-creator.js +5 -5
- package/es/constants.js +1 -0
- package/es/engine/2d/viewer-utils.js +11 -11
- package/es/events/external/handleExternalEvent.util.js +80 -66
- package/es/events/external/handlers.changeDoorStyle.js +8 -15
- package/es/events/external/handlers.loadProject.js +8 -15
- package/es/mappings/external-events/mapExternalEventPayload.js +4 -4
- package/es/mappings/external-events/mappers/addItemMapper.js +9 -9
- package/es/mappings/external-events/mappers/ccdfMapper.js +7 -13
- package/es/models.js +2 -0
- package/es/shared/concurrency/async-pool.js +71 -0
- package/es/shared/domain/asset/sanitize-asset-url.js +5 -5
- package/es/shared/math/line-metrics.js +11 -11
- package/es/utils/geometry.js +6 -4
- package/es/utils/skinPanelEngine.js +14 -14
- package/lib/assets/img/svg/accessories.svg +4 -4
- package/lib/assets/img/svg/bottombar/elevation-back.svg +6 -6
- package/lib/assets/img/svg/bottombar/elevation-front.svg +6 -6
- package/lib/assets/img/svg/bottombar/elevation-left.svg +6 -6
- package/lib/assets/img/svg/bottombar/elevation-right.svg +7 -7
- package/lib/assets/img/svg/bottombar/elevation.svg +13 -13
- package/lib/assets/img/svg/detail.svg +77 -77
- package/lib/assets/img/svg/filtersActive.svg +19 -19
- package/lib/assets/img/svg/invert.svg +12 -12
- package/lib/assets/img/svg/menubar/login.svg +84 -84
- package/lib/assets/img/svg/menubar/my_projects.svg +85 -85
- package/lib/assets/img/svg/menubar/new_project.svg +110 -110
- package/lib/assets/img/svg/menubar/save_project.svg +84 -84
- package/lib/assets/img/svg/options.svg +3 -3
- package/lib/assets/img/svg/positioning.svg +3 -3
- package/lib/assets/img/svg/toggleFilters.svg +19 -19
- package/lib/assets/img/svg/toolbar/shopping-cart.svg +13 -13
- package/lib/assets/img/svg/wizardstep/detail_view.svg +87 -87
- package/lib/assets/img/svg/wizardstep/tile_view.svg +95 -95
- package/lib/catalog/utils/exporter.js +2 -0
- package/lib/catalog/utils/item-loader.js +9 -4
- package/lib/class/item.js +1 -0
- package/lib/components/viewer3d/camera-controls-module/camera-controls.module.js +556 -556
- package/lib/components/viewer3d/scene-creator.js +5 -5
- package/lib/constants.js +5 -4
- package/lib/engine/2d/viewer-utils.js +11 -11
- package/lib/events/external/handleExternalEvent.util.js +80 -66
- package/lib/events/external/handlers.changeDoorStyle.js +8 -15
- package/lib/events/external/handlers.loadProject.js +8 -15
- package/lib/mappings/external-events/mapExternalEventPayload.js +4 -4
- package/lib/mappings/external-events/mappers/addItemMapper.js +9 -9
- package/lib/mappings/external-events/mappers/ccdfMapper.js +7 -13
- package/lib/models.js +2 -0
- package/lib/shared/concurrency/async-pool.js +78 -0
- package/lib/shared/domain/asset/sanitize-asset-url.js +5 -5
- package/lib/shared/math/line-metrics.js +11 -11
- package/lib/utils/geometry.js +5 -3
- package/lib/utils/skinPanelEngine.js +14 -14
- package/package.json +1 -1
|
@@ -3058,12 +3058,12 @@ export function createBacksplash(item, layer, planData, scene) {
|
|
|
3058
3058
|
var disD0 = lineLength * hole.offset - width / 2;
|
|
3059
3059
|
var disD1 = lineLength * hole.offset + width / 2;
|
|
3060
3060
|
D0 = {
|
|
3061
|
-
x: v0.x + disD0 * Math.cos(hole.
|
|
3062
|
-
y: v0.y + disD0 * Math.sin(hole.
|
|
3061
|
+
x: v0.x + disD0 * Math.cos(hole.rotation),
|
|
3062
|
+
y: v0.y + disD0 * Math.sin(hole.rotation)
|
|
3063
3063
|
};
|
|
3064
3064
|
D1 = {
|
|
3065
|
-
x: v0.x + disD1 * Math.cos(hole.
|
|
3066
|
-
y: v0.y + disD1 * Math.sin(hole.
|
|
3065
|
+
x: v0.x + disD1 * Math.cos(hole.rotation),
|
|
3066
|
+
y: v0.y + disD1 * Math.sin(hole.rotation)
|
|
3067
3067
|
};
|
|
3068
3068
|
}
|
|
3069
3069
|
if (!isEmpty(width) && !isEmpty(altitude) && hole.line === (curLine === null || curLine === void 0 ? void 0 : curLine.id)) altItems.push({
|
|
@@ -3638,7 +3638,7 @@ export function updateMoldingGroupArray(MGArray, selItem, planData, layer) {
|
|
|
3638
3638
|
var _mg$items$2, _mg$items$3, _mg$items$4;
|
|
3639
3639
|
var molding = isImmutable((_mg$items$2 = mg.items[0]) === null || _mg$items$2 === void 0 ? void 0 : _mg$items$2.molding) ? (_mg$items$3 = mg.items[0]) === null || _mg$items$3 === void 0 || (_mg$items$3 = _mg$items$3.molding) === null || _mg$items$3 === void 0 ? void 0 : _mg$items$3.filter(function (mol) {
|
|
3640
3640
|
var _mol$toJS2;
|
|
3641
|
-
return (mol === null || mol === void 0 || (_mol$toJS2 = mol.toJS()) === null || _mol$toJS2 === void 0 ? void 0 : _mol$toJS2.location_type) === mg.location_type;
|
|
3641
|
+
return isImmutable(mol) ? (mol === null || mol === void 0 || (_mol$toJS2 = mol.toJS()) === null || _mol$toJS2 === void 0 ? void 0 : _mol$toJS2.location_type) === mg.location_type : (mol === null || mol === void 0 ? void 0 : mol.location_type) === mg.location_type;
|
|
3642
3642
|
}).toJS()[0] : (_mg$items$4 = mg.items[0]) === null || _mg$items$4 === void 0 || (_mg$items$4 = _mg$items$4.molding) === null || _mg$items$4 === void 0 ? void 0 : _mg$items$4.filter(function (mol) {
|
|
3643
3643
|
return (mol === null || mol === void 0 ? void 0 : mol.location_type) === mg.location_type;
|
|
3644
3644
|
})[0];
|
package/es/constants.js
CHANGED
|
@@ -459,6 +459,7 @@ export var UNIT_MILE = 'mi';
|
|
|
459
459
|
export var UNITS_LENGTH = [UNIT_MILLIMETER, UNIT_CENTIMETER, UNIT_METER, UNIT_INCH, UNIT_FOOT, UNIT_MILE];
|
|
460
460
|
export var CEIL_UNITS_LENGTH = [UNIT_CENTIMETER, UNIT_METER, UNIT_INCH, UNIT_FOOT];
|
|
461
461
|
export var EPSILON = 0.5;
|
|
462
|
+
export var LINE_EPSILON = 0.01;
|
|
462
463
|
|
|
463
464
|
// distance between item and wall
|
|
464
465
|
export var DISTANCE_EPSILON = 5.0; //5.08; // 2 inch
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { APPLIANCE_CATEGORY_COOK_TOP, APPLIANCE_CATEGORY_HOOD, APPLIANCE_CATEGORY_RANGE } from "../../constants/applianceCategories";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Returns `true` for items that are intentionally allowed to overlap other
|
|
5
|
-
* elements while being placed/dragged in the 2D viewer.
|
|
6
|
-
*
|
|
7
|
-
* Why this exists:
|
|
8
|
-
* - `GeometryUtils.validInterSect(...)` is used as a collision/intersection gate.
|
|
9
|
-
* - Some appliances (e.g. cooktops/ranges/hoods) are expected to be placed "on"
|
|
10
|
-
* or "inside" cabinetry/countertops, so they must not be blocked by that gate.
|
|
11
|
-
*
|
|
12
|
-
* NOTE: This currently identifies items by the appliance category strings found
|
|
13
|
-
* in `itemInfo.name` / `itemInfo.cabinet_category`.
|
|
3
|
+
/**
|
|
4
|
+
* Returns `true` for items that are intentionally allowed to overlap other
|
|
5
|
+
* elements while being placed/dragged in the 2D viewer.
|
|
6
|
+
*
|
|
7
|
+
* Why this exists:
|
|
8
|
+
* - `GeometryUtils.validInterSect(...)` is used as a collision/intersection gate.
|
|
9
|
+
* - Some appliances (e.g. cooktops/ranges/hoods) are expected to be placed "on"
|
|
10
|
+
* or "inside" cabinetry/countertops, so they must not be blocked by that gate.
|
|
11
|
+
*
|
|
12
|
+
* NOTE: This currently identifies items by the appliance category strings found
|
|
13
|
+
* in `itemInfo.name` / `itemInfo.cabinet_category`.
|
|
14
14
|
*/
|
|
15
15
|
export var shouldBypassItemIntersectionValidation = function shouldBypassItemIntersectionValidation(itemRect) {
|
|
16
16
|
var itemInfo = itemRect === null || itemRect === void 0 ? void 0 : itemRect.itemInfo;
|
|
@@ -44,40 +44,54 @@ function parseTempPlaceholdersFromCabinetPayload(_x) {
|
|
|
44
44
|
}
|
|
45
45
|
/***** Update cabinetPayloadData with updatedTempPlaceholders *****/
|
|
46
46
|
function _parseTempPlaceholdersFromCabinetPayload() {
|
|
47
|
-
_parseTempPlaceholdersFromCabinetPayload = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function
|
|
48
|
-
var
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
_parseTempPlaceholdersFromCabinetPayload = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4(cabinetPayload) {
|
|
48
|
+
var _cabinetPayload$struc;
|
|
49
|
+
var keys, gltfEntries, temp, tempPlaceholdersData, k, _cabinetPayload$struc3, el, tempData, doorKey, drawerKey, fixedKey, doorPHs, drawerPHs, has_single_door, fixedPHs;
|
|
50
|
+
return _regeneratorRuntime.wrap(function (_context4) {
|
|
51
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
51
52
|
case 0:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
link = cabinetPayload.structure_json[keys[i]];
|
|
66
|
-
_t2 = temp;
|
|
67
|
-
_t3 = keys[i];
|
|
68
|
-
_context3.next = 2;
|
|
69
|
-
return loadJSONWithFallback(link);
|
|
70
|
-
case 2:
|
|
71
|
-
_t4 = _context3.sent;
|
|
72
|
-
_t2.push.call(_t2, {
|
|
73
|
-
name: _t3,
|
|
74
|
-
data: _t4
|
|
53
|
+
keys = Object.keys((_cabinetPayload$struc = cabinetPayload.structure_json) !== null && _cabinetPayload$struc !== void 0 ? _cabinetPayload$struc : {}); // Load all referenced .gltf JSONs in parallel.
|
|
54
|
+
// NOTE: loadJSON() already has a per-URL promise cache, so duplicates are de-duped across calls.
|
|
55
|
+
gltfEntries = keys.map(function (name) {
|
|
56
|
+
var _cabinetPayload$struc2;
|
|
57
|
+
return {
|
|
58
|
+
name: name,
|
|
59
|
+
link: (_cabinetPayload$struc2 = cabinetPayload.structure_json) === null || _cabinetPayload$struc2 === void 0 ? void 0 : _cabinetPayload$struc2[name]
|
|
60
|
+
};
|
|
61
|
+
}).filter(function (_ref3) {
|
|
62
|
+
var _link$toString, _link$toString2;
|
|
63
|
+
var link = _ref3.link;
|
|
64
|
+
return (link === null || link === void 0 || (_link$toString = link.toString) === null || _link$toString === void 0 || (_link$toString = _link$toString.call(link)) === null || _link$toString === void 0 ? void 0 : _link$toString.includes('.gltf')) && (link === null || link === void 0 || (_link$toString2 = link.toString) === null || _link$toString2 === void 0 || (_link$toString2 = _link$toString2.call(link)) === null || _link$toString2 === void 0 ? void 0 : _link$toString2.startsWith('http'));
|
|
75
65
|
});
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
_context4.next = 1;
|
|
67
|
+
return Promise.all(gltfEntries.map(/*#__PURE__*/function () {
|
|
68
|
+
var _ref5 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(_ref4) {
|
|
69
|
+
var name, link, _t2, _t3;
|
|
70
|
+
return _regeneratorRuntime.wrap(function (_context3) {
|
|
71
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
72
|
+
case 0:
|
|
73
|
+
name = _ref4.name, link = _ref4.link;
|
|
74
|
+
_t2 = name;
|
|
75
|
+
_context3.next = 1;
|
|
76
|
+
return loadJSONWithFallback(link);
|
|
77
|
+
case 1:
|
|
78
|
+
_t3 = _context3.sent;
|
|
79
|
+
return _context3.abrupt("return", {
|
|
80
|
+
name: _t2,
|
|
81
|
+
data: _t3
|
|
82
|
+
});
|
|
83
|
+
case 2:
|
|
84
|
+
case "end":
|
|
85
|
+
return _context3.stop();
|
|
86
|
+
}
|
|
87
|
+
}, _callee3);
|
|
88
|
+
}));
|
|
89
|
+
return function (_x9) {
|
|
90
|
+
return _ref5.apply(this, arguments);
|
|
91
|
+
};
|
|
92
|
+
}()));
|
|
93
|
+
case 1:
|
|
94
|
+
temp = _context4.sent;
|
|
81
95
|
tempPlaceholdersData = [];
|
|
82
96
|
for (k = 0; k < (cabinetPayload === null || cabinetPayload === void 0 || (_cabinetPayload$struc3 = cabinetPayload.structure_json) === null || _cabinetPayload$struc3 === void 0 || (_cabinetPayload$struc3 = _cabinetPayload$struc3.tempPlaceholders) === null || _cabinetPayload$struc3 === void 0 ? void 0 : _cabinetPayload$struc3.length); k++) {
|
|
83
97
|
el = cabinetPayload.structure_json.tempPlaceholders[k].id;
|
|
@@ -386,12 +400,12 @@ function _parseTempPlaceholdersFromCabinetPayload() {
|
|
|
386
400
|
structure: cabinetPayload.structure_json.tempPlaceholders[k].structure
|
|
387
401
|
});
|
|
388
402
|
}
|
|
389
|
-
return
|
|
390
|
-
case
|
|
403
|
+
return _context4.abrupt("return", tempPlaceholdersData);
|
|
404
|
+
case 2:
|
|
391
405
|
case "end":
|
|
392
|
-
return
|
|
406
|
+
return _context4.stop();
|
|
393
407
|
}
|
|
394
|
-
},
|
|
408
|
+
}, _callee4);
|
|
395
409
|
}));
|
|
396
410
|
return _parseTempPlaceholdersFromCabinetPayload.apply(this, arguments);
|
|
397
411
|
}
|
|
@@ -399,16 +413,16 @@ function updateCabinetPayload(_x2) {
|
|
|
399
413
|
return _updateCabinetPayload.apply(this, arguments);
|
|
400
414
|
}
|
|
401
415
|
function _updateCabinetPayload() {
|
|
402
|
-
_updateCabinetPayload = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function
|
|
416
|
+
_updateCabinetPayload = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5(cabinetPayload) {
|
|
403
417
|
var tempPlaceholders, cabinetPayloadKeys, i;
|
|
404
|
-
return _regeneratorRuntime.wrap(function (
|
|
405
|
-
while (1) switch (
|
|
418
|
+
return _regeneratorRuntime.wrap(function (_context5) {
|
|
419
|
+
while (1) switch (_context5.prev = _context5.next) {
|
|
406
420
|
case 0:
|
|
407
421
|
tempPlaceholders = [];
|
|
408
|
-
|
|
422
|
+
_context5.next = 1;
|
|
409
423
|
return parseTempPlaceholdersFromCabinetPayload(cabinetPayload);
|
|
410
424
|
case 1:
|
|
411
|
-
tempPlaceholders =
|
|
425
|
+
tempPlaceholders = _context5.sent;
|
|
412
426
|
cabinetPayloadKeys = Object.keys(cabinetPayload);
|
|
413
427
|
for (i = 0; i < cabinetPayloadKeys.length; i++) {
|
|
414
428
|
if (cabinetPayloadKeys[i] === 'structure_json') {
|
|
@@ -420,12 +434,12 @@ function _updateCabinetPayload() {
|
|
|
420
434
|
cabinetPayload[cabinetPayloadKeys[i]]['tempPlaceholders'] = tempPlaceholders;
|
|
421
435
|
}
|
|
422
436
|
}
|
|
423
|
-
return
|
|
437
|
+
return _context5.abrupt("return", cabinetPayload);
|
|
424
438
|
case 2:
|
|
425
439
|
case "end":
|
|
426
|
-
return
|
|
440
|
+
return _context5.stop();
|
|
427
441
|
}
|
|
428
|
-
},
|
|
442
|
+
}, _callee5);
|
|
429
443
|
}));
|
|
430
444
|
return _updateCabinetPayload.apply(this, arguments);
|
|
431
445
|
}
|
|
@@ -526,23 +540,23 @@ export function addItemToCatalog(_x4, _x5, _x6, _x7) {
|
|
|
526
540
|
|
|
527
541
|
// Get attributs of current selected element
|
|
528
542
|
function _addItemToCatalog() {
|
|
529
|
-
_addItemToCatalog = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function
|
|
543
|
+
_addItemToCatalog = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee6(element, state, catalogInstance, projectActions) {
|
|
530
544
|
var _elementJs, _elementJs$structure_, _elementJs$structure_2, _elementJs$structure_3, _elementJs$structure_4, _elementJs3;
|
|
531
545
|
var elementJs, outlineSVGData, _state$getIn, cds, _cds$find, _elementJs2, currentCdsId, cdsIdx, ttph, updatedStructureJson, catalogElements, catalogElementKeys, catalogItem, k, _catalogElements$cata, tempPlaceholderArray, _catalogItem$structur, newTempPlaceholderArray, mergedTempPlaceholder;
|
|
532
|
-
return _regeneratorRuntime.wrap(function (
|
|
533
|
-
while (1) switch (
|
|
546
|
+
return _regeneratorRuntime.wrap(function (_context6) {
|
|
547
|
+
while (1) switch (_context6.prev = _context6.next) {
|
|
534
548
|
case 0:
|
|
535
549
|
if (!isEmpty(element === null || element === void 0 ? void 0 : element.name)) {
|
|
536
|
-
|
|
550
|
+
_context6.next = 1;
|
|
537
551
|
break;
|
|
538
552
|
}
|
|
539
|
-
return
|
|
553
|
+
return _context6.abrupt("return");
|
|
540
554
|
case 1:
|
|
541
555
|
elementJs = populateCCDFList(element); // if (isEmpty(catalog?.elements[element.name])) {
|
|
542
|
-
|
|
556
|
+
_context6.next = 2;
|
|
543
557
|
return loadSVGsByItem(elementJs);
|
|
544
558
|
case 2:
|
|
545
|
-
outlineSVGData =
|
|
559
|
+
outlineSVGData = _context6.sent;
|
|
546
560
|
if (((_elementJs = elementJs) === null || _elementJs === void 0 ? void 0 : _elementJs.type) === 'cabinet') {
|
|
547
561
|
// move the tempPlaceholder of current door style to first of tempPlaceholders array
|
|
548
562
|
cds = (_state$getIn = state.getIn(['scene', 'layers', 'layer-1', 'doorStyle'])) === null || _state$getIn === void 0 ? void 0 : _state$getIn.cds;
|
|
@@ -570,13 +584,13 @@ function _addItemToCatalog() {
|
|
|
570
584
|
}
|
|
571
585
|
});
|
|
572
586
|
if (isEmpty((_elementJs$structure_4 = elementJs.structure_json) === null || _elementJs$structure_4 === void 0 ? void 0 : _elementJs$structure_4.tempPlaceholders)) {
|
|
573
|
-
|
|
587
|
+
_context6.next = 4;
|
|
574
588
|
break;
|
|
575
589
|
}
|
|
576
|
-
|
|
590
|
+
_context6.next = 3;
|
|
577
591
|
return updateCabinetPayload(elementJs);
|
|
578
592
|
case 3:
|
|
579
|
-
elementJs =
|
|
593
|
+
elementJs = _context6.sent;
|
|
580
594
|
case 4:
|
|
581
595
|
elementJs = _objectSpread(_objectSpread({}, elementJs), {}, {
|
|
582
596
|
outlineSVGData: outlineSVGData,
|
|
@@ -593,18 +607,18 @@ function _addItemToCatalog() {
|
|
|
593
607
|
k = 0;
|
|
594
608
|
case 5:
|
|
595
609
|
if (!(k < catalogElementKeys.length)) {
|
|
596
|
-
|
|
610
|
+
_context6.next = 7;
|
|
597
611
|
break;
|
|
598
612
|
}
|
|
599
613
|
if (!(((_catalogElements$cata = catalogElements[catalogElementKeys[k]]) === null || _catalogElements$cata === void 0 ? void 0 : _catalogElements$cata.itemID) === elementJs.itemID)) {
|
|
600
|
-
|
|
614
|
+
_context6.next = 6;
|
|
601
615
|
break;
|
|
602
616
|
}
|
|
603
617
|
catalogItem = catalogElements[catalogElementKeys[k]];
|
|
604
|
-
return
|
|
618
|
+
return _context6.abrupt("continue", 7);
|
|
605
619
|
case 6:
|
|
606
620
|
k++;
|
|
607
|
-
|
|
621
|
+
_context6.next = 5;
|
|
608
622
|
break;
|
|
609
623
|
case 7:
|
|
610
624
|
// get old tempPlaceholder array from catalog item
|
|
@@ -635,9 +649,9 @@ function _addItemToCatalog() {
|
|
|
635
649
|
}
|
|
636
650
|
case 8:
|
|
637
651
|
case "end":
|
|
638
|
-
return
|
|
652
|
+
return _context6.stop();
|
|
639
653
|
}
|
|
640
|
-
},
|
|
654
|
+
}, _callee6);
|
|
641
655
|
}));
|
|
642
656
|
return _addItemToCatalog.apply(this, arguments);
|
|
643
657
|
}
|
|
@@ -1001,11 +1015,11 @@ export function loadMoldingSvg(_x8) {
|
|
|
1001
1015
|
return _loadMoldingSvg.apply(this, arguments);
|
|
1002
1016
|
}
|
|
1003
1017
|
function _loadMoldingSvg() {
|
|
1004
|
-
_loadMoldingSvg = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function
|
|
1005
|
-
return _regeneratorRuntime.wrap(function (
|
|
1006
|
-
while (1) switch (
|
|
1018
|
+
_loadMoldingSvg = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee7(molding) {
|
|
1019
|
+
return _regeneratorRuntime.wrap(function (_context7) {
|
|
1020
|
+
while (1) switch (_context7.prev = _context7.next) {
|
|
1007
1021
|
case 0:
|
|
1008
|
-
return
|
|
1022
|
+
return _context7.abrupt("return", new Promise(function (resolve, reject) {
|
|
1009
1023
|
var url = molding === null || molding === void 0 ? void 0 : molding.shape_svg;
|
|
1010
1024
|
if (!url) {
|
|
1011
1025
|
// Skip if no SVG URL available
|
|
@@ -1027,9 +1041,9 @@ function _loadMoldingSvg() {
|
|
|
1027
1041
|
}));
|
|
1028
1042
|
case 1:
|
|
1029
1043
|
case "end":
|
|
1030
|
-
return
|
|
1044
|
+
return _context7.stop();
|
|
1031
1045
|
}
|
|
1032
|
-
},
|
|
1046
|
+
}, _callee7);
|
|
1033
1047
|
}));
|
|
1034
1048
|
return _loadMoldingSvg.apply(this, arguments);
|
|
1035
1049
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
2
2
|
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
|
+
import { asyncPool } from "../../shared/concurrency/async-pool";
|
|
3
4
|
function prepareMoldingCCDFList(doorStyle, moldingData) {
|
|
4
5
|
var moldingCCDFs = [];
|
|
5
6
|
for (var i = 0; i < moldingData.length; i++) {
|
|
@@ -110,7 +111,7 @@ function _handleChangeDoorStyleEvent() {
|
|
|
110
111
|
function () {
|
|
111
112
|
var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(result) {
|
|
112
113
|
var _result$ccdf_list, _doorStyle$id2, _result$molding_ccdf_;
|
|
113
|
-
var mappedCabinetDefinitionList, rt
|
|
114
|
+
var mappedCabinetDefinitionList, rt;
|
|
114
115
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
115
116
|
while (1) switch (_context.prev = _context.next) {
|
|
116
117
|
case 0:
|
|
@@ -118,27 +119,19 @@ function _handleChangeDoorStyleEvent() {
|
|
|
118
119
|
// because host `cabinet_id` can vary by doorstyle.
|
|
119
120
|
itemCDS = mapFromCCDFToCDS(result === null || result === void 0 ? void 0 : result.ccdf_list, targetItems);
|
|
120
121
|
mappedCabinetDefinitionList = ccdfMapper(result === null || result === void 0 ? void 0 : result.ccdf_list, layer); // result: ccdf_list
|
|
121
|
-
rt = mergeSameElements(mappedCabinetDefinitionList);
|
|
122
|
-
_i = 0;
|
|
123
|
-
case 1:
|
|
124
|
-
if (!(_i < (rt === null || rt === void 0 ? void 0 : rt.length))) {
|
|
125
|
-
_context.next = 3;
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
_context.next = 2;
|
|
129
|
-
return addItemToCatalog(rt[_i], state, props.catalog, props.projectActions);
|
|
130
|
-
case 2:
|
|
131
|
-
_i++;
|
|
122
|
+
rt = mergeSameElements(mappedCabinetDefinitionList); // Load/parse cabinet assets in parallel (but capped to avoid flooding the network/main thread)
|
|
132
123
|
_context.next = 1;
|
|
133
|
-
|
|
134
|
-
|
|
124
|
+
return asyncPool(6, rt !== null && rt !== void 0 ? rt : [], function (element) {
|
|
125
|
+
return addItemToCatalog(element, state, props.catalog, props.projectActions);
|
|
126
|
+
});
|
|
127
|
+
case 1:
|
|
135
128
|
// Persist ccdf on affected instances so SYNC includes the latest ccdf.id for each item.
|
|
136
129
|
// IMPORTANT: host response `ccdf_list[]` may not include `door_finish_id`.
|
|
137
130
|
// Use request door_finish_id (doorStyle.id) as the source of truth for door_finish_id.
|
|
138
131
|
props.itemsActions.setItemsCCDF((_result$ccdf_list = result === null || result === void 0 ? void 0 : result.ccdf_list) !== null && _result$ccdf_list !== void 0 ? _result$ccdf_list : [], applyScope, itemIds, (_doorStyle$id2 = doorStyle === null || doorStyle === void 0 ? void 0 : doorStyle.id) !== null && _doorStyle$id2 !== void 0 ? _doorStyle$id2 : null);
|
|
139
132
|
props.itemsActions.setMoldingsCCDF((_result$molding_ccdf_ = result === null || result === void 0 ? void 0 : result.molding_ccdf_list) !== null && _result$molding_ccdf_ !== void 0 ? _result$molding_ccdf_ : [], applyScope);
|
|
140
133
|
props.itemsActions.setDoorStyle(doorStyle, itemCDS, applyScope, itemIds);
|
|
141
|
-
case
|
|
134
|
+
case 2:
|
|
142
135
|
case "end":
|
|
143
136
|
return _context.stop();
|
|
144
137
|
}
|
|
@@ -6,6 +6,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
6
6
|
import { convert } from "../../utils/convert-units-lite";
|
|
7
7
|
import { INTERNAL_EVENT_ITEMS_CATALOG } from "../../constants";
|
|
8
8
|
import { Scene, State } from "../../models";
|
|
9
|
+
import { asyncPool } from "../../shared/concurrency/async-pool";
|
|
9
10
|
export function handleLoadProjectEvent(_x, _x2, _x3, _x4, _x5, _x6, _x7, _x8) {
|
|
10
11
|
return _handleLoadProjectEvent.apply(this, arguments);
|
|
11
12
|
}
|
|
@@ -59,7 +60,7 @@ function _handleLoadProjectEvent() {
|
|
|
59
60
|
}, /*#__PURE__*/function () {
|
|
60
61
|
var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(result) {
|
|
61
62
|
var _evt$payload2;
|
|
62
|
-
var cdsList, _result$ccdf_list, resp, cabinetDefinitionList, rt
|
|
63
|
+
var cdsList, _result$ccdf_list, resp, cabinetDefinitionList, rt;
|
|
63
64
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
64
65
|
while (1) switch (_context.prev = _context.next) {
|
|
65
66
|
case 0:
|
|
@@ -91,22 +92,14 @@ function _handleLoadProjectEvent() {
|
|
|
91
92
|
// best-effort only
|
|
92
93
|
}
|
|
93
94
|
cabinetDefinitionList = ccdfMapper(result === null || result === void 0 ? void 0 : result.ccdf_list, evt === null || evt === void 0 || (_evt$payload2 = evt.payload) === null || _evt$payload2 === void 0 ? void 0 : _evt$payload2.layers['layer-1']);
|
|
94
|
-
rt = mergeSameElements(cabinetDefinitionList);
|
|
95
|
-
i = 0;
|
|
96
|
-
case 1:
|
|
97
|
-
if (!(i < (rt === null || rt === void 0 ? void 0 : rt.length))) {
|
|
98
|
-
_context.next = 3;
|
|
99
|
-
break;
|
|
100
|
-
}
|
|
101
|
-
_context.next = 2;
|
|
102
|
-
return addItemToCatalog(rt[i], tempState, props.catalog, props.projectActions);
|
|
103
|
-
case 2:
|
|
104
|
-
i++;
|
|
95
|
+
rt = mergeSameElements(cabinetDefinitionList); // Load/parse cabinet assets in parallel (but capped to avoid flooding the network/main thread)
|
|
105
96
|
_context.next = 1;
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
return asyncPool(6, rt !== null && rt !== void 0 ? rt : [], function (element) {
|
|
98
|
+
return addItemToCatalog(element, tempState, props.catalog, props.projectActions);
|
|
99
|
+
});
|
|
100
|
+
case 1:
|
|
108
101
|
props.projectActions.loadProject(evt.payload);
|
|
109
|
-
case
|
|
102
|
+
case 2:
|
|
110
103
|
case "end":
|
|
111
104
|
return _context.stop();
|
|
112
105
|
}
|
|
@@ -4,10 +4,10 @@ import { mapAddItemEvent } from "./mappers/addItemMapper";
|
|
|
4
4
|
import { mapChangeDoorStyleEvent } from "./mappers/changeDoorStyleMapper";
|
|
5
5
|
import { mapLoadProjectEvent } from "./mappers/loadProjectMapper";
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* Main dispatcher for external event payload mapping.
|
|
9
|
-
* Converts new API formats into legacy internal formats (e.g. assets3d -> structure_json)
|
|
10
|
-
* without changing the behavior of the existing 3D tool.
|
|
7
|
+
/**
|
|
8
|
+
* Main dispatcher for external event payload mapping.
|
|
9
|
+
* Converts new API formats into legacy internal formats (e.g. assets3d -> structure_json)
|
|
10
|
+
* without changing the behavior of the existing 3D tool.
|
|
11
11
|
*/
|
|
12
12
|
export function mapExternalEventPayload(evt, state, defaultTextures) {
|
|
13
13
|
if (isEmpty(evt)) return null;
|
|
@@ -5,15 +5,15 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
5
5
|
import { ITEM_TYPE } from "../../../constants";
|
|
6
6
|
import { isEmpty } from "../../../utils/helper";
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* Mapping logic for EXTERNAL_EVENT_ADD_ITEM.
|
|
10
|
-
*
|
|
11
|
-
* Converts the new assets3d payload shape into the legacy structure_json format
|
|
12
|
-
* expected by the existing 3D tool.
|
|
13
|
-
*
|
|
14
|
-
* @param {Object} evt.payload External event payload
|
|
15
|
-
* @param {Immutable.Map} state Planner state
|
|
16
|
-
* @returns {Object|null} Updated event (or null when payload is empty)
|
|
8
|
+
/**
|
|
9
|
+
* Mapping logic for EXTERNAL_EVENT_ADD_ITEM.
|
|
10
|
+
*
|
|
11
|
+
* Converts the new assets3d payload shape into the legacy structure_json format
|
|
12
|
+
* expected by the existing 3D tool.
|
|
13
|
+
*
|
|
14
|
+
* @param {Object} evt.payload External event payload
|
|
15
|
+
* @param {Immutable.Map} state Planner state
|
|
16
|
+
* @returns {Object|null} Updated event (or null when payload is empty)
|
|
17
17
|
*/
|
|
18
18
|
export function mapAddItemEvent(orgEvtPayload, state) {
|
|
19
19
|
var _evtPayload, _evtPayload3;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
1
2
|
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
3
|
+
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; }
|
|
4
|
+
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(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; }
|
|
2
5
|
import { isEmpty } from "../../../components/viewer2d/utils";
|
|
3
6
|
import { toJSIfNeeded } from "../../../shared/objects/immutable";
|
|
4
7
|
export function ccdfMapper(ccdf_list, layer) {
|
|
@@ -26,7 +29,7 @@ export function ccdfMapper(ccdf_list, layer) {
|
|
|
26
29
|
}
|
|
27
30
|
var cd = layerJS.items[correctItemId];
|
|
28
31
|
if (cd && !!(ccdf !== null && ccdf !== void 0 && ccdf.scene_cabinet_id) && (cd === null || cd === void 0 ? void 0 : cd.id) === ccdf.scene_cabinet_id) {
|
|
29
|
-
var _ccdf$cabinet_id, _ccdf$long_name, _ccdf$sizeinfo, _ccdf$shape_svg
|
|
32
|
+
var _ccdf$cabinet_id, _ccdf$long_name, _ccdf$sizeinfo, _ccdf$shape_svg;
|
|
30
33
|
if (!isEmpty(ccdf === null || ccdf === void 0 ? void 0 : ccdf.id)) {
|
|
31
34
|
cdfId = ccdf.id;
|
|
32
35
|
}
|
|
@@ -74,27 +77,18 @@ export function ccdfMapper(ccdf_list, layer) {
|
|
|
74
77
|
tempPlaceholders: tempPlaceholders
|
|
75
78
|
};else structure_json = structure;
|
|
76
79
|
// make cabinet definition using structure_json and catalog
|
|
77
|
-
cabinetDefinition = {
|
|
80
|
+
cabinetDefinition = _objectSpread(_objectSpread({}, cd), {}, {
|
|
78
81
|
type: cd.category,
|
|
79
82
|
itemID: (_ccdf$cabinet_id = ccdf === null || ccdf === void 0 ? void 0 : ccdf.cabinet_id) !== null && _ccdf$cabinet_id !== void 0 ? _ccdf$cabinet_id : cd.itemID,
|
|
80
83
|
// cd.itemID may be legacy from legacy project, so ccdf.cabinet_id is preferred if exists
|
|
81
|
-
name: cd.name,
|
|
82
84
|
long_name: (_ccdf$long_name = ccdf === null || ccdf === void 0 ? void 0 : ccdf.long_name) !== null && _ccdf$long_name !== void 0 ? _ccdf$long_name : cd.long_name,
|
|
83
85
|
sizeinfo: (_ccdf$sizeinfo = ccdf === null || ccdf === void 0 ? void 0 : ccdf.sizeinfo) !== null && _ccdf$sizeinfo !== void 0 ? _ccdf$sizeinfo : cd.sizeinfo,
|
|
84
|
-
description: cd.description,
|
|
85
|
-
prototype: cd.prototype,
|
|
86
|
-
base: cd.base,
|
|
87
|
-
ccdf: cd.ccdf,
|
|
88
86
|
shape_svg: (_ccdf$shape_svg = ccdf === null || ccdf === void 0 ? void 0 : ccdf.shape_svg) !== null && _ccdf$shape_svg !== void 0 ? _ccdf$shape_svg : cd.shape_svg,
|
|
89
87
|
// If host provides cabinet base gltf/bin at CCDF top-level, prefer it.
|
|
90
88
|
gltf: (ccdf === null || ccdf === void 0 ? void 0 : ccdf.gltf) || cd.gltf,
|
|
91
89
|
bin: (ccdf === null || ccdf === void 0 ? void 0 : ccdf.bin) || (cd === null || cd === void 0 ? void 0 : cd.bin),
|
|
92
|
-
structure_json: structure_json
|
|
93
|
-
|
|
94
|
-
is_corner: (_ccdf$is_corner = ccdf === null || ccdf === void 0 ? void 0 : ccdf.is_corner) !== null && _ccdf$is_corner !== void 0 ? _ccdf$is_corner : cd.is_corner,
|
|
95
|
-
obj_property: cd.obj_property,
|
|
96
|
-
outline: cd.outline
|
|
97
|
-
};
|
|
90
|
+
structure_json: structure_json
|
|
91
|
+
});
|
|
98
92
|
}
|
|
99
93
|
// make cabinet definition list using cabinetDefinition
|
|
100
94
|
cabinetDefinitionList.push(cabinetDefinition);
|
package/es/models.js
CHANGED
|
@@ -208,6 +208,7 @@ export var Item = /*#__PURE__*/function (_Record7) {
|
|
|
208
208
|
uri: ''
|
|
209
209
|
},
|
|
210
210
|
molding: [],
|
|
211
|
+
do_not_overwrite_textures: false,
|
|
211
212
|
can_be_mirrored: false,
|
|
212
213
|
mirrored: false,
|
|
213
214
|
isInitialPos: false,
|
|
@@ -358,6 +359,7 @@ export var CatalogElement = /*#__PURE__*/function (_Record1) {
|
|
|
358
359
|
type: '',
|
|
359
360
|
cds: new Map(),
|
|
360
361
|
ccdf_list: new List(),
|
|
362
|
+
do_not_overwrite_textures: false,
|
|
361
363
|
can_be_mirrored: false,
|
|
362
364
|
mirrored: false,
|
|
363
365
|
structure_json: {},
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
2
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
|
+
/**
|
|
4
|
+
* Run async work over a list with a concurrency limit.
|
|
5
|
+
*
|
|
6
|
+
* @template T,R
|
|
7
|
+
* @param {number} limit number of concurrently executing promises
|
|
8
|
+
* @param {T[]} items input items
|
|
9
|
+
* @param {(item: T, index: number) => Promise<R>} iteratorFn async function
|
|
10
|
+
* @returns {Promise<R[]>} results in input order
|
|
11
|
+
*/
|
|
12
|
+
export function asyncPool(_x, _x2, _x3) {
|
|
13
|
+
return _asyncPool.apply(this, arguments);
|
|
14
|
+
}
|
|
15
|
+
function _asyncPool() {
|
|
16
|
+
_asyncPool = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(limit, items, iteratorFn) {
|
|
17
|
+
var safeLimit, ret, executing, _loop, i, _items$length;
|
|
18
|
+
return _regeneratorRuntime.wrap(function (_context2) {
|
|
19
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
20
|
+
case 0:
|
|
21
|
+
safeLimit = Math.max(1, Number(limit) || 1);
|
|
22
|
+
ret = [];
|
|
23
|
+
executing = new Set();
|
|
24
|
+
_loop = /*#__PURE__*/_regeneratorRuntime.mark(function _loop(i) {
|
|
25
|
+
var item, p, cleanup;
|
|
26
|
+
return _regeneratorRuntime.wrap(function (_context) {
|
|
27
|
+
while (1) switch (_context.prev = _context.next) {
|
|
28
|
+
case 0:
|
|
29
|
+
item = items[i];
|
|
30
|
+
p = Promise.resolve().then(function () {
|
|
31
|
+
return iteratorFn(item, i);
|
|
32
|
+
});
|
|
33
|
+
ret.push(p);
|
|
34
|
+
executing.add(p);
|
|
35
|
+
cleanup = function cleanup() {
|
|
36
|
+
return executing["delete"](p);
|
|
37
|
+
};
|
|
38
|
+
p.then(cleanup)["catch"](cleanup);
|
|
39
|
+
if (!(executing.size >= safeLimit)) {
|
|
40
|
+
_context.next = 1;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
_context.next = 1;
|
|
44
|
+
return Promise.race(executing);
|
|
45
|
+
case 1:
|
|
46
|
+
case "end":
|
|
47
|
+
return _context.stop();
|
|
48
|
+
}
|
|
49
|
+
}, _loop);
|
|
50
|
+
});
|
|
51
|
+
i = 0;
|
|
52
|
+
case 1:
|
|
53
|
+
if (!(i < ((_items$length = items === null || items === void 0 ? void 0 : items.length) !== null && _items$length !== void 0 ? _items$length : 0))) {
|
|
54
|
+
_context2.next = 3;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
return _context2.delegateYield(_loop(i), "t0", 2);
|
|
58
|
+
case 2:
|
|
59
|
+
i++;
|
|
60
|
+
_context2.next = 1;
|
|
61
|
+
break;
|
|
62
|
+
case 3:
|
|
63
|
+
return _context2.abrupt("return", Promise.all(ret));
|
|
64
|
+
case 4:
|
|
65
|
+
case "end":
|
|
66
|
+
return _context2.stop();
|
|
67
|
+
}
|
|
68
|
+
}, _callee);
|
|
69
|
+
}));
|
|
70
|
+
return _asyncPool.apply(this, arguments);
|
|
71
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Strip stray dots from the **path portion** of a GLTF/BIN URL.
|
|
3
|
-
* e.g. `…/B36_36x34.5x24.gltf` → `…/B36_36x345x24.gltf`
|
|
4
|
-
*
|
|
5
|
-
* Leaves the protocol/domain and the final file extension untouched.
|
|
1
|
+
/**
|
|
2
|
+
* Strip stray dots from the **path portion** of a GLTF/BIN URL.
|
|
3
|
+
* e.g. `…/B36_36x34.5x24.gltf` → `…/B36_36x345x24.gltf`
|
|
4
|
+
*
|
|
5
|
+
* Leaves the protocol/domain and the final file extension untouched.
|
|
6
6
|
*/
|
|
7
7
|
export var sanitizeAssetUrl = function sanitizeAssetUrl(url) {
|
|
8
8
|
if (!url) return url;
|
|
@@ -8,17 +8,17 @@ function getVertex(vertices, vertexId) {
|
|
|
8
8
|
return typeof vertices.get === 'function' ? vertices.get(vertexId) : vertices[vertexId];
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Computes a line length using its 2 vertices.
|
|
13
|
-
*
|
|
14
|
-
* Assumptions (matches existing DRAG logic):
|
|
15
|
-
* - vertex coordinates are stored in centimeters
|
|
16
|
-
* - result is converted to the provided unit
|
|
17
|
-
*
|
|
18
|
-
* @param {object} line - line object/record with `vertices` (array or immutable List)
|
|
19
|
-
* @param {object} vertices - vertices collection (plain object map or immutable Map)
|
|
20
|
-
* @param {string} unit - target unit (e.g. 'in', 'cm')
|
|
21
|
-
* @returns {number|null}
|
|
11
|
+
/**
|
|
12
|
+
* Computes a line length using its 2 vertices.
|
|
13
|
+
*
|
|
14
|
+
* Assumptions (matches existing DRAG logic):
|
|
15
|
+
* - vertex coordinates are stored in centimeters
|
|
16
|
+
* - result is converted to the provided unit
|
|
17
|
+
*
|
|
18
|
+
* @param {object} line - line object/record with `vertices` (array or immutable List)
|
|
19
|
+
* @param {object} vertices - vertices collection (plain object map or immutable Map)
|
|
20
|
+
* @param {string} unit - target unit (e.g. 'in', 'cm')
|
|
21
|
+
* @returns {number|null}
|
|
22
22
|
*/
|
|
23
23
|
export function getLineLength(line, vertices) {
|
|
24
24
|
var _v0$x, _v1$x, _v0$y, _v1$y;
|