@@ -12,6 +12,8 @@ import { Interval as S1Interval } from '../s1/Interval'
12
12
import { MinWidthMetric } from './Metric_constants'
13
13
import * as cellid from './cellid'
14
14
import type { CellID } from './cellid'
15
+ import { Region } from './Region'
16
+ import { Cell } from './Cell'
15
17
16
18
export const CENTER_POINT = Point . fromCoords ( 1.0 , 0 , 0 )
17
19
@@ -49,7 +51,7 @@ export const CENTER_POINT = Point.fromCoords(1.0, 0, 0)
49
51
*
50
52
* @beta incomplete
51
53
*/
52
- export class Cap {
54
+ export class Cap implements Region {
53
55
center : Point
54
56
rad : ChordAngle
55
57
@@ -204,13 +206,86 @@ export class Cap {
204
206
return chordangle . add ( this . rad , other . rad ) > Point . chordAngleBetweenPoints ( this . center , other . center )
205
207
}
206
208
209
+ /**
210
+ * Reports whether the cap intersects the cell.
211
+ */
212
+ intersectsCell ( cell : Cell ) : boolean {
213
+ // If the cap contains any cell vertex, return true.
214
+ const vertices : Point [ ] = [ ]
215
+ for ( let k = 0 ; k < 4 ; k ++ ) {
216
+ vertices [ k ] = cell . vertex ( k )
217
+ if ( this . containsPoint ( vertices [ k ] ) ) return true
218
+ }
219
+ return this . _intersects ( cell , vertices )
220
+ }
221
+
222
+ /**
223
+ * Reports whether the cap intersects any point of the cell excluding
224
+ * its vertices (which are assumed to already have been checked).
225
+ */
226
+ private _intersects ( cell : Cell , vertices : Point [ ] ) : boolean {
227
+ // If the cap is a hemisphere or larger, the cell and the complement of the cap
228
+ // are both convex. Therefore since no vertex of the cell is contained, no other
229
+ // interior point of the cell is contained either.
230
+ if ( this . rad >= RIGHT_CHORDANGLE ) return false
231
+
232
+ // We need to check for empty caps due to the center check just below.
233
+ if ( this . isEmpty ( ) ) return false
234
+
235
+ // Optimization: return true if the cell contains the cap center. This allows half
236
+ // of the edge checks below to be skipped.
237
+ if ( cell . containsPoint ( this . center ) ) return true
238
+
239
+ // At this point we know that the cell does not contain the cap center, and the cap
240
+ // does not contain any cell vertex. The only way that they can intersect is if the
241
+ // cap intersects the interior of some edge.
242
+ const sin2Angle = chordangle . sin2 ( this . rad )
243
+ for ( let k = 0 ; k < 4 ; k ++ ) {
244
+ const edge = cell . edge ( k ) . vector
245
+ const dot = this . center . vector . dot ( edge )
246
+ if ( dot > 0 ) {
247
+ // The center is in the interior half-space defined by the edge. We do not need
248
+ // to consider these edges, since if the cap intersects this edge then it also
249
+ // intersects the edge on the opposite side of the cell, because the center is
250
+ // not contained with the cell.
251
+ continue
252
+ }
253
+
254
+ // The Norm2() factor is necessary because "edge" is not normalized.
255
+ if ( dot * dot > sin2Angle * edge . norm2 ( ) ) return false
256
+
257
+ // Otherwise, the great circle containing this edge intersects the interior of the cap. We just
258
+ // need to check whether the point of closest approach occurs between the two edge endpoints.
259
+ const dir = edge . cross ( this . center . vector )
260
+ if ( dir . dot ( vertices [ k ] . vector ) < 0 && dir . dot ( vertices [ ( k + 1 ) & 3 ] . vector ) > 0 ) {
261
+ return true
262
+ }
263
+ }
264
+
265
+ return false
266
+ }
267
+
207
268
/**
208
269
* Reports whether this cap contains the point.
209
270
*/
210
271
containsPoint ( p : Point ) : boolean {
211
272
return Point . chordAngleBetweenPoints ( this . center , p ) <= this . rad
212
273
}
213
274
275
+ /** Reports whether the cap contains the given cell. */
276
+ containsCell ( cell : Cell ) : boolean {
277
+ // If the cap does not contain all cell vertices, return false.
278
+ const vertices : Point [ ] = [ ]
279
+ for ( let k = 0 ; k < 4 ; k ++ ) {
280
+ vertices [ k ] = cell . vertex ( k )
281
+ if ( ! this . containsPoint ( vertices [ k ] ) ) {
282
+ return false
283
+ }
284
+ }
285
+ // Otherwise, return true if the complement of the cap does not intersect the cell.
286
+ return ! this . complement ( ) . _intersects ( cell , vertices )
287
+ }
288
+
214
289
/**
215
290
* Reports whether the point is within the interior of this cap.
216
291
*/
0 commit comments