kitchen-simulator 5.0.0-test.66 → 5.0.0-test.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/_KitchenConfigurator.jsx +1 -1
- package/src/catalog/factories/wall-factory-3d.js +1 -1
- package/src/catalog/properties/property-lenght-measure.jsx +1 -1
- package/src/catalog/properties/property-length-measure.jsx +1 -1
- package/src/catalog/properties/property-length-measure_hole.jsx +1 -1
- package/src/catalog/utils/exporter.js +1 -1
- package/src/catalog/utils/item-loader.jsx +1 -1
- package/src/class/item.js +1 -1
- package/src/components/viewer2d/area.jsx +1 -1
- package/src/components/viewer2d/grids/grid-horizontal-streak.jsx +1 -1
- package/src/components/viewer2d/grids/grid-streak.jsx +1 -1
- package/src/components/viewer2d/grids/grid-vertical-streak.jsx +1 -1
- package/src/components/viewer2d/item.jsx +1 -1
- package/src/components/viewer2d/ruler.jsx +1 -1
- package/src/components/viewer2d/rulerDist.jsx +1 -1
- package/src/components/viewer2d/viewer2d.jsx +1 -1
- package/src/components/viewer3d/ruler-utils/itemRect.jsx +91 -91
- package/src/components/viewer3d/ruler-utils/layer3D.jsx +528 -528
- package/src/components/viewer3d/ruler-utils/scene3D.jsx +1 -1
- package/src/components/viewer3d/scene-creator.js +1 -1
- package/src/components/viewer3d/viewer3d.jsx +1 -1
- package/src/models.js +1 -1
- package/src/reducers/viewer2d-reducer.js +1 -1
- package/src/reducers/viewer3d-reducer.js +1 -1
- package/src/utils/geometry.js +2 -2
- package/src/utils/helper.js +1 -1
- package/src/utils/molding.js +973 -973
package/src/utils/molding.js
CHANGED
|
@@ -1,973 +1,973 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BASE_CABINET_LAYOUTPOS,
|
|
3
|
-
BOTTOM_MOLDING_LOCATION,
|
|
4
|
-
EPSILON,
|
|
5
|
-
MIDDLE_MOLDING_LOCATION,
|
|
6
|
-
MOLDING_LOCATIONS,
|
|
7
|
-
OVERLAP_INCLUDED,
|
|
8
|
-
OVERLAP_LINK,
|
|
9
|
-
OVERLAP_SAME,
|
|
10
|
-
OVERLAP_SOME,
|
|
11
|
-
TALL_CABINET_LAYOUTPOS,
|
|
12
|
-
TOP_MOLDING_LOCATION,
|
|
13
|
-
WALL_CABINET_LAYOUTPOS
|
|
14
|
-
} from '../constants';
|
|
15
|
-
import * as Three from 'three';
|
|
16
|
-
import convert from 'convert-units';
|
|
17
|
-
import IDBroker from './id-broker';
|
|
18
|
-
import { returnReplaceableDeepSearchType } from '../components/viewer2d/utils';
|
|
19
|
-
import { GeometryUtils } from './export';
|
|
20
|
-
import { isEmpty } from './helper';
|
|
21
|
-
|
|
22
|
-
export function getItemRect(item) {
|
|
23
|
-
let x = item.x;
|
|
24
|
-
let y = item.y;
|
|
25
|
-
let rotRad = (item.rotation / 180) * Math.PI;
|
|
26
|
-
let itemWidth = item.properties.get('width').get('_length');
|
|
27
|
-
let itemWidthUnit = item.properties.get('width').get('_unit') || 'cm';
|
|
28
|
-
itemWidth = convert(itemWidth / 2)
|
|
29
|
-
.from(itemWidthUnit)
|
|
30
|
-
.to('cm');
|
|
31
|
-
let itemDepth = item.properties.get('depth').get('_length');
|
|
32
|
-
let itemDepthUnit = item.properties.get('depth').get('_unit') || 'cm';
|
|
33
|
-
itemDepth = convert(itemDepth / 2)
|
|
34
|
-
.from(itemDepthUnit)
|
|
35
|
-
.to('cm');
|
|
36
|
-
let mx = x - itemWidth * Math.cos(rotRad);
|
|
37
|
-
let my = y - itemWidth * Math.sin(rotRad);
|
|
38
|
-
let x0 = mx + itemDepth * Math.sin(rotRad);
|
|
39
|
-
let y0 = my - itemDepth * Math.cos(rotRad);
|
|
40
|
-
let x3 = mx * 2 - x0;
|
|
41
|
-
let y3 = my * 2 - y0;
|
|
42
|
-
let x1 = x * 2 - x3;
|
|
43
|
-
let y1 = y * 2 - y3;
|
|
44
|
-
let x2 = x * 2 - x0;
|
|
45
|
-
let y2 = y * 2 - y0;
|
|
46
|
-
return {
|
|
47
|
-
rect: [
|
|
48
|
-
{ x: x0, y: y0 },
|
|
49
|
-
{ x: x1, y: y1 },
|
|
50
|
-
{ x: x2, y: y2 },
|
|
51
|
-
{ x: x3, y: y3 }
|
|
52
|
-
]
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function hasMoldingLayout(molding, layoutpos) {
|
|
57
|
-
const types = molding?.molding_type;
|
|
58
|
-
return (
|
|
59
|
-
(Array.isArray(types) || typeof types === 'string') &&
|
|
60
|
-
types.includes(layoutpos)
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function isEnableItemForMolding(layer, selItem, molding = null) {
|
|
65
|
-
let allLineRects = GeometryUtils.buildRectFromLines(
|
|
66
|
-
layer,
|
|
67
|
-
GeometryUtils.getAllLines(layer)
|
|
68
|
-
);
|
|
69
|
-
let result =
|
|
70
|
-
!isEmpty(selItem) &&
|
|
71
|
-
selItem.category === 'cabinet' &&
|
|
72
|
-
((selItem.layoutpos === BASE_CABINET_LAYOUTPOS &&
|
|
73
|
-
!GeometryUtils.isSnappedLine(getItemRect(selItem), allLineRects)) ||
|
|
74
|
-
((selItem.layoutpos === WALL_CABINET_LAYOUTPOS ||
|
|
75
|
-
selItem.layoutpos === TALL_CABINET_LAYOUTPOS) &&
|
|
76
|
-
GeometryUtils.isSnappedLine(getItemRect(selItem), allLineRects)));
|
|
77
|
-
|
|
78
|
-
// check this item is enable for any molding
|
|
79
|
-
if (isEmpty(molding)) return result;
|
|
80
|
-
// check this item is enable for specified molding
|
|
81
|
-
else return result && hasMoldingLayout(molding, selItem.layoutpos);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Check two line segments are overlap. The direction of the two line segments must be opposite.
|
|
86
|
-
* s1 c2 s2 c1
|
|
87
|
-
* |--------|------|-----------|
|
|
88
|
-
* Decision Formular: L(s1,c1) + L(s2, c2) = L(s1, s2) + L(c1, c2)
|
|
89
|
-
* @param {*} selRectPos1
|
|
90
|
-
* @param {*} selRectPos2
|
|
91
|
-
* @param {*} curRectPos1
|
|
92
|
-
* @param {*} curRectPos2
|
|
93
|
-
* @returns L(s1,c1) + L(s2, c2) - L(s1, s2) - L(c1, c2)
|
|
94
|
-
*/
|
|
95
|
-
function getDelta(selRectPos1, selRectPos2, curRectPos1, curRectPos2) {
|
|
96
|
-
return (
|
|
97
|
-
// GeometryUtils.verticesDistance(curRectPos1, selRectPos2) +
|
|
98
|
-
// GeometryUtils.verticesDistance(selRectPos1, curRectPos2) -
|
|
99
|
-
// Math.abs(
|
|
100
|
-
// GeometryUtils.verticesDistance(curRectPos2, curRectPos1) -
|
|
101
|
-
// GeometryUtils.verticesDistance(selRectPos1, selRectPos2)
|
|
102
|
-
// )
|
|
103
|
-
Math.abs(
|
|
104
|
-
GeometryUtils.verticesDistance(curRectPos1, selRectPos1) +
|
|
105
|
-
GeometryUtils.verticesDistance(selRectPos2, curRectPos2) -
|
|
106
|
-
GeometryUtils.verticesDistance(curRectPos2, curRectPos1) -
|
|
107
|
-
GeometryUtils.verticesDistance(selRectPos1, selRectPos2)
|
|
108
|
-
)
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function isItemSnappedItem(selItem, curItem) {
|
|
113
|
-
const selRect = getItemRect(selItem).rect;
|
|
114
|
-
const curRect = getItemRect(curItem).rect;
|
|
115
|
-
const flag30 =
|
|
116
|
-
getDelta(selRect[3], selRect[0], curRect[1], curRect[2]) < EPSILON;
|
|
117
|
-
const flag21 =
|
|
118
|
-
getDelta(selRect[2], selRect[1], curRect[0], curRect[3]) < EPSILON;
|
|
119
|
-
const flag23 =
|
|
120
|
-
getDelta(selRect[2], selRect[3], curRect[2], curRect[3]) < EPSILON;
|
|
121
|
-
const flag01 =
|
|
122
|
-
getDelta(selRect[1], selRect[0], curRect[0], curRect[3]) < EPSILON;
|
|
123
|
-
const flag03 =
|
|
124
|
-
getDelta(selRect[0], selRect[3], curRect[1], curRect[0]) < EPSILON;
|
|
125
|
-
return flag30 || flag21 || flag23 || flag01 || flag03;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export function isItemSnappedGroup(selItem, itemGroup) {
|
|
129
|
-
return itemGroup.some(curItem => isItemSnappedItem(selItem, curItem));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function sortItemsByDistance(items, selItem) {
|
|
133
|
-
items.sort((a, b) => {
|
|
134
|
-
return (
|
|
135
|
-
GeometryUtils.pointsDistance(a.x, a.y, selItem.x, selItem.y) -
|
|
136
|
-
GeometryUtils.pointsDistance(b.x, b.y, selItem.x, selItem.y)
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
return items;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export function isSameMoldingLayoutpos(curItem, item) {
|
|
143
|
-
return (
|
|
144
|
-
(curItem.layoutpos === BASE_CABINET_LAYOUTPOS &&
|
|
145
|
-
curItem.layoutpos === item.layoutpos) ||
|
|
146
|
-
([WALL_CABINET_LAYOUTPOS, TALL_CABINET_LAYOUTPOS].includes(
|
|
147
|
-
curItem.layoutpos
|
|
148
|
-
) &&
|
|
149
|
-
[WALL_CABINET_LAYOUTPOS, TALL_CABINET_LAYOUTPOS].includes(item.layoutpos))
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export function isItemSameItemByLocation(item1, item2, location) {
|
|
154
|
-
let item1Altitude = item1.properties.get('altitude').get('_length');
|
|
155
|
-
let item1AltitudeUnit = item1.properties.get('altitude').get('_unit');
|
|
156
|
-
item1Altitude = convert(item1Altitude).from(item1AltitudeUnit).to('cm');
|
|
157
|
-
let item1Height = item1.properties.get('height').get('_length');
|
|
158
|
-
let item1HeightUnit = item1.properties.get('height').get('_unit');
|
|
159
|
-
item1Height = convert(item1Height).from(item1HeightUnit).to('cm');
|
|
160
|
-
let item2Altitude = item2.properties.get('altitude').get('_length');
|
|
161
|
-
let item2AltitudeUnit = item2.properties.get('altitude').get('_unit');
|
|
162
|
-
item2Altitude = convert(item2Altitude).from(item2AltitudeUnit).to('cm');
|
|
163
|
-
let item2Height = item2.properties.get('height').get('_length');
|
|
164
|
-
let item2HeightUnit = item2.properties.get('height').get('_unit');
|
|
165
|
-
item2Height = convert(item2Height).from(item2HeightUnit).to('cm');
|
|
166
|
-
let flag = false;
|
|
167
|
-
switch (location) {
|
|
168
|
-
case TOP_MOLDING_LOCATION:
|
|
169
|
-
if (
|
|
170
|
-
GeometryUtils.sameDistances(
|
|
171
|
-
item1Altitude + item1Height,
|
|
172
|
-
item2Altitude + item2Height
|
|
173
|
-
)
|
|
174
|
-
)
|
|
175
|
-
flag = true;
|
|
176
|
-
break;
|
|
177
|
-
case MIDDLE_MOLDING_LOCATION:
|
|
178
|
-
if (
|
|
179
|
-
GeometryUtils.sameDistances(
|
|
180
|
-
item1Altitude + item1Height / 2,
|
|
181
|
-
item2Altitude + item2Height / 2
|
|
182
|
-
)
|
|
183
|
-
)
|
|
184
|
-
flag = true;
|
|
185
|
-
break;
|
|
186
|
-
case BOTTOM_MOLDING_LOCATION:
|
|
187
|
-
if (GeometryUtils.sameDistances(item1Altitude, item2Altitude))
|
|
188
|
-
flag = true;
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
return flag;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
export function tryMergeMDItem(layer, selItem, curItem, itemGroup, molding) {
|
|
195
|
-
return (
|
|
196
|
-
isSameMoldingLayoutpos(selItem, curItem) &&
|
|
197
|
-
isEnableItemForMolding(layer, curItem, molding) &&
|
|
198
|
-
isItemSnappedGroup(curItem, itemGroup) &&
|
|
199
|
-
!itemGroup.some(item => item.id === curItem.id) &&
|
|
200
|
-
isItemSameItemByLocation(selItem, curItem, molding.location_type)
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
export function getItemGroupFromMolding(layer, curItem, molding) {
|
|
205
|
-
const selectedItem = layer.getIn(['items', layer.selected.toJS().items[0]]);
|
|
206
|
-
let itemGroup = [curItem];
|
|
207
|
-
let temp_layer_items = layer.items.toArray().filter(item => {
|
|
208
|
-
return (
|
|
209
|
-
item.category === 'cabinet' &&
|
|
210
|
-
item.id !== curItem.id &&
|
|
211
|
-
item.id !== selectedItem?.id
|
|
212
|
-
);
|
|
213
|
-
});
|
|
214
|
-
temp_layer_items = sortItemsByDistance(temp_layer_items, curItem);
|
|
215
|
-
for (let idx = 0; idx < temp_layer_items.length; idx++) {
|
|
216
|
-
if (
|
|
217
|
-
tryMergeMDItem(layer, curItem, temp_layer_items[idx], itemGroup, molding)
|
|
218
|
-
) {
|
|
219
|
-
itemGroup.push(temp_layer_items[idx]);
|
|
220
|
-
idx = 0;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return itemGroup;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
function tryMergeItemWithLocation(curItem, itemGroup, location) {
|
|
227
|
-
return itemGroup.some(item => {
|
|
228
|
-
return (
|
|
229
|
-
isItemSnappedItem(curItem, item) &&
|
|
230
|
-
isItemSameItemByLocation(curItem, item, location)
|
|
231
|
-
);
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
export function getAllMoldingGroups(layer, items = null) {
|
|
236
|
-
if (items === null) items = layer.items.toArray();
|
|
237
|
-
let itemGroups = [];
|
|
238
|
-
items.forEach(curItem => {
|
|
239
|
-
// let allLineRects = GeometryUtils.buildRectFromLines(
|
|
240
|
-
// layer,
|
|
241
|
-
// GeometryUtils.getAllLines(layer)
|
|
242
|
-
// );
|
|
243
|
-
// if (
|
|
244
|
-
// (curItem.category === 'cabinet' &&
|
|
245
|
-
// curItem.layoutpos === BASE_CABINET_LAYOUTPOS &&
|
|
246
|
-
// !GeometryUtils.isSnappedLine(getItemRect(curItem), allLineRects)) ||
|
|
247
|
-
// ((curItem.layoutpos === WALL_CABINET_LAYOUTPOS ||
|
|
248
|
-
// curItem.layoutpos === TALL_CABINET_LAYOUTPOS) &&
|
|
249
|
-
// GeometryUtils.isSnappedLine(getItemRect(curItem), allLineRects))
|
|
250
|
-
// ) {
|
|
251
|
-
if (curItem.category === 'cabinet') {
|
|
252
|
-
let temp_items = items.filter(it => {
|
|
253
|
-
return (
|
|
254
|
-
it.category === 'cabinet' &&
|
|
255
|
-
isSameMoldingLayoutpos(curItem, it) &&
|
|
256
|
-
it.id !== curItem.id
|
|
257
|
-
);
|
|
258
|
-
});
|
|
259
|
-
temp_items = sortItemsByDistance(temp_items, curItem);
|
|
260
|
-
MOLDING_LOCATIONS.forEach(location => {
|
|
261
|
-
if (
|
|
262
|
-
!itemGroups.some(
|
|
263
|
-
ig =>
|
|
264
|
-
ig.items.some(it => it.id === curItem.id) &&
|
|
265
|
-
ig.location_type === location
|
|
266
|
-
)
|
|
267
|
-
) {
|
|
268
|
-
let itemGroup = [curItem];
|
|
269
|
-
for (let idx = 0; idx < temp_items.length; idx++) {
|
|
270
|
-
if (
|
|
271
|
-
tryMergeItemWithLocation(temp_items[idx], itemGroup, location)
|
|
272
|
-
) {
|
|
273
|
-
itemGroup.push(temp_items[idx]);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
itemGroups.push({
|
|
277
|
-
id: IDBroker.acquireID(),
|
|
278
|
-
items: itemGroup,
|
|
279
|
-
location_type: location,
|
|
280
|
-
molding: null,
|
|
281
|
-
lines: null,
|
|
282
|
-
pointGroups: null,
|
|
283
|
-
meshes: [],
|
|
284
|
-
rot: 0,
|
|
285
|
-
pos: 0
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
// }
|
|
291
|
-
});
|
|
292
|
-
return itemGroups;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
export function getLinesOfItem(item, allLineRects, catalog) {
|
|
296
|
-
let lines = [];
|
|
297
|
-
let outline = null;
|
|
298
|
-
let element = catalog.elements[item.get('type')];
|
|
299
|
-
if (!element)
|
|
300
|
-
element =
|
|
301
|
-
catalog.elements[returnReplaceableDeepSearchType(item.get('type'))];
|
|
302
|
-
// get edge lines
|
|
303
|
-
let newWidth = item.properties.get('width').get('_length');
|
|
304
|
-
let wUnit = item.properties.get('width').get('_unit') || 'cm';
|
|
305
|
-
newWidth = convert(newWidth).from(wUnit).to('cm');
|
|
306
|
-
let newDepth = item.properties.get('depth').get('_length');
|
|
307
|
-
let hUnit = item.properties.get('depth').get('_unit') || 'cm';
|
|
308
|
-
newDepth = convert(newDepth).from(hUnit).to('cm');
|
|
309
|
-
if (item) {
|
|
310
|
-
// Get Outline Data of Selected Item
|
|
311
|
-
outline = element.info.outline;
|
|
312
|
-
|
|
313
|
-
if (outline) {
|
|
314
|
-
// Extract Points from `outline`
|
|
315
|
-
var outlinePaths = outline.paths;
|
|
316
|
-
var outlineWidth = outline.svgWidth;
|
|
317
|
-
var outlineHeight = outline.svgHeight;
|
|
318
|
-
var outlinePoints = []; // Hold Points Of SVG
|
|
319
|
-
for (let path of outlinePaths) {
|
|
320
|
-
for (let subPath of path.subPaths) {
|
|
321
|
-
outlinePoints = outlinePoints.concat(subPath.getPoints());
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
outline.reverse && outlinePoints.reverse();
|
|
325
|
-
for (let i = 0; i < outlinePoints.length - 1; i++) {
|
|
326
|
-
lines.push([
|
|
327
|
-
GeometryUtils.rotatePointAroundPoint(
|
|
328
|
-
(outlinePoints[i].x / outlineWidth - 0.5) * newWidth + item.x,
|
|
329
|
-
(outlinePoints[i].y / outlineHeight - 0.5) * newDepth + item.y,
|
|
330
|
-
item.x,
|
|
331
|
-
item.y,
|
|
332
|
-
item.rotation + 90
|
|
333
|
-
),
|
|
334
|
-
GeometryUtils.rotatePointAroundPoint(
|
|
335
|
-
(outlinePoints[i + 1].x / outlineWidth - 0.5) * newWidth + item.x,
|
|
336
|
-
(outlinePoints[i + 1].y / outlineHeight - 0.5) * newDepth + item.y,
|
|
337
|
-
item.x,
|
|
338
|
-
item.y,
|
|
339
|
-
item.rotation + 90
|
|
340
|
-
),
|
|
341
|
-
IDBroker.acquireID()
|
|
342
|
-
]);
|
|
343
|
-
}
|
|
344
|
-
} else {
|
|
345
|
-
let pos = [
|
|
346
|
-
[-1, -1],
|
|
347
|
-
[1, -1],
|
|
348
|
-
[1, 1],
|
|
349
|
-
[-1, 1]
|
|
350
|
-
];
|
|
351
|
-
for (let i = 0; i < 4; i++) {
|
|
352
|
-
lines.push([
|
|
353
|
-
GeometryUtils.rotatePointAroundPoint(
|
|
354
|
-
(pos[i][0] * newWidth) / 2 + item.x,
|
|
355
|
-
(pos[i][1] * newDepth) / 2 + item.y,
|
|
356
|
-
item.x,
|
|
357
|
-
item.y,
|
|
358
|
-
item.rotation
|
|
359
|
-
),
|
|
360
|
-
GeometryUtils.rotatePointAroundPoint(
|
|
361
|
-
(pos[(i + 1) % 4][0] * newWidth) / 2 + item.x,
|
|
362
|
-
(pos[(i + 1) % 4][1] * newDepth) / 2 + item.y,
|
|
363
|
-
item.x,
|
|
364
|
-
item.y,
|
|
365
|
-
item.rotation
|
|
366
|
-
),
|
|
367
|
-
IDBroker.acquireID()
|
|
368
|
-
]);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
if (item.layoutpos !== BASE_CABINET_LAYOUTPOS) {
|
|
373
|
-
lines = lines.filter(
|
|
374
|
-
line =>
|
|
375
|
-
!GeometryUtils.isSnappedLine(
|
|
376
|
-
{ rect: [{ x: 0, y: 0 }, { x: 0, y: 0 }, line[0], line[1]] },
|
|
377
|
-
allLineRects
|
|
378
|
-
)
|
|
379
|
-
);
|
|
380
|
-
}
|
|
381
|
-
return lines;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
function isParallelLines(line1, line2) {
|
|
385
|
-
let isParallel = false;
|
|
386
|
-
if (
|
|
387
|
-
Math.abs(line1[0].y - line1[1].y) <= EPSILON &&
|
|
388
|
-
Math.abs(line2[0].y - line2[1].y) <= EPSILON
|
|
389
|
-
)
|
|
390
|
-
isParallel = true;
|
|
391
|
-
if (
|
|
392
|
-
Math.abs(line1[0].x - line1[1].x) <= EPSILON &&
|
|
393
|
-
Math.abs(line2[0].x - line2[1].x) <= EPSILON
|
|
394
|
-
)
|
|
395
|
-
isParallel = true;
|
|
396
|
-
if (
|
|
397
|
-
Math.abs(
|
|
398
|
-
(line1[0].x - line1[1].x) / (line1[0].y - line1[1].y) -
|
|
399
|
-
(line2[0].x - line2[1].x) / (line2[0].y - line2[1].y)
|
|
400
|
-
) <= EPSILON
|
|
401
|
-
)
|
|
402
|
-
isParallel = true;
|
|
403
|
-
if (isParallel) {
|
|
404
|
-
return true;
|
|
405
|
-
}
|
|
406
|
-
return false;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
export function isLinesOverlapped(line1, line2) {
|
|
410
|
-
return (
|
|
411
|
-
isParallelLines(line1, line2) &&
|
|
412
|
-
line1.some(l1 => line2.some(l2 => GeometryUtils.samePoints(l1, l2)))
|
|
413
|
-
);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
export function mergeOverlappedLines(line1, line2) {
|
|
417
|
-
let line1_idx = 0,
|
|
418
|
-
line2_idx = 0;
|
|
419
|
-
line1.forEach((l1, idx1) => {
|
|
420
|
-
if (idx1 !== line1.length - 1) {
|
|
421
|
-
line2.forEach((l2, idx2) => {
|
|
422
|
-
if (idx2 !== line2.length - 1) {
|
|
423
|
-
if (GeometryUtils.samePoints(l1, l2)) {
|
|
424
|
-
line1_idx = idx1;
|
|
425
|
-
line2_idx = idx2;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
//If line1 's end point and line2 's start point is same, two lines merge into a line with
|
|
432
|
-
//the line1's start point as the start point and line2's end point as the end point.
|
|
433
|
-
if (line1_idx === 1) {
|
|
434
|
-
return [line1[1 - line1_idx], line2[1 - line2_idx], IDBroker.acquireID()];
|
|
435
|
-
} else {
|
|
436
|
-
return [line2[1 - line2_idx], line1[1 - line1_idx], IDBroker.acquireID()];
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* Get the contour line array of moldingGroup items
|
|
442
|
-
* @param {*} moldingGroup
|
|
443
|
-
* @param {*} layer
|
|
444
|
-
* @param {*} catalog
|
|
445
|
-
* @returns contour line array of moldingGroup items
|
|
446
|
-
*/
|
|
447
|
-
export function getLinesFromItems2(moldingGroup, layer, catalog) {
|
|
448
|
-
// wall lines
|
|
449
|
-
let allLineRects = GeometryUtils.buildRectFromLines(
|
|
450
|
-
layer,
|
|
451
|
-
GeometryUtils.getAllLines(layer)
|
|
452
|
-
);
|
|
453
|
-
let MGlines = [];
|
|
454
|
-
let MGlinesOtherSnapped = [];
|
|
455
|
-
|
|
456
|
-
let items = [...moldingGroup.items];
|
|
457
|
-
// The other item's lines (these items are snapped to the moldingGroup items)
|
|
458
|
-
let itemsOtherSnapped = layer.items.toArray().filter(item => {
|
|
459
|
-
if (items.some(it => item.id === it.id)) return false;
|
|
460
|
-
if (isItemSnappedGroup(item, items)) {
|
|
461
|
-
const itemLines = getLinesOfItem(item, allLineRects, catalog);
|
|
462
|
-
let itemAltitude = item.properties.get('altitude').get('_length');
|
|
463
|
-
let itemAltitudeUnit = item.properties.get('altitude').get('_unit');
|
|
464
|
-
itemAltitude = convert(itemAltitude).from(itemAltitudeUnit).to('cm');
|
|
465
|
-
let itemHeight = item.properties.get('height').get('_length');
|
|
466
|
-
let itemHeightUnit = item.properties.get('height').get('_unit');
|
|
467
|
-
itemHeight = convert(itemHeight).from(itemHeightUnit).to('cm');
|
|
468
|
-
itemLines.forEach(line => {
|
|
469
|
-
line.push({ altitude: itemAltitude, height: itemHeight });
|
|
470
|
-
});
|
|
471
|
-
MGlinesOtherSnapped = [...MGlinesOtherSnapped, ...itemLines];
|
|
472
|
-
return true;
|
|
473
|
-
} else return false;
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
// get all lines of moldingGroup items
|
|
477
|
-
items.forEach(item => {
|
|
478
|
-
let itemAltitude = item.properties.get('altitude').get('_length');
|
|
479
|
-
let itemAltitudeUnit = item.properties.get('altitude').get('_unit');
|
|
480
|
-
itemAltitude = convert(itemAltitude).from(itemAltitudeUnit).to('cm');
|
|
481
|
-
let itemHeight = item.properties.get('height').get('_length');
|
|
482
|
-
let itemHeightUnit = item.properties.get('height').get('_unit');
|
|
483
|
-
itemHeight = convert(itemHeight).from(itemHeightUnit).to('cm');
|
|
484
|
-
|
|
485
|
-
let itemLines = getLinesOfItem(item, allLineRects, catalog);
|
|
486
|
-
|
|
487
|
-
// remove the edge that overlapped with other snapped items
|
|
488
|
-
itemLines = itemLines.filter(itLine => {
|
|
489
|
-
let ret = true;
|
|
490
|
-
const srcLine = {
|
|
491
|
-
x1: itLine[0].x,
|
|
492
|
-
y1: itLine[0].y,
|
|
493
|
-
x2: itLine[1].x,
|
|
494
|
-
y2: itLine[1].y
|
|
495
|
-
};
|
|
496
|
-
for (let j = 0; j < MGlinesOtherSnapped.length; j++) {
|
|
497
|
-
let bCheck = false;
|
|
498
|
-
switch (moldingGroup.location_type) {
|
|
499
|
-
case TOP_MOLDING_LOCATION:
|
|
500
|
-
bCheck =
|
|
501
|
-
MGlinesOtherSnapped[j][3].altitude +
|
|
502
|
-
MGlinesOtherSnapped[j][3].height >
|
|
503
|
-
itemAltitude + itemHeight;
|
|
504
|
-
break;
|
|
505
|
-
case MIDDLE_MOLDING_LOCATION:
|
|
506
|
-
bCheck = true;
|
|
507
|
-
break;
|
|
508
|
-
case BOTTOM_MOLDING_LOCATION:
|
|
509
|
-
bCheck = MGlinesOtherSnapped[j][3].altitude < itemAltitude;
|
|
510
|
-
break;
|
|
511
|
-
}
|
|
512
|
-
if (
|
|
513
|
-
item.category !== 'cabinet' ||
|
|
514
|
-
![
|
|
515
|
-
BASE_CABINET_LAYOUTPOS,
|
|
516
|
-
WALL_CABINET_LAYOUTPOS,
|
|
517
|
-
TALL_CABINET_LAYOUTPOS
|
|
518
|
-
].includes(item.layoutpos)
|
|
519
|
-
)
|
|
520
|
-
bCheck = true;
|
|
521
|
-
if (bCheck) {
|
|
522
|
-
const destLine = {
|
|
523
|
-
x1: MGlinesOtherSnapped[j][0].x,
|
|
524
|
-
y1: MGlinesOtherSnapped[j][0].y,
|
|
525
|
-
x2: MGlinesOtherSnapped[j][1].x,
|
|
526
|
-
y2: MGlinesOtherSnapped[j][1].y
|
|
527
|
-
};
|
|
528
|
-
const rst = GeometryUtils.relationshipOfTwoOverlappedLines(
|
|
529
|
-
srcLine,
|
|
530
|
-
destLine
|
|
531
|
-
);
|
|
532
|
-
if (rst.result === OVERLAP_SAME || rst.result === OVERLAP_INCLUDED) {
|
|
533
|
-
ret = false;
|
|
534
|
-
break;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
return ret;
|
|
539
|
-
});
|
|
540
|
-
MGlines = [...MGlines, ...itemLines];
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
// Filtering overlapped edges and get contour edges
|
|
544
|
-
let removeLineIds = []; // remove the edge that fully overlapped to other edge
|
|
545
|
-
let newLines = []; // new countour edge segment that except the overlapped part
|
|
546
|
-
for (let i = 0; i < MGlines.length; i++) {
|
|
547
|
-
const srcLine = {
|
|
548
|
-
x1: MGlines[i][0].x,
|
|
549
|
-
y1: MGlines[i][0].y,
|
|
550
|
-
x2: MGlines[i][1].x,
|
|
551
|
-
y2: MGlines[i][1].y
|
|
552
|
-
};
|
|
553
|
-
for (let j = 0; j < MGlines.length; j++) {
|
|
554
|
-
if (i === j) continue;
|
|
555
|
-
const destLine = {
|
|
556
|
-
x1: MGlines[j][0].x,
|
|
557
|
-
y1: MGlines[j][0].y,
|
|
558
|
-
x2: MGlines[j][1].x,
|
|
559
|
-
y2: MGlines[j][1].y
|
|
560
|
-
};
|
|
561
|
-
const rst = GeometryUtils.relationshipOfTwoOverlappedLines(
|
|
562
|
-
srcLine,
|
|
563
|
-
destLine
|
|
564
|
-
);
|
|
565
|
-
if (rst.result === OVERLAP_SAME || rst.result === OVERLAP_INCLUDED) {
|
|
566
|
-
removeLineIds.push(i);
|
|
567
|
-
break;
|
|
568
|
-
} else if (rst.result === OVERLAP_SOME) {
|
|
569
|
-
removeLineIds.push(i);
|
|
570
|
-
const lineSegs = getTrimmedContourLineSegs(
|
|
571
|
-
rst.trimmedSegs,
|
|
572
|
-
MGlines.filter((v, idx) => idx !== i && idx !== j),
|
|
573
|
-
0
|
|
574
|
-
);
|
|
575
|
-
if (lineSegs.length > 0) newLines = [...newLines, ...lineSegs];
|
|
576
|
-
break;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
MGlines = MGlines.filter(
|
|
582
|
-
(line, idx) => !removeLineIds.some(id => idx === id)
|
|
583
|
-
);
|
|
584
|
-
if (newLines.length > 0) MGlines = [...MGlines, ...newLines];
|
|
585
|
-
|
|
586
|
-
// merge the collinear linked lines to one line
|
|
587
|
-
let newMGlines = [];
|
|
588
|
-
let filteredMGlines = MGlines;
|
|
589
|
-
for (let i = 0; i < MGlines.length; i++) {
|
|
590
|
-
if (filteredMGlines.length < 1) break;
|
|
591
|
-
if (!filteredMGlines.some(v => v[2] === MGlines[i][2])) continue;
|
|
592
|
-
let mergedResult = getMergedLine(MGlines[i], filteredMGlines);
|
|
593
|
-
newMGlines.push(mergedResult.mergedLine);
|
|
594
|
-
filteredMGlines = mergedResult.filteredMGlines;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
return newMGlines;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* Get the line that colinear linked with [line], and merge them to a new line
|
|
602
|
-
* @param {*} line
|
|
603
|
-
* @param {*} MGlines
|
|
604
|
-
* @returns
|
|
605
|
-
* - returns merged new line
|
|
606
|
-
* - returns filtered new line group (remove linked line from [MGlines])
|
|
607
|
-
*/
|
|
608
|
-
function getMergedLine(line, MGlines) {
|
|
609
|
-
let newMGlines = MGlines.filter(v => line[2] !== v[2]);
|
|
610
|
-
let mergeResult = {
|
|
611
|
-
mergedLine: line,
|
|
612
|
-
filteredMGlines: newMGlines
|
|
613
|
-
};
|
|
614
|
-
const srcLine = {
|
|
615
|
-
x1: line[0].x,
|
|
616
|
-
y1: line[0].y,
|
|
617
|
-
x2: line[1].x,
|
|
618
|
-
y2: line[1].y
|
|
619
|
-
};
|
|
620
|
-
for (let i = 0; i < newMGlines.length; i++) {
|
|
621
|
-
const destLine = {
|
|
622
|
-
x1: newMGlines[i][0].x,
|
|
623
|
-
y1: newMGlines[i][0].y,
|
|
624
|
-
x2: newMGlines[i][1].x,
|
|
625
|
-
y2: newMGlines[i][1].y
|
|
626
|
-
};
|
|
627
|
-
const rst = GeometryUtils.relationshipOfTwoOverlappedLines(
|
|
628
|
-
srcLine,
|
|
629
|
-
destLine
|
|
630
|
-
);
|
|
631
|
-
if (rst.result === OVERLAP_LINK) {
|
|
632
|
-
let mergedLine = [
|
|
633
|
-
{ x: rst.linkedLine.x1, y: rst.linkedLine.y1 },
|
|
634
|
-
{ x: rst.linkedLine.x2, y: rst.linkedLine.y2 },
|
|
635
|
-
IDBroker.acquireID()
|
|
636
|
-
];
|
|
637
|
-
mergeResult = getMergedLine(
|
|
638
|
-
mergedLine,
|
|
639
|
-
newMGlines.filter((v, idx) => idx !== i)
|
|
640
|
-
);
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
return mergeResult;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/**
|
|
647
|
-
* Get the contour line segments from [lineSegs]
|
|
648
|
-
* @param {*} lineSegs
|
|
649
|
-
* @param {*} otherLines
|
|
650
|
-
* @returns
|
|
651
|
-
*/
|
|
652
|
-
function getTrimmedContourLineSegs(lineSegs, otherLines, cnt) {
|
|
653
|
-
try {
|
|
654
|
-
cnt++;
|
|
655
|
-
if (cnt > 5000) return [];
|
|
656
|
-
let returnSegs = [];
|
|
657
|
-
for (let i = 0; i < lineSegs.length; i++) {
|
|
658
|
-
const srcLine = {
|
|
659
|
-
x1: lineSegs[i].x1,
|
|
660
|
-
y1: lineSegs[i].y1,
|
|
661
|
-
x2: lineSegs[i].x2,
|
|
662
|
-
y2: lineSegs[i].y2
|
|
663
|
-
};
|
|
664
|
-
let bContourSeg = true;
|
|
665
|
-
for (let j = 0; j < otherLines.length; j++) {
|
|
666
|
-
const destLine = {
|
|
667
|
-
x1: otherLines[j][0].x,
|
|
668
|
-
y1: otherLines[j][0].y,
|
|
669
|
-
x2: otherLines[j][1].x,
|
|
670
|
-
y2: otherLines[j][1].y
|
|
671
|
-
};
|
|
672
|
-
const rst = GeometryUtils.relationshipOfTwoOverlappedLines(
|
|
673
|
-
srcLine,
|
|
674
|
-
destLine
|
|
675
|
-
);
|
|
676
|
-
if (rst.result == OVERLAP_SAME || rst.result == OVERLAP_INCLUDED) {
|
|
677
|
-
bContourSeg = false;
|
|
678
|
-
break;
|
|
679
|
-
} else if (rst.result == OVERLAP_SOME) {
|
|
680
|
-
const tLineSegs = getTrimmedContourLineSegs(
|
|
681
|
-
rst.trimmedSegs,
|
|
682
|
-
otherLines.filter((v, idx) => idx !== j),
|
|
683
|
-
cnt
|
|
684
|
-
);
|
|
685
|
-
if (tLineSegs.length > 0) returnSegs = [...returnSegs, ...tLineSegs];
|
|
686
|
-
bContourSeg = false;
|
|
687
|
-
break;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
if (bContourSeg)
|
|
691
|
-
returnSegs.push([
|
|
692
|
-
{ x: lineSegs[i].x1, y: lineSegs[i].y1 },
|
|
693
|
-
{ x: lineSegs[i].x2, y: lineSegs[i].y2 },
|
|
694
|
-
IDBroker.acquireID()
|
|
695
|
-
]);
|
|
696
|
-
}
|
|
697
|
-
return returnSegs;
|
|
698
|
-
} catch (e) {
|
|
699
|
-
console.log('molding catched :', e);
|
|
700
|
-
return [];
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
export function getLinesFromItems(moldingGroup, layer, catalog) {
|
|
705
|
-
let allLineRects = GeometryUtils.buildRectFromLines(
|
|
706
|
-
layer,
|
|
707
|
-
GeometryUtils.getAllLines(layer)
|
|
708
|
-
);
|
|
709
|
-
let items = [...moldingGroup.items];
|
|
710
|
-
let MGlines = getLinesOfItem(items[0], allLineRects, catalog);
|
|
711
|
-
items = sortItemsByDistance(items, items[0]);
|
|
712
|
-
for (let i = 1; i < items.length; i++) {
|
|
713
|
-
let itemLines = getLinesOfItem(items[i], allLineRects, catalog);
|
|
714
|
-
let temp_MGLines = [];
|
|
715
|
-
MGlines.forEach(line => {
|
|
716
|
-
let idx = itemLines.findIndex(itemLine =>
|
|
717
|
-
isLinesOverlapped(line, itemLine)
|
|
718
|
-
);
|
|
719
|
-
const curItemLine = itemLines[idx];
|
|
720
|
-
if (idx > -1) {
|
|
721
|
-
if (
|
|
722
|
-
!(
|
|
723
|
-
(GeometryUtils.samePoints(line[0], curItemLine[0]) &&
|
|
724
|
-
GeometryUtils.samePoints(line[1], curItemLine[1])) ||
|
|
725
|
-
(GeometryUtils.samePoints(line[0], curItemLine[1]) &&
|
|
726
|
-
GeometryUtils.samePoints(line[1], curItemLine[0]))
|
|
727
|
-
)
|
|
728
|
-
) {
|
|
729
|
-
let MGLine = mergeOverlappedLines(line, curItemLine);
|
|
730
|
-
temp_MGLines.push(MGLine);
|
|
731
|
-
}
|
|
732
|
-
itemLines.splice(idx, 1);
|
|
733
|
-
} else {
|
|
734
|
-
temp_MGLines.push(line);
|
|
735
|
-
}
|
|
736
|
-
});
|
|
737
|
-
itemLines.forEach(itemLine => temp_MGLines.push(itemLine));
|
|
738
|
-
MGlines = [...temp_MGLines];
|
|
739
|
-
}
|
|
740
|
-
// return MGlines;
|
|
741
|
-
let snapped_other_items = layer.items.toArray().filter(item => {
|
|
742
|
-
if (items.some(it => item.id === it.id)) return false;
|
|
743
|
-
return isItemSnappedGroup(item, items);
|
|
744
|
-
});
|
|
745
|
-
snapped_other_items.forEach(item => {
|
|
746
|
-
let itemAltitude = item.properties.get('altitude').get('_length');
|
|
747
|
-
let itemAltitudeUnit = item.properties.get('altitude').get('_unit');
|
|
748
|
-
itemAltitude = convert(itemAltitude).from(itemAltitudeUnit).to('cm');
|
|
749
|
-
let itemHeight = item.properties.get('height').get('_length');
|
|
750
|
-
let itemHeightUnit = item.properties.get('height').get('_unit');
|
|
751
|
-
itemHeight = convert(itemHeight).from(itemHeightUnit).to('cm');
|
|
752
|
-
let mgroupAltitude = items[0].properties.get('altitude').get('_length');
|
|
753
|
-
let mgroupAltitudeUnit = items[0].properties.get('altitude').get('_unit');
|
|
754
|
-
mgroupAltitude = convert(mgroupAltitude).from(mgroupAltitudeUnit).to('cm');
|
|
755
|
-
let mgroupHeight = items[0].properties.get('height').get('_length');
|
|
756
|
-
let mgroupHeightUnit = items[0].properties.get('height').get('_unit');
|
|
757
|
-
mgroupHeight = convert(mgroupHeight).from(mgroupHeightUnit).to('cm');
|
|
758
|
-
let flag = false;
|
|
759
|
-
switch (moldingGroup.location_type) {
|
|
760
|
-
case TOP_MOLDING_LOCATION:
|
|
761
|
-
flag = itemAltitude + itemHeight > mgroupAltitude + mgroupHeight;
|
|
762
|
-
break;
|
|
763
|
-
case MIDDLE_MOLDING_LOCATION:
|
|
764
|
-
flag = true;
|
|
765
|
-
break;
|
|
766
|
-
case BOTTOM_MOLDING_LOCATION:
|
|
767
|
-
flag = itemAltitude < mgroupAltitude;
|
|
768
|
-
break;
|
|
769
|
-
}
|
|
770
|
-
if (
|
|
771
|
-
item.category !== 'cabinet' ||
|
|
772
|
-
![
|
|
773
|
-
BASE_CABINET_LAYOUTPOS,
|
|
774
|
-
WALL_CABINET_LAYOUTPOS,
|
|
775
|
-
TALL_CABINET_LAYOUTPOS
|
|
776
|
-
].includes(item.layoutpos)
|
|
777
|
-
)
|
|
778
|
-
flag = true;
|
|
779
|
-
if (flag) {
|
|
780
|
-
let itemLines = getLinesOfItem(item, allLineRects, catalog);
|
|
781
|
-
let temp_MGLines = [];
|
|
782
|
-
MGlines.forEach(mgl => {
|
|
783
|
-
let idx = itemLines.findIndex(itl => isLinesOverlapped(mgl, itl));
|
|
784
|
-
const curITL = itemLines[idx];
|
|
785
|
-
if (idx > -1) {
|
|
786
|
-
if (
|
|
787
|
-
getDelta(mgl[0], mgl[1], curITL[1], curITL[0]) < EPSILON ||
|
|
788
|
-
getDelta(mgl[0], mgl[1], curITL[0], curITL[1]) < EPSILON
|
|
789
|
-
) {
|
|
790
|
-
if (
|
|
791
|
-
GeometryUtils.verticesDistance(mgl[0], mgl[1]) >
|
|
792
|
-
GeometryUtils.verticesDistance(curITL[0], curITL[1])
|
|
793
|
-
) {
|
|
794
|
-
let MGLine = mergeOverlappedLines(mgl, curITL);
|
|
795
|
-
temp_MGLines.push(MGLine);
|
|
796
|
-
}
|
|
797
|
-
itemLines.splice(idx, 1);
|
|
798
|
-
} else {
|
|
799
|
-
temp_MGLines.push(mgl);
|
|
800
|
-
}
|
|
801
|
-
} else {
|
|
802
|
-
temp_MGLines.push(mgl);
|
|
803
|
-
}
|
|
804
|
-
});
|
|
805
|
-
MGlines = [...temp_MGLines];
|
|
806
|
-
}
|
|
807
|
-
});
|
|
808
|
-
return MGlines;
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
function getMDPoints(newMD) {
|
|
812
|
-
if (newMD.lines.length < 1)
|
|
813
|
-
return {
|
|
814
|
-
...newMD,
|
|
815
|
-
pointGroups: []
|
|
816
|
-
};
|
|
817
|
-
// let maxX = newMD.lines[0][0].x,
|
|
818
|
-
let maxX = newMD.lines[0][0].x,
|
|
819
|
-
minX = newMD.lines[0][0].x;
|
|
820
|
-
let maxY = newMD.lines[0][0].y,
|
|
821
|
-
minY = newMD.lines[0][0].y;
|
|
822
|
-
|
|
823
|
-
newMD.lines.forEach(line => {
|
|
824
|
-
if (line[0].x > maxX) {
|
|
825
|
-
maxX = line[0].x;
|
|
826
|
-
}
|
|
827
|
-
if (line[0].x < minX) {
|
|
828
|
-
minX = line[0].x;
|
|
829
|
-
}
|
|
830
|
-
if (line[1].x > maxX) {
|
|
831
|
-
maxX = line[1].x;
|
|
832
|
-
}
|
|
833
|
-
if (line[1].x < minX) {
|
|
834
|
-
minX = line[1].x;
|
|
835
|
-
}
|
|
836
|
-
if (line[0].y > maxY) {
|
|
837
|
-
maxY = line[0].y;
|
|
838
|
-
}
|
|
839
|
-
if (line[0].y < minY) {
|
|
840
|
-
minY = line[0].y;
|
|
841
|
-
}
|
|
842
|
-
if (line[1].y > maxY) {
|
|
843
|
-
maxY = line[1].y;
|
|
844
|
-
}
|
|
845
|
-
if (line[1].y < minY) {
|
|
846
|
-
minY = line[1].y;
|
|
847
|
-
}
|
|
848
|
-
});
|
|
849
|
-
|
|
850
|
-
let cPos = {
|
|
851
|
-
x: (maxX + minX) / 2,
|
|
852
|
-
y: (maxY + minY) / 2
|
|
853
|
-
};
|
|
854
|
-
|
|
855
|
-
let newSize = { ...newMD.size, width: maxX - minX, depth: maxY - minY };
|
|
856
|
-
|
|
857
|
-
// get vertex points
|
|
858
|
-
let MDlines = [...newMD.lines];
|
|
859
|
-
let pointGroups = [[]];
|
|
860
|
-
let flag = 1;
|
|
861
|
-
let i = 0;
|
|
862
|
-
while (MDlines.length !== 0) {
|
|
863
|
-
if (pointGroups[i].length === 0) {
|
|
864
|
-
pointGroups[i].push(
|
|
865
|
-
new Three.Vector2(MDlines[0][0].x - cPos.x, MDlines[0][0].y - cPos.y),
|
|
866
|
-
new Three.Vector2(MDlines[0][1].x - cPos.x, MDlines[0][1].y - cPos.y)
|
|
867
|
-
);
|
|
868
|
-
MDlines.splice(0, 1);
|
|
869
|
-
} else {
|
|
870
|
-
if (flag) {
|
|
871
|
-
let lastPoint = pointGroups[i][pointGroups[i].length - 1];
|
|
872
|
-
let res = MDlines.findIndex(
|
|
873
|
-
a =>
|
|
874
|
-
GeometryUtils.samePoints(
|
|
875
|
-
{ x: a[0].x - cPos.x, y: a[0].y - cPos.y },
|
|
876
|
-
lastPoint
|
|
877
|
-
) ||
|
|
878
|
-
GeometryUtils.samePoints(
|
|
879
|
-
{ x: a[1].x - cPos.x, y: a[1].y - cPos.y },
|
|
880
|
-
lastPoint
|
|
881
|
-
)
|
|
882
|
-
);
|
|
883
|
-
if (res > -1) {
|
|
884
|
-
let newPos = {
|
|
885
|
-
x: MDlines[res][0].x - cPos.x,
|
|
886
|
-
y: MDlines[res][0].y - cPos.y
|
|
887
|
-
};
|
|
888
|
-
if (GeometryUtils.samePoints(newPos, lastPoint)) {
|
|
889
|
-
newPos = {
|
|
890
|
-
x: MDlines[res][1].x - cPos.x,
|
|
891
|
-
y: MDlines[res][1].y - cPos.y
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
pointGroups[i].push(new Three.Vector2(newPos.x, newPos.y));
|
|
895
|
-
MDlines.splice(res, 1);
|
|
896
|
-
} else {
|
|
897
|
-
flag = 0;
|
|
898
|
-
}
|
|
899
|
-
} else {
|
|
900
|
-
let firstPoint = pointGroups[i][0];
|
|
901
|
-
let res = MDlines.findIndex(
|
|
902
|
-
a =>
|
|
903
|
-
GeometryUtils.samePoints(
|
|
904
|
-
{ x: a[0].x - cPos.x, y: a[0].y - cPos.y },
|
|
905
|
-
firstPoint
|
|
906
|
-
) ||
|
|
907
|
-
GeometryUtils.samePoints(
|
|
908
|
-
{ x: a[1].x - cPos.x, y: a[1].y - cPos.y },
|
|
909
|
-
firstPoint
|
|
910
|
-
)
|
|
911
|
-
);
|
|
912
|
-
if (res > -1) {
|
|
913
|
-
let newPos = {
|
|
914
|
-
x: MDlines[res][0].x - cPos.x,
|
|
915
|
-
y: MDlines[res][0].y - cPos.y
|
|
916
|
-
};
|
|
917
|
-
if (GeometryUtils.samePoints(newPos, firstPoint)) {
|
|
918
|
-
newPos = {
|
|
919
|
-
x: MDlines[res][1].x - cPos.x,
|
|
920
|
-
y: MDlines[res][1].y - cPos.y
|
|
921
|
-
};
|
|
922
|
-
}
|
|
923
|
-
pointGroups[i] = [
|
|
924
|
-
new Three.Vector2(newPos.x, newPos.y),
|
|
925
|
-
...pointGroups[i]
|
|
926
|
-
];
|
|
927
|
-
MDlines.splice(res, 1);
|
|
928
|
-
} else {
|
|
929
|
-
flag = 1;
|
|
930
|
-
i++;
|
|
931
|
-
if (MDlines.length !== 0) pointGroups.push([]);
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
let z = newMD.items[0].properties.get('altitude').get('_length');
|
|
938
|
-
let zUnit = newMD.items[0].properties.get('altitude').get('_unit') || 'cm';
|
|
939
|
-
z = convert(z).from(zUnit).to('cm');
|
|
940
|
-
let height = newMD.items[0].properties.get('height').get('_length');
|
|
941
|
-
let heightUnit = newMD.items[0].properties.get('height').get('_unit') || 'cm';
|
|
942
|
-
height = convert(height).from(heightUnit).to('cm');
|
|
943
|
-
|
|
944
|
-
switch (newMD.location_type) {
|
|
945
|
-
case TOP_MOLDING_LOCATION:
|
|
946
|
-
z += height;
|
|
947
|
-
break;
|
|
948
|
-
case MIDDLE_MOLDING_LOCATION:
|
|
949
|
-
z += height / 2;
|
|
950
|
-
break;
|
|
951
|
-
case BOTTOM_MOLDING_LOCATION:
|
|
952
|
-
z += 0;
|
|
953
|
-
break;
|
|
954
|
-
default:
|
|
955
|
-
break;
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
return {
|
|
959
|
-
...newMD,
|
|
960
|
-
pointGroups,
|
|
961
|
-
pos: { ...cPos, z: z },
|
|
962
|
-
size: newSize
|
|
963
|
-
};
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
export function createMonldingGroup(oldMG, layer, molding, catalog) {
|
|
967
|
-
let newMG = { ...oldMG };
|
|
968
|
-
newMG.molding = molding;
|
|
969
|
-
newMG.lines = getLinesFromItems2(oldMG, layer, catalog);
|
|
970
|
-
newMG.lines.reverse();
|
|
971
|
-
newMG = getMDPoints(newMG);
|
|
972
|
-
return newMG;
|
|
973
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
BASE_CABINET_LAYOUTPOS,
|
|
3
|
+
BOTTOM_MOLDING_LOCATION,
|
|
4
|
+
EPSILON,
|
|
5
|
+
MIDDLE_MOLDING_LOCATION,
|
|
6
|
+
MOLDING_LOCATIONS,
|
|
7
|
+
OVERLAP_INCLUDED,
|
|
8
|
+
OVERLAP_LINK,
|
|
9
|
+
OVERLAP_SAME,
|
|
10
|
+
OVERLAP_SOME,
|
|
11
|
+
TALL_CABINET_LAYOUTPOS,
|
|
12
|
+
TOP_MOLDING_LOCATION,
|
|
13
|
+
WALL_CABINET_LAYOUTPOS
|
|
14
|
+
} from '../constants';
|
|
15
|
+
import * as Three from 'three';
|
|
16
|
+
import * as convert from 'convert-units';
|
|
17
|
+
import IDBroker from './id-broker';
|
|
18
|
+
import { returnReplaceableDeepSearchType } from '../components/viewer2d/utils';
|
|
19
|
+
import { GeometryUtils } from './export';
|
|
20
|
+
import { isEmpty } from './helper';
|
|
21
|
+
|
|
22
|
+
export function getItemRect(item) {
|
|
23
|
+
let x = item.x;
|
|
24
|
+
let y = item.y;
|
|
25
|
+
let rotRad = (item.rotation / 180) * Math.PI;
|
|
26
|
+
let itemWidth = item.properties.get('width').get('_length');
|
|
27
|
+
let itemWidthUnit = item.properties.get('width').get('_unit') || 'cm';
|
|
28
|
+
itemWidth = convert(itemWidth / 2)
|
|
29
|
+
.from(itemWidthUnit)
|
|
30
|
+
.to('cm');
|
|
31
|
+
let itemDepth = item.properties.get('depth').get('_length');
|
|
32
|
+
let itemDepthUnit = item.properties.get('depth').get('_unit') || 'cm';
|
|
33
|
+
itemDepth = convert(itemDepth / 2)
|
|
34
|
+
.from(itemDepthUnit)
|
|
35
|
+
.to('cm');
|
|
36
|
+
let mx = x - itemWidth * Math.cos(rotRad);
|
|
37
|
+
let my = y - itemWidth * Math.sin(rotRad);
|
|
38
|
+
let x0 = mx + itemDepth * Math.sin(rotRad);
|
|
39
|
+
let y0 = my - itemDepth * Math.cos(rotRad);
|
|
40
|
+
let x3 = mx * 2 - x0;
|
|
41
|
+
let y3 = my * 2 - y0;
|
|
42
|
+
let x1 = x * 2 - x3;
|
|
43
|
+
let y1 = y * 2 - y3;
|
|
44
|
+
let x2 = x * 2 - x0;
|
|
45
|
+
let y2 = y * 2 - y0;
|
|
46
|
+
return {
|
|
47
|
+
rect: [
|
|
48
|
+
{ x: x0, y: y0 },
|
|
49
|
+
{ x: x1, y: y1 },
|
|
50
|
+
{ x: x2, y: y2 },
|
|
51
|
+
{ x: x3, y: y3 }
|
|
52
|
+
]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function hasMoldingLayout(molding, layoutpos) {
|
|
57
|
+
const types = molding?.molding_type;
|
|
58
|
+
return (
|
|
59
|
+
(Array.isArray(types) || typeof types === 'string') &&
|
|
60
|
+
types.includes(layoutpos)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function isEnableItemForMolding(layer, selItem, molding = null) {
|
|
65
|
+
let allLineRects = GeometryUtils.buildRectFromLines(
|
|
66
|
+
layer,
|
|
67
|
+
GeometryUtils.getAllLines(layer)
|
|
68
|
+
);
|
|
69
|
+
let result =
|
|
70
|
+
!isEmpty(selItem) &&
|
|
71
|
+
selItem.category === 'cabinet' &&
|
|
72
|
+
((selItem.layoutpos === BASE_CABINET_LAYOUTPOS &&
|
|
73
|
+
!GeometryUtils.isSnappedLine(getItemRect(selItem), allLineRects)) ||
|
|
74
|
+
((selItem.layoutpos === WALL_CABINET_LAYOUTPOS ||
|
|
75
|
+
selItem.layoutpos === TALL_CABINET_LAYOUTPOS) &&
|
|
76
|
+
GeometryUtils.isSnappedLine(getItemRect(selItem), allLineRects)));
|
|
77
|
+
|
|
78
|
+
// check this item is enable for any molding
|
|
79
|
+
if (isEmpty(molding)) return result;
|
|
80
|
+
// check this item is enable for specified molding
|
|
81
|
+
else return result && hasMoldingLayout(molding, selItem.layoutpos);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check two line segments are overlap. The direction of the two line segments must be opposite.
|
|
86
|
+
* s1 c2 s2 c1
|
|
87
|
+
* |--------|------|-----------|
|
|
88
|
+
* Decision Formular: L(s1,c1) + L(s2, c2) = L(s1, s2) + L(c1, c2)
|
|
89
|
+
* @param {*} selRectPos1
|
|
90
|
+
* @param {*} selRectPos2
|
|
91
|
+
* @param {*} curRectPos1
|
|
92
|
+
* @param {*} curRectPos2
|
|
93
|
+
* @returns L(s1,c1) + L(s2, c2) - L(s1, s2) - L(c1, c2)
|
|
94
|
+
*/
|
|
95
|
+
function getDelta(selRectPos1, selRectPos2, curRectPos1, curRectPos2) {
|
|
96
|
+
return (
|
|
97
|
+
// GeometryUtils.verticesDistance(curRectPos1, selRectPos2) +
|
|
98
|
+
// GeometryUtils.verticesDistance(selRectPos1, curRectPos2) -
|
|
99
|
+
// Math.abs(
|
|
100
|
+
// GeometryUtils.verticesDistance(curRectPos2, curRectPos1) -
|
|
101
|
+
// GeometryUtils.verticesDistance(selRectPos1, selRectPos2)
|
|
102
|
+
// )
|
|
103
|
+
Math.abs(
|
|
104
|
+
GeometryUtils.verticesDistance(curRectPos1, selRectPos1) +
|
|
105
|
+
GeometryUtils.verticesDistance(selRectPos2, curRectPos2) -
|
|
106
|
+
GeometryUtils.verticesDistance(curRectPos2, curRectPos1) -
|
|
107
|
+
GeometryUtils.verticesDistance(selRectPos1, selRectPos2)
|
|
108
|
+
)
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function isItemSnappedItem(selItem, curItem) {
|
|
113
|
+
const selRect = getItemRect(selItem).rect;
|
|
114
|
+
const curRect = getItemRect(curItem).rect;
|
|
115
|
+
const flag30 =
|
|
116
|
+
getDelta(selRect[3], selRect[0], curRect[1], curRect[2]) < EPSILON;
|
|
117
|
+
const flag21 =
|
|
118
|
+
getDelta(selRect[2], selRect[1], curRect[0], curRect[3]) < EPSILON;
|
|
119
|
+
const flag23 =
|
|
120
|
+
getDelta(selRect[2], selRect[3], curRect[2], curRect[3]) < EPSILON;
|
|
121
|
+
const flag01 =
|
|
122
|
+
getDelta(selRect[1], selRect[0], curRect[0], curRect[3]) < EPSILON;
|
|
123
|
+
const flag03 =
|
|
124
|
+
getDelta(selRect[0], selRect[3], curRect[1], curRect[0]) < EPSILON;
|
|
125
|
+
return flag30 || flag21 || flag23 || flag01 || flag03;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function isItemSnappedGroup(selItem, itemGroup) {
|
|
129
|
+
return itemGroup.some(curItem => isItemSnappedItem(selItem, curItem));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function sortItemsByDistance(items, selItem) {
|
|
133
|
+
items.sort((a, b) => {
|
|
134
|
+
return (
|
|
135
|
+
GeometryUtils.pointsDistance(a.x, a.y, selItem.x, selItem.y) -
|
|
136
|
+
GeometryUtils.pointsDistance(b.x, b.y, selItem.x, selItem.y)
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
return items;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function isSameMoldingLayoutpos(curItem, item) {
|
|
143
|
+
return (
|
|
144
|
+
(curItem.layoutpos === BASE_CABINET_LAYOUTPOS &&
|
|
145
|
+
curItem.layoutpos === item.layoutpos) ||
|
|
146
|
+
([WALL_CABINET_LAYOUTPOS, TALL_CABINET_LAYOUTPOS].includes(
|
|
147
|
+
curItem.layoutpos
|
|
148
|
+
) &&
|
|
149
|
+
[WALL_CABINET_LAYOUTPOS, TALL_CABINET_LAYOUTPOS].includes(item.layoutpos))
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function isItemSameItemByLocation(item1, item2, location) {
|
|
154
|
+
let item1Altitude = item1.properties.get('altitude').get('_length');
|
|
155
|
+
let item1AltitudeUnit = item1.properties.get('altitude').get('_unit');
|
|
156
|
+
item1Altitude = convert(item1Altitude).from(item1AltitudeUnit).to('cm');
|
|
157
|
+
let item1Height = item1.properties.get('height').get('_length');
|
|
158
|
+
let item1HeightUnit = item1.properties.get('height').get('_unit');
|
|
159
|
+
item1Height = convert(item1Height).from(item1HeightUnit).to('cm');
|
|
160
|
+
let item2Altitude = item2.properties.get('altitude').get('_length');
|
|
161
|
+
let item2AltitudeUnit = item2.properties.get('altitude').get('_unit');
|
|
162
|
+
item2Altitude = convert(item2Altitude).from(item2AltitudeUnit).to('cm');
|
|
163
|
+
let item2Height = item2.properties.get('height').get('_length');
|
|
164
|
+
let item2HeightUnit = item2.properties.get('height').get('_unit');
|
|
165
|
+
item2Height = convert(item2Height).from(item2HeightUnit).to('cm');
|
|
166
|
+
let flag = false;
|
|
167
|
+
switch (location) {
|
|
168
|
+
case TOP_MOLDING_LOCATION:
|
|
169
|
+
if (
|
|
170
|
+
GeometryUtils.sameDistances(
|
|
171
|
+
item1Altitude + item1Height,
|
|
172
|
+
item2Altitude + item2Height
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
flag = true;
|
|
176
|
+
break;
|
|
177
|
+
case MIDDLE_MOLDING_LOCATION:
|
|
178
|
+
if (
|
|
179
|
+
GeometryUtils.sameDistances(
|
|
180
|
+
item1Altitude + item1Height / 2,
|
|
181
|
+
item2Altitude + item2Height / 2
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
flag = true;
|
|
185
|
+
break;
|
|
186
|
+
case BOTTOM_MOLDING_LOCATION:
|
|
187
|
+
if (GeometryUtils.sameDistances(item1Altitude, item2Altitude))
|
|
188
|
+
flag = true;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
return flag;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function tryMergeMDItem(layer, selItem, curItem, itemGroup, molding) {
|
|
195
|
+
return (
|
|
196
|
+
isSameMoldingLayoutpos(selItem, curItem) &&
|
|
197
|
+
isEnableItemForMolding(layer, curItem, molding) &&
|
|
198
|
+
isItemSnappedGroup(curItem, itemGroup) &&
|
|
199
|
+
!itemGroup.some(item => item.id === curItem.id) &&
|
|
200
|
+
isItemSameItemByLocation(selItem, curItem, molding.location_type)
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function getItemGroupFromMolding(layer, curItem, molding) {
|
|
205
|
+
const selectedItem = layer.getIn(['items', layer.selected.toJS().items[0]]);
|
|
206
|
+
let itemGroup = [curItem];
|
|
207
|
+
let temp_layer_items = layer.items.toArray().filter(item => {
|
|
208
|
+
return (
|
|
209
|
+
item.category === 'cabinet' &&
|
|
210
|
+
item.id !== curItem.id &&
|
|
211
|
+
item.id !== selectedItem?.id
|
|
212
|
+
);
|
|
213
|
+
});
|
|
214
|
+
temp_layer_items = sortItemsByDistance(temp_layer_items, curItem);
|
|
215
|
+
for (let idx = 0; idx < temp_layer_items.length; idx++) {
|
|
216
|
+
if (
|
|
217
|
+
tryMergeMDItem(layer, curItem, temp_layer_items[idx], itemGroup, molding)
|
|
218
|
+
) {
|
|
219
|
+
itemGroup.push(temp_layer_items[idx]);
|
|
220
|
+
idx = 0;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return itemGroup;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function tryMergeItemWithLocation(curItem, itemGroup, location) {
|
|
227
|
+
return itemGroup.some(item => {
|
|
228
|
+
return (
|
|
229
|
+
isItemSnappedItem(curItem, item) &&
|
|
230
|
+
isItemSameItemByLocation(curItem, item, location)
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function getAllMoldingGroups(layer, items = null) {
|
|
236
|
+
if (items === null) items = layer.items.toArray();
|
|
237
|
+
let itemGroups = [];
|
|
238
|
+
items.forEach(curItem => {
|
|
239
|
+
// let allLineRects = GeometryUtils.buildRectFromLines(
|
|
240
|
+
// layer,
|
|
241
|
+
// GeometryUtils.getAllLines(layer)
|
|
242
|
+
// );
|
|
243
|
+
// if (
|
|
244
|
+
// (curItem.category === 'cabinet' &&
|
|
245
|
+
// curItem.layoutpos === BASE_CABINET_LAYOUTPOS &&
|
|
246
|
+
// !GeometryUtils.isSnappedLine(getItemRect(curItem), allLineRects)) ||
|
|
247
|
+
// ((curItem.layoutpos === WALL_CABINET_LAYOUTPOS ||
|
|
248
|
+
// curItem.layoutpos === TALL_CABINET_LAYOUTPOS) &&
|
|
249
|
+
// GeometryUtils.isSnappedLine(getItemRect(curItem), allLineRects))
|
|
250
|
+
// ) {
|
|
251
|
+
if (curItem.category === 'cabinet') {
|
|
252
|
+
let temp_items = items.filter(it => {
|
|
253
|
+
return (
|
|
254
|
+
it.category === 'cabinet' &&
|
|
255
|
+
isSameMoldingLayoutpos(curItem, it) &&
|
|
256
|
+
it.id !== curItem.id
|
|
257
|
+
);
|
|
258
|
+
});
|
|
259
|
+
temp_items = sortItemsByDistance(temp_items, curItem);
|
|
260
|
+
MOLDING_LOCATIONS.forEach(location => {
|
|
261
|
+
if (
|
|
262
|
+
!itemGroups.some(
|
|
263
|
+
ig =>
|
|
264
|
+
ig.items.some(it => it.id === curItem.id) &&
|
|
265
|
+
ig.location_type === location
|
|
266
|
+
)
|
|
267
|
+
) {
|
|
268
|
+
let itemGroup = [curItem];
|
|
269
|
+
for (let idx = 0; idx < temp_items.length; idx++) {
|
|
270
|
+
if (
|
|
271
|
+
tryMergeItemWithLocation(temp_items[idx], itemGroup, location)
|
|
272
|
+
) {
|
|
273
|
+
itemGroup.push(temp_items[idx]);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
itemGroups.push({
|
|
277
|
+
id: IDBroker.acquireID(),
|
|
278
|
+
items: itemGroup,
|
|
279
|
+
location_type: location,
|
|
280
|
+
molding: null,
|
|
281
|
+
lines: null,
|
|
282
|
+
pointGroups: null,
|
|
283
|
+
meshes: [],
|
|
284
|
+
rot: 0,
|
|
285
|
+
pos: 0
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
// }
|
|
291
|
+
});
|
|
292
|
+
return itemGroups;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export function getLinesOfItem(item, allLineRects, catalog) {
|
|
296
|
+
let lines = [];
|
|
297
|
+
let outline = null;
|
|
298
|
+
let element = catalog.elements[item.get('type')];
|
|
299
|
+
if (!element)
|
|
300
|
+
element =
|
|
301
|
+
catalog.elements[returnReplaceableDeepSearchType(item.get('type'))];
|
|
302
|
+
// get edge lines
|
|
303
|
+
let newWidth = item.properties.get('width').get('_length');
|
|
304
|
+
let wUnit = item.properties.get('width').get('_unit') || 'cm';
|
|
305
|
+
newWidth = convert(newWidth).from(wUnit).to('cm');
|
|
306
|
+
let newDepth = item.properties.get('depth').get('_length');
|
|
307
|
+
let hUnit = item.properties.get('depth').get('_unit') || 'cm';
|
|
308
|
+
newDepth = convert(newDepth).from(hUnit).to('cm');
|
|
309
|
+
if (item) {
|
|
310
|
+
// Get Outline Data of Selected Item
|
|
311
|
+
outline = element.info.outline;
|
|
312
|
+
|
|
313
|
+
if (outline) {
|
|
314
|
+
// Extract Points from `outline`
|
|
315
|
+
var outlinePaths = outline.paths;
|
|
316
|
+
var outlineWidth = outline.svgWidth;
|
|
317
|
+
var outlineHeight = outline.svgHeight;
|
|
318
|
+
var outlinePoints = []; // Hold Points Of SVG
|
|
319
|
+
for (let path of outlinePaths) {
|
|
320
|
+
for (let subPath of path.subPaths) {
|
|
321
|
+
outlinePoints = outlinePoints.concat(subPath.getPoints());
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
outline.reverse && outlinePoints.reverse();
|
|
325
|
+
for (let i = 0; i < outlinePoints.length - 1; i++) {
|
|
326
|
+
lines.push([
|
|
327
|
+
GeometryUtils.rotatePointAroundPoint(
|
|
328
|
+
(outlinePoints[i].x / outlineWidth - 0.5) * newWidth + item.x,
|
|
329
|
+
(outlinePoints[i].y / outlineHeight - 0.5) * newDepth + item.y,
|
|
330
|
+
item.x,
|
|
331
|
+
item.y,
|
|
332
|
+
item.rotation + 90
|
|
333
|
+
),
|
|
334
|
+
GeometryUtils.rotatePointAroundPoint(
|
|
335
|
+
(outlinePoints[i + 1].x / outlineWidth - 0.5) * newWidth + item.x,
|
|
336
|
+
(outlinePoints[i + 1].y / outlineHeight - 0.5) * newDepth + item.y,
|
|
337
|
+
item.x,
|
|
338
|
+
item.y,
|
|
339
|
+
item.rotation + 90
|
|
340
|
+
),
|
|
341
|
+
IDBroker.acquireID()
|
|
342
|
+
]);
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
let pos = [
|
|
346
|
+
[-1, -1],
|
|
347
|
+
[1, -1],
|
|
348
|
+
[1, 1],
|
|
349
|
+
[-1, 1]
|
|
350
|
+
];
|
|
351
|
+
for (let i = 0; i < 4; i++) {
|
|
352
|
+
lines.push([
|
|
353
|
+
GeometryUtils.rotatePointAroundPoint(
|
|
354
|
+
(pos[i][0] * newWidth) / 2 + item.x,
|
|
355
|
+
(pos[i][1] * newDepth) / 2 + item.y,
|
|
356
|
+
item.x,
|
|
357
|
+
item.y,
|
|
358
|
+
item.rotation
|
|
359
|
+
),
|
|
360
|
+
GeometryUtils.rotatePointAroundPoint(
|
|
361
|
+
(pos[(i + 1) % 4][0] * newWidth) / 2 + item.x,
|
|
362
|
+
(pos[(i + 1) % 4][1] * newDepth) / 2 + item.y,
|
|
363
|
+
item.x,
|
|
364
|
+
item.y,
|
|
365
|
+
item.rotation
|
|
366
|
+
),
|
|
367
|
+
IDBroker.acquireID()
|
|
368
|
+
]);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (item.layoutpos !== BASE_CABINET_LAYOUTPOS) {
|
|
373
|
+
lines = lines.filter(
|
|
374
|
+
line =>
|
|
375
|
+
!GeometryUtils.isSnappedLine(
|
|
376
|
+
{ rect: [{ x: 0, y: 0 }, { x: 0, y: 0 }, line[0], line[1]] },
|
|
377
|
+
allLineRects
|
|
378
|
+
)
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
return lines;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function isParallelLines(line1, line2) {
|
|
385
|
+
let isParallel = false;
|
|
386
|
+
if (
|
|
387
|
+
Math.abs(line1[0].y - line1[1].y) <= EPSILON &&
|
|
388
|
+
Math.abs(line2[0].y - line2[1].y) <= EPSILON
|
|
389
|
+
)
|
|
390
|
+
isParallel = true;
|
|
391
|
+
if (
|
|
392
|
+
Math.abs(line1[0].x - line1[1].x) <= EPSILON &&
|
|
393
|
+
Math.abs(line2[0].x - line2[1].x) <= EPSILON
|
|
394
|
+
)
|
|
395
|
+
isParallel = true;
|
|
396
|
+
if (
|
|
397
|
+
Math.abs(
|
|
398
|
+
(line1[0].x - line1[1].x) / (line1[0].y - line1[1].y) -
|
|
399
|
+
(line2[0].x - line2[1].x) / (line2[0].y - line2[1].y)
|
|
400
|
+
) <= EPSILON
|
|
401
|
+
)
|
|
402
|
+
isParallel = true;
|
|
403
|
+
if (isParallel) {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export function isLinesOverlapped(line1, line2) {
|
|
410
|
+
return (
|
|
411
|
+
isParallelLines(line1, line2) &&
|
|
412
|
+
line1.some(l1 => line2.some(l2 => GeometryUtils.samePoints(l1, l2)))
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export function mergeOverlappedLines(line1, line2) {
|
|
417
|
+
let line1_idx = 0,
|
|
418
|
+
line2_idx = 0;
|
|
419
|
+
line1.forEach((l1, idx1) => {
|
|
420
|
+
if (idx1 !== line1.length - 1) {
|
|
421
|
+
line2.forEach((l2, idx2) => {
|
|
422
|
+
if (idx2 !== line2.length - 1) {
|
|
423
|
+
if (GeometryUtils.samePoints(l1, l2)) {
|
|
424
|
+
line1_idx = idx1;
|
|
425
|
+
line2_idx = idx2;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
//If line1 's end point and line2 's start point is same, two lines merge into a line with
|
|
432
|
+
//the line1's start point as the start point and line2's end point as the end point.
|
|
433
|
+
if (line1_idx === 1) {
|
|
434
|
+
return [line1[1 - line1_idx], line2[1 - line2_idx], IDBroker.acquireID()];
|
|
435
|
+
} else {
|
|
436
|
+
return [line2[1 - line2_idx], line1[1 - line1_idx], IDBroker.acquireID()];
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Get the contour line array of moldingGroup items
|
|
442
|
+
* @param {*} moldingGroup
|
|
443
|
+
* @param {*} layer
|
|
444
|
+
* @param {*} catalog
|
|
445
|
+
* @returns contour line array of moldingGroup items
|
|
446
|
+
*/
|
|
447
|
+
export function getLinesFromItems2(moldingGroup, layer, catalog) {
|
|
448
|
+
// wall lines
|
|
449
|
+
let allLineRects = GeometryUtils.buildRectFromLines(
|
|
450
|
+
layer,
|
|
451
|
+
GeometryUtils.getAllLines(layer)
|
|
452
|
+
);
|
|
453
|
+
let MGlines = [];
|
|
454
|
+
let MGlinesOtherSnapped = [];
|
|
455
|
+
|
|
456
|
+
let items = [...moldingGroup.items];
|
|
457
|
+
// The other item's lines (these items are snapped to the moldingGroup items)
|
|
458
|
+
let itemsOtherSnapped = layer.items.toArray().filter(item => {
|
|
459
|
+
if (items.some(it => item.id === it.id)) return false;
|
|
460
|
+
if (isItemSnappedGroup(item, items)) {
|
|
461
|
+
const itemLines = getLinesOfItem(item, allLineRects, catalog);
|
|
462
|
+
let itemAltitude = item.properties.get('altitude').get('_length');
|
|
463
|
+
let itemAltitudeUnit = item.properties.get('altitude').get('_unit');
|
|
464
|
+
itemAltitude = convert(itemAltitude).from(itemAltitudeUnit).to('cm');
|
|
465
|
+
let itemHeight = item.properties.get('height').get('_length');
|
|
466
|
+
let itemHeightUnit = item.properties.get('height').get('_unit');
|
|
467
|
+
itemHeight = convert(itemHeight).from(itemHeightUnit).to('cm');
|
|
468
|
+
itemLines.forEach(line => {
|
|
469
|
+
line.push({ altitude: itemAltitude, height: itemHeight });
|
|
470
|
+
});
|
|
471
|
+
MGlinesOtherSnapped = [...MGlinesOtherSnapped, ...itemLines];
|
|
472
|
+
return true;
|
|
473
|
+
} else return false;
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
// get all lines of moldingGroup items
|
|
477
|
+
items.forEach(item => {
|
|
478
|
+
let itemAltitude = item.properties.get('altitude').get('_length');
|
|
479
|
+
let itemAltitudeUnit = item.properties.get('altitude').get('_unit');
|
|
480
|
+
itemAltitude = convert(itemAltitude).from(itemAltitudeUnit).to('cm');
|
|
481
|
+
let itemHeight = item.properties.get('height').get('_length');
|
|
482
|
+
let itemHeightUnit = item.properties.get('height').get('_unit');
|
|
483
|
+
itemHeight = convert(itemHeight).from(itemHeightUnit).to('cm');
|
|
484
|
+
|
|
485
|
+
let itemLines = getLinesOfItem(item, allLineRects, catalog);
|
|
486
|
+
|
|
487
|
+
// remove the edge that overlapped with other snapped items
|
|
488
|
+
itemLines = itemLines.filter(itLine => {
|
|
489
|
+
let ret = true;
|
|
490
|
+
const srcLine = {
|
|
491
|
+
x1: itLine[0].x,
|
|
492
|
+
y1: itLine[0].y,
|
|
493
|
+
x2: itLine[1].x,
|
|
494
|
+
y2: itLine[1].y
|
|
495
|
+
};
|
|
496
|
+
for (let j = 0; j < MGlinesOtherSnapped.length; j++) {
|
|
497
|
+
let bCheck = false;
|
|
498
|
+
switch (moldingGroup.location_type) {
|
|
499
|
+
case TOP_MOLDING_LOCATION:
|
|
500
|
+
bCheck =
|
|
501
|
+
MGlinesOtherSnapped[j][3].altitude +
|
|
502
|
+
MGlinesOtherSnapped[j][3].height >
|
|
503
|
+
itemAltitude + itemHeight;
|
|
504
|
+
break;
|
|
505
|
+
case MIDDLE_MOLDING_LOCATION:
|
|
506
|
+
bCheck = true;
|
|
507
|
+
break;
|
|
508
|
+
case BOTTOM_MOLDING_LOCATION:
|
|
509
|
+
bCheck = MGlinesOtherSnapped[j][3].altitude < itemAltitude;
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
if (
|
|
513
|
+
item.category !== 'cabinet' ||
|
|
514
|
+
![
|
|
515
|
+
BASE_CABINET_LAYOUTPOS,
|
|
516
|
+
WALL_CABINET_LAYOUTPOS,
|
|
517
|
+
TALL_CABINET_LAYOUTPOS
|
|
518
|
+
].includes(item.layoutpos)
|
|
519
|
+
)
|
|
520
|
+
bCheck = true;
|
|
521
|
+
if (bCheck) {
|
|
522
|
+
const destLine = {
|
|
523
|
+
x1: MGlinesOtherSnapped[j][0].x,
|
|
524
|
+
y1: MGlinesOtherSnapped[j][0].y,
|
|
525
|
+
x2: MGlinesOtherSnapped[j][1].x,
|
|
526
|
+
y2: MGlinesOtherSnapped[j][1].y
|
|
527
|
+
};
|
|
528
|
+
const rst = GeometryUtils.relationshipOfTwoOverlappedLines(
|
|
529
|
+
srcLine,
|
|
530
|
+
destLine
|
|
531
|
+
);
|
|
532
|
+
if (rst.result === OVERLAP_SAME || rst.result === OVERLAP_INCLUDED) {
|
|
533
|
+
ret = false;
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return ret;
|
|
539
|
+
});
|
|
540
|
+
MGlines = [...MGlines, ...itemLines];
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
// Filtering overlapped edges and get contour edges
|
|
544
|
+
let removeLineIds = []; // remove the edge that fully overlapped to other edge
|
|
545
|
+
let newLines = []; // new countour edge segment that except the overlapped part
|
|
546
|
+
for (let i = 0; i < MGlines.length; i++) {
|
|
547
|
+
const srcLine = {
|
|
548
|
+
x1: MGlines[i][0].x,
|
|
549
|
+
y1: MGlines[i][0].y,
|
|
550
|
+
x2: MGlines[i][1].x,
|
|
551
|
+
y2: MGlines[i][1].y
|
|
552
|
+
};
|
|
553
|
+
for (let j = 0; j < MGlines.length; j++) {
|
|
554
|
+
if (i === j) continue;
|
|
555
|
+
const destLine = {
|
|
556
|
+
x1: MGlines[j][0].x,
|
|
557
|
+
y1: MGlines[j][0].y,
|
|
558
|
+
x2: MGlines[j][1].x,
|
|
559
|
+
y2: MGlines[j][1].y
|
|
560
|
+
};
|
|
561
|
+
const rst = GeometryUtils.relationshipOfTwoOverlappedLines(
|
|
562
|
+
srcLine,
|
|
563
|
+
destLine
|
|
564
|
+
);
|
|
565
|
+
if (rst.result === OVERLAP_SAME || rst.result === OVERLAP_INCLUDED) {
|
|
566
|
+
removeLineIds.push(i);
|
|
567
|
+
break;
|
|
568
|
+
} else if (rst.result === OVERLAP_SOME) {
|
|
569
|
+
removeLineIds.push(i);
|
|
570
|
+
const lineSegs = getTrimmedContourLineSegs(
|
|
571
|
+
rst.trimmedSegs,
|
|
572
|
+
MGlines.filter((v, idx) => idx !== i && idx !== j),
|
|
573
|
+
0
|
|
574
|
+
);
|
|
575
|
+
if (lineSegs.length > 0) newLines = [...newLines, ...lineSegs];
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
MGlines = MGlines.filter(
|
|
582
|
+
(line, idx) => !removeLineIds.some(id => idx === id)
|
|
583
|
+
);
|
|
584
|
+
if (newLines.length > 0) MGlines = [...MGlines, ...newLines];
|
|
585
|
+
|
|
586
|
+
// merge the collinear linked lines to one line
|
|
587
|
+
let newMGlines = [];
|
|
588
|
+
let filteredMGlines = MGlines;
|
|
589
|
+
for (let i = 0; i < MGlines.length; i++) {
|
|
590
|
+
if (filteredMGlines.length < 1) break;
|
|
591
|
+
if (!filteredMGlines.some(v => v[2] === MGlines[i][2])) continue;
|
|
592
|
+
let mergedResult = getMergedLine(MGlines[i], filteredMGlines);
|
|
593
|
+
newMGlines.push(mergedResult.mergedLine);
|
|
594
|
+
filteredMGlines = mergedResult.filteredMGlines;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
return newMGlines;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Get the line that colinear linked with [line], and merge them to a new line
|
|
602
|
+
* @param {*} line
|
|
603
|
+
* @param {*} MGlines
|
|
604
|
+
* @returns
|
|
605
|
+
* - returns merged new line
|
|
606
|
+
* - returns filtered new line group (remove linked line from [MGlines])
|
|
607
|
+
*/
|
|
608
|
+
function getMergedLine(line, MGlines) {
|
|
609
|
+
let newMGlines = MGlines.filter(v => line[2] !== v[2]);
|
|
610
|
+
let mergeResult = {
|
|
611
|
+
mergedLine: line,
|
|
612
|
+
filteredMGlines: newMGlines
|
|
613
|
+
};
|
|
614
|
+
const srcLine = {
|
|
615
|
+
x1: line[0].x,
|
|
616
|
+
y1: line[0].y,
|
|
617
|
+
x2: line[1].x,
|
|
618
|
+
y2: line[1].y
|
|
619
|
+
};
|
|
620
|
+
for (let i = 0; i < newMGlines.length; i++) {
|
|
621
|
+
const destLine = {
|
|
622
|
+
x1: newMGlines[i][0].x,
|
|
623
|
+
y1: newMGlines[i][0].y,
|
|
624
|
+
x2: newMGlines[i][1].x,
|
|
625
|
+
y2: newMGlines[i][1].y
|
|
626
|
+
};
|
|
627
|
+
const rst = GeometryUtils.relationshipOfTwoOverlappedLines(
|
|
628
|
+
srcLine,
|
|
629
|
+
destLine
|
|
630
|
+
);
|
|
631
|
+
if (rst.result === OVERLAP_LINK) {
|
|
632
|
+
let mergedLine = [
|
|
633
|
+
{ x: rst.linkedLine.x1, y: rst.linkedLine.y1 },
|
|
634
|
+
{ x: rst.linkedLine.x2, y: rst.linkedLine.y2 },
|
|
635
|
+
IDBroker.acquireID()
|
|
636
|
+
];
|
|
637
|
+
mergeResult = getMergedLine(
|
|
638
|
+
mergedLine,
|
|
639
|
+
newMGlines.filter((v, idx) => idx !== i)
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
return mergeResult;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Get the contour line segments from [lineSegs]
|
|
648
|
+
* @param {*} lineSegs
|
|
649
|
+
* @param {*} otherLines
|
|
650
|
+
* @returns
|
|
651
|
+
*/
|
|
652
|
+
function getTrimmedContourLineSegs(lineSegs, otherLines, cnt) {
|
|
653
|
+
try {
|
|
654
|
+
cnt++;
|
|
655
|
+
if (cnt > 5000) return [];
|
|
656
|
+
let returnSegs = [];
|
|
657
|
+
for (let i = 0; i < lineSegs.length; i++) {
|
|
658
|
+
const srcLine = {
|
|
659
|
+
x1: lineSegs[i].x1,
|
|
660
|
+
y1: lineSegs[i].y1,
|
|
661
|
+
x2: lineSegs[i].x2,
|
|
662
|
+
y2: lineSegs[i].y2
|
|
663
|
+
};
|
|
664
|
+
let bContourSeg = true;
|
|
665
|
+
for (let j = 0; j < otherLines.length; j++) {
|
|
666
|
+
const destLine = {
|
|
667
|
+
x1: otherLines[j][0].x,
|
|
668
|
+
y1: otherLines[j][0].y,
|
|
669
|
+
x2: otherLines[j][1].x,
|
|
670
|
+
y2: otherLines[j][1].y
|
|
671
|
+
};
|
|
672
|
+
const rst = GeometryUtils.relationshipOfTwoOverlappedLines(
|
|
673
|
+
srcLine,
|
|
674
|
+
destLine
|
|
675
|
+
);
|
|
676
|
+
if (rst.result == OVERLAP_SAME || rst.result == OVERLAP_INCLUDED) {
|
|
677
|
+
bContourSeg = false;
|
|
678
|
+
break;
|
|
679
|
+
} else if (rst.result == OVERLAP_SOME) {
|
|
680
|
+
const tLineSegs = getTrimmedContourLineSegs(
|
|
681
|
+
rst.trimmedSegs,
|
|
682
|
+
otherLines.filter((v, idx) => idx !== j),
|
|
683
|
+
cnt
|
|
684
|
+
);
|
|
685
|
+
if (tLineSegs.length > 0) returnSegs = [...returnSegs, ...tLineSegs];
|
|
686
|
+
bContourSeg = false;
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
if (bContourSeg)
|
|
691
|
+
returnSegs.push([
|
|
692
|
+
{ x: lineSegs[i].x1, y: lineSegs[i].y1 },
|
|
693
|
+
{ x: lineSegs[i].x2, y: lineSegs[i].y2 },
|
|
694
|
+
IDBroker.acquireID()
|
|
695
|
+
]);
|
|
696
|
+
}
|
|
697
|
+
return returnSegs;
|
|
698
|
+
} catch (e) {
|
|
699
|
+
console.log('molding catched :', e);
|
|
700
|
+
return [];
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
export function getLinesFromItems(moldingGroup, layer, catalog) {
|
|
705
|
+
let allLineRects = GeometryUtils.buildRectFromLines(
|
|
706
|
+
layer,
|
|
707
|
+
GeometryUtils.getAllLines(layer)
|
|
708
|
+
);
|
|
709
|
+
let items = [...moldingGroup.items];
|
|
710
|
+
let MGlines = getLinesOfItem(items[0], allLineRects, catalog);
|
|
711
|
+
items = sortItemsByDistance(items, items[0]);
|
|
712
|
+
for (let i = 1; i < items.length; i++) {
|
|
713
|
+
let itemLines = getLinesOfItem(items[i], allLineRects, catalog);
|
|
714
|
+
let temp_MGLines = [];
|
|
715
|
+
MGlines.forEach(line => {
|
|
716
|
+
let idx = itemLines.findIndex(itemLine =>
|
|
717
|
+
isLinesOverlapped(line, itemLine)
|
|
718
|
+
);
|
|
719
|
+
const curItemLine = itemLines[idx];
|
|
720
|
+
if (idx > -1) {
|
|
721
|
+
if (
|
|
722
|
+
!(
|
|
723
|
+
(GeometryUtils.samePoints(line[0], curItemLine[0]) &&
|
|
724
|
+
GeometryUtils.samePoints(line[1], curItemLine[1])) ||
|
|
725
|
+
(GeometryUtils.samePoints(line[0], curItemLine[1]) &&
|
|
726
|
+
GeometryUtils.samePoints(line[1], curItemLine[0]))
|
|
727
|
+
)
|
|
728
|
+
) {
|
|
729
|
+
let MGLine = mergeOverlappedLines(line, curItemLine);
|
|
730
|
+
temp_MGLines.push(MGLine);
|
|
731
|
+
}
|
|
732
|
+
itemLines.splice(idx, 1);
|
|
733
|
+
} else {
|
|
734
|
+
temp_MGLines.push(line);
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
itemLines.forEach(itemLine => temp_MGLines.push(itemLine));
|
|
738
|
+
MGlines = [...temp_MGLines];
|
|
739
|
+
}
|
|
740
|
+
// return MGlines;
|
|
741
|
+
let snapped_other_items = layer.items.toArray().filter(item => {
|
|
742
|
+
if (items.some(it => item.id === it.id)) return false;
|
|
743
|
+
return isItemSnappedGroup(item, items);
|
|
744
|
+
});
|
|
745
|
+
snapped_other_items.forEach(item => {
|
|
746
|
+
let itemAltitude = item.properties.get('altitude').get('_length');
|
|
747
|
+
let itemAltitudeUnit = item.properties.get('altitude').get('_unit');
|
|
748
|
+
itemAltitude = convert(itemAltitude).from(itemAltitudeUnit).to('cm');
|
|
749
|
+
let itemHeight = item.properties.get('height').get('_length');
|
|
750
|
+
let itemHeightUnit = item.properties.get('height').get('_unit');
|
|
751
|
+
itemHeight = convert(itemHeight).from(itemHeightUnit).to('cm');
|
|
752
|
+
let mgroupAltitude = items[0].properties.get('altitude').get('_length');
|
|
753
|
+
let mgroupAltitudeUnit = items[0].properties.get('altitude').get('_unit');
|
|
754
|
+
mgroupAltitude = convert(mgroupAltitude).from(mgroupAltitudeUnit).to('cm');
|
|
755
|
+
let mgroupHeight = items[0].properties.get('height').get('_length');
|
|
756
|
+
let mgroupHeightUnit = items[0].properties.get('height').get('_unit');
|
|
757
|
+
mgroupHeight = convert(mgroupHeight).from(mgroupHeightUnit).to('cm');
|
|
758
|
+
let flag = false;
|
|
759
|
+
switch (moldingGroup.location_type) {
|
|
760
|
+
case TOP_MOLDING_LOCATION:
|
|
761
|
+
flag = itemAltitude + itemHeight > mgroupAltitude + mgroupHeight;
|
|
762
|
+
break;
|
|
763
|
+
case MIDDLE_MOLDING_LOCATION:
|
|
764
|
+
flag = true;
|
|
765
|
+
break;
|
|
766
|
+
case BOTTOM_MOLDING_LOCATION:
|
|
767
|
+
flag = itemAltitude < mgroupAltitude;
|
|
768
|
+
break;
|
|
769
|
+
}
|
|
770
|
+
if (
|
|
771
|
+
item.category !== 'cabinet' ||
|
|
772
|
+
![
|
|
773
|
+
BASE_CABINET_LAYOUTPOS,
|
|
774
|
+
WALL_CABINET_LAYOUTPOS,
|
|
775
|
+
TALL_CABINET_LAYOUTPOS
|
|
776
|
+
].includes(item.layoutpos)
|
|
777
|
+
)
|
|
778
|
+
flag = true;
|
|
779
|
+
if (flag) {
|
|
780
|
+
let itemLines = getLinesOfItem(item, allLineRects, catalog);
|
|
781
|
+
let temp_MGLines = [];
|
|
782
|
+
MGlines.forEach(mgl => {
|
|
783
|
+
let idx = itemLines.findIndex(itl => isLinesOverlapped(mgl, itl));
|
|
784
|
+
const curITL = itemLines[idx];
|
|
785
|
+
if (idx > -1) {
|
|
786
|
+
if (
|
|
787
|
+
getDelta(mgl[0], mgl[1], curITL[1], curITL[0]) < EPSILON ||
|
|
788
|
+
getDelta(mgl[0], mgl[1], curITL[0], curITL[1]) < EPSILON
|
|
789
|
+
) {
|
|
790
|
+
if (
|
|
791
|
+
GeometryUtils.verticesDistance(mgl[0], mgl[1]) >
|
|
792
|
+
GeometryUtils.verticesDistance(curITL[0], curITL[1])
|
|
793
|
+
) {
|
|
794
|
+
let MGLine = mergeOverlappedLines(mgl, curITL);
|
|
795
|
+
temp_MGLines.push(MGLine);
|
|
796
|
+
}
|
|
797
|
+
itemLines.splice(idx, 1);
|
|
798
|
+
} else {
|
|
799
|
+
temp_MGLines.push(mgl);
|
|
800
|
+
}
|
|
801
|
+
} else {
|
|
802
|
+
temp_MGLines.push(mgl);
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
MGlines = [...temp_MGLines];
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
return MGlines;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
function getMDPoints(newMD) {
|
|
812
|
+
if (newMD.lines.length < 1)
|
|
813
|
+
return {
|
|
814
|
+
...newMD,
|
|
815
|
+
pointGroups: []
|
|
816
|
+
};
|
|
817
|
+
// let maxX = newMD.lines[0][0].x,
|
|
818
|
+
let maxX = newMD.lines[0][0].x,
|
|
819
|
+
minX = newMD.lines[0][0].x;
|
|
820
|
+
let maxY = newMD.lines[0][0].y,
|
|
821
|
+
minY = newMD.lines[0][0].y;
|
|
822
|
+
|
|
823
|
+
newMD.lines.forEach(line => {
|
|
824
|
+
if (line[0].x > maxX) {
|
|
825
|
+
maxX = line[0].x;
|
|
826
|
+
}
|
|
827
|
+
if (line[0].x < minX) {
|
|
828
|
+
minX = line[0].x;
|
|
829
|
+
}
|
|
830
|
+
if (line[1].x > maxX) {
|
|
831
|
+
maxX = line[1].x;
|
|
832
|
+
}
|
|
833
|
+
if (line[1].x < minX) {
|
|
834
|
+
minX = line[1].x;
|
|
835
|
+
}
|
|
836
|
+
if (line[0].y > maxY) {
|
|
837
|
+
maxY = line[0].y;
|
|
838
|
+
}
|
|
839
|
+
if (line[0].y < minY) {
|
|
840
|
+
minY = line[0].y;
|
|
841
|
+
}
|
|
842
|
+
if (line[1].y > maxY) {
|
|
843
|
+
maxY = line[1].y;
|
|
844
|
+
}
|
|
845
|
+
if (line[1].y < minY) {
|
|
846
|
+
minY = line[1].y;
|
|
847
|
+
}
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
let cPos = {
|
|
851
|
+
x: (maxX + minX) / 2,
|
|
852
|
+
y: (maxY + minY) / 2
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
let newSize = { ...newMD.size, width: maxX - minX, depth: maxY - minY };
|
|
856
|
+
|
|
857
|
+
// get vertex points
|
|
858
|
+
let MDlines = [...newMD.lines];
|
|
859
|
+
let pointGroups = [[]];
|
|
860
|
+
let flag = 1;
|
|
861
|
+
let i = 0;
|
|
862
|
+
while (MDlines.length !== 0) {
|
|
863
|
+
if (pointGroups[i].length === 0) {
|
|
864
|
+
pointGroups[i].push(
|
|
865
|
+
new Three.Vector2(MDlines[0][0].x - cPos.x, MDlines[0][0].y - cPos.y),
|
|
866
|
+
new Three.Vector2(MDlines[0][1].x - cPos.x, MDlines[0][1].y - cPos.y)
|
|
867
|
+
);
|
|
868
|
+
MDlines.splice(0, 1);
|
|
869
|
+
} else {
|
|
870
|
+
if (flag) {
|
|
871
|
+
let lastPoint = pointGroups[i][pointGroups[i].length - 1];
|
|
872
|
+
let res = MDlines.findIndex(
|
|
873
|
+
a =>
|
|
874
|
+
GeometryUtils.samePoints(
|
|
875
|
+
{ x: a[0].x - cPos.x, y: a[0].y - cPos.y },
|
|
876
|
+
lastPoint
|
|
877
|
+
) ||
|
|
878
|
+
GeometryUtils.samePoints(
|
|
879
|
+
{ x: a[1].x - cPos.x, y: a[1].y - cPos.y },
|
|
880
|
+
lastPoint
|
|
881
|
+
)
|
|
882
|
+
);
|
|
883
|
+
if (res > -1) {
|
|
884
|
+
let newPos = {
|
|
885
|
+
x: MDlines[res][0].x - cPos.x,
|
|
886
|
+
y: MDlines[res][0].y - cPos.y
|
|
887
|
+
};
|
|
888
|
+
if (GeometryUtils.samePoints(newPos, lastPoint)) {
|
|
889
|
+
newPos = {
|
|
890
|
+
x: MDlines[res][1].x - cPos.x,
|
|
891
|
+
y: MDlines[res][1].y - cPos.y
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
pointGroups[i].push(new Three.Vector2(newPos.x, newPos.y));
|
|
895
|
+
MDlines.splice(res, 1);
|
|
896
|
+
} else {
|
|
897
|
+
flag = 0;
|
|
898
|
+
}
|
|
899
|
+
} else {
|
|
900
|
+
let firstPoint = pointGroups[i][0];
|
|
901
|
+
let res = MDlines.findIndex(
|
|
902
|
+
a =>
|
|
903
|
+
GeometryUtils.samePoints(
|
|
904
|
+
{ x: a[0].x - cPos.x, y: a[0].y - cPos.y },
|
|
905
|
+
firstPoint
|
|
906
|
+
) ||
|
|
907
|
+
GeometryUtils.samePoints(
|
|
908
|
+
{ x: a[1].x - cPos.x, y: a[1].y - cPos.y },
|
|
909
|
+
firstPoint
|
|
910
|
+
)
|
|
911
|
+
);
|
|
912
|
+
if (res > -1) {
|
|
913
|
+
let newPos = {
|
|
914
|
+
x: MDlines[res][0].x - cPos.x,
|
|
915
|
+
y: MDlines[res][0].y - cPos.y
|
|
916
|
+
};
|
|
917
|
+
if (GeometryUtils.samePoints(newPos, firstPoint)) {
|
|
918
|
+
newPos = {
|
|
919
|
+
x: MDlines[res][1].x - cPos.x,
|
|
920
|
+
y: MDlines[res][1].y - cPos.y
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
pointGroups[i] = [
|
|
924
|
+
new Three.Vector2(newPos.x, newPos.y),
|
|
925
|
+
...pointGroups[i]
|
|
926
|
+
];
|
|
927
|
+
MDlines.splice(res, 1);
|
|
928
|
+
} else {
|
|
929
|
+
flag = 1;
|
|
930
|
+
i++;
|
|
931
|
+
if (MDlines.length !== 0) pointGroups.push([]);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
let z = newMD.items[0].properties.get('altitude').get('_length');
|
|
938
|
+
let zUnit = newMD.items[0].properties.get('altitude').get('_unit') || 'cm';
|
|
939
|
+
z = convert(z).from(zUnit).to('cm');
|
|
940
|
+
let height = newMD.items[0].properties.get('height').get('_length');
|
|
941
|
+
let heightUnit = newMD.items[0].properties.get('height').get('_unit') || 'cm';
|
|
942
|
+
height = convert(height).from(heightUnit).to('cm');
|
|
943
|
+
|
|
944
|
+
switch (newMD.location_type) {
|
|
945
|
+
case TOP_MOLDING_LOCATION:
|
|
946
|
+
z += height;
|
|
947
|
+
break;
|
|
948
|
+
case MIDDLE_MOLDING_LOCATION:
|
|
949
|
+
z += height / 2;
|
|
950
|
+
break;
|
|
951
|
+
case BOTTOM_MOLDING_LOCATION:
|
|
952
|
+
z += 0;
|
|
953
|
+
break;
|
|
954
|
+
default:
|
|
955
|
+
break;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
return {
|
|
959
|
+
...newMD,
|
|
960
|
+
pointGroups,
|
|
961
|
+
pos: { ...cPos, z: z },
|
|
962
|
+
size: newSize
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
export function createMonldingGroup(oldMG, layer, molding, catalog) {
|
|
967
|
+
let newMG = { ...oldMG };
|
|
968
|
+
newMG.molding = molding;
|
|
969
|
+
newMG.lines = getLinesFromItems2(oldMG, layer, catalog);
|
|
970
|
+
newMG.lines.reverse();
|
|
971
|
+
newMG = getMDPoints(newMG);
|
|
972
|
+
return newMG;
|
|
973
|
+
}
|