@eturnity/eturnity_maths 1.0.2
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/babel.config.js +3 -0
- package/package.json +30 -0
- package/src/assets/theme.js +45 -0
- package/src/config.js +77 -0
- package/src/coords.js +24 -0
- package/src/geo.js +51 -0
- package/src/geometry.js +760 -0
- package/src/index.js +10 -0
- package/src/intersectionPolygon.js +623 -0
- package/src/matrix.js +53 -0
- package/src/objects/Circle.js +51 -0
- package/src/objects/Line.js +110 -0
- package/src/objects/Point.js +57 -0
- package/src/objects/Polygon.js +240 -0
- package/src/objects/derivedState/AddMargin.js +109 -0
- package/src/objects/derivedState/UpdateRoofModuleFieldRelations.js +119 -0
- package/src/objects/derivedState/UpdateRoofObstacleRelations.js +86 -0
- package/src/objects/derivedState/index.js +2 -0
- package/src/objects/derivedState/updateComputedGeometryPolygon.js +168 -0
- package/src/objects/graph/DFS.js +80 -0
- package/src/objects/graph/graphCreation.js +44 -0
- package/src/objects/hydrate.js +24 -0
- package/src/objects/index.js +8 -0
- package/src/splitMergePolygons.js +553 -0
- package/src/test/maths.test.js +10 -0
- package/src/vector.js +56 -0
- package/webpack.config.js +11 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
|
|
2
|
+
import {
|
|
3
|
+
getPointInsideOutline,
|
|
4
|
+
isInsidePolygon
|
|
5
|
+
} from './geometry'
|
|
6
|
+
import {getIntersections,
|
|
7
|
+
getNodeList,
|
|
8
|
+
getEdgeList,
|
|
9
|
+
getOutlineList
|
|
10
|
+
} from './splitMergePolygons'
|
|
11
|
+
|
|
12
|
+
// Determines whether a given polygon is self-intersecting
|
|
13
|
+
//is counterClockwise
|
|
14
|
+
export function isCounterClockwise(A, B, C) {
|
|
15
|
+
return (C.y - A.y) * (B.x - A.x) > (B.y - A.y) * (C.x - A.x)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Determines whether line segment AB intersects line segment CD
|
|
19
|
+
export function doLineSegmentsIntersect(A, B, C, D) {
|
|
20
|
+
return (
|
|
21
|
+
isCounterClockwise(A, C, D) != isCounterClockwise(B, C, D) &&
|
|
22
|
+
isCounterClockwise(A, B, C) != isCounterClockwise(A, B, D)
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
export function isSelfIntersecting(outline) {
|
|
26
|
+
let isSelfIntersecting = false
|
|
27
|
+
const length = outline.length
|
|
28
|
+
if (length < 4) return false
|
|
29
|
+
//let AB and CD be two edges we are testing for intersection
|
|
30
|
+
for (let k = 0; k < length; k++) {
|
|
31
|
+
let A = outline[k]
|
|
32
|
+
let B = outline[(k + 1) % length]
|
|
33
|
+
let offset = k == 0 ? 0 : 1
|
|
34
|
+
for (let j = k + 2; j < length - 1 + offset; j++) {
|
|
35
|
+
let C = outline[j]
|
|
36
|
+
let D = outline[(j + 1) % length]
|
|
37
|
+
if (doLineSegmentsIntersect(A, B, C, D)) {
|
|
38
|
+
isSelfIntersecting = true
|
|
39
|
+
break
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (isSelfIntersecting) {
|
|
43
|
+
break
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return isSelfIntersecting
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
export function logicOperationOnPolygons(outline1,outline2,mode='intersect')
|
|
51
|
+
{
|
|
52
|
+
const fig1 = outline1.map((p) => {
|
|
53
|
+
return { x: p.x, y: p.y, z: p.z }
|
|
54
|
+
})
|
|
55
|
+
fig1.push(fig1[0])
|
|
56
|
+
const fig2 = outline2.map((p) => {
|
|
57
|
+
return { x: p.x, y: p.y, z: p.z }
|
|
58
|
+
})
|
|
59
|
+
//nodeList:
|
|
60
|
+
let dirtyNodeList = []
|
|
61
|
+
fig1.forEach((p) => {dirtyNodeList.push(p)})
|
|
62
|
+
fig2.forEach((p) => {dirtyNodeList.push(p)})
|
|
63
|
+
//edgeList (just in term of indexes)
|
|
64
|
+
const edges=fig2.map((p,index)=>{
|
|
65
|
+
return {outline:[p,fig2[(index+1)%fig2.length]]}
|
|
66
|
+
})
|
|
67
|
+
let intersections = getIntersections({outline:fig1}, edges)
|
|
68
|
+
//2. gather all nodes+intersection in a list[[x,y],[x,y]]
|
|
69
|
+
const nodeList = getNodeList(intersections, edges, {outline:fig1})
|
|
70
|
+
//3. generate all edges not cut, those cut and those from construction polyline
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
const edgeList = getEdgeList(
|
|
74
|
+
nodeList,
|
|
75
|
+
intersections,
|
|
76
|
+
edges,
|
|
77
|
+
{outline:fig1},
|
|
78
|
+
1
|
|
79
|
+
)
|
|
80
|
+
//4. run planar-face-discovery to get all cycles and rebuild our polygons
|
|
81
|
+
const outlineList = getOutlineList(nodeList, edgeList)
|
|
82
|
+
|
|
83
|
+
return filterPolygons(outlineList, fig1, fig2, mode)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function filterPolygons(polygons, fig1, fig2, mode) {
|
|
87
|
+
var filtered = []
|
|
88
|
+
var c1, c2
|
|
89
|
+
var point
|
|
90
|
+
var bigPolygons = removeSmallPolygons(polygons, 0.0001)
|
|
91
|
+
for (var i = 0; i < bigPolygons.length; i++) {
|
|
92
|
+
point = getPointInsideOutline(bigPolygons[i],bigPolygons.filter((p,index)=>index!=i))
|
|
93
|
+
c1 = isInsidePolygon(point, fig1)
|
|
94
|
+
c2 = isInsidePolygon(point, fig2)
|
|
95
|
+
if (
|
|
96
|
+
(mode === 'intersect' && c1 && c2) || //intersection
|
|
97
|
+
(mode === 'cut1' && c1 && !c2) || //fig1 - fig2
|
|
98
|
+
(mode === 'cut2' && !c1 && c2) || //fig2 - fig2
|
|
99
|
+
(mode === 'sum' && (c1 || c2))
|
|
100
|
+
) {
|
|
101
|
+
//fig1 + fig2
|
|
102
|
+
//remove undefined point:
|
|
103
|
+
bigPolygons[i]=bigPolygons[i].filter(p=>!!p)
|
|
104
|
+
filtered.push(bigPolygons[i])
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return filtered
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
export function intersectOutlines(outline1, outline2) {
|
|
112
|
+
const fig1 = outline1.map((p) => {
|
|
113
|
+
return { x: p.x, y: p.y, z: p.z }
|
|
114
|
+
})
|
|
115
|
+
const fig2 = outline2.map((p) => {
|
|
116
|
+
return { x: p.x, y: p.y, z: p.z }
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
return logicOperationOnPolygons(fig1,fig2,'intersect')
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function alignPolygon(polygon, points) {
|
|
124
|
+
for (let i = 0; i < polygon.length; i++) {
|
|
125
|
+
for (let j = 0; j < points.length; j++) {
|
|
126
|
+
if (distance(polygon[i], points[j]) < 0.0001) polygon[i] = points[j]
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return polygon
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function distance(p1, p2) {
|
|
133
|
+
var dx = Math.abs(p1.x - p2.x)
|
|
134
|
+
var dy = Math.abs(p1.y - p2.y)
|
|
135
|
+
return Math.sqrt(dx * dx + dy * dy)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
//check polygons for correctness
|
|
139
|
+
function checkPolygons(fig1, fig2) {
|
|
140
|
+
var figs = [fig1, fig2]
|
|
141
|
+
for (var i = 0; i < figs.length; i++) {
|
|
142
|
+
if (figs[i].length < 3) {
|
|
143
|
+
console.error('Polygon ' + (i + 1) + ' is invalid!')
|
|
144
|
+
return false
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//create array of edges of all polygons
|
|
151
|
+
function edgify(fig1, fig2) {
|
|
152
|
+
//create primary array from all edges
|
|
153
|
+
var primEdges = getEdges(fig1).concat(getEdges(fig2))
|
|
154
|
+
var secEdges = []
|
|
155
|
+
//check every edge
|
|
156
|
+
for (var i = 0; i < primEdges.length; i++) {
|
|
157
|
+
var points = []
|
|
158
|
+
//for intersection with every edge except itself
|
|
159
|
+
for (var j = 0; j < primEdges.length; j++) {
|
|
160
|
+
if (i != j) {
|
|
161
|
+
var interPoints = findEdgeIntersection(primEdges[i], primEdges[j])
|
|
162
|
+
addNewPoints(interPoints, points)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//add start and end points to intersection points
|
|
166
|
+
let startPoint = primEdges[i][0]
|
|
167
|
+
startPoint.t = 0
|
|
168
|
+
let endPoint = primEdges[i][1]
|
|
169
|
+
endPoint.t = 1
|
|
170
|
+
addNewPoints([startPoint, endPoint], points)
|
|
171
|
+
//sort all points by position on edge
|
|
172
|
+
points = sortPoints(points)
|
|
173
|
+
//break edge to parts
|
|
174
|
+
for (var k = 0; k < points.length - 1; k++) {
|
|
175
|
+
var edge = [
|
|
176
|
+
{ x: points[k].x, y: points[k].y },
|
|
177
|
+
{ x: points[k + 1].x, y: points[k + 1].y }
|
|
178
|
+
]
|
|
179
|
+
// check for existanse in sec.array
|
|
180
|
+
if (!edgeExists(edge, secEdges)) {
|
|
181
|
+
//push if not exists
|
|
182
|
+
secEdges.push(edge)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return secEdges
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function addNewPoints(newPoints, points) {
|
|
190
|
+
if (newPoints.length > 0) {
|
|
191
|
+
//check for uniqueness
|
|
192
|
+
for (var k = 0; k < newPoints.length; k++) {
|
|
193
|
+
if (!pointExists(newPoints[k], points)) {
|
|
194
|
+
points.push(newPoints[k])
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function sortPoints(points) {
|
|
201
|
+
var p = points
|
|
202
|
+
p.sort((a, b) => {
|
|
203
|
+
if (a.t > b.t) return 1
|
|
204
|
+
if (a.t < b.t) return -1
|
|
205
|
+
})
|
|
206
|
+
return p
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function getEdges(fig) {
|
|
210
|
+
var edges = []
|
|
211
|
+
var len = fig.length
|
|
212
|
+
for (var i = 0; i < len; i++) {
|
|
213
|
+
edges.push([
|
|
214
|
+
{ x: fig[i % len].x, y: fig[i % len].y },
|
|
215
|
+
{ x: fig[(i + 1) % len].x, y: fig[(i + 1) % len].y }
|
|
216
|
+
])
|
|
217
|
+
}
|
|
218
|
+
return edges
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function findEdgeIntersection(edge1, edge2) {
|
|
222
|
+
var x1 = edge1[0].x
|
|
223
|
+
var x2 = edge1[1].x
|
|
224
|
+
var x3 = edge2[0].x
|
|
225
|
+
var x4 = edge2[1].x
|
|
226
|
+
var y1 = edge1[0].y
|
|
227
|
+
var y2 = edge1[1].y
|
|
228
|
+
var y3 = edge2[0].y
|
|
229
|
+
var y4 = edge2[1].y
|
|
230
|
+
var nom1 = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)
|
|
231
|
+
var nom2 = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)
|
|
232
|
+
var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
|
|
233
|
+
var t1 = nom1 / denom
|
|
234
|
+
var t2 = nom2 / denom
|
|
235
|
+
var interPoints = []
|
|
236
|
+
//1. lines are parallel or edges don't intersect
|
|
237
|
+
if ((denom === 0 && nom1 !== 0) || t1 <= 0 || t1 >= 1 || t2 < 0 || t2 > 1) {
|
|
238
|
+
return interPoints
|
|
239
|
+
}
|
|
240
|
+
//2. lines are collinear
|
|
241
|
+
else if (nom1 === 0 && denom === 0) {
|
|
242
|
+
//check if endpoints of edge2 lies on edge1
|
|
243
|
+
for (var i = 0; i < 2; i++) {
|
|
244
|
+
var classify = classifyPoint(edge2[i], edge1)
|
|
245
|
+
//find position of this endpoints relatively to edge1
|
|
246
|
+
if (classify.loc == 'ORIGIN' || classify.loc == 'DESTINATION') {
|
|
247
|
+
interPoints.push({ x: edge2[i].x, y: edge2[i].y, t: classify.t })
|
|
248
|
+
} else if (classify.loc == 'BETWEEN') {
|
|
249
|
+
x = +(x1 + classify.t * (x2 - x1)).toFixed(9)
|
|
250
|
+
y = +(y1 + classify.t * (y2 - y1)).toFixed(9)
|
|
251
|
+
interPoints.push({ x: x, y: y, t: classify.t })
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return interPoints
|
|
255
|
+
}
|
|
256
|
+
//3. edges intersect
|
|
257
|
+
else {
|
|
258
|
+
for (var i = 0; i < 2; i++) {
|
|
259
|
+
var classify = classifyPoint(edge2[i], edge1)
|
|
260
|
+
if (classify.loc == 'ORIGIN' || classify.loc == 'DESTINATION') {
|
|
261
|
+
interPoints.push({ x: edge2[i].x, y: edge2[i].y, t: classify.t })
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (interPoints.length > 0) {
|
|
265
|
+
return interPoints
|
|
266
|
+
}
|
|
267
|
+
var x = +(x1 + t1 * (x2 - x1)).toFixed(9)
|
|
268
|
+
var y = +(y1 + t1 * (y2 - y1)).toFixed(9)
|
|
269
|
+
interPoints.push({ x: x, y: y, t: t1 })
|
|
270
|
+
return interPoints
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function classifyPoint(p, edge) {
|
|
275
|
+
var ax = edge[1].x - edge[0].x
|
|
276
|
+
var ay = edge[1].y - edge[0].y
|
|
277
|
+
var bx = p.x - edge[0].x
|
|
278
|
+
var by = p.y - edge[0].y
|
|
279
|
+
var sa = ax * by - bx * ay
|
|
280
|
+
if (p.x === edge[0].x && p.y === edge[0].y) {
|
|
281
|
+
return { loc: 'ORIGIN', t: 0 }
|
|
282
|
+
}
|
|
283
|
+
if (p.x === edge[1].x && p.y === edge[1].y) {
|
|
284
|
+
return { loc: 'DESTINATION', t: 1 }
|
|
285
|
+
}
|
|
286
|
+
var theta =
|
|
287
|
+
(polarAngle([edge[1], edge[0]]) -
|
|
288
|
+
polarAngle([
|
|
289
|
+
{ x: edge[1].x, y: edge[1].y },
|
|
290
|
+
{ x: p.x, y: p.y }
|
|
291
|
+
])) %
|
|
292
|
+
360
|
|
293
|
+
if (theta < 0) {
|
|
294
|
+
theta = theta + 360
|
|
295
|
+
}
|
|
296
|
+
if (sa < -0.0000001) {
|
|
297
|
+
return { loc: 'LEFT', theta: theta }
|
|
298
|
+
}
|
|
299
|
+
if (sa > 0.0000001) {
|
|
300
|
+
return { loc: 'RIGHT', theta: theta }
|
|
301
|
+
}
|
|
302
|
+
if (ax * bx < 0 || ay * by < 0) {
|
|
303
|
+
return { loc: 'BEHIND', theta: theta }
|
|
304
|
+
}
|
|
305
|
+
if (Math.sqrt(ax * ax + ay * ay) < Math.sqrt(bx * bx + by * by)) {
|
|
306
|
+
return { loc: 'BEYOND', theta: theta }
|
|
307
|
+
}
|
|
308
|
+
var t
|
|
309
|
+
if (ax !== 0) {
|
|
310
|
+
t = bx / ax
|
|
311
|
+
} else {
|
|
312
|
+
t = by / ay
|
|
313
|
+
}
|
|
314
|
+
return { loc: 'BETWEEN', t: t }
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function polarAngle(edge) {
|
|
318
|
+
var dx = edge[1].x - edge[0].x
|
|
319
|
+
var dy = edge[1].y - edge[0].y
|
|
320
|
+
if (dx === 0 && dy === 0) {
|
|
321
|
+
//console.error("Edge has zero length.");
|
|
322
|
+
return false
|
|
323
|
+
}
|
|
324
|
+
if (dx === 0) {
|
|
325
|
+
return dy > 0 ? 90 : 270
|
|
326
|
+
}
|
|
327
|
+
if (dy === 0) {
|
|
328
|
+
return dx > 0 ? 0 : 180
|
|
329
|
+
}
|
|
330
|
+
var theta = (Math.atan(dy / dx) * 360) / (2 * Math.PI)
|
|
331
|
+
if (dx > 0) {
|
|
332
|
+
return dy >= 0 ? theta : theta + 360
|
|
333
|
+
} else {
|
|
334
|
+
return theta + 180
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function pointExists(p, points) {
|
|
339
|
+
if (points.length === 0) {
|
|
340
|
+
return false
|
|
341
|
+
}
|
|
342
|
+
for (var i = 0; i < points.length; i++) {
|
|
343
|
+
if (p.x === points[i].x && p.y === points[i].y) {
|
|
344
|
+
return true
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return false
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function edgeExists(e, edges) {
|
|
351
|
+
if (edges.length === 0) {
|
|
352
|
+
return false
|
|
353
|
+
}
|
|
354
|
+
for (var i = 0; i < edges.length; i++) {
|
|
355
|
+
if (equalEdges(e, edges[i])) return true
|
|
356
|
+
}
|
|
357
|
+
return false
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function equalEdges(edge1, edge2) {
|
|
361
|
+
if (
|
|
362
|
+
(edge1[0].x === edge2[0].x &&
|
|
363
|
+
edge1[0].y === edge2[0].y &&
|
|
364
|
+
edge1[1].x === edge2[1].x &&
|
|
365
|
+
edge1[1].y === edge2[1].y) ||
|
|
366
|
+
(edge1[0].x === edge2[1].x &&
|
|
367
|
+
edge1[0].y === edge2[1].y &&
|
|
368
|
+
edge1[1].x === edge2[0].x &&
|
|
369
|
+
edge1[1].y === edge2[0].y)
|
|
370
|
+
) {
|
|
371
|
+
return true
|
|
372
|
+
} else {
|
|
373
|
+
return false
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function polygonate(edges) {
|
|
378
|
+
var polygons = []
|
|
379
|
+
var polygon = []
|
|
380
|
+
var len = edges.length
|
|
381
|
+
var midpoints = getMidpoints(edges)
|
|
382
|
+
//start from every edge and create non-selfintersecting polygons
|
|
383
|
+
for (var i = 0; i < len - 2; i++) {
|
|
384
|
+
var org = { x: edges[i][0].x, y: edges[i][0].y }
|
|
385
|
+
var dest = { x: edges[i][1].x, y: edges[i][1].y }
|
|
386
|
+
var currentEdge = i
|
|
387
|
+
var point
|
|
388
|
+
var p
|
|
389
|
+
var direction
|
|
390
|
+
var stop
|
|
391
|
+
//while we havn't come to the starting edge again
|
|
392
|
+
for (direction = 0; direction < 2; direction++) {
|
|
393
|
+
polygon = []
|
|
394
|
+
stop = false
|
|
395
|
+
while (polygon.length === 0 || !stop) {
|
|
396
|
+
//add point to polygon
|
|
397
|
+
polygon.push({ x: org.x, y: org.y })
|
|
398
|
+
point = undefined
|
|
399
|
+
//look for edge connected with end of current edge
|
|
400
|
+
for (var j = 0; j < len; j++) {
|
|
401
|
+
p = undefined
|
|
402
|
+
//except itself
|
|
403
|
+
if (!equalEdges(edges[j], edges[currentEdge])) {
|
|
404
|
+
//if some edge is connected to current edge in one endpoint
|
|
405
|
+
if (edges[j][0].x === dest.x && edges[j][0].y === dest.y) {
|
|
406
|
+
p = edges[j][1]
|
|
407
|
+
}
|
|
408
|
+
if (edges[j][1].x === dest.x && edges[j][1].y === dest.y) {
|
|
409
|
+
p = edges[j][0]
|
|
410
|
+
}
|
|
411
|
+
//compare it with last found connected edge for minimum angle between itself and current edge
|
|
412
|
+
if (p) {
|
|
413
|
+
var classify = classifyPoint(p, [org, dest])
|
|
414
|
+
//if this edge has smaller theta then last found edge update data of next edge of polygon
|
|
415
|
+
if (
|
|
416
|
+
!point ||
|
|
417
|
+
(classify.theta < point.theta && direction === 0) ||
|
|
418
|
+
(classify.theta > point.theta && direction === 1)
|
|
419
|
+
) {
|
|
420
|
+
point = { x: p.x, y: p.y, theta: classify.theta, edge: j }
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
//change current edge to next edge
|
|
426
|
+
org.x = dest.x
|
|
427
|
+
org.y = dest.y
|
|
428
|
+
dest.x = point.x
|
|
429
|
+
dest.y = point.y
|
|
430
|
+
currentEdge = point.edge
|
|
431
|
+
//if we reach start edge
|
|
432
|
+
if (equalEdges([org, dest], edges[i])) {
|
|
433
|
+
stop = true
|
|
434
|
+
//check polygon for correctness
|
|
435
|
+
/*for (var k = 0; k < allPoints.length; k++) {
|
|
436
|
+
//if some point is inside polygon it is incorrect
|
|
437
|
+
if ((!pointExists(allPoints[k], polygon)) && (findPointInsidePolygon(allPoints[k], polygon))) {
|
|
438
|
+
polygon = false;
|
|
439
|
+
}
|
|
440
|
+
}*/
|
|
441
|
+
for (let k = 0; k < midpoints.length; k++) {
|
|
442
|
+
//if some midpoint is inside polygon (edge inside polygon) it is incorrect
|
|
443
|
+
if (findPointInsidePolygon(midpoints[k], polygon)) {
|
|
444
|
+
polygon = false
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
//add created polygon if it is correct and was not found before
|
|
450
|
+
if (polygon && !polygonExists(polygon, polygons)) {
|
|
451
|
+
polygons.push(polygon)
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return polygons
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function polygonExists(polygon, polygons) {
|
|
459
|
+
//if array is empty element doesn't exist in it
|
|
460
|
+
if (polygons.length === 0) return false
|
|
461
|
+
//check every polygon in array
|
|
462
|
+
for (var i = 0; i < polygons.length; i++) {
|
|
463
|
+
//if lengths are not same go to next element
|
|
464
|
+
if (polygon.length !== polygons[i].length) continue
|
|
465
|
+
//if length are same need to check
|
|
466
|
+
else {
|
|
467
|
+
//if all the points are same
|
|
468
|
+
for (var j = 0; j < polygon.length; j++) {
|
|
469
|
+
//if point is not found break forloop and go to next element
|
|
470
|
+
if (!pointExists(polygon[j], polygons[i])) break
|
|
471
|
+
//if point found
|
|
472
|
+
else {
|
|
473
|
+
//and it is last point in polygon we found polygon in array!
|
|
474
|
+
if (j === polygon.length - 1) return true
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return false
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function filterPolygonsOld(polygons, fig1, fig2, mode) {
|
|
483
|
+
var filtered = []
|
|
484
|
+
var c1, c2
|
|
485
|
+
var point
|
|
486
|
+
var bigPolygons = removeSmallPolygons(polygons, 0.0001)
|
|
487
|
+
for (var i = 0; i < bigPolygons.length; i++) {
|
|
488
|
+
point = getPointInsidePolygon(bigPolygons[i])
|
|
489
|
+
c1 = findPointInsidePolygon(point, fig1)
|
|
490
|
+
c2 = findPointInsidePolygon(point, fig2)
|
|
491
|
+
if (
|
|
492
|
+
(mode === 'intersect' && c1 && c2) || //intersection
|
|
493
|
+
(mode === 'cut1' && c1 && !c2) || //fig1 - fig2
|
|
494
|
+
(mode === 'cut2' && !c1 && c2) || //fig2 - fig2
|
|
495
|
+
(mode === 'sum' && (c1 || c2))
|
|
496
|
+
) {
|
|
497
|
+
//fig1 + fig2
|
|
498
|
+
filtered.push(bigPolygons[i])
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return filtered
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function removeSmallPolygons(polygons, minSize) {
|
|
505
|
+
var big = []
|
|
506
|
+
for (var i = 0; i < polygons.length; i++) {
|
|
507
|
+
if (polygonArea(polygons[i]) >= minSize) {
|
|
508
|
+
big.push(polygons[i])
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return big
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function polygonArea(p) {
|
|
515
|
+
var len = p.length
|
|
516
|
+
var s = 0
|
|
517
|
+
for (var i = 0; i < len; i++) {
|
|
518
|
+
s += Math.abs(
|
|
519
|
+
p[i % len].x * p[(i + 1) % len].y - p[i % len].y * p[(i + 1) % len].x
|
|
520
|
+
)
|
|
521
|
+
}
|
|
522
|
+
return s / 2
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function getPointInsidePolygon(polygon) {
|
|
526
|
+
var point
|
|
527
|
+
var size = getSize(polygon)
|
|
528
|
+
var edges = getEdges(polygon)
|
|
529
|
+
var y = size.y.min + (size.y.max - size.y.min) / Math.PI
|
|
530
|
+
var dy = (size.y.max - size.y.min) / 13
|
|
531
|
+
var line = []
|
|
532
|
+
var points
|
|
533
|
+
var interPoints = []
|
|
534
|
+
var pointsOK = false
|
|
535
|
+
while (!pointsOK) {
|
|
536
|
+
line = [
|
|
537
|
+
{ x: size.x.min - 1, y: y },
|
|
538
|
+
{ x: size.x.max + 1, y: y }
|
|
539
|
+
]
|
|
540
|
+
//find intersections with all polygon edges
|
|
541
|
+
for (var i = 0; i < edges.length; i++) {
|
|
542
|
+
points = findEdgeIntersection(line, edges[i])
|
|
543
|
+
//if edge doesn't lie inside line
|
|
544
|
+
if (points && points.length === 1) {
|
|
545
|
+
interPoints.push(points[0])
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
interPoints = sortPoints(interPoints)
|
|
549
|
+
//find two correct interpoints
|
|
550
|
+
for (var i = 0; i < interPoints.length - 1; i++) {
|
|
551
|
+
if (interPoints[i].t !== interPoints[i + 1].t) {
|
|
552
|
+
//enable exit from loop and calculate point coordinates
|
|
553
|
+
pointsOK = true
|
|
554
|
+
point = { x: (interPoints[i].x + interPoints[i + 1].x) / 2, y: y }
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
//all points are incorrect, need to change line parameters
|
|
558
|
+
y = y + dy
|
|
559
|
+
if ((y > size.y.max || y < size.y.min) && pointsOK === false) {
|
|
560
|
+
pointsOK = true
|
|
561
|
+
point = undefined
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return point
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function getSize(polygon) {
|
|
568
|
+
var size = {
|
|
569
|
+
x: {
|
|
570
|
+
min: polygon[0].x,
|
|
571
|
+
max: polygon[0].x
|
|
572
|
+
},
|
|
573
|
+
y: {
|
|
574
|
+
min: polygon[0].y,
|
|
575
|
+
max: polygon[0].y
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
for (var i = 1; i < polygon.length; i++) {
|
|
579
|
+
if (polygon[i].x < size.x.min) size.x.min = polygon[i].x
|
|
580
|
+
if (polygon[i].x > size.x.max) size.x.max = polygon[i].x
|
|
581
|
+
if (polygon[i].y < size.y.min) size.y.min = polygon[i].y
|
|
582
|
+
if (polygon[i].y > size.y.max) size.y.max = polygon[i].y
|
|
583
|
+
}
|
|
584
|
+
return size
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
function findPointInsidePolygon(point, polygon) {
|
|
588
|
+
var cross = 0
|
|
589
|
+
var edges = getEdges(polygon)
|
|
590
|
+
var classify
|
|
591
|
+
var org, dest
|
|
592
|
+
for (var i = 0; i < edges.length; i++) {
|
|
593
|
+
;[org, dest] = edges[i]
|
|
594
|
+
classify = classifyPoint(point, [org, dest])
|
|
595
|
+
if (
|
|
596
|
+
(classify.loc === 'RIGHT' && org.y < point.y && dest.y >= point.y) ||
|
|
597
|
+
(classify.loc === 'LEFT' && org.y >= point.y && dest.y < point.y)
|
|
598
|
+
) {
|
|
599
|
+
cross++
|
|
600
|
+
}
|
|
601
|
+
if (classify.loc === 'BETWEEN') return false
|
|
602
|
+
}
|
|
603
|
+
if (cross % 2) {
|
|
604
|
+
return true
|
|
605
|
+
} else {
|
|
606
|
+
return false
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function getMidpoints(edges) {
|
|
611
|
+
var midpoints = []
|
|
612
|
+
var x, y
|
|
613
|
+
for (var i = 0; i < edges.length; i++) {
|
|
614
|
+
x = (edges[i][0].x + edges[i][1].x) / 2
|
|
615
|
+
y = (edges[i][0].y + edges[i][1].y) / 2
|
|
616
|
+
let classify = classifyPoint({ x: x, y: y }, edges[i])
|
|
617
|
+
if (classify.loc != 'BETWEEN') {
|
|
618
|
+
//console.error('Midpoint calculation error in intersect algo',edges)
|
|
619
|
+
}
|
|
620
|
+
midpoints.push({ x: x, y: y })
|
|
621
|
+
}
|
|
622
|
+
return midpoints
|
|
623
|
+
}
|
package/src/matrix.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export function inverse2x2Matrix([a, b, c, d]) {
|
|
2
|
+
//inverse matrix |a,c|
|
|
3
|
+
// |b,d|
|
|
4
|
+
const det = a * b - c * b
|
|
5
|
+
if (det == 0) {
|
|
6
|
+
return null
|
|
7
|
+
}
|
|
8
|
+
return [d / det, -b / det, -c / det, a / det]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function inverse3x3matrix(m) {
|
|
12
|
+
let [[a, b, c], [d, e, f], [g, h, i]] = m
|
|
13
|
+
let x = e * i - h * f
|
|
14
|
+
let y = f * g - d * i
|
|
15
|
+
let z = d * h - g * e
|
|
16
|
+
let det = a * x + b * y + c * z
|
|
17
|
+
return det != 0
|
|
18
|
+
? [
|
|
19
|
+
[x, c * h - b * i, b * f - c * e],
|
|
20
|
+
[y, a * i - c * g, d * c - a * f],
|
|
21
|
+
[z, g * b - a * h, a * e - d * b]
|
|
22
|
+
].map((r) => r.map((v) => (v /= det)))
|
|
23
|
+
: null
|
|
24
|
+
}
|
|
25
|
+
export function multiplyMatrices(a, b) {
|
|
26
|
+
if (!Array.isArray(a) || !Array.isArray(b) || !a.length || !b.length) {
|
|
27
|
+
throw new Error('arguments should be in 2-dimensional array format')
|
|
28
|
+
}
|
|
29
|
+
let x = a.length
|
|
30
|
+
let z = a[0].length
|
|
31
|
+
let y = b[0].length
|
|
32
|
+
if (b.length !== z) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
'number of columns in the first matrix should be the same as the number of rows in the second'
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
let productRow = Array.apply(null, new Array(y)).map(
|
|
38
|
+
Number.prototype.valueOf,
|
|
39
|
+
0
|
|
40
|
+
)
|
|
41
|
+
let product = new Array(x)
|
|
42
|
+
for (let p = 0; p < x; p++) {
|
|
43
|
+
product[p] = productRow.slice()
|
|
44
|
+
}
|
|
45
|
+
for (let i = 0; i < x; i++) {
|
|
46
|
+
for (let j = 0; j < y; j++) {
|
|
47
|
+
for (let k = 0; k < z; k++) {
|
|
48
|
+
product[i][j] += a[i][k] * b[k][j]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return product
|
|
53
|
+
}
|