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 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;
package/dist/DPoint.d.ts CHANGED
@@ -102,5 +102,5 @@ export declare class DPoint {
102
102
  setIfLessThan(p: DPoint): DPoint;
103
103
  minus(): DPoint;
104
104
  orthodromicPath(point: DPoint, pointsCount?: number): DPolygon;
105
- findCloserPoint(p: DPolygon): DPoint;
105
+ sortByDistance(p: DPolygon): DPolygon;
106
106
  }
package/dist/DPoint.js CHANGED
@@ -462,17 +462,15 @@ class DPoint {
462
462
  return new DPoint(x, y).radiansToDegrees();
463
463
  }));
464
464
  }
465
- findCloserPoint(p) {
466
- let d = Infinity;
467
- let res = DPoint.zero();
468
- for (const t of p.points) {
469
- const td = this.distance(t);
470
- if (td < d) {
471
- d = td;
472
- res = t.clone();
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;
@@ -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 (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,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 (let k = 0; k < p.length - 1; k++) {
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 (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));
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 = p.at(i);
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 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);
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 (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);
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 (let i = 0; i < poly.length - 1; i++) {
508
- const p1 = poly.at(i);
509
- const p2 = poly.at(i + 1);
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
- result = false;
575
+ return false;
525
576
  }
526
577
  else if (Math.abs(2 * Math.PI - absTotalFi) < eps) {
527
- result = true;
528
- }
529
- else {
530
- throw new Error('contains2 faild');
578
+ return true;
531
579
  }
532
- return result;
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 (let i = 0; i < poly.length - 1; i++) {
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 (let i = 0; i < this.pPoints.length - 1; i++) {
582
- const p1 = this.pPoints[i];
583
- const p2 = this.pPoints[i + 1];
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 (p1.distance(p2) - currentPieceLength > 0) {
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
- if (p1.distance(p2) - currentPieceLength < 0) {
600
- currentPieceLength -= p1.distance(p2);
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 (let i = 0; i < this.length - 1; i++) {
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.17",
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.21.9",
48
+ "typedoc": "^0.22.11",
49
49
  "typescript": "^4.4.3"
50
50
  },
51
51
  "jest": {