3d-tiles-renderer
Version:
https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification
179 lines (122 loc) • 3.55 kB
JavaScript
import { MathUtils, Matrix4 } from 'three';
import { Vector3 } from 'three';
import { Ellipsoid } from './Ellipsoid.js';
const PI = Math.PI;
const HALF_PI = PI / 2;
const _orthoX = new Vector3();
const _orthoY = new Vector3();
const _orthoZ = new Vector3();
const _invMatrix = new Matrix4();
let _poolIndex = 0;
const _pointsPool = [];
function getVector( usePool = false ) {
if ( ! usePool ) {
return new Vector3();
}
if ( ! _pointsPool[ _poolIndex ] ) {
_pointsPool[ _poolIndex ] = new Vector3();
}
_poolIndex ++;
return _pointsPool[ _poolIndex - 1 ];
}
function resetPool() {
_poolIndex = 0;
}
export class EllipsoidRegion extends Ellipsoid {
constructor(
x, y, z,
latStart = - HALF_PI, latEnd = HALF_PI,
lonStart = 0, lonEnd = 2 * PI,
heightStart = 0, heightEnd = 0
) {
super( x, y, z );
this.latStart = latStart;
this.latEnd = latEnd;
this.lonStart = lonStart;
this.lonEnd = lonEnd;
this.heightStart = heightStart;
this.heightEnd = heightEnd;
}
_getPoints( usePool = false ) {
const {
latStart, latEnd,
lonStart, lonEnd,
heightStart, heightEnd,
} = this;
const midLat = MathUtils.mapLinear( 0.5, 0, 1, latStart, latEnd );
const midLon = MathUtils.mapLinear( 0.5, 0, 1, lonStart, lonEnd );
const lonOffset = Math.floor( lonStart / HALF_PI ) * HALF_PI;
const latlon = [
[ - PI / 2, 0 ],
[ PI / 2, 0 ],
[ 0, lonOffset ],
[ 0, lonOffset + PI / 2 ],
[ 0, lonOffset + PI ],
[ 0, lonOffset + 3 * PI / 2 ],
[ latStart, lonEnd ],
[ latEnd, lonEnd ],
[ latStart, lonStart ],
[ latEnd, lonStart ],
[ 0, lonStart ],
[ 0, lonEnd ],
[ midLat, midLon ],
[ latStart, midLon ],
[ latEnd, midLon ],
[ midLat, lonStart ],
[ midLat, lonEnd ],
];
const target = [];
const total = latlon.length;
for ( let z = 0; z <= 1; z ++ ) {
const height = MathUtils.mapLinear( z, 0, 1, heightStart, heightEnd );
for ( let i = 0, l = total; i < l; i ++ ) {
const [ lat, lon ] = latlon[ i ];
if ( lat >= latStart && lat <= latEnd && lon >= lonStart && lon <= lonEnd ) {
const v = getVector( usePool );
target.push( v );
this.getCartographicToPosition( lat, lon, height, v );
}
}
}
return target;
}
getBoundingBox( box, matrix ) {
resetPool();
const {
latStart, latEnd,
lonStart, lonEnd,
} = this;
const latRange = latEnd - latStart;
if ( latRange < PI / 2 ) {
// get the midway point for the region
const midLat = MathUtils.mapLinear( 0.5, 0, 1, latStart, latEnd );
const midLon = MathUtils.mapLinear( 0.5, 0, 1, lonStart, lonEnd );
// get the frame matrix for the box - works well for smaller regions
this.getCartographicToNormal( midLat, midLon, _orthoZ );
_orthoY.set( 0, 0, 1 );
_orthoX.crossVectors( _orthoY, _orthoZ );
_orthoY.crossVectors( _orthoX, _orthoZ );
matrix.makeBasis( _orthoX, _orthoY, _orthoZ );
} else {
_orthoX.set( 1, 0, 0 );
_orthoY.set( 0, 1, 0 );
_orthoZ.set( 0, 0, 1 );
matrix.makeBasis( _orthoX, _orthoY, _orthoZ );
}
// transform the points into the local frame
_invMatrix.copy( matrix ).invert();
const points = this._getPoints( true );
for ( let i = 0, l = points.length; i < l; i ++ ) {
points[ i ].applyMatrix4( _invMatrix );
}
// init the box
box.makeEmpty();
box.setFromPoints( points );
}
getBoundingSphere( sphere, center ) {
resetPool();
const points = this._getPoints( true );
sphere.makeEmpty();
sphere.setFromPoints( points, center );
}
}