dgeoutils 2.0.1 → 2.2.1

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/DCircle.d.ts CHANGED
@@ -12,11 +12,31 @@ export declare class DCircle {
12
12
  clone(): DCircle;
13
13
  /**
14
14
  * Find intersection points with other circle.
15
+ *
16
+ * ![Example](/media/examples/findPoints.png)
15
17
  * @param c
16
18
  */
17
19
  findPoints(c: DCircle): DPoint[] | number;
18
20
  equal({ center, r }: DCircle): boolean;
21
+ /**
22
+ * Transform circle to polygon
23
+ *
24
+ * ![Example](/media/examples/findPolygonInside.png)
25
+ * @param [pointCount=64]
26
+ */
19
27
  findPolygonInside(pointCount?: number): DPolygon;
28
+ /**
29
+ * Transform circle to polygon on sphere. It would be different for different latitude.
30
+ *
31
+ * @remarks
32
+ * Center should be Lng/Lat.
33
+ *
34
+ * @remarks
35
+ * Radius should be in meters.
36
+ *
37
+ * ![Example](/media/examples/findPolygonInsideOnSphere.png)
38
+ * @param [pointCount=64]
39
+ */
20
40
  findPolygonInsideOnSphere(pointCount?: number): DPolygon;
21
41
  private sphereOffset;
22
42
  }
package/dist/DCircle.js CHANGED
@@ -23,6 +23,8 @@ class DCircle {
23
23
  }
24
24
  /**
25
25
  * Find intersection points with other circle.
26
+ *
27
+ * ![Example](/media/examples/findPoints.png)
26
28
  * @param c
27
29
  */
