@crystaldesign/web-planner-logic 26.13.0-beta.33 → 26.13.0-beta.35

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 (122) hide show
  1. package/build/cjs/{DivaBoxPlanner-c0b3b67e.js → DivaBoxPlanner-7f6bd584.js} +3 -3
  2. package/build/cjs/{DivaStandardPlanner-cf61c859.js → DivaStandardPlanner-77c603dc.js} +1903 -195
  3. package/build/cjs/{DoorPlanner-dc29d7ab.js → DoorPlanner-5de2bbf0.js} +2 -2
  4. package/build/cjs/{Host3DSignalR-4d97cc14.js → Host3DSignalR-26b95303.js} +2 -2
  5. package/build/cjs/{LiviqueWWSHandler-64ed4664.js → LiviqueWWSHandler-1e419862.js} +2 -2
  6. package/build/cjs/{PfisterWWSHandler-8b3bca3f.js → PfisterWWSHandler-b2f7a5ec.js} +2 -2
  7. package/build/cjs/{PlannerHandler2D-9ff3a275.js → PlannerHandler2D-ff734c3e.js} +10 -10
  8. package/build/cjs/{SeriousBasketHandler-7f4b1074.js → SeriousBasketHandler-e54bd31b.js} +2 -2
  9. package/build/cjs/{ShelfPlanner-6de3f648.js → ShelfPlanner-08e15d16.js} +2 -2
  10. package/build/cjs/{StandardWWSHandler-a0f96b15.js → StandardWWSHandler-0e7b20dc.js} +2 -2
  11. package/build/cjs/{index-3ecaaaa1.js → index-5dd5fb4b.js} +4711 -794
  12. package/build/cjs/index.js +3 -3
  13. package/build/esm/{DivaBoxPlanner-8ccf387b.js → DivaBoxPlanner-6ac448b4.js} +3 -3
  14. package/build/esm/{DivaStandardPlanner-9ff3f239.js → DivaStandardPlanner-abd9609d.js} +1893 -186
  15. package/build/esm/{DoorPlanner-ad29d046.js → DoorPlanner-fde32e61.js} +2 -2
  16. package/build/esm/{Host3DSignalR-f4450ab3.js → Host3DSignalR-0f97c7f3.js} +2 -2
  17. package/build/esm/{LiviqueWWSHandler-6b0cefa0.js → LiviqueWWSHandler-9ee5b7cb.js} +2 -2
  18. package/build/esm/{PfisterWWSHandler-da0842f9.js → PfisterWWSHandler-b9699549.js} +2 -2
  19. package/build/esm/{PlannerHandler2D-15825d64.js → PlannerHandler2D-8d963e77.js} +2 -2
  20. package/build/esm/{SeriousBasketHandler-93cadbac.js → SeriousBasketHandler-40e7e46c.js} +2 -2
  21. package/build/esm/{ShelfPlanner-967358c5.js → ShelfPlanner-69cbb2c1.js} +2 -2
  22. package/build/esm/{StandardWWSHandler-2fd953d1.js → StandardWWSHandler-dbf02663.js} +2 -2
  23. package/build/esm/{index-62a23464.js → index-88148ccc.js} +4673 -787
  24. package/build/esm/index.js +2 -2
  25. package/build/types/web-planner-logic/src/index.d.ts +1 -0
  26. package/build/types/web-planner-logic/src/index.d.ts.map +1 -1
  27. package/build/types/web-planner-logic/src/interface/Articles/CatalogArticleDataType.d.ts +13 -0
  28. package/build/types/web-planner-logic/src/interface/Articles/CatalogArticleDataType.d.ts.map +1 -1
  29. package/build/types/web-planner-logic/src/interface/DivaCatalogDataType.d.ts +3 -0
  30. package/build/types/web-planner-logic/src/interface/DivaCatalogDataType.d.ts.map +1 -1
  31. package/build/types/web-planner-logic/src/interface/FunctionTypes/index.d.ts +15 -1
  32. package/build/types/web-planner-logic/src/interface/FunctionTypes/index.d.ts.map +1 -1
  33. package/build/types/web-planner-logic/src/interface/Planner/ISaveSetPlanner.d.ts +10 -0
  34. package/build/types/web-planner-logic/src/interface/Planner/ISaveSetPlanner.d.ts.map +1 -1
  35. package/build/types/web-planner-logic/src/interface/Planner/RoomSceneTypes.d.ts +76 -0
  36. package/build/types/web-planner-logic/src/interface/Planner/RoomSceneTypes.d.ts.map +1 -0
  37. package/build/types/web-planner-logic/src/interface/webPlannerParams/WebPlannerParamsType.d.ts +1 -1
  38. package/build/types/web-planner-logic/src/interface/webPlannerParams/WebPlannerParamsType.d.ts.map +1 -1
  39. package/build/types/web-planner-logic/src/logic/DivaWebPlanner.d.ts +34 -8
  40. package/build/types/web-planner-logic/src/logic/DivaWebPlanner.d.ts.map +1 -1
  41. package/build/types/web-planner-logic/src/logic/Planner/DivaPlannerHandler.d.ts +67 -7
  42. package/build/types/web-planner-logic/src/logic/Planner/DivaPlannerHandler.d.ts.map +1 -1
  43. package/build/types/web-planner-logic/src/logic/Planner/DivaStandardPlanner.d.ts +175 -4
  44. package/build/types/web-planner-logic/src/logic/Planner/DivaStandardPlanner.d.ts.map +1 -1
  45. package/build/types/web-planner-logic/src/logic/Planner/Placement/carrierGuests.d.ts +75 -0
  46. package/build/types/web-planner-logic/src/logic/Planner/Placement/carrierGuests.d.ts.map +1 -0
  47. package/build/types/web-planner-logic/src/logic/Planner/Placement/guestPlacement.d.ts +47 -0
  48. package/build/types/web-planner-logic/src/logic/Planner/Placement/guestPlacement.d.ts.map +1 -0
  49. package/build/types/web-planner-logic/src/logic/Planner/Placement/guestPlacement.test.d.ts +2 -0
  50. package/build/types/web-planner-logic/src/logic/Planner/Placement/guestPlacement.test.d.ts.map +1 -0
  51. package/build/types/web-planner-logic/src/logic/Planner/Placement/placementDefaults.d.ts +9 -0
  52. package/build/types/web-planner-logic/src/logic/Planner/Placement/placementDefaults.d.ts.map +1 -0
  53. package/build/types/web-planner-logic/src/logic/Planner/Placement/placementRules.d.ts +78 -0
  54. package/build/types/web-planner-logic/src/logic/Planner/Placement/placementRules.d.ts.map +1 -0
  55. package/build/types/web-planner-logic/src/logic/Planner/Placement/placementRules.test.d.ts +2 -0
  56. package/build/types/web-planner-logic/src/logic/Planner/Placement/placementRules.test.d.ts.map +1 -0
  57. package/build/types/web-planner-logic/src/logic/Planner/Placement/placementSlots.d.ts +81 -0
  58. package/build/types/web-planner-logic/src/logic/Planner/Placement/placementSlots.d.ts.map +1 -0
  59. package/build/types/web-planner-logic/src/logic/Planner/Placement/placementTypes.d.ts +13 -0
  60. package/build/types/web-planner-logic/src/logic/Planner/Placement/placementTypes.d.ts.map +1 -0
  61. package/build/types/web-planner-logic/src/logic/Planner/PlannerUtils/DockingPointHandler.d.ts +1 -1
  62. package/build/types/web-planner-logic/src/logic/Planner/PlannerUtils/DockingPointHandler.d.ts.map +1 -1
  63. package/build/types/web-planner-logic/src/logic/Planner/PlannerUtils/SVGUtils.d.ts +1 -1
  64. package/build/types/web-planner-logic/src/logic/Planner/Room/elementShapes.d.ts +56 -0
  65. package/build/types/web-planner-logic/src/logic/Planner/Room/elementShapes.d.ts.map +1 -0
  66. package/build/types/web-planner-logic/src/logic/Planner/Room/elementShapes.test.d.ts +2 -0
  67. package/build/types/web-planner-logic/src/logic/Planner/Room/elementShapes.test.d.ts.map +1 -0
  68. package/build/types/web-planner-logic/src/logic/Planner/Room/roomCollisions.d.ts +90 -0
  69. package/build/types/web-planner-logic/src/logic/Planner/Room/roomCollisions.d.ts.map +1 -0
  70. package/build/types/web-planner-logic/src/logic/Planner/Room/roomCollisions.test.d.ts +2 -0
  71. package/build/types/web-planner-logic/src/logic/Planner/Room/roomCollisions.test.d.ts.map +1 -0
  72. package/build/types/web-planner-logic/src/logic/Planner/Room/roomGroups.d.ts +32 -0
  73. package/build/types/web-planner-logic/src/logic/Planner/Room/roomGroups.d.ts.map +1 -0
  74. package/build/types/web-planner-logic/src/logic/Planner/Room/roomGroups.test.d.ts +2 -0
  75. package/build/types/web-planner-logic/src/logic/Planner/Room/roomGroups.test.d.ts.map +1 -0
  76. package/build/types/web-planner-logic/src/logic/Planner/Room/roomProperties.test.d.ts +2 -0
  77. package/build/types/web-planner-logic/src/logic/Planner/Room/roomProperties.test.d.ts.map +1 -0
  78. package/build/types/web-planner-logic/src/logic/Planner/Room/roomScenes.d.ts +21 -0
  79. package/build/types/web-planner-logic/src/logic/Planner/Room/roomScenes.d.ts.map +1 -0
  80. package/build/types/web-planner-logic/src/logic/Planner/Room/roomScenes.test.d.ts +2 -0
  81. package/build/types/web-planner-logic/src/logic/Planner/Room/roomScenes.test.d.ts.map +1 -0
  82. package/build/types/web-planner-logic/src/logic/Planner/Room/roomValidation.d.ts +13 -0
  83. package/build/types/web-planner-logic/src/logic/Planner/Room/roomValidation.d.ts.map +1 -0
  84. package/build/types/web-planner-logic/src/logic/Planner/Room/roomValidation.test.d.ts +2 -0
  85. package/build/types/web-planner-logic/src/logic/Planner/Room/roomValidation.test.d.ts.map +1 -0
  86. package/build/types/web-planner-logic/src/logic/Planner/Room/rtvFeatures.d.ts.map +1 -1
  87. package/build/types/web-planner-logic/src/logic/Planner/Room/wallBinding.d.ts +72 -0
  88. package/build/types/web-planner-logic/src/logic/Planner/Room/wallBinding.d.ts.map +1 -0
  89. package/build/types/web-planner-logic/src/logic/Planner/Room/wallBinding.test.d.ts +2 -0
  90. package/build/types/web-planner-logic/src/logic/Planner/Room/wallBinding.test.d.ts.map +1 -0
  91. package/build/types/web-planner-logic/src/logic/Planner/Room/wallMode.d.ts +7 -0
  92. package/build/types/web-planner-logic/src/logic/Planner/Room/wallMode.d.ts.map +1 -0
  93. package/build/types/web-planner-logic/src/logic/Set/DivaSetHandler.d.ts.map +1 -1
  94. package/build/types/web-planner-logic/src/model/Articles/Article/CatalogArticleData.d.ts +4 -0
  95. package/build/types/web-planner-logic/src/model/Articles/Article/CatalogArticleData.d.ts.map +1 -1
  96. package/build/types/web-planner-logic/src/model/Catalog/CatalogData.d.ts +24 -0
  97. package/build/types/web-planner-logic/src/model/Catalog/CatalogData.d.ts.map +1 -1
  98. package/build/types/web-planner-logic/src/model/Catalog/IDMCatalogData.d.ts.map +1 -1
  99. package/build/types/web-planner-logic/src/model/Planner/DockingPoint.d.ts +1 -1
  100. package/build/types/web-planner-logic/src/model/Planner/DockingPoint.d.ts.map +1 -1
  101. package/build/types/web-planner-logic/src/model/Planner/PlannerElementData.d.ts +29 -0
  102. package/build/types/web-planner-logic/src/model/Planner/PlannerElementData.d.ts.map +1 -1
  103. package/build/types/web-planner-logic/src/model/Properties/propertySchemaRegistry.d.ts.map +1 -1
  104. package/build/types/web-planner-logic/src/test/carrierGuests.test.d.ts +2 -0
  105. package/build/types/web-planner-logic/src/test/carrierGuests.test.d.ts.map +1 -0
  106. package/build/types/web-planner-logic/src/test/dragZones.test.d.ts +2 -0
  107. package/build/types/web-planner-logic/src/test/dragZones.test.d.ts.map +1 -0
  108. package/build/types/web-planner-logic/src/test/headlessRoomScenes.test.d.ts +2 -0
  109. package/build/types/web-planner-logic/src/test/headlessRoomScenes.test.d.ts.map +1 -0
  110. package/build/types/web-planner-logic/src/test/oltRectBody.test.d.ts +2 -0
  111. package/build/types/web-planner-logic/src/test/oltRectBody.test.d.ts.map +1 -0
  112. package/build/types/web-planner-logic/src/test/plannerRoomScenesSwitch.test.d.ts +2 -0
  113. package/build/types/web-planner-logic/src/test/plannerRoomScenesSwitch.test.d.ts.map +1 -0
  114. package/build/types/web-planner-logic/src/test/planningRoundTrip.test.d.ts +2 -0
  115. package/build/types/web-planner-logic/src/test/planningRoundTrip.test.d.ts.map +1 -0
  116. package/build/types/web-planner-logic/src/test/roomDragContact.test.d.ts +2 -0
  117. package/build/types/web-planner-logic/src/test/roomDragContact.test.d.ts.map +1 -0
  118. package/build/types/web-planner-logic/src/test/roomPlacement.test.d.ts +2 -0
  119. package/build/types/web-planner-logic/src/test/roomPlacement.test.d.ts.map +1 -0
  120. package/build/types/web-planner-logic/src/test/roomScenePlanning.test.d.ts +2 -0
  121. package/build/types/web-planner-logic/src/test/roomScenePlanning.test.d.ts.map +1 -0
  122. package/package.json +3 -3
@@ -1,16 +1,16 @@
1
1
  'use strict';
2
2
 
3
- var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
4
3
  var _asyncToGenerator = require('@babel/runtime/helpers/asyncToGenerator');
4
+ var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
5
5
  var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
6
6
  var _createClass = require('@babel/runtime/helpers/createClass');
7
7
  var _defineProperty = require('@babel/runtime/helpers/defineProperty');
8
+ var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
8
9
  var _regeneratorRuntime = require('@babel/runtime/regenerator');
9
- var index = require('./index-3ecaaaa1.js');
10
+ var index = require('./index-5dd5fb4b.js');
10
11
  var DivaUtils = require('@crystaldesign/diva-utils');
11
- var planner2dCore = require('@crystaldesign/planner-2d-core');
12
- var PlannerHandler2D = require('./PlannerHandler2D-9ff3a275.js');
13
- require('@babel/runtime/helpers/slicedToArray');
12
+ var plannerCore = require('@crystaldesign/planner-core');
13
+ var PlannerHandler2D = require('./PlannerHandler2D-ff734c3e.js');
14
14
  require('@babel/runtime/helpers/objectWithoutProperties');
15
15
  require('axios');
16
16
  require('@babel/runtime/helpers/typeof');
@@ -27,36 +27,85 @@ require('@babel/runtime/helpers/get');
27
27
 
28
28
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
29
29
 
30
- var _toConsumableArray__default = /*#__PURE__*/_interopDefaultLegacy(_toConsumableArray);
31
30
  var _asyncToGenerator__default = /*#__PURE__*/_interopDefaultLegacy(_asyncToGenerator);
31
+ var _toConsumableArray__default = /*#__PURE__*/_interopDefaultLegacy(_toConsumableArray);
32
32
  var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck);
33
33
  var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass);
34
34
  var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty);
35
+ var _slicedToArray__default = /*#__PURE__*/_interopDefaultLegacy(_slicedToArray);
35
36
  var _regeneratorRuntime__default = /*#__PURE__*/_interopDefaultLegacy(_regeneratorRuntime);
36
37
  var DivaUtils__default = /*#__PURE__*/_interopDefaultLegacy(DivaUtils);
37
38
 
38
- /** Configurator 2.0 set planner payload (`SetPlanData` after base64 decode). */
39
-
40
- /** Legacy planner 1.x payload (no `v: 2` wrapper). */
41
-
42
- function parseSetPlanData(setPlanData) {
43
- var planDataString = DivaUtils__default["default"].decodeBase64(setPlanData);
44
- return JSON.parse(planDataString);
45
- }
46
- function isSavePlannerV2(planData) {
47
- return planData.v === 2;
48
- }
49
-
50
- /** Article codex from a V2 or legacy element record. */
51
- function saveElementArticleCodex(element) {
52
- return element.articleCodex || element.Codex;
53
- }
54
-
55
39
  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; } } }; }
56
40
  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; } }
57
41
  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; }
42
+ 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; }
43
+ 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; }
58
44
  var LOG = DivaUtils__default["default"].initLog('Planner', 'WEB-PLANNER-LOGIC');
59
45
  var ACC_DOCK_TYPES = ['AVO', 'AVU', 'AVC', 'AVS', 'AVN'];
