@eturnity/eturnity_maths 7.51.2 → 8.4.1
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/geometry.js +2 -2
- package/src/intersectionPolygon.js +57 -36
- package/src/matrix.js +37 -10
- package/src/splitMergePolygons.js +53 -41
- package/src/tests/intersectionPolygon/{logicOperationOnPolygons.spec.waitingList.js → logicOperationOnPolygons.spec.js} +101 -0
- package/src/tests/matrix/inverse2x2Matrix.spec.js +17 -0
- package/src/tests/matrix/inverse3x3Matrix.spec.js +18 -0
package/package.json
CHANGED
package/src/geometry.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
vectorLength,
|
|
10
10
|
normalizeVector,
|
|
11
11
|
} from './vector'
|
|
12
|
-
import {
|
|
12
|
+
import { inverse3x3Matrix, multiplyMatrices } from './matrix'
|
|
13
13
|
import { Point } from './objects/Point'
|
|
14
14
|
import { Line } from './objects/Line'
|
|
15
15
|
import concaveman from './lib/concaveman'
|
|
@@ -132,7 +132,7 @@ export function getDataAboutTwo3DLines(A, u, B, v) {
|
|
|
132
132
|
[u.y, v.y, w.y],
|
|
133
133
|
[u.z, v.z, w.z],
|
|
134
134
|
]
|
|
135
|
-
let mInv =
|
|
135
|
+
let mInv = inverse3x3Matrix(m)
|
|
136
136
|
if (!mInv) {
|
|
137
137
|
return null
|
|
138
138
|
}
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
getPointInsideOutline,
|
|
3
3
|
isInsidePolygon,
|
|
4
4
|
isSamePoint2D,
|
|
5
|
+
calcPolygonArea,
|
|
5
6
|
isInsideEdge2D,
|
|
6
7
|
getDegree,
|
|
7
8
|
} from './geometry'
|
|
@@ -10,8 +11,37 @@ import {
|
|
|
10
11
|
getNodeList,
|
|
11
12
|
getEdgeList,
|
|
12
13
|
getOutlineList,
|
|
14
|
+
getEdgeIntersections,
|
|
15
|
+
getEdgeListV2,
|
|
13
16
|
} from './splitMergePolygons'
|
|
14
17
|
|
|
18
|
+
export function isOutlineTouchingOutline(outline, outlineSelection) {
|
|
19
|
+
const isOutlinePointWithinSelection = outline.some((p) =>
|
|
20
|
+
isInsidePolygon(p, outlineSelection)
|
|
21
|
+
)
|
|
22
|
+
if (isOutlinePointWithinSelection) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const isEdgeInSelection = outline.some((p, index) => {
|
|
27
|
+
const nextIndex = (index + 1) % outline.length
|
|
28
|
+
const nextP = outline[nextIndex]
|
|
29
|
+
return outlineSelection.some((selectionPoint, selectionIndex) => {
|
|
30
|
+
const nextSelectionIndex = (selectionIndex + 1) % outlineSelection.length
|
|
31
|
+
const nextSelectionPoint = outlineSelection[nextSelectionIndex]
|
|
32
|
+
return doLineSegmentsIntersect(
|
|
33
|
+
p,
|
|
34
|
+
nextP,
|
|
35
|
+
selectionPoint,
|
|
36
|
+
nextSelectionPoint
|
|
37
|
+
)
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
if (isEdgeInSelection) {
|
|
41
|
+
return true
|
|
42
|
+
}
|
|
43
|
+
return false
|
|
44
|
+
}
|
|
15
45
|
export function isOutlineTouchingBoundingBox(outline, bbox) {
|
|
16
46
|
const isOutlinePointWithinBbox = outline.some(
|
|
17
47
|
(p) =>
|
|
@@ -87,6 +117,20 @@ export function isSelfIntersecting(outline, isClosePolygon = true) {
|
|
|
87
117
|
}
|
|
88
118
|
return isSelfIntersecting
|
|
89
119
|
}
|
|
120
|
+
function generateEdges2DFromOutlines(outlines) {
|
|
121
|
+
return outlines
|
|
122
|
+
.map((outline, outlineIndex) =>
|
|
123
|
+
outline.map((currentPoint, index) => {
|
|
124
|
+
const nextIndex = (index + 1) % outline.length
|
|
125
|
+
const nextPoint = outline[nextIndex]
|
|
126
|
+
return {
|
|
127
|
+
belongsTo: [{ polygonId: outlineIndex }],
|
|
128
|
+
outline: [currentPoint, nextPoint],
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
)
|
|
132
|
+
.flat()
|
|
133
|
+
}
|
|
90
134
|
export function isLastPointsInOutlineAtCloseAngle(outline) {
|
|
91
135
|
const length = outline.length
|
|
92
136
|
const previousIndex = (length - 1) % length
|
|
@@ -102,42 +146,13 @@ export function logicOperationOnPolygons(
|
|
|
102
146
|
outline2,
|
|
103
147
|
mode = 'intersect'
|
|
104
148
|
) {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const fig2 = outline2.map((p) => {
|
|
110
|
-
return { x: p.x, y: p.y, z: p.z }
|
|
111
|
-
})
|
|
112
|
-
//nodeList:
|
|
113
|
-
let dirtyNodeList = []
|
|
114
|
-
fig1.forEach((p) => {
|
|
115
|
-
dirtyNodeList.push(p)
|
|
116
|
-
})
|
|
117
|
-
fig2.forEach((p) => {
|
|
118
|
-
dirtyNodeList.push(p)
|
|
119
|
-
})
|
|
120
|
-
//edgeList (just in term of indexes)
|
|
121
|
-
const edges = fig2.map((p, index) => {
|
|
122
|
-
return { outline: [p, fig2[(index + 1) % fig2.length]] }
|
|
123
|
-
})
|
|
124
|
-
let intersections = getIntersections({ outline: fig1 }, edges)
|
|
125
|
-
|
|
126
|
-
//2. gather all nodes+intersection in a list[[x,y],[x,y]]
|
|
127
|
-
const nodeList = getNodeList(intersections, edges, { outline: fig1 })
|
|
128
|
-
//3. generate all edges not cut, those cut and those from construction polyline
|
|
129
|
-
|
|
130
|
-
const edgeList = getEdgeList(
|
|
131
|
-
nodeList,
|
|
132
|
-
intersections,
|
|
133
|
-
edges,
|
|
134
|
-
{ outline: fig1 },
|
|
135
|
-
1
|
|
136
|
-
)
|
|
137
|
-
//4. run planar-face-discovery to get all cycles and rebuild our polygons
|
|
149
|
+
const edges = generateEdges2DFromOutlines([outline1, outline2])
|
|
150
|
+
const intersections = getEdgeIntersections(edges)
|
|
151
|
+
const nodeList = getNodeList(intersections, edges)
|
|
152
|
+
const edgeList = getEdgeListV2(nodeList, intersections, edges)
|
|
138
153
|
try {
|
|
139
154
|
const outlineList = getOutlineList(nodeList, edgeList)
|
|
140
|
-
return filterPolygons(outlineList,
|
|
155
|
+
return filterPolygons(outlineList, outline1, outline2, mode)
|
|
141
156
|
} catch (err) {
|
|
142
157
|
console.error('error with getOutlineList', nodeList, edgeList, err)
|
|
143
158
|
return []
|
|
@@ -149,7 +164,7 @@ function filterPolygons(outlineList, fig1, fig2, mode) {
|
|
|
149
164
|
const filtered = []
|
|
150
165
|
let c1, c2
|
|
151
166
|
let point
|
|
152
|
-
const bigPolygons = removeSmallPolygons(polygons, 0.
|
|
167
|
+
const bigPolygons = removeSmallPolygons(polygons, 0.001)
|
|
153
168
|
for (var i = 0; i < bigPolygons.length; i++) {
|
|
154
169
|
point = getPointInsideOutline(
|
|
155
170
|
bigPolygons[i],
|
|
@@ -570,7 +585,13 @@ function filterPolygonsOld(polygons, fig1, fig2, mode) {
|
|
|
570
585
|
function removeSmallPolygons(polygons, minSize) {
|
|
571
586
|
var big = []
|
|
572
587
|
for (var i = 0; i < polygons.length; i++) {
|
|
573
|
-
if (
|
|
588
|
+
if (
|
|
589
|
+
calcPolygonArea(
|
|
590
|
+
polygons[i].map((p) => {
|
|
591
|
+
return { ...p, z: 0 }
|
|
592
|
+
})
|
|
593
|
+
) >= minSize
|
|
594
|
+
) {
|
|
574
595
|
big.push(polygons[i])
|
|
575
596
|
}
|
|
576
597
|
}
|
package/src/matrix.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
import { substractVector } from './vector'
|
|
2
|
-
export function inverse2x2Matrix([a, b, c, d]) {
|
|
3
|
-
//inverse matrix |a,
|
|
4
|
-
// |
|
|
5
|
-
const det = a *
|
|
1
|
+
import { substractVector, addVector, multiplyVector } from './vector'
|
|
2
|
+
export function inverse2x2Matrix([[a, b], [c, d]]) {
|
|
3
|
+
//inverse matrix |a,b|
|
|
4
|
+
// |c,d|
|
|
5
|
+
const det = a * d - c * b
|
|
6
6
|
if (det == 0) {
|
|
7
7
|
return null
|
|
8
8
|
}
|
|
9
|
-
return [
|
|
9
|
+
return [
|
|
10
|
+
[d / det, -b / det],
|
|
11
|
+
[-c / det, a / det],
|
|
12
|
+
]
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
export function
|
|
15
|
+
export function inverse3x3Matrix(m) {
|
|
16
|
+
//inverse matrix |a,b,c|
|
|
17
|
+
// |d,e,f|
|
|
18
|
+
// |g,h,i|
|
|
13
19
|
let [[a, b, c], [d, e, f], [g, h, i]] = m
|
|
14
20
|
let x = e * i - h * f
|
|
15
21
|
let y = f * g - d * i
|
|
@@ -19,7 +25,7 @@ export function inverse3x3matrix(m) {
|
|
|
19
25
|
? [
|
|
20
26
|
[x, c * h - b * i, b * f - c * e],
|
|
21
27
|
[y, a * i - c * g, d * c - a * f],
|
|
22
|
-
[z, g * b - a * h, a * e - d * b]
|
|
28
|
+
[z, g * b - a * h, a * e - d * b],
|
|
23
29
|
].map((r) => r.map((v) => (v /= det)))
|
|
24
30
|
: null
|
|
25
31
|
}
|
|
@@ -55,11 +61,32 @@ export function multiplyMatrices(a, b) {
|
|
|
55
61
|
export function rotateTransformation(point, angle, center = { x: 0, y: 0 }) {
|
|
56
62
|
let rotationMatrix = [
|
|
57
63
|
[Math.cos(angle), Math.sin(angle)],
|
|
58
|
-
[-Math.sin(angle), Math.cos(angle)]
|
|
64
|
+
[-Math.sin(angle), Math.cos(angle)],
|
|
59
65
|
]
|
|
60
66
|
let k = multiplyMatrices(rotationMatrix, [
|
|
61
67
|
[point.x - center.x],
|
|
62
|
-
[point.y - center.y]
|
|
68
|
+
[point.y - center.y],
|
|
63
69
|
])
|
|
64
70
|
return { x: k[0][0] + center.x, y: k[1][0] + center.y }
|
|
65
71
|
}
|
|
72
|
+
|
|
73
|
+
export function getOutlineFromCornerPointsAndDirections(
|
|
74
|
+
downPoint,
|
|
75
|
+
point,
|
|
76
|
+
directions
|
|
77
|
+
) {
|
|
78
|
+
let M = [
|
|
79
|
+
[directions[0].x, directions[1].x],
|
|
80
|
+
[directions[0].y, directions[1].y],
|
|
81
|
+
]
|
|
82
|
+
let invM = inverse2x2Matrix(M)
|
|
83
|
+
const v = substractVector(point, downPoint)
|
|
84
|
+
const coefs = multiplyMatrices(invM, [[v.x], [v.y]])
|
|
85
|
+
const coords = [
|
|
86
|
+
downPoint,
|
|
87
|
+
addVector(downPoint, multiplyVector(coefs[0], directions[0])),
|
|
88
|
+
point,
|
|
89
|
+
addVector(downPoint, multiplyVector(coefs[1], directions[1])),
|
|
90
|
+
]
|
|
91
|
+
return coords
|
|
92
|
+
}
|
|
@@ -17,13 +17,14 @@ import {
|
|
|
17
17
|
calculateArea,
|
|
18
18
|
getPointInsideOutline,
|
|
19
19
|
} from './geometry'
|
|
20
|
-
import { intersectOutlines } from './intersectionPolygon'
|
|
21
20
|
import { groupBy } from 'lodash'
|
|
22
21
|
import { Polygon } from './objects/Polygon'
|
|
23
|
-
import { defaultBaseHeight
|
|
22
|
+
import { defaultBaseHeight } from './config'
|
|
24
23
|
import { generateEdges2D } from './objects/derivedState/nodesEdgesCreation'
|
|
25
24
|
import { Point, updateComputedGeometryPolygon } from './objects'
|
|
26
25
|
|
|
26
|
+
const FLOAT_PRECISION = 1e-6
|
|
27
|
+
|
|
27
28
|
export function mergePolygons(polygonIdsToMerge, edges, layer, polygons) {
|
|
28
29
|
const outsideEdge = edges.filter((e) => e.belongsTo.length == 1)
|
|
29
30
|
const insideEdge = edges.filter((e) => e.belongsTo.length == 2)
|
|
@@ -43,7 +44,7 @@ export function mergePolygons(polygonIdsToMerge, edges, layer, polygons) {
|
|
|
43
44
|
const nodeList = []
|
|
44
45
|
for (let node of dirtyNodeList) {
|
|
45
46
|
const nodeFound = nodeList.find((n) => {
|
|
46
|
-
return n && isAlmostSamePoint2D(n, node,
|
|
47
|
+
return n && isAlmostSamePoint2D(n, node, FLOAT_PRECISION)
|
|
47
48
|
})
|
|
48
49
|
if (!nodeFound) {
|
|
49
50
|
nodeList.push(node)
|
|
@@ -117,7 +118,7 @@ export function splitPolygonsV2(polygons) {
|
|
|
117
118
|
let numberOfIntersectionPoints = 0
|
|
118
119
|
outline.forEach((point) => {
|
|
119
120
|
const result = intersections.filter((n) =>
|
|
120
|
-
isAlmostSamePoint2D(point, n.point,
|
|
121
|
+
isAlmostSamePoint2D(point, n.point, FLOAT_PRECISION)
|
|
121
122
|
)
|
|
122
123
|
if (result.length) {
|
|
123
124
|
numberOfIntersectionPoints++
|
|
@@ -190,7 +191,9 @@ export function splitPolygonsV2(polygons) {
|
|
|
190
191
|
parentPolygons.sort(
|
|
191
192
|
(a, b) => calculateArea(b.outline) - calculateArea(a.outline)
|
|
192
193
|
)
|
|
193
|
-
if (
|
|
194
|
+
if (
|
|
195
|
+
Math.abs(edge.outline[0].z - edge.outline[1].z) < FLOAT_PRECISION
|
|
196
|
+
) {
|
|
194
197
|
// edge is flat horizontally, create a flat polygon to project to
|
|
195
198
|
const flatOutline = parentPolygons[0].outline.map((point) => {
|
|
196
199
|
return {
|
|
@@ -434,7 +437,7 @@ export function getNodeList(intersections, edges, constructionPolyline) {
|
|
|
434
437
|
if (constructionPolyline) {
|
|
435
438
|
constructionPolyline.outline.forEach((p) => {
|
|
436
439
|
const node = nodeList.find((n) => {
|
|
437
|
-
return isAlmostSamePoint2D(p, n,
|
|
440
|
+
return isAlmostSamePoint2D(p, n, FLOAT_PRECISION)
|
|
438
441
|
})
|
|
439
442
|
if (!node) {
|
|
440
443
|
nodeList.push(p)
|
|
@@ -445,14 +448,14 @@ export function getNodeList(intersections, edges, constructionPolyline) {
|
|
|
445
448
|
return isAlmostSamePoint2D(
|
|
446
449
|
p,
|
|
447
450
|
constructionPolyline.outline[0],
|
|
448
|
-
|
|
451
|
+
FLOAT_PRECISION
|
|
449
452
|
)
|
|
450
453
|
})
|
|
451
454
|
const polylineEnd = nodeList.find((p) =>
|
|
452
455
|
isAlmostSamePoint2D(
|
|
453
456
|
p,
|
|
454
457
|
constructionPolyline.outline[polylineLength - 1],
|
|
455
|
-
|
|
458
|
+
FLOAT_PRECISION
|
|
456
459
|
)
|
|
457
460
|
)
|
|
458
461
|
constructionPolyline.outline.forEach((p, index) => {
|
|
@@ -466,11 +469,11 @@ export function getNodeList(intersections, edges, constructionPolyline) {
|
|
|
466
469
|
}
|
|
467
470
|
|
|
468
471
|
intersections.forEach((inter) => {
|
|
469
|
-
const edge = edges[inter.
|
|
472
|
+
const edge = edges[inter.edge_index_1]
|
|
470
473
|
if (edge) {
|
|
471
474
|
inter.point.z =
|
|
472
475
|
edge.outline[0].z +
|
|
473
|
-
inter.
|
|
476
|
+
inter.edge_param_1 * (edge.outline[1].z - edge.outline[0].z)
|
|
474
477
|
}
|
|
475
478
|
nodeList.push(inter.point)
|
|
476
479
|
})
|
|
@@ -479,7 +482,7 @@ export function getNodeList(intersections, edges, constructionPolyline) {
|
|
|
479
482
|
for (let k = 0; k < nodeList.length; k++) {
|
|
480
483
|
const node = nodeList[k]
|
|
481
484
|
const newNode = nodeListClean.find((n) => {
|
|
482
|
-
return n && isAlmostSamePoint2D(n, node,
|
|
485
|
+
return n && isAlmostSamePoint2D(n, node, FLOAT_PRECISION)
|
|
483
486
|
})
|
|
484
487
|
if (!newNode) {
|
|
485
488
|
nodeListClean.push(node)
|
|
@@ -493,10 +496,10 @@ function getEdgeListSimple(nodeList, edges) {
|
|
|
493
496
|
const edgeList = []
|
|
494
497
|
for (let index in edges) {
|
|
495
498
|
const node_0_index = nodeList.findIndex((n) =>
|
|
496
|
-
isAlmostSamePoint2D(edges[index].outline[0], n,
|
|
499
|
+
isAlmostSamePoint2D(edges[index].outline[0], n, FLOAT_PRECISION)
|
|
497
500
|
)
|
|
498
501
|
const node_1_index = nodeList.findIndex((n) =>
|
|
499
|
-
isAlmostSamePoint2D(edges[index].outline[1], n,
|
|
502
|
+
isAlmostSamePoint2D(edges[index].outline[1], n, FLOAT_PRECISION)
|
|
500
503
|
)
|
|
501
504
|
edgeList.push([node_0_index, node_1_index])
|
|
502
505
|
}
|
|
@@ -562,10 +565,10 @@ export function getEdgeList(
|
|
|
562
565
|
//get untouchEdge edge
|
|
563
566
|
untouchedEdgeIndexes.forEach((index) => {
|
|
564
567
|
const node_0_index = nodeList.findIndex((n) =>
|
|
565
|
-
isAlmostSamePoint2D(edges[index].outline[0], n,
|
|
568
|
+
isAlmostSamePoint2D(edges[index].outline[0], n, FLOAT_PRECISION)
|
|
566
569
|
)
|
|
567
570
|
const node_1_index = nodeList.findIndex((n) =>
|
|
568
|
-
isAlmostSamePoint2D(edges[index].outline[1], n,
|
|
571
|
+
isAlmostSamePoint2D(edges[index].outline[1], n, FLOAT_PRECISION)
|
|
569
572
|
)
|
|
570
573
|
edgeList.push([node_0_index, node_1_index])
|
|
571
574
|
})
|
|
@@ -573,13 +576,17 @@ export function getEdgeList(
|
|
|
573
576
|
untouchedPolylineIndexes.forEach((index) => {
|
|
574
577
|
const length = constructionPolyline.outline.length
|
|
575
578
|
const node_0_index = nodeList.findIndex((n) =>
|
|
576
|
-
isAlmostSamePoint2D(
|
|
579
|
+
isAlmostSamePoint2D(
|
|
580
|
+
constructionPolyline.outline[index],
|
|
581
|
+
n,
|
|
582
|
+
FLOAT_PRECISION
|
|
583
|
+
)
|
|
577
584
|
)
|
|
578
585
|
const node_1_index = nodeList.findIndex((n) =>
|
|
579
586
|
isAlmostSamePoint2D(
|
|
580
587
|
constructionPolyline.outline[(index + 1) % length],
|
|
581
588
|
n,
|
|
582
|
-
|
|
589
|
+
FLOAT_PRECISION
|
|
583
590
|
)
|
|
584
591
|
)
|
|
585
592
|
edgeList.push([node_0_index, node_1_index])
|
|
@@ -591,36 +598,40 @@ export function getEdgeList(
|
|
|
591
598
|
isAlmostSamePoint2D(
|
|
592
599
|
edges[intersectionOnEdge[0].edgeIndex].outline[0],
|
|
593
600
|
n,
|
|
594
|
-
|
|
601
|
+
FLOAT_PRECISION
|
|
595
602
|
)
|
|
596
603
|
)
|
|
597
604
|
const node_1_index_start = nodeList.findIndex((n) =>
|
|
598
|
-
isAlmostSamePoint2D(intersectionOnEdge[0].point, n,
|
|
605
|
+
isAlmostSamePoint2D(intersectionOnEdge[0].point, n, FLOAT_PRECISION)
|
|
599
606
|
)
|
|
600
607
|
edgeList.push([node_0_index_start, node_1_index_start])
|
|
601
608
|
|
|
602
609
|
for (let k = 0; k < length - 1; k++) {
|
|
603
610
|
const node_0_index = nodeList.findIndex((n) =>
|
|
604
|
-
isAlmostSamePoint2D(intersectionOnEdge[k].point, n,
|
|
611
|
+
isAlmostSamePoint2D(intersectionOnEdge[k].point, n, FLOAT_PRECISION)
|
|
605
612
|
)
|
|
606
613
|
const node_1_index = nodeList.findIndex((n) =>
|
|
607
614
|
isAlmostSamePoint2D(
|
|
608
615
|
intersectionOnEdge[(k + 1) % length].point,
|
|
609
616
|
n,
|
|
610
|
-
|
|
617
|
+
FLOAT_PRECISION
|
|
611
618
|
)
|
|
612
619
|
)
|
|
613
620
|
edgeList.push([node_0_index, node_1_index])
|
|
614
621
|
}
|
|
615
622
|
|
|
616
623
|
const node_0_index_end = nodeList.findIndex((n) =>
|
|
617
|
-
isAlmostSamePoint2D(
|
|
624
|
+
isAlmostSamePoint2D(
|
|
625
|
+
intersectionOnEdge[length - 1].point,
|
|
626
|
+
n,
|
|
627
|
+
FLOAT_PRECISION
|
|
628
|
+
)
|
|
618
629
|
)
|
|
619
630
|
const node_1_index_end = nodeList.findIndex((n) =>
|
|
620
631
|
isAlmostSamePoint2D(
|
|
621
632
|
edges[intersectionOnEdge[0].edgeIndex].outline[1],
|
|
622
633
|
n,
|
|
623
|
-
|
|
634
|
+
FLOAT_PRECISION
|
|
624
635
|
)
|
|
625
636
|
)
|
|
626
637
|
edgeList.push([node_0_index_end, node_1_index_end])
|
|
@@ -633,23 +644,23 @@ export function getEdgeList(
|
|
|
633
644
|
isAlmostSamePoint2D(
|
|
634
645
|
constructionPolyline.outline[intersectionOnPolyline[0].polylineIndex],
|
|
635
646
|
n,
|
|
636
|
-
|
|
647
|
+
FLOAT_PRECISION
|
|
637
648
|
)
|
|
638
649
|
)
|
|
639
650
|
const node_1_index_start = nodeList.findIndex((n) =>
|
|
640
|
-
isAlmostSamePoint2D(intersectionOnPolyline[0].point, n,
|
|
651
|
+
isAlmostSamePoint2D(intersectionOnPolyline[0].point, n, FLOAT_PRECISION)
|
|
641
652
|
)
|
|
642
653
|
edgeList.push([node_0_index_start, node_1_index_start])
|
|
643
654
|
|
|
644
655
|
for (let k = 0; k < length - 1; k++) {
|
|
645
656
|
const node_0_index = nodeList.findIndex((n) =>
|
|
646
|
-
isAlmostSamePoint2D(intersectionOnPolyline[k].point, n,
|
|
657
|
+
isAlmostSamePoint2D(intersectionOnPolyline[k].point, n, FLOAT_PRECISION)
|
|
647
658
|
)
|
|
648
659
|
const node_1_index = nodeList.findIndex((n) =>
|
|
649
660
|
isAlmostSamePoint2D(
|
|
650
661
|
intersectionOnPolyline[(k + 1) % length].point,
|
|
651
662
|
n,
|
|
652
|
-
|
|
663
|
+
FLOAT_PRECISION
|
|
653
664
|
)
|
|
654
665
|
)
|
|
655
666
|
edgeList.push([node_0_index, node_1_index])
|
|
@@ -659,7 +670,7 @@ export function getEdgeList(
|
|
|
659
670
|
isAlmostSamePoint2D(
|
|
660
671
|
intersectionOnPolyline[length - 1].point,
|
|
661
672
|
n,
|
|
662
|
-
|
|
673
|
+
FLOAT_PRECISION
|
|
663
674
|
)
|
|
664
675
|
)
|
|
665
676
|
const node_1_index_end = nodeList.findIndex((n) =>
|
|
@@ -668,7 +679,7 @@ export function getEdgeList(
|
|
|
668
679
|
(intersectionOnPolyline[0].polylineIndex + 1) % lengthPolyline
|
|
669
680
|
],
|
|
670
681
|
n,
|
|
671
|
-
|
|
682
|
+
FLOAT_PRECISION
|
|
672
683
|
)
|
|
673
684
|
)
|
|
674
685
|
edgeList.push([node_0_index_end, node_1_index_end])
|
|
@@ -694,7 +705,7 @@ export function getEdgeList(
|
|
|
694
705
|
* @param {Array<edge>} edges
|
|
695
706
|
* @returns {Array<[index1, index2]>} Array of indices indicating which nodes create an edge
|
|
696
707
|
*/
|
|
697
|
-
function getEdgeListV2(nodes, intersections, edges) {
|
|
708
|
+
export function getEdgeListV2(nodes, intersections, edges) {
|
|
698
709
|
const edgeList = []
|
|
699
710
|
const groupedIntersections = {}
|
|
700
711
|
intersections.forEach((intersection) => {
|
|
@@ -724,10 +735,10 @@ function getEdgeListV2(nodes, intersections, edges) {
|
|
|
724
735
|
// untouched edge
|
|
725
736
|
edgeList.push([
|
|
726
737
|
nodes.findIndex((n) =>
|
|
727
|
-
isAlmostSamePoint2D(edge.outline[0], n,
|
|
738
|
+
isAlmostSamePoint2D(edge.outline[0], n, FLOAT_PRECISION)
|
|
728
739
|
),
|
|
729
740
|
nodes.findIndex((n) =>
|
|
730
|
-
isAlmostSamePoint2D(edge.outline[1], n,
|
|
741
|
+
isAlmostSamePoint2D(edge.outline[1], n, FLOAT_PRECISION)
|
|
731
742
|
),
|
|
732
743
|
])
|
|
733
744
|
} else {
|
|
@@ -741,10 +752,10 @@ function getEdgeListV2(nodes, intersections, edges) {
|
|
|
741
752
|
for (let i = 0; i < tempNodes.length - 1; i++) {
|
|
742
753
|
edgeList.push([
|
|
743
754
|
nodes.findIndex((n) =>
|
|
744
|
-
isAlmostSamePoint2D(tempNodes[i], n,
|
|
755
|
+
isAlmostSamePoint2D(tempNodes[i], n, FLOAT_PRECISION)
|
|
745
756
|
),
|
|
746
757
|
nodes.findIndex((n) =>
|
|
747
|
-
isAlmostSamePoint2D(tempNodes[i + 1], n,
|
|
758
|
+
isAlmostSamePoint2D(tempNodes[i + 1], n, FLOAT_PRECISION)
|
|
748
759
|
),
|
|
749
760
|
])
|
|
750
761
|
}
|
|
@@ -805,6 +816,7 @@ export function getOutlineList(nodeList, edgeList, roofs = []) {
|
|
|
805
816
|
let cycleArray = forestRecursion(cycleTree)
|
|
806
817
|
cycles.push(...cycleArray)
|
|
807
818
|
}
|
|
819
|
+
|
|
808
820
|
let outlines = cycles
|
|
809
821
|
.map(({ cycle, children }) => {
|
|
810
822
|
cycle.pop()
|
|
@@ -849,8 +861,8 @@ function getIntersectionSegmentWithParams(A, B, C, D) {
|
|
|
849
861
|
const denom_v = dotProduct(u, v_normal)
|
|
850
862
|
const AB = vectorLength(u)
|
|
851
863
|
const CD = vectorLength(v)
|
|
852
|
-
if (AB <
|
|
853
|
-
if (getDistanceBetweenPoints(A, C) <
|
|
864
|
+
if (AB < FLOAT_PRECISION && CD < FLOAT_PRECISION) {
|
|
865
|
+
if (getDistanceBetweenPoints(A, C) < FLOAT_PRECISION * 2) {
|
|
854
866
|
return [
|
|
855
867
|
{
|
|
856
868
|
point: A,
|
|
@@ -862,7 +874,7 @@ function getIntersectionSegmentWithParams(A, B, C, D) {
|
|
|
862
874
|
} else if (AB == 0) {
|
|
863
875
|
//let's check if CD go through A
|
|
864
876
|
P = getPointOnLine(A, C, D)
|
|
865
|
-
if (getDistanceBetweenPoints(P, A) <
|
|
877
|
+
if (getDistanceBetweenPoints(P, A) < FLOAT_PRECISION) {
|
|
866
878
|
j = vectorLength(substractVector(C, A)) / CD
|
|
867
879
|
return [
|
|
868
880
|
{
|
|
@@ -875,7 +887,7 @@ function getIntersectionSegmentWithParams(A, B, C, D) {
|
|
|
875
887
|
} else if (CD == 0) {
|
|
876
888
|
//let's check if AB go through C
|
|
877
889
|
M = getPointOnLine(C, A, B)
|
|
878
|
-
if (getDistanceBetweenPoints(M, C) <
|
|
890
|
+
if (getDistanceBetweenPoints(M, C) < FLOAT_PRECISION) {
|
|
879
891
|
h = vectorLength(substractVector(C, A)) / AB
|
|
880
892
|
return [
|
|
881
893
|
{
|
|
@@ -886,15 +898,15 @@ function getIntersectionSegmentWithParams(A, B, C, D) {
|
|
|
886
898
|
]
|
|
887
899
|
}
|
|
888
900
|
}
|
|
889
|
-
if (Math.abs(denom_u) / (AB * CD) <
|
|
901
|
+
if (Math.abs(denom_u) / (AB * CD) < FLOAT_PRECISION) {
|
|
890
902
|
//u,v parallel
|
|
891
903
|
//let's check if they are close
|
|
892
904
|
//distance from A to CD
|
|
893
905
|
P = getPointOnLine(A, C, D)
|
|
894
906
|
M = getPointOnLine(B, C, D)
|
|
895
907
|
if (
|
|
896
|
-
getDistanceBetweenPoints(A, P) <
|
|
897
|
-
getDistanceBetweenPoints(B, M) <
|
|
908
|
+
getDistanceBetweenPoints(A, P) < FLOAT_PRECISION ||
|
|
909
|
+
getDistanceBetweenPoints(B, M) < FLOAT_PRECISION
|
|
898
910
|
) {
|
|
899
911
|
// AB and CD are colinear
|
|
900
912
|
// let's find which point are in the middle
|
|
@@ -6,6 +6,107 @@ import {
|
|
|
6
6
|
|
|
7
7
|
//TEST CASE for new implementation of spliting algorithm
|
|
8
8
|
describe('logicOperationOnPolygons function', () => {
|
|
9
|
+
test('returns intersecting polygon real case scenario', () => {
|
|
10
|
+
const out1 = [
|
|
11
|
+
{
|
|
12
|
+
x: 26665.34996686136,
|
|
13
|
+
y: 655753.6781718059,
|
|
14
|
+
z: 15000,
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
x: -55126.43646282707,
|
|
18
|
+
y: 640611.2872626077,
|
|
19
|
+
z: 15000,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
x: -61494.57624074482,
|
|
23
|
+
y: 675008.8623742728,
|
|
24
|
+
z: 15000,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
x: 20188.395676486834,
|
|
28
|
+
y: 690324.419608749,
|
|
29
|
+
z: 15000,
|
|
30
|
+
},
|
|
31
|
+
]
|
|
32
|
+
const out2 = [
|
|
33
|
+
{
|
|
34
|
+
x: 26665.56077244963,
|
|
35
|
+
y: 655752.5529970465,
|
|
36
|
+
z: 15000,
|
|
37
|
+
hasWarning: false,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
x: -55011.40036315337,
|
|
41
|
+
y: 640438.122784121,
|
|
42
|
+
z: 15000,
|
|
43
|
+
hasWarning: false,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
x: -61493.45350740093,
|
|
47
|
+
y: 675009.0728867748,
|
|
48
|
+
z: 15000,
|
|
49
|
+
hasWarning: false,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
x: 20188.395676486834,
|
|
53
|
+
y: 690324.419608749,
|
|
54
|
+
z: 15000,
|
|
55
|
+
hasWarning: false,
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
expect(logicOperationOnPolygons(out1, out2).length).toEqual(1)
|
|
59
|
+
})
|
|
60
|
+
test('returns intersecting polygon simplified real case scenario', () => {
|
|
61
|
+
const A = {
|
|
62
|
+
x: 0,
|
|
63
|
+
y: 0,
|
|
64
|
+
}
|
|
65
|
+
const B = {
|
|
66
|
+
x: 1000,
|
|
67
|
+
y: 1000,
|
|
68
|
+
}
|
|
69
|
+
const C = {
|
|
70
|
+
x: 0,
|
|
71
|
+
y: 1000,
|
|
72
|
+
}
|
|
73
|
+
const out1 = [
|
|
74
|
+
A,
|
|
75
|
+
{
|
|
76
|
+
x: 1000,
|
|
77
|
+
y: 0,
|
|
78
|
+
},
|
|
79
|
+
B,
|
|
80
|
+
C,
|
|
81
|
+
]
|
|
82
|
+
const out2 = [
|
|
83
|
+
A,
|
|
84
|
+
{
|
|
85
|
+
x: 1005,
|
|
86
|
+
y: 5,
|
|
87
|
+
},
|
|
88
|
+
B,
|
|
89
|
+
C,
|
|
90
|
+
]
|
|
91
|
+
expect(logicOperationOnPolygons(out1, out2).length).toEqual(1)
|
|
92
|
+
})
|
|
93
|
+
test('returns child parent polygon', () => {
|
|
94
|
+
const O = { x: 0, y: 0, z: 0 }
|
|
95
|
+
const A = { x: 100, y: 0, z: 0 }
|
|
96
|
+
const B = { x: 100, y: 100, z: 0 }
|
|
97
|
+
const C = { x: 0, y: 100, z: 0 }
|
|
98
|
+
const D = { x: 96, y: 94, z: 0 }
|
|
99
|
+
const E = { x: 70, y: 50, z: 0 }
|
|
100
|
+
const F = { x: 70, y: 70, z: 0 }
|
|
101
|
+
const G = { x: 50, y: 70, z: 0 }
|
|
102
|
+
|
|
103
|
+
const out1 = [O, A, B, C]
|
|
104
|
+
const out2 = [O, D, B, C]
|
|
105
|
+
const res = [[O, D, B, C]]
|
|
106
|
+
expect(logicOperationOnPolygons(out1, out2)).toEqual(
|
|
107
|
+
expect.arrayContaining(res)
|
|
108
|
+
)
|
|
109
|
+
})
|
|
9
110
|
test('returns intersecting polygon', () => {
|
|
10
111
|
const O = { x: 0, y: 0, z: 0 }
|
|
11
112
|
const A = { x: 10, y: 0, z: 0 }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { inverse2x2Matrix, multiplyMatrices } from '../../index'
|
|
2
|
+
|
|
3
|
+
describe('inverse2x2Matrix function', () => {
|
|
4
|
+
test('returns identity if MxinvM ', () => {
|
|
5
|
+
const M = [
|
|
6
|
+
[4, 3],
|
|
7
|
+
[7, 1],
|
|
8
|
+
]
|
|
9
|
+
const invM = inverse2x2Matrix(M)
|
|
10
|
+
const id = multiplyMatrices(M, invM)
|
|
11
|
+
for (let i = 0; i < id.length; i++) {
|
|
12
|
+
for (let j = 0; j < id.length; j++) {
|
|
13
|
+
expect(id[i][j] - (i == j ? 1 : 0) < 0.001).toBe(true)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { inverse3x3Matrix, multiplyMatrices } from '../../index'
|
|
2
|
+
|
|
3
|
+
describe('inverse3x3Matrix function', () => {
|
|
4
|
+
test('returns identity if MxinvM ', () => {
|
|
5
|
+
const M = [
|
|
6
|
+
[4, 3, 2],
|
|
7
|
+
[7, 1, 0],
|
|
8
|
+
[2, 1, 8],
|
|
9
|
+
]
|
|
10
|
+
const invM = inverse3x3Matrix(M)
|
|
11
|
+
const id = multiplyMatrices(M, invM)
|
|
12
|
+
for (let i = 0; i < id.length; i++) {
|
|
13
|
+
for (let j = 0; j < id.length; j++) {
|
|
14
|
+
expect(id[i][j] - (i == j ? 1 : 0) < 0.001).toBe(true)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
})
|