Source: og/segment/SegmentLonLat.js

"use strict";

import { Extent } from "../Extent.js";
import { Layer } from "../layer/Layer.js";
import { LonLat } from "../LonLat.js";
import { Vec3 } from "../math/Vec3.js";
import * as mercator from "../mercator.js";
import { EPSG4326 } from "../proj/EPSG4326.js";
import * as quadTree from "../quadTree/quadTree.js";
import { Segment } from "./Segment.js";

const _heightLat = 90.0 - mercator.MAX_LAT;
const _maxPoleZoom = 7;
const _pieceSize = _heightLat / Math.pow(2, _maxPoleZoom);

let _tempHigh = new Vec3(),
    _tempLow = new Vec3();

/**
 * Planet segment Web Mercator tile class that stored and rendered with quad tree.
 * @class
 * @extends {Segment}
 * @param {quadNode.Node} node - Quad tree segment node.
 * @param {Planet} planet - Scene planet.
 * @param {Number} tileZoom - Segment tile zoom index.
 * @param {Extent} extent - Segment WGS84 extent.
 */
class SegmentLonLat extends Segment {
    /**
     * @param {quadTree.Node} node - Segment node.
     * @param {Planet} planet - Current planet scene.
     * @param {number} tileZoom - Zoom index.
     * @param {Extent} extent - Segment extent.
     */
    constructor(node, planet, tileZoom, extent) {
        super(node, planet, tileZoom, extent);

        // TODO:
        // be carefull with functions in constructor _assignTileIndexes
        // this._isNorth = false;

        this._projection = EPSG4326;
        this._extentMerc = new Extent(
            extent.southWest.forwardMercatorEPS01(),
            extent.northEast.forwardMercatorEPS01()
        );
        this.isPole = true;
    }

    _setExtentLonLat() {
        this._extentLonLat = this._extent;
    }

    projectNative(coords) {
        return coords;
    }

    getTerrainPoint(xyz, insideSegmentPosition, res, normal) {
        res.copy(this.planet.ellipsoid.hitRay(xyz, xyz.negateTo().normalize()));
        if (normal) {
            normal.copy(res.normal());
        }
        return xyz.length() - res.length();
    }

    acceptForRendering(camera) {
        var maxPoleZoom;
        var lat = this._extent.northEast.lat;
        if (this._isNorth) {
            //north pole limits
            let Yz = Math.floor((90.0 - lat) / _pieceSize);
            maxPoleZoom = Math.floor(Yz / 16) + 7;
        } else {
            //south pole limits
            let Yz = Math.floor((mercator.MIN_LAT - lat) / _pieceSize);
            maxPoleZoom = 12 - Math.floor(Yz / 16);
        }
        return (
            Segment.prototype.acceptForRendering.call(this, camera) || this.tileZoom >= maxPoleZoom
        );
    }

    _assignTileIndexes() {
        var tileZoom = this.tileZoom;
        var extent = this._extent;

        this.tileX = Math.round(
            Math.abs(-180.0 - extent.southWest.lon) / (extent.northEast.lon - extent.southWest.lon)
        );

        var lat = extent.northEast.lat;

        if (lat > 0) {
            //north pole
            this._isNorth = true;
            this._tileGroup = 1;
            this.tileY = Math.round((90.0 - lat) / (extent.northEast.lat - extent.southWest.lat));
        } else {
            //south pole
            this._tileGroup = 2;
            this.tileY = Math.round(
                (mercator.MIN_LAT - lat) / (extent.northEast.lat - extent.southWest.lat)
            );
        }

        var p2 = 1 << tileZoom;
        this.tileXE = (this.tileX + 1) % p2;
        this.tileXW = (p2 + this.tileX - 1) % p2;

        this.tileYN = this.tileY - 1;
        this.tileYS = this.tileY + 1;

        this.tileIndex = Layer.getTileIndex(this.tileX, this.tileY, tileZoom);
    }

