dgeoutils 2.2.18 → 2.2.24

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 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.intersection(per, Infinity);
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.begin.distance(this.end) / 2;
225
- const dcosT = td * Math.cos(fi);
226
- const dsinT = td * Math.sin(fi);
227
- const p1T = new DPoint_1.DPoint(p.x - dsinT, p.y - dcosT);
228
- const p2T = new DPoint_1.DPoint(p.x + dsinT, p.y + dcosT);
229
- const dcos = d * Math.cos(fi);
230
- const dsin = d * Math.sin(fi);
231
- const p2 = new DPoint_1.DPoint(p.x + dsin, p.y + dcos);
232
- const p3 = new DPoint_1.DPoint(p.x - dsin, p.y + dcos);
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;
@@ -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;
@@ -50,6 +51,8 @@ export declare class DPolygon {
50
51
  get isClockwise(): boolean;
51
52
  get clockWise(): DPolygon;
52
53
  get noHoles(): DPolygon;
54
+ reduce<T>(f: (a: T, p: DPoint) => T, v: T): T;
55
+ reduce<T>(f: (a: T, p: DPoint, index: number) => T, v: T): T;
53
56
  intersection(l: DLine, includeOnly?: boolean): DPoint[];
54
57
  setCenter(newCenter: DPoint): DPolygon;
55
58
  static WKT_LINESTRING: string;
@@ -58,6 +61,8 @@ export declare class DPolygon {
58
61
  filter(f: (p: DPoint) => boolean): DPolygon;
59
62
  map(f: (r: DPoint) => DPoint): DPolygon;
60
63
  map(f: (r: DPoint, index: number) => DPoint): DPolygon;
64
+ mapArray<T>(f: (r: DPoint) => T): T[];
65
+ mapArray<T>(f: (r: DPoint, index: number) => T): T[];
61
66
  sort(f: (a: DPoint, b: DPoint) => number): DPolygon;
62
67
  at(index: number): DPoint;
63
68
  pop(): DPoint;
@@ -75,6 +80,8 @@ export declare class DPolygon {
75
80
  equal(p: DPolygon | null): boolean;
76
81
  same(p: DPolygon): boolean;
77
82
  findIndex(p: DPoint): number;
83
+ findIndex(f: (p: DPoint) => boolean): number;
84
+ findIndex(f: (p: DPoint, index: number) => boolean): number;
78
85
  approximation(e?: number): DPolygon;
79
86
  insertAfter(index: number, ...points: DPoint[]): void;
80
87
  removePart(index: number, count: number): DPoint[];
@@ -102,8 +109,11 @@ export declare class DPolygon {
102
109
  getTrianglesPointIndexes(): number[];
103
110
  get closed(): boolean;
104
111
  buffer(v: number, quadrantSegments?: number, type?: number): DPolygon;
112
+ sideBuffers(v: number, quadrantSegments?: number): [DPolygon, DPolygon];
105
113
  bezier(step?: number): DPolygon;
106
114
  setGrowingHeight(from: number, to: number): DPolygon;
115
+ loopPointsGenerator(): () => Generator<[DPoint, DPoint, undefined, number]>;
116
+ loopPointsGenerator(withLine: True): () => Generator<[DPoint, DPoint, DLine, number]>;
107
117
  private getBezierPoint;
108
118
  private simpleIncludeX;
109
119
  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;
@@ -100,16 +137,16 @@ class DPolygon {
100
137
  return this.pPoints;
101
138
  }
102
139
  get maxX() {
103
- return this.pPoints.reduce((a, r) => Math.max(a, r.x), -Infinity);
140
+ return this.reduce((a, r) => Math.max(a, r.x), -Infinity);
104
141
  }
105
142
  get minX() {
106
- return this.pPoints.reduce((a, r) => Math.min(a, r.x), Infinity);
143
+ return this.reduce((a, r) => Math.min(a, r.x), Infinity);
107
144
  }
108
145
  get maxY() {
109
- return this.pPoints.reduce((a, r) => Math.max(a, r.y), -Infinity);
146
+ return this.reduce((a, r) => Math.max(a, r.y), -Infinity);
110
147
  }
111
148
  get minY() {
112
- return this.pPoints.reduce((a, r) => Math.min(a, r.y), Infinity);
149
+ return this.reduce((a, r) => Math.min(a, r.y), Infinity);
113
150
  }
114
151
  get center() {
115
152
  return this.leftTop.move(this.size.divide(2));
@@ -156,24 +193,25 @@ class DPolygon {
156
193
  }
157
194
  get perimeter() {
158
195
  let p = 0;
159
- for (let i = 1; i < this.pPoints.length; i++) {
160
- p += this.pPoints[i - 1].distance(this.pPoints[i]);
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 (let i = 1; i < closed.length; i++) {
168
- const cur = closed.at(i);
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
- const p = this.clone().close();
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,23 @@ 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.reduce((a, e) => a && containCalculator(origin, e), true);
237
+ if (allInside && origin.isClockwise === part.isClockwise) {
238
+ origin.insertAfter(record[j - 1] - 1, ...part.reverse().points);
239
+ p = origin;
240
+ }
241
+ }
242
+ }
243
+ }
244
+ }
190
245
  return p;
191
246
  }
192
247
  get valid() {
@@ -205,19 +260,18 @@ class DPolygon {
205
260
  const p = this.convex;
206
261
  let resultPolygon = new DPolygon();
207
262
  let resultArea = Infinity;
208
- for (let k = 0; k < p.length - 1; k++) {
209
- const l = p.at(k).findLine(p.at(k + 1));
263
+ for (const [, , l] of p.loopPointsGenerator(true)()) {
210
264
  let maxWidth = 0;
211
265
  let maxWidthPoint1 = null;
212
266
  let maxWidthPoint2 = null;
213
267
  let maxHeight = 0;
214
268
  let maxHeightPoint = null;
215
- for (let i = 0; i < p.length - 1; i++) {
216
- const p1 = l.findPoint(l.findPerpendicular(p.at(i)));
217
- const h = p1.distance(p.at(i));
269
+ for (const [z, , , i] of p.loopPointsGenerator()()) {
270
+ const p1 = l.findPoint(l.findPerpendicular(z));
271
+ const h = p1.distance(z);
218
272
  if (h >= maxHeight) {
219
273
  maxHeight = h;
220
- maxHeightPoint = p.at(i);
274
+ maxHeightPoint = z;
221
275
  }
222
276
  for (let j = i; j < p.length - 1; j++) {
223
277
  const p2 = l.findPoint(l.findPerpendicular(p.at(j)));
@@ -290,11 +344,9 @@ class DPolygon {
290
344
  }
291
345
  get isClockwise() {
292
346
  let sum = 0;
293
- const p = this.clone().close();
294
- for (let i = 1; i < p.length; i++) {
295
- const p1 = p.at(i - 1);
296
- const p2 = p.at(i);
297
- sum += (p2.x - p1.x) * (p2.y + p1.y);
347
+ for (const [{ x, y }, { x: a, y: b }] of this.clone().close()
348
+ .loopPointsGenerator()()) {
349
+ sum += (a - x) * (b + y);
298
350
  }
299
351
  return sum < 0;
300
352
  }
@@ -309,12 +361,12 @@ class DPolygon {
309
361
  res.holes = [];
310
362
  return res;
311
363
  }
364
+ reduce(f, v) {
365
+ return this.pPoints.reduce(f, v);
366
+ }
312
367
  intersection(l, includeOnly = false) {
313
368
  const res = [];
314
- for (let i = 0; i < this.pPoints.length - 1; i++) {
315
- const p1 = this.pPoints[i];
316
- const p2 = this.pPoints[i + 1];
317
- const line = p1.findLine(p2);
369
+ for (const [, , line] of this.loopPointsGenerator(true)()) {
318
370
  const intersect = line.intersection(l, 0, includeOnly);
319
371
  if (intersect) {
320
372
  res.push(intersect);
@@ -334,10 +386,10 @@ class DPolygon {
334
386
  h = `, ${this.holes.map((hole) => hole.toString())
335
387
  .join(', ')}`;
336
388
  }
337
- return `POLYGON ((${this.deintersection.pPoints.map((r) => `${r.x} ${r.y}${withZ ? ` ${r.z}` : ''}`)
389
+ return `POLYGON ((${this.deintersection.mapArray((r) => `${r.x} ${r.y}${withZ ? ` ${r.z}` : ''}`)
338
390
  .join(', ')})${h})`;
339
391
  }
340
- return `LINESTRING (${this.pPoints.map((r) => `${r.x} ${r.y}${withZ ? ` ${r.z}` : ''}`)
392
+ return `LINESTRING (${this.mapArray((r) => `${r.x} ${r.y}${withZ ? ` ${r.z}` : ''}`)
341
393
  .join(', ')})`;
342
394
  }
343
395
  filter(f) {
@@ -345,10 +397,13 @@ class DPolygon {
345
397
  return this;
346
398
  }
347
399
  map(f) {
348
- this.pPoints = this.pPoints.map(f);
400
+ this.pPoints = this.mapArray(f);
349
401
  this.holes = this.holes.map((h) => h.map(f));
350
402
  return this;
351
403
  }
404
+ mapArray(f) {
405
+ return this.pPoints.map(f);
406
+ }
352
407
  sort(f) {
353
408
  this.points.sort(f);
354
409
  return this;
@@ -379,7 +434,7 @@ class DPolygon {
379
434
  .reduce((a, h) => a + h.getValue(), ''));
380
435
  }
381
436
  toString() {
382
- return `(${this.pPoints.map((r) => r.toString()).join(', ')})`;
437
+ return `(${this.mapArray((r) => r.toString()).join(', ')})`;
383
438
  }
384
439
  close() {
385
440
  const p0 = this.first;
@@ -433,8 +488,11 @@ class DPolygon {
433
488
  }
434
489
  return false;
435
490
  }
436
- findIndex(p) {
437
- return this.points.findIndex((t) => t.equal(p));
491
+ findIndex(a) {
492
+ if (a instanceof DPoint_1.DPoint) {
493
+ return this.points.findIndex((t) => t.equal(a));
494
+ }
495
+ return this.points.findIndex(a);
438
496
  }
439
497
  approximation(e = Math.sqrt(this.perimeter) * APPROXIMATION_VALUE) {
440
498
  return new DPolygon(this.clone().douglasPeucker(this.pPoints, e));
@@ -508,11 +566,9 @@ class DPolygon {
508
566
  }
509
567
  const poly = this.deintersection;
510
568
  let totalFi = 0;
511
- for (let i = 0; i < poly.length - 1; i++) {
512
- const p1 = poly.at(i);
513
- const p2 = poly.at(i + 1);
514
- const line1 = new DLine_1.DLine(p1.x - p.x, p1.y - p.y, 0);
515
- const line2 = new DLine_1.DLine(p2.x - p.x, p2.y - p.y, 0);
569
+ for (const [{ x, y }, { x: a, y: b }] of poly.loopPointsGenerator()()) {
570
+ const line1 = new DLine_1.DLine(x - p.x, y - p.y, 0);
571
+ const line2 = new DLine_1.DLine(a - p.x, b - p.y, 0);
516
572
  const fiDif = line1.findFi(line2);
517
573
  if (line1.vectorProduct(line2).c > 0) {
518
574
  totalFi += fiDif;
@@ -522,18 +578,14 @@ class DPolygon {
522
578
  }
523
579
  }
524
580
  const eps = Math.PI / 10000;
525
- let result = false;
526
581
  const absTotalFi = Math.abs(totalFi);
527
582
  if (absTotalFi < eps) {
528
- result = false;
583
+ return false;
529
584
  }
530
585
  else if (Math.abs(2 * Math.PI - absTotalFi) < eps) {
531
- result = true;
532
- }
533
- else {
534
- throw new Error('contains2 faild');
586
+ return true;
535
587
  }
536
- return result;
588
+ throw new Error('contains2 faild');
537
589
  }
538
590
  onBorder(p) {
539
591
  const simpleInclude = this.simpleInclude(p);
@@ -543,10 +595,7 @@ class DPolygon {
543
595
  if (hasSamePoint) {
544
596
  return true;
545
597
  }
546
- for (let i = 0; i < poly.length - 1; i++) {
547
- const p0 = poly.at(i);
548
- const p1 = poly.at(i + 1);
549
- const polygonLine = p0.findLine(p1);
598
+ for (const [, , polygonLine] of poly.loopPointsGenerator(true)()) {
550
599
  const onBorder = polygonLine.x(p).equal(p) && polygonLine.inRange(p);
551
600
  if (onBorder) {
552
601
  return true;
@@ -576,21 +625,19 @@ class DPolygon {
576
625
  return new DPolygon(a.map((r) => DPoint_1.DPoint.parse(r)));
577
626
  }
578
627
  toArrayOfCoords() {
579
- return this.pPoints.map((r) => r.toCoords());
628
+ return this.mapArray((r) => r.toCoords());
580
629
  }
581
630
  divideToPieces(piecesCount) {
582
631
  const { fullLength } = this;
583
632
  const pieceLength = fullLength / piecesCount;
584
633
  let currentPieceLength = pieceLength;
585
- for (let i = 0; i < this.pPoints.length - 1; i++) {
586
- const p1 = this.pPoints[i];
587
- const p2 = this.pPoints[i + 1];
588
- if (p1.distance(p2) === currentPieceLength) {
634
+ for (const [p1, p2, , i] of this.loopPointsGenerator()()) {
635
+ const d = p1.distance(p2);
636
+ if (d === currentPieceLength) {
589
637
  p2.properties.pieceBorder = true;
590
638
  currentPieceLength = pieceLength;
591
- continue;
592
639
  }
593
- if (p1.distance(p2) - currentPieceLength > 0) {
640
+ else if (d - currentPieceLength > 0) {
594
641
  const circle = new DCircle_1.DCircle(p1, currentPieceLength);
595
642
  const line = p1.findLine(p2);
596
643
  const intersectionPoint = line.intersectionWithCircle(circle)
@@ -598,10 +645,9 @@ class DPolygon {
598
645
  intersectionPoint.properties.pieceBorder = true;
599
646
  this.insertAfter(i, intersectionPoint);
600
647
  currentPieceLength = pieceLength;
601
- continue;
602
648
  }
603
- if (p1.distance(p2) - currentPieceLength < 0) {
604
- currentPieceLength -= p1.distance(p2);
649
+ else {
650
+ currentPieceLength -= d;
605
651
  }
606
652
  }
607
653
  return this;
@@ -812,6 +858,17 @@ class DPolygon {
812
858
  .getCoordinates();
813
859
  return new DPolygon(points.map(({ x, y }) => new DPoint_1.DPoint(x, y)));
814
860
  }
861
+ sideBuffers(v, quadrantSegments = 64) {
862
+ const { first, last } = this;
863
+ const buffer = this.buffer(v, quadrantSegments, DPolygon.CAP_FLAT).open();
864
+ const [start0, start1] = first.sortByDistance(buffer).points.map((r) => r.properties.index);
865
+ const [end0, end1] = last.sortByDistance(buffer).points.map((r) => r.properties.index);
866
+ const fromPoint = Math.min(Math.max(start0, start1), Math.max(end0, end1));
867
+ const toPoint = Math.max(Math.min(start0, start1), Math.min(end0, end1));
868
+ const linePart = new DPolygon(buffer.removePart(fromPoint - 1, toPoint - fromPoint + 1));
869
+ buffer.unshift(buffer.pop());
870
+ return [linePart, buffer];
871
+ }
815
872
  bezier(step = 0.1) {
816
873
  const res = new DPolygon();
817
874
  for (let i = 0; i < 1; i += step) {
@@ -833,13 +890,21 @@ class DPolygon {
833
890
  .run();
834
891
  return this;
835
892
  }
893
+ loopPointsGenerator(withLine = false) {
894
+ const that = this;
895
+ return function* () {
896
+ for (let i = 0; i < that.length - 1; i++) {
897
+ const p1 = that.at(i);
898
+ const p2 = that.at(i + 1);
899
+ yield [p1, p2, withLine ? p1.findLine(p2) : undefined, i];
900
+ }
901
+ };
902
+ }
836
903
  getBezierPoint(v) {
837
904
  if (this.length === 1) {
838
905
  return this.first;
839
906
  }
840
- for (let i = 0; i < this.length - 1; i++) {
841
- const p1 = this.at(i);
842
- const p2 = this.at(i + 1);
907
+ for (const [p1, p2] of this.loopPointsGenerator()()) {
843
908
  p1.move(p2.clone().move(p1.clone().minus())
844
909
  .scale(v));
845
910
  }
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.18",
3
+ "version": "2.2.24",
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.21.9",
48
+ "typedoc": "^0.22.11",
49
49
  "typescript": "^4.4.3"
50
50
  },
51
51
  "jest": {