dgeoutils 2.1.0 → 2.2.3

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/DPolygon.js CHANGED
@@ -13,13 +13,13 @@ const APPROXIMATION_VALUE = 0.1;
13
13
  const MAX_CONVEX_ITERATIONS = 100;
14
14
  const CLOSE_TO_INTERSECTION_DISTANCE = 0.001;
15
15
  class DPolygon {
16
- constructor(points = []) {
16
+ // eslint-disable-next-line no-useless-constructor,no-empty-function
17
+ constructor(pPoints = []) {
18
+ this.pPoints = pPoints;
17
19
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
20
  this.properties = {};
19
21
  this.holes = [];
20
- this.pPoints = [];
21
22
  this.searchStore = {};
22
- this.pPoints = points;
23
23
  }
24
24
  /**
25
25
  * Get size of min area rectangle.
@@ -93,7 +93,7 @@ class DPolygon {
93
93
  return res;
94
94
  }
95
95
  static createSquareBySize(size) {
96
- return new DPolygon([DPoint_1.DPoint.Zero(), size.clone().setX(0), size.clone(), size.clone().setY(0)]).close();
96
+ return new DPolygon([DPoint_1.DPoint.zero(), size.clone().setX(0), size.clone(), size.clone().setY(0)]).close();
97
97
  }
98
98
  loop() {
99
99
  return new DPolygonLoop_1.DPolygonLoop(this);
@@ -209,8 +209,8 @@ class DPolygon {
209
209
  const closed = this.deintersection;
210
210
  let sum = 0;
211
211
  for (let i = 1; i < closed.length; i++) {
212
- const cur = closed.p(i);
213
- const prev = closed.p(i - 1);
212
+ const cur = closed.at(i);
213
+ const prev = closed.at(i - 1);
214
214
  sum += prev.x * cur.y - prev.y * cur.x;
215
215
  }
216
216
  return Math.abs(sum / 2) - this.holes.reduce((a, hole) => a + hole.area, 0);
@@ -222,8 +222,8 @@ class DPolygon {
222
222
  const p = this.clone().close();
223
223
  for (let i = 0; i < p.length - 1; i++) {
224
224
  for (let j = i + 2; j < p.length - 1; j++) {
225
- const firstLine = p.p(i).findLine(p.p(i + 1));
226
- const secondLine = p.p(j).findLine(p.p(j + 1));
225
+ const firstLine = p.at(i).findLine(p.at(i + 1));
226
+ const secondLine = p.at(j).findLine(p.at(j + 1));
227
227
  const intersectionPoint = firstLine.intersection(secondLine);
228
228
  if (intersectionPoint &&
229
229
  ![...firstLine.points, ...secondLine.points].some((t) => t.like(intersectionPoint))) {
@@ -246,19 +246,19 @@ class DPolygon {
246
246
  * Get first point
247
247
  */
248
248
  get first() {
249
- return this.p(0);
249
+ return this.at(0);
250
250
  }
251
251
  /**
252
252
  * Get second point
253
253
  */
254
254
  get second() {
255
- return this.p(1);
255
+ return this.at(1);
256
256
  }
257
257
  /**
258
258
  * Get last point
259
259
  */
260
260
  get last() {
261
- return this.p(this.length - 1);
261
+ return this.at(this.length - 1);
262
262
  }
263
263
  /**
264
264
  * Get min area rectangle
@@ -268,21 +268,21 @@ class DPolygon {
268
268
  let resultPolygon = new DPolygon();
269
269
  let resultArea = Infinity;
270
270
  for (let k = 0; k < p.length - 1; k++) {
271
- const l = p.p(k).findLine(p.p(k + 1));
271
+ const l = p.at(k).findLine(p.at(k + 1));
272
272
  let maxWidth = 0;
273
273
  let maxWidthPoint1 = null;
274
274
  let maxWidthPoint2 = null;
275
275
  let maxHeight = 0;
276
276
  let maxHeightPoint = null;
277
277
  for (let i = 0; i < p.length - 1; i++) {
278
- const p1 = l.findPoint(l.findPerpendicular(p.p(i)));
279
- const h = p1.distance(p.p(i));
278
+ const p1 = l.findPoint(l.findPerpendicular(p.at(i)));
279
+ const h = p1.distance(p.at(i));
280
280
  if (h >= maxHeight) {
281
281
  maxHeight = h;
282
- maxHeightPoint = p.p(i);
282
+ maxHeightPoint = p.at(i);
283
283
  }
284
284
  for (let j = i; j < p.length - 1; j++) {
285
- const p2 = l.findPoint(l.findPerpendicular(p.p(j)));
285
+ const p2 = l.findPoint(l.findPerpendicular(p.at(j)));
286
286
  const w = p1.distance(p2);
287
287
  if (w >= maxWidth) {
288
288
  maxWidth = w;
@@ -338,9 +338,9 @@ class DPolygon {
338
338
  p = p.deintersection;
339
339
  l = p.length;
340
340
  for (let i = 1; i < p.length - 1; i++) {
341
- const p1 = p.p(i - 1);
342
- const p2 = p.p(i);
343
- const p3 = p.p(i + 1);
341
+ const p1 = p.at(i - 1);
342
+ const p2 = p.at(i);
343
+ const p3 = p.at(i + 1);
344
344
  const d = p2.findInnerAngle(p1, p3);
345
345
  if (d > Math.PI || DNumbers_1.DNumbers.likeZero(DNumbers_1.DNumbers.rad2Deg(d)) || DNumbers_1.DNumbers.likePI(d) || DNumbers_1.DNumbers.like2PI(d)) {
346
346
  p.removePart(--i, 1);
@@ -360,8 +360,8 @@ class DPolygon {
360
360
  let sum = 0;
361
361
  const p = this.clone().close();
362
362
  for (let i = 1; i < p.length; i++) {
363
- const p1 = p.p(i - 1);
364
- const p2 = p.p(i);
363
+ const p1 = p.at(i - 1);
364
+ const p2 = p.at(i);
365
365
  sum += (p2.x - p1.x) * (p2.y + p1.y);
366
366
  }
367
367
  return sum < 0;
@@ -386,14 +386,15 @@ class DPolygon {
386
386
  /**
387
387
  * Check polygon intersection with line
388
388
  * @param l
389
+ * @param [includeOnly=false]
389
390
  */
390
- intersection(l) {
391
+ intersection(l, includeOnly = false) {
391
392
  const res = [];
392
393
  for (let i = 0; i < this.pPoints.length - 1; i++) {
393
394
  const p1 = this.pPoints[i];
394
395
  const p2 = this.pPoints[i + 1];
395
396
  const line = p1.findLine(p2);
396
- const intersect = line.intersection(l);
397
+ const intersect = line.intersection(l, 0, includeOnly);
397
398
  if (intersect) {
398
399
  res.push(intersect);
399
400
  }
@@ -405,7 +406,9 @@ class DPolygon {
405
406
  * @param newCenter
406
407
  */
407
408
  setCenter(newCenter) {
408
- return this.clone().move(newCenter.clone().move(this.center.minus()));
409
+ return this.loop()
410
+ .move(newCenter.clone().move(this.center.minus()))
411
+ .run();
409
412
  }
410
413
  toWKT() {
411
414
  let h = '';
@@ -414,15 +417,6 @@ class DPolygon {
414
417
  }
415
418
  return `POLYGON ((${this.deintersection.pPoints.map((r) => `${r.x} ${r.y}`).join(', ')})${h})`;
416
419
  }
417
- /**
418
- * Rotate polygon with center in point {0, 0}
419
- * @param a Radians
420
- */
421
- rotate(a) {
422
- this.pPoints = this.pPoints.map((p) => p.rotate(a));
423
- this.holes = this.holes.map((h) => h.rotate(a));
424
- return this;
425
- }
426
420
  /**
427
421
  * Filter points
428
422
  * @param f
@@ -431,60 +425,14 @@ class DPolygon {
431
425
  this.pPoints = this.pPoints.filter(f);
432
426
  return this;
433
427
  }
434
- move(x = 0, y) {
435
- this.pPoints = this.pPoints.map((p) => p.move(x, y));
436
- this.holes = this.holes.map((h) => h.move(x, y));
437
- return this;
438
- }
439
- scale(x = 0, y) {
440
- this.pPoints = this.pPoints.map((p) => p.scale(x, y));
441
- this.holes = this.holes.map((h) => h.scale(x, y));
442
- return this;
443
- }
444
- divide(x = 0, y) {
445
- this.pPoints = this.pPoints.map((p) => p.divide(x, y));
446
- this.holes = this.holes.map((h) => h.divide(x, y));
447
- return this;
448
- }
449
- round() {
450
- this.pPoints = this.pPoints.map((p) => p.round());
451
- this.holes = this.holes.map((h) => h.round());
452
- return this;
453
- }
454
- floor() {
455
- this.pPoints = this.pPoints.map((p) => p.floor());
456
- this.holes = this.holes.map((h) => h.floor());
457
- return this;
458
- }
459
- ceil() {
460
- this.pPoints = this.pPoints.map((p) => p.ceil());
461
- this.holes = this.holes.map((h) => h.ceil());
462
- return this;
463
- }
464
- flipVertically(size) {
465
- this.pPoints = this.pPoints.map((p) => p.flipVertically(size));
466
- this.holes = this.holes.map((h) => h.flipVertically(size));
467
- return this;
468
- }
469
- toFixed(n = 2) {
470
- this.pPoints = this.pPoints.map((p) => p.toFixed(n));
471
- this.holes = this.holes.map((h) => h.toFixed(n));
472
- return this;
473
- }
474
428
  map(f) {
475
429
  this.pPoints = this.pPoints.map(f);
476
430
  this.holes = this.holes.map((h) => h.map(f));
477
431
  return this;
478
432
  }
479
- p(index, divide = false) {
480
- if (divide) {
481
- let t = index;
482
- while (t < 0) {
483
- t += this.length;
484
- }
485
- return this.pPoints[t % this.length];
486
- }
487
- return this.pPoints[index];
433
+ at(index) {
434
+ const { length } = this;
435
+ return this.points[(index % length + length) % length];
488
436
  }
489
437
  pop() {
490
438
  return this.pPoints.pop();
@@ -507,26 +455,6 @@ class DPolygon {
507
455
  return (this.pPoints.map((r) => r.getValue()) + this.holes
508
456
  .reduce((a, h) => a + h.getValue(), ''));
509
457
  }
510
- degreeToMeters() {
511
- this.pPoints = this.pPoints.map((r) => r.degreeToMeters());
512
- this.holes = this.holes.map((h) => h.degreeToMeters());
513
- return this;
514
- }
515
- metersToDegree() {
516
- this.pPoints = this.pPoints.map((r) => r.metersToDegree());
517
- this.holes = this.holes.map((h) => h.metersToDegree());
518
- return this;
519
- }
520
- radiansToMeters() {
521
- this.pPoints = this.pPoints.map((r) => r.radiansToMeters());
522
- this.holes = this.holes.map((h) => h.radiansToMeters());
523
- return this;
524
- }
525
- metersToRadians() {
526
- this.pPoints = this.pPoints.map((r) => r.metersToRadians());
527
- this.holes = this.holes.map((h) => h.metersToRadians());
528
- return this;
529
- }
530
458
  toString() {
531
459
  return `(${this.pPoints.map((r) => r.toString()).join(', ')})`;
532
460
  }
@@ -550,15 +478,6 @@ class DPolygon {
550
478
  }
551
479
  return this;
552
480
  }
553
- /**
554
- * Set `height` (`z`)
555
- * @param z
556
- */
557
- height(z) {
558
- this.map((p) => p.height(z));
559
- this.holes = this.holes.map((h) => h.height(z));
560
- return this;
561
- }
562
481
  add(poly) {
563
482
  const res = new DPolygon([...this.points, ...poly.points]).close();
564
483
  res.holes = [...this.holes, ...poly.holes].map((h) => h.clone());
@@ -585,7 +504,7 @@ class DPolygon {
585
504
  if (!(p instanceof DPolygon)) {
586
505
  return false;
587
506
  }
588
- if (this.clone().open().length !== p.clone().open().length || this.holes.length !== p.holes.length) {
507
+ if (this.length !== p.length || this.holes.length !== p.holes.length) {
589
508
  return false;
590
509
  }
591
510
  return (this.same(p) &&
@@ -596,20 +515,18 @@ class DPolygon {
596
515
  * @param p
597
516
  */
598
517
  same(p) {
599
- const pClone = p.clone().open();
600
- const thisClone = this.clone().open();
601
- const thisAsString = thisClone.toString();
602
- return thisClone.points.reduce((a) => {
603
- const f = pClone.shift();
604
- pClone.push(f);
605
- return (a ||
606
- thisAsString === pClone.toString() ||
607
- thisAsString ===
608
- pClone
609
- .clone()
610
- .reverse()
611
- .toString());
612
- }, false);
518
+ const pClone = p.clone().close();
519
+ const thisAsString = this.clone()
520
+ .close()
521
+ .toString();
522
+ for (let i = 0; i < pClone.length; i++) {
523
+ if (thisAsString === pClone.toString() || thisAsString === pClone.clone().reverse()
524
+ .toString()) {
525
+ return true;
526
+ }
527
+ pClone.nextStart();
528
+ }
529
+ return false;
613
530
  }
614
531
  findIndex(p) {
615
532
  return this.points.findIndex((t) => t.equal(p));
@@ -617,7 +534,7 @@ class DPolygon {
617
534
  /**
618
535
  * Get polygon approximation by
619
536
  * [Ramer–Douglas–Peucker algorithm](https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm)
620
- * @param e
537
+ * @param [e=Math.sqrt(this.perimeter)*APPROXIMATION_VALUE]
621
538
  */
622
539
  approximation(e = Math.sqrt(this.perimeter) * APPROXIMATION_VALUE) {
623
540
  return new DPolygon(this.clone().douglasPeucker(this.pPoints, e));
@@ -662,7 +579,7 @@ class DPolygon {
662
579
  if (lineWidth) {
663
580
  ctx.lineWidth = lineWidth;
664
581
  }
665
- if (fillColor) {
582
+ if (fillColor || strokeColor) {
666
583
  ctx.beginPath();
667
584
  }
668
585
  this.goByPath(ctx, steps % this.length);
@@ -691,10 +608,10 @@ class DPolygon {
691
608
  /**
692
609
  * Check if contain point
693
610
  * @param p
694
- * @param isBorderInside
695
- * @param move Ignore this parameter
611
+ * @param [isBorderInside=false]
612
+ * @param [move=(0,0)] Ignore this parameter
696
613
  */
697
- contain(p, isBorderInside = false, move = DPoint_1.DPoint.Zero()) {
614
+ contain(p, isBorderInside = false, move = DPoint_1.DPoint.zero()) {
698
615
  const simpleInclude = this.simpleInclude(p);
699
616
  if (!simpleInclude) {
700
617
  return false;
@@ -707,7 +624,7 @@ class DPolygon {
707
624
  const poly = this.deintersection;
708
625
  const intersectionPoints = [];
709
626
  for (let i = 0; i < poly.length - 1; i++) {
710
- const polygonLine = poly.p(i).findLine(poly.p(i + 1));
627
+ const polygonLine = poly.at(i).findLine(poly.at(i + 1));
711
628
  const intersection = line.intersection(polygonLine, CLOSE_TO_INTERSECTION_DISTANCE);
712
629
  if (intersection) {
713
630
  intersectionPoints.push(intersection);
@@ -732,8 +649,8 @@ class DPolygon {
732
649
  return true;
733
650
  }
734
651
  for (let i = 0; i < poly.length - 1; i++) {
735
- const p0 = poly.p(i);
736
- const p1 = poly.p(i + 1);
652
+ const p0 = poly.at(i);
653
+ const p1 = poly.at(i + 1);
737
654
  const polygonLine = p0.findLine(p1);
738
655
  const onBorder = polygonLine.x(p).equal(p) && polygonLine.inRange(p);
739
656
  if (onBorder) {
@@ -757,8 +674,8 @@ class DPolygon {
757
674
  */
758
675
  removeDuplicates() {
759
676
  for (let i = 0; i < this.length - 1; i++) {
760
- const p1 = this.p(i);
761
- const p2 = this.p(i + 1);
677
+ const p1 = this.at(i);
678
+ const p2 = this.at(i + 1);
762
679
  if (p1.equal(p2)) {
763
680
  this.removePart(i, 1);
764
681
  i--;
@@ -766,11 +683,6 @@ class DPolygon {
766
683
  }
767
684
  return this;
768
685
  }
769
- /**
770
- * Parse from [OpenLayers](https://openlayers.org/) coordinates or
771
- * [GeoJSON](https://en.wikipedia.org/wiki/GeoJSON) coordinates
772
- * @param a
773
- */
774
686
  static parse(a) {
775
687
  return new DPolygon(a.map((r) => DPoint_1.DPoint.parse(r)));
776
688
  }
@@ -902,6 +814,64 @@ class DPolygon {
902
814
  }
903
815
  return res;
904
816
  }
817
+ /**
818
+ * Divide polygon to triangles
819
+ *
820
+ * ![Example](https://edejin.github.io/DGeoUtils/media/examples/toTriangles.png)
821
+ */
822
+ toTriangles() {
823
+ const innerAndNotIntersect = (poly, p1, p2) => {
824
+ const l = p1.findLine(p2);
825
+ const { center } = l;
826
+ const intersections = poly.holes.reduce((a, hole) => a && Boolean(hole.clone().close()
827
+ .intersection(l, true).length), Boolean(poly.clone().close()
828
+ .intersection(l, true).length));
829
+ const contain = poly.holes.reduce((a, hole) => a && !hole
830
+ .contain(center), poly.contain(center));
831
+ return !intersections && contain;
832
+ };
833
+ const getTriangle = (poly) => {
834
+ for (let i = 0; i < poly.length; i++) {
835
+ const p0 = poly.at(0);
836
+ const p1 = poly.at(1);
837
+ const p2 = poly.at(2);
838
+ if (innerAndNotIntersect(poly, p0, p2)) {
839
+ poly.removePart(0, 1);
840
+ return new DPolygon([
841
+ p0.clone(),
842
+ p1.clone(),
843
+ p2.clone()
844
+ ]);
845
+ }
846
+ poly.push(poly.shift());
847
+ }
848
+ return undefined;
849
+ };
850
+ const p = this.clone().clockWise.open();
851
+ while (p.holes.length) {
852
+ const h = p.holes.shift()
853
+ .clone()
854
+ .clockWise
855
+ .reverse()
856
+ .close();
857
+ for (let i = 0; i < p.length; i++) {
858
+ if (innerAndNotIntersect(p, p.first, h.first)) {
859
+ p.insertAfter(0, ...h.points, p.first);
860
+ break;
861
+ }
862
+ p.push(p.shift());
863
+ }
864
+ }
865
+ const res = [];
866
+ while (p.length > 3) {
867
+ const triangle = getTriangle(p);
868
+ if (triangle) {
869
+ res.push(triangle);
870
+ }
871
+ }
872
+ res.push(p);
873
+ return res;
874
+ }
905
875
  simpleIncludeX(p) {
906
876
  const { x } = p;
907
877
  return this.minX <= x && this.maxX >= x;
@@ -934,7 +904,7 @@ class DPolygon {
934
904
  const start = this.first;
935
905
  ctx.moveTo(start.x, start.y);
936
906
  for (let i = 1; i <= (steps % this.length); i++) {
937
- const { x, y } = this.p(i);
907
+ const { x, y } = this.at(i);
938
908
  ctx.lineTo(x, y);
939
909
  }
940
910
  }
@@ -950,8 +920,8 @@ class DPolygon {
950
920
  const poly = this.deintersection;
951
921
  let totalFi = 0;
952
922
  for (let i = 0; i < poly.length - 1; i++) {
953
- const p1 = poly.p(i);
954
- const p2 = poly.p(i + 1);
923
+ const p1 = poly.at(i);
924
+ const p2 = poly.at(i + 1);
955
925
  const line1 = new DLine_1.DLine(p1.x - p.x, p1.y - p.y, 0);
956
926
  const line2 = new DLine_1.DLine(p2.x - p.x, p2.y - p.y, 0);
957
927
  const fiDif = line1.findFi(line2);
@@ -2,27 +2,97 @@ import { DPolygon } from './DPolygon';
2
2
  import { DPoint, SetterFunction } from './DPoint';
3
3
  export declare type LoopFunction = (k: DPoint) => DPoint;
4
4
  export declare class DPolygonLoop {
5
- private f;
6
5
  private readonly parent;
6
+ private pool;
7
7
  constructor(parent: DPolygon);
8
+ private getLoopFunction;
8
9
  /**
9
10
  * Run loop
10
11
  */
11
- run(f?: LoopFunction): DPolygon;
12
+ run(): DPolygon;
13
+ /**
14
+ * @param zoom default value would be `z` of point
15
+ */
12
16
  getTileFromCoords(zoom?: number): DPolygonLoop;
17
+ /**
18
+ * @param zoom default value would be `z` of point
19
+ */
13
20
  getCoordsFromTile(zoom?: number): DPolygonLoop;
14
21
  height(z: number): DPolygonLoop;
15
- setX(x: number | SetterFunction): DPolygonLoop;
16
- setY(y: number | SetterFunction): DPolygonLoop;
22
+ /**
23
+ * Set `x` value
24
+ * @param x
25
+ */
26
+ setX(x: number): DPolygonLoop;
27
+ /**
28
+ * Transform `x` value by function
29
+ * @param f
30
+ */
31
+ setX(f: SetterFunction): DPolygonLoop;
32
+ /**
33
+ * Set `y` value
34
+ * @param y
35
+ */
36
+ setY(y: number): DPolygonLoop;
37
+ /**
38
+ * Transform `y` value by function
39
+ * @param f
40
+ */
41
+ setY(f: SetterFunction): DPolygonLoop;
17
42
  rotate(a: number): DPolygonLoop;
18
- move(x?: number | DPoint, y?: number): DPolygonLoop;
43
+ /**
44
+ * Add `v` to `x` and `y`
45
+ * @param v
46
+ */
47
+ move(v: number): DPolygonLoop;
48
+ /**
49
+ * Add `p.x` to `x` field and `p.y` to `y` field.
50
+ * @param p
51
+ */
52
+ move(p: DPoint): DPolygonLoop;
53
+ /**
54
+ * Add `x` to `x` field and `y` to `y` field.
55
+ * @param x
56
+ * @param y
57
+ */
58
+ move(x: number, y: number): DPolygonLoop;
19
59
  round(): DPolygonLoop;
20
60
  ceil(): DPolygonLoop;
21
61
  floor(): DPolygonLoop;
22
62
  toFixed(n?: number): DPolygonLoop;
23
63
  abs(): DPolygonLoop;
24
- scale(x?: number | DPoint, y?: number): DPolygonLoop;
25
- divide(x?: number | DPoint, y?: number): DPolygonLoop;
64
+ /**
65
+ * Multiply `v` to `x` and `y`
66
+ * @param v
67
+ */
68
+ scale(v: number): DPolygonLoop;
69
+ /**
70
+ * Multiply `p.x` to `x` field and `p.y` to `y` field.
71
+ * @param p
72
+ */
73
+ scale(p: DPoint): DPolygonLoop;
74
+ /**
75
+ * Multiply `x` to `x` field and `y` to `y` field.
76
+ * @param x
77
+ * @param y
78
+ */
79
+ scale(x: number, y: number): DPolygonLoop;
80
+ /**
81
+ * Divide `x` and `y` to `v`
82
+ * @param v
83
+ */
84
+ divide(v: number): DPolygonLoop;
85
+ /**
86
+ * Divide `x` field to `p.x` and `y` field to `p.y`.
87
+ * @param p
88
+ */
89
+ divide(p: DPoint): DPolygonLoop;
90
+ /**
91
+ * Divide `x` field to `x` and `y` field to `y`.
92
+ * @param x
93
+ * @param y
94
+ */
95
+ divide(x: number, y: number): DPolygonLoop;
26
96
  degreeToRadians(): DPolygonLoop;
27
97
  radiansToDegrees(): DPolygonLoop;
28
98
  radiansToMeters(): DPolygonLoop;
@@ -36,5 +106,14 @@ export declare class DPolygonLoop {
36
106
  minus(): DPolygonLoop;
37
107
  degreeToMeters(): DPolygonLoop;
38
108
  metersToDegree(): DPolygonLoop;
39
- flipVertically(size: DPoint | number): DPolygonLoop;
109
+ /**
110
+ * Flip vertically
111
+ * @param size canvas size
112
+ */
113
+ flipVertically(size: DPoint): DPolygonLoop;
114
+ /**
115
+ * Flip vertically
116
+ * @param height canvas height
117
+ */
118
+ flipVertically(height: number): DPolygonLoop;
40
119
  }