46
+
47
+ /** An element of the set as a drag checks it: its shape, and its layer for the catalog's layer rule. */
48
+
49
+ /**
50
+ * Something a dragged group may not run into: an element of another docking group of this set or of another set (its id,
51
+ * its layer where the catalog's layer rule applies; of another set its set and that set's rules), or a door's clearance,
52
+ * its swing or doorway (none).
53
+ */
54
+
55
+ /** A pose on the floor moved rigidly from `from` to `to`, as the points it carries (see `movePoints`). */
56
+ function movePose(pose, from, to) {
57
+ var _movePoints = index.movePoints([new index.Vector2(pose.center.x, pose.center.z)], from, to),
58
+ _movePoints2 = _slicedToArray__default["default"](_movePoints, 1),
59
+ center = _movePoints2[0];
60
+ return {
61
+ center: {
62
+ x: center.x,
63
+ z: center.y
64
+ },
65
+ rotDeg: pose.rotDeg + to.rotDeg - from.rotDeg
66
+ };
67
+ }
68
+
69
+ /** How close (cm) a 'snap' group's wall pose has to be to the dragged position for it to dock to the wall. */
70
+ var WALL_SNAP_DISTANCE = 30;
71
+ /** The free-pose search around a group that landed on another: ring spacing (cm) and directions per ring. */
72
+ var CLEAR_SEARCH_STEP = 10;
73
+ var CLEAR_SEARCH_DIRECTIONS = 16;
74
+ /** cm a blocked turn's release looks around for a free place at least (farther where the group's longer side is longer). */
75
+ var TURN_PLACE_REACH = 100;
76
+ /** cm the room rule may move a suggested place before it no longer counts as that place. */
77
+ var PLACE_TOLERANCE = 1;
78
+ /** cm the room rule may move a pose a guest snaps to off its place (the float noise of moved outlines). */
79
+ var ROOM_RULE_NOISE = 0.01;
80
+ /** cm between the poses a drag checks on its way: less than the thinnest part (a table leg), so nothing is jumped. */
81
+ var PATH_STEP = 2;
82
+ /** cm a pair that overlapped at the start may vary in depth while it moves along (the float noise of moved outlines). */
83
+ var DEPTH_NOISE = 1e-6;
84
+ /** cm within which a dragged guest snaps into a free place of a slot that takes it. */
85
+ var SLOT_SNAP_DISTANCE = 20;
86
+ /** cm within which a drag counts as back at its start (the float noise of the summed moves). */
87
+ var START_NOISE = 1e-6;
88
+ var toFloorRect = function toFloorRect(block, pose) {
89
+ return {
90
+ center: pose.center,
91
+ halfWidth: block.halfWidth,
92
+ halfDepth: block.halfDepth,
93
+ rotDeg: pose.rotDeg
94
+ };
95
+ };
96
+
97
+ /** The article codex the room rules read: a main element's; none for an accessory. */
98
+ var mainCodex = function mainCodex(member) {
99
+ return member.IsAccessoire ? '' : member.ArticleCodex;
100
+ };
101
+
102
+ /** `pose` moved back inside the room, its rotation kept. */
103
+ var insidePose = function insidePose(block, pose, room) {
104
+ return {
105
+ center: index.keepInsideRoom(toFloorRect(block, pose), room),
106
+ rotDeg: pose.rotDeg
107
+ };
108
+ };
60
109
  var DivaStandardPlanner = /*#__PURE__*/function () {
61
110
  /*
62
111
  This function updates te planner data of all Elements if they changed.
@@ -68,7 +117,13 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
68
117
 
69
118
  function DivaStandardPlanner(set, updatePlannerMsgContainer, plannerId, globalBoundingBox, doDisablePlanner2D, plannerHasStaticBackground) {
70
119
  var _this = this;
120
+ var getOtherCollisionSets = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : function () {
121
+ return [];
122
+ };
123
+ var findCarrier = arguments.length > 7 ? arguments[7] : undefined;
71
124
  _classCallCheck__default["default"](this, DivaStandardPlanner);
125
+ this.getOtherCollisionSets = getOtherCollisionSets;
126
+ this.findCarrier = findCarrier;
72
127
  _defineProperty__default["default"](this, "plannerID", void 0);
73
128
  _defineProperty__default["default"](this, "set", void 0);
74
129
  _defineProperty__default["default"](this, "plannerBoundingBox", void 0);
@@ -82,6 +137,16 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
82
137
  _defineProperty__default["default"](this, "IDM3DCatCodex", '');
83
138
  _defineProperty__default["default"](this, "IDM3DEnvironment", 'diva.ro');
84
139
  _defineProperty__default["default"](this, "nextElementId", 1);
140
+ _defineProperty__default["default"](this, "room", void 0);
141
+ _defineProperty__default["default"](this, "roomDrag", void 0);
142
+ /** Elements whose group a room rule placed (insert, resize, drag, scene switch, …): a measurement re-binds them. */
143
+ _defineProperty__default["default"](this, "roomPlaced", new WeakSet());
144
+ /** The elements the current drag moves (ids): the grabbed one, those the viewer moves with it, a room drag's group, their guests. */
145
+ _defineProperty__default["default"](this, "dragUnit", void 0);
146
+ /** Of the current drag's elements, the guests it carries along (ids, see `getFollowers`). */
147
+ _defineProperty__default["default"](this, "dragFollowers", new Set());
148
+ /** The free slot places the grabbed element may snap into (see `findSlotSnap`), found when the drag starts where it stood. */
149
+ _defineProperty__default["default"](this, "dragSlots", void 0);
85
150
  _defineProperty__default["default"](this, "collisionHandler", void 0);
86
151
  _defineProperty__default["default"](this, "dockToAVUorAVOororAVNorAVSorAVC", function (plannerElement, targetElements) {
87
152
  // Capability comes from the SVG-parsed docking points, not the catalog metadata counts
@@ -179,6 +244,18 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
179
244
  if (!this.getCatalogData().dontSetPosNrFromPlanner) startChainElements = startChainElements.sort(function (a, b) {
180
245
  return a.WorldPosCenter.x - b.WorldPosCenter.x;
181
246
  });
247
+ // Elements put into a carrier's slot come after the chains, by the numbers they have; a new one last.
248
+ var keptPosNr = function keptPosNr(element) {
249
+ return element.PosNr > 0 ? element.PosNr : Infinity;
250
+ };
251
+ var atEnd = startChainElements.filter(function (element) {
252
+ return element.PosNrAtEnd;
253
+ }).sort(function (a, b) {
254
+ return keptPosNr(a) - keptPosNr(b);
255
+ });
256
+ startChainElements = [].concat(_toConsumableArray__default["default"](startChainElements.filter(function (element) {
257
+ return !element.PosNrAtEnd;
258
+ })), _toConsumableArray__default["default"](atEnd));
182
259
  var posNrAcc;
183
260
  var _updateAccessoiresOfElement = function updateAccessoiresOfElement(curElement, posNrParent) {
184
261
  //Nun habe ich ein Element und muss überprüfen, ob es Accessoires hat. Das sind Elemente, die über AVO, AVU oder AVC gedockt sind.
@@ -278,7 +355,7 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
278
355
  }, {
279
356
  key: "applyDockTransform",
280
357
  value: function applyDockTransform(plannerElement, refElement, dockingPoint, refDockingPoint) {
281
- var dockedTransform = planner2dCore.computeDockedTransform(refElement, refDockingPoint, plannerElement, dockingPoint);
358
+ var dockedTransform = plannerCore.computeDockedTransform(refElement, refDockingPoint, plannerElement, dockingPoint);
282
359
  plannerElement.RotDeg = dockedTransform.rotDeg;
283
360
  plannerElement.WorldPosCorner = new index.Vector3(dockedTransform.worldPosCorner.x, dockedTransform.worldPosCorner.y, dockedTransform.worldPosCorner.z);
284
361
  plannerElement.WorldPosCornerIgnoreOLF = new index.Vector3(dockedTransform.worldPosCornerIgnoreOLF.x, dockedTransform.worldPosCornerIgnoreOLF.y, dockedTransform.worldPosCornerIgnoreOLF.z);
@@ -290,16 +367,217 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
290
367
  * {@link applyDockTransform} (apply → read → restore, no docking relations touched). Returns the
291
368
  * delta from the element's current transform (cm / deg), or null if nothing is in snapping range.
292
369
  * `excludeElementIds` skips the element's own move-group so it doesn't "snap" to siblings that
293
- * are translating with it.
370
+ * are translating with it. In a room drag it is the room pose instead, with what blocks it at contact.
294
371
  */
295
372
  }, {
296
373
  key: "getDockSnapPreview",
297
374
  value: function getDockSnapPreview(elementId, autoDockingDistance) {
375
+ var _this$roomDrag, _this$findDockSnap;
298
376
  var excludeElementIds = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
299
377
  var element = this.plannerElements.get(elementId);
300
378
  if (!element) return null;
379
+ // A room drag that turned into a rotation moves the normal way: its preview only names what the turned group runs into.
380
+ if (this.room && ((_this$roomDrag = this.roomDrag) === null || _this$roomDrag === void 0 ? void 0 : _this$roomDrag.elementId) === elementId) {
381
+ return this.roomDrag.rotating ? this.getRoomTurnPreview(element, this.roomDrag) : this.getRoomDragPreview(element, this.roomDrag);
382
+ }
383
+ return (_this$findDockSnap = this.findDockSnap(element, autoDockingDistance, [].concat(_toConsumableArray__default["default"](excludeElementIds), _toConsumableArray__default["default"](this.dragFollowers)))) !== null && _this$findDockSnap !== void 0 ? _this$findDockSnap : this.findSlotSnap(element);
384
+ }
385
+
386
+ /**
387
+ * The move (cm / deg, about the element's centre) into the nearest free slot place found when its drag started (see
388
+ * `findDragSlotPlaces`), within SLOT_SNAP_DISTANCE: lined up and turned as the place says, at its own distance to the
389
+ * carrier as far as the slot's band allows. Null when no place is that near, the element is not the one dragged or it
390
+ * is back where the drag started (a cancel ends there exactly).
391
+ */
392
+ }, {
393
+ key: "findSlotSnap",
394
+ value: function findSlotSnap(element) {
395
+ var _this$dragSlots;
396
+ var slots = ((_this$dragSlots = this.dragSlots) === null || _this$dragSlots === void 0 ? void 0 : _this$dragSlots.elementId) === element.ElementId ? this.dragSlots : undefined;
397
+ var _poseOf = index.poseOf(element),
398
+ center = _poseOf.center;
399
+ var places = slots && Math.hypot(center.x - slots.start.x, center.z - slots.start.z) > START_NOISE ? slots.places : [];
400
+ var nearest = index.getSnapPlace(places, center, SLOT_SNAP_DISTANCE);
401
+ if (!nearest) return null;
402
+ return {
403
+ dx: nearest.center.x - center.x,
404
+ dz: nearest.center.z - center.z,
405
+ dRotDeg: index.getTurnDeg(element.RotDeg, places[nearest.index].rotDeg)
406
+ };
407
+ }
408
+
409
+ // The group's pose where the grabbed element snaps into a free slot place (see findSlotSnap) from where the pointer has
410
+ // it in a room drag; undefined when no place is near.
411
+ }, {
412
+ key: "getSlotSnapPose",
413
+ value: function getSlotSnapPose(drag) {
414
+ var _this$dragSlots2;
415
+ var places = ((_this$dragSlots2 = this.dragSlots) === null || _this$dragSlots2 === void 0 ? void 0 : _this$dragSlots2.elementId) === drag.elementId ? this.dragSlots.places : [];
416
+ if (places.length === 0) return undefined;
417
+ var raw = {
418
+ center: {
419
+ x: drag.grabbedStart.x + drag.dx,
420
+ z: drag.grabbedStart.z + drag.dz
421
+ },
422
+ rotDeg: drag.grabbedStartRotDeg
423
+ };
424
+ var nearest = index.getSnapPlace(places, raw.center, SLOT_SNAP_DISTANCE);
425
+ if (!nearest) return undefined;
426
+ var block = {
427
+ center: {
428
+ x: drag.start.center.x + drag.dx,
429
+ z: drag.start.center.z + drag.dz
430
+ },
431
+ rotDeg: drag.start.rotDeg
432
+ };
433
+ return movePose(block, raw, {
434
+ center: nearest.center,
435
+ rotDeg: places[nearest.index].rotDeg
436
+ });
437
+ }
438
+
439
+ /**
440
+ * The free places of the slots that take the grabbed element, at carriers outside the dragged unit in this and the
441
+ * other sets, for a unit of one main element; free where the element stands clear of every body and zone there (its
442
+ * carrier's zone and a slot's reach under its carrier allowed). Found once when the drag starts.
443
+ */
444
+ }, {
445
+ key: "findDragSlotPlaces",
446
+ value: function findDragSlotPlaces(element, unit) {
447
+ var _this3 = this;
448
+ var _ref = element.IsAccessoire ? [] : this.getPlacementTypes(element),
449
+ _ref2 = _slicedToArray__default["default"](_ref, 1),
450
+ type = _ref2[0];
451
+ var group = this.getDockingGroupOf(element);
452
+ if (!type || group.filter(function (member) {
453
+ return !member.IsAccessoire;
454
+ }).length !== 1) return [];
455
+ var otherSets = this.getOtherCollisionSets(group.map(function (member) {
456
+ return member.ElementId;
457
+ }));
458
+ var own = index.getDockingGroups(this.getAllPlannerElements().filter(function (other) {
459
+ return !unit.includes(other);
460
+ })).filter(function (carrier) {
461
+ return carrier.some(function (member) {
462
+ return !member.IsAccessoire;
463
+ });
464
+ }).map(function (carrier) {
465
+ return {
466
+ rules: _this3.getCatalogData().placementOptions.rules,
467
+ members: _this3.getSlotMembers(carrier)
468
+ };
469
+ });
470
+ var others = otherSets.flatMap(function (set) {
471
+ return _toConsumableArray__default["default"](new Set(set.parts.map(function (part) {
472
+ return part.group;
473
+ }))).map(function (members) {
474
+ return {
475
+ rules: set.rules,
476
+ members: members
477
+ };
478
+ });
479
+ });
480
+ var body = index.getElementShape(element, false).body[0];
481
+ var pose = index.poseOf(element);
482
+ var outline = function outline(rotDeg) {
483
+ return index.movePoints(body, pose, {
484
+ center: {
485
+ x: 0,
486
+ z: 0
487
+ },
488
+ rotDeg: rotDeg
489
+ });
490
+ };
491
+ var drag = this.room ? this.createRoomDrag(element.ElementId, false, otherSets) : undefined;
492
+ return [].concat(_toConsumableArray__default["default"](own), _toConsumableArray__default["default"](others)).flatMap(function (_ref3) {
493
+ var rules = _ref3.rules,
494
+ members = _ref3.members;
495
+ return index.getCarrierSlots(rules, members, type);
496
+ }).flatMap(function (slot) {
497
+ return index.getSlotPlaces(slot, outline);
498
+ }).filter(function (place) {
499
+ return _this3.placeIsFree(element, group, place, otherSets);
500
+ }).map(function (place) {
501
+ return drag ? _this3.cutBandToRoom(drag, place) : place;
502
+ });
503
+ }
504
+
505
+ // The free place with its band cut to the offsets at which the room rule leaves the dragged group where it is: a guest
506
+ // never snaps where the rule would move it.
507
+ }, {
508
+ key: "cutBandToRoom",
509
+ value: function cutBandToRoom(drag, place) {
510
+ var _this4 = this;
511
+ var grabbed = {
512
+ center: drag.grabbedStart,
513
+ rotDeg: drag.grabbedStartRotDeg
514
+ };
515
+ var kept = function kept(offset) {
516
+ var center = {
517
+ x: place.center.x + place.normal.x * offset,
518
+ z: place.center.z + place.normal.z * offset
519
+ };
520
+ return !!_this4.getKeptPose(drag, movePose(drag.start, grabbed, {
521
+ center: center,
522
+ rotDeg: place.rotDeg
523
+ }), ROOM_RULE_NOISE);
524
+ };
525
+ var cut = function cut(end) {
526
+ if (kept(end)) return end;
527
+ var free = 0;
528
+ var blocked = end;
529
+ for (var i = 0; i < 12; i++) {
530
+ var mid = (free + blocked) / 2;
531
+ if (kept(mid)) free = mid;else blocked = mid;
532
+ }
533
+ return free;
534
+ };
535
+ return _objectSpread(_objectSpread({}, place), {}, {
536
+ band: [cut(place.band[0]), cut(place.band[1])]
537
+ });
538
+ }
539
+
540
+ // Whether the element's group, moved so the element stands at `place`, stands there by the room rule and collides with
541
+ // nothing (see fitsAt); it is put back where it stood.
542
+ }, {
543
+ key: "placeIsFree",
544
+ value: function placeIsFree(element, group, place, otherSets) {
545
+ var saved = group.map(function (member) {
546
+ return {
547
+ member: member,
548
+ center: member.WorldPosCenter,
549
+ rotDeg: member.RotDeg
550
+ };
551
+ });
552
+ index.moveGroupRigidly(group, index.poseOf(element), place);
553
+ var drag = this.createRoomDrag(element.ElementId, false, otherSets);
554
+ var free = !!drag && !!this.getKeptPose(drag) && !this.isBlocked(drag, drag.start);
555
+ var _iterator = _createForOfIteratorHelper(saved),
556
+ _step;
557
+ try {
558
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
559
+ var _step$value = _step.value,
560
+ member = _step$value.member,
561
+ center = _step$value.center,
562
+ rotDeg = _step$value.rotDeg;
563
+ member.WorldPosCenter = center;
564
+ member.RotDeg = rotDeg;
565
+ }
566
+ } catch (err) {
567
+ _iterator.e(err);
568
+ } finally {
569
+ _iterator.f();
570
+ }
571
+ return free;
572
+ }
573
+
574
+ // The move (cm / deg, about the element's centre) onto the element's nearest dock within `autoDockingDistance`, to an
575
+ // element not in `excludeElementIds`; null when none is in range. Nothing changes.
576
+ }, {
577
+ key: "findDockSnap",
578
+ value: function findDockSnap(element, autoDockingDistance, excludeElementIds) {
301
579
  var targets = this.getAllPlannerElements().filter(function (e) {
302
- return e.getElementId() !== elementId && !excludeElementIds.includes(e.getElementId());
580
+ return e !== element && !excludeElementIds.includes(e.getElementId());
303
581
  });
304
582
  var pairs = PlannerHandler2D.dockingPointHandlerInst.searchDockableElementsInArea(element, targets, autoDockingDistance);
305
583
  if (!pairs || pairs.size === 0) return null;
@@ -328,6 +606,1273 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
328
606
  return result;
329
607
  }
330
608
 
609
+ /**
610
+ * The rigid move from where the planner holds a dragged element's group to where a viewer shows it with `preview` (see
611
+ * {@link getDockSnapPreview}): none in a room drag, which holds the group where it shows; else the dock snap, turning
612
+ * about the element's centre.
613
+ */
614
+ }, {
615
+ key: "getPreviewMove",
616
+ value: function getPreviewMove(elementId, preview) {
617
+ var _this$roomDrag2;
618
+ var element = this.plannerElements.get(elementId);
619
+ if (!element || !preview || this.room && ((_this$roomDrag2 = this.roomDrag) === null || _this$roomDrag2 === void 0 ? void 0 : _this$roomDrag2.elementId) === elementId) return undefined;
620
+ return this.snapMove(element, preview);
621
+ }
622
+
623
+ // The rigid move of a dock snap (see findDockSnap): shifted and turned about the element's centre.
624
+ }, {
625
+ key: "snapMove",
626
+ value: function snapMove(element, snap) {
627
+ var center = {
628
+ x: element.WorldPosCenter.x,
629
+ z: element.WorldPosCenter.z
630
+ };
631
+ return {
632
+ from: {
633
+ center: center,
634
+ rotDeg: 0
635
+ },
636
+ to: {
637
+ center: {
638
+ x: center.x + snap.dx,
639
+ z: center.z + snap.dz
640
+ },
641
+ rotDeg: snap.dRotDeg
642
+ }
643
+ };
644
+ }
645
+
646
+ /**
647
+ * Activates (or clears) the room the elements are bound to. With `bindGroups` every docking group of main elements
648
+ * gets the room rule once: a forced group goes to its nearest wall pose, any other is pushed inside the room. A group
649
+ * the rules leave on other furniture or in a door's clearance (swing or doorway), where it did not stand so before, then
650
+ * goes to the nearest free pose (see {@link moveClearOfObstacles}). Returns false when a forced group fits on no wall
651
+ * (it stays where it is).
652
+ */
653
+ }, {
654
+ key: "setRoom",
655
+ value: function setRoom(room, bindGroups) {
656
+ // Measured in the room the elements stood in so far.
657
+ var blockedBefore = room && bindGroups ? this.getBlockedGroupKeys() : new Set();
658
+ this.room = room;
659
+ this.roomDrag = undefined;
660
+ if (!room || !bindGroups) return true;
661
+ var allGroupsFit = this.placeGroupsInRoom();
662
+ this.clearNewlyBlockedGroups(room, blockedBefore);
663
+ this.updatePlannerPosNr();
664
+ this.checkCollision(false);
665
+ this.updatePlannerBoundingBox();
666
+ return allGroupsFit;
667
+ }
668
+
669
+ // Applies the room rules to every docking group of main elements, or only to the groups holding one of `elements`;
670
+ // false when a forced group fits on no wall. A group of guests goes with its carrier instead.
671
+ }, {
672
+ key: "placeGroupsInRoom",
673
+ value: function placeGroupsInRoom(elements) {
674
+ var allGroupsFit = true;
675
+ var _iterator2 = _createForOfIteratorHelper(index.getDockingGroups(this.getAllPlannerElements())),
676
+ _step2;
677
+ try {
678
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
679
+ var group = _step2.value;
680
+ if (elements && !group.some(function (member) {
681
+ return elements.includes(member);
682
+ })) continue;
683
+ if (this.followsCarrier(group)) continue;
684
+ if (!this.placeGroupInRoom(group)) allGroupsFit = false;
685
+ }
686
+ } catch (err) {
687
+ _iterator2.e(err);
688
+ } finally {
689
+ _iterator2.f();
690
+ }
691
+ return allGroupsFit;
692
+ }
693
+
694
+ // The first main element of each docking group (not a guest at its carrier) that stands on another group, of this set
695
+ // or of another set in the room, or in a door's clearance in the active room.
696
+ }, {
697
+ key: "getBlockedGroupKeys",
698
+ value: function getBlockedGroupKeys() {
699
+ var blocked = new Set();
700
+ var _iterator3 = _createForOfIteratorHelper(index.getDockingGroups(this.getAllPlannerElements())),
701
+ _step3;
702
+ try {
703
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
704
+ var group = _step3.value;
705
+ var main = group.find(function (member) {
706
+ return !member.IsAccessoire;
707
+ });
708
+ if (!main || this.followsCarrier(group)) continue;
709
+ var drag = this.createRoomDrag(main.ElementId);
710
+ if (drag && this.isBlocked(drag, drag.start)) blocked.add(main.ElementId);
711
+ }
712
+ } catch (err) {
713
+ _iterator3.e(err);
714
+ } finally {
715
+ _iterator3.f();
716
+ }
717
+ return blocked;
718
+ }
719
+
720
+ // Every group (but a guest at its carrier) whose first main element is not in `blockedBefore` and that stands on
721
+ // another group or in a door's clearance goes to the nearest free pose (moveClearOfObstacles).
722
+ }, {
723
+ key: "clearNewlyBlockedGroups",
724
+ value: function clearNewlyBlockedGroups(room, blockedBefore) {
725
+ var _iterator4 = _createForOfIteratorHelper(index.getDockingGroups(this.getAllPlannerElements())),
726
+ _step4;
727
+ try {
728
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
729
+ var group = _step4.value;
730
+ var main = group.find(function (member) {
731
+ return !member.IsAccessoire;
732
+ });
733
+ if (main && !blockedBefore.has(main.ElementId) && !this.followsCarrier(group)) this.moveClearOfObstacles(main.ElementId, room);
734
+ }
735
+ } catch (err) {
736
+ _iterator4.e(err);
737
+ } finally {
738
+ _iterator4.f();
739
+ }
740
+ }
741
+
742
+ // Elements added in a room: their groups get the room rules, and with `clearOfObstacles` a group standing on another or
743
+ // in a door's clearance moves to the nearest free pose.
744
+ }, {
745
+ key: "placeAddedInRoom",
746
+ value: function placeAddedInRoom(added, clearOfObstacles) {
747
+ var room = this.room;
748
+ if (!room) return;
749
+ if (!this.placeGroupsInRoom(added)) {
750
+ this.updateRoomNoFitMsg(true);
751
+ return;
752
+ }
753
+ if (!clearOfObstacles) return;
754
+ var _iterator5 = _createForOfIteratorHelper(index.getDockingGroups(this.getAllPlannerElements())),
755
+ _step5;
756
+ try {
757
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
758
+ var group = _step5.value;
759
+ var main = group.find(function (member) {
760
+ return !member.IsAccessoire && added.includes(member);
761
+ });
762
+ if (main && !this.followsCarrier(group)) this.moveClearOfObstacles(main.ElementId, room);
763
+ }
764
+ } catch (err) {
765
+ _iterator5.e(err);
766
+ } finally {
767
+ _iterator5.f();
768
+ }
769
+ }
770
+
771
+ // Placing some groups can only show ROOM_NO_FIT_MSG: whether every set fits is DivaPlannerHandler's to say.
772
+ }, {
773
+ key: "updateRoomNoFitMsg",
774
+ value: function updateRoomNoFitMsg(show) {
775
+ var _this$collisionHandle, _this$collisionHandle2;
776
+ (_this$collisionHandle = (_this$collisionHandle2 = this.collisionHandler).updatePlannerMsgContainer) === null || _this$collisionHandle === void 0 || _this$collisionHandle.call(_this$collisionHandle2, 'ROOM_NO_FIT_MSG', show, 'WARNING', 'ROOM_NO_FIT_MSG', false);
777
+ }
778
+
779
+ /**
780
+ * Whether every docking group of the set has its place in the active room: a forced group stands on its wall pose, any other
781
+ * (but guests at their carrier) room within the footprint as it stands turned, with its followers (no room: true). Until the
782
+ * viewer measured its main elements a group that has a wall pose counts as standing on it: an opened one was saved
783
+ * with their measured extents, which reach at least as far as the outline, a placed one goes there once measured (see
784
+ * setElementFootprints).
785
+ */
786
+ }, {
787
+ key: "groupsFitInRoom",
788
+ value: function groupsFitInRoom() {
789
+ var _this5 = this;
790
+ var room = this.room;
791
+ if (!room) return true;
792
+ return index.getDockingGroups(this.getAllPlannerElements()).every(function (group) {
793
+ if (group.every(function (member) {
794
+ return member.IsAccessoire;
795
+ })) return true;
796
+ if (!_this5.isWallBound(group)) return _this5.followsCarrier(group) || _this5.fitsInside(group, room);
797
+ var _this5$getWallBinding = _this5.getWallBinding(group, room),
798
+ groupBlock = _this5$getWallBinding.groupBlock,
799
+ pose = _this5$getWallBinding.pose;
800
+ if (!pose) return false;
801
+ return index.isSamePose(pose, groupBlock) || group.some(function (member) {
802
+ return !member.IsAccessoire && !member.GeoExtent;
803
+ });
804
+ });
805
+ }
806
+
807
+ // Whether the group with its followers, pushed inside the room (see insidePose), lies within it.
808
+ }, {
809
+ key: "fitsInside",
810
+ value: function fitsInside(group, room) {
811
+ var groupBlock = index.getGroupBlock([].concat(_toConsumableArray__default["default"](group), _toConsumableArray__default["default"](this.getFollowers(group))), this.getRoomFrame(group).RotDeg);
812
+ return index.fitsInsideRoom(toFloorRect(groupBlock.block, insidePose(groupBlock.block, groupBlock, room)), room);
813
+ }
814
+
815
+ // A forced group goes to its nearest wall pose (false when it fits on none), any other group is pushed inside the room
816
+ // with its followers (their bodies too; false when it is wider or deeper than the room). The followers go along
817
+ // either way.
818
+ }, {
819
+ key: "placeGroupInRoom",
820
+ value: function placeGroupInRoom(group, frameElement) {
821
+ var _this6 = this;
822
+ var followers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.getFollowers(group);
823
+ if (!this.room || group.every(function (member) {
824
+ return member.IsAccessoire;
825
+ })) return true;
826
+ group.forEach(function (member) {
827
+ return _this6.roomPlaced.add(member);
828
+ });
829
+ if (this.isWallBound(group)) return this.bindGroupToWalls(group, frameElement, followers);
830
+ var frame = this.getRoomFrame(group, frameElement);
831
+ var unit = [].concat(_toConsumableArray__default["default"](group), _toConsumableArray__default["default"](followers));
832
+ var groupBlock = index.getGroupBlock(unit, frame.RotDeg);
833
+ var pose = insidePose(groupBlock.block, groupBlock, this.room);
834
+ index.moveGroupRigidly(unit, groupBlock, pose);
835
+ return index.fitsInsideRoom(toFloorRect(groupBlock.block, pose), this.room);
836
+ }
837
+
838
+ // The element whose rotation frames the group: `preferred` unless it is an accessory, else the oldest main element.
839
+ }, {
840
+ key: "getRoomFrame",
841
+ value: function getRoomFrame(members, preferred) {
842
+ var _members$find;
843
+ if (preferred && !preferred.IsAccessoire) return preferred;
844
+ return (_members$find = members.find(function (member) {
845
+ return !member.IsAccessoire;
846
+ })) !== null && _members$find !== void 0 ? _members$find : members[0];
847
+ }
848
+ }, {
849
+ key: "bindGroupToWalls",
850
+ value: function bindGroupToWalls(members, frameElement) {
851
+ var followers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
852
+ if (!this.room || !members.length) return false;
853
+ var _this$getWallBinding = this.getWallBinding(members, this.room, frameElement),
854
+ groupBlock = _this$getWallBinding.groupBlock,
855
+ pose = _this$getWallBinding.pose;
856
+ if (!pose) return false;
857
+ index.moveGroupRigidly([].concat(_toConsumableArray__default["default"](members), _toConsumableArray__default["default"](followers)), groupBlock, pose);
858
+ return true;
859
+ }
860
+
861
+ /**
862
+ * The group as one block, and its wall pose (null: it fits on no wall), in the frame it is bound in: `preferred`'s,
863
+ * else the rotation of a main element in which it already stands on its wall pose (a group released by a turned
864
+ * element keeps that frame), else the oldest main element's (see getRoomFrame).
865
+ */
866
+ }, {
867
+ key: "getWallBinding",
868
+ value: function getWallBinding(members, room, preferred) {
869
+ var _this7 = this;
870
+ var bindingIn = function bindingIn(frame) {
871
+ var groupBlock = _this7.getRoomBlock(members, frame);
872
+ return {
873
+ groupBlock: groupBlock,
874
+ pose: index.bindToWalls(groupBlock.center, groupBlock.block, room)
875
+ };
876
+ };
877
+ var first = bindingIn(this.getRoomFrame(members, preferred));
878
+ if (preferred && !preferred.IsAccessoire) return first;
879
+ var standsOn = function standsOn(_ref4) {
880
+ var groupBlock = _ref4.groupBlock,
881
+ pose = _ref4.pose;
882
+ return !!pose && index.isSamePose(pose, groupBlock);
883
+ };
884
+ if (standsOn(first)) return first;
885
+ var _iterator6 = _createForOfIteratorHelper(members),
886
+ _step6;
887
+ try {
888
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
889
+ var member = _step6.value;
890
+ if (member.IsAccessoire || member.RotDeg === first.groupBlock.rotDeg) continue;
891
+ var binding = bindingIn(member);
892
+ if (standsOn(binding)) return binding;
893
+ }
894
+ } catch (err) {
895
+ _iterator6.e(err);
896
+ } finally {
897
+ _iterator6.f();
898
+ }
899
+ return first;
900
+ }
901
+
902
+ /**
903
+ * Takes the 3D extents the viewer measured for this set's main elements, so a part reaching beyond the 2D outline
904
+ * stays out of the walls. A forced group a room rule placed goes to its wall pose with them (it was placed before its
905
+ * model was measured); a group as the planning was opened moves only with the next user action. Returns whether an
906
+ * element moved.
907
+ */
908
+ }, {
909
+ key: "setElementFootprints",
910
+ value: function setElementFootprints(footprints) {
911
+ var _this8 = this;
912
+ var changed = [];
913
+ var _iterator7 = _createForOfIteratorHelper(footprints),
914
+ _step7;
915
+ try {
916
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
917
+ var _step7$value = _step7.value,
918
+ elementId = _step7$value.elementId,
919
+ minX = _step7$value.minX,
920
+ maxX = _step7$value.maxX,
921
+ minZ = _step7$value.minZ,
922
+ maxZ = _step7$value.maxZ,
923
+ top = _step7$value.top;
924
+ var element = this.plannerElements.get(elementId);
925
+ var extent = {
926
+ minX: minX,
927
+ maxX: maxX,
928
+ minZ: minZ,
929
+ maxZ: maxZ,
930
+ top: top
931
+ };
932
+ if (!element || element.IsAccessoire || index.sameGeoExtent(element.GeoExtent, extent)) continue;
933
+ element.GeoExtent = extent;
934
+ if (this.roomPlaced.has(element)) changed.push(element);
935
+ }
936
+ } catch (err) {
937
+ _iterator7.e(err);
938
+ } finally {
939
+ _iterator7.f();
940
+ }
941
+ if (!this.room || changed.length === 0) return false;
942
+ var groups = index.getDockingGroups(this.getAllPlannerElements()).filter(function (group) {
943
+ return group.some(function (member) {
944
+ return changed.includes(member);
945
+ }) && _this8.isWallBound(group) && !_this8.followsCarrier(group);
946
+ });
947
+ var members = groups.flat();
948
+ var before = members.map(function (member) {
949
+ return [member.WorldPosCenter.x, member.WorldPosCenter.z, member.RotDeg];
950
+ });
951
+ groups.forEach(function (group) {
952
+ return _this8.placeGroupInRoom(group);
953
+ });
954
+ var moved = members.some(function (member, i) {
955
+ var _before$i = _slicedToArray__default["default"](before[i], 3),
956
+ x = _before$i[0],
957
+ z = _before$i[1],
958
+ rotDeg = _before$i[2];
959
+ return member.WorldPosCenter.x !== x || member.WorldPosCenter.z !== z || member.RotDeg !== rotDeg;
960
+ });
961
+ if (!moved) return false;
962
+ this.updatePlannerPosNr();
963
+ this.checkCollision(false);
964
+ this.updatePlannerBoundingBox();
965
+ return true;
966
+ }
967
+
968
+ /** Whether the element's docking group is bound to the walls of the active room. */
969
+ }, {
970
+ key: "isElementWallBound",
971
+ value: function isElementWallBound(elementId) {
972
+ var element = this.plannerElements.get(elementId);
973
+ return !!this.room && !!element && this.isWallBound(this.getDockingGroupOf(element));
974
+ }
975
+
976
+ /**
977
+ * A group's wall mode: forced when a main element is forced or a corner element, else snap when one snaps, else free. A
978
+ * guest's own wall rule rests while it stands at its carrier.
979
+ */
980
+ }, {
981
+ key: "getGroupWallMode",
982
+ value: function getGroupWallMode(members) {
983
+ var _this9 = this;
984
+ var catalogData = this.getCatalogData();
985
+ var modes = members.flatMap(function (member) {
986
+ var codex = _this9.getCarrierOf(member) ? '' : mainCodex(member);
987
+ if (!codex) return [];
988
+ return [catalogData.getCornerSide(codex) ? 'forced' : catalogData.getWallMode(codex)];
989
+ });
990
+ return modes.includes('forced') ? 'forced' : modes.includes('snap') ? 'snap' : 'free';
991
+ }
992
+ }, {
993
+ key: "isWallBound",
994
+ value: function isWallBound(members) {
995
+ return this.getGroupWallMode(members) === 'forced';
996
+ }
997
+
998
+ // The group as one block in `frame`'s rotation; a corner element at one of its ends pins that end into a corner.
999
+ }, {
1000
+ key: "getRoomBlock",
1001
+ value: function getRoomBlock(members, frame) {
1002
+ var groupBlock = index.getGroupBlock(members, frame.RotDeg);
1003
+ var catalogData = this.getCatalogData();
1004
+ var _iterator8 = _createForOfIteratorHelper(members),
1005
+ _step8;
1006
+ try {
1007
+ for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
1008
+ var member = _step8.value;
1009
+ var codex = mainCodex(member);
1010
+ var side = codex ? catalogData.getCornerSide(codex) : undefined;
1011
+ if (!side) continue;
1012
+ var cornerEnd = index.getCornerEnd(members, frame.RotDeg, member, side);
1013
+ if (cornerEnd) return _objectSpread(_objectSpread({}, groupBlock), {}, {
1014
+ block: _objectSpread(_objectSpread({}, groupBlock.block), {}, {
1015
+ cornerEnd: cornerEnd
1016
+ })
1017
+ });
1018
+ }
1019
+ } catch (err) {
1020
+ _iterator8.e(err);
1021
+ } finally {
1022
+ _iterator8.f();
1023
+ }
1024
+ return groupBlock;
1025
+ }
1026
+
1027
+ /** A group collides unless all its main elements are NO_COLLISION (e.g. rugs). */
1028
+ }, {
1029
+ key: "collides",
1030
+ value: function collides(members) {
1031
+ var _this10 = this;
1032
+ return members.some(function (member) {
1033
+ var codex = mainCodex(member);
1034
+ return !!codex && !_this10.hasNoCollision(codex);
1035
+ });
1036
+ }
1037
+ }, {
1038
+ key: "hasNoCollision",
1039
+ value: function hasNoCollision(codex) {
1040
+ return !!codex && this.getCatalogData().hasNoCollision(codex);
1041
+ }
1042
+
1043
+ /** The article's placement types, primary first (PLACEMENT_TYPE, else palette group); empty without one. */
1044
+ }, {
1045
+ key: "getPlacementTypes",
1046
+ value: function getPlacementTypes(element) {
1047
+ var codex = element.ArticleCodex;
1048
+ return codex && this.getCatalogData().getPlacementType(codex) || [];
1049
+ }
1050
+
1051
+ // The main elements of a group as carriers of placement slots, by their outlines (never the viewer's measures).
1052
+ }, {
1053
+ key: "getSlotMembers",
1054
+ value: function getSlotMembers(group) {
1055
+ var _this11 = this;
1056
+ return group.filter(function (member) {
1057
+ return !member.IsAccessoire;
1058
+ }).map(function (member) {
1059
+ return {
1060
+ types: _this11.getPlacementTypes(member),
1061
+ rotDeg: member.RotDeg,
1062
+ body: index.getElementShape(member, false).body[0],
1063
+ basketId: member.getBasketId()
1064
+ };
1065
+ });
1066
+ }
1067
+
1068
+ // The member with its shape where it stands (with the viewer's measures when `measured`) and its group as slot carrier.
1069
+ }, {
1070
+ key: "toCollisionShape",
1071
+ value: function toCollisionShape(member, slotMembers, measured) {
1072
+ return {
1073
+ elementId: member.ElementId,
1074
+ shape: index.getElementShape(member, measured),
1075
+ types: this.getPlacementTypes(member),
1076
+ group: slotMembers,
1077
+ layer: Number(member.Layer)
1078
+ };
1079
+ }
1080
+
1081
+ // The members of `group` that take part in collisions (see toCollisionShape).
1082
+ }, {
1083
+ key: "getCollidingShapes",
1084
+ value: function getCollidingShapes(group, measured) {
1085
+ var _this12 = this;
1086
+ var slotMembers = this.getSlotMembers(group);
1087
+ return group.filter(function (member) {
1088
+ return !_this12.hasNoCollision(member.ArticleCodex);
1089
+ }).map(function (member) {
1090
+ return _this12.toCollisionShape(member, slotMembers, measured);
1091
+ });
1092
+ }
1093
+
1094
+ // Every element of the other colliding groups (not those of `unit`, the group with its followers), the elements of the
1095
+ // other sets (`otherSets`, else those without the guests going with `members`), and in a room the door clearances: the
1096
+ // swings and doorways (getDoorClearanceRects).
1097
+ }, {
1098
+ key: "getObstacles",
1099
+ value: function getObstacles(members, measured) {
1100
+ var _this13 = this;
1101
+ var unit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : members;
1102
+ var otherSets = arguments.length > 3 ? arguments[3] : undefined;
1103
+ if (!this.collides(members)) return [];
1104
+ var others = index.getDockingGroups(this.getAllPlannerElements()).filter(function (group) {
1105
+ return !group.some(function (member) {
1106
+ return unit.includes(member);
1107
+ }) && _this13.collides(group);
1108
+ });
1109
+ var _this$getCatalogData = this.getCatalogData(),
1110
+ catalogCodex = _this$getCatalogData.catalogCodex;
1111
+ // Two catalogs always collide; one catalog in two sets by its layer rule.
1112
+ var foreign = (otherSets !== null && otherSets !== void 0 ? otherSets : this.getOtherCollisionSets(members.map(function (member) {
1113
+ return member.ElementId;
1114
+ }))).flatMap(function (set) {
1115
+ return set.parts.map(function (_ref5) {
1116
+ var shape = _ref5.shape,
1117
+ types = _ref5.types,
1118
+ group = _ref5.group,
1119
+ elementId = _ref5.elementId,
1120
+ layer = _ref5.layer;
1121
+ var ownLayerRule = set.catalogCodex === catalogCodex;
1122
+ return {
1123
+ shape: shape,
1124
+ types: types,
1125
+ group: group,
1126
+ elementId: elementId,
1127
+ layer: ownLayerRule ? layer : undefined,
1128
+ setId: set.setId,
1129
+ rules: set.rules
1130
+ };
1131
+ });
1132
+ });
1133
+ var doors = (this.room ? index.getDoorClearanceRects(this.room) : []).map(function (swing) {
1134
+ var polygon = index.rectCorners(swing).map(function (corner) {
1135
+ return new index.Vector2(corner.x, corner.z);
1136
+ });
1137
+ return {
1138
+ shape: {
1139
+ body: [polygon],
1140
+ free: [polygon]
1141
+ },
1142
+ types: [],
1143
+ group: []
1144
+ };
1145
+ });
1146
+ return [].concat(_toConsumableArray__default["default"](others.flatMap(function (group) {
1147
+ return _this13.getCollidingShapes(group, measured);
1148
+ })), _toConsumableArray__default["default"](foreign), _toConsumableArray__default["default"](doors));
1149
+ }
1150
+ }, {
1151
+ key: "getDockingGroupOf",
1152
+ value: function getDockingGroupOf(element) {
1153
+ var _getDockingGroups$fin;
1154
+ return (_getDockingGroups$fin = index.getDockingGroups(this.getAllPlannerElements()).find(function (group) {
1155
+ return group.includes(element);
1156
+ })) !== null && _getDockingGroups$fin !== void 0 ? _getDockingGroups$fin : [element];
1157
+ }
1158
+
1159
+ /** The element whose article has the basket id; undefined when the set has none. */
1160
+ }, {
1161
+ key: "getElementByBasketId",
1162
+ value: function getElementByBasketId(basketId) {
1163
+ return this.getAllPlannerElements().find(function (element) {
1164
+ return element.getBasketId() === basketId;
1165
+ });
1166
+ }
1167
+
1168
+ // The carrier a guest stands at while its set is loaded; without a resolver only one of this set.
1169
+ }, {
1170
+ key: "getCarrierOf",
1171
+ value: function getCarrierOf(element) {
1172
+ var placement = element.Placement;
1173
+ if (!placement) return undefined;
1174
+ if (this.findCarrier) return this.findCarrier(placement);
1175
+ return this.getElementByBasketId(placement.carrierBasketId);
1176
+ }
1177
+
1178
+ // Whether every main element of the group is a guest at a carrier outside it: the group goes with its carrier.
1179
+ }, {
1180
+ key: "followsCarrier",
1181
+ value: function followsCarrier(group) {
1182
+ var _this14 = this;
1183
+ var mains = group.filter(function (member) {
1184
+ return !member.IsAccessoire;
1185
+ });
1186
+ return mains.length > 0 && mains.every(function (member) {
1187
+ var carrier = _this14.getCarrierOf(member);
1188
+ return !!carrier && !group.includes(carrier);
1189
+ });
1190
+ }
1191
+
1192
+ /**
1193
+ * The guests of this set that go with `members`: those standing at one of them, and the guests of those (at most
1194
+ * MAX_GUEST_DEPTH carriers deep), each with its docking group; never one of `members`.
1195
+ */
1196
+ }, {
1197
+ key: "getFollowers",
1198
+ value: function getFollowers(members) {
1199
+ var _this15 = this;
1200
+ var unit = new Set(members);
1201
+ var followers = [];
1202
+ var carriers = members;
1203
+ for (var depth = 0; depth < index.MAX_GUEST_DEPTH && carriers.length > 0; depth++) {
1204
+ var guests = this.getAllPlannerElements().filter(function (element) {
1205
+ var carrier = !unit.has(element) && _this15.getCarrierOf(element);
1206
+ return !!carrier && carriers.includes(carrier);
1207
+ });
1208
+ var next = _toConsumableArray__default["default"](new Set(guests.flatMap(function (guest) {
1209
+ return _this15.getDockingGroupOf(guest);
1210
+ }))).filter(function (element) {
1211
+ return !unit.has(element);
1212
+ });
1213
+ next.forEach(function (element) {
1214
+ return unit.add(element);
1215
+ });
1216
+ followers.push.apply(followers, _toConsumableArray__default["default"](next));
1217
+ carriers = next;
1218
+ }
1219
+ return followers;
1220
+ }
1221
+
1222
+ /** The ids of the element's docking group, the element included. */
1223
+ }, {
1224
+ key: "getDockingGroupIds",
1225
+ value: function getDockingGroupIds(elementId) {
1226
+ var element = this.plannerElements.get(elementId);
1227
+ return element ? this.getDockingGroupOf(element).map(function (member) {
1228
+ return member.ElementId;
1229
+ }) : [];
1230
+ }
1231
+
1232
+ /** The element's first placement type; undefined for an accessory or an article without one. */
1233
+ }, {
1234
+ key: "getGuestType",
1235
+ value: function getGuestType(elementId) {
1236
+ var element = this.plannerElements.get(elementId);
1237
+ return element && !element.IsAccessoire ? this.getPlacementTypes(element)[0] : undefined;
1238
+ }
1239
+
1240
+ /** The main elements of every docking group as slot carriers (see `getSlotMembers`), but groups holding one of `excludeIds`. */
1241
+ }, {
1242
+ key: "getSlotCarriers",
1243
+ value: function getSlotCarriers(excludeIds) {
1244
+ var _this16 = this;
1245
+ return index.getDockingGroups(this.getAllPlannerElements()).filter(function (group) {
1246
+ return !group.some(function (member) {
1247
+ return excludeIds.includes(member.ElementId);
1248
+ });
1249
+ }).map(function (group) {
1250
+ return _this16.getSlotMembers(group);
1251
+ }).filter(function (members) {
1252
+ return members.length > 0;
1253
+ });
1254
+ }
1255
+
1256
+ /** Moves the element's docking group rigidly so the element stands at `pose` (a guest following its carrier). */
1257
+ }, {
1258
+ key: "moveGuest",
1259
+ value: function moveGuest(elementId, pose) {
1260
+ var element = this.plannerElements.get(elementId);
1261
+ if (element) index.moveGroupRigidly(this.getDockingGroupOf(element), index.poseOf(element), pose);
1262
+ }
1263
+
1264
+ /** After guests moved: position numbers, the collision warning and the bounding box follow. */
1265
+ }, {
1266
+ key: "refreshAfterGuestMoves",
1267
+ value: function refreshAfterGuestMoves() {
1268
+ this.updatePlannerPosNr();
1269
+ this.checkCollision(false);
1270
+ this.updatePlannerBoundingBox();
1271
+ }
1272
+
1273
+ /**
1274
+ * Whether the element's docking group, moved so the element stands at `pose`, runs a body into another body of this set
1275
+ * or of `otherSets` (a zone does not count, a slot guest at its carrier as everywhere); the group stays where it is.
1276
+ */
1277
+ }, {
1278
+ key: "isBodyBlockedAt",
1279
+ value: function isBodyBlockedAt(elementId, pose, otherSets) {
1280
+ var element = this.plannerElements.get(elementId);
1281
+ if (!element) return true;
1282
+ var group = this.getDockingGroupOf(element);
1283
+ var saved = group.map(function (member) {
1284
+ return {
1285
+ member: member,
1286
+ center: member.WorldPosCenter,
1287
+ rotDeg: member.RotDeg
1288
+ };
1289
+ });
1290
+ index.moveGroupRigidly(group, index.poseOf(element), pose);
1291
+ var drag = this.createRoomDrag(elementId, false, otherSets);
1292
+ if (drag) drag.zonesBlock = false;
1293
+ var blocked = !!drag && this.isBlocked(drag, drag.start);
1294
+ var _iterator9 = _createForOfIteratorHelper(saved),
1295
+ _step9;
1296
+ try {
1297
+ for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
1298
+ var _step9$value = _step9.value,
1299
+ member = _step9$value.member,
1300
+ center = _step9$value.center,
1301
+ rotDeg = _step9$value.rotDeg;
1302
+ member.WorldPosCenter = center;
1303
+ member.RotDeg = rotDeg;
1304
+ }
1305
+ } catch (err) {
1306
+ _iterator9.e(err);
1307
+ } finally {
1308
+ _iterator9.f();
1309
+ }
1310
+ return blocked;
1311
+ }
1312
+ }, {
1313
+ key: "startRoomDrag",
1314
+ value: function startRoomDrag(elementId) {
1315
+ this.roomDrag = undefined;
1316
+ var drag = this.createRoomDrag(elementId);
1317
+ if (!drag) return;
1318
+ drag.zonesBlock = false;
1319
+ var moved = this.movedShapes(drag, drag.start);
1320
+ var _iterator10 = _createForOfIteratorHelper(drag.obstacles),
1321
+ _step10;
1322
+ try {
1323
+ var _loop = function _loop() {
1324
+ var obstacle = _step10.value;
1325
+ // A guest standing in its slot as far under its carrier as the slot lets it (a chair at the table) overlaps by right.
1326
+ var depths = moved.map(function (member) {
1327
+ var _obstacle$rules;
1328
+ return index.slotExempt(drag.rules, member, (_obstacle$rules = obstacle.rules) !== null && _obstacle$rules !== void 0 ? _obstacle$rules : drag.rules, obstacle) ? 0 : index.bodiesOverlap(member.shape, obstacle.shape);
1329
+ });
1330
+ if (depths.some(function (depth) {
1331
+ return depth > 0;
1332
+ })) drag.startOverlaps.set(obstacle, depths);
1333
+ };
1334
+ for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
1335
+ _loop();
1336
+ }
1337
+ } catch (err) {
1338
+ _iterator10.e(err);
1339
+ } finally {
1340
+ _iterator10.f();
1341
+ }
1342
+ this.roomDrag = drag;
1343
+ }
1344
+
1345
+ /**
1346
+ * The element's group as one block where it stands, with its followers (see `getFollowers`): the members' and the
1347
+ * followers' shapes and every obstacle but them; not started. A forced group's block is its own, any other group's
1348
+ * takes in the followers, so the room rule keeps them inside too.
1349
+ */
1350
+ }, {
1351
+ key: "createRoomDrag",
1352
+ value: function createRoomDrag(elementId) {
1353
+ var _this17 = this;
1354
+ var measured = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
1355
+ var otherSets = arguments.length > 2 ? arguments[2] : undefined;
1356
+ var element = this.plannerElements.get(elementId);
1357
+ if (!element) return undefined;
1358
+ var members = this.getDockingGroupOf(element);
1359
+ if (members.every(function (member) {
1360
+ return member.IsAccessoire;
1361
+ })) return undefined;
1362
+ var followers = this.getFollowers(members);
1363
+ var wallMode = this.getGroupWallMode(members);
1364
+ var frame = this.getRoomFrame(members, element);
1365
+ var start = wallMode === 'forced' ? this.getRoomBlock(members, frame) : index.getGroupBlock([].concat(_toConsumableArray__default["default"](members), _toConsumableArray__default["default"](followers)), frame.RotDeg);
1366
+ var position = element.WorldPosCenter;
1367
+ var followerShapes = index.getDockingGroups(followers).filter(function (group) {
1368
+ return _this17.collides(group);
1369
+ }).flatMap(function (group) {
1370
+ return _this17.getCollidingShapes(group, measured);
1371
+ });
1372
+ var memberShapes = this.collides(members) ? this.getCollidingShapes(members, measured) : [];
1373
+ var drag = {
1374
+ elementId: elementId,
1375
+ members: members,
1376
+ followers: followers,
1377
+ start: start,
1378
+ current: start,
1379
+ grabbedStart: {
1380
+ x: position.x,
1381
+ z: position.z
1382
+ },
1383
+ grabbedStartRotDeg: element.RotDeg,
1384
+ dx: 0,
1385
+ dz: 0,
1386
+ wallMode: wallMode,
1387
+ shapes: this.collides(members) ? [].concat(_toConsumableArray__default["default"](memberShapes), _toConsumableArray__default["default"](followerShapes)) : [],
1388
+ memberShapes: memberShapes.length,
1389
+ obstacles: this.getObstacles(members, measured, [].concat(_toConsumableArray__default["default"](members), _toConsumableArray__default["default"](followers)), otherSets),
1390
+ blockedBy: [],
1391
+ startOverlaps: new Map(),
1392
+ rules: this.getCatalogData().placementOptions.rules,
1393
+ zonesBlock: true,
1394
+ rotating: false,
1395
+ slotSnapped: false
1396
+ };
1397
+ return drag;
1398
+ }
1399
+
1400
+ /**
1401
+ * A group placed beside the planning, or by the room rules, that stands on another group (of this set or another set in
1402
+ * the room) or in a door's clearance goes to the nearest free pose, by the room rule of its wall mode, and slides back
1403
+ * until it touches what it was cleared of. It stays where it is when the room has no free pose for it.
1404
+ */
1405
+ }, {
1406
+ key: "moveClearOfObstacles",
1407
+ value: function moveClearOfObstacles(elementId, room) {
1408
+ var drag = this.createRoomDrag(elementId);
1409
+ if (!drag || !this.isBlocked(drag, drag.start)) return;
1410
+ var _drag$start = drag.start,
1411
+ block = _drag$start.block,
1412
+ rotDeg = _drag$start.rotDeg;
1413
+ _drag$start.center;
1414
+ var poseAt = function poseAt(raw) {
1415
+ return drag.wallMode === 'forced' ? index.bindToWalls(raw, block, room) : insidePose(block, {
1416
+ center: raw,
1417
+ rotDeg: rotDeg
1418
+ }, room);
1419
+ };
1420
+ var xs = room.footprint.map(function (_ref6) {
1421
+ var _ref7 = _slicedToArray__default["default"](_ref6, 1),
1422
+ x = _ref7[0];
1423
+ return x;
1424
+ });
1425
+ var zs = room.footprint.map(function (_ref8) {
1426
+ var _ref9 = _slicedToArray__default["default"](_ref8, 2),
1427
+ z = _ref9[1];
1428
+ return z;
1429
+ });
1430
+ var reach = Math.hypot(Math.max.apply(Math, _toConsumableArray__default["default"](xs)) - Math.min.apply(Math, _toConsumableArray__default["default"](xs)), Math.max.apply(Math, _toConsumableArray__default["default"](zs)) - Math.min.apply(Math, _toConsumableArray__default["default"](zs)));
1431
+ var target = this.nearestFreePose(drag, drag.start, poseAt, reach);
1432
+ if (target) index.moveGroupRigidly([].concat(_toConsumableArray__default["default"](drag.members), _toConsumableArray__default["default"](drag.followers)), drag.start, target);
1433
+ }
1434
+
1435
+ // Of the free poses on the first ring around `origin` that has one, slid back until they touch, the nearest one.
1436
+ }, {
1437
+ key: "nearestFreePose",
1438
+ value: function nearestFreePose(drag, origin, poseAt, reach) {
1439
+ var center = origin.center;
1440
+ for (var radius = CLEAR_SEARCH_STEP; radius <= reach; radius += CLEAR_SEARCH_STEP) {
1441
+ var nearest = void 0;
1442
+ for (var i = 0; i < CLEAR_SEARCH_DIRECTIONS; i++) {
1443
+ var _this$slideToContact;
1444
+ var angle = i / CLEAR_SEARCH_DIRECTIONS * 2 * Math.PI;
1445
+ var pose = poseAt({
1446
+ x: center.x + radius * Math.cos(angle),
1447
+ z: center.z + radius * Math.sin(angle)
1448
+ });
1449
+ if (!pose || this.isBlocked(drag, pose)) continue;
1450
+ drag.current = pose;
1451
+ var slid = (_this$slideToContact = this.slideToContact(drag, origin)) === null || _this$slideToContact === void 0 ? void 0 : _this$slideToContact.pose;
1452
+ // The way back may cross a notch of the room: the slid pose counts only where the room rule keeps it.
1453
+ var kept = slid && poseAt(slid.center);
1454
+ var target = slid && kept && Math.hypot(kept.center.x - slid.center.x, kept.center.z - slid.center.z) < 0.5 ? slid : pose;
1455
+ var distance = Math.hypot(target.center.x - center.x, target.center.z - center.z);
1456
+ if (!nearest || distance < nearest.distance - START_NOISE) nearest = {
1457
+ pose: target,
1458
+ distance: distance
1459
+ };
1460
+ }
1461
+ if (nearest) return nearest.pose;
1462
+ }
1463
+ return undefined;
1464
+ }
1465
+
1466
+ /**
1467
+ * Puts a new element at the first free place a slot of the `isCarrier` groups suggests (lowest PosNr first, planner
1468
+ * data only), numbers it last (PosNrAtEnd) and makes it a guest of the carrier (see `attachToSlot`); false, the element
1469
+ * unmoved, when no place is free.
1470
+ */
1471
+ }, {
1472
+ key: "placeAtSuggestedPlace",
1473
+ value: function placeAtSuggestedPlace(element, isCarrier) {
1474
+ var _this18 = this;
1475
+ var _ref10 = element.IsAccessoire ? [] : this.getPlacementTypes(element),
1476
+ _ref11 = _slicedToArray__default["default"](_ref10, 1),
1477
+ type = _ref11[0];
1478
+ if (!type) return false;
1479
+ var rules = this.getCatalogData().placementOptions.rules;
1480
+ var before = {
1481
+ center: {
1482
+ x: element.WorldPosCenter.x,
1483
+ z: element.WorldPosCenter.z
1484
+ },
1485
+ rotDeg: element.RotDeg
1486
+ };
1487
+ var body = index.getElementShape(element, false).body[0];
1488
+ var outline = function outline(rotDeg) {
1489
+ return index.movePoints(body, before, {
1490
+ center: {
1491
+ x: 0,
1492
+ z: 0
1493
+ },
1494
+ rotDeg: rotDeg
1495
+ });
1496
+ };
1497
+ var lowestPosNr = function lowestPosNr(group) {
1498
+ return Math.min.apply(Math, _toConsumableArray__default["default"](group.map(function (member) {
1499
+ return member.PosNr;
1500
+ })));
1501
+ };
1502
+ var carriers = index.getDockingGroups(this.getAllPlannerElements().filter(function (other) {
1503
+ return other !== element;
1504
+ })).filter(function (group) {
1505
+ return isCarrier(group) && group.some(function (member) {
1506
+ return !member.IsAccessoire;
1507
+ });
1508
+ }).sort(function (a, b) {
1509
+ return lowestPosNr(a) - lowestPosNr(b);
1510
+ });
1511
+ var otherSets = carriers.length > 0 ? this.getOtherCollisionSets() : [];
1512
+ var _iterator11 = _createForOfIteratorHelper(carriers),
1513
+ _step11;
1514
+ try {
1515
+ for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
1516
+ var group = _step11.value;
1517
+ var _iterator12 = _createForOfIteratorHelper(index.getCarrierSlots(rules, this.getSlotMembers(group), type)),
1518
+ _step12;
1519
+ try {
1520
+ for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
1521
+ var slot = _step12.value;
1522
+ if (!index.getSlotPlaces(slot, outline).some(function (place) {
1523
+ return _this18.fitsAt(element, place, otherSets);
1524
+ })) continue;
1525
+ element.PosNrAtEnd = true;
1526
+ this.attachToSlot(element, slot);
1527
+ return true;
1528
+ }
1529
+ } catch (err) {
1530
+ _iterator12.e(err);
1531
+ } finally {
1532
+ _iterator12.f();
1533
+ }
1534
+ }
1535
+ } catch (err) {
1536
+ _iterator11.e(err);
1537
+ } finally {
1538
+ _iterator11.f();
1539
+ }
1540
+ element.WorldPosCenter = new index.Vector3(before.center.x, element.WorldPosCenter.y, before.center.z);
1541
+ element.RotDeg = before.rotDeg;
1542
+ return false;
1543
+ }
1544
+
1545
+ // Makes the element a guest of the member of `slot` nearest to it: it goes with that carrier from now on. Not when the
1546
+ // carrier is a guest MAX_GUEST_DEPTH deep itself.
1547
+ }, {
1548
+ key: "attachToSlot",
1549
+ value: function attachToSlot(element, slot) {
1550
+ var _getNearestMember;
1551
+ var basketId = (_getNearestMember = index.getNearestMember(slot, index.poseOf(element).center)) === null || _getNearestMember === void 0 ? void 0 : _getNearestMember.basketId;
1552
+ var carrier = basketId ? this.getElementByBasketId(basketId) : undefined;
1553
+ if (!basketId || !carrier || this.getGuestDepth(carrier) >= index.MAX_GUEST_DEPTH) return;
1554
+ var offset = index.toPlacementOffset(index.poseOf(carrier), index.poseOf(element));
1555
+ element.Placement = {
1556
+ carrierBasketId: basketId,
1557
+ slotId: slot.id,
1558
+ offset: offset
1559
+ };
1560
+ }
1561
+
1562
+ // How many carriers stand above the element: 0 on its own, 1 at a carrier on its own, …
1563
+ }, {
1564
+ key: "getGuestDepth",
1565
+ value: function getGuestDepth(element) {
1566
+ var depth = 0;
1567
+ for (var carrier = this.getCarrierOf(element); carrier && depth <= index.MAX_GUEST_DEPTH; carrier = this.getCarrierOf(carrier)) depth++;
1568
+ return depth;
1569
+ }
1570
+
1571
+ // Moves the element to `pose` as the room rule keeps it; whether it fits there: the rule moves it no further than the
1572
+ // tolerance and it collides with nothing of this set or of `otherSets`.
1573
+ }, {
1574
+ key: "fitsAt",
1575
+ value: function fitsAt(element, pose, otherSets) {
1576
+ element.WorldPosCenter = new index.Vector3(pose.center.x, this.plannerBoundingBox.WorldPos.y, pose.center.z);
1577
+ element.RotDeg = pose.rotDeg;
1578
+ var drag = this.createRoomDrag(element.ElementId, false, otherSets);
1579
+ var kept = drag && this.getKeptPose(drag);
1580
+ if (!drag || !kept) return false;
1581
+ index.moveGroupRigidly(drag.members, drag.start, kept);
1582
+ return !this.isBlocked(drag, kept);
1583
+ }
1584
+
1585
+ // Where the room rule of its wall mode keeps the drag's group standing at `pose` (no room: the pose); undefined when it
1586
+ // would move the group further than `tolerance`, turn it, or fit it on no wall.
1587
+ }, {
1588
+ key: "getKeptPose",
1589
+ value: function getKeptPose(drag) {
1590
+ var pose = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : drag.start;
1591
+ var tolerance = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : PLACE_TOLERANCE;
1592
+ var room = this.room;
1593
+ if (!room) return pose;
1594
+ var block = drag.start.block;
1595
+ var center = pose.center,
1596
+ rotDeg = pose.rotDeg;
1597
+ var kept = drag.wallMode === 'forced' ? index.bindToWalls(center, block, room) : insidePose(block, pose, room);
1598
+ if (!kept || Math.hypot(kept.center.x - center.x, kept.center.z - center.z) > tolerance) return undefined;
1599
+ return Math.abs(index.getTurnDeg(rotDeg, kept.rotDeg)) > 0.01 ? undefined : kept;
1600
+ }
1601
+
1602
+ // The colliding members and followers of the dragged group, moved with it to `pose`, each group's carrier outlines too.
1603
+ }, {
1604
+ key: "movedShapes",
1605
+ value: function movedShapes(drag, pose) {
1606
+ var movedGroups = new Map();
1607
+ return drag.shapes.map(function (member) {
1608
+ var _movedGroups$get;
1609
+ var group = (_movedGroups$get = movedGroups.get(member.group)) !== null && _movedGroups$get !== void 0 ? _movedGroups$get : member.group.map(function (slotMember) {
1610
+ return index.moveSlotMember(slotMember, drag.start, pose);
1611
+ });
1612
+ movedGroups.set(member.group, group);
1613
+ return _objectSpread(_objectSpread({}, member), {}, {
1614
+ shape: index.moveShape(member.shape, drag.start, pose),
1615
+ group: group
1616
+ });
1617
+ });
1618
+ }
1619
+
1620
+ // Whether a member collides with an obstacle: body against body (a pair that overlapped at the start once it gets
1621
+ // deeper), and where zones block, a body in the other's free area. A guest standing in a slot of its carrier's group may
1622
+ // stand in the carrier's free area (a hocker in front of the sofa), and reach under its body as far as the slot lets it
1623
+ // (a chair's seat under the table top). Two layers only as the catalog lets them collide, as in the collision warning.
1624
+ }, {
1625
+ key: "overlapsAny",
1626
+ value: function overlapsAny(moved, obstacle, drag) {
1627
+ var startDepths = drag.startOverlaps.get(obstacle);
1628
+ var collidingLayers = this.getCatalogData().checkCollisionForDifferentLayers;
1629
+ return moved.some(function (member, i) {
1630
+ var _obstacle$rules2;
1631
+ if (obstacle.layer !== undefined && !index.layersCollide(collidingLayers, member.layer, obstacle.layer)) return false;
1632
+ if (startDepths) return index.bodiesOverlap(member.shape, obstacle.shape) > startDepths[i] + DEPTH_NOISE;
1633
+ return index.shapesCollide(member.shape, obstacle.shape, !drag.zonesBlock) && !index.slotExempt(drag.rules, member, (_obstacle$rules2 = obstacle.rules) !== null && _obstacle$rules2 !== void 0 ? _obstacle$rules2 : drag.rules, obstacle);
1634
+ });
1635
+ }
1636
+ }, {
1637
+ key: "isBlocked",
1638
+ value: function isBlocked(drag, pose) {
1639
+ var _this19 = this;
1640
+ var moved = this.movedShapes(drag, pose);
1641
+ return drag.obstacles.some(function (obstacle) {
1642
+ return _this19.overlapsAny(moved, obstacle, drag);
1643
+ });
1644
+ }
1645
+
1646
+ // The obstacles the group runs into at `pose`.
1647
+ }, {
1648
+ key: "blockersAt",
1649
+ value: function blockersAt(drag, pose) {
1650
+ var _this20 = this;
1651
+ var moved = this.movedShapes(drag, pose);
1652
+ return drag.obstacles.filter(function (obstacle) {
1653
+ return _this20.overlapsAny(moved, obstacle, drag);
1654
+ });
1655
+ }
1656
+
1657
+ // The straight way from the current pose to `target`, checked every PATH_STEP and cut at the first contact: the
1658
+ // furthest free pose before it (none when the group cannot move at all), so a blocked group ends up touching, and the
1659
+ // obstacles it runs into just beyond; `target` and none when the whole way is free. Undefined when the way turns the group.
1660
+ }, {
1661
+ key: "slideToContact",
1662
+ value: function slideToContact(drag, target) {
1663
+ if (Math.abs(index.getTurnDeg(drag.current.rotDeg, target.rotDeg)) > 0.01) return undefined;
1664
+ var from = drag.current.center;
1665
+ var at = function at(s) {
1666
+ return {
1667
+ center: {
1668
+ x: from.x + (target.center.x - from.x) * s,
1669
+ z: from.z + (target.center.z - from.z) * s
1670
+ },
1671
+ rotDeg: target.rotDeg
1672
+ };
1673
+ };
1674
+ var steps = Math.max(1, Math.ceil(Math.hypot(target.center.x - from.x, target.center.z - from.z) / PATH_STEP));
1675
+ var free = 0;
1676
+ for (var step = 1; step <= steps; step++) {
1677
+ var blocked = step / steps;
1678
+ if (!this.isBlocked(drag, at(blocked))) {
1679
+ free = blocked;
1680
+ continue;
1681
+ }
1682
+ for (var i = 0; i < 12; i++) {
1683
+ var mid = (free + blocked) / 2;
1684
+ if (this.isBlocked(drag, at(mid))) blocked = mid;else free = mid;
1685
+ }
1686
+ return {
1687
+ pose: free > 0 ? at(free) : undefined,
1688
+ blockers: this.blockersAt(drag, at(blocked))
1689
+ };
1690
+ }
1691
+ return {
1692
+ pose: target,
1693
+ blockers: []
1694
+ };
1695
+ }
1696
+
1697
+ // The group follows the grabbed element rigidly to the wall or inside-room pose of the raw centre, also where it runs
1698
+ // into an obstacle: what it runs into there is kept as `blockedBy` (the viewer shows the drag blocked, a release there
1699
+ // goes back to the start). A forced group that fits on no wall is kept inside the room like a free one. Back at the
1700
+ // start (a cancel, a blocked release) it stands exactly where it started, nothing snaps.
1701
+ }, {
1702
+ key: "updateRoomDrag",
1703
+ value: function updateRoomDrag(room, drag, deltaMove) {
1704
+ drag.dx += deltaMove.x;
1705
+ drag.dz += deltaMove.z;
1706
+ var _drag$start2 = drag.start,
1707
+ block = _drag$start2.block,
1708
+ rotDeg = _drag$start2.rotDeg;
1709
+ var rawCenter = {
1710
+ x: drag.start.center.x + drag.dx,
1711
+ z: drag.start.center.z + drag.dz
1712
+ };
1713
+ var atStart = Math.hypot(drag.dx, drag.dz) <= START_NOISE;
1714
+ // A free slot place near the pointer comes before the wall.
1715
+ var slotPose = atStart ? undefined : this.getSlotSnapPose(drag);
1716
+ var wallPose = atStart || slotPose || drag.wallMode === 'free' ? null : index.bindToWalls(rawCenter, block, room);
1717
+ var snapsToWall = !!wallPose && Math.hypot(wallPose.center.x - rawCenter.x, wallPose.center.z - rawCenter.z) <= WALL_SNAP_DISTANCE;
1718
+ var startPose = {
1719
+ center: drag.start.center,
1720
+ rotDeg: rotDeg
1721
+ };
1722
+ var wanted = atStart ? startPose : slotPose !== null && slotPose !== void 0 ? slotPose : wallPose && (drag.wallMode === 'forced' || snapsToWall) ? wallPose : insidePose(block, {
1723
+ center: rawCenter,
1724
+ rotDeg: rotDeg
1725
+ }, room);
1726
+ drag.blockedBy = this.blockersAt(drag, wanted);
1727
+ index.moveGroupRigidly([].concat(_toConsumableArray__default["default"](drag.members), _toConsumableArray__default["default"](drag.followers)), drag.current, wanted);
1728
+ drag.current = wanted;
1729
+ drag.slotSnapped = !!slotPose;
1730
+ // A pair that overlapped at the start may only come apart, never go back in.
1731
+ if (drag.startOverlaps.size === 0) return;
1732
+ var moved = this.movedShapes(drag, wanted);
1733
+ drag.startOverlaps.forEach(function (depths, obstacle) {
1734
+ return drag.startOverlaps.set(obstacle, depths.map(function (depth, i) {
1735
+ return Math.min(depth, index.bodiesOverlap(moved[i].shape, obstacle.shape));
1736
+ }));
1737
+ });
1738
+ }
1739
+
1740
+ // The unit moved rigidly onto the nearest dock of `element` outside it (see findDockSnap), else with `slots` into the
1741
+ // nearest free slot place (see findSlotSnap).
1742
+ }, {
1743
+ key: "snapToDock",
1744
+ value: function snapToDock(element, unit, autoDockingDistance, slots) {
1745
+ var _this$findDockSnap2;
1746
+ var unitIds = unit.map(function (member) {
1747
+ return member.ElementId;
1748
+ });
1749
+ var snap = (_this$findDockSnap2 = this.findDockSnap(element, autoDockingDistance, unitIds)) !== null && _this$findDockSnap2 !== void 0 ? _this$findDockSnap2 : slots ? this.findSlotSnap(element) : null;
1750
+ if (!snap) return;
1751
+ var move = this.snapMove(element, snap);
1752
+ index.moveGroupRigidly(unit, move.from, move.to);
1753
+ }
1754
+
1755
+ // The unit of a drag starting at the element: in a room the drag's group, else the element (the viewer's UPDATEs add the
1756
+ // rest of its group), with the guests that go along; and the free slot places it may snap into.
1757
+ }, {
1758
+ key: "startDragUnit",
1759
+ value: function startDragUnit(elementId, roomDrag) {
1760
+ var _roomDrag$followers, _roomDrag$members$map;
1761
+ var element = this.plannerElements.get(elementId);
1762
+ var followers = (_roomDrag$followers = roomDrag === null || roomDrag === void 0 ? void 0 : roomDrag.followers) !== null && _roomDrag$followers !== void 0 ? _roomDrag$followers : element ? this.getFollowers(this.getDockingGroupOf(element)) : [];
1763
+ this.dragFollowers = new Set(followers.map(function (follower) {
1764
+ return follower.ElementId;
1765
+ }));
1766
+ this.dragUnit = new Set([elementId].concat(_toConsumableArray__default["default"]((_roomDrag$members$map = roomDrag === null || roomDrag === void 0 ? void 0 : roomDrag.members.map(function (member) {
1767
+ return member.ElementId;
1768
+ })) !== null && _roomDrag$members$map !== void 0 ? _roomDrag$members$map : []), _toConsumableArray__default["default"](this.dragFollowers)));
1769
+ var unit = element ? [].concat(_toConsumableArray__default["default"](this.getDockingGroupOf(element)), _toConsumableArray__default["default"](followers)) : [];
1770
+ this.dragSlots = element ? {
1771
+ elementId: elementId,
1772
+ start: index.poseOf(element).center,
1773
+ places: this.findDragSlotPlaces(element, unit)
1774
+ } : undefined;
1775
+ }
1776
+
1777
+ // Where the group shows against where the pointer put the grabbed element, and what it runs into there.
1778
+ }, {
1779
+ key: "getRoomDragPreview",
1780
+ value: function getRoomDragPreview(element, drag) {
1781
+ var position = element.WorldPosCenter;
1782
+ var preview = {
1783
+ dx: position.x - (drag.grabbedStart.x + drag.dx),
1784
+ dz: position.z - (drag.grabbedStart.z + drag.dz),
1785
+ dRotDeg: index.getTurnDeg(drag.start.rotDeg, element.RotDeg)
1786
+ };
1787
+ return this.withDragBlock(preview, drag);
1788
+ }
1789
+
1790
+ // What a free group being turned runs into where it is turned now (it moves no further than the turn: no offset). Only
1791
+ // its members count: a guest swung into a body leaves its carrier on release instead (see DivaPlannerHandler).
1792
+ }, {
1793
+ key: "getRoomTurnPreview",
1794
+ value: function getRoomTurnPreview(element, drag) {
1795
+ var members = _objectSpread(_objectSpread({}, drag), {}, {
1796
+ shapes: drag.shapes.slice(0, drag.memberShapes)
1797
+ });
1798
+ drag.blockedBy = this.blockersAt(members, this.getTurnedPose(element, drag));
1799
+ return this.withDragBlock({
1800
+ dx: 0,
1801
+ dz: 0,
1802
+ dRotDeg: 0
1803
+ }, drag);
1804
+ }
1805
+
1806
+ // A blocked turn's release: at its angle, the nearest free place inside the room within reach; undefined when none.
1807
+ }, {
1808
+ key: "findTurnPlace",
1809
+ value: function findTurnPlace(element, drag, room) {
1810
+ var turned = this.getTurnedPose(element, drag);
1811
+ var block = drag.start.block;
1812
+ var members = _objectSpread(_objectSpread({}, drag), {}, {
1813
+ shapes: drag.shapes.slice(0, drag.memberShapes),
1814
+ current: turned
1815
+ });
1816
+ if (!this.isBlocked(members, turned)) return turned;
1817
+ var poseAt = function poseAt(raw) {
1818
+ return insidePose(block, {
1819
+ center: raw,
1820
+ rotDeg: turned.rotDeg
1821
+ }, room);
1822
+ };
1823
+ return this.nearestFreePose(members, turned, poseAt, Math.max(TURN_PLACE_REACH, 2 * Math.max(block.halfWidth, block.halfDepth)));
1824
+ }
1825
+
1826
+ // The pose of the group's block where the grabbed element stands now, moved with it rigidly from the start.
1827
+ }, {
1828
+ key: "getTurnedPose",
1829
+ value: function getTurnedPose(element, drag) {
1830
+ return movePose(drag.start, {
1831
+ center: drag.grabbedStart,
1832
+ rotDeg: drag.grabbedStartRotDeg
1833
+ }, index.poseOf(element));
1834
+ }
1835
+
1836
+ // `preview` with what the group runs into (`blockedBy`): the elements, and whether a door's clearance; as it is while free.
1837
+ }, {
1838
+ key: "withDragBlock",
1839
+ value: function withDragBlock(preview, drag) {
1840
+ if (drag.blockedBy.length === 0) return preview;
1841
+ var ownSetId = this.set.getSetId();
1842
+ var elements = [];
1843
+ var _iterator13 = _createForOfIteratorHelper(drag.blockedBy),
1844
+ _step13;
1845
+ try {
1846
+ var _loop2 = function _loop2() {
1847
+ var _step13$value = _step13.value,
1848
+ _step13$value$setId = _step13$value.setId,
1849
+ setId = _step13$value$setId === void 0 ? ownSetId : _step13$value$setId,
1850
+ elementId = _step13$value.elementId;
1851
+ if (elementId !== undefined && !elements.some(function (element) {
1852
+ return element.setId === setId && element.elementId === elementId;
1853
+ })) elements.push({
1854
+ setId: setId,
1855
+ elementId: elementId
1856
+ });
1857
+ };
1858
+ for (_iterator13.s(); !(_step13 = _iterator13.n()).done;) {
1859
+ _loop2();
1860
+ }
1861
+ } catch (err) {
1862
+ _iterator13.e(err);
1863
+ } finally {
1864
+ _iterator13.f();
1865
+ }
1866
+ return _objectSpread(_objectSpread({}, preview), {}, {
1867
+ blockedBy: {
1868
+ elements: elements,
1869
+ door: drag.blockedBy.some(function (obstacle) {
1870
+ return obstacle.elementId === undefined;
1871
+ })
1872
+ }
1873
+ });
1874
+ }
1875
+
331
1876
  /**
332
1877
  * This function updates the position information of all elements. It is called after updating the SVG of 1 element.
333
1878
  * The position is updated based on the posNr.
@@ -385,11 +1930,11 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
385
1930
  var progressed = true;
386
1931
  while (progressed) {
387
1932
  progressed = false;
388
- var _iterator = _createForOfIteratorHelper(sortedPlannerElementsbyPosNr),
389
- _step;
1933
+ var _iterator14 = _createForOfIteratorHelper(sortedPlannerElementsbyPosNr),
1934
+ _step14;
390
1935
  try {
391
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
392
- var _element = _step.value;
1936
+ for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
1937
+ var _element = _step14.value;
393
1938
  if (!_element || moved.has(_element.ElementId)) continue;
394
1939
  var dpToMovedPartner = getDockedDPsInPriorityOrder(_element).find(function (dp) {
395
1940
  return moved.has(dp.OnElementId);
@@ -401,9 +1946,9 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
401
1946
  }
402
1947
  }
403
1948
  } catch (err) {
404
- _iterator.e(err);
1949
+ _iterator14.e(err);
405
1950
  } finally {
406
- _iterator.f();
1951
+ _iterator14.f();
407
1952
  }
408
1953
  }
409
1954
  }
@@ -424,8 +1969,10 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
424
1969
  key: "addElementToWorld",
425
1970
  value: (function () {
426
1971
  var _addElementToWorld = _asyncToGenerator__default["default"](/*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee(plannerElement, dockingPointInfos, suppressDock, globalBoundingBox) {
1972
+ var _this21 = this;
427
1973
  var xOffset,
428
1974
  setToTransform,
1975
+ placedBeside,
429
1976
  _setToTransform$trans,
430
1977
  worldPosCenter,
431
1978
  height,
@@ -438,16 +1985,22 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
438
1985
  targetDP,
439
1986
  successDP,
440
1987
  success,
441
- allPlannerElements,
1988
+ selectedId,
1989
+ atSelected,
1990
+ mayPlace,
1991
+ placed,
442
1992
  _success,
1993
+ allPlannerElements,
443
1994
  _args = arguments;
444
1995
  return _regeneratorRuntime__default["default"].wrap(function _callee$(_context) {
445
1996
  while (1) switch (_context.prev = _context.next) {
446
1997
  case 0:
447
1998
  xOffset = _args.length > 4 && _args[4] !== undefined ? _args[4] : 100;
448
1999
  setToTransform = _args.length > 5 ? _args[5] : undefined;
2000
+ // Docked to nothing: put beside the planning, where it may land on another group in the room.
2001
+ placedBeside = false;
449
2002
  if (!(setToTransform && setToTransform.forceSetToTrans)) {
450
- _context.next = 10;
2003
+ _context.next = 13;
451
2004
  break;
452
2005
  }
453
2006
  // A switched element keeps the place of the old one; if that stood on the floor, the new one stands there too.
@@ -455,64 +2008,66 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
455
2008
  stoodOnFloor = index.PlannerElementData.standsOnFloor(worldPosCenter.y, height);
456
2009
  plannerElement.WorldPosCenter = stoodOnFloor && Number.isFinite(plannerElement.Height) ? new index.Vector3(worldPosCenter.x, plannerElement.Height / 2, worldPosCenter.z) : worldPosCenter;
457
2010
  plannerElement.RotDeg = setToTransform.transform.rotDeg;
2011
+ plannerElement.PosNrAtEnd = !!setToTransform.transform.posNrAtEnd;
2012
+ plannerElement.Placement = setToTransform.transform.placement;
458
2013
  this.set.onDockingChanged(plannerElement.ElementId, -1, 'NOT_DOCKED');
459
- _context.next = 50;
2014
+ _context.next = 52;
460
2015
  break;
461
- case 10:
2016
+ case 13:
462
2017
  //Nun unterscheidet man, ob man das Element zu einem bestimmten vorselektierten Element Docken will , zu einem vorselektierten DockingPoint oder an eine Freie Planung.
463
2018
  dockingFound = false;
464
2019
  if (!dockingPointInfos) {
465
- _context.next = 49;
2020
+ _context.next = 51;
466
2021
  break;
467
2022
  }
468
2023
  i = 0;
469
- case 13:
2024
+ case 16:
470
2025
  if (!(i < dockingPointInfos.length)) {
471
- _context.next = 49;
2026
+ _context.next = 51;
472
2027
  break;
473
2028
  }
474
2029
  targetElemIdToDock = dockingPointInfos[i].targetElemIdToDock;
475
2030
  targetDockingPointId = dockingPointInfos[i].targetDockingPointId;
476
2031
  if (!(targetElemIdToDock && targetElemIdToDock > -1 && this.plannerElements.has(targetElemIdToDock))) {
477
- _context.next = 46;
2032
+ _context.next = 48;
478
2033
  break;
479
2034
  }
480
2035
  if (!(targetDockingPointId && targetDockingPointId != '')) {
481
- _context.next = 34;
2036
+ _context.next = 37;
482
2037
  break;
483
2038
  }
484
2039
  targetElem = this.plannerElements.get(targetElemIdToDock);
485
2040
  if (!targetElem) {
486
- _context.next = 32;
2041
+ _context.next = 35;
487
2042
  break;
488
2043
  }
489
2044
  targetDP = targetElem.getDockingPointById(targetDockingPointId);
490
2045
  if (!targetDP) {
491
- _context.next = 32;
2046
+ _context.next = 35;
492
2047
  break;
493
2048
  }
494
2049
  successDP = PlannerHandler2D.dockingPointHandlerInst.tryDockElementToDP(plannerElement, targetElem, targetDP);
495
2050
  if (!successDP) {
496
- _context.next = 28;
2051
+ _context.next = 31;
497
2052
  break;
498
2053
  }
499
2054
  this.updateWorldPos(plannerElement, successDP);
500
2055
  dockingFound = true;
501
- _context.next = 32;
2056
+ _context.next = 35;
502
2057
  break;
503
- case 28:
504
- _context.next = 30;
2058
+ case 31:
2059
+ _context.next = 33;
505
2060
  return this.tryToDockWithDifferentSVGWithFormula(plannerElement, targetElemIdToDock);
506
- case 30:
2061
+ case 33:
507
2062
  if (!_context.sent) {
508
- _context.next = 32;
2063
+ _context.next = 35;
509
2064
  break;
510
2065
  }
511
2066
  dockingFound = true;
512
- case 32:
513
- _context.next = 46;
2067
+ case 35:
2068
+ _context.next = 48;
514
2069
  break;
515
- case 34:
2070
+ case 37:
516
2071
  success = false;
517
2072
  if (plannerElement.HasAVL || plannerElement.HasAVR) {
518
2073
  success = this.dockToAVLorAVR(plannerElement, [this.plannerElements.get(targetElemIdToDock)]);
@@ -521,55 +2076,72 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
521
2076
  success = this.dockToAVUorAVOororAVNorAVSorAVC(plannerElement, [this.plannerElements.get(targetElemIdToDock)]);
522
2077
  }
523
2078
  if (success) {
524
- _context.next = 45;
2079
+ _context.next = 47;
525
2080
  break;
526
2081
  }
527
- _context.next = 40;
2082
+ _context.next = 43;
528
2083
  return this.tryToDockWithDifferentSVGWithFormula(plannerElement, targetElemIdToDock);
529
- case 40:
2084
+ case 43:
530
2085
  success = _context.sent;
531
2086
  if (success) {
532
- _context.next = 45;
2087
+ _context.next = 47;
533
2088
  break;
534
2089
  }
535
- _context.next = 44;
536
- return this.addElementToWorld(plannerElement, undefined, undefined, undefined, 50);
537
- case 44:
538
- return _context.abrupt("return");
539
- case 45:
2090
+ xOffset = 50;
2091
+ return _context.abrupt("break", 51);
2092
+ case 47:
540
2093
  if (success) dockingFound = true;
541
- case 46:
2094
+ case 48:
542
2095
  i++;
543
- _context.next = 13;
2096
+ _context.next = 16;
544
2097
  break;
545
- case 49:
2098
+ case 51:
546
2099
  if (!dockingFound) {
547
- allPlannerElements = this.getAllPlannerElements();
548
- _success = this.dockToAVLorAVR(plannerElement, allPlannerElements);
549
- if (suppressDock) _success = false;
550
- if (!_success) {
551
- //No free AVR or AVL Docking Point
552
- _success = this.dockToAVUorAVOororAVNorAVSorAVC(plannerElement, allPlannerElements);
2100
+ selectedId = dockingPointInfos === null || dockingPointInfos === void 0 ? void 0 : dockingPointInfos.map(function (info) {
2101
+ return info.targetElemIdToDock;
2102
+ }).find(function (id) {
2103
+ return id != null && _this21.plannerElements.has(id);
2104
+ });
2105
+ atSelected = function atSelected(group) {
2106
+ return selectedId === undefined || group.some(function (member) {
2107
+ return member.ElementId === selectedId;
2108
+ });
2109
+ };
2110
+ mayPlace = globalBoundingBox == undefined; // The places the rules suggest at the selected group (without a selection: at any group) come before docking anywhere.
2111
+ placed = mayPlace && this.placeAtSuggestedPlace(plannerElement, atSelected);
2112
+ _success = false;
2113
+ if (!placed) {
2114
+ allPlannerElements = this.getAllPlannerElements();
2115
+ _success = this.dockToAVLorAVR(plannerElement, allPlannerElements);
553
2116
  if (suppressDock) _success = false;
554
2117
  if (!_success) {
555
- //This is the center position of the element - This is needed in order to set the static room layout correctly
556
-
557
- if (globalBoundingBox == undefined) {
558
- plannerElement.WorldPosCenter = new index.Vector3(this.plannerBoundingBox.WorldPos.x + this.plannerBoundingBox.Size.x + (this.plannerBoundingBox.Size.x == 0 ? 0 : plannerElement.Width / 2 + xOffset), this.plannerBoundingBox.WorldPos.y, this.plannerBoundingBox.WorldPos.z + plannerElement.Depth / 2);
559
- }
560
-
561
- //Tell the set this the element was not docked
562
- this.set.onDockingChanged(plannerElement.ElementId, -1, 'NOT_DOCKED');
2118
+ //No free AVR or AVL Docking Point
2119
+ _success = this.dockToAVUorAVOororAVNorAVSorAVC(plannerElement, allPlannerElements);
2120
+ if (suppressDock) _success = false;
563
2121
  }
2122
+ if (!_success && mayPlace && selectedId !== undefined) placed = this.placeAtSuggestedPlace(plannerElement, function (group) {
2123
+ return !atSelected(group);
2124
+ });
2125
+ }
2126
+ if (!_success) {
2127
+ //This is the center position of the element - This is needed in order to set the static room layout correctly
2128
+ if (mayPlace && !placed) {
2129
+ placedBeside = true;
2130
+ plannerElement.WorldPosCenter = new index.Vector3(this.plannerBoundingBox.WorldPos.x + this.plannerBoundingBox.Size.x + (this.plannerBoundingBox.Size.x == 0 ? 0 : plannerElement.Width / 2 + xOffset), this.plannerBoundingBox.WorldPos.y, this.plannerBoundingBox.WorldPos.z + plannerElement.Depth / 2);
2131
+ }
2132
+
2133
+ //Tell the set this the element was not docked
2134
+ this.set.onDockingChanged(plannerElement.ElementId, -1, 'NOT_DOCKED');
564
2135
  }
565
2136
  }
566
- case 50:
2137
+ case 52:
567
2138
  this.updatePlannerPosNr();
568
2139
  this.updateAllElementsWorldPos();
569
2140
  this.updatePlannerPosNr();
2141
+ if (!plannerElement.IsAccessoire) this.placeAddedInRoom([plannerElement], placedBeside);
570
2142
  this.checkCollision(false, plannerElement.getElementId());
571
2143
  this.updatePlannerBoundingBox();
572
- case 55:
2144
+ case 58:
573
2145
  case "end":
574
2146
  return _context.stop();
575
2147
  }
@@ -757,16 +2329,16 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
757
2329
  var candidates = [];
758
2330
  var seen = new Set();
759
2331
  var collect = function collect(connectorFeature, targetFilters) {
760
- var _iterator2 = _createForOfIteratorHelper(targetFilters),
761
- _step2;
2332
+ var _iterator15 = _createForOfIteratorHelper(targetFilters),
2333
+ _step15;
762
2334
  try {
763
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
764
- var filter = _step2.value;
765
- var _iterator3 = _createForOfIteratorHelper(article.getVariantValuesInfluencingOptions([optPrefix + connectorFeature], opvPrefix + filter)),
766
- _step3;
2335
+ for (_iterator15.s(); !(_step15 = _iterator15.n()).done;) {
2336
+ var filter = _step15.value;
2337
+ var _iterator16 = _createForOfIteratorHelper(article.getVariantValuesInfluencingOptions([optPrefix + connectorFeature], opvPrefix + filter)),
2338
+ _step16;
767
2339
  try {
768
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
769
- var vv = _step3.value;
2340
+ for (_iterator16.s(); !(_step16 = _iterator16.n()).done;) {
2341
+ var vv = _step16.value;
770
2342
  var key = JSON.stringify(vv);
771
2343
  if (!seen.has(key)) {
772
2344
  seen.add(key);
@@ -774,15 +2346,15 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
774
2346
  }
775
2347
  }
776
2348
  } catch (err) {
777
- _iterator3.e(err);
2349
+ _iterator16.e(err);
778
2350
  } finally {
779
- _iterator3.f();
2351
+ _iterator16.f();
780
2352
  }
781
2353
  }
782
2354
  } catch (err) {
783
- _iterator2.e(err);
2355
+ _iterator15.e(err);
784
2356
  } finally {
785
- _iterator2.f();
2357
+ _iterator15.f();
786
2358
  }
787
2359
  };
788
2360
  //this article's AVL side (feature 89) docks against the target's AVR side and vice versa
@@ -1010,6 +2582,11 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1010
2582
  }
1011
2583
  }
1012
2584
  this.updateAllElementsWorldPos(undefined, elemtsWhereSomethingChanged);
2585
+ // A resized group must not reach through a wall; where the room moved it, its collisions are checked again.
2586
+ if (this.room) {
2587
+ this.placeGroupsInRoom();
2588
+ this.checkCollision(false);
2589
+ }
1013
2590
  this.updatePlannerPosNr();
1014
2591
  this.updatePlannerBoundingBox();
1015
2592
  }
@@ -1043,9 +2620,9 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1043
2620
  return _regeneratorRuntime__default["default"].wrap(function _callee5$(_context5) {
1044
2621
  while (1) switch (_context5.prev = _context5.next) {
1045
2622
  case 0:
1046
- planData = parseSetPlanData(setPlanData);
1047
- if (!isSavePlannerV2(planData)) {
1048
- _context5.next = 39;
2623
+ planData = index.parseSetPlanData(setPlanData);
2624
+ if (!index.isSavePlannerV2(planData)) {
2625
+ _context5.next = 42;
1049
2626
  break;
1050
2627
  }
1051
2628
  jsonElements = planData.set.elements;
@@ -1055,12 +2632,12 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1055
2632
  i = 0;
1056
2633
  case 7:
1057
2634
  if (!(i < jsonElements.length)) {
1058
- _context5.next = 35;
2635
+ _context5.next = 37;
1059
2636
  break;
1060
2637
  }
1061
2638
  _context5.prev = 8;
1062
2639
  jsonElement = jsonElements[i];
1063
- catalogArticle = (_this$set$getArticleB = (_this$set$getArticleB2 = this.set.getArticleByBasketId(jsonElement.basketID)) === null || _this$set$getArticleB2 === void 0 ? void 0 : _this$set$getArticleB2.catalogArticle) !== null && _this$set$getArticleB !== void 0 ? _this$set$getArticleB : this.set.CatalogData.getCatalogArticleByArticleCodex((_saveElementArticleCo = saveElementArticleCodex(jsonElement)) !== null && _saveElementArticleCo !== void 0 ? _saveElementArticleCo : '');
2640
+ catalogArticle = (_this$set$getArticleB = (_this$set$getArticleB2 = this.set.getArticleByBasketId(jsonElement.basketID)) === null || _this$set$getArticleB2 === void 0 ? void 0 : _this$set$getArticleB2.catalogArticle) !== null && _this$set$getArticleB !== void 0 ? _this$set$getArticleB : this.set.CatalogData.getCatalogArticleByArticleCodex((_saveElementArticleCo = index.saveElementArticleCodex(jsonElement)) !== null && _saveElementArticleCo !== void 0 ? _saveElementArticleCo : '');
1064
2641
  if (!(!catalogArticle && (_jsonElement$Accessoi = jsonElement.AccessoireInitParams) !== null && _jsonElement$Accessoi !== void 0 && _jsonElement$Accessoi.RelatedToBasketID && !this.set.getSetState.onlyRunLogic)) {
1065
2642
  _context5.next = 14;
1066
2643
  break;
@@ -1068,7 +2645,7 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1068
2645
  LOG.error(new DivaUtils.DivaError('Error initializing element nr ' + i + ' in the Standard Web Planner. PlanData V2', {
1069
2646
  code: 'WC_0012'
1070
2647
  }));
1071
- return _context5.abrupt("continue", 32);
2648
+ return _context5.abrupt("continue", 34);
1072
2649
  case 14:
1073
2650
  plannerElement = new index.PlannerElementData(this.set.getSetId(), jsonElement.basketID, this.nextElementId, DivaStandardPlanner.plannerType);
1074
2651
  oldElementidMapping.set(jsonElement.elementID, plannerElement);
@@ -1086,6 +2663,8 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1086
2663
  case 24:
1087
2664
  plannerElement.WorldPosCenter = new index.Vector3(globalBoundingBox.WorldPos.x + globalBoundingBox.Size.x + jsonElement.x + 100, globalBoundingBox.WorldPos.y + jsonElement.y, globalBoundingBox.WorldPos.z + jsonElement.z);
1088
2665
  plannerElement.RotDeg = jsonElement.rot;
2666
+ plannerElement.PosNrAtEnd = !!jsonElement.posNrAtEnd;
2667
+ plannerElement.Placement = index.parseGuestPlacement(jsonElement.placement);
1089
2668
  if (plannerElement.IsDockedAccessoire) {
1090
2669
  accElements.push(jsonElement);
1091
2670
  plannerElement.PosNr = jsonElement.posNr;
@@ -1094,20 +2673,20 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1094
2673
  elementsSortedbyPosNr[jsonElement.posNr - 1] = jsonElement;
1095
2674
  plannerElement.PosNr = jsonElement.posNr;
1096
2675
  }
1097
- _context5.next = 32;
2676
+ _context5.next = 34;
1098
2677
  break;
1099
- case 29:
1100
- _context5.prev = 29;
2678
+ case 31:
2679
+ _context5.prev = 31;
1101
2680
  _context5.t0 = _context5["catch"](8);
1102
2681
  LOG.error(new DivaUtils.DivaError('Error initializing element nr ' + i + ' in the Standard Web Planner. PlanData V2', {
1103
2682
  cause: _context5.t0,
1104
2683
  code: 'WC_0012'
1105
2684
  }));
1106
- case 32:
2685
+ case 34:
1107
2686
  i++;
1108
2687
  _context5.next = 7;
1109
2688
  break;
1110
- case 35:
2689
+ case 37:
1111
2690
  elementsForDockingExtend = [].concat(_toConsumableArray__default["default"](elementsSortedbyPosNr.filter(function (e) {
1112
2691
  return e != null;
1113
2692
  })), accElements);
@@ -1129,17 +2708,19 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1129
2708
  }
1130
2709
  }
1131
2710
  }
1132
- _context5.next = 40;
2711
+ // Added beside the planning, the new elements can stand outside the room: they get the room rules like an insert.
2712
+ this.placeAddedInRoom(_toConsumableArray__default["default"](oldElementidMapping.values()), true);
2713
+ _context5.next = 43;
1133
2714
  break;
1134
- case 39:
2715
+ case 42:
1135
2716
  LOG.error(new DivaUtils.DivaError('The function extend Planner works only with products that are saved in the configurator 2.0', {
1136
2717
  code: 'WC_0012'
1137
2718
  }));
1138
- case 40:
2719
+ case 43:
1139
2720
  case "end":
1140
2721
  return _context5.stop();
1141
2722
  }
1142
- }, _callee5, this, [[8, 29]]);
2723
+ }, _callee5, this, [[8, 31]]);
1143
2724
  }));
1144
2725
  function extendPlanner(_x10, _x11) {
1145
2726
  return _extendPlanner.apply(this, arguments);
@@ -1154,9 +2735,9 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1154
2735
  return _regeneratorRuntime__default["default"].wrap(function _callee6$(_context6) {
1155
2736
  while (1) switch (_context6.prev = _context6.next) {
1156
2737
  case 0:
1157
- planData = parseSetPlanData(setPlanData);
1158
- if (!isSavePlannerV2(planData)) {
1159
- _context6.next = 63;
2738
+ planData = index.parseSetPlanData(setPlanData);
2739
+ if (!index.isSavePlannerV2(planData)) {
2740
+ _context6.next = 65;
1160
2741
  break;
1161
2742
  }
1162
2743
  LOG.debug('Initialize set Plan Data - V2\n' + planData, 'DivaStandardPlanner initPlanner');
@@ -1172,12 +2753,12 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1172
2753
  i = 0;
1173
2754
  case 9:
1174
2755
  if (!(i < jsonElements.length)) {
1175
- _context6.next = 37;
2756
+ _context6.next = 39;
1176
2757
  break;
1177
2758
  }
1178
2759
  _context6.prev = 10;
1179
2760
  jsonElement = jsonElements[i];
1180
- catalogArticle = (_this$set$getArticleB3 = (_this$set$getArticleB4 = this.set.getArticleByBasketId(jsonElement.basketID)) === null || _this$set$getArticleB4 === void 0 ? void 0 : _this$set$getArticleB4.catalogArticle) !== null && _this$set$getArticleB3 !== void 0 ? _this$set$getArticleB3 : this.set.CatalogData.getCatalogArticleByArticleCodex((_saveElementArticleCo2 = saveElementArticleCodex(jsonElement)) !== null && _saveElementArticleCo2 !== void 0 ? _saveElementArticleCo2 : '');
2761
+ catalogArticle = (_this$set$getArticleB3 = (_this$set$getArticleB4 = this.set.getArticleByBasketId(jsonElement.basketID)) === null || _this$set$getArticleB4 === void 0 ? void 0 : _this$set$getArticleB4.catalogArticle) !== null && _this$set$getArticleB3 !== void 0 ? _this$set$getArticleB3 : this.set.CatalogData.getCatalogArticleByArticleCodex((_saveElementArticleCo2 = index.saveElementArticleCodex(jsonElement)) !== null && _saveElementArticleCo2 !== void 0 ? _saveElementArticleCo2 : '');
1181
2762
  if (!(!catalogArticle && (_jsonElement$Accessoi2 = jsonElement.AccessoireInitParams) !== null && _jsonElement$Accessoi2 !== void 0 && _jsonElement$Accessoi2.RelatedToBasketID && !this.set.getSetState.onlyRunLogic)) {
1182
2763
  _context6.next = 16;
1183
2764
  break;
@@ -1185,7 +2766,7 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1185
2766
  LOG.error(new DivaUtils.DivaError('Error initializing element nr ' + i + ' in the Standard Web Planner. PlanData V2', {
1186
2767
  code: 'WC_0012'
1187
2768
  }));
1188
- return _context6.abrupt("continue", 34);
2769
+ return _context6.abrupt("continue", 36);
1189
2770
  case 16:
1190
2771
  elementID = jsonElement.elementID;
1191
2772
  plannerElement = new index.PlannerElementData(this.set.getSetId(), jsonElement.basketID, elementID, DivaStandardPlanner.plannerType);
@@ -1205,6 +2786,8 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1205
2786
  //plannerElement.WorldPosCenter = new Vector3(jsonElement.x, jsonElement.y, jsonElement.z);
1206
2787
  plannerElement.WorldPosCenter = new index.Vector3(this.plannerBoundingBox.WorldPos.x + jsonElement.x, this.plannerBoundingBox.WorldPos.y + jsonElement.y, this.plannerBoundingBox.WorldPos.z + jsonElement.z);
1207
2788
  plannerElement.RotDeg = jsonElement.rot;
2789
+ plannerElement.PosNrAtEnd = !!jsonElement.posNrAtEnd;
2790
+ plannerElement.Placement = index.parseGuestPlacement(jsonElement.placement);
1208
2791
  if (plannerElement.IsDockedAccessoire) {
1209
2792
  accElements.push(jsonElement);
1210
2793
  plannerElement.PosNr = jsonElement.posNr;
@@ -1213,34 +2796,34 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1213
2796
  elementsSortedbyPosNr[jsonElement.posNr - 1] = jsonElement;
1214
2797
  plannerElement.PosNr = jsonElement.posNr;
1215
2798
  }
1216
- _context6.next = 34;
2799
+ _context6.next = 36;
1217
2800
  break;
1218
- case 31:
1219
- _context6.prev = 31;
2801
+ case 33:
2802
+ _context6.prev = 33;
1220
2803
  _context6.t0 = _context6["catch"](10);
1221
2804
  LOG.error(new DivaUtils.DivaError('Error initializing element nr ' + i + ' in the Standard Web Planner. PlanData V2', {
1222
2805
  cause: _context6.t0,
1223
2806
  code: 'WC_0012'
1224
2807
  }));
1225
- case 34:
2808
+ case 36:
1226
2809
  i++;
1227
2810
  _context6.next = 9;
1228
2811
  break;
1229
- case 37:
2812
+ case 39:
1230
2813
  onlyOneBaseElement = elementsSortedbyPosNr.filter(Boolean).length == 1; //Saves if only one base element is in the planning. All the others are only accessoires
1231
2814
  elementsForDocking = [].concat(_toConsumableArray__default["default"](elementsSortedbyPosNr.filter(function (e) {
1232
2815
  return e != null;
1233
2816
  })), accElements);
1234
2817
  i = 0;
1235
- case 40:
2818
+ case 42:
1236
2819
  if (!(i < elementsForDocking.length)) {
1237
- _context6.next = 61;
2820
+ _context6.next = 63;
1238
2821
  break;
1239
2822
  }
1240
- _context6.prev = 41;
2823
+ _context6.prev = 43;
1241
2824
  row = elementsForDocking[i];
1242
2825
  if (!(i == 0 && onlyOneBaseElement && this.plannerHasStaticBackground)) {
1243
- _context6.next = 48;
2826
+ _context6.next = 50;
1244
2827
  break;
1245
2828
  }
1246
2829
  //if the planner has a static background room and there is only one base element (ignore docked ACCs) then it should be forced positioned in the center of the room.
@@ -1252,14 +2835,14 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1252
2835
  element = this.plannerElements.get(row.elementID);
1253
2836
  if (element) element.WorldPosCenter = new index.Vector3(0, element.Height / 2, element.Depth / 2);
1254
2837
  }
1255
- return _context6.abrupt("continue", 58);
1256
- case 48:
2838
+ return _context6.abrupt("continue", 60);
2839
+ case 50:
1257
2840
  if (!(row.DP == null || row.DP.length == 0)) {
1258
- _context6.next = 50;
2841
+ _context6.next = 52;
1259
2842
  break;
1260
2843
  }
1261
- return _context6.abrupt("continue", 58);
1262
- case 50:
2844
+ return _context6.abrupt("continue", 60);
2845
+ case 52:
1263
2846
  DPsInfo = row.DP;
1264
2847
  for (j = 0; j < DPsInfo.length; j++) {
1265
2848
  dpInfo = DPsInfo[j];
@@ -1280,79 +2863,79 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1280
2863
  }
1281
2864
  }
1282
2865
  }
1283
- _context6.next = 58;
2866
+ _context6.next = 60;
1284
2867
  break;
1285
- case 54:
1286
- _context6.prev = 54;
1287
- _context6.t1 = _context6["catch"](41);
2868
+ case 56:
2869
+ _context6.prev = 56;
2870
+ _context6.t1 = _context6["catch"](43);
1288
2871
  elementId = (_elementsForDocking$i = elementsForDocking[i]) === null || _elementsForDocking$i === void 0 ? void 0 : _elementsForDocking$i.elementID;
1289
2872
  LOG.error(new DivaUtils.DivaError('Error initializing dockingPoints of element with elementID ' + elementId, {
1290
2873
  cause: _context6.t1,
1291
2874
  code: 'WC_0012'
1292
2875
  }));
1293
- case 58:
2876
+ case 60:
1294
2877
  i++;
1295
- _context6.next = 40;
1296
- break;
1297
- case 61:
1298
- _context6.next = 116;
2878
+ _context6.next = 42;
1299
2879
  break;
1300
2880
  case 63:
2881
+ _context6.next = 118;
2882
+ break;
2883
+ case 65:
1301
2884
  LOG.debug('Initialize set Plan Data - old V1\n' + planData, 'DivaStandardPlanner initPlanner');
1302
2885
  legacySet = (_planData$Sets = planData.Sets) === null || _planData$Sets === void 0 ? void 0 : _planData$Sets[0];
1303
2886
  if (legacySet !== null && legacySet !== void 0 && (_legacySet$Elements = legacySet.Elements) !== null && _legacySet$Elements !== void 0 && _legacySet$Elements.length) {
1304
- _context6.next = 67;
2887
+ _context6.next = 69;
1305
2888
  break;
1306
2889
  }
1307
2890
  return _context6.abrupt("return");
1308
- case 67:
2891
+ case 69:
1309
2892
  _jsonElements = legacySet.Elements;
1310
2893
  _elementsSortedbyPosNr = [];
1311
2894
  _accElements = []; //Zuerst initialisiere alle Elemente
1312
2895
  //Dann positioniere sie richtig
1313
2896
  i = 0;
1314
- case 71:
2897
+ case 73:
1315
2898
  if (!(i < _jsonElements.length)) {
1316
- _context6.next = 105;
2899
+ _context6.next = 107;
1317
2900
  break;
1318
2901
  }
1319
- _context6.prev = 72;
2902
+ _context6.prev = 74;
1320
2903
  _jsonElement2 = _jsonElements[i];
1321
- _catalogArticle = this.set.CatalogData.getCatalogArticleByArticleCodex((_saveElementArticleCo3 = saveElementArticleCodex(_jsonElement2)) !== null && _saveElementArticleCo3 !== void 0 ? _saveElementArticleCo3 : '');
2904
+ _catalogArticle = this.set.CatalogData.getCatalogArticleByArticleCodex((_saveElementArticleCo3 = index.saveElementArticleCodex(_jsonElement2)) !== null && _saveElementArticleCo3 !== void 0 ? _saveElementArticleCo3 : '');
1322
2905
  if (!(!_catalogArticle && (_jsonElement2$Accesso = _jsonElement2.AccessoireInitParams) !== null && _jsonElement2$Accesso !== void 0 && _jsonElement2$Accesso.RelatedToBasketID && !this.set.getSetState.onlyRunLogic)) {
1323
- _context6.next = 78;
2906
+ _context6.next = 80;
1324
2907
  break;
1325
2908
  }
1326
2909
  LOG.error(new DivaUtils.DivaError('Error initializing element nr ' + i + ' in the Standard Web Planner. PlanData V1', {
1327
2910
  code: 'WC_0012'
1328
2911
  }));
1329
- return _context6.abrupt("continue", 102);
1330
- case 78:
2912
+ return _context6.abrupt("continue", 104);
2913
+ case 80:
1331
2914
  basketID = _jsonElement2.BasketID;
1332
2915
  if (this.set.getElementId(basketID) == -1) this.set.setElementId(basketID, Number(_jsonElement2.ID));
1333
2916
  _elementId = this.set.getElementId(basketID);
1334
2917
  _jsonElement2.elementId = _elementId;
1335
2918
  if (!(_elementId == -1)) {
1336
- _context6.next = 85;
2919
+ _context6.next = 87;
1337
2920
  break;
1338
2921
  }
1339
2922
  LOG.error(new DivaUtils.DivaError('Error when initializing planner. The elementID Was not saved in the article. ', {
1340
2923
  code: 'WC_0012'
1341
2924
  }));
1342
- return _context6.abrupt("continue", 102);
1343
- case 85:
2925
+ return _context6.abrupt("continue", 104);
2926
+ case 87:
1344
2927
  _plannerElement = new index.PlannerElementData(this.set.getSetId(), basketID, _elementId, DivaStandardPlanner.plannerType);
1345
2928
  this.nextElementId = _elementId + 1;
1346
2929
  this.plannerElements.set(_plannerElement.ElementId, _plannerElement);
1347
2930
  _data = this.set.getPlannerData(_plannerElement.ElementId);
1348
2931
  _plannerElement.updatePlannerData(_data);
1349
2932
  if (this.doDisablePlanner2D) {
1350
- _context6.next = 93;
2933
+ _context6.next = 95;
1351
2934
  break;
1352
2935
  }
1353
- _context6.next = 93;
2936
+ _context6.next = 95;
1354
2937
  return PlannerHandler2D.handler2D.loadSVG(_plannerElement, this.set);
1355
- case 93:
2938
+ case 95:
1356
2939
  //Achtung die Pos Infos im alten Planer waren Zentrumskoordinaten!!! Nicht hinten oben.
1357
2940
  centerWorldPos = new index.Vector3(_jsonElement2.PosX, _jsonElement2.PosZ, _jsonElement2.PosY);
1358
2941
  _plannerElement.WorldPosCenter = new index.Vector3(this.plannerBoundingBox.WorldPos.x + centerWorldPos.x, this.plannerBoundingBox.WorldPos.y + centerWorldPos.y, this.plannerBoundingBox.WorldPos.z + centerWorldPos.z);
@@ -1369,36 +2952,36 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1369
2952
  _elementsSortedbyPosNr[_jsonElement2.PosNum - 1] = _jsonElement2;
1370
2953
  _plannerElement.PosNr = _jsonElement2.PosNum;
1371
2954
  }
1372
- _context6.next = 102;
2955
+ _context6.next = 104;
1373
2956
  break;
1374
- case 99:
1375
- _context6.prev = 99;
1376
- _context6.t2 = _context6["catch"](72);
2957
+ case 101:
2958
+ _context6.prev = 101;
2959
+ _context6.t2 = _context6["catch"](74);
1377
2960
  LOG.error(new DivaUtils.DivaError('Error initializing element nr ' + i + ' in the Standard Web Planner - Plan Data old Planner', {
1378
2961
  cause: _context6.t2,
1379
2962
  code: 'WC_0012'
1380
2963
  }));
1381
- case 102:
2964
+ case 104:
1382
2965
  i++;
1383
- _context6.next = 71;
2966
+ _context6.next = 73;
1384
2967
  break;
1385
- case 105:
2968
+ case 107:
1386
2969
  elementsForDockingV1 = [].concat(_toConsumableArray__default["default"](_elementsSortedbyPosNr.filter(function (e) {
1387
2970
  return e != null;
1388
2971
  })), _accElements);
1389
2972
  i = 0;
1390
- case 107:
2973
+ case 109:
1391
2974
  if (!(i < elementsForDockingV1.length)) {
1392
- _context6.next = 116;
2975
+ _context6.next = 118;
1393
2976
  break;
1394
2977
  }
1395
2978
  _row = elementsForDockingV1[i];
1396
2979
  if (!(_row.DP == null || _row.DP.length == 0)) {
1397
- _context6.next = 111;
2980
+ _context6.next = 113;
1398
2981
  break;
1399
2982
  }
1400
- return _context6.abrupt("continue", 113);
1401
- case 111:
2983
+ return _context6.abrupt("continue", 115);
2984
+ case 113:
1402
2985
  _DPsInfo = _row.DP;
1403
2986
  for (j = 0; j < _DPsInfo.length; j++) {
1404
2987
  _dpInfo = _DPsInfo[j];
@@ -1416,21 +2999,21 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1416
2999
  }
1417
3000
  }
1418
3001
  }
1419
- case 113:
3002
+ case 115:
1420
3003
  i++;
1421
- _context6.next = 107;
3004
+ _context6.next = 109;
1422
3005
  break;
1423
- case 116:
3006
+ case 118:
1424
3007
  this.plannerElements.forEach(function (el) {
1425
3008
  if (!el.IsDockedAccessoire && (anchorElement == undefined || el.PosNr < anchorElement.PosNr)) anchorElement = el;
1426
3009
  });
1427
3010
  this.updateAllElementsWorldPos(undefined, anchorElement ? [anchorElement.ElementId] : undefined);
1428
3011
  this.updatePlannerPosNr();
1429
- case 119:
3012
+ case 121:
1430
3013
  case "end":
1431
3014
  return _context6.stop();
1432
3015
  }
1433
- }, _callee6, this, [[10, 31], [41, 54], [72, 99]]);
3016
+ }, _callee6, this, [[10, 33], [43, 56], [74, 101]]);
1434
3017
  }));
1435
3018
  function initPlanner(_x12) {
1436
3019
  return _initPlanner.apply(this, arguments);
@@ -1690,7 +3273,9 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1690
3273
  transform = {
1691
3274
  rotDeg: plannerElement.getRotDeg(),
1692
3275
  worldPosCenter: plannerElement.WorldPosCenter,
1693
- height: plannerElement.Height
3276
+ height: plannerElement.Height,
3277
+ posNrAtEnd: plannerElement.PosNrAtEnd,
3278
+ placement: plannerElement.Placement
1694
3279
  };
1695
3280
  if (!removeDockingRelation) {
1696
3281
  PlannerHandler2D.dockingPointHandlerInst.removeDockingPointRelations(plannerElement);
@@ -1699,6 +3284,8 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1699
3284
  this.tryToDockForNotDockedAccessoire(parent);
1700
3285
  this.updatePlannerPosNr();
1701
3286
  this.updateAllElementsWorldPos();
3287
+ // A group the deletion lets fit, or splits, takes its place in the room.
3288
+ if (this.room) this.placeGroupsInRoom();
1702
3289
  this.updatePlannerPosNr();
1703
3290
  this.checkCollision(false, plannerElement.getElementId());
1704
3291
  this.updatePlannerBoundingBox();
@@ -1706,7 +3293,7 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1706
3293
  newElementToSelect: newSelElemIdPrev >= 0 ? newSelElemIdPrev : newSelElemIdNext >= 0 ? newSelElemIdNext : undefined,
1707
3294
  transform: transform
1708
3295
  });
1709
- case 24:
3296
+ case 25:
1710
3297
  case "end":
1711
3298
  return _context9.stop();
1712
3299
  }
@@ -1749,8 +3336,33 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1749
3336
  }, {
1750
3337
  key: "checkCollision",
1751
3338
  value: function checkCollision(calcCollisionPairs, checkSingleElementId) {
3339
+ var _this22 = this;
1752
3340
  if (this.doDisablePlanner2D) return;
1753
3341
  var allElements = this.getAllPlannerElements();
3342
+ // A NO_COLLISION article (e.g. a rug) neither collides with anything nor is collided with.
3343
+ var noCollisionIds = new Set(allElements.filter(function (element) {
3344
+ return _this22.hasNoCollision(element.ArticleCodex);
3345
+ }).map(function (element) {
3346
+ return element.ElementId;
3347
+ }));
3348
+ // Each colliding element with its outline and its group as slot carrier, built when a pair collides.
3349
+ var slotted;
3350
+ var slottedOf = function slottedOf(element) {
3351
+ var _slotted;
3352
+ (_slotted = slotted) !== null && _slotted !== void 0 ? _slotted : slotted = new Map(index.getDockingGroups(allElements).flatMap(function (group) {
3353
+ return _this22.getCollidingShapes(group, false);
3354
+ }).map(function (shape) {
3355
+ return [shape.elementId, shape];
3356
+ }));
3357
+ return slotted.get(element.ElementId);
3358
+ };
3359
+ // A guest in its carrier's slot only warns when the bodies overlap.
3360
+ var inSlotClear = function inSlotClear(a, b) {
3361
+ var shapeA = slottedOf(a);
3362
+ var shapeB = slottedOf(b);
3363
+ var rules = _this22.getCatalogData().placementOptions.rules;
3364
+ return !!shapeA && !!shapeB && index.slotExempt(rules, shapeA, rules, shapeB);
3365
+ };
1754
3366
  var collisionDetected = false;
1755
3367
  var collisionPairs = [];
1756
3368
  for (var i = 0; i < allElements.length; i++) {
@@ -1761,10 +3373,12 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1761
3373
  var _this$set$CatalogData, _this$set$CatalogData2;
1762
3374
  var element2 = allElements[j];
1763
3375
  if (element1.getElementId() == element2.getElementId()) continue;
3376
+ if (noCollisionIds.has(element1.ElementId) || noCollisionIds.has(element2.ElementId)) continue;
1764
3377
  if (PlannerHandler2D.dockingPointHandlerInst.checkElementsAreDocking(element1, element2)) continue;
1765
3378
  var collision = false;
1766
3379
  if (this.set.CatalogData.doCheckConstructionWarnings || (_this$set$CatalogData = this.set.CatalogData.forceConstructionWarningForArticles) !== null && _this$set$CatalogData !== void 0 && _this$set$CatalogData.includes(element1.ArticleCodex) || (_this$set$CatalogData2 = this.set.CatalogData.forceConstructionWarningForArticles) !== null && _this$set$CatalogData2 !== void 0 && _this$set$CatalogData2.includes(element2.ArticleCodex)) {
1767
3380
  collision = PlannerHandler2D.handler2D.checkCollision(element1, element2, this.set.CatalogData.checkCollisionForDifferentLayers);
3381
+ if (collision && inSlotClear(element1, element2)) collision = false;
1768
3382
  }
1769
3383
  if (collision) {
1770
3384
  collisionDetected = true;
@@ -1779,17 +3393,56 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1779
3393
  }
1780
3394
  }
1781
3395
  if (this.collisionHandler.collisionDetected && !collisionDetected) {
1782
- var _this$collisionHandle, _this$collisionHandle2;
3396
+ var _this$collisionHandle3, _this$collisionHandle4;
1783
3397
  //Collision has changed
1784
- (_this$collisionHandle = (_this$collisionHandle2 = this.collisionHandler).updatePlannerMsgContainer) === null || _this$collisionHandle === void 0 || _this$collisionHandle.call(_this$collisionHandle2, 'COLLISION_MSG', false, 'WARNING', 'COLLISION_MSG', false);
3398
+ (_this$collisionHandle3 = (_this$collisionHandle4 = this.collisionHandler).updatePlannerMsgContainer) === null || _this$collisionHandle3 === void 0 || _this$collisionHandle3.call(_this$collisionHandle4, 'COLLISION_MSG', false, 'WARNING', 'COLLISION_MSG', false);
1785
3399
  } else if (!this.collisionHandler.collisionDetected && collisionDetected) {
1786
- var _this$collisionHandle3, _this$collisionHandle4;
1787
- (_this$collisionHandle3 = (_this$collisionHandle4 = this.collisionHandler).updatePlannerMsgContainer) === null || _this$collisionHandle3 === void 0 || _this$collisionHandle3.call(_this$collisionHandle4, 'COLLISION_MSG', true, 'WARNING', 'COLLISION_MSG', false /*this.collisionHandler.collisionPairs*/);
3400
+ var _this$collisionHandle5, _this$collisionHandle6;
3401
+ (_this$collisionHandle5 = (_this$collisionHandle6 = this.collisionHandler).updatePlannerMsgContainer) === null || _this$collisionHandle5 === void 0 || _this$collisionHandle5.call(_this$collisionHandle6, 'COLLISION_MSG', true, 'WARNING', 'COLLISION_MSG', false /*this.collisionHandler.collisionPairs*/);
1788
3402
  }
