dgeoutils 2.2.17 → 2.2.23
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/dist/DLine.js +11 -14
- package/dist/DPoint.d.ts +1 -1
- package/dist/DPoint.js +9 -11
- package/dist/DPolygon.d.ts +5 -0
- package/dist/DPolygon.js +112 -51
- package/dist/utils.d.ts +1 -1
- package/package.json +2 -2
package/dist/DLine.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DLine = void 0;
|
|
4
4
|
const DPoint_1 = require("./DPoint");
|
|
5
5
|
const utils_1 = require("./utils");
|
|
6
|
+
const DNumbers_1 = require("./DNumbers");
|
|
6
7
|
class DLine {
|
|
7
8
|
constructor(a, b, c, begin = DPoint_1.DPoint.zero(), end = DPoint_1.DPoint.zero()) {
|
|
8
9
|
this.a = a;
|
|
@@ -49,7 +50,7 @@ class DLine {
|
|
|
49
50
|
intersectionWithCircle(circle) {
|
|
50
51
|
const { center, r } = circle;
|
|
51
52
|
const per = this.findPerpendicular(center);
|
|
52
|
-
const t = this.
|
|
53
|
+
const t = this.findPoint(per);
|
|
53
54
|
let distance = t.distance(center);
|
|
54
55
|
if (this.begin.equal(center)) {
|
|
55
56
|
distance = 0;
|
|
@@ -221,19 +222,15 @@ class DLine {
|
|
|
221
222
|
}
|
|
222
223
|
movePoint(p, d) {
|
|
223
224
|
const fi = this.findFi(new DLine(1, 0, 0));
|
|
224
|
-
const td = this.
|
|
225
|
-
const
|
|
226
|
-
const
|
|
227
|
-
const p1T =
|
|
228
|
-
const p2T =
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (this.inRange(p1T) || this.inRange(p2T)) {
|
|
234
|
-
return p2;
|
|
235
|
-
}
|
|
236
|
-
return p3;
|
|
225
|
+
const td = this.x(new DPoint_1.DPoint(1, 1)).distance(this.x(new DPoint_1.DPoint(2, 2))) / 2;
|
|
226
|
+
const sinCos = new DPoint_1.DPoint(Math.sin(fi), Math.cos(fi));
|
|
227
|
+
const dt = sinCos.clone().scale(td);
|
|
228
|
+
const p1T = p.clone().move(dt.clone().minus());
|
|
229
|
+
const p2T = p.clone().move(dt);
|
|
230
|
+
if (DNumbers_1.DNumbers.like(this.y(p1T).y, p1T.y) || DNumbers_1.DNumbers.like(this.y(p2T).y, p2T.y)) {
|
|
231
|
+
return p.clone().move(sinCos.scale(d));
|
|
232
|
+
}
|
|
233
|
+
return p.clone().move(sinCos.scale(d).setX(({ x }) => -x));
|
|
237
234
|
}
|
|
238
235
|
findFi({ a, b }, delta = 1.0001) {
|
|
239
236
|
const { a: q, b: w } = this;
|
package/dist/DPoint.d.ts
CHANGED
package/dist/DPoint.js
CHANGED
|
@@ -462,17 +462,15 @@ class DPoint {
|
|
|
462
462
|
return new DPoint(x, y).radiansToDegrees();
|
|
463
463
|
}));
|
|
464
464
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
}
|
|
475
|
-
return res;
|
|
465
|
+
sortByDistance(p) {
|
|
466
|
+
return p
|
|
467
|
+
.clone()
|
|
468
|
+
.map((d, index) => {
|
|
469
|
+
d.properties.distance = d.distance(this);
|
|
470
|
+
d.properties.index = index;
|
|
471
|
+
return d;
|
|
472
|
+
})
|
|
473
|
+
.sort((a, b) => a.properties.distance - b.properties.distance);
|
|
476
474
|
}
|
|
477
475
|
}
|
|
478
476
|
exports.DPoint = DPoint;
|
package/dist/DPolygon.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { DCoord, DPoint, LatLng } from './DPoint';
|
|
3
3
|
import { DLine } from './DLine';
|
|
4
4
|
import { DPolygonLoop } from './DPolygonLoop';
|
|
5
|
+
import { True } from './utils';
|
|
5
6
|
export declare const MIN_POINTS_IN_VALID_POLYGON = 3;
|
|
6
7
|
export declare class DPolygon {
|
|
7
8
|
private pPoints;
|
|
@@ -58,6 +59,7 @@ export declare class DPolygon {
|
|
|
58
59
|
filter(f: (p: DPoint) => boolean): DPolygon;
|
|
59
60
|
map(f: (r: DPoint) => DPoint): DPolygon;
|
|
60
61
|
map(f: (r: DPoint, index: number) => DPoint): DPolygon;
|
|
62
|
+
sort(f: (a: DPoint, b: DPoint) => number): DPolygon;
|
|
61
63
|
at(index: number): DPoint;
|
|
62
64
|
pop(): DPoint;
|
|
63
65
|
push(...args: DPoint[]): number;
|
|
@@ -101,8 +103,11 @@ export declare class DPolygon {
|
|
|
101
103
|
getTrianglesPointIndexes(): number[];
|
|
102
104
|
get closed(): boolean;
|
|
103
105
|
buffer(v: number, quadrantSegments?: number, type?: number): DPolygon;
|
|
106
|
+
sideBuffers(v: number, quadrantSegments?: number): [DPolygon, DPolygon];
|
|
104
107
|
bezier(step?: number): DPolygon;
|
|
105
108
|
setGrowingHeight(from: number, to: number): DPolygon;
|
|
109
|
+
loopPointsGenerator(): () => Generator<[DPoint, DPoint, undefined, number]>;
|
|
110
|
+
loopPointsGenerator(withLine: True): () => Generator<[DPoint, DPoint, DLine, number]>;
|
|
106
111
|
private getBezierPoint;
|
|
107
112
|
private simpleIncludeX;
|
|
108
113
|
private simpleIncludeY;
|
package/dist/DPolygon.js
CHANGED
|
@@ -13,6 +13,43 @@ exports.MIN_POINTS_IN_VALID_POLYGON = 3;
|
|
|
13
13
|
const APPROXIMATION_VALUE = 0.1;
|
|
14
14
|
const MAX_CONVEX_ITERATIONS = 100;
|
|
15
15
|
const CLOSE_TO_INTERSECTION_DISTANCE = 0.001;
|
|
16
|
+
const containCalculator = (poly, p) => {
|
|
17
|
+
const hasSamePoint = poly.points.some((point) => point.equal(p));
|
|
18
|
+
if (hasSamePoint) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
for (const [, , polygonLine] of poly.loopPointsGenerator(true)()) {
|
|
22
|
+
const onBorder = polygonLine.x(p).equal(p) && polygonLine.inRange(p);
|
|
23
|
+
if (onBorder) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
let totalFi = 0;
|
|
28
|
+
for (const [{ x, y }, { x: a, y: b }] of poly.loopPointsGenerator()()) {
|
|
29
|
+
const line1 = new DLine_1.DLine(x - p.x, y - p.y, 0);
|
|
30
|
+
const line2 = new DLine_1.DLine(a - p.x, b - p.y, 0);
|
|
31
|
+
const fiDif = line1.findFi(line2);
|
|
32
|
+
if (line1.vectorProduct(line2).c > 0) {
|
|
33
|
+
totalFi += fiDif;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
totalFi -= fiDif;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const eps = Math.PI / 10000;
|
|
40
|
+
let result = false;
|
|
41
|
+
const absTotalFi = Math.abs(totalFi);
|
|
42
|
+
if (absTotalFi < eps) {
|
|
43
|
+
result = false;
|
|
44
|
+
}
|
|
45
|
+
else if (Math.abs(2 * Math.PI - absTotalFi) < eps) {
|
|
46
|
+
result = true;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
throw new Error('contains2 faild');
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
};
|
|
16
53
|
class DPolygon {
|
|
17
54
|
constructor(pPoints = []) {
|
|
18
55
|
this.pPoints = pPoints;
|
|
@@ -156,24 +193,25 @@ class DPolygon {
|
|
|
156
193
|
}
|
|
157
194
|
get perimeter() {
|
|
158
195
|
let p = 0;
|
|
159
|
-
for (
|
|
160
|
-
p +=
|
|
196
|
+
for (const [p1, p2] of this.loopPointsGenerator()()) {
|
|
197
|
+
p += p1.distance(p2);
|
|
161
198
|
}
|
|
162
199
|
return p;
|
|
163
200
|
}
|
|
164
201
|
get area() {
|
|
165
|
-
const closed = this.deintersection;
|
|
166
202
|
let sum = 0;
|
|
167
|
-
for (
|
|
168
|
-
|
|
169
|
-
const prev = closed.at(i - 1);
|
|
170
|
-
sum += prev.x * cur.y - prev.y * cur.x;
|
|
203
|
+
for (const [{ x, y }, { x: a, y: b }] of this.deintersection.loopPointsGenerator()()) {
|
|
204
|
+
sum += x * b - y * a;
|
|
171
205
|
}
|
|
172
206
|
return Math.abs(sum / 2) - this.holes.reduce((a, hole) => a + hole.area, 0);
|
|
173
207
|
}
|
|
174
208
|
get deintersection() {
|
|
175
|
-
|
|
209
|
+
let p = this.clone().close();
|
|
210
|
+
const store = {};
|
|
176
211
|
for (let i = 0; i < p.length - 1; i++) {
|
|
212
|
+
const k = p.at(i).toString();
|
|
213
|
+
store[k] = store[k] || [];
|
|
214
|
+
store[k].push(i);
|
|
177
215
|
for (let j = i + 2; j < p.length - 1; j++) {
|
|
178
216
|
const firstLine = p.at(i).findLine(p.at(i + 1));
|
|
179
217
|
const secondLine = p.at(j).findLine(p.at(j + 1));
|
|
@@ -187,6 +225,24 @@ class DPolygon {
|
|
|
187
225
|
}
|
|
188
226
|
}
|
|
189
227
|
}
|
|
228
|
+
for (const key of Object.keys(store)) {
|
|
229
|
+
const record = store[key];
|
|
230
|
+
if (record.length > 1) {
|
|
231
|
+
for (let j = record.length - 1; j > 0; j--) {
|
|
232
|
+
const origin = p.clone();
|
|
233
|
+
const d = record[j] - record[j - 1];
|
|
234
|
+
if (d > 1) {
|
|
235
|
+
const part = new DPolygon(origin.removePart(record[j - 1], d));
|
|
236
|
+
const allInside = part.points
|
|
237
|
+
.reduce((a, e) => a && containCalculator(origin, e), true);
|
|
238
|
+
if (allInside && origin.isClockwise === part.isClockwise) {
|
|
239
|
+
origin.insertAfter(record[j - 1] - 1, ...part.reverse().points);
|
|
240
|
+
p = origin;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
190
246
|
return p;
|
|
191
247
|
}
|
|
192
248
|
get valid() {
|
|
@@ -205,19 +261,18 @@ class DPolygon {
|
|
|
205
261
|
const p = this.convex;
|
|
206
262
|
let resultPolygon = new DPolygon();
|
|
207
263
|
let resultArea = Infinity;
|
|
208
|
-
for (
|
|
209
|
-
const l = p.at(k).findLine(p.at(k + 1));
|
|
264
|
+
for (const [, , l] of p.loopPointsGenerator(true)()) {
|
|
210
265
|
let maxWidth = 0;
|
|
211
266
|
let maxWidthPoint1 = null;
|
|
212
267
|
let maxWidthPoint2 = null;
|
|
213
268
|
let maxHeight = 0;
|
|
214
269
|
let maxHeightPoint = null;
|
|
215
|
-
for (
|
|
216
|
-
const p1 = l.findPoint(l.findPerpendicular(
|
|
217
|
-
const h = p1.distance(
|
|
270
|
+
for (const [z, , , i] of p.loopPointsGenerator()()) {
|
|
271
|
+
const p1 = l.findPoint(l.findPerpendicular(z));
|
|
272
|
+
const h = p1.distance(z);
|
|
218
273
|
if (h >= maxHeight) {
|
|
219
274
|
maxHeight = h;
|
|
220
|
-
maxHeightPoint =
|
|
275
|
+
maxHeightPoint = z;
|
|
221
276
|
}
|
|
222
277
|
for (let j = i; j < p.length - 1; j++) {
|
|
223
278
|
const p2 = l.findPoint(l.findPerpendicular(p.at(j)));
|
|
@@ -290,11 +345,9 @@ class DPolygon {
|
|
|
290
345
|
}
|
|
291
346
|
get isClockwise() {
|
|
292
347
|
let sum = 0;
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
const p2 = p.at(i);
|
|
297
|
-
sum += (p2.x - p1.x) * (p2.y + p1.y);
|
|
348
|
+
for (const [{ x, y }, { x: a, y: b }] of this.clone().close()
|
|
349
|
+
.loopPointsGenerator()()) {
|
|
350
|
+
sum += (a - x) * (b + y);
|
|
298
351
|
}
|
|
299
352
|
return sum < 0;
|
|
300
353
|
}
|
|
@@ -311,10 +364,7 @@ class DPolygon {
|
|
|
311
364
|
}
|
|
312
365
|
intersection(l, includeOnly = false) {
|
|
313
366
|
const res = [];
|
|
314
|
-
for (
|
|
315
|
-
const p1 = this.pPoints[i];
|
|
316
|
-
const p2 = this.pPoints[i + 1];
|
|
317
|
-
const line = p1.findLine(p2);
|
|
367
|
+
for (const [, , line] of this.loopPointsGenerator(true)()) {
|
|
318
368
|
const intersect = line.intersection(l, 0, includeOnly);
|
|
319
369
|
if (intersect) {
|
|
320
370
|
res.push(intersect);
|
|
@@ -349,6 +399,10 @@ class DPolygon {
|
|
|
349
399
|
this.holes = this.holes.map((h) => h.map(f));
|
|
350
400
|
return this;
|
|
351
401
|
}
|
|
402
|
+
sort(f) {
|
|
403
|
+
this.points.sort(f);
|
|
404
|
+
return this;
|
|
405
|
+
}
|
|
352
406
|
at(index) {
|
|
353
407
|
const { length } = this;
|
|
354
408
|
return this.points[(index % length + length) % length];
|
|
@@ -504,11 +558,9 @@ class DPolygon {
|
|
|
504
558
|
}
|
|
505
559
|
const poly = this.deintersection;
|
|
506
560
|
let totalFi = 0;
|
|
507
|
-
for (
|
|
508
|
-
const
|
|
509
|
-
const
|
|
510
|
-
const line1 = new DLine_1.DLine(p1.x - p.x, p1.y - p.y, 0);
|
|
511
|
-
const line2 = new DLine_1.DLine(p2.x - p.x, p2.y - p.y, 0);
|
|
561
|
+
for (const [{ x, y }, { x: a, y: b }] of poly.loopPointsGenerator()()) {
|
|
562
|
+
const line1 = new DLine_1.DLine(x - p.x, y - p.y, 0);
|
|
563
|
+
const line2 = new DLine_1.DLine(a - p.x, b - p.y, 0);
|
|
512
564
|
const fiDif = line1.findFi(line2);
|
|
513
565
|
if (line1.vectorProduct(line2).c > 0) {
|
|
514
566
|
totalFi += fiDif;
|
|
@@ -518,18 +570,14 @@ class DPolygon {
|
|
|
518
570
|
}
|
|
519
571
|
}
|
|
520
572
|
const eps = Math.PI / 10000;
|
|
521
|
-
let result = false;
|
|
522
573
|
const absTotalFi = Math.abs(totalFi);
|
|
523
574
|
if (absTotalFi < eps) {
|
|
524
|
-
|
|
575
|
+
return false;
|
|
525
576
|
}
|
|
526
577
|
else if (Math.abs(2 * Math.PI - absTotalFi) < eps) {
|
|
527
|
-
|
|
528
|
-
}
|
|
529
|
-
else {
|
|
530
|
-
throw new Error('contains2 faild');
|
|
578
|
+
return true;
|
|
531
579
|
}
|
|
532
|
-
|
|
580
|
+
throw new Error('contains2 faild');
|
|
533
581
|
}
|
|
534
582
|
onBorder(p) {
|
|
535
583
|
const simpleInclude = this.simpleInclude(p);
|
|
@@ -539,10 +587,7 @@ class DPolygon {
|
|
|
539
587
|
if (hasSamePoint) {
|
|
540
588
|
return true;
|
|
541
589
|
}
|
|
542
|
-
for (
|
|
543
|
-
const p0 = poly.at(i);
|
|
544
|
-
const p1 = poly.at(i + 1);
|
|
545
|
-
const polygonLine = p0.findLine(p1);
|
|
590
|
+
for (const [, , polygonLine] of poly.loopPointsGenerator(true)()) {
|
|
546
591
|
const onBorder = polygonLine.x(p).equal(p) && polygonLine.inRange(p);
|
|
547
592
|
if (onBorder) {
|
|
548
593
|
return true;
|
|
@@ -578,15 +623,13 @@ class DPolygon {
|
|
|
578
623
|
const { fullLength } = this;
|
|
579
624
|
const pieceLength = fullLength / piecesCount;
|
|
580
625
|
let currentPieceLength = pieceLength;
|
|
581
|
-
for (
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
if (p1.distance(p2) === currentPieceLength) {
|
|
626
|
+
for (const [p1, p2, , i] of this.loopPointsGenerator()()) {
|
|
627
|
+
const d = p1.distance(p2);
|
|
628
|
+
if (d === currentPieceLength) {
|
|
585
629
|
p2.properties.pieceBorder = true;
|
|
586
630
|
currentPieceLength = pieceLength;
|
|
587
|
-
continue;
|
|
588
631
|
}
|
|
589
|
-
if (
|
|
632
|
+
else if (d - currentPieceLength > 0) {
|
|
590
633
|
const circle = new DCircle_1.DCircle(p1, currentPieceLength);
|
|
591
634
|
const line = p1.findLine(p2);
|
|
592
635
|
const intersectionPoint = line.intersectionWithCircle(circle)
|
|
@@ -594,10 +637,9 @@ class DPolygon {
|
|
|
594
637
|
intersectionPoint.properties.pieceBorder = true;
|
|
595
638
|
this.insertAfter(i, intersectionPoint);
|
|
596
639
|
currentPieceLength = pieceLength;
|
|
597
|
-
continue;
|
|
598
640
|
}
|
|
599
|
-
|
|
600
|
-
currentPieceLength -=
|
|
641
|
+
else {
|
|
642
|
+
currentPieceLength -= d;
|
|
601
643
|
}
|
|
602
644
|
}
|
|
603
645
|
return this;
|
|
@@ -808,6 +850,17 @@ class DPolygon {
|
|
|
808
850
|
.getCoordinates();
|
|
809
851
|
return new DPolygon(points.map(({ x, y }) => new DPoint_1.DPoint(x, y)));
|
|
810
852
|
}
|
|
853
|
+
sideBuffers(v, quadrantSegments = 64) {
|
|
854
|
+
const { first, last } = this;
|
|
855
|
+
const buffer = this.buffer(v, quadrantSegments, DPolygon.CAP_FLAT).open();
|
|
856
|
+
const [start0, start1] = first.sortByDistance(buffer).points.map((r) => r.properties.index);
|
|
857
|
+
const [end0, end1] = last.sortByDistance(buffer).points.map((r) => r.properties.index);
|
|
858
|
+
const fromPoint = Math.min(Math.max(start0, start1), Math.max(end0, end1));
|
|
859
|
+
const toPoint = Math.max(Math.min(start0, start1), Math.min(end0, end1));
|
|
860
|
+
const linePart = new DPolygon(buffer.removePart(fromPoint - 1, toPoint - fromPoint + 1));
|
|
861
|
+
buffer.unshift(buffer.pop());
|
|
862
|
+
return [linePart, buffer];
|
|
863
|
+
}
|
|
811
864
|
bezier(step = 0.1) {
|
|
812
865
|
const res = new DPolygon();
|
|
813
866
|
for (let i = 0; i < 1; i += step) {
|
|
@@ -829,13 +882,21 @@ class DPolygon {
|
|
|
829
882
|
.run();
|
|
830
883
|
return this;
|
|
831
884
|
}
|
|
885
|
+
loopPointsGenerator(withLine = false) {
|
|
886
|
+
const that = this;
|
|
887
|
+
return function* () {
|
|
888
|
+
for (let i = 0; i < that.length - 1; i++) {
|
|
889
|
+
const p1 = that.at(i);
|
|
890
|
+
const p2 = that.at(i + 1);
|
|
891
|
+
yield [p1, p2, withLine ? p1.findLine(p2) : undefined, i];
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
}
|
|
832
895
|
getBezierPoint(v) {
|
|
833
896
|
if (this.length === 1) {
|
|
834
897
|
return this.first;
|
|
835
898
|
}
|
|
836
|
-
for (
|
|
837
|
-
const p1 = this.at(i);
|
|
838
|
-
const p2 = this.at(i + 1);
|
|
899
|
+
for (const [p1, p2] of this.loopPointsGenerator()()) {
|
|
839
900
|
p1.move(p2.clone().move(p1.clone().minus())
|
|
840
901
|
.scale(v));
|
|
841
902
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export declare const gaussianElimination: {
|
|
|
22
22
|
(matrix: number[][]): number[];
|
|
23
23
|
MIN: number;
|
|
24
24
|
};
|
|
25
|
-
declare type True = true;
|
|
25
|
+
export declare type True = true;
|
|
26
26
|
export declare const createCanvas: {
|
|
27
27
|
(size: number): [HTMLCanvasElement, CanvasRenderingContext2D];
|
|
28
28
|
(size: number, offscreen: True): [OffscreenCanvas, OffscreenCanvasRenderingContext2D];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dgeoutils",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.23",
|
|
4
4
|
"description": "",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "node_modules/.bin/tsc",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"jest-html-reporter": "^3.4.2",
|
|
46
46
|
"jsdom": "^17.0.0",
|
|
47
47
|
"ts-jest": "^27.0.4",
|
|
48
|
-
"typedoc": "^0.
|
|
48
|
+
"typedoc": "^0.22.11",
|
|
49
49
|
"typescript": "^4.4.3"
|
|
50
50
|
},
|
|
51
51
|
"jest": {
|