Name | flatcitybuf JSON |
Version |
0.1.2
JSON |
| download |
home_page | None |
Summary | Python bindings for FlatCityBuf - a cloud-optimized binary format for 3D city models |
upload_time | 2025-08-12 20:15:55 |
maintainer | None |
docs_url | None |
author | HideBa |
requires_python | >=3.8.1 |
license | MIT |
keywords |
gis
3d
cityjson
citymodel
flatbuffers
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# FlatCityBuf Python Bindings
Python bindings for [FlatCityBuf](../../README.md), 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
```bash
# 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)
```bash
pip install flatcitybuf
```
## Quick Start
### Local File Access
```python
import flatcitybuf as fcb
# Read a local file
reader = fcb.Reader("data.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
```python
import asyncio
import flatcitybuf as fcb
async def main():
# Create async reader for HTTP URL
async_reader = fcb.AsyncReader("https://example.com/data.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.
```python
reader = fcb.Reader(path: str)
```
**Methods:**
- `info() -> FileInfo` - Get file metadata and statistics
- `cityjson_header() -> CityJSON` - Get CityJSON header with transform/metadata
- `query_bbox(min_x, min_y, max_x, max_y) -> Iterator[Feature]` - Spatial query
- `query_attr(filters: List[AttrFilter]) -> Iterator[Feature]` - Attribute query
- `__iter__() -> Iterator[Feature]` - Iterate all features
### AsyncReader (HTTP)
Asynchronous reader for HTTP-based FlatCityBuf files.
```python
async_reader = fcb.AsyncReader(url: str)
opened_reader = await async_reader.open()
```
**Methods:**
- `info() -> FileInfo` - Get file metadata
- `cityjson_header() -> CityJSON` - Get CityJSON header information
- `select_all() -> AsyncFeatureIterator` - Get all features as async iterator
- `query_bbox(min_x, min_y, max_x, max_y) -> AsyncFeatureIterator` - Async spatial query
- `query_attr(filters: List[AttrFilter]) -> AsyncFeatureIterator` - Async attribute query
### AsyncFeatureIterator
Efficient async iterator for streaming features from HTTP sources.
```python
# 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.
```python
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.
```python
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.
```python
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.
```python
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.
```python
class Transform:
scale: List[float] # Scale factors [x, y, z]
translate: List[float] # Translation [x, y, z]
```
### Query Types
```python
# 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:
```python
# 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/](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
```bash
# 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
```bash
# 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](../../LICENSE) file for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "flatcitybuf",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8.1",
"maintainer_email": null,
"keywords": "gis, 3d, cityjson, citymodel, flatbuffers",
"author": "HideBa",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/eb/17/2e18344ebf1fd2ebc5f1c5a4074d6e3cee4bb6e447a58428a0bae0d41d1f/flatcitybuf-0.1.2.tar.gz",
"platform": null,
"description": "# FlatCityBuf Python Bindings\n\nPython bindings for [FlatCityBuf](../../README.md), a cloud-optimized binary format for storing and retrieving 3D city models with full CityJSON compatibility.\n\n## Features\n\n- **Fast reading** of FlatCityBuf (.fcb) files with zero-copy access\n- **Local and HTTP** file support with async iteration\n- **CityJSON integration** with transform, metadata, and proper structure\n- **Spatial queries** using bounding boxes with R-tree indexing\n- **Attribute queries** for filtering features with B+tree indices\n- **Async iterators** for efficient streaming from HTTP sources\n- **Nested boundaries** support for complex 3D geometries\n- **Pythonic API** with comprehensive type support\n\n## Installation\n\n### From Source\n\n```bash\n# Prerequisites: Rust toolchain and maturin\npip install maturin\n\n# Build and install with HTTP support\ncd src/rust/fcb_py\nmaturin develop --features http\n```\n\n### Using pip (when available)\n\n```bash\npip install flatcitybuf\n```\n\n## Quick Start\n\n### Local File Access\n\n```python\nimport flatcitybuf as fcb\n\n# Read a local file\nreader = fcb.Reader(\"data.fcb\")\n\n# Get file information\ninfo = reader.info()\nprint(f\"Features: {info.feature_count}\")\n\n# Get CityJSON header with transform and metadata\ncityjson = reader.cityjson_header()\nprint(f\"CityJSON version: {cityjson.version}\")\nprint(f\"Transform: {cityjson.transform.scale}, {cityjson.transform.translate}\")\n\n# Iterate all features (CityJSON format)\nfor feature in reader:\n print(f\"ID: {feature.id}, Type: {feature.type}\")\n print(f\"City Objects: {len(feature.city_objects)}\")\n print(f\"Vertices: {len(feature.vertices)}\")\n\n# Spatial query\nfeatures = list(reader.query_bbox(84227.77, 445377.33, 85323.23, 446334.69))\nprint(f\"Found {len(features)} features in bounding box\")\n\n# Attribute query\nid_filter = fcb.AttrFilter(\"identificatie\", fcb.Operator.Eq, \"building_123\")\nbuildings = list(reader.query_attr([id_filter]))\nprint(f\"Found {len(buildings)} matching buildings\")\n```\n\n### HTTP Access with Async Iterators\n\n```python\nimport asyncio\nimport flatcitybuf as fcb\n\nasync def main():\n # Create async reader for HTTP URL\n async_reader = fcb.AsyncReader(\"https://example.com/data.fcb\")\n opened_reader = await async_reader.open()\n \n # Get file info\n info = opened_reader.info()\n print(f\"Features: {info.feature_count}\")\n \n # Async iteration - efficient streaming\n async_iter = opened_reader.select_all()\n \n # Process features one by one\n count = 0\n while count < 10: # Get first 10 features\n feature = await async_iter.next()\n if feature is None:\n break\n print(f\"Feature {count}: {feature.id}\")\n count += 1\n \n # Or collect all at once\n all_features = await opened_reader.select_all().collect()\n print(f\"Total features: {len(all_features)}\")\n \n # Async spatial query\n bbox_iter = opened_reader.query_bbox(84227.77, 445377.33, 85323.23, 446334.69)\n spatial_features = await bbox_iter.collect()\n print(f\"Spatial query result: {len(spatial_features)} features\")\n\nasyncio.run(main())\n```\n\n## API Reference\n\n### Reader (Synchronous)\n\nMain class for reading local FlatCityBuf files.\n\n```python\nreader = fcb.Reader(path: str)\n```\n\n**Methods:**\n- `info() -> FileInfo` - Get file metadata and statistics\n- `cityjson_header() -> CityJSON` - Get CityJSON header with transform/metadata\n- `query_bbox(min_x, min_y, max_x, max_y) -> Iterator[Feature]` - Spatial query\n- `query_attr(filters: List[AttrFilter]) -> Iterator[Feature]` - Attribute query\n- `__iter__() -> Iterator[Feature]` - Iterate all features\n\n### AsyncReader (HTTP)\n\nAsynchronous reader for HTTP-based FlatCityBuf files.\n\n```python\nasync_reader = fcb.AsyncReader(url: str)\nopened_reader = await async_reader.open()\n```\n\n**Methods:**\n- `info() -> FileInfo` - Get file metadata\n- `cityjson_header() -> CityJSON` - Get CityJSON header information\n- `select_all() -> AsyncFeatureIterator` - Get all features as async iterator\n- `query_bbox(min_x, min_y, max_x, max_y) -> AsyncFeatureIterator` - Async spatial query\n- `query_attr(filters: List[AttrFilter]) -> AsyncFeatureIterator` - Async attribute query\n\n### AsyncFeatureIterator\n\nEfficient async iterator for streaming features from HTTP sources.\n\n```python\n# Get features one by one\nfeature = await async_iter.next() # Returns Feature or None\n\n# Collect all remaining features\nfeatures = await async_iter.collect() # Returns List[Feature]\n```\n\n### Feature (CityJSON Format)\n\nRepresents a CityJSON feature with proper structure.\n\n```python\nclass Feature:\n id: str # Feature ID\n type: str # Feature type \n vertices: List[List[float]] # 3D vertices as [x, y, z] arrays\n city_objects: Dict[str, CityObject] # Dictionary of city objects\n```\n\n### CityObject\n\nIndividual city object within a feature.\n\n```python\nclass CityObject:\n type: str # Object type (e.g., \"Building\")\n geometry: List[Geometry] # List of geometries\n attributes: Dict[str, Any] # Object attributes\n children: List[str] # Child object IDs\n parents: List[str] # Parent object IDs\n```\n\n### Geometry\n\n3D geometry with nested boundary structure.\n\n```python\nclass Geometry:\n type: str # Geometry type\n boundaries: PyObject # Nested boundary arrays (preserves structure)\n semantics: Optional[Any] # Semantic information\n```\n\n### CityJSON Header\n\nCityJSON metadata and transform information.\n\n```python\nclass CityJSON:\n type: str # Always \"CityJSON\"\n version: str # CityJSON version\n transform: Transform # Coordinate transformation\n metadata: Optional[Metadata] # Optional metadata\n feature_count: int # Number of features\n```\n\n### Transform\n\nCoordinate transformation parameters.\n\n```python\nclass Transform:\n scale: List[float] # Scale factors [x, y, z]\n translate: List[float] # Translation [x, y, z]\n```\n\n### Query Types\n\n```python\n# Bounding box\nbbox = fcb.BBox(min_x=0, min_y=0, max_x=100, max_y=100)\n\n# Attribute filters\nfilter_eq = fcb.AttrFilter(\"type\", fcb.Operator.Eq, \"building\")\nfilter_gt = fcb.AttrFilter(\"height\", fcb.Operator.Gt, 50.0)\nfilter_le = fcb.AttrFilter(\"floors\", fcb.Operator.Le, 10)\n\n# Available operators\nfcb.Operator.Eq # Equal\nfcb.Operator.Ne # Not equal \nfcb.Operator.Gt # Greater than\nfcb.Operator.Ge # Greater than or equal\nfcb.Operator.Lt # Less than\nfcb.Operator.Le # Less than or equal\n```\n\n## Performance\n\nThe Python bindings leverage Rust's zero-copy deserialization and efficient indexing:\n\n- **10-20\u00d7 faster** than parsing equivalent JSON formats\n- **2-6\u00d7 less memory** usage compared to text formats \n- **Efficient spatial indexing** with packed R-tree queries\n- **HTTP range requests** for cloud-optimized partial access\n- **Async streaming** minimizes memory usage for large datasets\n- **Nested boundary preservation** avoids flattening overhead\n\n## Nested Boundaries\n\nThe bindings properly preserve CityJSON's nested boundary structure:\n\n```python\n# Boundaries can be nested arrays at arbitrary depth\n# Example: [[0, 1, 2, 3]] for a single surface\n# Example: [[[0, 1, 2, 3], [4, 5, 6, 7]]] for surfaces with holes\ngeometry.boundaries # Preserves exact nesting from CityJSON\n```\n\n## HTTP Optimization\n\nAsyncReader is optimized for HTTP access:\n\n- **Persistent connections** - HTTP client maintained across iterator calls\n- **Range request batching** - Efficient partial downloads\n- **Prefetching strategies** - Reduces round-trip latency\n- **Async streaming** - Process features as they arrive\n\n## Examples\n\nSee the [examples/](examples/) directory for comprehensive usage examples including:\n- Basic local file reading\n- HTTP access with async iteration\n- CityJSON header processing\n- Spatial and attribute queries\n- Nested geometry handling\n\n## Development\n\n### Building from Source\n\n```bash\n# Install development dependencies\npip install maturin pytest pytest-asyncio\n\n# Build in development mode\nmaturin develop --features http\n\n# Run tests\npytest tests/\n\n# Run with coverage\npytest tests/ --cov=flatcitybuf\n```\n\n### Testing\n\n```bash\n# Run all tests\npython -m pytest tests/test_e2e.py -v\n\n# Run only sync tests\npython -m pytest tests/test_e2e.py::TestE2EIntegration -v\n\n# Run only async tests \npython -m pytest tests/test_e2e.py::TestAsyncReaderE2E -v\n```\n\n### Project Structure\n\n```\nsrc/rust/fcb_py/\n\u251c\u2500\u2500 python/ # Python stub files\n\u251c\u2500\u2500 src/ # Rust PyO3 bindings\n\u2502 \u251c\u2500\u2500 lib.rs # Main module\n\u2502 \u251c\u2500\u2500 reader.rs # Sync reader\n\u2502 \u251c\u2500\u2500 async_reader.rs # Async reader\n\u2502 \u251c\u2500\u2500 types.rs # Python types\n\u2502 \u251c\u2500\u2500 utils.rs # Conversion utilities\n\u2502 \u2514\u2500\u2500 query.rs # Query types\n\u251c\u2500\u2500 tests/ # Python tests\n\u251c\u2500\u2500 examples/ # Usage examples\n\u251c\u2500\u2500 Cargo.toml # Rust dependencies\n\u2514\u2500\u2500 pyproject.toml # Python project config\n```\n\n## License\n\nMIT License - see [LICENSE](../../LICENSE) file for details.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python bindings for FlatCityBuf - a cloud-optimized binary format for 3D city models",
"version": "0.1.2",
"project_urls": {
"Bug Tracker": "https://github.com/cityjson/flatcitybuf/issues",
"Documentation": "https://github.com/cityjson/flatcitybuf/blob/main/README.md",
"Source Code": "https://github.com/cityjson/flatcitybuf"
},
"split_keywords": [
"gis",
" 3d",
" cityjson",
" citymodel",
" flatbuffers"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "cf965334995703809d734656d19bef19b7d9a987296fe77b4420ff51c1d9b051",
"md5": "994720940aa720f496879ee261b76bdc",
"sha256": "75c3b21581222bb6f157e7e00b47cad82e9aea6c6e32556b56081c89aefef9f6"
},
"downloads": -1,
"filename": "flatcitybuf-0.1.2-cp313-cp313-macosx_11_0_arm64.whl",
"has_sig": false,
"md5_digest": "994720940aa720f496879ee261b76bdc",
"packagetype": "bdist_wheel",
"python_version": "cp313",
"requires_python": ">=3.8.1",
"size": 1971028,
"upload_time": "2025-08-12T20:15:53",
"upload_time_iso_8601": "2025-08-12T20:15:53.608584Z",
"url": "https://files.pythonhosted.org/packages/cf/96/5334995703809d734656d19bef19b7d9a987296fe77b4420ff51c1d9b051/flatcitybuf-0.1.2-cp313-cp313-macosx_11_0_arm64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "124521a14f7f246abfad9aeaa010125713f32116bf6a3eb5d2b8a8882c6f5ad9",
"md5": "01bcdd4a05293e02f2b3d7d0fcea66ab",
"sha256": "1590104af1410de9fa8845027c5f06b0fbb2dc0f01964e70f56562a32f7c0c5f"
},
"downloads": -1,
"filename": "flatcitybuf-0.1.2-cp39-cp39-win_amd64.whl",
"has_sig": false,
"md5_digest": "01bcdd4a05293e02f2b3d7d0fcea66ab",
"packagetype": "bdist_wheel",
"python_version": "cp39",
"requires_python": ">=3.8.1",
"size": 2079810,
"upload_time": "2025-08-12T20:19:10",
"upload_time_iso_8601": "2025-08-12T20:19:10.183219Z",
"url": "https://files.pythonhosted.org/packages/12/45/21a14f7f246abfad9aeaa010125713f32116bf6a3eb5d2b8a8882c6f5ad9/flatcitybuf-0.1.2-cp39-cp39-win_amd64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "eb172e18344ebf1fd2ebc5f1c5a4074d6e3cee4bb6e447a58428a0bae0d41d1f",
"md5": "6ac18526cdac9d79bc7f767d9484110e",
"sha256": "78f36db2d61ad9cffab805bbf6311bcfa4120e30da447b5af848bf6097d45d0b"
},
"downloads": -1,
"filename": "flatcitybuf-0.1.2.tar.gz",
"has_sig": false,
"md5_digest": "6ac18526cdac9d79bc7f767d9484110e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8.1",
"size": 1673826,
"upload_time": "2025-08-12T20:15:55",
"upload_time_iso_8601": "2025-08-12T20:15:55.765288Z",
"url": "https://files.pythonhosted.org/packages/eb/17/2e18344ebf1fd2ebc5f1c5a4074d6e3cee4bb6e447a58428a0bae0d41d1f/flatcitybuf-0.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-12 20:15:55",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "cityjson",
"github_project": "flatcitybuf",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "flatcitybuf"
}