28
30
  findPoints(c) {
@@ -57,6 +59,12 @@ class DCircle {
57
59
  equal({ center, r }) {
58
60
  return this.center.equal(center) && this.r === r;
59
61
  }
62
+ /**
63
+ * Transform circle to polygon
64
+ *
65
+ * ![Example](/media/examples/findPolygonInside.png)
66
+ * @param [pointCount=64]
67
+ */
60
68
  findPolygonInside(pointCount = 64) {
61
69
  const preAngle = 2 * Math.PI / pointCount;
62
70
  const points = [];
@@ -68,6 +76,18 @@ class DCircle {
68
76
  }
69
77
  return new DPolygon_1.DPolygon([...points, points[0]]);
70
78
  }
79
+ /**
80
+ * Transform circle to polygon on sphere. It would be different for different latitude.
81
+ *
82
+ * @remarks
83
+ * Center should be Lng/Lat.
84
+ *
85
+ * @remarks
86
+ * Radius should be in meters.
87
+ *
88
+ * ![Example](/media/examples/findPolygonInsideOnSphere.png)
89
+ * @param [pointCount=64]
90
+ */
71
91
  findPolygonInsideOnSphere(pointCount = 64) {
72
92
  (0, utils_1.checkFunction)('findPolygonInsideOnSphere')
73
93
  .checkArgument('center')
@@ -76,7 +96,7 @@ class DCircle {
76
96
  for (let i = 0; i < pointCount; i++) {
77
97
  res.push(this.sphereOffset(2 * Math.PI * i / pointCount));
78
98
  }
79
- return res;
99
+ return res.close();
80
100
  }
81
101
  sphereOffset(bearing, earthRadius = DPoint_1.EARTH_RADIUS_IN_METERS) {
82
102
  const lat1 = DNumbers_1.DNumbers.deg2Rad(this.center.y);
package/dist/DLine.d.ts CHANGED
@@ -14,9 +14,10 @@ export declare class DLine {
14
14
  * Find intersection of two lines segments.
15
15
  * For intersection of two lines use [[findPoint]]
16
16
  * @param l
17
- * @param d
17
+ * @param [d=0]
18
+ * @param [includeOnly=false]
18
19
  */
19
- intersection(l: DLine, d?: number): DPoint | null;
20
+ intersection(l: DLine, d?: number, includeOnly?: boolean): DPoint | null;
20
21
  intersectionWithCircle(circle: DCircle): DPoint | [DPoint, DPoint] | null;
21
22
  /**
22
23
  * Check if point below to line segment
@@ -24,6 +25,13 @@ export declare class DLine {
24
25
  * @param d
25
26
  */
26
27
  inRange(p: DPoint, d?: number): boolean;
28
+ /**
29
+ * Check if point below to line segment, but not equal star or end point.
30
+ * @param p
31
+ * @param d
32
+ */
33
+ insideRange(p: DPoint, d?: number): boolean;
34
+ get center(): DPoint;
27
35
  get minX(): number;
28
36
  get minY(): number;
29
37
  get maxX(): number;
package/dist/DLine.js CHANGED
@@ -45,11 +45,15 @@ class DLine {
45
45
  * Find intersection of two lines segments.
46
46
  * For intersection of two lines use [[findPoint]]
47
47
  * @param l
48
- * @param d
48
+ * @param [d=0]
49
+ * @param [includeOnly=false]
49
50
  */
50
- intersection(l, d = 0) {
51
+ intersection(l, d = 0, includeOnly = false) {
51
52
  const p = this.findPoint(l);
52
53
  if (p) {
54
+ if (includeOnly) {
55
+ return this.insideRange(p, d) && l.insideRange(p, d) ? p : null;
56
+ }
53
57
  return this.inRange(p, d) && l.inRange(p, d) ? p : null;
54
58
  }
55
59
  return null;
@@ -117,6 +121,32 @@ class DLine {
117
121
  const isInY = y >= minY - d && y <= maxY + d;
118
122
  return isInX && isInY;
119
123
  }
124
+ /**
125
+ * Check if point below to line segment, but not equal star or end point.
126
+ * @param p
127
+ * @param d
128
+ */
129
+ insideRange(p, d = 0) {
130
+ const { minX, minY, maxX, maxY, p1, p2 } = this;
131
+ const { x, y } = p;
132
+ return this.inRange(p, d) && !p1.like(p, 0.00001) && !p2.like(p, 0.00001);
133
+ const isInX = x > minX - d && x < maxX + d;
134
+ const isInY = y > minY - d && y < maxY + d;
135
+ return isInX && isInY && !p1.like(p, 0.00001) && !p2.like(p, 0.00001);
136
+ }
137
+ get center() {
138
+ return this.p1
139
+ .clone()
140
+ .setIfLessThan(this.p2)
141
+ .move(this.p2
142
+ .clone()
143
+ .move(this.p1
144
+ .clone()
145
+ .minus())
146
+ .abs()
147
+ .minus()
148
+ .divide(2));
149
+ }
120
150
  get minX() {
121
151
  return Math.min(this.p1.x, this.p2.x);
122
152
  }
package/dist/DPoint.d.ts CHANGED
@@ -1,19 +1,5 @@
1
1
  import { DLine } from './DLine';
2
2
  import { DPolygon } from './DPolygon';
3
- /**
4
- * Meters
5
- * Projected bounds:
6
- * -20026376.39 -20048966.10
7
- * 20026376.39 20048966.10
8
- */
9
- export declare const PSEUDO_MERCATOR = "EPSG:3857";
10
- /**
11
- * Degrees
12
- * Projected bounds:
13
- * -180.0 -90.0
14
- * 180.0 90.0
15
- */
16
- export declare const WORLD_GEODETIC_SYSTEM = "EPSG:4326";
17
3
  export declare const EARTH_RADIUS_IN_METERS = 6371008.8;
18
4
  export declare type DCoord = [number, number] | [number, number, number];
19
5
  export interface LatLng {
@@ -45,7 +31,21 @@ export declare class DPoint {
45
31
  static isPoint(p: unknown): boolean;
46
32
  static parseFromWKT(wkt: string): DPoint;
47
33
  static Random(): DPoint;
34
+ /**
35
+ * @remark Point should be Lng/Lat.
36
+ *
37
+ * @remark `z` value default for `zoom` argument.
38
+ *
39
+ * @param [zoom=this.z]
40
+ */
48
41
  getTileFromCoords(zoom?: number): DPoint;
42
+ /**
43
+ * Result would be Lng/Lat.
44
+ *
45
+ * @remark `z` value default for `zoom` argument.
46
+ *
47
+ * @param [zoom=this.z]
48
+ */
49
49
  getCoordsFromTile(zoom?: number): DPoint;
50
50
  toCoords(): DCoord;
51
51
  /**
@@ -54,7 +54,6 @@ export declare class DPoint {
54
54
  */
55
55
  findLine(p: DPoint): DLine;
56
56
  findInnerAngle(p1: DPoint, p3: DPoint): number;
57
- transform(from?: string, to?: string): DPoint;
58
57
  toString(): string;
59
58
  getValue(): [number, number];
60
59
  height(z: number): DPoint;
@@ -73,8 +72,12 @@ export declare class DPoint {
73
72
  */
74
73
  rotate(a: number): DPoint;
75
74
  move(x?: number | DPoint, y?: number): DPoint;
76
- asRadians(): DPoint;
77
- asDegrees(): DPoint;
75
+ degreeToMeters(): DPoint;
76
+ metersToDegree(): DPoint;
77
+ degreeToRadians(): DPoint;
78
+ radiansToDegrees(): DPoint;
79
+ radiansToMeters(): DPoint;
80
+ metersToRadians(): DPoint;
78
81
  round(): DPoint;
79
82
  ceil(): DPoint;
80
83
  floor(): DPoint;
@@ -84,6 +87,7 @@ export declare class DPoint {
84
87
  divide(x?: number | DPoint, y?: number): DPoint;
85
88
  equal(p: DPoint): boolean;
86
89
  like(p: DPoint, d?: number): boolean;
90
+ flipVertically(size: DPoint | number): DPoint;
87
91
  /**
88
92
  * Check if point looks like radians
89
93
  */
@@ -114,7 +118,15 @@ export declare class DPoint {
114
118
  };
115
119
  setIfLessThan(p: DPoint): DPoint;
116
120
  minus(): DPoint;
121
+ /**
122
+ * Find [orthodromic path](https://en.wikipedia.org/wiki/Great-circle_navigation) between to points.
123
+ *
124
+ * @remark Points should be Lng/Lat.
125
+ *
126
+ * ![example](/media/examples/orthodromicPath.png)
127
+ *
128
+ * @param point
129
+ * @param [pointsCount=360]
130
+ */
117
131
  orthodromicPath(point: DPoint, pointsCount?: number): DPolygon;
118
- private degrees2meters;
119
- private meters2degrees;
120
132
  }
package/dist/DPoint.js CHANGED
@@ -1,26 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DPoint = exports.DEGREE_TO_PI = exports.PI_TO_DEGREE = exports.DOUBLE_PI_IN_DEGREE = exports.PI_IN_DEGREE = exports.HALF_PI_IN_DEGREE = exports.EARTH_RADIUS_IN_METERS = exports.WORLD_GEODETIC_SYSTEM = exports.PSEUDO_MERCATOR = void 0;
3
+ exports.DPoint = exports.DEGREE_TO_PI = exports.PI_TO_DEGREE = exports.DOUBLE_PI_IN_DEGREE = exports.PI_IN_DEGREE = exports.HALF_PI_IN_DEGREE = exports.EARTH_RADIUS_IN_METERS = void 0;
4
4
  const DLine_1 = require("./DLine");
5
5
  const DPolygon_1 = require("./DPolygon");
6
6
  const utils_1 = require("./utils");
7
7
  const diff = 0;
8
8
  const radiansPolygon = new DPolygon_1.DPolygon();
9
- /**
10
- * Meters
11
- * Projected bounds:
12
- * -20026376.39 -20048966.10
13
- * 20026376.39 20048966.10
14
- */
15
- exports.PSEUDO_MERCATOR = 'EPSG:3857';
16
9
  const pseudoMercatorPolygon = new DPolygon_1.DPolygon();
17
- /**
18
- * Degrees
19
- * Projected bounds:
20
- * -180.0 -90.0
21
- * 180.0 90.0
22
- */
23
- exports.WORLD_GEODETIC_SYSTEM = 'EPSG:4326';
24
10
  const worldGeodeticPolygon = new DPolygon_1.DPolygon();
25
11
  exports.EARTH_RADIUS_IN_METERS = 6371008.8;
26
12
  const EARTH_IN_MITERS = 20037508.34;
@@ -72,6 +58,13 @@ class DPoint {
72
58
  static Random() {
73
59
  return new DPoint(Math.random(), Math.random());
74
60
  }
61
+ /**
62
+ * @remark Point should be Lng/Lat.
63
+ *
64
+ * @remark `z` value default for `zoom` argument.
65
+ *
66
+ * @param [zoom=this.z]
67
+ */
75
68
  getTileFromCoords(zoom = this.z) {
76
69
  (0, utils_1.checkFunction)('getTileFromCoords')
77
70
  .checkArgument('this')
@@ -80,6 +73,13 @@ class DPoint {
80
73
  const y = Math.floor((1 - Math.log(Math.tan(this.y * exports.PI_TO_DEGREE) + 1 / Math.cos(this.y * exports.PI_TO_DEGREE)) / Math.PI) / 2 * (Math.pow(2, zoom)));
81
74
  return new DPoint(x, y, zoom);
82
75
  }
76
+ /**
77
+ * Result would be Lng/Lat.
78
+ *
79
+ * @remark `z` value default for `zoom` argument.
80
+ *
81
+ * @param [zoom=this.z]
82
+ */
83
83
  getCoordsFromTile(zoom = this.z) {
84
84
  (0, utils_1.checkFunction)('getCoordsFromTile')
85
85
  .checkArgument('this')
@@ -134,18 +134,6 @@ class DPoint {
134
134
  }
135
135
  return a2 + Math.PI * 2 - a1;
136
136
  }
137
- transform(from = exports.PSEUDO_MERCATOR, to = exports.WORLD_GEODETIC_SYSTEM) {
138
- if (from === to && [exports.PSEUDO_MERCATOR, exports.WORLD_GEODETIC_SYSTEM].includes(from)) {
139
- return this;
140
- }
141
- if (from === exports.PSEUDO_MERCATOR && to === exports.WORLD_GEODETIC_SYSTEM) {
142
- return this.meters2degrees();
143
- }
144
- if (from === exports.WORLD_GEODETIC_SYSTEM && to === exports.PSEUDO_MERCATOR) {
145
- return this.degrees2meters();
146
- }
147
- return this;
148
- }
149
137
  toString() {
150
138
  return `${this.x} ${this.y}`;
151
139
  }
@@ -221,18 +209,52 @@ class DPoint {
221
209
  this.y = yV;
222
210
  return this;
223
211
  }
224
- asRadians() {
225
- (0, utils_1.checkFunction)('asRadians')
212
+ degreeToMeters() {
213
+ (0, utils_1.checkFunction)('degreeToMeters')
214
+ .checkArgument('this')
215
+ .shouldBeDegree(this);
216
+ const x = ((this.x + exports.PI_IN_DEGREE) % exports.DOUBLE_PI_IN_DEGREE - exports.PI_IN_DEGREE) * MITERS_IN_ONE_DEGREE;
217
+ const y = (Math.log(Math.tan(((this.y + exports.HALF_PI_IN_DEGREE) % exports.PI_IN_DEGREE) *
218
+ (Math.PI / exports.DOUBLE_PI_IN_DEGREE))) / exports.PI_TO_DEGREE) * MITERS_IN_ONE_DEGREE;
219
+ this.x = x;
220
+ this.y = y;
221
+ return this;
222
+ }
223
+ metersToDegree() {
224
+ (0, utils_1.checkFunction)('metersToDegree')
225
+ .checkArgument('this')
226
+ .shouldBeMeters(this);
227
+ const lon = this.x * DEGREES_IN_ONE_MITER;
228
+ const lat = Math.atan(Math.pow(Math.E, ((this.y / MITERS_IN_ONE_DEGREE) * exports.PI_TO_DEGREE))) *
229
+ (exports.DOUBLE_PI_IN_DEGREE / Math.PI) - exports.HALF_PI_IN_DEGREE;
230
+ this.x = lon;
231
+ this.y = lat;
232
+ return this;
233
+ }
234
+ degreeToRadians() {
235
+ (0, utils_1.checkFunction)('degreeToRadians')
226
236
  .checkArgument('this')
227
237
  .shouldBeDegree(this);
228
238
  return this.scale(exports.PI_TO_DEGREE);
229
239
  }
230
- asDegrees() {
231
- (0, utils_1.checkFunction)('asDegrees')
240
+ radiansToDegrees() {
241
+ (0, utils_1.checkFunction)('radiansToDegrees')
232
242
  .checkArgument('this')
233
243
  .shouldBeRadians(this);
234
244
  return this.scale(exports.DEGREE_TO_PI);
235
245
  }
246
+ radiansToMeters() {
247
+ (0, utils_1.checkFunction)('radiansToMeters')
248
+ .checkArgument('this')
249
+ .shouldBeRadians(this);
250
+ return this.radiansToDegrees().degreeToMeters();
251
+ }
252
+ metersToRadians() {
253
+ (0, utils_1.checkFunction)('metersToRadians')
254
+ .checkArgument('this')
255
+ .shouldBeMeters(this);
256
+ return this.metersToDegree().degreeToRadians();
257
+ }
236
258
  round() {
237
259
  this.x = Math.round(this.x);
238
260
  this.y = Math.round(this.y);
@@ -297,6 +319,14 @@ class DPoint {
297
319
  const likeZ = this.z === p.z || Math.abs(this.z - p.z) < d;
298
320
  return likeX && likeY && likeZ;
299
321
  }
322
+ flipVertically(size) {
323
+ let v = size;
324
+ if (size instanceof DPoint) {
325
+ v = size.y;
326
+ }
327
+ this.y = v - this.y;
328
+ return this;
329
+ }
300
330
  /**
301
331
  * Check if point looks like radians
302
332
  */
@@ -386,14 +416,24 @@ class DPoint {
386
416
  minus() {
387
417
  return this.clone().scale(-1);
388
418
  }
419
+ /**
420
+ * Find [orthodromic path](https://en.wikipedia.org/wiki/Great-circle_navigation) between to points.
421
+ *
422
+ * @remark Points should be Lng/Lat.
423
+ *
424
+ * ![example](/media/examples/orthodromicPath.png)
425
+ *
426
+ * @param point
427
+ * @param [pointsCount=360]
428
+ */
389
429
  orthodromicPath(point, pointsCount = 360) {
390
430
  (0, utils_1.checkFunction)('orthodromicPath')
391
431
  .checkArgument('this')
392
432
  .shouldBeDegree(this)
393
433
  .checkArgument('point')
394
434
  .shouldBeDegree(point);
395
- const t = this.clone().asRadians();
396
- const p = point.clone().asRadians();
435
+ const t = this.clone().degreeToRadians();
436
+ const p = point.clone().degreeToRadians();
397
437
  const d = Math.sin(p.x - t.x);
398
438
  const step = (p.x - t.x) / (pointsCount - 1);
399
439
  return new DPolygon_1.DPolygon(Array.from(new Array(pointsCount))
@@ -401,30 +441,8 @@ class DPoint {
401
441
  const x = t.x + step * i;
402
442
  const y = Math.atan((Math.tan(t.y) * Math.sin(p.x - x)) / d +
403
443
  (Math.tan(p.y) * Math.sin(x - t.x)) / d);
404
- return new DPoint(x, y).asDegrees();
444
+ return new DPoint(x, y).radiansToDegrees();
405
445
  }));
406
446
  }
407
- degrees2meters() {
408
- (0, utils_1.checkFunction)('degrees2meters')
409
- .checkArgument('this')
410
- .shouldBeDegree(this);
411
- const x = ((this.x + exports.PI_IN_DEGREE) % exports.DOUBLE_PI_IN_DEGREE - exports.PI_IN_DEGREE) * MITERS_IN_ONE_DEGREE;
412
- const y = (Math.log(Math.tan(((this.y + exports.HALF_PI_IN_DEGREE) % exports.PI_IN_DEGREE) *
413
- (Math.PI / exports.DOUBLE_PI_IN_DEGREE))) / exports.PI_TO_DEGREE) * MITERS_IN_ONE_DEGREE;
414
- this.x = x;
415
- this.y = y;
416
- return this;
417
- }
418
- meters2degrees() {
419
- (0, utils_1.checkFunction)('meters2degrees')
420
- .checkArgument('this')
421
- .shouldBeMeters(this);
422
- const lon = this.x * DEGREES_IN_ONE_MITER;
423
- const lat = Math.atan(Math.pow(Math.E, ((this.y / MITERS_IN_ONE_DEGREE) * exports.PI_TO_DEGREE))) *
424
- (exports.DOUBLE_PI_IN_DEGREE / Math.PI) - exports.HALF_PI_IN_DEGREE;
425
- this.x = lon;
426
- this.y = lat;
427
- return this;
428
- }
429
447
  }
430
448
  exports.DPoint = DPoint;
@@ -2,10 +2,6 @@
2
2
  import { DCoord, DPoint, LatLng } from './DPoint';
3
3
  import { DLine } from './DLine';
4
4
  import { DPolygonLoop } from './DPolygonLoop';
5
- interface ParseProps {
6
- dataProjection: string;
7
- featureProjection: string;
8
- }
9
5
  export declare const MIN_POINTS_IN_VALID_POLYGON = 3;
10
6
  export declare class DPolygon {
11
7
  properties: {
@@ -30,7 +26,7 @@ export declare class DPolygon {
30
26
  * @param poly should be `minAreaRectangle`
31
27
  */
32
28
  static minAreaRectangleDirection(poly: DPolygon): number;
33
- static parseFromWKT(wkt: string, optProps?: ParseProps): DPolygon;
29
+ static parseFromWKT(wkt: string): DPolygon;
34
30
  static createSquareBySize(size: DPoint): DPolygon;
35
31
  loop(): DPolygonLoop;
36
32
  set points(p: DPoint[]);
@@ -134,8 +130,9 @@ export declare class DPolygon {
134
130
  /**
135
131
  * Check polygon intersection with line
136
132
  * @param l
133
+ * @param [includeOnly=false]
137
134
  */
138
- intersection(l: DLine): DPoint[];
135
+ intersection(l: DLine, includeOnly?: boolean): DPoint[];
139
136
  /**
140
137
  * Set polygon center
141
138
  * @param newCenter
@@ -158,6 +155,7 @@ export declare class DPolygon {
158
155
  round(): DPolygon;
159
156
  floor(): DPolygon;
160
157
  ceil(): DPolygon;
158
+ flipVertically(size: DPoint | number): DPolygon;
161
159
  toFixed(n?: number): DPolygon;
162
160
  map(f: (r: DPoint, index?: number) => DPoint): DPolygon;
163
161
  p(index: number, divide?: boolean): DPoint;
@@ -167,7 +165,10 @@ export declare class DPolygon {
167
165
  unshift(...args: DPoint[]): number;
168
166
  reverse(): DPolygon;
169
167
  getValue(): string;
170
- transform(from?: string, to?: string): DPolygon;
168
+ degreeToMeters(): DPolygon;
169
+ metersToDegree(): DPolygon;
170
+ radiansToMeters(): DPolygon;
171
+ metersToRadians(): DPolygon;
171
172
  toString(): string;
172
173
  /**
173
174
  * Add to the end of polygon point equal to first point if it not exist
@@ -266,6 +267,17 @@ export declare class DPolygon {
266
267
  simpleIntersection(p: DPolygon): DPolygon | null | DPolygon[];
267
268
  simpleDifference(p: DPolygon): DPolygon | null | DPolygon[];
268
269
  smartUnion(p: DPolygon): DPolygon | null;
270
+ /**
271
+ * Divide polygon to triangles
272
+ *
273
+ * ![Example](/media/examples/toTriangles.png)
274
+ */
275
+ toTriangles(): DPolygon[];
276
+ /**
277
+ * @internal
278
+ */
279
+ getTriangle(): DPolygon | void;
280
+ private innerAndNotIntersect;
269
281
  private simpleIncludeX;
270
282
  private simpleIncludeY;
271
283
  private douglasPeucker;
@@ -274,4 +286,3 @@ export declare class DPolygon {
274
286
  private getJSTSGeometry;
275
287
  private simpleLogicFunction;
276
288
  }
277
- export {};
package/dist/DPolygon.js CHANGED
@@ -66,7 +66,7 @@ class DPolygon {
66
66
  }
67
67
  return first.findLine(last).getFi();
68
68
  }
69
- static parseFromWKT(wkt, optProps) {
69
+ static parseFromWKT(wkt) {
70
70
  const data = wkt.trim().toUpperCase();
71
71
  let res = new DPolygon();
72
72
  if (data.indexOf('POLYGON') === 0) {
@@ -90,9 +90,6 @@ class DPolygon {
90
90
  if (data.indexOf('POINT') === 0) {
91
91
  res = new DPolygon([DPoint_1.DPoint.parseFromWKT(data)]);
92
92
  }
93
- if (optProps) {
94
- return res.transform(optProps.dataProjection, optProps.featureProjection);
95
- }
96
93
  return res;
97
94
  }
98
95
  static createSquareBySize(size) {
@@ -389,14 +386,15 @@ class DPolygon {
389
386
  /**
390
387
  * Check polygon intersection with line
391
388
  * @param l
389
+ * @param [includeOnly=false]
392
390
  */
393
- intersection(l) {
391
+ intersection(l, includeOnly = false) {
394
392
  const res = [];
395
393
  for (let i = 0; i < this.pPoints.length - 1; i++) {
396
394
  const p1 = this.pPoints[i];
397
395
  const p2 = this.pPoints[i + 1];
398
396
  const line = p1.findLine(p2);
399
- const intersect = line.intersection(l);
397
+ const intersect = line.intersection(l, 0, includeOnly);
400
398
  if (intersect) {
401
399
  res.push(intersect);
402
400
  }
@@ -464,6 +462,11 @@ class DPolygon {
464
462
  this.holes = this.holes.map((h) => h.ceil());
465
463
  return this;
466
464
  }
465
+ flipVertically(size) {
466
+ this.pPoints = this.pPoints.map((p) => p.flipVertically(size));
467
+ this.holes = this.holes.map((h) => h.flipVertically(size));
468
+ return this;
469
+ }
467
470
  toFixed(n = 2) {
468
471
  this.pPoints = this.pPoints.map((p) => p.toFixed(n));
469
472
  this.holes = this.holes.map((h) => h.toFixed(n));
@@ -505,9 +508,24 @@ class DPolygon {
505
508
  return (this.pPoints.map((r) => r.getValue()) + this.holes
506
509
  .reduce((a, h) => a + h.getValue(), ''));
507
510
  }
508
- transform(from = DPoint_1.PSEUDO_MERCATOR, to = DPoint_1.WORLD_GEODETIC_SYSTEM) {
509
- this.pPoints = this.pPoints.map((r) => r.transform(from, to));
510
- this.holes = this.holes.map((h) => h.transform(from, to));
511
+ degreeToMeters() {
512
+ this.pPoints = this.pPoints.map((r) => r.degreeToMeters());
513
+ this.holes = this.holes.map((h) => h.degreeToMeters());
514
+ return this;
515
+ }
516
+ metersToDegree() {
517
+ this.pPoints = this.pPoints.map((r) => r.metersToDegree());
518
+ this.holes = this.holes.map((h) => h.metersToDegree());
519
+ return this;
520
+ }
521
+ radiansToMeters() {
522
+ this.pPoints = this.pPoints.map((r) => r.radiansToMeters());
523
+ this.holes = this.holes.map((h) => h.radiansToMeters());
524
+ return this;
525
+ }
526
+ metersToRadians() {
527
+ this.pPoints = this.pPoints.map((r) => r.metersToRadians());
528
+ this.holes = this.holes.map((h) => h.metersToRadians());
511
529
  return this;
512
530
  }
513
531
  toString() {
@@ -645,7 +663,7 @@ class DPolygon {
645
663
  if (lineWidth) {
646
664
  ctx.lineWidth = lineWidth;
647
665
  }
648
- if (fillColor) {
666
+ if (fillColor || strokeColor) {
649
667
  ctx.beginPath();
650
668
  }
651
669
  this.goByPath(ctx, steps % this.length);
@@ -885,6 +903,67 @@ class DPolygon {
885
903
  }
886
904
  return res;
887
905
  }
906
+ /**
907
+ * Divide polygon to triangles
908
+ *
909
+ * ![Example](/media/examples/toTriangles.png)
910
+ */
911
+ toTriangles() {
912
+ const p = this.clone().clockWise.open();
913
+ while (p.holes.length) {
914
+ const h = p.holes.shift()
915
+ .clone()
916
+ .clockWise
917
+ .reverse()
918
+ .close();
919
+ for (let i = 0; i < p.length; i++) {
920
+ if (p.innerAndNotIntersect(p.first, h.first)) {
921
+ p.insertAfter(0, ...h.points, p.first);
922
+ break;
923
+ }
924
+ p.push(p.shift());
925
+ }
926
+ }
927
+ const res = [];
928
+ while (p.length > 3) {
929
+ const triangle = p.getTriangle();
930
+ if (triangle) {
931
+ res.push(triangle);
932
+ }
933
+ }
934
+ res.push(p);
935
+ return res;
936
+ }
937
+ /**
938
+ * @internal
939
+ */
940
+ getTriangle() {
941
+ for (let i = 0; i < this.length; i++) {
942
+ const p0 = this.p(0);
943
+ const p1 = this.p(1);
944
+ const p2 = this.p(2);
945
+ if (this.innerAndNotIntersect(p0, p2)) {
946
+ this.removePart(0, 1);
947
+ return new DPolygon([
948
+ p0.clone(),
949
+ p1.clone(),
950
+ p2.clone()
951
+ ]);
952
+ }
953
+ this.push(this.shift());
954
+ }
955
+ return undefined;
956
+ }
957
+ innerAndNotIntersect(p1, p2) {
958
+ const l = p1.findLine(p2);
959
+ const { center } = l;
960
+ const intersections = this.holes.reduce((a, hole) => a && Boolean(hole.clone().close()
961
+ .intersection(l, true).length), Boolean(this.clone().close()
962
+ .intersection(l, true).length));
963
+ const contain = this.holes.reduce((a, hole) => a && !hole
964
+ .contain(center), this.contain(center));
965
+ return !intersections && contain;
966
+ }
888
967
  simpleIncludeX(p) {
889
968
  const { x } = p;
890
969
  return this.minX <= x && this.maxX >= x;
@@ -1,12 +1,17 @@
1
1
  import { DPolygon } from './DPolygon';
2
2
  import { DPoint, SetterFunction } from './DPoint';
3
+ export declare type LoopFunction = (k: DPoint) => DPoint;
3
4
  export declare class DPolygonLoop {
4
- private f;
5
5
  private readonly parent;
6
+ private pool;
6
7
  constructor(parent: DPolygon);
8
+ private getLoopFunction;
9
+ /**
10
+ * Run loop
11
+ */
12
+ run(): DPolygon;
7
13
  getTileFromCoords(zoom?: number): DPolygonLoop;
8
14
  getCoordsFromTile(zoom?: number): DPolygonLoop;
9
- transform(from?: string, to?: string): DPolygonLoop;
10
15
  height(z: number): DPolygonLoop;
11
16
  setX(x: number | SetterFunction): DPolygonLoop;
12
17
  setY(y: number | SetterFunction): DPolygonLoop;
@@ -19,8 +24,10 @@ export declare class DPolygonLoop {
19
24
  abs(): DPolygonLoop;
20
25
  scale(x?: number | DPoint, y?: number): DPolygonLoop;
21
26
  divide(x?: number | DPoint, y?: number): DPolygonLoop;
22
- asRadians(): DPolygonLoop;
23
- asDegrees(): DPolygonLoop;
27
+ degreeToRadians(): DPolygonLoop;
28
+ radiansToDegrees(): DPolygonLoop;
29
+ radiansToMeters(): DPolygonLoop;
30
+ metersToRadians(): DPolygonLoop;
24
31
  getHipPoint(): DPolygonLoop;
25
32
  getXPoint(): DPolygonLoop;
26
33
  getYPoint(): DPolygonLoop;
@@ -28,5 +35,7 @@ export declare class DPolygonLoop {
28
35
  getHPoint(): DPolygonLoop;
29
36
  setIfLessThan(p: DPoint): DPolygonLoop;
30
37
  minus(): DPolygonLoop;
31
- run(): DPolygon;
38
+ degreeToMeters(): DPolygonLoop;
39
+ metersToDegree(): DPolygonLoop;
40
+ flipVertically(size: DPoint | number): DPolygonLoop;
32
41
  }
@@ -1,135 +1,353 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DPolygonLoop = void 0;
4
- const DPoint_1 = require("./DPoint");
4
+ var LoopFunctions;
5
+ (function (LoopFunctions) {
6
+ LoopFunctions[LoopFunctions["getTileFromCoords"] = 0] = "getTileFromCoords";
7
+ LoopFunctions[LoopFunctions["getCoordsFromTile"] = 1] = "getCoordsFromTile";
8
+ LoopFunctions[LoopFunctions["height"] = 2] = "height";
9
+ LoopFunctions[LoopFunctions["setX"] = 3] = "setX";
10
+ LoopFunctions[LoopFunctions["setY"] = 4] = "setY";
11
+ LoopFunctions[LoopFunctions["rotate"] = 5] = "rotate";
12
+ LoopFunctions[LoopFunctions["move"] = 6] = "move";
13
+ LoopFunctions[LoopFunctions["round"] = 7] = "round";
14
+ LoopFunctions[LoopFunctions["ceil"] = 8] = "ceil";
15
+ LoopFunctions[LoopFunctions["floor"] = 9] = "floor";
16
+ LoopFunctions[LoopFunctions["toFixed"] = 10] = "toFixed";
17
+ LoopFunctions[LoopFunctions["abs"] = 11] = "abs";
18
+ LoopFunctions[LoopFunctions["scale"] = 12] = "scale";
19
+ LoopFunctions[LoopFunctions["divide"] = 13] = "divide";
20
+ LoopFunctions[LoopFunctions["degreeToRadians"] = 14] = "degreeToRadians";
21
+ LoopFunctions[LoopFunctions["radiansToDegrees"] = 15] = "radiansToDegrees";
22
+ LoopFunctions[LoopFunctions["radiansToMeters"] = 16] = "radiansToMeters";
23
+ LoopFunctions[LoopFunctions["metersToRadians"] = 17] = "metersToRadians";
24
+ LoopFunctions[LoopFunctions["hipPoint"] = 18] = "hipPoint";
25
+ LoopFunctions[LoopFunctions["xPoint"] = 19] = "xPoint";
26
+ LoopFunctions[LoopFunctions["yPoint"] = 20] = "yPoint";
27
+ LoopFunctions[LoopFunctions["wPoint"] = 21] = "wPoint";
28
+ LoopFunctions[LoopFunctions["hPoint"] = 22] = "hPoint";
29
+ LoopFunctions[LoopFunctions["setIfLessThan"] = 23] = "setIfLessThan";
30
+ LoopFunctions[LoopFunctions["minus"] = 24] = "minus";
31
+ LoopFunctions[LoopFunctions["degreeToMeters"] = 25] = "degreeToMeters";
32
+ LoopFunctions[LoopFunctions["metersToDegree"] = 26] = "metersToDegree";
33
+ LoopFunctions[LoopFunctions["flipVertically"] = 27] = "flipVertically";
34
+ })(LoopFunctions || (LoopFunctions = {}));
35
+ // eslint-disable-next-line complexity
36
+ const decodePoolRecord = (a, { functionName, pointArg, numberPointArg, numberArg, setterArg }) => {
37
+ let res = a;
38
+ switch (functionName) {
39
+ case LoopFunctions.getTileFromCoords:
40
+ res = (k) => a(k)
41
+ .getTileFromCoords(numberArg);
42
+ break;
43
+ case LoopFunctions.getCoordsFromTile:
44
+ res = (k) => a(k)
45
+ .getCoordsFromTile(numberArg);
46
+ break;
47
+ case LoopFunctions.height:
48
+ res = (k) => a(k)
49
+ .height(numberArg);
50
+ break;
51
+ case LoopFunctions.setX:
52
+ res = (k) => a(k)
53
+ .setX(setterArg);
54
+ break;
55
+ case LoopFunctions.setY:
56
+ res = (k) => a(k)
57
+ .setY(setterArg);
58
+ break;
59
+ case LoopFunctions.rotate:
60
+ res = (k) => a(k)
61
+ .rotate(numberArg);
62
+ break;
63
+ case LoopFunctions.move:
64
+ res = (k) => a(k)
65
+ .move(numberPointArg, numberArg);
66
+ break;
67
+ case LoopFunctions.round:
68
+ res = (k) => a(k)
69
+ .round();
70
+ break;
71
+ case LoopFunctions.ceil:
72
+ res = (k) => a(k)
73
+ .ceil();
74
+ break;
75
+ case LoopFunctions.floor:
76
+ res = (k) => a(k)
77
+ .floor();
78
+ break;
79
+ case LoopFunctions.toFixed:
80
+ res = (k) => a(k)
81
+ .toFixed(numberArg);
82
+ break;
83
+ case LoopFunctions.abs:
84
+ res = (k) => a(k)
85
+ .abs();
86
+ break;
87
+ case LoopFunctions.scale:
88
+ res = (k) => a(k)
89
+ .scale(numberPointArg, numberArg);
90
+ break;
91
+ case LoopFunctions.divide:
92
+ res = (k) => a(k)
93
+ .divide(numberPointArg, numberArg);
94
+ break;
95
+ case LoopFunctions.degreeToRadians:
96
+ res = (k) => a(k)
97
+ .degreeToRadians();
98
+ break;
99
+ case LoopFunctions.radiansToDegrees:
100
+ res = (k) => a(k)
101
+ .radiansToDegrees();
102
+ break;
103
+ case LoopFunctions.radiansToMeters:
104
+ res = (k) => a(k)
105
+ .radiansToMeters();
106
+ break;
107
+ case LoopFunctions.metersToRadians:
108
+ res = (k) => a(k)
109
+ .metersToRadians();
110
+ break;
111
+ case LoopFunctions.hipPoint:
112
+ res = (k) => a(k)
113
+ .hipPoint;
114
+ break;
115
+ case LoopFunctions.xPoint:
116
+ res = (k) => a(k)
117
+ .xPoint;
118
+ break;
119
+ case LoopFunctions.yPoint:
120
+ res = (k) => a(k)
121
+ .yPoint;
122
+ break;
123
+ case LoopFunctions.wPoint:
124
+ res = (k) => a(k)
125
+ .wPoint;
126
+ break;
127
+ case LoopFunctions.hPoint:
128
+ res = (k) => a(k)
129
+ .hPoint;
130
+ break;
131
+ case LoopFunctions.setIfLessThan:
132
+ res = (k) => a(k)
133
+ .setIfLessThan(pointArg);
134
+ break;
135
+ case LoopFunctions.minus:
136
+ res = (k) => a(k)
137
+ .minus();
138
+ break;
139
+ case LoopFunctions.degreeToMeters:
140
+ res = (k) => a(k)
141
+ .degreeToMeters();
142
+ break;
143
+ case LoopFunctions.metersToDegree:
144
+ res = (k) => a(k)
145
+ .metersToDegree();
146
+ break;
147
+ case LoopFunctions.flipVertically:
148
+ res = (k) => a(k)
149
+ .flipVertically(numberPointArg);
150
+ break;
151
+ default:
152
+ }
153
+ return res;
154
+ };
5
155
  class DPolygonLoop {
6
156
  constructor(parent) {
7
- this.f = (k) => k;
8
157
  this.parent = parent;
158
+ this.pool = [];
159
+ }
160
+ getLoopFunction() {
161
+ return this.pool.reduce(decodePoolRecord, (k) => k);
162
+ }
163
+ /**
164
+ * Run loop
165
+ */
166
+ run() {
167
+ return this.parent.map(this.getLoopFunction());
9
168
  }
10
169
  getTileFromCoords(zoom) {
11
- const t = this.f.bind(null);
12
- this.f = (k) => t(k).getTileFromCoords(zoom);
170
+ this.pool.push({
171
+ functionName: LoopFunctions.getTileFromCoords,
172
+ numberArg: zoom
173
+ });
13
174
  return this;
14
175
  }
15
176
  getCoordsFromTile(zoom) {
16
- const t = this.f.bind(null);
17
- this.f = (k) => t(k).getCoordsFromTile(zoom);
18
- return this;
19
- }
20
- transform(from = DPoint_1.PSEUDO_MERCATOR, to = DPoint_1.WORLD_GEODETIC_SYSTEM) {
21
- const t = this.f.bind(null);
22
- this.f = (k) => t(k).transform(from, to);
177
+ this.pool.push({
178
+ functionName: LoopFunctions.getCoordsFromTile,
179
+ numberArg: zoom
180
+ });
23
181
  return this;
24
182
  }
25
183
  height(z) {
26
- const t = this.f.bind(null);
27
- this.f = (k) => t(k).height(z);
184
+ this.pool.push({
185
+ functionName: LoopFunctions.height,
186
+ numberArg: z
187
+ });
28
188
  return this;
29
189
  }
30
190
  setX(x) {
31
- const t = this.f.bind(null);
32
- this.f = (k) => t(k).setX(x);
191
+ this.pool.push({
192
+ functionName: LoopFunctions.setX,
193
+ setterArg: x
194
+ });
33
195
  return this;
34
196
  }
35
197
  setY(y) {
36
- const t = this.f.bind(null);
37
- this.f = (k) => t(k).setY(y);
198
+ this.pool.push({
199
+ functionName: LoopFunctions.setY,
200
+ setterArg: y
201
+ });
38
202
  return this;
39
203
  }
40
204
  rotate(a) {
41
- const t = this.f.bind(null);
42
- this.f = (k) => t(k).rotate(a);
205
+ this.pool.push({
206
+ functionName: LoopFunctions.rotate,
207
+ numberArg: a
208
+ });
43
209
  return this;
44
210
  }
45
- move(x = 0, y) {
46
- const t = this.f.bind(null);
47
- this.f = (k) => t(k).move(x, y);
211
+ move(x = 0, y = x) {
212
+ this.pool.push({
213
+ functionName: LoopFunctions.move,
214
+ numberPointArg: x,
215
+ numberArg: y
216
+ });
48
217
  return this;
49
218
  }
50
219
  round() {
51
- const t = this.f.bind(null);
52
- this.f = (k) => t(k).round();
220
+ this.pool.push({
221
+ functionName: LoopFunctions.round
222
+ });
53
223
  return this;
54
224
  }
55
225
  ceil() {
56
- const t = this.f.bind(null);
57
- this.f = (k) => t(k).ceil();
226
+ this.pool.push({
227
+ functionName: LoopFunctions.ceil
228
+ });
58
229
  return this;
59
230
  }
60
231
  floor() {
61
- const t = this.f.bind(null);
62
- this.f = (k) => t(k).floor();
232
+ this.pool.push({
233
+ functionName: LoopFunctions.floor
234
+ });
63
235
  return this;
64
236
  }
65
237
  toFixed(n = 2) {
66
- const t = this.f.bind(null);
67
- this.f = (k) => t(k).toFixed(n);
238
+ this.pool.push({
239
+ functionName: LoopFunctions.toFixed,
240
+ numberArg: n
241
+ });
68
242
  return this;
69
243
  }
70
244
  abs() {
71
- const t = this.f.bind(null);
72
- this.f = (k) => t(k).abs();
245
+ this.pool.push({
246
+ functionName: LoopFunctions.abs
247
+ });
73
248
  return this;
74
249
  }
75
- scale(x = 0, y) {
76
- const t = this.f.bind(null);
77
- this.f = (k) => t(k).scale(x, y);
250
+ scale(x = 0, y = x) {
251
+ this.pool.push({
252
+ functionName: LoopFunctions.scale,
253
+ numberPointArg: x,
254
+ numberArg: y
255
+ });
78
256
  return this;
79
257
  }
80
258
  divide(x = 0, y) {
81
- const t = this.f.bind(null);
82
- this.f = (k) => t(k).divide(x, y);
259
+ this.pool.push({
260
+ functionName: LoopFunctions.divide,
261
+ numberPointArg: x,
262
+ numberArg: y
263
+ });
264
+ return this;
265
+ }
266
+ degreeToRadians() {
267
+ this.pool.push({
268
+ functionName: LoopFunctions.degreeToRadians
269
+ });
83
270
  return this;
84
271
  }
85
- asRadians() {
86
- const t = this.f.bind(null);
87
- this.f = (k) => t(k).asRadians();
272
+ radiansToDegrees() {
273
+ this.pool.push({
274
+ functionName: LoopFunctions.radiansToDegrees
275
+ });
88
276
  return this;
89
277
  }
90
- asDegrees() {
91
- const t = this.f.bind(null);
92
- this.f = (k) => t(k).asDegrees();
278
+ radiansToMeters() {
279
+ this.pool.push({
280
+ functionName: LoopFunctions.radiansToMeters
281
+ });
282
+ return this;
283
+ }
284
+ metersToRadians() {
285
+ this.pool.push({
286
+ functionName: LoopFunctions.metersToRadians
287
+ });
93
288
  return this;
94
289
  }
95
290
  getHipPoint() {
96
- const t = this.f.bind(null);
97
- this.f = (k) => t(k).hipPoint;
291
+ this.pool.push({
292
+ functionName: LoopFunctions.hipPoint
293
+ });
98
294
  return this;
99
295
  }
100
296
  getXPoint() {
101
- const t = this.f.bind(null);
102
- this.f = (k) => t(k).xPoint;
297
+ this.pool.push({
298
+ functionName: LoopFunctions.xPoint
299
+ });
103
300
  return this;
104
301
  }
105
302
  getYPoint() {
106
- const t = this.f.bind(null);
107
- this.f = (k) => t(k).yPoint;
303
+ this.pool.push({
304
+ functionName: LoopFunctions.yPoint
305
+ });
108
306
  return this;
109
307
  }
110
308
  getWPoint() {
111
- const t = this.f.bind(null);
112
- this.f = (k) => t(k).wPoint;
309
+ this.pool.push({
310
+ functionName: LoopFunctions.wPoint
311
+ });
113
312
  return this;
114
313
  }
115
314
  getHPoint() {
116
- const t = this.f.bind(null);
117
- this.f = (k) => t(k).hPoint;
315
+ this.pool.push({
316
+ functionName: LoopFunctions.hPoint
317
+ });
118
318
  return this;
119
319
  }
120
320
  setIfLessThan(p) {
121
- const t = this.f.bind(null);
122
- this.f = (k) => t(k).setIfLessThan(p);
321
+ this.pool.push({
322
+ functionName: LoopFunctions.setIfLessThan,
323
+ pointArg: p
324
+ });
123
325
  return this;
124
326
  }
125
327
  minus() {
126
- const t = this.f.bind(null);
127
- this.f = (k) => t(k).minus();
328
+ this.pool.push({
329
+ functionName: LoopFunctions.minus
330
+ });
128
331
  return this;
129
332
  }
130
- run() {
131
- this.parent.points = this.parent.points.map(this.f);
132
- return this.parent;
333
+ degreeToMeters() {
334
+ this.pool.push({
335
+ functionName: LoopFunctions.degreeToMeters
336
+ });
337
+ return this;
338
+ }
339
+ metersToDegree() {
340
+ this.pool.push({
341
+ functionName: LoopFunctions.metersToDegree
342
+ });
343
+ return this;
344
+ }
345
+ flipVertically(size) {
346
+ this.pool.push({
347
+ functionName: LoopFunctions.flipVertically,
348
+ numberPointArg: size
349
+ });
350
+ return this;
133
351
  }
134
352
  }
135
353
  exports.DPolygonLoop = DPolygonLoop;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dgeoutils",
3
- "version": "2.0.1",
3
+ "version": "2.2.1",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "build": "node_modules/.bin/tsc",