GeoJSON to 3D Exploration - Initial Research with ChatGPT
Question 1
I have a network of sewer mains described in a 2D GeoJSON file. Currently, I am using Cesium to generate 3D models at runtime, but this is incredibly slow. I would like to instead preprocess the geojson to generate a collection of 3D models and/or a 3D scene, whatever would work best. The only stipulation is that each individual entity (sewer main) needs to be clickable. Also, some of the mains are segmented (denoted with multi-linestrings instead of simple linestrings). The final product will either be uploaded to Cesium Ion for serving, or it will be served from the local website's static content directory. What are my options for performing this pre-processing programmatically?
- Convert GeoJSON to glTF or 3D Tiles
- Export to COLLADA or KML
- Generate a Preprocessed 3D Scene Locally
- Tools to Consider:
- Python Libraries:
- trimesh: Create and export 3D geometries as glTF.
- py3dtiles: Convert geometries into 3D Tiles.
- Fiona and Shapely: Handle GeoJSON input.
- Node.js Tools:
- @turf/turf: GeoJSON processing.
- three.js: Model generation and export.
- Python Libraries:
Question 2
Could cadquery work for generating the 3D models? [https://www.viktor.ai/blog/166/how-to-make-complex-3d-models-with-python]
It answered yes and gave some explanation, but I don't think this will be a good fit...
Question 3
For ease of transformations, all tubes or cylinders should be extruded on either the X or Y plane, effectively defining height by radius and length the extrusion.
Extruding all tubes or cylinders on a single plane (X or Y) is a good strategy for simplicity in transformations. You can build your tubes in this manner by:
Defining the path (geometry) on the chosen plane—either XZ or YZ—depending on your preferred orientation.
Using radius to define the cross-sectional size of the tube.
Extruding along the length of the sewer main based on your GeoJSON coordinates.
Then it has some examples of how to do so in CADQuery
Question 4
Since I need the final results to be georeferenced, is there a programmatic solution that's better suited than the others?
For georeferenced 3D models that need to work seamlessly with Cesium (especially in WGS84 coordinates), Cesium 3D Tiles or glTF models with embedded georeferencing are your best options. Below is an overview of programmatic solutions specifically suited for georeferenced 3D data processing:
FME (Feature Manipulation Engine)
- Why it's suited: FME can convert GeoJSON to 3D Tiles, glTF, or COLLADA, ensuring georeferencing is preserved.
- Capabilities:
- Works with geospatial data formats and can process large GeoJSON files.
- Can automate workflows for converting and georeferencing 2D paths into 3D tubes or cylinders.
- Programmatic Access:
- Use FME Desktop to design workflows and FME Server or FME Engine for programmatic execution via APIs.
- Use Case: Ideal if you have the budget and want a no-code/low-code solution with robust geospatial handling.
Py3D Tiles
- Why it's suited: Py3D Tiles is an open-source library specifically designed for generating 3D Tiles from geospatial data.
- Capabilities:
- Can handle GeoJSON and produce 3D Tiles for use in Cesium.
- Allows you to define tilesets with per-entity metadata (e.g., IDs for click events).
- Programmatic Access:
- Use Python to preprocess your GeoJSON, extrude paths into 3D, and generate 3D Tiles.
- Use Case: Great if you’re focused on Cesium compatibility and want to control the tiling process programmatically.
Blender with GIS Add-ons
- Why it's suited: Blender's GIS add-ons allow you to import GeoJSON, work in WGS84 coordinates, and export georeferenced 3D models.
- Capabilities:
- Use Python scripts within Blender to automate extrusion, material application, and export processes.
- Export models in glTF with embedded georeferencing for Cesium.
- Programmatic Access:
- Automate Blender tasks with its Python API, such as reading GeoJSON and applying transformations.
- Use Case: Best for complex visualizations or when custom materials/textures are required.
OGR + GDAL + Custom Libraries
- Why it's suited: The OGR library from GDAL is excellent for working with geospatial formats programmatically, including GeoJSON, while preserving georeferencing.
- Capabilities:
- Parse GeoJSON, perform geometric transformations, and extrude into 3D models.
- Combine with libraries like pyvista, vtk, or trimesh for creating tubes or cylinders.
- Export results as glTF or 3D Tiles.
- Use Case: Ideal for those comfortable with Python and needing open-source, low-level tools.
Cesium ion + Custom Preprocessing
- Why it's suited: Cesium ion simplifies uploading GeoJSON and automatically converts it into 3D Tiles with georeferencing.
- Capabilities:
- Preprocess your GeoJSON locally (e.g., extrude paths into 3D using CadQuery or other tools).
- Upload preprocessed models to Cesium ion for tiling and georeferencing.
- Programmatic Access:
- Use the Cesium ion REST API to upload and manage assets.
- Use Case: Perfect for minimal local preprocessing and leveraging Cesium’s tiling engine.
3D CityDB Importer/Exporter
- Why it's suited: Designed for geospatial 3D city models, it supports the CityGML format, which can be converted to 3D Tiles.
- Capabilities:
- Import GeoJSON data, extrude paths, and export georeferenced 3D models in formats like KML, COLLADA, or glTF.
- Convert results to 3D Tiles for Cesium.
- Programmatic Access:
- Use the Importer/Exporter tool for batch processing or automate tasks via its command-line interface.
- Use Case: Suitable for projects with city-scale data and strong geospatial requirements.
Recommendation for Your Case
- If you need georeferenced 3D models of sewer mains, here’s a streamlined pipeline:
- Use Py3D Tiles (or Cesium ion if you prefer cloud-based processing):
- Preprocess GeoJSON with Python:
- Parse coordinates and extrude 3D tubes using CadQuery, pyvista, or similar.
- Include georeferencing metadata (WGS84).
- Export to 3D Tiles:
- Use Py3D Tiles to programmatically create a tileset where each tube is clickable.
- Preprocess GeoJSON with Python:
- Use Py3D Tiles (or Cesium ion if you prefer cloud-based processing):
- Use Cesium ion (easiest for glTF/3D Tiles):
- Preprocess GeoJSON into 3D tubes locally.
- Upload to Cesium ion for georeferenced tiling and serving.
- Alternative Low-Level Workflow with OGR + GDAL:
- Parse and extrude GeoJSON using OGR.
- Create 3D tiles programmatically using Py3D Tiles or export as glTF.
Comparison

Question 5
For now, I'm less interested in the tiling process and more interested in making sure that my network of pipes can be generated and rendered properly. I can consider tiling at a later time for optimization after I verify it works in the first place. I would like a free option (so no FME) and I don't think that 3D City DB will work. With this in mind, what are my best options?
Answer 1
- Python + PyVista/VTK for 3D Model Generation
- Blender with Python API for GeoJSON to 3D glTF
- OGR + GDAL + trimesh for GeoJSON to 3D
- Cesium ion with Preprocessed glTF Models
Answer 2
Python with GDAL and 3D Modeling Libraries
Parse GeoJSON: Use GDAL or Python libraries like geojson or shapely to parse GeoJSON and extract LineString or MultiLineString geometries.
import geojson
with open("sewer_mains.geojson") as f:
data = geojson.load(f)
for feature in data["features"]:
coords = feature["geometry"]["coordinates"]
print(f"Pipe coordinates: {coords}")Generate 3D Tubes: Use vtk or trimesh to extrude the lines into 3D tubes or cylinders.
import trimesh
import numpy as np
def generate_tube(coordinates, radius=0.5):
# Create a 3D tube along the coordinates
path = trimesh.load_path(np.array(coordinates))
tube = path.to_tubes(radius=radius, count=8)
return tubeEmbed Georeferencing
- Use the geographic coordinates (WGS84) directly in your 3D model.
- For each tube, ensure its position aligns with the geographic coordinate system.
Export to glTF
import bpy
import mathutils
# Example coordinates
coordinates = [(0, 0, 0), (10, 0, 0), (10, 10, 0)]
# Create a curve
curve = bpy.data.curves.new("PipeCurve", type="CURVE")
curve.dimensions = "3D"
spline = curve.splines.new(type="POLY")
spline.points.add(len(coordinates) - 1)
for i, coord in enumerate(coordinates):
x, y, z = coord
spline.points[i].co = (x, y, z, 1)
# Create an object from the curve
curve_obj = bpy.data.objects.new("Pipe", curve)
bpy.context.scene.collection.objects.link(curve_obj)
# Extrude to make a 3D tube
bpy.ops.object.convert(target="MESH")
bpy.ops.object.modifier_add(type="SOLIDIFY")
Blender with Python Automation
Import the GeoJSON directly into Blender using GIS add-ons (like BlenderGIS).
Extrude pipes/cylinders along the imported paths.
tube.export("pipe.glb")Automate the entire process with Blender’s Python API for batch processing.