惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
博客园 - Franky
博客园 - 三生石上(FineUI控件)
爱范儿
爱范儿
博客园 - 司徒正美
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
宝玉的分享
宝玉的分享
V
Visual Studio Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
IT之家
IT之家
博客园_首页
S
SegmentFault 最新的问题
A
About on SuperTechFans
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
H
Help Net Security
MongoDB | Blog
MongoDB | Blog

博客园 - zhh

Cesium 河道形状 Cesium 实现 FlowMap Unity3D c# 使对象物体始终面向摄像机 Cesium For Unity Convert WGS84 to Earth Centered Earth Fixed 小流域设计洪水计算 cesium自定义st Redis Server监控数据采集 cesium添加过道corridor Cesium:entity闪烁(点、面以及billboard) arcgis 3.x 打印 CAS Client集群环境的Session问题及解决方案 不能退出登录 Client Server集群模式下session问题[转] quartz数据不完整导致不调度并且报错Couldn‘t store trigger arcgis popup关闭事件 arcgis 叠加图片 watch arcgis 叠加图片 三维地图3DGIS平台技术指标要求规划 Java – Get All Dates Between Two Dates 太阳方位角
TerrainProviderEdit
zhh · 2023-08-29 · via 博客园 - zhh

import {

    Request,

    TerrainData,

    Rectangle

} from 'cesium';

import * as turf from '@turf/turf';

import {

    Feature,

    Polygon

} from '@turf/turf';

const MAX_SHORT = 32767;

interface ModelEdit {

    polygon: Feature < Polygon > ;

    polygonTriangles: Feature < Polygon > [];

    // TIN algorithm result on polygon

}

export class TerrainProviderEdit extends Cesium.CesiumTerrainProvider {

    private modelEdits: ModelEdit[] = [];

    constructor({

        url,

        modelEdits

    }: {

        url: string;modelEdits: ModelEdit[]

    }) {

        super({

            url

        });

        this.modelEdits = modelEdits;

    }

    requestTileGeometry(x: number, y: number, level: number, request: Request): Promise < TerrainData > | undefined {

        const promise = super.requestTileGeometry(x, y, level, request);

        if (!promise || this.modelEdits.length === 0) {

            return promise;

        }

        const tileRectangle: Rectangle = this.tilingScheme.tileXYToRectangle(x, y, level);

        const tilePolygon = GeoUtils.rectangleToPolygon(tileRectangle);

        // Create turf polygon from tile rectangle

        const relevantEdits = this.modelEdits.filter(edit => turf.booleanOverlap(edit.polygon, tilePolygon) || turf.booleanContains(edit.polygon, tilePolygon));

        if (relevantEdits.length === 0) {

            return promise;

        }

        return promise.then((data: TerrainData) => this.modifyTerrainTile(data, tileRectangle, relevantEdits));

    }

    private modifyTerrainTile(terrainData: TerrainData, tileRectangle: Rectangle, modelEdits: ModelEdit[]) {

        const data = terrainData as any;

        const minimumHeight = data._minimumHeight;

        const maximumHeight = data._maximumHeight;

        const quantizedVertices: Uint16Array = data._quantizedVertices;

        const vertexCount = quantizedVertices.length / 3;

        const positions: number[][] = [];

        for (let i = 0; i < vertexCount; i++) {

            const rawU = quantizedVertices[i];

            const rawV = quantizedVertices[i + vertexCount];

            const rawH = quantizedVertices[i + vertexCount * 2];

            const u = rawU / MAX_SHORT;

            const v = rawV / MAX_SHORT;

            const longitude = Cesium.Math.toDegrees(Cesium.Math.lerp(tileRectangle.west, tileRectangle.east, u));

            const latitude = Cesium.Math.toDegrees(Cesium.Math.lerp(tileRectangle.south, tileRectangle.north, v));

            let height = Cesium.Math.lerp(minimumHeight, maximumHeight, rawH / MAX_SHORT);

            const currentPoint = turf.point([longitude, latitude]);

            const relevantEdit = modelEdits.find(edit => turf.booleanPointInPolygon(currentPoint, edit.polygon));

            if (relevantEdit) {

                const relevantTriangle = relevantEdit.polygonTriangles.find(triangle => turf.booleanPointInPolygon(currentPoint, triangle));

                if (relevantTriangle) {

                    height = turf.planepoint(currentPoint, relevantTriangle);

                }

            }

            positions.push([longitude, latitude, height]);

        } // TODO: split mesh triangles that are crossing the user polygon's perimiter and recreate mesh

        const heights = positions.map(p => p[2]);

        const newMinHeight = Math.min(...heights);

        const newMaxHeight = Math.max(...heights);

        const newQuantizedVertices = new Uint16Array(positions.length * 3);

        positions.forEach((p, i) => {

            const lonRad = Cesium.Math.toRadians(p[0]);

            newQuantizedVertices[i] = Math.round(Cesium.Math.lerp(MAX_SHORT, 0, (lonRad - tileRectangle.east) / (tileRectangle.west - tileRectangle.east)));

            const latRad = Cesium.Math.toRadians(p[1]);

            newQuantizedVertices[i + positions.length] = Math.round(Cesium.Math.lerp(MAX_SHORT, 0, (latRad - tileRectangle.north) / (tileRectangle.south - tileRectangle.north)));

            const relativeHeight = Math.round(Cesium.Math.lerp(0, MAX_SHORT, (p[2] - newMinHeight) / (newMaxHeight - newMinHeight)));

            newQuantizedVertices[i + positions.length * 2] = relativeHeight;

        });

        data._minimumHeight = newMinHeight;

        data._maximumHeight = newMaxHeight;

        data._quantizedVertices = newQuantizedVertices;

        return data as TerrainData;

    }

}