Python bindings for FlatCityBuf - a cloud-optimized binary format for 3D city models
Project description
FlatCityBuf Python Bindings
Python bindings for FlatCityBuf, a cloud-optimized binary format for storing and retrieving 3D city models with full CityJSON compatibility.
Features
- Fast reading of FlatCityBuf (.fcb) files with zero-copy access
- Local and HTTP file support with async iteration
- CityJSON integration with transform, metadata, and proper structure
- Spatial queries using bounding boxes with R-tree indexing
- Attribute queries for filtering features with B+tree indices
- Async iterators for efficient streaming from HTTP sources
- Nested boundaries support for complex 3D geometries
- Pythonic API with comprehensive type support
Installation
From Source
# Prerequisites: Rust toolchain and maturin
pip install maturin
# Build and install with HTTP support
cd src/rust/fcb_py
maturin develop --features http
Using pip (when available)
pip install flatcitybuf
Quick Start
Local File Access
import flatcitybuf as fcb
# Read a local file
reader = fcb.Reader("https://storage.googleapis.com/flatcitybuf/3dbag_all_index.fcb")
# Get file information
info = reader.info()
print(f"Features: {info.feature_count}")
# Get CityJSON header with transform and metadata
cityjson = reader.cityjson_header()
print(f"CityJSON version: {cityjson.version}")
print(f"Transform: {cityjson.transform.scale}, {cityjson.transform.translate}")
# Iterate all features (CityJSON format)
for feature in reader:
print(f"ID: {feature.id}, Type: {feature.type}")
print(f"City Objects: {len(feature.city_objects)}")
print(f"Vertices: {len(feature.vertices)}")
# Spatial query
features = list(reader.query_bbox(84227.77, 445377.33, 85323.23, 446334.69))
print(f"Found {len(features)} features in bounding box")
# Attribute query
id_filter = fcb.AttrFilter("identificatie", fcb.Operator.Eq, "building_123")
buildings = list(reader.query_attr([id_filter]))
print(f"Found {len(buildings)} matching buildings")
HTTP Access with Async Iterators
import asyncio
import flatcitybuf as fcb
async def main():
# Create async reader for HTTP URL
async_reader = fcb.AsyncReader("https://storage.googleapis.com/flatcitybuf/3dbag_subset_all_index.fcb")
opened_reader = await async_reader.open()
# Get file info
info = opened_reader.info()
print(f"Features: {info.feature_count}")
# Async iteration - efficient streaming
async_iter = opened_reader.select_all()
# Process features one by one
count = 0
while count < 10: # Get first 10 features
feature = await async_iter.next()
if feature is None:
break
print(f"Feature {count}: {feature.id}")
count += 1
# Or collect all at once
all_features = await opened_reader.select_all().collect()
print(f"Total features: {len(all_features)}")
# Async spatial query
bbox_iter = opened_reader.query_bbox(84227.77, 445377.33, 85323.23, 446334.69)
spatial_features = await bbox_iter.collect()
print(f"Spatial query result: {len(spatial_features)} features")
asyncio.run(main())
API Reference
Reader (Synchronous)
Main class for reading local FlatCityBuf files.
reader = fcb.Reader(path: str)
Methods:
info() -> FileInfo- Get file metadata and statisticscityjson_header() -> CityJSON- Get CityJSON header with transform/metadataquery_bbox(min_x, min_y, max_x, max_y) -> Iterator[Feature]- Spatial queryquery_attr(filters: List[AttrFilter]) -> Iterator[Feature]- Attribute query__iter__() -> Iterator[Feature]- Iterate all features
AsyncReader (HTTP)
Asynchronous reader for HTTP-based FlatCityBuf files.
async_reader = fcb.AsyncReader(url: str)
opened_reader = await async_reader.open()
Methods:
info() -> FileInfo- Get file metadatacityjson_header() -> CityJSON- Get CityJSON header informationselect_all() -> AsyncFeatureIterator- Get all features as async iteratorquery_bbox(min_x, min_y, max_x, max_y) -> AsyncFeatureIterator- Async spatial queryquery_attr(filters: List[AttrFilter]) -> AsyncFeatureIterator- Async attribute query
AsyncFeatureIterator
Efficient async iterator for streaming features from HTTP sources.
# Get features one by one
feature = await async_iter.next() # Returns Feature or None
# Collect all remaining features
features = await async_iter.collect() # Returns List[Feature]
Feature (CityJSON Format)
Represents a CityJSON feature with proper structure.
class Feature:
id: str # Feature ID
type: str # Feature type
vertices: List[List[float]] # 3D vertices as [x, y, z] arrays
city_objects: Dict[str, CityObject] # Dictionary of city objects
CityObject
Individual city object within a feature.
class CityObject:
type: str # Object type (e.g., "Building")
geometry: List[Geometry] # List of geometries
attributes: Dict[str, Any] # Object attributes
children: List[str] # Child object IDs
parents: List[str] # Parent object IDs
Geometry
3D geometry with nested boundary structure.
class Geometry:
type: str # Geometry type
boundaries: PyObject # Nested boundary arrays (preserves structure)
semantics: Optional[Any] # Semantic information
CityJSON Header
CityJSON metadata and transform information.
class CityJSON:
type: str # Always "CityJSON"
version: str # CityJSON version
transform: Transform # Coordinate transformation
metadata: Optional[Metadata] # Optional metadata
feature_count: int # Number of features
Transform
Coordinate transformation parameters.
class Transform:
scale: List[float] # Scale factors [x, y, z]
translate: List[float] # Translation [x, y, z]
Query Types
# Bounding box
bbox = fcb.BBox(min_x=0, min_y=0, max_x=100, max_y=100)
# Attribute filters
filter_eq = fcb.AttrFilter("type", fcb.Operator.Eq, "building")
filter_gt = fcb.AttrFilter("height", fcb.Operator.Gt, 50.0)
filter_le = fcb.AttrFilter("floors", fcb.Operator.Le, 10)
# Available operators
fcb.Operator.Eq # Equal
fcb.Operator.Ne # Not equal
fcb.Operator.Gt # Greater than
fcb.Operator.Ge # Greater than or equal
fcb.Operator.Lt # Less than
fcb.Operator.Le # Less than or equal
Performance
The Python bindings leverage Rust's zero-copy deserialization and efficient indexing:
- 10-20× faster than parsing equivalent JSON formats
- 2-6× less memory usage compared to text formats
- Efficient spatial indexing with packed R-tree queries
- HTTP range requests for cloud-optimized partial access
- Async streaming minimizes memory usage for large datasets
- Nested boundary preservation avoids flattening overhead
Nested Boundaries
The bindings properly preserve CityJSON's nested boundary structure:
# Boundaries can be nested arrays at arbitrary depth
# Example: [[0, 1, 2, 3]] for a single surface
# Example: [[[0, 1, 2, 3], [4, 5, 6, 7]]] for surfaces with holes
geometry.boundaries # Preserves exact nesting from CityJSON
HTTP Optimization
AsyncReader is optimized for HTTP access:
- Persistent connections - HTTP client maintained across iterator calls
- Range request batching - Efficient partial downloads
- Prefetching strategies - Reduces round-trip latency
- Async streaming - Process features as they arrive
Examples
See the examples/ directory for comprehensive usage examples including:
- Basic local file reading
- HTTP access with async iteration
- CityJSON header processing
- Spatial and attribute queries
- Nested geometry handling
Development
Building from Source
# Install development dependencies
pip install maturin pytest pytest-asyncio
# Build in development mode
maturin develop --features http
# Run tests
pytest tests/
# Run with coverage
pytest tests/ --cov=flatcitybuf
Testing
# Run all tests
python -m pytest tests/test_e2e.py -v
# Run only sync tests
python -m pytest tests/test_e2e.py::TestE2EIntegration -v
# Run only async tests
python -m pytest tests/test_e2e.py::TestAsyncReaderE2E -v
Project Structure
src/rust/fcb_py/
├── python/ # Python stub files
├── src/ # Rust PyO3 bindings
│ ├── lib.rs # Main module
│ ├── reader.rs # Sync reader
│ ├── async_reader.rs # Async reader
│ ├── types.rs # Python types
│ ├── utils.rs # Conversion utilities
│ └── query.rs # Query types
├── tests/ # Python tests
├── examples/ # Usage examples
├── Cargo.toml # Rust dependencies
└── pyproject.toml # Python project config
License
MIT License - see LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flatcitybuf-0.2.0.tar.gz.
File metadata
- Download URL: flatcitybuf-0.2.0.tar.gz
- Upload date:
- Size: 1.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ded5c8fa50e427649f0aa9a9345c698866b3ffbd9714d6534a7e975fe7031b5
|
|
| MD5 |
84bc5275a3977d85553f8a0bdeb1840a
|
|
| BLAKE2b-256 |
6c93e921b99a0ccbb3363fd4e4a7e6cc2ddbfe0d420ebf1891254500581d60a5
|
File details
Details for the file flatcitybuf-0.2.0-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: flatcitybuf-0.2.0-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9af168476fee1c6bb515cbed527341575401cf209d5daf783dd7b70acc43228d
|
|
| MD5 |
dc3e3bc997d85178990972e4f64d8a1a
|
|
| BLAKE2b-256 |
c7772283f54852ef0187a32c6e86667bf9efc2aea107b30e1e92f1f9bce9b139
|
File details
Details for the file flatcitybuf-0.2.0-cp39-cp39-win_amd64.whl.
File metadata
- Download URL: flatcitybuf-0.2.0-cp39-cp39-win_amd64.whl
- Upload date:
- Size: 2.1 MB
- Tags: CPython 3.9, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
88c4da33e7d310ebe0e302b6cb066856d2f16c7706eb78aa1c58aaf64fc85163
|
|
| MD5 |
831a7df9f10ce5f2fd5a29302084bdda
|
|
| BLAKE2b-256 |
8b7e8d32bc80351af2c6d4fb6de598946aad29fac01a1487843313cc1106f643
|