<!DOCTYPE html> <html lang="en"> <head> <!-- Use correct character set. --> <meta charset="utf-8" /> <!-- Tell IE to use the latest, best version. --> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <!-- Make the application on mobile take up the full browser screen and disable user scaling. --> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> <title>Hello World!</title> <script src="../Build/Cesium/Cesium.js"></script> <style> @import url(../Build/CesiumUnminified/Widgets/widgets.css); html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } .control-panel { position: absolute; top: 10px; left: 10px; background: rgba(42, 42, 42, 0.95); padding: 15px; border-radius: 8px; color: white; z-index: 1000; min-width: 300px; font-family: Arial, sans-serif; } .control-panel h3 { margin: 0 0 10px 0; color: #48b; } .control-panel button { margin: 5px; padding: 8px 12px; background: #48b; border: none; color: white; border-radius: 4px; cursor: pointer; width: 100%; } .control-panel button:hover { background: #5a9; } .info-section { margin: 10px 0; padding: 10px; background: rgba(255, 255, 255, 0.1); border-radius: 4px; } .info-item { margin: 5px 0; font-size: 12px; } .color-legend { display: flex; height: 20px; margin: 5px 0; border-radius: 3px; overflow: hidden; } </style> </head> <body> <div id="cesiumContainer"></div> <div class="control-panel"> <h3>二维贴地等高线 - IDW算法</h3> <button onclick="generateNewData()">🔄 生成新数据</button> <button onclick="toggleContours()">📊 切换等高线</button> <button onclick="togglePoints()">📍 切换采样点</button> <button onclick="toggleFill()">🎨 切换颜色填充</button> <div class="info-section"> <div class="info-item">采样点: <span id="pointCount">100</span>个</div> <div class="info-item">数值范围: <span id="valueRange">-</span></div> <div class="info-item">等高线: <span id="contourCount">0</span>条</div> <div class="info-item">网格精度: <span id="gridSize">50</span>x50</div> </div> <div class="info-section"> <div class="info-item">IDW参数:</div> <select id="powerSelect" onchange="updateParameters()"> <option value="1">幂参数: 1 (平滑)</option> <option value="2" selected>幂参数: 2 (标准)</option> <option value="3">幂参数: 3 (锐利)</option> </select> <select id="gridSelect" onchange="updateParameters()"> <option value="30">网格: 30x30</option> <option value="50" selected>网格: 50x50</option> <option value="70">网格: 70x70</option> </select> </div> <div class="info-section"> <div class="info-item">颜色图例 (低 → 高):</div> <div class="color-legend" id="colorLegend"></div> </div> </div> <script> const viewer = new Cesium.Viewer("cesiumContainer"); // 设置初始视角 // 设置初始视角 viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(117.5, 33, 80000), orientation: { heading: 0.0, pitch: -0.8, roll: 0.0, }, }); // 全局变量 let points = []; let contoursVisible = true; let pointsVisible = true; let fillVisible = true; let idwPower = 2; let gridSize = 50; // 数据源 let contourDataSource = new Cesium.CustomDataSource("等高线"); let pointDataSource = new Cesium.CustomDataSource("采样点"); let fillDataSource = new Cesium.CustomDataSource("颜色填充"); viewer.dataSources.add(contourDataSource); viewer.dataSources.add(pointDataSource); viewer.dataSources.add(fillDataSource); // 初始化 points = generateRandomPoints(); generateContourLines(); function generateRandomPoints() { const points = []; const minLon = 117.0; const maxLon = 118.0; const minLat = 32.0; const maxLat = 34; const numPoints = 100; for (let i = 0; i < numPoints; i++) { const lon = minLon + Math.random() * (maxLon - minLon); const lat = minLat + Math.random() * (maxLat - minLat); // 创建一个有规律的山丘状分布 const centerLon = 117.5; const centerLat = 33; const distance = Math.sqrt( Math.pow(lon - centerLon, 2) + Math.pow(lat - centerLat, 2) ); // 使用高斯函数创建山丘效果 const value = 50 * Math.exp(-distance * distance * 10) + 20 * Math.sin(lon * 8) + 15 * Math.cos(lat * 8) + Math.random() * 10; points.push({ longitude: lon, latitude: lat, height: 0, value: value, }); } return points; } // 反距离加权插值 function idwInterpolation(targetLon, targetLat, points, power = 2) { let numerator = 0; let denominator = 0; for (const point of points) { const distance = Math.sqrt( Math.pow(point.longitude - targetLon, 2) + Math.pow(point.latitude - targetLat, 2) ); if (distance === 0) return point.value; const weight = 1 / Math.pow(distance, power); numerator += weight * point.value; denominator += weight; } return numerator / denominator; } function generateContourLines() { // 清除之前的数据 clearDataSources(); if (points.length === 0) return; // 计算数值范围 const values = points.map((p) => p.value); const minValue = Math.min(...values); const maxValue = Math.max(...values); const valueRange = maxValue - minValue; // 生成网格数据 const gridData = generateGridData(minValue, maxValue, points); // 生成颜色填充 if (fillVisible) { generateColorFill(gridData, minValue, maxValue); } // 生成等高线 generateContours(gridData, minValue, maxValue); // 显示采样点 if (pointsVisible) { showSamplingPoints(minValue, maxValue); } updateColorLegend(minValue, maxValue); } function generateGridData(minValue, maxValue, points) { const gridLons = []; const gridLats = []; const gridValues = []; const longitudes = points.map((p) => p.longitude); const minLongitudes = Math.min(...longitudes); const maxLongitudes = Math.max(...longitudes); const latitudes = points.map((p) => p.latitude); const minLatitudes = Math.min(...latitudes); const maxLatitudes = Math.max(...latitudes); // 生成网格坐标 for (let i = 0; i < gridSize; i++) { gridLons[i] = minLongitudes + (i / (gridSize - 1)) * (maxLongitudes - minLongitudes); gridLats[i] = minLatitudes + (i / (gridSize - 1)) * (maxLatitudes - minLatitudes); gridValues[i] = new Array(gridSize); } // 计算每个网格点的IDW值 for (let i = 0; i < gridSize; i++) { for (let j = 0; j < gridSize; j++) { gridValues[i][j] = idwInterpolation( gridLons[i], gridLats[j], points, idwPower ); } } return { gridLons, gridLats, gridValues, minValue, maxValue }; } function generateColorFill(gridData, minValue, maxValue) { const { gridLons, gridLats, gridValues } = gridData; const valueRange = maxValue - minValue; // 为每个网格单元创建颜色填充 for (let i = 0; i < gridSize - 1; i++) { for (let j = 0; j < gridSize - 1; j++) { const value = gridValues[i][j]; const normalizedValue = (value - minValue) / valueRange; // 计算颜色 const hue = (1 - normalizedValue) * 240; const color = Cesium.Color.fromHsl(hue / 360, 0.7, 0.5, 0.6); // 创建网格单元的多边形 const positions = [ Cesium.Cartesian3.fromDegrees(gridLons[i], gridLats[j]), Cesium.Cartesian3.fromDegrees(gridLons[i + 1], gridLats[j]), Cesium.Cartesian3.fromDegrees(gridLons[i + 1], gridLats[j + 1]), Cesium.Cartesian3.fromDegrees(gridLons[i], gridLats[j + 1]), ]; fillDataSource.entities.add({ polygon: { hierarchy: positions, material: color, height: 0, extrudedHeight: 0, outline: false, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, }, }); } } } function generateContours(gridData, minValue, maxValue) { const { gridLons, gridLats, gridValues } = gridData; const valueRange = maxValue - minValue; const contourInterval = valueRange / 15; const numContours = Math.ceil(valueRange / contourInterval); document.getElementById("contourCount").textContent = numContours; // 为每个等高线级别生成线条 for (let level = 0; level <= numContours; level++) { const contourValue = minValue + level * contourInterval; const contourLines = []; // 遍历网格单元,寻找等高线 for (let i = 0; i < gridSize - 1; i++) { for (let j = 0; j < gridSize - 1; j++) { const cellValues = [ gridValues[i][j], gridValues[i + 1][j], gridValues[i + 1][j + 1], gridValues[i][j + 1], ]; const cellPoints = [ { lon: gridLons[i], lat: gridLats[j] }, { lon: gridLons[i + 1], lat: gridLats[j] }, { lon: gridLons[i + 1], lat: gridLats[j + 1] }, { lon: gridLons[i], lat: gridLats[j + 1] }, ]; // 寻找等高线与网格边的交点 const intersections = []; for (let k = 0; k < 4; k++) { const v1 = cellValues[k]; const v2 = cellValues[(k + 1) % 4]; if ( (v1 < contourValue && v2 >= contourValue) || (v1 >= contourValue && v2 < contourValue) ) { const t = (contourValue - v1) / (v2 - v1); const lon = cellPoints[k].lon + t * (cellPoints[(k + 1) % 4].lon - cellPoints[k].lon); const lat = cellPoints[k].lat + t * (cellPoints[(k + 1) % 4].lat - cellPoints[k].lat); intersections.push(Cesium.Cartesian3.fromDegrees(lon, lat)); } } // 如果有两个交点,创建等高线段 if (intersections.length === 2) { contourLines.push({ positions: intersections, value: contourValue, }); } } } // 绘制等高线 if (contourLines.length > 0) { const normalizedValue = (contourValue - minValue) / valueRange; const hue = (1 - normalizedValue) * 240; const color = Cesium.Color.fromHsl(hue / 360, 0.9, 0.3); // 为每个等高线段创建实体 contourLines.forEach((line) => { contourDataSource.entities.add({ polyline: { positions: line.positions, width: 2, material: color, clampToGround: true, }, }); }); // 添加等高线标签 if (contourLines.length > 0 && level % 2 === 0) { const midPoint = contourLines[Math.floor(contourLines.length / 2)].positions[0]; contourDataSource.entities.add({ position: midPoint, label: { text: contourValue.toFixed(0), font: "12pt Arial", fillColor: Cesium.Color.BLACK, outlineColor: Cesium.Color.WHITE, outlineWidth: 2, style: Cesium.LabelStyle.FILL_AND_OUTLINE, pixelOffset: new Cesium.Cartesian2(0, 0), heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, }, }); } } } } function showSamplingPoints(minValue, maxValue) { const valueRange = maxValue - minValue; points.forEach((point, index) => { const normalizedValue = (point.value - minValue) / valueRange; const hue = (1 - normalizedValue) * 240; const color = Cesium.Color.fromHsl(hue / 360, 0.8, 0.5); pointDataSource.entities.add({ position: Cesium.Cartesian3.fromDegrees( point.longitude, point.latitude ), point: { pixelSize: 8, color: color, outlineColor: Cesium.Color.BLACK, outlineWidth: 1, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, disableDepthTestDistance: Number.POSITIVE_INFINITY, }, label: { text: point.value.toFixed(0), font: "10pt Arial", pixelOffset: new Cesium.Cartesian2(0, -15), fillColor: Cesium.Color.BLACK, outlineColor: Cesium.Color.WHITE, outlineWidth: 2, style: Cesium.LabelStyle.FILL_AND_OUTLINE, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, }, }); }); } function clearDataSources() { contourDataSource.entities.removeAll(); pointDataSource.entities.removeAll(); fillDataSource.entities.removeAll(); } function updateColorLegend(minValue, maxValue) { const legend = document.getElementById("colorLegend"); legend.innerHTML = ""; for (let i = 0; i < 10; i++) { const normalizedValue = i / 9; const hue = (1 - normalizedValue) * 240; const color = Cesium.Color.fromHsl(hue / 360, 0.7, 0.5); const colorHex = Cesium.Color.toCssColorString(color); const colorBar = document.createElement("div"); colorBar.style.flex = "1"; colorBar.style.background = colorHex; colorBar.title = `${( minValue + normalizedValue * (maxValue - minValue) ).toFixed(1)}`; legend.appendChild(colorBar); } } function toggleContours() { contoursVisible = !contoursVisible; contourDataSource.show = contoursVisible; } function togglePoints() { pointsVisible = !pointsVisible; pointDataSource.show = pointsVisible; } function toggleFill() { fillVisible = !fillVisible; fillDataSource.show = fillVisible; } function updateParameters() { idwPower = parseInt(document.getElementById("powerSelect").value); gridSize = parseInt(document.getElementById("gridSelect").value); generateContourLines(); } </script> </body> </html>
效果截图:

浙公网安备 33010602011771号