0

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.

marc_s
760k186 gold badges1.4k silver badges1.5k bronze badges
asked Aug 16, 2025 at 11:49
6
  • always put full error message because there are other useful information. Commented Aug 16, 2025 at 12:57
  • if you run get_terrain_heights() many times in the same code then maybe don't unlink file. Or maybe create it inside index() and unlink it in submit() - and it will create it again when you will run many times get_terrain_heights(). Commented Aug 16, 2025 at 13:04
  • Executing Javascript from Python - Stack Overflow Commented Aug 16, 2025 at 13:05
  • I search cesium ion API in 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. Commented Aug 16, 2025 at 13:13
  • I search python cesium ion API in Google and I found cesiumpy · PyPI Commented Aug 16, 2025 at 13:14

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.