    _createPlainVertices() {
        var gridSize = this.planet.terrain.gridSizeByZoom[this.tileZoom];

        var e = this._extent,
            fgs = this.planet.terrain.plainGridSize;
        var lonSize = e.getWidth();
        var latSize = e.getHeight();
        var llStep = lonSize / Math.max(fgs, gridSize);
        var ltStep = latSize / gridSize;
        var esw_lon = e.southWest.lon,
            ene_lat = e.northEast.lat;
        var dg = Math.max(fgs / gridSize, 1),
            gs = Math.max(fgs, gridSize) + 1;
        var r2 = this.planet.ellipsoid._invRadii2;
        var ind = 0,
            nmInd = 0;
        const gsgs = gs * gs;

        var gridSize3 = (gridSize + 1) * (gridSize + 1) * 3;

        this.plainNormals = new Float32Array(gridSize3);
        this.plainVertices = new Float64Array(gridSize3);
        this.plainVerticesHigh = new Float32Array(gridSize3);
        this.plainVerticesLow = new Float32Array(gridSize3);

        this.normalMapNormals = new Float32Array(gsgs * 3);
        this.normalMapVertices = new Float64Array(gsgs * 3);
        this.normalMapVerticesHigh = new Float32Array(gsgs * 3);
        this.normalMapVerticesLow = new Float32Array(gsgs * 3);

        let xmin = 549755748352.0,
            xmax = -549755748352.0,
            ymin = 549755748352.0,
            ymax = -549755748352.0,
            zmin = 549755748352.0,
            zmax = -549755748352.0;

        var verts = this.plainVertices,
            vertsHigh = this.plainVerticesHigh,
            vertsLow = this.plainVerticesLow,
            norms = this.plainNormals,
            nmVerts = this.normalMapVertices,
            nmVertsHigh = this.normalMapVerticesHigh,
            nmVertsLow = this.normalMapVerticesLow,
            nmNorms = this.normalMapNormals;

        for (var k = 0; k < gsgs; k++) {
            var j = k % gs,
                i = ~~(k / gs);

            var v = this.planet.ellipsoid.lonLatToCartesian(
                new LonLat(esw_lon + j * llStep, ene_lat - i * ltStep)
            );
            var nx = v.x * r2.x,
                ny = v.y * r2.y,
                nz = v.z * r2.z;
            var l = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz);
            var nxl = nx * l,
                nyl = ny * l,
                nzl = nz * l;

            Vec3.doubleToTwoFloats(v, _tempHigh, _tempLow);

            nmVerts[nmInd] = v.x;
            nmVertsHigh[nmInd] = _tempHigh.x;
            nmVertsLow[nmInd] = _tempLow.x;
            nmNorms[nmInd++] = nxl;

            nmVerts[nmInd] = v.y;
            nmVertsHigh[nmInd] = _tempHigh.y;
            nmVertsLow[nmInd] = _tempLow.y;
            nmNorms[nmInd++] = nyl;

            nmVerts[nmInd] = v.z;
            nmVertsHigh[nmInd] = _tempHigh.z;
            nmVertsLow[nmInd] = _tempLow.z;
            nmNorms[nmInd++] = nzl;

            if (i % dg === 0 && j % dg === 0) {
                verts[ind] = v.x;
                vertsHigh[ind] = _tempHigh.x;
                vertsLow[ind] = _tempLow.x;
                norms[ind++] = nxl;

                verts[ind] = v.y;
                vertsHigh[ind] = _tempHigh.y;
                vertsLow[ind] = _tempLow.y;
                norms[ind++] = nyl;

                verts[ind] = v.z;
                vertsHigh[ind] = _tempHigh.z;
                vertsLow[ind] = _tempLow.z;
                norms[ind++] = nzl;

                if (v.x < xmin) xmin = v.x;
                if (v.x > xmax) xmax = v.x;
                if (v.y < ymin) ymin = v.y;
                if (v.y > ymax) ymax = v.y;
                if (v.z < zmin) zmin = v.z;
                if (v.z > zmax) zmax = v.z;
            }
        }

        this.terrainVertices = verts;
        this.terrainVerticesHigh = vertsHigh;
        this.terrainVerticesLow = vertsLow;

        //store raw normals
        this.normalMapNormalsRaw = new Float32Array(nmNorms.length);
        this.normalMapNormalsRaw.set(nmNorms);

        let x = (xmax - xmin) * 0.5,
            y = (ymax - ymin) * 0.5,
            z = (zmax - zmin) * 0.5;

        this._plainRadius = Math.sqrt(x * x + y * y + z * z);

        this.plainReady = true;
    }

    _assignGlobalTextureCoordinates() {
        var e = this._extent;
        this._globalTextureCoordinates[0] = (e.southWest.lon + 180.0) / 360.0;
        this._globalTextureCoordinates[1] = (90 - e.northEast.lat) / 180.0;
        this._globalTextureCoordinates[2] = (e.northEast.lon + 180.0) / 360.0;
        this._globalTextureCoordinates[3] = (90 - e.southWest.lat) / 180.0;
    }

    _collectVisibleNodes() {
        if (this._isNorth) {
            this.planet._visibleNodesNorth[this.node.nodeId] = this.node;
        } else {
            this.planet._visibleNodesSouth[this.node.nodeId] = this.node;
        }
    }

    isEntityInside(e) {
        return this._extent.isInside(e._lonlat);
    }

    _getLayerExtentOffset(layer) {
        var v0s = layer._extent;
        var v0t = this._extent;
        var sSize_x = v0s.northEast.lon - v0s.southWest.lon;
        var sSize_y = v0s.northEast.lat - v0s.southWest.lat;
        var dV0s_x = (v0t.southWest.lon - v0s.southWest.lon) / sSize_x;
        var dV0s_y = (v0s.northEast.lat - v0t.northEast.lat) / sSize_y;
        var dSize_x = (v0t.northEast.lon - v0t.southWest.lon) / sSize_x;
        var dSize_y = (v0t.northEast.lat - v0t.southWest.lat) / sSize_y;
        return [dV0s_x, dV0s_y, dSize_x, dSize_y];
    }

    layerOverlap(layer) {
        return this._extent.overlaps(layer._extent);
    }

    getDefaultTexture() {
        return this._isNorth ? this.planet.solidTextureOne : this.planet.solidTextureTwo;
    }

    getExtentLonLat() {
        return this._extent;
    }

    getExtentMerc() {
        return this._extentMerc;
    }

    getNodeState() {
        var vn;
        if (this._isNorth) {
            vn = this.planet._visibleNodesNorth[this.node.nodeId];
        } else {
            vn = this.planet._visibleNodesSouth[this.node.nodeId];
        }
        return (vn && vn.state) || quadTree.NOTRENDERING;
    }

    _freeCache() {
        //empty for a time
    }
}
export { SegmentLonLat };