nodes2ts 1.1.9 → 3.0.0
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/.eslintignore +3 -0
- package/.eslintrc.cjs +11 -0
- package/.github/workflows/lint.js.yml +22 -0
- package/.github/workflows/node.js.yml +22 -0
- package/.mocharc.js +7 -0
- package/README.md +22 -5
- package/dist/Interval.d.ts +7 -8
- package/dist/Interval.js +12 -12
- package/dist/Interval.js.map +1 -1
- package/dist/MutableInteger.js +5 -4
- package/dist/MutableInteger.js.map +1 -1
- package/dist/Platform.d.ts +15 -0
- package/dist/Platform.js +53 -0
- package/dist/Platform.js.map +1 -0
- package/dist/R1Interval.d.ts +8 -9
- package/dist/R1Interval.js +59 -78
- package/dist/R1Interval.js.map +1 -1
- package/dist/R2Vector.d.ts +12 -13
- package/dist/R2Vector.js +65 -85
- package/dist/R2Vector.js.map +1 -1
- package/dist/S1Angle.d.ts +38 -5
- package/dist/S1Angle.js +89 -37
- package/dist/S1Angle.js.map +1 -1
- package/dist/S1ChordAngle.d.ts +166 -0
- package/dist/S1ChordAngle.js +318 -0
- package/dist/S1ChordAngle.js.map +1 -0
- package/dist/S1Interval.d.ts +11 -12
- package/dist/S1Interval.js +134 -140
- package/dist/S1Interval.js.map +1 -1
- package/dist/S2.d.ts +8 -5
- package/dist/S2.js +91 -108
- package/dist/S2.js.map +1 -1
- package/dist/S2Cap.d.ts +33 -25
- package/dist/S2Cap.js +199 -203
- package/dist/S2Cap.js.map +1 -1
- package/dist/S2Cell.d.ts +15 -13
- package/dist/S2Cell.js +196 -206
- package/dist/S2Cell.js.map +1 -1
- package/dist/S2CellId.d.ts +37 -14
- package/dist/S2CellId.js +407 -359
- package/dist/S2CellId.js.map +1 -1
- package/dist/S2CellUnion.d.ts +1 -2
- package/dist/S2CellUnion.js +137 -133
- package/dist/S2CellUnion.js.map +1 -1
- package/dist/S2EdgeUtil.js +14 -17
- package/dist/S2EdgeUtil.js.map +1 -1
- package/dist/S2LatLng.d.ts +15 -11
- package/dist/S2LatLng.js +100 -114
- package/dist/S2LatLng.js.map +1 -1
- package/dist/S2LatLngRect.d.ts +8 -4
- package/dist/S2LatLngRect.js +215 -197
- package/dist/S2LatLngRect.js.map +1 -1
- package/dist/S2Metric.d.ts +4 -5
- package/dist/S2Metric.js +30 -27
- package/dist/S2Metric.js.map +1 -1
- package/dist/S2Point.d.ts +48 -14
- package/dist/S2Point.js +156 -109
- package/dist/S2Point.js.map +1 -1
- package/dist/S2Projections.d.ts +43 -9
- package/dist/S2Projections.js +226 -47
- package/dist/S2Projections.js.map +1 -1
- package/dist/S2Region.js +2 -1
- package/dist/S2Region.js.map +1 -1
- package/dist/S2RegionCoverer.d.ts +21 -6
- package/dist/S2RegionCoverer.js +144 -109
- package/dist/S2RegionCoverer.js.map +1 -1
- package/dist/export.d.ts +0 -1
- package/dist/export.js +42 -32
- package/dist/export.js.map +1 -1
- package/dist/utils/preconditions.d.ts +2 -0
- package/dist/utils/preconditions.js +16 -0
- package/dist/utils/preconditions.js.map +1 -0
- package/package.json +28 -34
- package/.npmignore +0 -8
- package/.nyc_output/1eb1f420a13c15f529aac41a40bcaa21.json +0 -1
- package/.nyc_output/5ff62256eb1c111254ba0b469fb547da.json +0 -1
- package/.nyc_output/949d6e8c2061067f3bdfd27dfff5ba83.json +0 -1
- package/coverage/Interval.ts.html +0 -203
- package/coverage/MutableInteger.ts.html +0 -77
- package/coverage/R1Interval.ts.html +0 -647
- package/coverage/R2Vector.ts.html +0 -587
- package/coverage/S1Angle.ts.html +0 -344
- package/coverage/S1Interval.ts.html +0 -1349
- package/coverage/S2.ts.html +0 -1178
- package/coverage/S2Cap.ts.html +0 -1433
- package/coverage/S2Cell.ts.html +0 -1415
- package/coverage/S2CellId.ts.html +0 -3329
- package/coverage/S2EdgeUtil.ts.html +0 -2534
- package/coverage/S2LatLng.ts.html +0 -848
- package/coverage/S2LatLngRect.ts.html +0 -2222
- package/coverage/S2Point.ts.html +0 -758
- package/coverage/S2Projections.ts.html +0 -518
- package/coverage/base.css +0 -212
- package/coverage/decimal.ts.html +0 -68
- package/coverage/index.html +0 -288
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -1
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -158
- package/dist/decimal.d.ts +0 -3
- package/dist/decimal.js +0 -4
- package/dist/decimal.js.map +0 -1
- package/dist/decimal_augmentation.d.ts +0 -24
- package/dist/decimal_augmentation.js +0 -2
- package/dist/decimal_augmentation.js.map +0 -1
package/dist/S2LatLngRect.js
CHANGED
|
@@ -1,47 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.S2LatLngRect = void 0;
|
|
4
|
+
const S1Interval_1 = require("./S1Interval");
|
|
5
|
+
const R1Interval_1 = require("./R1Interval");
|
|
6
|
+
const S2LatLng_1 = require("./S2LatLng");
|
|
7
|
+
const S2_1 = require("./S2");
|
|
8
|
+
const S2Point_1 = require("./S2Point");
|
|
9
|
+
const S1Angle_1 = require("./S1Angle");
|
|
10
|
+
const S2EdgeUtil_1 = require("./S2EdgeUtil");
|
|
11
|
+
const S2Cap_1 = require("./S2Cap");
|
|
12
|
+
const Platform_1 = require("./Platform");
|
|
13
|
+
class S2LatLngRect {
|
|
14
|
+
constructor(lat, lng) {
|
|
13
15
|
this.lat = lat;
|
|
14
16
|
this.lng = lng;
|
|
15
17
|
}
|
|
16
|
-
|
|
18
|
+
static fromLatLng(lo, hi) {
|
|
17
19
|
return new S2LatLngRect(new R1Interval_1.R1Interval(lo.latRadians, hi.latRadians), new S1Interval_1.S1Interval(lo.lngRadians, hi.lngRadians));
|
|
18
|
-
}
|
|
20
|
+
}
|
|
19
21
|
/** The canonical empty rectangle */
|
|
20
|
-
|
|
22
|
+
static empty() {
|
|
21
23
|
return new S2LatLngRect(R1Interval_1.R1Interval.empty(), S1Interval_1.S1Interval.empty());
|
|
22
|
-
}
|
|
24
|
+
}
|
|
23
25
|
/** The canonical full rectangle. */
|
|
24
|
-
|
|
26
|
+
static full() {
|
|
25
27
|
return new S2LatLngRect(S2LatLngRect.fullLat(), S1Interval_1.S1Interval.full());
|
|
26
|
-
}
|
|
28
|
+
}
|
|
27
29
|
/** The full allowable range of latitudes. */
|
|
28
|
-
|
|
30
|
+
static fullLat() {
|
|
29
31
|
return new R1Interval_1.R1Interval(-S2_1.S2.M_PI_2, S2_1.S2.M_PI_2);
|
|
30
|
-
}
|
|
32
|
+
}
|
|
31
33
|
/**
|
|
32
34
|
* Construct a rectangle from a center point (in lat-lng space) and size in
|
|
33
35
|
* each dimension. If size.lng is greater than 360 degrees it is clamped,
|
|
34
36
|
* and latitudes greater than +/- 90 degrees are also clamped. So for example,
|
|
35
37
|
* FromCenterSize((80,170),(20,20)) -> (lo=(60,150),hi=(90,-170)).
|
|
36
38
|
*/
|
|
37
|
-
|
|
39
|
+
static fromCenterSize(center, size) {
|
|
38
40
|
return S2LatLngRect.fromPoint(center).expanded(size.mul(0.5));
|
|
39
|
-
}
|
|
41
|
+
}
|
|
40
42
|
/** Convenience method to construct a rectangle containing a single point. */
|
|
41
|
-
|
|
43
|
+
static fromPoint(p) {
|
|
42
44
|
// assert (p.isValid());
|
|
43
45
|
return S2LatLngRect.fromLatLng(p, p);
|
|
44
|
-
}
|
|
46
|
+
}
|
|
45
47
|
/**
|
|
46
48
|
* Convenience method to construct the minimal bounding rectangle containing
|
|
47
49
|
* the two given points. This is equivalent to starting with an empty
|
|
@@ -49,80 +51,92 @@ var S2LatLngRect = (function () {
|
|
|
49
51
|
* S2LatLngRect(lo, hi) constructor, where the first point is always used as
|
|
50
52
|
* the lower-left corner of the resulting rectangle.
|
|
51
53
|
*/
|
|
52
|
-
|
|
54
|
+
static fromPointPair(p1, p2) {
|
|
53
55
|
// assert (p1.isValid() && p2.isValid());
|
|
54
56
|
return new S2LatLngRect(R1Interval_1.R1Interval.fromPointPair(p1.latRadians, p2
|
|
55
57
|
.latRadians), S1Interval_1.S1Interval.fromPointPair(p1.lngRadians, p2.lngRadians));
|
|
56
|
-
}
|
|
58
|
+
}
|
|
57
59
|
/**
|
|
58
60
|
* Return a latitude-longitude rectangle that contains the edge from "a" to
|
|
59
61
|
* "b". Both points must be unit-length. Note that the bounding rectangle of
|
|
60
62
|
* an edge can be larger than the bounding rectangle of its endpoints.
|
|
61
63
|
*/
|
|
62
|
-
|
|
64
|
+
static fromEdge(a, b) {
|
|
63
65
|
// assert (S2.isUnitLength(a) && S2.isUnitLength(b));
|
|
64
|
-
|
|
66
|
+
const r = S2LatLngRect.fromPointPair(S2LatLng_1.S2LatLng.fromPoint(a), S2LatLng_1.S2LatLng.fromPoint(b));
|
|
65
67
|
// Check whether the min/max latitude occurs in the edge interior.
|
|
66
68
|
// We find the normal to the plane containing AB, and then a vector "dir" in
|
|
67
69
|
// this plane that also passes through the equator. We use RobustCrossProd
|
|
68
70
|
// to ensure that the edge normal is accurate even when the two points are
|
|
69
71
|
// very close together.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (da
|
|
72
|
+
const ab = S2_1.S2.robustCrossProd(a, b);
|
|
73
|
+
const dir = S2Point_1.S2Point.crossProd(ab, new S2Point_1.S2Point(0, 0, 1));
|
|
74
|
+
const da = dir.dotProd(a);
|
|
75
|
+
const db = dir.dotProd(b);
|
|
76
|
+
if (da * db >= 0) {
|
|
75
77
|
// Minimum and maximum latitude are attained at the vertices.
|
|
76
78
|
return r;
|
|
77
79
|
}
|
|
78
80
|
// Minimum/maximum latitude occurs in the edge interior. This affects the
|
|
79
81
|
// latitude bounds but not the longitude bounds.
|
|
80
|
-
|
|
81
|
-
if (da
|
|
82
|
+
const absLat = Math.acos(ab.z / Math.abs(ab.norm()));
|
|
83
|
+
if (da < 0) {
|
|
82
84
|
return new S2LatLngRect(new R1Interval_1.R1Interval(r.lat.lo, absLat), r.lng);
|
|
83
85
|
}
|
|
84
86
|
else {
|
|
85
87
|
return new S2LatLngRect(new R1Interval_1.R1Interval(-absLat, r.lat.hi), r.lng);
|
|
86
88
|
}
|
|
87
|
-
}
|
|
89
|
+
}
|
|
88
90
|
/**
|
|
89
91
|
* Return true if the rectangle is valid, which essentially just means that
|
|
90
92
|
* the latitude bounds do not exceed Pi/2 in absolute value and the longitude
|
|
91
93
|
* bounds do not exceed Pi in absolute value.
|
|
92
94
|
*
|
|
93
95
|
*/
|
|
94
|
-
|
|
96
|
+
isValid() {
|
|
95
97
|
// The lat/lng ranges must either be both empty or both non-empty.
|
|
96
|
-
return (this.lat.lo
|
|
98
|
+
return (Math.abs(this.lat.lo) <= S2_1.S2.M_PI_2 && Math.abs(this.lat.hi) <= (S2_1.S2.M_PI_2)
|
|
97
99
|
&& this.lng.isValid() && this.lat.isEmpty() == this.lng.isEmpty());
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
+
}
|
|
101
|
+
lo() {
|
|
100
102
|
return new S2LatLng_1.S2LatLng(this.lat.lo, this.lng.lo);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
+
}
|
|
104
|
+
hi() {
|
|
103
105
|
return new S2LatLng_1.S2LatLng(this.lat.hi, this.lng.hi);
|
|
104
|
-
}
|
|
106
|
+
}
|
|
107
|
+
latLo() {
|
|
108
|
+
return S1Angle_1.S1Angle.radians(this.lat.lo);
|
|
109
|
+
}
|
|
110
|
+
latHi() {
|
|
111
|
+
return S1Angle_1.S1Angle.radians(this.lat.hi);
|
|
112
|
+
}
|
|
113
|
+
lngLo() {
|
|
114
|
+
return S1Angle_1.S1Angle.radians(this.lng.lo);
|
|
115
|
+
}
|
|
116
|
+
lngHi() {
|
|
117
|
+
return S1Angle_1.S1Angle.radians(this.lng.hi);
|
|
118
|
+
}
|
|
105
119
|
/**
|
|
106
120
|
* Return true if the rectangle is empty, i.e. it contains no points at all.
|
|
107
121
|
*/
|
|
108
|
-
|
|
122
|
+
isEmpty() {
|
|
109
123
|
return this.lat.isEmpty();
|
|
110
|
-
}
|
|
124
|
+
}
|
|
111
125
|
// Return true if the rectangle is full, i.e. it contains all points.
|
|
112
|
-
|
|
126
|
+
isFull() {
|
|
113
127
|
// console.log(this.lat.toString());
|
|
114
128
|
// console.log(S2LatLngRect.fullLat().toString());
|
|
115
129
|
return this.lat.equals(S2LatLngRect.fullLat()) && this.lng.isFull();
|
|
116
|
-
}
|
|
130
|
+
}
|
|
117
131
|
/**
|
|
118
132
|
* Return true if lng_.lo() > lng_.hi(), i.e. the rectangle crosses the 180
|
|
119
133
|
* degree latitude line.
|
|
120
134
|
*/
|
|
121
|
-
|
|
135
|
+
isInverted() {
|
|
122
136
|
return this.lng.isInverted();
|
|
123
|
-
}
|
|
137
|
+
}
|
|
124
138
|
/** Return the k-th vertex of the rectangle (k = 0,1,2,3) in CCW order. */
|
|
125
|
-
|
|
139
|
+
getVertex(k) {
|
|
126
140
|
// Return the points in CCW order (SW, SE, NE, NW).
|
|
127
141
|
switch (k) {
|
|
128
142
|
case 0:
|
|
@@ -136,87 +150,85 @@ var S2LatLngRect = (function () {
|
|
|
136
150
|
default:
|
|
137
151
|
throw new Error("Invalid vertex index.");
|
|
138
152
|
}
|
|
139
|
-
}
|
|
153
|
+
}
|
|
140
154
|
/**
|
|
141
155
|
* Return the center of the rectangle in latitude-longitude space (in general
|
|
142
156
|
* this is not the center of the region on the sphere).
|
|
143
157
|
*/
|
|
144
|
-
|
|
158
|
+
getCenter() {
|
|
145
159
|
return new S2LatLng_1.S2LatLng(this.lat.getCenter(), this.lng.getCenter());
|
|
146
|
-
}
|
|
160
|
+
}
|
|
147
161
|
/**
|
|
148
162
|
* Return the minimum distance (measured along the surface of the sphere)
|
|
149
163
|
* from a given point to the rectangle (both its boundary and its interior).
|
|
150
164
|
* The latLng must be valid.
|
|
151
165
|
*/
|
|
152
|
-
|
|
166
|
+
getDistanceLL(p) {
|
|
153
167
|
// The algorithm here is the same as in getDistance(S2LagLngRect), only
|
|
154
168
|
// with simplified calculations.
|
|
155
|
-
|
|
156
|
-
if (a.isEmpty()) {
|
|
169
|
+
if (this.isEmpty()) {
|
|
157
170
|
throw new Error();
|
|
158
171
|
}
|
|
159
172
|
if (!p.isValid()) {
|
|
160
173
|
throw new Error('point is not valid');
|
|
161
174
|
}
|
|
162
|
-
if (
|
|
163
|
-
return new S1Angle_1.S1Angle(
|
|
175
|
+
if (this.lng.contains(p.lngRadians)) {
|
|
176
|
+
return new S1Angle_1.S1Angle(Math.max(0.0, Math.max(p.latRadians - this.lat.hi, this.lat.lo - p.latRadians)));
|
|
164
177
|
}
|
|
165
|
-
|
|
166
|
-
|
|
178
|
+
const interval = new S1Interval_1.S1Interval(this.lng.hi, this.lng.complement().getCenter());
|
|
179
|
+
let aLng = this.lng.lo;
|
|
167
180
|
if (interval.contains(p.lngRadians)) {
|
|
168
|
-
aLng =
|
|
181
|
+
aLng = this.lng.hi;
|
|
169
182
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
183
|
+
const lo = new S2LatLng_1.S2LatLng(this.lat.lo, aLng).toPoint();
|
|
184
|
+
const hi = new S2LatLng_1.S2LatLng(this.lat.hi, aLng).toPoint();
|
|
185
|
+
const loCrossHi = new S2LatLng_1.S2LatLng(0, aLng - S2_1.S2.M_PI_2).normalized().toPoint();
|
|
173
186
|
return S2EdgeUtil_1.S2EdgeUtil.getDistance(p.toPoint(), lo, hi, loCrossHi);
|
|
174
|
-
}
|
|
187
|
+
}
|
|
175
188
|
/**
|
|
176
189
|
* Return the minimum distance (measured along the surface of the sphere) to
|
|
177
190
|
* the given S2LatLngRect. Both S2LatLngRects must be non-empty.
|
|
178
191
|
*/
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if (a.isEmpty()) {
|
|
192
|
+
getDistanceLLR(other) {
|
|
193
|
+
const b = other;
|
|
194
|
+
if (this.isEmpty()) {
|
|
183
195
|
throw new Error();
|
|
184
196
|
}
|
|
185
197
|
if (b.isEmpty()) {
|
|
186
198
|
throw new Error();
|
|
187
199
|
}
|
|
188
200
|
// First, handle the trivial cases where the longitude intervals overlap.
|
|
189
|
-
if (
|
|
190
|
-
if (
|
|
201
|
+
if (this.lng.intersects(b.lng)) {
|
|
202
|
+
if (this.lat.intersects(b.lat)) {
|
|
191
203
|
return new S1Angle_1.S1Angle(0); // Intersection between a and b.
|
|
192
204
|
}
|
|
193
205
|
// We found an overlap in the longitude interval, but not in the latitude
|
|
194
206
|
// interval. This means the shortest path travels along some line of
|
|
195
207
|
// longitude connecting the high-latitude of the lower rect with the
|
|
196
208
|
// low-latitude of the higher rect.
|
|
197
|
-
|
|
198
|
-
if (
|
|
209
|
+
let lo, hi;
|
|
210
|
+
if (this.lat.lo > b.lat.hi) {
|
|
199
211
|
lo = b.lat.hi;
|
|
200
|
-
hi =
|
|
212
|
+
hi = this.lat.lo;
|
|
201
213
|
}
|
|
202
214
|
else {
|
|
203
|
-
lo =
|
|
215
|
+
lo = this.lat.hi;
|
|
204
216
|
hi = b.lat.lo;
|
|
205
217
|
}
|
|
206
|
-
return
|
|
218
|
+
return S1Angle_1.S1Angle.radians(hi.radians() - lo.radians());
|
|
207
219
|
}
|
|
208
220
|
// The longitude intervals don't overlap. In this case, the closest points
|
|
209
221
|
// occur somewhere on the pair of longitudinal edges which are nearest in
|
|
210
222
|
// longitude-space.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (loHi.getLength()
|
|
215
|
-
aLng =
|
|
223
|
+
let aLng, bLng;
|
|
224
|
+
const loHi = S1Interval_1.S1Interval.fromPointPair(this.lng.lo, b.lng.hi);
|
|
225
|
+
const hiLo = S1Interval_1.S1Interval.fromPointPair(this.lng.hi, b.lng.lo);
|
|
226
|
+
if (loHi.getLength() < (hiLo.getLength())) {
|
|
227
|
+
aLng = this.lng.lo;
|
|
216
228
|
bLng = b.lng.hi;
|
|
217
229
|
}
|
|
218
230
|
else {
|
|
219
|
-
aLng =
|
|
231
|
+
aLng = this.lng.hi;
|
|
220
232
|
bLng = b.lng.lo;
|
|
221
233
|
}
|
|
222
234
|
// The shortest distance between the two longitudinal segments will include
|
|
@@ -224,78 +236,78 @@ var S2LatLngRect = (function () {
|
|
|
224
236
|
// to a single point-edge distance by comparing the relative latitudes of the
|
|
225
237
|
// endpoints, but for the sake of clarity, we'll do all four point-edge
|
|
226
238
|
// distance tests.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
239
|
+
const aLo = new S2LatLng_1.S2LatLng(this.lat.lo, aLng).toPoint();
|
|
240
|
+
const aHi = new S2LatLng_1.S2LatLng(this.lat.hi, aLng).toPoint();
|
|
241
|
+
const aLoCrossHi = new S2LatLng_1.S2LatLng(0, aLng.radians().minus(S2_1.S2.M_PI_2)).normalized().toPoint();
|
|
242
|
+
const bLo = new S2LatLng_1.S2LatLng(b.lat.lo, bLng).toPoint();
|
|
243
|
+
const bHi = new S2LatLng_1.S2LatLng(b.lat.hi, bLng).toPoint();
|
|
244
|
+
const bLoCrossHi = new S2LatLng_1.S2LatLng(0, bLng.radians().minus(S2_1.S2.M_PI_2)).normalized().toPoint();
|
|
233
245
|
return S1Angle_1.S1Angle.min(S2EdgeUtil_1.S2EdgeUtil.getDistance(aLo, bLo, bHi, bLoCrossHi), S1Angle_1.S1Angle.min(S2EdgeUtil_1.S2EdgeUtil.getDistance(aHi, bLo, bHi, bLoCrossHi), S1Angle_1.S1Angle.min(S2EdgeUtil_1.S2EdgeUtil.getDistance(bLo, aLo, aHi, aLoCrossHi), S2EdgeUtil_1.S2EdgeUtil.getDistance(bHi, aLo, aHi, aLoCrossHi))));
|
|
234
|
-
}
|
|
246
|
+
}
|
|
235
247
|
/**
|
|
236
248
|
* Return the width and height of this rectangle in latitude-longitude space.
|
|
237
249
|
* Empty rectangles have a negative width and height.
|
|
238
250
|
*/
|
|
239
|
-
|
|
251
|
+
getSize() {
|
|
240
252
|
return new S2LatLng_1.S2LatLng(this.lat.getLength(), this.lng.getLength());
|
|
241
|
-
}
|
|
253
|
+
}
|
|
242
254
|
/**
|
|
243
255
|
* More efficient version of Contains() that accepts a S2LatLng rather than an
|
|
244
256
|
* S2Point.
|
|
245
257
|
*/
|
|
246
|
-
|
|
258
|
+
containsLL(ll) {
|
|
247
259
|
// assert (ll.isValid());
|
|
248
260
|
return (this.lat.contains(ll.latRadians) && this.lng.contains(ll.lngRadians));
|
|
249
|
-
}
|
|
261
|
+
}
|
|
250
262
|
/**
|
|
251
263
|
* Return true if and only if the given point is contained in the interior of
|
|
252
264
|
* the region (i.e. the region excluding its boundary). The point 'p' does not
|
|
253
265
|
* need to be normalized.
|
|
254
266
|
*/
|
|
255
|
-
|
|
267
|
+
interiorContainsP(p) {
|
|
256
268
|
return this.interiorContainsLL(S2LatLng_1.S2LatLng.fromPoint(p));
|
|
257
|
-
}
|
|
269
|
+
}
|
|
258
270
|
/**
|
|
259
271
|
* More efficient version of InteriorContains() that accepts a S2LatLng rather
|
|
260
272
|
* than an S2Point.
|
|
261
273
|
*/
|
|
262
|
-
|
|
274
|
+
interiorContainsLL(ll) {
|
|
263
275
|
// assert (ll.isValid());
|
|
264
276
|
return (this.lat.interiorContains(ll.latRadians) && this.lng
|
|
265
277
|
.interiorContains(ll.lngRadians));
|
|
266
|
-
}
|
|
278
|
+
}
|
|
267
279
|
/**
|
|
268
280
|
* Return true if and only if the rectangle contains the given other
|
|
269
281
|
* rectangle.
|
|
270
282
|
*/
|
|
271
|
-
|
|
283
|
+
containsLLR(other) {
|
|
272
284
|
return this.lat.containsI(other.lat) && this.lng.containsI(other.lng);
|
|
273
|
-
}
|
|
285
|
+
}
|
|
274
286
|
/**
|
|
275
287
|
* Return true if and only if the interior of this rectangle contains all
|
|
276
288
|
* points of the given other rectangle (including its boundary).
|
|
277
289
|
*/
|
|
278
|
-
|
|
290
|
+
interiorContainsLLR(other) {
|
|
279
291
|
return (this.lat.interiorContainsI(other.lat) && this.lng
|
|
280
292
|
.interiorContainsI(other.lng));
|
|
281
|
-
}
|
|
293
|
+
}
|
|
282
294
|
/** Return true if this rectangle and the given other rectangle have any
|
|
283
295
|
points in common. */
|
|
284
|
-
|
|
296
|
+
intersectsLLR(other) {
|
|
285
297
|
return this.lat.intersects(other.lat) && this.lng.intersects(other.lng);
|
|
286
|
-
}
|
|
298
|
+
}
|
|
287
299
|
/**
|
|
288
300
|
* Returns true if this rectangle intersects the given cell. (This is an exact
|
|
289
301
|
* test and may be fairly expensive, see also MayIntersect below.)
|
|
290
302
|
*/
|
|
291
|
-
|
|
303
|
+
intersects(cell) {
|
|
292
304
|
// First we eliminate the cases where one region completely contains the
|
|
293
305
|
// other. Once these are disposed of, then the regions will intersect
|
|
294
306
|
// if and only if their boundaries intersect.
|
|
295
307
|
if (this.isEmpty()) {
|
|
296
308
|
return false;
|
|
297
309
|
}
|
|
298
|
-
if (this.containsP(cell.
|
|
310
|
+
if (this.containsP(cell.getCenterRaw())) {
|
|
299
311
|
return true;
|
|
300
312
|
}
|
|
301
313
|
if (cell.contains(this.getCenter().toPoint())) {
|
|
@@ -309,22 +321,22 @@ var S2LatLngRect = (function () {
|
|
|
309
321
|
// latitude-longitude rectangle does not have straight edges -- two edges
|
|
310
322
|
// are curved, and at least one of them is concave.
|
|
311
323
|
// Precompute the cell vertices as points and latitude-longitudes.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
for (
|
|
324
|
+
const cellV = new Array(4);
|
|
325
|
+
const cellLl = new Array(4);
|
|
326
|
+
for (let i = 0; i < 4; ++i) {
|
|
315
327
|
cellV[i] = cell.getVertex(i); // Must be normalized.
|
|
316
328
|
cellLl[i] = S2LatLng_1.S2LatLng.fromPoint(cellV[i]);
|
|
317
329
|
if (this.containsLL(cellLl[i])) {
|
|
318
330
|
return true; // Quick acceptance test.
|
|
319
331
|
}
|
|
320
332
|
}
|
|
321
|
-
for (
|
|
322
|
-
|
|
333
|
+
for (let i = 0; i < 4; ++i) {
|
|
334
|
+
const edgeLng = S1Interval_1.S1Interval.fromPointPair(cellLl[i].lngRadians, cellLl[(i + 1) & 3].lngRadians);
|
|
323
335
|
if (!this.lng.intersects(edgeLng)) {
|
|
324
336
|
continue;
|
|
325
337
|
}
|
|
326
|
-
|
|
327
|
-
|
|
338
|
+
const a = cellV[i];
|
|
339
|
+
const b = cellV[(i + 1) & 3];
|
|
328
340
|
if (edgeLng.contains(this.lng.lo)) {
|
|
329
341
|
if (S2LatLngRect.intersectsLngEdge(a, b, this.lat, this.lng.lo)) {
|
|
330
342
|
return true;
|
|
@@ -343,25 +355,25 @@ var S2LatLngRect = (function () {
|
|
|
343
355
|
}
|
|
344
356
|
}
|
|
345
357
|
return false;
|
|
346
|
-
}
|
|
358
|
+
}
|
|
347
359
|
/**
|
|
348
360
|
* Return true if and only if the interior of this rectangle intersects any
|
|
349
361
|
* point (including the boundary) of the given other rectangle.
|
|
350
362
|
*/
|
|
351
|
-
|
|
363
|
+
interiorIntersects(other) {
|
|
352
364
|
return (this.lat.interiorIntersects(other.lat) && this.lng
|
|
353
365
|
.interiorIntersects(other.lng));
|
|
354
|
-
}
|
|
355
|
-
|
|
366
|
+
}
|
|
367
|
+
addPoint(p) {
|
|
356
368
|
return this.addPointLL(S2LatLng_1.S2LatLng.fromPoint(p));
|
|
357
|
-
}
|
|
369
|
+
}
|
|
358
370
|
// Increase the size of the bounding rectangle to include the given point.
|
|
359
371
|
// The rectangle is expanded by the minimum amount possible.
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
372
|
+
addPointLL(ll) {
|
|
373
|
+
const newLat = this.lat.addPoint(ll.latRadians);
|
|
374
|
+
const newLng = this.lng.addPoint(ll.lngRadians);
|
|
363
375
|
return new S2LatLngRect(newLat, newLng);
|
|
364
|
-
}
|
|
376
|
+
}
|
|
365
377
|
/**
|
|
366
378
|
* Return a rectangle that contains all points whose latitude distance from
|
|
367
379
|
* this rectangle is at most margin.lat, and whose longitude distance from
|
|
@@ -373,7 +385,7 @@ var S2LatLngRect = (function () {
|
|
|
373
385
|
* NOTE: If you are trying to grow a rectangle by a certain *distance* on the
|
|
374
386
|
* sphere (e.g. 5km), use the ConvolveWithCap() method instead.
|
|
375
387
|
*/
|
|
376
|
-
|
|
388
|
+
expanded(margin) {
|
|
377
389
|
// assert (margin.latRadians >= 0 && margin.lngRadians >= 0);
|
|
378
390
|
if (this.isEmpty()) {
|
|
379
391
|
return this;
|
|
@@ -381,29 +393,37 @@ var S2LatLngRect = (function () {
|
|
|
381
393
|
return new S2LatLngRect(this.lat
|
|
382
394
|
.expanded(margin.latRadians)
|
|
383
395
|
.intersection(S2LatLngRect.fullLat()), this.lng.expanded(margin.lngRadians));
|
|
384
|
-
}
|
|
396
|
+
}
|
|
397
|
+
polarClosure() {
|
|
398
|
+
if (this.lat.lo == -S2_1.S2.M_PI_2 || this.lat.hi == S2_1.S2.M_PI_2) {
|
|
399
|
+
return new S2LatLngRect(this.lat, S1Interval_1.S1Interval.full());
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
return this;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
385
405
|
/**
|
|
386
406
|
* Return the smallest rectangle containing the union of this rectangle and
|
|
387
407
|
* the given rectangle.
|
|
388
408
|
*/
|
|
389
|
-
|
|
409
|
+
union(other) {
|
|
390
410
|
return new S2LatLngRect(this.lat.union(other.lat), this.lng.union(other.lng));
|
|
391
|
-
}
|
|
411
|
+
}
|
|
392
412
|
/**
|
|
393
413
|
* Return the smallest rectangle containing the intersection of this rectangle
|
|
394
414
|
* and the given rectangle. Note that the region of intersection may consist
|
|
395
415
|
* of two disjoint rectangles, in which case a single rectangle spanning both
|
|
396
416
|
* of them is returned.
|
|
397
417
|
*/
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
418
|
+
intersection(other) {
|
|
419
|
+
const intersectLat = this.lat.intersection(other.lat);
|
|
420
|
+
const intersectLng = this.lng.intersection(other.lng);
|
|
401
421
|
if (intersectLat.isEmpty() || intersectLng.isEmpty()) {
|
|
402
422
|
// The lat/lng ranges must either be both empty or both non-empty.
|
|
403
423
|
return S2LatLngRect.empty();
|
|
404
424
|
}
|
|
405
425
|
return new S2LatLngRect(intersectLat, intersectLng);
|
|
406
|
-
}
|
|
426
|
+
}
|
|
407
427
|
//
|
|
408
428
|
// /**
|
|
409
429
|
// * Return a rectangle that contains the convolution of this rectangle with a
|
|
@@ -429,80 +449,79 @@ var S2LatLngRect = (function () {
|
|
|
429
449
|
// return r;
|
|
430
450
|
// }
|
|
431
451
|
/** Return the surface area of this rectangle on the unit sphere. */
|
|
432
|
-
|
|
452
|
+
area() {
|
|
433
453
|
if (this.isEmpty()) {
|
|
434
|
-
return
|
|
454
|
+
return 0;
|
|
435
455
|
}
|
|
436
456
|
// This is the size difference of the two spherical caps, multiplied by
|
|
437
457
|
// the longitude ratio.
|
|
438
|
-
//TODO: check if this.lat.hi & this.lat.lo is radians.
|
|
439
|
-
return this.lng.getLength()
|
|
440
|
-
}
|
|
458
|
+
//TODO: check if this.lat.hi & this.lat.lo is radians.
|
|
459
|
+
return this.lng.getLength() * (Math.sin(this.lat.hi) - Math.abs(Math.sin(this.lat.lo)));
|
|
460
|
+
}
|
|
441
461
|
/** Return true if two rectangles contains the same set of points. */
|
|
442
|
-
|
|
462
|
+
equals(that) {
|
|
443
463
|
if (!(that instanceof S2LatLngRect)) {
|
|
444
464
|
return false;
|
|
445
465
|
}
|
|
446
466
|
return this.lat.equals(that.lat) && this.lng.equals(that.lng);
|
|
447
|
-
}
|
|
467
|
+
}
|
|
448
468
|
/**
|
|
449
469
|
* Return true if the latitude and longitude intervals of the two rectangles
|
|
450
470
|
* are the same up to the given tolerance (see r1interval.h and s1interval.h
|
|
451
471
|
* for details).
|
|
452
472
|
*/
|
|
453
|
-
|
|
454
|
-
if (maxError === void 0) { maxError = 1e-15; }
|
|
473
|
+
approxEquals(other, maxError = 1e-15) {
|
|
455
474
|
return (this.lat.approxEquals(other.lat, maxError) && this.lng.approxEquals(other.lng, maxError));
|
|
456
|
-
}
|
|
475
|
+
}
|
|
457
476
|
// //////////////////////////////////////////////////////////////////////
|
|
458
477
|
// S2Region interface (see {@code S2Region} for details):
|
|
459
|
-
|
|
478
|
+
clone() {
|
|
460
479
|
return new S2LatLngRect(this.lat, this.lng);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// We consider two possible bounding caps, one whose axis passes
|
|
464
|
-
//
|
|
465
|
-
//
|
|
480
|
+
}
|
|
481
|
+
getCapBound() {
|
|
482
|
+
// We consider two possible bounding caps, one whose axis passes through the center of the
|
|
483
|
+
// lat-lng rectangle and one whose axis is the north or south pole. We return the smaller of the
|
|
484
|
+
// two caps.
|
|
466
485
|
if (this.isEmpty()) {
|
|
467
486
|
return S2Cap_1.S2Cap.empty();
|
|
468
487
|
}
|
|
469
|
-
|
|
470
|
-
|
|
488
|
+
let poleZ = 0;
|
|
489
|
+
let poleAngle = 0;
|
|
490
|
+
if (this.lat.lo + this.lat.hi < 0) {
|
|
471
491
|
// South pole axis yields smaller cap.
|
|
472
492
|
poleZ = -1;
|
|
473
|
-
poleAngle = this.lat.hi
|
|
493
|
+
poleAngle = S2_1.S2.M_PI_2 + this.lat.hi;
|
|
474
494
|
}
|
|
475
495
|
else {
|
|
476
496
|
poleZ = 1;
|
|
477
|
-
poleAngle = this.lat.lo
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
// For bounding rectangles that span 180 degrees or less in longitude, the
|
|
481
|
-
//
|
|
482
|
-
//
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
for (var k = 0; k < 4; ++k) {
|
|
497
|
+
poleAngle = S2_1.S2.M_PI_2 - this.lat.lo;
|
|
498
|
+
}
|
|
499
|
+
const poleCap = S2Cap_1.S2Cap.fromAxisAngle(new S2Point_1.S2Point(0, 0, poleZ), S1Angle_1.S1Angle.radians(poleAngle));
|
|
500
|
+
// For bounding rectangles that span 180 degrees or less in longitude, the maximum cap size is
|
|
501
|
+
// achieved at one of the rectangle vertices. For rectangles that are larger than 180 degrees,
|
|
502
|
+
// we punt and always return a bounding cap centered at one of the two poles.
|
|
503
|
+
const lngSpan = this.lng.hi - this.lng.lo;
|
|
504
|
+
if (Platform_1.Platform.IEEEremainder(lngSpan, 2 * S2_1.S2.M_PI) >= 0) {
|
|
505
|
+
if (lngSpan < 2 * S2_1.S2.M_PI) {
|
|
506
|
+
let midCap = S2Cap_1.S2Cap.fromAxisAngle(this.getCenter().toPoint(), S1Angle_1.S1Angle.radians(0));
|
|
507
|
+
for (let k = 0; k < 4; ++k) {
|
|
489
508
|
midCap = midCap.addPoint(this.getVertex(k).toPoint());
|
|
490
509
|
}
|
|
491
|
-
if (midCap.height
|
|
510
|
+
if (midCap.height() < poleCap.height()) {
|
|
492
511
|
return midCap;
|
|
493
512
|
}
|
|
494
513
|
}
|
|
495
514
|
}
|
|
496
515
|
return poleCap;
|
|
497
|
-
}
|
|
498
|
-
|
|
516
|
+
}
|
|
517
|
+
getRectBound() {
|
|
499
518
|
return this;
|
|
500
|
-
}
|
|
501
|
-
|
|
519
|
+
}
|
|
520
|
+
containsC(cell) {
|
|
502
521
|
// A latitude-longitude rectangle contains a cell if and only if it contains
|
|
503
522
|
// the cell's bounding rectangle. (This is an exact test.)
|
|
504
523
|
return this.containsLLR(cell.getRectBound());
|
|
505
|
-
}
|
|
524
|
+
}
|
|
506
525
|
/**
|
|
507
526
|
* This test is cheap but is NOT exact. Use Intersects() if you want a more
|
|
508
527
|
* accurate and more expensive test. Note that when this method is used by an
|
|
@@ -510,97 +529,96 @@ var S2LatLngRect = (function () {
|
|
|
510
529
|
* intersect the region then it is subdivided, and the accuracy of this method
|
|
511
530
|
* goes up as the cells get smaller.
|
|
512
531
|
*/
|
|
513
|
-
|
|
532
|
+
mayIntersectC(cell) {
|
|
514
533
|
// This test is cheap but is NOT exact (see s2latlngrect.h).
|
|
515
534
|
return this.intersectsLLR(cell.getRectBound());
|
|
516
|
-
}
|
|
535
|
+
}
|
|
517
536
|
/** The point 'p' does not need to be normalized. */
|
|
518
|
-
|
|
537
|
+
containsP(p) {
|
|
519
538
|
return this.containsLL(S2LatLng_1.S2LatLng.fromPoint(p));
|
|
520
|
-
}
|
|
539
|
+
}
|
|
521
540
|
/**
|
|
522
541
|
* Return true if the edge AB intersects the given edge of constant longitude.
|
|
523
542
|
*/
|
|
524
|
-
|
|
543
|
+
static /*boolean*/ intersectsLngEdge(a, b, lat, lng) {
|
|
525
544
|
// Return true if the segment AB intersects the given edge of constant
|
|
526
545
|
// longitude. The nice thing about edges of constant longitude is that
|
|
527
546
|
// they are straight lines on the sphere (geodesics).
|
|
528
547
|
return S2_1.S2.simpleCrossing(a, b, new S2LatLng_1.S2LatLng(lat.lo, lng)
|
|
529
548
|
.toPoint(), new S2LatLng_1.S2LatLng(lat.hi, lng).toPoint());
|
|
530
|
-
}
|
|
549
|
+
}
|
|
531
550
|
/**
|
|
532
551
|
* Return true if the edge AB intersects the given edge of constant latitude.
|
|
533
552
|
*/
|
|
534
|
-
|
|
553
|
+
static /*boolean*/ intersectsLatEdge(a, b, lat, lng) {
|
|
535
554
|
// Return true if the segment AB intersects the given edge of constant
|
|
536
555
|
// latitude. Unfortunately, lines of constant latitude are curves on
|
|
537
556
|
// the sphere. They can intersect a straight edge in 0, 1, or 2 points.
|
|
538
557
|
// assert (S2.isUnitLength(a) && S2.isUnitLength(b));
|
|
539
558
|
// First, compute the normal to the plane AB that points vaguely north.
|
|
540
|
-
|
|
541
|
-
if (z.z
|
|
559
|
+
let z = S2Point_1.S2Point.normalize(S2_1.S2.robustCrossProd(a, b));
|
|
560
|
+
if (z.z < (0)) {
|
|
542
561
|
z = S2Point_1.S2Point.neg(z);
|
|
543
562
|
}
|
|
544
563
|
// Extend this to an orthonormal frame (x,y,z) where x is the direction
|
|
545
564
|
// where the great circle through AB achieves its maximium latitude.
|
|
546
|
-
|
|
547
|
-
|
|
565
|
+
const y = S2Point_1.S2Point.normalize(S2_1.S2.robustCrossProd(z, new S2Point_1.S2Point(0, 0, 1)));
|
|
566
|
+
const x = S2Point_1.S2Point.crossProd(y, z);
|
|
548
567
|
// assert (S2.isUnitLength(x) && x.z >= 0);
|
|
549
568
|
// Compute the angle "theta" from the x-axis (in the x-y plane defined
|
|
550
569
|
// above) where the great circle intersects the given line of latitude.
|
|
551
|
-
|
|
552
|
-
if (
|
|
570
|
+
const sinLat = Math.sin(lat);
|
|
571
|
+
if (Math.abs(sinLat) >= (x.z)) {
|
|
553
572
|
return false; // The great circle does not reach the given latitude.
|
|
554
573
|
}
|
|
555
574
|
// assert (x.z > 0);
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
575
|
+
const cosTheta = sinLat / x.z;
|
|
576
|
+
const sinTheta = Math.sqrt(1 - cosTheta * cosTheta);
|
|
577
|
+
const theta = Math.atan2(sinTheta, cosTheta);
|
|
559
578
|
// Math.atan2(sinTheta, cosTheta);
|
|
560
579
|
// The candidate intersection points are located +/- theta in the x-y
|
|
561
580
|
// plane. For an intersection to be valid, we need to check that the
|
|
562
581
|
// intersection point is contained in the interior of the edge AB and
|
|
563
582
|
// also that it is contained within the given longitude interval "lng".
|
|
564
583
|
// Compute the range of theta values spanned by the edge AB.
|
|
565
|
-
|
|
584
|
+
const abTheta = S1Interval_1.S1Interval.fromPointPair(Math.atan2(a.dotProd(y), a.dotProd(x)), Math.atan2(b.dotProd(y), b.dotProd(x)));
|
|
566
585
|
if (abTheta.contains(theta)) {
|
|
567
586
|
// Check if the intersection point is also in the given "lng" interval.
|
|
568
|
-
|
|
569
|
-
if (lng.contains(
|
|
587
|
+
const isect = S2Point_1.S2Point.add(S2Point_1.S2Point.mul(x, cosTheta), S2Point_1.S2Point.mul(y, sinTheta));
|
|
588
|
+
if (lng.contains(Math.atan2(isect.y, isect.x))) {
|
|
570
589
|
return true;
|
|
571
590
|
}
|
|
572
591
|
}
|
|
573
|
-
if (abTheta.contains(theta
|
|
592
|
+
if (abTheta.contains(theta * -1)) {
|
|
574
593
|
// Check if the intersection point is also in the given "lng" interval.
|
|
575
|
-
|
|
576
|
-
if (lng.contains(
|
|
594
|
+
const intersection = S2Point_1.S2Point.sub(S2Point_1.S2Point.mul(x, cosTheta), S2Point_1.S2Point.mul(y, sinTheta));
|
|
595
|
+
if (lng.contains(Math.atan2(intersection.y, intersection.x))) {
|
|
577
596
|
return true;
|
|
578
597
|
}
|
|
579
598
|
}
|
|
580
599
|
return false;
|
|
581
|
-
}
|
|
582
|
-
|
|
600
|
+
}
|
|
601
|
+
allVertex() {
|
|
583
602
|
return [
|
|
584
603
|
this.getVertex(0),
|
|
585
604
|
this.getVertex(1),
|
|
586
605
|
this.getVertex(2),
|
|
587
606
|
this.getVertex(3)
|
|
588
607
|
];
|
|
589
|
-
}
|
|
590
|
-
|
|
608
|
+
}
|
|
609
|
+
toGEOJSON() {
|
|
591
610
|
return {
|
|
592
611
|
type: 'Feature',
|
|
593
612
|
geometry: {
|
|
594
613
|
type: 'Polygon',
|
|
595
|
-
coordinates: [this.allVertex().concat(this.getVertex(0)).map(
|
|
614
|
+
coordinates: [this.allVertex().concat(this.getVertex(0)).map(v => [parseFloat(v.lngDegrees.toFixed(5)), parseFloat(v.latDegrees.toFixed(5))])],
|
|
596
615
|
},
|
|
597
616
|
properties: {}
|
|
598
617
|
};
|
|
599
|
-
}
|
|
600
|
-
|
|
618
|
+
}
|
|
619
|
+
toString() {
|
|
601
620
|
return "[Lo=" + this.lo().toString() + ", Hi=" + this.hi().toString() + "]";
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
}());
|
|
621
|
+
}
|
|
622
|
+
}
|
|
605
623
|
exports.S2LatLngRect = S2LatLngRect;
|
|
606
624
|
//# sourceMappingURL=S2LatLngRect.js.map
|