Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
private evaluatePlanarProj(camera: THREE.Camera, projection: Projection): ViewRanges {
assert(projection.type !== ProjectionType.Spherical);
const clipPlanes = { ...this.minimumViewRange };
const cameraTilt = this.getCameraTiltAngle(camera, projection);
const lookAtDist = this.getCameraLookAtDistance(camera, projection);
// Generally near/far planes are set to keep look at distance, then
// margins are applied. Here margins (min/max elevations) are meant to be
// defined as distance along the ground normal vector thus during camera
// tilt they need to be projected on the eye vector:
// actualMargin = margin / groundNormal.dot(eyeVec)
// Assuming that tilt angle defined relative to actual ground normal, we have:
let cameraEyeDotGround = Math.cos(cameraTilt);
cameraEyeDotGround = cameraEyeDotGround === 0 ? epsilon : cameraEyeDotGround;
clipPlanes.near = lookAtDist - this.maxElevation / cameraEyeDotGround;
clipPlanes.far = lookAtDist - this.minElevation / cameraEyeDotGround;
// Correct cliping planse distance for the top/bottom frustum planes (edges).
// If we deal with perspective camera type, this step would not be required
// returns box with altitude min/max equal to zero) will be propagated as
// min and max elevation, these tiles most probably contains features that
// lays directly on the ground surface.
if (useElevationRangeSource) {
const range = elevationRangeSource!.getElevationRange(childTileKey);
geoBox.southWest.altitude = range.minElevation;
geoBox.northEast.altitude = range.maxElevation;
calculationFinal =
calculationFinal &&
range.calculationStatus === CalculationStatus.FinalPrecise;
}
let subTileArea = 0;
const obbIntersections: boolean =
this.mapView.projection.type === ProjectionType.Spherical;
if (obbIntersections) {
const obb = new OrientedBox3();
this.mapView.projection.projectBox(geoBox, obb);
subTileArea = this.computeSubTileArea(obb);
} else {
this.mapView.projection.projectBox(geoBox, tileBounds);
subTileArea = this.computeSubTileArea(tileBounds);
}
if (subTileArea > 0) {
const subTileEntry = new TileKeyEntry(
childTileKey,
subTileArea,
offset,
geoBox.southWest.altitude, // minElevation
geoBox.northEast.altitude // maxElevation
const newTargetPosition = rayCastWorldCoordinates(
mapView,
targetPositionOnScreenXinNDC,
targetPositionOnScreenYinNDC
);
if (!targetPosition || !newTargetPosition) {
return;
}
if (mapView.projection.type === ProjectionType.Planar) {
// Calculate the difference and pan the map to maintain the map relative to the target
// position.
targetPosition.sub(newTargetPosition);
panCameraAboveFlatMap(mapView, targetPosition.x, targetPosition.y);
} else if (mapView.projection.type === ProjectionType.Spherical) {
panCameraAroundGlobe(mapView, targetPosition, newTargetPosition);
}
}
export function rotate(
mapView: MapView,
deltaYawDeg: number,
deltaPitchDeg: number = 0,
maxTiltAngleRad = Math.PI / 4
) {
// 1. Apply yaw: rotate around the vertical axis.
mapView.camera.rotateOnWorldAxis(
mapView.projection.type === ProjectionType.Spherical
? cache.vector3[0].copy(mapView.camera.position).normalize()
: cache.vector3[0].set(0, 0, 1),
MathUtils.degToRad(-deltaYawDeg)
);
mapView.camera.updateMatrixWorld();
// 2. Apply pitch: rotate around the camera's local X axis.
if (deltaPitchDeg === 0) {
return;
}
const pitch = MapViewUtils.extractAttitude(mapView, mapView.camera).pitch;
// `maxTiltAngle` is equivalent to a `maxPitchAngle` in flat projections.
let newPitch = THREE.Math.clamp(
pitch + THREE.Math.degToRad(deltaPitchDeg),
0,
maxTiltAngleRad
function checkViewDistance(
worldCenter: THREE.Vector3,
textElement: TextElement,
projectionType: ProjectionType,
camera: THREE.Camera,
maxViewDistance: number
): number | undefined {
const textDistance = computeViewDistance(worldCenter, textElement);
if (projectionType !== ProjectionType.Spherical) {
return textDistance <= maxViewDistance ? textDistance : undefined;
}
// For sphere projection: Filter labels that are close to the horizon
tmpPosition.copy(textElement.position).normalize();
camera.getWorldPosition(tmpCameraDir).normalize();
const cosAlpha = tmpPosition.dot(tmpCameraDir);
const viewDistance =
cosAlpha > COS_TEXT_ELEMENT_FALLOFF_ANGLE && textDistance <= maxViewDistance
? textDistance
: undefined;
return viewDistance;
}
protected getFrustumGroundIntersectionDist(
camera: THREE.PerspectiveCamera,
projection: Projection
): { top: number; bottom: number } {
assert(projection.type !== ProjectionType.Spherical);
// This algorithm computes the length of frustum intersection with a flat ground surface,
// splitting the entire intersection into two sections, one for part above eye vector and
// another below.
// The following diagram may help explain the algorithm below.
// 🎥
// C
// |\
// |.\ .
// | . \ .
// z | . \ .c2
// | c1. \e .
// | . \ .
//___|a___D1.____\E1_____.D2______ g
// C1 . \ .
// . \.E2
// . .
this.m_decodeInfo.tileBounds.getCenter(tempTileOrigin);
const {
positions,
normals,
textureCoordinates,
colors,
extrusionAxis,
indices,
edgeIndices,
groups
} = meshBuffers;
const featureStride = texCoordType !== undefined ? 4 : 2;
const vertexStride = featureStride + 2;
const isSpherical = this.m_decodeInfo.targetProjection.type === ProjectionType.Spherical;
const edgeWidth = isExtruded
? extrudedPolygonTechnique.lineWidth || 0.0
: isFilled
? fillTechnique.lineWidth || 0.0
: 0.0;
const hasEdges = edgeWidth > 0.0;
let color: THREE.Color | undefined;
if (isExtrudedPolygonTechnique(technique)) {
if (getOptionValue(technique.vertexColors, false)) {
let colorValue = evaluateTechniqueAttr(context, technique.color);
if (colorValue === undefined) {
const featureColor = context.env.lookup("color");
if (this.isColorStringValid(featureColor)) {
colorValue = String(featureColor);
addGroundPlane(tile: Tile, renderOrder: number) {
const mapView = tile.mapView;
const dataSource = tile.dataSource;
const projection = tile.projection;
const color = mapView.clearColor;
const tmpV = new THREE.Vector3();
if (tile.projection.type === ProjectionType.Spherical) {
const { east, west, north, south } = tile.geoBox;
const sourceProjection = dataSource.getTilingScheme().projection;
const g = new THREE.BufferGeometry();
const posAttr = new THREE.BufferAttribute(
new Float32Array([
...sourceProjection
.projectPoint(new GeoCoordinates(south, west), tmpV)
.toArray(),
...sourceProjection
.projectPoint(new GeoCoordinates(south, east), tmpV)
.toArray(),
...sourceProjection
.projectPoint(new GeoCoordinates(north, west), tmpV)
.toArray(),
...sourceProjection
.projectPoint(new GeoCoordinates(north, east), tmpV)
dispose() {
for (let i = 0; i < this.m_faceCount; ++i) {
this.m_faces[i].dispose();
}
if (this.m_projectionType === ProjectionType.Spherical) {
this.m_skybox!.dispose();
}
}
.then(([texture, copyrightInfo]) => {
tile.copyrightInfo = copyrightInfo;
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.generateMipmaps = false;
tile.addOwnedTexture(texture);
const shouldSubdivide = this.projection.type === ProjectionType.Spherical;
const sourceProjection = this.getTilingScheme().projection;
const tmpV = new THREE.Vector3();
const { east, west, north, south } = tile.geoBox;
const g = new THREE.BufferGeometry();
const posAttr = new THREE.BufferAttribute(
new Float32Array([
...sourceProjection
.projectPoint(new GeoCoordinates(south, west), tmpV)
.toArray(),
...sourceProjection
.projectPoint(new GeoCoordinates(south, east), tmpV)
.toArray(),