1- import { MathUtils , Matrix4 } from 'three' ;
2- import { Vector3 } from 'three' ;
1+ import { Matrix4 , Vector3 , Box3 } from 'three' ;
32import { Ellipsoid } from './Ellipsoid.js' ;
43
4+ // bounds are lightly inflated to account for floating point error
5+ const INFLATE_EPSILON = 1e-13 ;
56const PI = Math . PI ;
67const HALF_PI = PI / 2 ;
78
8- const _orthoX = new Vector3 ( ) ;
9- const _orthoY = new Vector3 ( ) ;
10- const _orthoZ = new Vector3 ( ) ;
11- const _invMatrix = new Matrix4 ( ) ;
9+ const _orthoX = /* @__PURE__ */ new Vector3 ( ) ;
10+ const _orthoY = /* @__PURE__ */ new Vector3 ( ) ;
11+ const _orthoZ = /* @__PURE__ */ new Vector3 ( ) ;
12+ const _vec = /* @__PURE__ */ new Vector3 ( ) ;
13+ const _invMatrix = /* @__PURE__ */ new Matrix4 ( ) ;
14+ const _box = /* @__PURE__ */ new Box3 ( ) ;
15+ const _matrix = /* @__PURE__ */ new Matrix4 ( ) ;
1216
13- let _poolIndex = 0 ;
14- const _pointsPool = [ ] ;
15- function getVector ( usePool = false ) {
17+ function expandSphereRadiusSquared ( vec , target ) {
1618
17- if ( ! usePool ) {
18-
19- return new Vector3 ( ) ;
20-
21- }
22-
23- if ( ! _pointsPool [ _poolIndex ] ) {
24-
25- _pointsPool [ _poolIndex ] = new Vector3 ( ) ;
26-
27- }
28-
29- _poolIndex ++ ;
30- return _pointsPool [ _poolIndex - 1 ] ;
19+ target . radius = Math . max ( target . radius , vec . distanceToSquared ( target . center ) ) ;
3120
3221}
3322
34- function resetPool ( ) {
23+ function isTriaxial ( radii ) {
3524
36- _poolIndex = 0 ;
25+ return radii . x !== radii . y ;
3726
3827}
3928
4029export class EllipsoidRegion extends Ellipsoid {
4130
4231 constructor (
43- x , y , z ,
32+ x = 1 , y = 1 , z = 1 ,
4433 latStart = - HALF_PI , latEnd = HALF_PI ,
4534 lonStart = 0 , lonEnd = 2 * PI ,
4635 heightStart = 0 , heightEnd = 0
@@ -56,122 +45,224 @@ export class EllipsoidRegion extends Ellipsoid {
5645
5746 }
5847
59- _getPoints ( usePool = false ) {
48+ getBoundingBox ( box , matrix ) {
49+
50+ if ( isTriaxial ( this . radius ) ) {
51+
52+ console . warn ( 'EllipsoidRegion: Triaxial ellipsoids are not supported.' ) ;
53+
54+ }
6055
6156 const {
6257 latStart, latEnd,
6358 lonStart, lonEnd,
6459 heightStart, heightEnd,
6560 } = this ;
6661
67- const midLat = MathUtils . mapLinear ( 0.5 , 0 , 1 , latStart , latEnd ) ;
68- const midLon = MathUtils . mapLinear ( 0.5 , 0 , 1 , lonStart , lonEnd ) ;
62+ const latMid = ( latStart + latEnd ) * 0.5 ;
63+ const lonMid = ( lonStart + lonEnd ) * 0.5 ;
64+ const allAboveEquator = latStart > 0.0 ;
65+ const allBelowEquator = latEnd < 0.0 ;
6966
70- const lonOffset = Math . floor ( lonStart / HALF_PI ) * HALF_PI ;
71- const latlon = [
72- [ - PI / 2 , 0 ] ,
73- [ PI / 2 , 0 ] ,
74- [ 0 , lonOffset ] ,
75- [ 0 , lonOffset + PI / 2 ] ,
76- [ 0 , lonOffset + PI ] ,
77- [ 0 , lonOffset + 3 * PI / 2 ] ,
67+ let nearEquatorLat ;
68+ if ( allAboveEquator ) {
7869
79- [ latStart , lonEnd ] ,
80- [ latEnd , lonEnd ] ,
81- [ latStart , lonStart ] ,
82- [ latEnd , lonStart ] ,
70+ nearEquatorLat = latStart ;
8371
84- [ 0 , lonStart ] ,
85- [ 0 , lonEnd ] ,
72+ } else if ( allBelowEquator ) {
8673
87- [ midLat , midLon ] ,
88- [ latStart , midLon ] ,
89- [ latEnd , midLon ] ,
90- [ midLat , lonStart ] ,
91- [ midLat , lonEnd ] ,
74+ nearEquatorLat = latEnd ;
9275
93- ] ;
76+ } else {
9477
95- const target = [ ] ;
96- const total = latlon . length ;
78+ nearEquatorLat = 0 ;
9779
98- for ( let z = 0 ; z <= 1 ; z ++ ) {
80+ }
9981
100- const height = MathUtils . mapLinear ( z , 0 , 1 , heightStart , heightEnd ) ;
101- for ( let i = 0 , l = total ; i < l ; i ++ ) {
82+ // measure the extents
83+ const { min, max } = box ;
84+ min . setScalar ( Infinity ) ;
85+ max . setScalar ( - Infinity ) ;
86+ if ( lonEnd - lonStart <= PI ) {
87+
88+ // extract the axes
89+ this . getCartographicToNormal ( latMid , lonMid , _orthoZ ) ;
90+ _orthoY . set ( 0 , 0 , 1 ) ;
91+ _orthoX . crossVectors ( _orthoY , _orthoZ ) . normalize ( ) ;
92+ _orthoY . crossVectors ( _orthoZ , _orthoX ) . normalize ( ) ;
93+
94+ // construct the frame
95+ matrix . makeBasis ( _orthoX , _orthoY , _orthoZ ) ;
96+ _invMatrix . copy ( matrix ) . invert ( ) ;
97+
98+ // extract x
99+ // check the most bowing point near the equator relative to the frame
100+ this . getCartographicToPosition ( nearEquatorLat , lonStart , heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
101+ max . x = Math . abs ( _vec . x ) ;
102+ min . x = - max . x ;
103+
104+ // extract y
105+ // check corners and mid points for the top
106+ this . getCartographicToPosition ( latEnd , lonStart , heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
107+ max . y = _vec . y ;
108+
109+ this . getCartographicToPosition ( latEnd , lonMid , heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
110+ max . y = Math . max ( _vec . y , max . y ) ;
111+
112+ // check corners and mid points for the bottom
113+ this . getCartographicToPosition ( latStart , lonStart , heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
114+ min . y = _vec . y ;
115+
116+ this . getCartographicToPosition ( latStart , lonMid , heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
117+ min . y = Math . min ( _vec . y , min . y ) ;
118+
119+ // extract z
120+ // check center point
121+ this . getCartographicToPosition ( latMid , lonMid , heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
122+ max . z = _vec . z ;
123+
124+ // check top and bottom reverse points
125+ this . getCartographicToPosition ( latStart , lonStart , heightStart , _vec ) . applyMatrix4 ( _invMatrix ) ;
126+ min . z = _vec . z ;
127+
128+ this . getCartographicToPosition ( latEnd , lonStart , heightStart , _vec ) . applyMatrix4 ( _invMatrix ) ;
129+ min . z = Math . min ( _vec . z , min . z ) ;
130+
131+ } else {
102132
103- const [ lat , lon ] = latlon [ i ] ;
104- if ( lat >= latStart && lat <= latEnd && lon >= lonStart && lon <= lonEnd ) {
133+ // extract a vector towards the middle of the region
134+ this . getCartographicToPosition ( nearEquatorLat , lonMid , heightEnd , _orthoZ ) ;
135+ _orthoZ . z = 0 ;
136+ if ( _orthoZ . length ( ) < 1e-10 ) {
105137
106- const v = getVector ( usePool ) ;
107- target . push ( v ) ;
108- this . getCartographicToPosition ( lat , lon , height , v ) ;
138+ _orthoZ . set ( 1 , 0 , 0 ) ;
109139
110- }
140+ } else {
141+
142+ _orthoZ . normalize ( ) ;
111143
112144 }
113145
146+ _orthoY . set ( 0 , 0 , 1 ) ;
147+ _orthoX . crossVectors ( _orthoZ , _orthoY ) . normalize ( ) ;
148+
149+ // construct the OBB frame
150+ matrix . makeBasis ( _orthoX , _orthoY , _orthoZ ) ;
151+ _invMatrix . copy ( matrix ) . invert ( ) ;
152+
153+ // x extents
154+ // find the furthest point rotated 90 degrees from the center of the region
155+ this . getCartographicToPosition ( nearEquatorLat , lonMid + HALF_PI , heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
156+ max . x = Math . abs ( _vec . x ) ;
157+ min . x = - max . x ;
158+
159+ // y extents
160+ // measure the top of the region, accounting for the diagonal tilt of the edge
161+ this . getCartographicToPosition ( latEnd , 0 , allBelowEquator ? heightStart : heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
162+ max . y = _vec . y ;
163+
164+ // measure the bottom of the region, accounting for the diagonal tilt of the edge
165+ this . getCartographicToPosition ( latStart , 0 , allAboveEquator ? heightStart : heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
166+ min . y = _vec . y ;
167+
168+ // z extends
169+ // measure the furthest point at the center of the region
170+ this . getCartographicToPosition ( nearEquatorLat , lonMid , heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
171+ max . z = _vec . z ;
172+
173+ // measure the opposite end, which is guaranteed to be at the furthest extents since this lon region extents is > PI
174+ this . getCartographicToPosition ( nearEquatorLat , lonEnd , heightEnd , _vec ) . applyMatrix4 ( _invMatrix ) ;
175+ min . z = _vec . z ;
176+
114177 }
115178
116- return target ;
179+ // center the frame
180+ box . getCenter ( _vec ) ;
181+ box . min . sub ( _vec ) . multiplyScalar ( 1 + INFLATE_EPSILON ) ;
182+ box . max . sub ( _vec ) . multiplyScalar ( 1 + INFLATE_EPSILON ) ;
183+
184+ _vec . applyMatrix4 ( matrix ) ;
185+ matrix . setPosition ( _vec ) ;
117186
118187 }
119188
120- getBoundingBox ( box , matrix ) {
189+ getBoundingSphere ( sphere ) {
190+
191+ if ( isTriaxial ( this . radius ) ) {
192+
193+ console . warn ( 'EllipsoidRegion: Triaxial ellipsoids are not supported.' ) ;
121194
122- resetPool ( ) ;
195+ }
196+
197+ // TODO: this could be optimized or the OBB could be generated at the same time since
198+ // a lot of the the points are reused
199+
200+ // use the OBB function to get a reasonable center
201+ this . getBoundingBox ( _box , _matrix ) ;
202+ sphere . center . setFromMatrixPosition ( _matrix ) ;
203+ sphere . radius = 0 ;
123204
124205 const {
125206 latStart, latEnd,
126207 lonStart, lonEnd,
208+ heightStart, heightEnd,
127209 } = this ;
128210
129- const latRange = latEnd - latStart ;
130- if ( latRange < PI / 2 ) {
211+ const latMid = ( latStart + latEnd ) * 0.5 ;
212+ const lonMid = ( lonStart + lonEnd ) * 0.5 ;
213+ const allAboveEquator = latStart > 0.0 ;
214+ const allBelowEquator = latEnd < 0.0 ;
131215
132- // get the midway point for the region
133- const midLat = MathUtils . mapLinear ( 0.5 , 0 , 1 , latStart , latEnd ) ;
134- const midLon = MathUtils . mapLinear ( 0.5 , 0 , 1 , lonStart , lonEnd ) ;
216+ let nearEquatorLat ;
217+ if ( allAboveEquator ) {
135218
136- // get the frame matrix for the box - works well for smaller regions
137- this . getCartographicToNormal ( midLat , midLon , _orthoZ ) ;
138- _orthoY . set ( 0 , 0 , 1 ) ;
139- _orthoX . crossVectors ( _orthoY , _orthoZ ) ;
140- _orthoY . crossVectors ( _orthoX , _orthoZ ) ;
141- matrix . makeBasis ( _orthoX , _orthoY , _orthoZ ) ;
219+ nearEquatorLat = latStart ;
220+
221+ } else if ( allBelowEquator ) {
222+
223+ nearEquatorLat = latEnd ;
142224
143225 } else {
144226
145- _orthoX . set ( 1 , 0 , 0 ) ;
146- _orthoY . set ( 0 , 1 , 0 ) ;
147- _orthoZ . set ( 0 , 0 , 1 ) ;
148- matrix . makeBasis ( _orthoX , _orthoY , _orthoZ ) ;
227+ nearEquatorLat = 0 ;
149228
150229 }
151230
152- // transform the points into the local frame
153- _invMatrix . copy ( matrix ) . invert ( ) ;
231+ // lon start extremity
232+ this . getCartographicToPosition ( nearEquatorLat , lonStart , heightEnd , _vec ) ;
233+ expandSphereRadiusSquared ( _vec , sphere ) ;
154234
155- const points = this . _getPoints ( true ) ;
156- for ( let i = 0 , l = points . length ; i < l ; i ++ ) {
235+ // check corners and mid points for the top
236+ this . getCartographicToPosition ( latEnd , lonStart , heightEnd , _vec ) ;
237+ expandSphereRadiusSquared ( _vec , sphere ) ;
157238
158- points [ i ] . applyMatrix4 ( _invMatrix ) ;
239+ this . getCartographicToPosition ( latEnd , lonMid , heightEnd , _vec ) ;
240+ expandSphereRadiusSquared ( _vec , sphere ) ;
159241
160- }
242+ // check corners and mid points for the bottom
243+ this . getCartographicToPosition ( latStart , lonStart , heightEnd , _vec ) ;
244+ expandSphereRadiusSquared ( _vec , sphere ) ;
161245
162- // init the box
163- box . makeEmpty ( ) ;
164- box . setFromPoints ( points ) ;
246+ this . getCartographicToPosition ( latStart , lonMid , heightEnd , _vec ) ;
247+ expandSphereRadiusSquared ( _vec , sphere ) ;
165248
166- }
249+ // check center extremity
250+ this . getCartographicToPosition ( latMid , lonMid , heightEnd , _vec ) ;
251+ expandSphereRadiusSquared ( _vec , sphere ) ;
167252
168- getBoundingSphere ( sphere , center ) {
253+ // check lower height extremity
254+ this . getCartographicToPosition ( latStart , lonStart , heightStart , _vec ) ;
255+ expandSphereRadiusSquared ( _vec , sphere ) ;
169256
170- resetPool ( ) ;
257+ // check 90 degree offset if range is larger than PI
258+ if ( lonEnd - lonStart > PI ) {
259+
260+ this . getCartographicToPosition ( nearEquatorLat , lonMid + PI , heightEnd , _vec ) ;
261+ expandSphereRadiusSquared ( _vec , sphere ) ;
262+
263+ }
171264
172- const points = this . _getPoints ( true ) ;
173- sphere . makeEmpty ( ) ;
174- sphere . setFromPoints ( points , center ) ;
265+ sphere . radius = Math . sqrt ( sphere . radius ) * ( 1 + INFLATE_EPSILON ) ;
175266
176267 }
177268
0 commit comments