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.
@@ -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
+ }