1789
3403
  this.collisionHandler.collisionPairs = collisionPairs;
1790
3404
  this.collisionHandler.collisionDetected = collisionDetected;
1791
3405
  }
1792
3406
 
3407
+ /**
3408
+ * The set's elements for the planning's collision warning (`ROOM_COLLISION_MSG`): every element of a colliding docking
3409
+ * group but the NO_COLLISION ones, with its outline (never the viewer's measures). None while the 2D planner is off.
3410
+ */
3411
+ }, {
3412
+ key: "getCollisionSet",
3413
+ value: function getCollisionSet() {
3414
+ return this.toCollisionSet(this.doDisablePlanner2D ? [] : index.getDockingGroups(this.getAllPlannerElements()));
3415
+ }
3416
+
3417
+ // The colliding ones of the docking groups `groups` as the planning's collision warning checks them.
3418
+ }, {
3419
+ key: "toCollisionSet",
3420
+ value: function toCollisionSet(groups) {
3421
+ var _this23 = this;
3422
+ var catalogData = this.getCatalogData();
3423
+ var parts = groups.filter(function (group) {
3424
+ return _this23.collides(group);
3425
+ }).flatMap(function (group, groupIndex) {
3426
+ var slotMembers = _this23.getSlotMembers(group);
3427
+ return group.filter(function (member) {
3428
+ return !_this23.hasNoCollision(member.ArticleCodex);
3429
+ }).map(function (member) {
3430
+ var _catalogData$forceCon;
3431
+ return _objectSpread(_objectSpread({}, _this23.toCollisionShape(member, slotMembers, false)), {}, {
3432
+ groupIndex: groupIndex,
3433
+ constructionChecked: catalogData.doCheckConstructionWarnings || !!((_catalogData$forceCon = catalogData.forceConstructionWarningForArticles) !== null && _catalogData$forceCon !== void 0 && _catalogData$forceCon.includes(member.ArticleCodex))
3434
+ });
3435
+ });
3436
+ });
3437
+ return {
3438
+ setId: this.set.getSetId(),
3439
+ catalogCodex: catalogData.catalogCodex,
3440
+ rules: catalogData.placementOptions.rules,
3441
+ collidingLayers: catalogData.checkCollisionForDifferentLayers,
3442
+ parts: parts
3443
+ };
3444
+ }
3445
+
1793
3446
  /**
1794
3447
  * Updates the overall set posNr
1795
3448
  * @param startSetPosNr Indicates the start PosNr for the planner
@@ -1823,8 +3476,24 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1823
3476
  }, {
1824
3477
  key: "updatePlannerTrans",
1825
3478
  value: function updatePlannerTrans(elementId, deltaMove, deltaAngleDeg, rotCorrection, transState, autoDockingDistance, turningPoint) {
1826
- var _this3 = this;
3479
+ var _this$dragUnit,
3480
+ _this24 = this;
1827
3481
  var updateConfig = false;
3482
+ var room = this.room;
3483
+ if (room && transState == 'START') this.startRoomDrag(elementId);
3484
+ var roomDrag = room ? this.roomDrag : undefined;
3485
+ if (transState == 'START') this.startDragUnit(elementId, roomDrag);else if (transState == 'UPDATE') (_this$dragUnit = this.dragUnit) === null || _this$dragUnit === void 0 || _this$dragUnit.add(elementId);
3486
+ // A turn keeps its direction: only a move snaps into a slot place.
3487
+ if (transState == 'UPDATE' && deltaAngleDeg !== 0) this.dragSlots = undefined;
3488
+ // Group members follow the grabbed element rigidly, so their own UPDATE deltas are dropped.
3489
+ // A free group's rotation goes the normal way; only wall-bound groups take their rotation from the wall.
3490
+ if (roomDrag && roomDrag.wallMode !== 'forced' && transState == 'UPDATE' && deltaAngleDeg !== 0) roomDrag.rotating = true;
3491
+ if (room && roomDrag && !roomDrag.rotating && transState == 'UPDATE' && roomDrag.members.some(function (member) {
3492
+ return member.ElementId == elementId;
3493
+ })) {
3494
+ if (elementId == roomDrag.elementId) this.updateRoomDrag(room, roomDrag, deltaMove);
3495
+ return false;
3496
+ }
1828
3497
  if (this.plannerElements.has(elementId)) {
1829
3498
  var plannerElement = this.plannerElements.get(elementId);
1830
3499
  plannerElement === null || plannerElement === void 0 || plannerElement.updateDeltaTrans(deltaMove, deltaAngleDeg, rotCorrection, transState == 'END', turningPoint);
@@ -1837,17 +3506,51 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1837
3506
  updateConfig = this.set.onDockingChanged(plannerElement.ElementId, undockedElements[i], 'UNDOCK');
1838
3507
  }
1839
3508
  }
1840
- } else if (transState == 'END') {
3509
+ } else if (transState == 'END' && plannerElement) {
3510
+ // A drag released where its group runs into something goes back to where it started, a turn only where findTurnPlace finds none.
3511
+ if ((roomDrag === null || roomDrag === void 0 ? void 0 : roomDrag.elementId) == elementId && roomDrag.blockedBy.length > 0) {
3512
+ var current = roomDrag.rotating ? this.getTurnedPose(plannerElement, roomDrag) : roomDrag.current;
3513
+ var target = roomDrag.rotating && room && this.findTurnPlace(plannerElement, roomDrag, room) || roomDrag.start;
3514
+ index.moveGroupRigidly([].concat(_toConsumableArray__default["default"](roomDrag.members), _toConsumableArray__default["default"](roomDrag.followers)), current, target);
3515
+ roomDrag.current = target;
3516
+ roomDrag.blockedBy = [];
3517
+ roomDrag.slotSnapped = false;
3518
+ }
3519
+ // Only the dragged unit moves: it is put back into the room and goes onto what it docks to (else into the free slot
3520
+ // place it snapped to), as the drag preview shows it, so docking it re-anchors nothing else. Its guests go with it.
3521
+ var unit = this.getAllPlannerElements().filter(function (element) {
3522
+ var _this24$dragUnit;
3523
+ return element === plannerElement || ((_this24$dragUnit = _this24.dragUnit) === null || _this24$dragUnit === void 0 ? void 0 : _this24$dragUnit.has(element.ElementId));
3524
+ });
3525
+ var followers = unit.filter(function (element) {
3526
+ return _this24.dragFollowers.has(element.ElementId);
3527
+ });
3528
+ var group = unit.filter(function (element) {
3529
+ return !_this24.dragFollowers.has(element.ElementId);
3530
+ });
3531
+ this.dragUnit = undefined;
3532
+ this.dragFollowers = new Set();
3533
+ var roomRule = (roomDrag === null || roomDrag === void 0 ? void 0 : roomDrag.elementId) == elementId && !roomDrag.slotSnapped && (roomDrag.wallMode === 'forced' || roomDrag.rotating);
3534
+ if (roomRule) this.placeGroupInRoom(group, plannerElement, followers);
3535
+ this.snapToDock(plannerElement, unit, autoDockingDistance, !roomDrag);
3536
+ this.dragSlots = undefined;
1841
3537
  var dockablePairs = PlannerHandler2D.dockingPointHandlerInst.searchDockableElementsInArea(plannerElement, this.getAllPlannerElements(), autoDockingDistance); //hier kann jetzt ein DP drinnen stehen - docke alle
1842
3538
  if (dockablePairs != null && dockablePairs.size > 0) {
1843
3539
  dockablePairs.forEach(function (dockPair, type) {
1844
- var targetPlannerElement = _this3.plannerElements.get(dockPair.targetDP.ElementId);
3540
+ var targetPlannerElement = _this24.plannerElements.get(dockPair.targetDP.ElementId);
1845
3541
  if (targetPlannerElement) {
1846
3542
  PlannerHandler2D.dockingPointHandlerInst.tryDockElementDPToDP(plannerElement, targetPlannerElement, dockPair.sourceDP, dockPair.targetDP);
1847
3543
  }
1848
3544
  });
1849
3545
  }
1850
3546
  updateConfig = this.updateAllElementsWorldPos(elementId);
3547
+ if ((roomDrag === null || roomDrag === void 0 ? void 0 : roomDrag.elementId) == elementId) {
3548
+ // The group as released, docked or turned: a wall-bound one goes to its wall, any other inside the room; where a
3549
+ // slot snap put it, it stays.
3550
+ if (!roomDrag.slotSnapped) this.placeGroupInRoom(this.getDockingGroupOf(plannerElement), plannerElement);
3551
+ this.checkCollision(false, elementId);
3552
+ this.roomDrag = undefined;
3553
+ }
1851
3554
  this.updatePlannerPosNr();
1852
3555
  this.updatePlannerBoundingBox();
1853
3556
  }
@@ -1873,7 +3576,7 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1873
3576
  }, {
1874
3577
  key: "saveSetPlanner",
1875
3578
  value: function saveSetPlanner() {
1876
- var _this4 = this;
3579
+ var _this25 = this;
1877
3580
  if (this.plannerElements.size == 0) return null;
1878
3581
  var plannerElements = [];
1879
3582
  this.plannerElements.forEach(function (elem, elemId) {
@@ -1888,13 +3591,18 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1888
3591
  };
1889
3592
  dpArr.push(saveDP);
1890
3593
  }
1891
- var plannerElement = {
3594
+ var plannerElement = _objectSpread(_objectSpread(_objectSpread({
1892
3595
  elementID: elem.getElementId(),
1893
- basketID: _this4.set.getBasketId(elem.getElementId()),
1894
- CatalogCodex: _this4.set.getCatalogCodex(),
1895
- Codex: _this4.set.getArticleCodex(elem.getElementId()),
3596
+ basketID: _this25.set.getBasketId(elem.getElementId()),
3597
+ CatalogCodex: _this25.set.getCatalogCodex(),
3598
+ Codex: _this25.set.getArticleCodex(elem.getElementId()),
1896
3599
  posNr: elem.PosNr,
1897
- accNr: elem.IsDockedAccessoire ? elem.AccessoirePosNr : undefined,
3600
+ accNr: elem.IsDockedAccessoire ? elem.AccessoirePosNr : undefined
3601
+ }, elem.PosNrAtEnd ? {
3602
+ posNrAtEnd: true
3603
+ } : {}), elem.Placement ? {
3604
+ placement: elem.Placement
3605
+ } : {}), {}, {
1898
3606
  x: elem.WorldPosCenter.x,
1899
3607
  y: elem.WorldPosCenter.y,
1900
3608
  z: elem.WorldPosCenter.z,
@@ -1903,9 +3611,9 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1903
3611
  height: elem.Height ? elem.Height : -1,
1904
3612
  depth: elem.Depth ? elem.Depth : -1,
1905
3613
  DP: dpArr
1906
- };
3614
+ });
1907
3615
  if (elem.IsAccessoire) {
1908
- var parentBasketId = _this4.set.getParentBasketIdOfElementId(elem.getElementId());
3616
+ var parentBasketId = _this25.set.getParentBasketIdOfElementId(elem.getElementId());
1909
3617
  if (parentBasketId != undefined) {
1910
3618
  plannerElement.AccessoireInitParams = {
1911
3619
  RelatedToBasketID: parentBasketId
@@ -1939,7 +3647,7 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1939
3647
  }, {
1940
3648
  key: "getSetData",
1941
3649
  value: function getSetData(only3DCompatible, useSetPlanner, doShow3DDimensionLines, alternateRenderInfo) {
1942
- var _this5 = this;
3650
+ var _this26 = this;
1943
3651
  var setId = useSetPlanner ? this.set.getSetId() : 'S1';
1944
3652
  var setData = {
1945
3653
  //ID: "S" + this.plannerID,
@@ -1966,19 +3674,19 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
1966
3674
  setData.IDM3DEnvironment = this.IDM3DEnvironment;
1967
3675
  }
1968
3676
  this.plannerElements.forEach(function (elem, elemId) {
1969
- var config = _this5.set.getPlannerConfigData(elemId, alternateRenderInfo);
3677
+ var config = _this26.set.getPlannerConfigData(elemId, alternateRenderInfo);
1970
3678
  var elemCfg = config.config;
1971
3679
  var accElements = [];
1972
3680
  if (config.accs && config.accs.length > 0) {
1973
3681
  for (var i = 0; i < config.accs.length; i++) {
1974
- if (_this5.plannerElements.has(config.accs[i])) {
3682
+ if (_this26.plannerElements.has(config.accs[i])) {
1975
3683
  accElements.push('E' + config.accs[i]);
1976
3684
  }
1977
3685
  }
1978
3686
  }
1979
3687
  if (!only3DCompatible || elemCfg.Model != undefined) {
1980
3688
  var _elemCfg$MOVE;
1981
- var article = _this5.set.getArticleByElementId(elemId);
3689
+ var article = _this26.set.getArticleByElementId(elemId);
1982
3690
  var elemJson = {
1983
3691
  ID: 'E' + elemId,
1984
3692
  // N: elemCfg.N,
@@ -2008,15 +3716,15 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
2008
3716
  elemJson.H = hash;
2009
3717
  setData.ELE.push(elemJson);
2010
3718
  }
2011
- var shelfPlannerElements = _this5.set.getShelfPlannerData(elemId);
3719
+ var shelfPlannerElements = _this26.set.getShelfPlannerData(elemId);
2012
3720
  if (shelfPlannerElements) {
2013
3721
  for (var _i5 = 0; _i5 < shelfPlannerElements.length; _i5++) {
2014
3722
  var accessorire = shelfPlannerElements[_i5];
2015
- var shelfConfig = _this5.set.getShelfPlannerConfigData(accessorire.basketId).config;
3723
+ var shelfConfig = _this26.set.getShelfPlannerConfigData(accessorire.basketId).config;
2016
3724
  var _accElements2 = [];
2017
3725
  if (shelfConfig.accs && shelfConfig.accs.length > 0) {
2018
3726
  for (var j = 0; j < shelfConfig.accs.length; j++) {
2019
- if (_this5.plannerElements.has(shelfConfig.accs[j])) {
3727
+ if (_this26.plannerElements.has(shelfConfig.accs[j])) {
2020
3728
  _accElements2.push('E' + shelfConfig.accs[j]);
2021
3729
  }
2022
3730
  }
@@ -2079,12 +3787,12 @@ var DivaStandardPlanner = /*#__PURE__*/function () {
2079
3787
  }, {
2080
3788
  key: "getPlanningIsComplete",
2081
3789
  value: function getPlanningIsComplete(forceCheck) {
2082
- var _this6 = this;
3790
+ var _this27 = this;
2083
3791
  var dontCheck = !forceCheck && (this.set.CatalogData.doHideCompletenessWarning || !this.set.CatalogData.doCheckConstructionWarnings);
2084
3792
  var elemNotComplete = false;
2085
3793
  this.plannerElements.forEach(function (plannerElement, key) {
2086
- var _this6$set$CatalogDat;
2087
- if (dontCheck && !((_this6$set$CatalogDat = _this6.set.CatalogData.forceConstructionWarningForArticles) !== null && _this6$set$CatalogDat !== void 0 && _this6$set$CatalogDat.includes(plannerElement.ArticleCodex))) return;
3794
+ var _this27$set$CatalogDa;
3795
+ if (dontCheck && !((_this27$set$CatalogDa = _this27.set.CatalogData.forceConstructionWarningForArticles) !== null && _this27$set$CatalogDa !== void 0 && _this27$set$CatalogDa.includes(plannerElement.ArticleCodex))) return;
2088
3796
  if (!elemNotComplete && (plannerElement.getFreeDockingPointsByType('AVL').length > 0 || plannerElement.getFreeDockingPointsByType('AVR').length > 0)) {
2089
3797
  elemNotComplete = true;
2090
3798
  }