I have multiple datasets with coordinates in them and I want to plot these points in Cesium for Unreal. For me to do that, I need to correct terrain heights and I want to have them in Python (since I'm doing some other stuff as well). Here I'm a bit stuck.
There is no API for Cesium that seems to be available for this task, so I used Python to create a HTML file, put the coordinates in there and retrieve the terrain heights:
import json
import threading
import time
from flask import Flask, request, send_file
import webbrowser
import tempfile
import os
def get_terrain_heights(points, access_token):
results = []
app = Flask(__name__)
temp_html_file = tempfile.NamedTemporaryFile(delete=False, suffix=".html")
temp_html_file.close()
html_content = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cesium Terrain Fetch</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/Build/Cesium/Cesium.js"></script>
<style>
html, body, #cesiumContainer {{width:100%; height:100%; margin:0; padding:0; overflow:hidden;}}
</style>
</head>
<body>
<div id="cesiumContainer"></div>
<script>
Cesium.Ion.defaultAccessToken = '{access_token}';
const viewer = new Cesium.Viewer('cesiumContainer', {{
terrainProvider: Cesium.createWorldTerrain()
}});
const points = {json.dumps(points)};
let results = [];
function sendToPython(data) {{
fetch('/submit', {{
method: 'POST',
headers: {{'Content-Type': 'application/json'}},
body: JSON.stringify(data)
}});
}}
points.forEach(p => {{
const position = Cesium.Cartographic.fromDegrees(p.lon, p.lat);
Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, [position]).then(updatedPositions => {{
const terrainHeight = updatedPositions[0].height;
const ellipsoidHeight = terrainHeight + p.alt_above_ground;
results.push({{
lat: p.lat,
lon: p.lon,
alt_above_ground: p.alt_above_ground,
terrain_height: terrainHeight,
alt_ellipsoid: ellipsoidHeight
}});
if (results.length === points.length) {{
sendToPython(results);
alert('Terrain heights fetched. You can close this window.');
}}
}});
}});
</script>
</body>
</html>
"""
with open(temp_html_file.name, "w") as f:
f.write(html_content)
@app.route('/')
def index():
return send_file(temp_html_file.name)
@app.route('/submit', methods=['POST'])
def submit():
nonlocal results
results = request.json
return {"status": "ok"}
def run_app():
app.run(port=5000)
thread = threading.Thread(target=run_app, daemon=True)
thread.start()
webbrowser.open("http://127.0.0.1:5000/")
while not results:
time.sleep(0.5)
# Delete the temporary file only after getting results
try:
os.unlink(temp_html_file.name)
except:
pass
return results
# Usage:
points = [{"lat": 52.3109, "lon": 4.77028, "alt_above_ground": 0},
{"lat": 52.3109, "lon": 4.57028, "alt_above_ground": 0}]
access_token = "access_token"
terrain_data = get_terrain_heights(points, access_token)
This works actually really good, it returns a list of dictionaries with the information I need. So this works, but only once. The second time I want to use this code it gives me the error:
FileNotFoundError: [WinError 2] The system cannot find the file specified: 'C:\Users\username\AppData\Local\Temp\tmp4y1vst8b.html'
This is logical, since it removes the temporary file after using. When I remove that piece of code however, it still does not work: it keeps running in the Python kernel and nothing happens, no data is retrieved.
Can someone assist in how to handle this? I want to go to a solution that I simply run the function, it retrieves the information I need and then it's done. If I want to run it after 1 minute again with other information, then it should be able to do that.
get_terrain_heights()many times in the same code then maybe don't unlink file. Or maybe create it insideindex()and unlink it insubmit()- and it will create it again when you will run many timesget_terrain_heights().cesium ion APIin Google and I found Ion REST API documentation – Cesium and APIs – Cesium. But I don't understand what you try to get so I don't know what to search in documentation.python cesium ion APIin Google and I found cesiumpy · PyPI