@eturnity/eturnity_maths 7.48.2 → 7.51.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/SHPSolver.js +342 -0
- package/src/geometry.js +26 -13
- package/src/index.js +3 -0
- package/src/intersectionPolygon.js +11 -0
- package/src/objects/Polygon.js +11 -7
- package/src/objects/hydrate.js +4 -2
- package/src/panelFunctions.js +51 -0
- package/src/stringPatchMatching.js +140 -0
- package/src/tests/SHPSolver/SHPSolver.spec.js +71 -0
- package/src/tests/SHPSolver/SHPSolverDebugCase.spec.js +26 -0
- package/src/tests/SHPSolver/scenarios/index.js +17 -0
- package/src/tests/SHPSolver/scenarios/scenario_1.json +58 -0
- package/src/tests/SHPSolver/scenarios/scenario_1_row.json +159 -0
- package/src/tests/SHPSolver/scenarios/scenario_1b.json +35 -0
- package/src/tests/SHPSolver/scenarios/scenario_1b_row.json +51 -0
- package/src/tests/SHPSolver/scenarios/scenario_2_row.json +175 -0
- package/src/tests/SHPSolver/scenarios/scenario_3.json +207 -0
- package/src/tests/SHPSolver/scenarios/scenario_3_simplify.json +151 -0
- package/src/tests/SHPSolver/scenarios/scenario_4.json +198 -0
- package/src/tests/panelFunctions/arePanelsAdjacent.spec.js +68 -0
- package/src/tests/panelFunctions/dividePanelsIntoAdjacentPatches.spec.js +59 -0
- package/src/tests/panelFunctions/stringPatchMatching.spec.js +72 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
{
|
|
2
|
+
"inputData": {
|
|
3
|
+
"panelsIndexes": [
|
|
4
|
+
[0, 1],
|
|
5
|
+
[5, 6],
|
|
6
|
+
[5, 5],
|
|
7
|
+
[4, 5],
|
|
8
|
+
[3, 5],
|
|
9
|
+
[2, 5],
|
|
10
|
+
[2, 4],
|
|
11
|
+
[3, 4],
|
|
12
|
+
[3, 3],
|
|
13
|
+
[2, 3],
|
|
14
|
+
[2, 2],
|
|
15
|
+
[3, 2],
|
|
16
|
+
[4, 2],
|
|
17
|
+
[4, 3],
|
|
18
|
+
[5, 3],
|
|
19
|
+
[5, 2],
|
|
20
|
+
[5, 1],
|
|
21
|
+
[4, 1],
|
|
22
|
+
[3, 1],
|
|
23
|
+
[2, 1]
|
|
24
|
+
],
|
|
25
|
+
"panels": [
|
|
26
|
+
{
|
|
27
|
+
"center": {
|
|
28
|
+
"x": 59089.470150869856,
|
|
29
|
+
"y": 23113.10010332451,
|
|
30
|
+
"z": 4623.0777308377055
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"center": {
|
|
35
|
+
"x": 57304.79417565741,
|
|
36
|
+
"y": 31846.12421495285,
|
|
37
|
+
"z": 8601.11072834007
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"center": {
|
|
42
|
+
"x": 58235.42820174781,
|
|
43
|
+
"y": 31451.10357057748,
|
|
44
|
+
"z": 8601.110728340082
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"center": {
|
|
49
|
+
"x": 57661.72937069992,
|
|
50
|
+
"y": 30099.519392627186,
|
|
51
|
+
"z": 7805.504128839598
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"center": {
|
|
56
|
+
"x": 57088.03053965201,
|
|
57
|
+
"y": 28747.9352146769,
|
|
58
|
+
"z": 7009.897529339132
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"center": {
|
|
63
|
+
"x": 56514.331708604055,
|
|
64
|
+
"y": 27396.351036726614,
|
|
65
|
+
"z": 6214.290929838656
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"center": {
|
|
70
|
+
"x": 57444.96573469447,
|
|
71
|
+
"y": 27001.330392351236,
|
|
72
|
+
"z": 6214.290929838656
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"center": {
|
|
77
|
+
"x": 58018.66456574242,
|
|
78
|
+
"y": 28352.91457030151,
|
|
79
|
+
"z": 7009.89752933913
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"center": {
|
|
84
|
+
"x": 58949.29859183279,
|
|
85
|
+
"y": 27957.89392592613,
|
|
86
|
+
"z": 7009.897529339129
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"center": {
|
|
91
|
+
"x": 58375.599760784884,
|
|
92
|
+
"y": 26606.30974797585,
|
|
93
|
+
"z": 6214.290929838658
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"center": {
|
|
98
|
+
"x": 59306.233786875324,
|
|
99
|
+
"y": 26211.28910360046,
|
|
100
|
+
"z": 6214.290929838653
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"center": {
|
|
105
|
+
"x": 59879.93261792322,
|
|
106
|
+
"y": 27562.873281550743,
|
|
107
|
+
"z": 7009.897529339125
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"center": {
|
|
112
|
+
"x": 60453.63144897114,
|
|
113
|
+
"y": 28914.45745950104,
|
|
114
|
+
"z": 7805.504128839594
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"center": {
|
|
119
|
+
"x": 59522.99742288074,
|
|
120
|
+
"y": 29309.47810387642,
|
|
121
|
+
"z": 7805.504128839607
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"center": {
|
|
126
|
+
"x": 60096.69625392865,
|
|
127
|
+
"y": 30661.0622818267,
|
|
128
|
+
"z": 8601.110728340056
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"center": {
|
|
133
|
+
"x": 61027.330280019065,
|
|
134
|
+
"y": 30266.041637451326,
|
|
135
|
+
"z": 8601.110728340074
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"center": {
|
|
140
|
+
"x": 61957.96430610949,
|
|
141
|
+
"y": 29871.02099307593,
|
|
142
|
+
"z": 8601.11072834006
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"center": {
|
|
147
|
+
"x": 61384.26547506159,
|
|
148
|
+
"y": 28519.43681512565,
|
|
149
|
+
"z": 7805.504128839572
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"center": {
|
|
154
|
+
"x": 60810.56664401362,
|
|
155
|
+
"y": 27167.85263717536,
|
|
156
|
+
"z": 7009.89752933911
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"center": {
|
|
161
|
+
"x": 60236.86781296576,
|
|
162
|
+
"y": 25816.268459225073,
|
|
163
|
+
"z": 6214.290929838648
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
"outputData": {
|
|
169
|
+
"indexOrder": [
|
|
170
|
+
19, 10, 9, 6, 5, 4, 7, 8, 11, 18, 17, 16, 15, 14, 2, 1, 3, 13, 12, 0
|
|
171
|
+
],
|
|
172
|
+
"hasSolution": true,
|
|
173
|
+
"isOptimal": false
|
|
174
|
+
},
|
|
175
|
+
"proximityMatrix": [
|
|
176
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
177
|
+
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
178
|
+
[0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
179
|
+
[0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
180
|
+
[0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
181
|
+
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
182
|
+
[0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
183
|
+
[0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
184
|
+
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0],
|
|
185
|
+
[0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
186
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
|
|
187
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0],
|
|
188
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
|
|
189
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
|
|
190
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
|
|
191
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0],
|
|
192
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0],
|
|
193
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0],
|
|
194
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
|
|
195
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0]
|
|
196
|
+
],
|
|
197
|
+
"arePanelsInSamePatch": false
|
|
198
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { arePanelsAdjacent } from '../../index'
|
|
2
|
+
|
|
3
|
+
describe('arePanelsAdjacent', () => {
|
|
4
|
+
it('should return true for horizontally adjacent panels in same module field', () => {
|
|
5
|
+
const panelA = {
|
|
6
|
+
moduleField: { id: 1 },
|
|
7
|
+
index: [0, 0],
|
|
8
|
+
}
|
|
9
|
+
const panelB = {
|
|
10
|
+
moduleField: { id: 1 },
|
|
11
|
+
index: [1, 0],
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
expect(arePanelsAdjacent(panelA, panelB)).toBe(true)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('should return true for vertically adjacent panels', () => {
|
|
18
|
+
const panelA = {
|
|
19
|
+
moduleField: { id: 1 },
|
|
20
|
+
index: [0, 0],
|
|
21
|
+
}
|
|
22
|
+
const panelB = {
|
|
23
|
+
moduleField: { id: 1 },
|
|
24
|
+
index: [0, 1],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
expect(arePanelsAdjacent(panelA, panelB)).toBe(true)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should return false for panels in different module fields', () => {
|
|
31
|
+
const panelA = {
|
|
32
|
+
moduleField: { id: 1 },
|
|
33
|
+
index: [0, 0],
|
|
34
|
+
}
|
|
35
|
+
const panelB = {
|
|
36
|
+
moduleField: { id: 2 },
|
|
37
|
+
index: [1, 0],
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
expect(arePanelsAdjacent(panelA, panelB)).toBe(false)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('should return false for non-adjacent panels', () => {
|
|
44
|
+
const panelA = {
|
|
45
|
+
moduleField: { id: 1 },
|
|
46
|
+
index: [0, 0],
|
|
47
|
+
}
|
|
48
|
+
const panelB = {
|
|
49
|
+
moduleField: { id: 1 },
|
|
50
|
+
index: [2, 2],
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
expect(arePanelsAdjacent(panelA, panelB)).toBe(false)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('should return false for diagonally adjacent panels', () => {
|
|
57
|
+
const panelA = {
|
|
58
|
+
moduleField: { id: 1 },
|
|
59
|
+
index: [0, 0],
|
|
60
|
+
}
|
|
61
|
+
const panelB = {
|
|
62
|
+
moduleField: { id: 1 },
|
|
63
|
+
index: [1, 1],
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
expect(arePanelsAdjacent(panelA, panelB)).toBe(false)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { dividePanelsIntoAdjacentPatches } from '../../index'
|
|
2
|
+
|
|
3
|
+
describe('dividePanelsIntoAdjacentPatches', () => {
|
|
4
|
+
it('should return empty array for empty input', () => {
|
|
5
|
+
expect(dividePanelsIntoAdjacentPatches([])).toEqual([])
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
it('should return single patch for single panel', () => {
|
|
9
|
+
const panel = {
|
|
10
|
+
moduleField: { id: 1 },
|
|
11
|
+
index: [0, 0],
|
|
12
|
+
}
|
|
13
|
+
expect(dividePanelsIntoAdjacentPatches([panel])).toEqual([[panel]])
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('should group horizontally adjacent panels', () => {
|
|
17
|
+
const panels = [
|
|
18
|
+
{ moduleField: { id: 1 }, index: [0, 0] },
|
|
19
|
+
{ moduleField: { id: 1 }, index: [1, 0] },
|
|
20
|
+
{ moduleField: { id: 1 }, index: [2, 0] },
|
|
21
|
+
]
|
|
22
|
+
expect(dividePanelsIntoAdjacentPatches(panels)).toEqual([panels])
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should group vertically adjacent panels', () => {
|
|
26
|
+
const panels = [
|
|
27
|
+
{ moduleField: { id: 1 }, index: [0, 0] },
|
|
28
|
+
{ moduleField: { id: 1 }, index: [0, 1] },
|
|
29
|
+
{ moduleField: { id: 1 }, index: [0, 2] },
|
|
30
|
+
]
|
|
31
|
+
expect(dividePanelsIntoAdjacentPatches(panels)).toEqual([panels])
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should create separate patches for non-adjacent panels', () => {
|
|
35
|
+
const panels = [
|
|
36
|
+
{ moduleField: { id: 1 }, index: [0, 0] },
|
|
37
|
+
{ moduleField: { id: 1 }, index: [0, 2] },
|
|
38
|
+
{ moduleField: { id: 1 }, index: [2, 0] },
|
|
39
|
+
]
|
|
40
|
+
expect(dividePanelsIntoAdjacentPatches(panels)).toEqual([
|
|
41
|
+
[panels[0]],
|
|
42
|
+
[panels[1]],
|
|
43
|
+
[panels[2]],
|
|
44
|
+
])
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('should handle multiple patches with different moduleField ids', () => {
|
|
48
|
+
const panels = [
|
|
49
|
+
{ moduleField: { id: 1 }, index: [0, 0] },
|
|
50
|
+
{ moduleField: { id: 1 }, index: [1, 0] },
|
|
51
|
+
{ moduleField: { id: 2 }, index: [0, 1] },
|
|
52
|
+
{ moduleField: { id: 2 }, index: [1, 1] },
|
|
53
|
+
]
|
|
54
|
+
expect(dividePanelsIntoAdjacentPatches(panels)).toEqual([
|
|
55
|
+
[panels[0], panels[1]],
|
|
56
|
+
[panels[2], panels[3]],
|
|
57
|
+
])
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { solveStringPatchMatching } from '../../stringPatchMatching'
|
|
2
|
+
|
|
3
|
+
describe('solveStringPatchMatching', () => {
|
|
4
|
+
it('should solve simple 1:1 matching case', () => {
|
|
5
|
+
const stringList = [5, 3]
|
|
6
|
+
const patchList = [5, 3]
|
|
7
|
+
const expected = [
|
|
8
|
+
[5, 0],
|
|
9
|
+
[0, 3],
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
expect(solveStringPatchMatching(stringList, patchList).matrix).toEqual(
|
|
13
|
+
expected
|
|
14
|
+
)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('should solve case where one patch needs multiple strings', () => {
|
|
18
|
+
const stringList = [2, 3, 4]
|
|
19
|
+
const patchList = [5, 4]
|
|
20
|
+
const expected = [
|
|
21
|
+
[2, 3, 0],
|
|
22
|
+
[0, 0, 4],
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
expect(solveStringPatchMatching(stringList, patchList).matrix).toEqual(
|
|
26
|
+
expected
|
|
27
|
+
)
|
|
28
|
+
})
|
|
29
|
+
it('should solve case where there is only one patch which needs multiple strings', () => {
|
|
30
|
+
const stringList = [2, 3, 4]
|
|
31
|
+
const patchList = [9]
|
|
32
|
+
const expected = [[2, 3, 4]]
|
|
33
|
+
|
|
34
|
+
expect(solveStringPatchMatching(stringList, patchList).matrix).toEqual(
|
|
35
|
+
expected
|
|
36
|
+
)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should handle empty lists', () => {
|
|
40
|
+
const stringList = []
|
|
41
|
+
const patchList = []
|
|
42
|
+
const expected = []
|
|
43
|
+
|
|
44
|
+
expect(solveStringPatchMatching(stringList, patchList).matrix).toEqual(
|
|
45
|
+
expected
|
|
46
|
+
)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should solve complex matching case', () => {
|
|
50
|
+
const stringList = [2, 2, 3, 4]
|
|
51
|
+
const patchList = [4, 7]
|
|
52
|
+
const expected = [
|
|
53
|
+
[0, 0, 0, 4],
|
|
54
|
+
[2, 2, 3, 0],
|
|
55
|
+
]
|
|
56
|
+
function validateSum(stringList, patchList, matrix) {
|
|
57
|
+
return (
|
|
58
|
+
stringList.every(
|
|
59
|
+
(s, index) => matrix.reduce((a, b) => a + b[index], 0) == s
|
|
60
|
+
) &&
|
|
61
|
+
patchList.every(
|
|
62
|
+
(p, index) => matrix[index].reduce((a, b) => a + b, 0) == p
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
const receivedMatrix = solveStringPatchMatching(
|
|
67
|
+
stringList,
|
|
68
|
+
patchList
|
|
69
|
+
).matrix
|
|
70
|
+
expect(validateSum(stringList, patchList, receivedMatrix)).toBe(true)
|
|
71
|
+
})
|
|
72
|
+
})
|