diff --git a/introduction.md b/introduction.md new file mode 100644 index 0000000..5623761 --- /dev/null +++ b/introduction.md @@ -0,0 +1,1159 @@ +# pybind11_geobuf — Python User Guide + +`pybind11_geobuf` is a C++ implementation of [Geobuf](https://github.com/mapbox/geobuf) (compact binary GeoJSON via Protocol Buffers) with full Python bindings. It provides: + +- Fast GeoJSON ↔ Geobuf (`.pbf`) encoding and decoding +- First-class GeoJSON object types (Feature, FeatureCollection, geometries) +- Spatial indexing with random access to individual features in large files +- In-memory feature collections with R-tree queries and polygon clipping +- Coordinate transforms (WGS84 ↔ ENU, affine, rotate, translate) +- JSON normalization utilities + +```bash +pip install pybind11_geobuf +``` + +```python +import pybind11_geobuf as gb +from pybind11_geobuf import geojson +``` + +--- + +## Table of Contents + +1. [Quick Start](#quick-start) +2. [The `__call__()` Pattern — Critical Reading](#the-__call__-pattern--critical-reading) +3. [GeoJSON Object Model](#geojson-object-model) +4. [Working with Features](#working-with-features) +5. [Working with FeatureCollections](#working-with-featurecollections) +6. [Geometry Types](#geometry-types) +7. [Encoder](#encoder) +8. [Decoder](#decoder) +9. [GeobufIndex — Large File Random Access](#geobufindex--large-file-random-access) +10. [Planet — In-Memory Spatial Index](#planet--in-memory-spatial-index) +11. [rapidjson](#rapidjson) +12. [Coordinate Transforms](#coordinate-transforms) +13. [JSON Normalization](#json-normalization) +14. [CLI](#cli) +15. [Custom Properties](#custom-properties) + +--- + +## Quick Start + +### Encode GeoJSON to Geobuf + +```python +import pybind11_geobuf as gb +from pybind11_geobuf import geojson + +# Build a feature in Python +pt = geojson.Point(116.3, 39.9) # lon, lat +f = geojson.Feature() +f.geometry(pt).properties({"name": "Beijing", "pop": 21_500_000}).id("BJ") + +# Encode to protobuf bytes +enc = gb.Encoder() +pbf_bytes = enc.encode(f) + +# Decode back +dec = gb.Decoder() +fc_json = dec.decode_to_geojson(pbf_bytes) +print(fc_json.as_feature()()) # -> {"type": "Feature", ...} +``` + +### File-level API + +```python +# Encode a .geojson file to .pbf +enc = gb.Encoder(max_precision=10**7) +enc.encode(geojson="cities.geojson", geobuf="cities.pbf") + +# Decode a .pbf file to .geojson +dec = gb.Decoder() +dec.decode(geobuf="cities.pbf", geojson="cities.geojson", indent=True) + +# Or use the load/dump shortcut on GeoJSON objects +fc = geojson.FeatureCollection().load("cities.pbf") # auto-detects .pbf +fc.dump("cities_copy.geojson", indent=True) # auto-detects .geojson +``` + +--- + +## The `__call__()` Pattern — Critical Reading + +**This is the most non-obvious aspect of the library.** Every C++ GeoJSON object and `rapidjson` value can be converted to a plain Python object by calling it like a function — `obj()`. Without this call you get a C++ wrapper, not a Python dict/list. + +```python +pt = geojson.Point(1.0, 2.0, 3.0) + +# This is a C++ Point wrapper: +print(pt) # + +# This is a Python list: +print(pt()) # [1.0, 2.0, 3.0] +``` + +The same applies to every type: + +```python +f = geojson.Feature({"type": "Feature", + "geometry": {"type": "Point", "coordinates": [1, 2]}, + "properties": {"k": 42}}) + +f() # -> {"type": "Feature", "geometry": {...}, "properties": {"k": 42}} +f.geometry()() # -> {"type": "Point", "coordinates": [1.0, 2.0, 0.0]} + +props = f.properties() # C++ PropertyMap (unordered_map) +props() # NOT available on PropertyMap — see next section +props["k"] # C++ geojson.value wrapper +props["k"]() # -> 42 (Python int) +``` + +### The `properties()()` Double Call + +`f.properties()` returns the internal C++ property map. Each value in that map is a `geojson.value` object (not a Python object). You must call `()` again on each value to get a Python object: + +```python +f = geojson.Feature({"type": "Feature", + "geometry": None, + "properties": {"name": "Alice", "score": 9.5, "tags": ["a", "b"]}}) + +props = f.properties() # C++ PropertyMap + +# Wrong — these are still C++ objects: +name = props["name"] # geojson.value wrapper +score = props["score"] # geojson.value wrapper + +# Correct — call () to get Python values: +name = props["name"]() # -> "Alice" (str) +score = props["score"]() # -> 9.5 (float) +tags = props["tags"]() # -> ["a", "b"] (list) +``` + +To get **all** properties as a Python dict at once, convert via `to_rapidjson()` and then call `()`: + +```python +props_dict = f.properties().to_rapidjson()() # -> {"name": "Alice", "score": 9.5, ...} +``` + +Or use `f()` to get the entire feature as a dict (includes geometry and properties): + +```python +feature_dict = f() # -> {"type": "Feature", "geometry": ..., "properties": {...}} +props_dict = feature_dict["properties"] # plain Python dict +``` + +### Summary Table + +| Expression | Type | Description | +|---|---|---| +| `f` | `geojson.Feature` | C++ wrapper | +| `f()` | `dict` | Full feature as Python dict | +| `f.geometry()` | `geojson.Geometry` | C++ Geometry wrapper | +| `f.geometry()()` | `dict` | Geometry as Python dict | +| `f.properties()` | `value.object_type` | C++ property map | +| `f.properties()["k"]` | `geojson.value` | C++ value wrapper | +| `f.properties()["k"]()` | Python object | Actual Python value | +| `rj` | `rapidjson` | C++ RapidJSON wrapper | +| `rj["key"]` | `rapidjson` | C++ sub-value | +| `rj["key"]()` | Python object | Python value | +| `rj()` | `dict` / `list` | Full conversion | + +--- + +## GeoJSON Object Model + +The library models GeoJSON using the following C++ type hierarchy, exposed to Python under `pybind11_geobuf.geojson`: + +``` +geojson.GeoJSON — variant: wraps one of Geometry / Feature / FeatureCollection + geojson.Geometry — variant: wraps one of the concrete geometry types below + geojson.Point + geojson.MultiPoint + geojson.LineString + geojson.MultiLineString + geojson.LinearRing + geojson.Polygon + geojson.MultiPolygon + geojson.GeometryCollection + geojson.Feature + geojson.FeatureCollection + geojson.value — variant: null / bool / int / float / str / list / dict +``` + +You can construct any type directly, from a Python dict, or from a raw JSON string. The library never forces you to build raw dicts — use the typed objects instead. + +```python +from pybind11_geobuf import geojson + +# Direct construction +pt = geojson.Point(116.3, 39.9, 50.0) # lon, lat, alt + +# From Python dict +ls = geojson.LineString([ # or as_numpy / from_numpy + [0.0, 0.0, 0.0], + [1.0, 1.0, 0.0], +]) +# Equivalent: +import numpy as np +ls = geojson.LineString() +ls.from_numpy(np.array([[0, 0, 0], [1, 1, 0]], dtype=float)) + +# From a JSON file (auto-detects .pbf or .geojson) +fc = geojson.FeatureCollection().load("data.geojson") +fc2 = geojson.FeatureCollection().load("data.pbf") + +# GeoJSON variant — used when you don't know the type in advance +g = geojson.GeoJSON().load("data.geojson") +if g.is_feature_collection(): + fc = g.as_feature_collection() +elif g.is_feature(): + f = g.as_feature() +elif g.is_geometry(): + geom = g.as_geometry() +``` + +--- + +## Working with Features + +### Constructing Features + +```python +from pybind11_geobuf import geojson + +# Empty feature, then set each part +f = geojson.Feature() +f.geometry(geojson.Point(116.3, 39.9)) # set geometry from a Point +f.properties({"name": "Beijing", "pop": 21_500_000}) # replace all properties +f.id("BJ") # set feature ID + +# Fluent chaining (each setter returns self) +f = (geojson.Feature() + .geometry(geojson.Point(116.3, 39.9)) + .properties({"name": "Beijing"}) + .id("BJ")) + +# From a Python dict +f = geojson.Feature({ + "type": "Feature", + "geometry": {"type": "Point", "coordinates": [116.3, 39.9]}, + "properties": {"name": "Beijing"}, +}) +``` + +### Reading Feature Data + +```python +# Geometry +geom = f.geometry() # geojson.Geometry wrapper +geom_dict = f.geometry()() # Python dict + +# Check geometry type +if f.geometry().is_point(): + pt = f.geometry().as_point() + x, y, z = pt.x, pt.y, pt.z + +# Properties — remember the double-call rule +props = f.properties() # C++ PropertyMap +for key in props.keys(): + value = props[key]() # () to get Python value + print(key, value) + +# Get a single property value +name = f.properties("name") # returns geojson.value | None +if name is not None: + name = name() # -> "Beijing" + +# Set a single property +f.properties("population", 21_500_000) +f.properties("deleted_key", None) # None deletes the key + +# Feature ID +fid = f.id() # int | float | str | None +``` + +### Serialization + +```python +# To Python dict +d = f() + +# To JSON string +import json +json_str = json.dumps(f()) + +# To Geobuf bytes +pbf = f.to_geobuf(precision=8, only_xy=False) + +# To file (auto-detects extension) +f.dump("feature.geojson", indent=True) +f.dump("feature.pbf") +``` + +### Bounding Box and Numpy Access + +```python +# Bounding box [min_lon, min_lat, max_lon, max_lat] +bbox = f.bbox() # np.ndarray([4]) + +# With Z: [min_lon, min_lat, min_alt, max_lon, max_lat, max_alt] +bbox6 = f.bbox(with_z=True) # np.ndarray([6]) + +# Mutable numpy view of coordinates (modifying this changes the C++ data) +coords = f.as_numpy() # np.ndarray shape (N, 3), writable +coords[:, 2] += 10.0 # shift all Z values in-place + +# Copy of coordinates (safe to modify without affecting C++ data) +coords_copy = f.to_numpy() +``` + +--- + +## Working with FeatureCollections + +### Construction and Access + +```python +from pybind11_geobuf import geojson +import numpy as np + +fc = geojson.FeatureCollection() + +# Append features +f1 = geojson.Feature().geometry(geojson.Point(0, 0)).properties({"id": 1}) +f2 = geojson.Feature().geometry(geojson.Point(1, 1)).properties({"id": 2}) +fc.append(f1) +fc.append(f2) + +# Index and iteration +print(len(fc)) # 2 +first = fc[0] # geojson.Feature +for f in fc: + props = f.properties() + print(props["id"]()) # remember () to get Python value + +# Slicing returns a new FeatureCollection +sub = fc[0:5] +del fc[:2] # delete first two features +``` + +### Loading and Saving + +```python +fc = geojson.FeatureCollection().load("input.geojson") +fc = geojson.FeatureCollection().load("input.pbf") # from Geobuf + +fc.dump("output.geojson", indent=True, sort_keys=True) +fc.dump("output.pbf", precision=8) + +# Convert to Python dict +fc_dict = fc() # {"type": "FeatureCollection", "features": [...]} +``` + +### Bulk Operations + +```python +# Get all feature IDs (reading properties) +ids = [f.id() for f in fc] + +# Filter by property value +results = geojson.FeatureCollection() +for f in fc: + props = f.properties() + if "type" in props and props["type"]() == "road": + results.append(f) + +# Collect property values into a list +names = [f.properties()["name"]() for f in fc if "name" in f.properties()] +``` + +--- + +## Geometry Types + +All geometry types live in `pybind11_geobuf.geojson`. They share a common interface: `__call__()`, `as_numpy()`, `to_numpy()`, `from_numpy()`, transform methods, `bbox()`, `clone()`, and `__eq__`. + +### Point + +```python +from pybind11_geobuf import geojson + +pt = geojson.Point(116.3, 39.9) # Z defaults to 0 +pt = geojson.Point(116.3, 39.9, 50.0) # with altitude + +pt.x, pt.y, pt.z # read coordinates +pt.x = 116.4 # write coordinates +pt[0], pt[1], pt[2] # index access + +pt() # -> [116.3, 39.9, 50.0] + +arr = pt.to_numpy() # shape (3,), copy +view = pt.as_numpy() # shape (3,), mutable view +``` + +### LineString and MultiPoint + +These share the same interface — a sequence of Points. + +```python +ls = geojson.LineString() +ls.push_back(geojson.Point(0, 0)) +ls.push_back(geojson.Point(1, 1)) +ls.push_back([2.0, 2.0, 0.0]) # array-like also accepted + +len(ls) # 3 +ls[0] # geojson.Point +ls[0]() # [0.0, 0.0, 0.0] + +ls() # -> [[0.0, 0.0, 0.0], [1.0, 1.0, 0.0], [2.0, 2.0, 0.0]] + +# Efficient numpy access +import numpy as np +coords = np.array([[0, 0, 0], [1, 1, 0], [2, 2, 0]], dtype=float) +ls = geojson.LineString() +ls.from_numpy(coords) + +view = ls.as_numpy() # shape (N, 3), mutable — changes reflect in C++ +copy = ls.to_numpy() # shape (N, 3), safe copy +view[0, 2] = 100.0 # this modifies the C++ LineString directly +``` + +### Polygon + +```python +ring = np.array([[0,0,0], [1,0,0], [1,1,0], [0,1,0], [0,0,0]], dtype=float) +poly = geojson.Polygon() +poly.push_back(ring) # exterior ring +poly.push_back(hole) # interior ring (hole) + +poly[0] # geojson.LinearRing (first ring) +poly[0].as_numpy() # Nx3 mutable view of ring coordinates +``` + +### Checking and Unwrapping via `Geometry` + +`geojson.Geometry` is a variant — it can hold any of the concrete types. + +```python +g = geojson.Geometry(geojson.Point(1, 2)) + +g.type() # "Point" +g.is_point() # True +g.is_line_string() # False + +pt = g.as_point() # geojson.Point + +# From dict +g = geojson.Geometry({"type": "LineString", "coordinates": [[0,0], [1,1]]}) +ls = g.as_line_string() +``` + +### Deduplication and `bbox` + +```python +ls.deduplicate_xyz() # removes consecutive duplicate points, returns bool (modified?) +ls.bbox() # [min_lon, min_lat, max_lon, max_lat] +ls.bbox(with_z=True) # [min_lon, min_lat, min_alt, max_lon, max_lat, max_alt] +``` + +--- + +## Encoder + +`Encoder` converts GeoJSON objects or files to compact Geobuf (Protocol Buffer) binary format. + +### Configuration + +```python +import pybind11_geobuf as gb + +enc = gb.Encoder( + max_precision=10**6, # default: 10^6 → 6 decimal places for lon/lat + only_xy=False, # if True, drop Z coordinate entirely + round_z=None, # round Z to N decimal places before encoding (e.g. round_z=2) +) +``` + +`max_precision` is a multiplier, not a digit count: +- `10**6` → 6 decimal places (default, ~0.1 m precision) +- `10**7` → 7 decimal places (~1 cm precision) +- `10**8` → 8 decimal places (~1 mm precision) + +### Encoding + +```python +from pybind11_geobuf import geojson + +fc = geojson.FeatureCollection().load("data.geojson") + +# Encode a FeatureCollection +pbf_bytes: bytes = enc.encode(fc) + +# Encode a single Feature +f = fc[0] +pbf_bytes = enc.encode(f) + +# Encode a Geometry +geom = f.geometry() +pbf_bytes = enc.encode(geom) + +# Encode from a Python dict (will be converted internally) +pbf_bytes = enc.encode({"type": "FeatureCollection", "features": []}) + +# File to file (most efficient for large data) +enc.encode(geojson="input.geojson", geobuf="output.pbf") +``` + +### Inspecting After Encode + +```python +enc.dim() # 2 or 3 (detected from data) +enc.e() # actual precision multiplier used +enc.max_precision() # the configured max_precision +enc.keys() # dict[str, int] — property key to index mapping +``` + +--- + +## Decoder + +`Decoder` converts Geobuf bytes back to GeoJSON objects, strings, or files. It also supports partial decoding. + +### Basic Decoding + +```python +import pybind11_geobuf as gb + +dec = gb.Decoder() + +# Decode to a GeoJSON variant object (recommended) +g = dec.decode_to_geojson(pbf_bytes) # geojson.GeoJSON +if g.is_feature_collection(): + fc = g.as_feature_collection() + +# Decode to a JSON string +json_str = dec.decode(pbf_bytes) +json_str = dec.decode(pbf_bytes, indent=True, sort_keys=True) + +# File to file +dec.decode(geobuf="input.pbf", geojson="output.geojson", indent=True) + +# Decode to rapidjson object +rj = dec.decode_to_rapidjson(pbf_bytes) +rj() # -> Python dict +``` + +### Inspecting the Decoded State + +After any decode call, the decoder retains state about the file: + +```python +dec.precision() # int — coordinate precision (e.g. 6 means 10^6) +dec.dim() # 2 or 3 — coordinate dimension +dec.keys() # list[str] — property key names in index order +dec.offsets() # list[int] — byte offsets for each feature in the stream +``` + +### Partial Decoding + +You can decode a raw byte slice for a single feature (useful when combined with `GeobufIndex`): + +```python +# Decode only header (populates keys, dim, precision) +dec.decode_header(pbf_bytes) + +# Decode a single feature from raw bytes +f = dec.decode_feature(feature_bytes) +f = dec.decode_feature(feature_bytes, only_geometry=True) # skip properties +f = dec.decode_feature(feature_bytes, only_properties=True) # skip geometry + +# Decode non-feature data (FeatureCollection-level custom properties) +v = dec.decode_non_features(trailing_bytes) +v() # -> Python dict +``` + +--- + +## GeobufIndex — Large File Random Access + +For large `.pbf` files with millions of features, loading the entire file is impractical. `GeobufIndex` enables: +- Memory-mapped access (no full file load) +- Random access to individual features by integer index or string ID +- Spatial queries via a packed R-tree + +### Building an Index + +First, create an index file from a geobuf file: + +```python +import pybind11_geobuf as gb + +# Build index alongside the geobuf file +gb.GeobufIndex.indexing( + "cities.pbf", # input geobuf + "cities.pbf.index", # output index file + feature_id="@", # "@" = auto-detect: uses feature.id, or falls back to + # "id" / "feature_id" / "fid" property keys + packed_rtree="@", # "@" = build R-tree (one AABB per feature) + # "per_line_segment" = one AABB per line segment +) +``` + +The index file is small compared to the geobuf — it contains offsets, feature IDs, and the packed R-tree. Store it next to the `.pbf` file. + +### Opening and Querying + +```python +idx = gb.GeobufIndex() + +# Two-step: load index, then memory-map the geobuf file +idx.mmap_init("cities.pbf.index", "cities.pbf") + +# Inspect the index +idx.num_features # total feature count +idx.header_size # bytes in PBF header +idx.offsets # list of byte offsets (length = num_features + 2) +idx.ids # dict[str, int] | None — feature_id → feature index +``` + +### Random Access by Index + +```python +# Decode a single feature (loads only that slice of the file) +f = idx.decode_feature(42) # feature at index 42 +f = idx.decode_feature(42, only_geometry=True) # skip properties +f = idx.decode_feature(42, only_properties=True) # skip geometry + +# Decode a batch of features +fc = idx.decode_features([0, 5, 100, 999]) # geojson.FeatureCollection +``` + +### Random Access by Feature ID + +If you built the index with `feature_id="@"`, you can look up features by their string ID: + +```python +f = idx.decode_feature_of_id("BJ") # geojson.Feature | None +f = idx.decode_feature_of_id("BJ", only_geometry=True) +``` + +### Spatial Query + +Returns a set of feature indices whose bounding boxes overlap the query box: + +```python +import numpy as np + +# Query features in a bounding box [lon_min, lat_min] to [lon_max, lat_max] +indices = idx.query( + np.array([116.0, 39.5]), # min corner (lon, lat) + np.array([117.0, 40.5]), # max corner (lon, lat) +) +# indices is a set[int] + +# Decode only those features +fc = idx.decode_features(sorted(indices)) +``` + +### FeatureCollection-level Custom Properties + +```python +# Decode non-feature data (trailing bytes after all features) +meta = idx.decode_non_features() # geojson.value +meta() # -> Python dict (e.g. {"source": "OSM", "date": "2024"}) +``` + +### Typical Workflow + +```python +# One-time: build index +gb.GeobufIndex.indexing("large.pbf", "large.pbf.index") + +# At query time +idx = gb.GeobufIndex() +idx.mmap_init("large.pbf.index", "large.pbf") + +# Get features in a region +hits = idx.query(np.array([min_lon, min_lat]), np.array([max_lon, max_lat])) +fc = idx.decode_features(sorted(hits)) +print(len(fc), "features found") +``` + +--- + +## Planet — In-Memory Spatial Index + +`Planet` wraps a `FeatureCollection` with a built-in packed R-tree. Use it when the entire dataset fits in memory but you need repeated spatial queries. + +```python +import pybind11_geobuf as gb +from pybind11_geobuf import geojson +import numpy as np + +# Load +fc = geojson.FeatureCollection().load("roads.pbf") +planet = gb.Planet(fc) + +# Build R-tree (lazy — also triggered automatically on first query) +planet.build() +planet.build(per_line_segment=True) # separate AABB per line segment (for long roads) + +# Spatial query — returns int32 numpy array of feature indices +indices = planet.query( + np.array([116.0, 39.5]), # min corner (lon, lat) + np.array([117.0, 40.5]), # max corner (lon, lat) +) + +# Extract matching features +result_fc = planet.copy(indices) # geojson.FeatureCollection +``` + +### Polygon Clipping + +```python +import numpy as np + +# Define a clipping polygon (Nx2, lon/lat) +polygon = np.array([ + [116.0, 39.5], + [117.0, 39.5], + [117.0, 40.5], + [116.0, 40.5], + [116.0, 39.5], +], dtype=float) + +clipped = planet.crop( + polygon, + clipping_mode="longest", # keep only the longest segment of each clipped linestring + strip_properties=False, # if True, replace properties with {"index": original_index} + is_wgs84=True, # use geodesic calculations +) +# clipped is a geojson.FeatureCollection + +# Clipping modes: +# "longest" — for each feature, keep only the longest clipped segment +# "first" — keep only the first clipped segment +# "all" — return all segments as separate features +# "whole" — keep entire feature if its centroid is inside the polygon +``` + +### Accessing and Replacing Features + +```python +# Access the underlying FeatureCollection +fc = planet.features() # reference to internal FC — modifying it modifies Planet + +# Replace with a new FeatureCollection (resets R-tree) +planet.features(new_fc) +planet.build(force=True) # rebuild after replacement +``` + +--- + +## rapidjson + +`pybind11_geobuf.rapidjson` is a Python binding for the [RapidJSON](https://rapidjson.org/) C++ value type. It provides a fast, dict/list-compatible JSON value that interoperates with all GeoJSON types. + +You'll encounter it when you need to: +- Load/save raw JSON without going through the GeoJSON type system +- Normalize or round JSON values in-place +- Use `to_rapidjson()` / `from_rapidjson()` bridges on GeoJSON objects + +### Basic Usage + +```python +from pybind11_geobuf import rapidjson + +# Create from Python object +rj = rapidjson({"type": "FeatureCollection", "features": []}) +rj = rapidjson([1, 2, 3]) +rj = rapidjson("hello") + +# The () operator converts to Python +rj() # -> Python dict/list/primitive + +# Load from file / string +rj = rapidjson().load("data.json") +rj = rapidjson().loads('{"x": 1}') + +# Save +rj.dump("out.json", indent=True, sort_keys=True) +s = rj.dumps(indent=True) +``` + +### Dict/Array Interface + +```python +rj = rapidjson({"a": 1, "b": [10, 20, 30]}) + +# Read +rj["a"] # rapidjson wrapper +rj["a"]() # -> 1 (Python int) +rj["b"][0]() # -> 10 +"a" in rj # True + +# Write +rj["c"] = 42 +rj["b"].push_back(40) +del rj["a"] + +# Keys and values +rj.keys() # list[str] +rj.values() # list[rapidjson] + +# Get returns None if missing (won't raise KeyError) +rj.get("missing") # -> None +``` + +### Normalization and Rounding + +`rapidjson` exposes in-place normalization methods that are commonly used to clean up GeoJSON before encoding or comparing: + +```python +rj = rapidjson().load("data.geojson") + +# Sort all object keys recursively (for deterministic output) +rj.sort_keys() + +# Round all coordinates: [lon_precision, lat_precision, alt_precision] +rj.round_geojson_geometry(precision=[8, 8, 3]) + +# Round non-geometry numeric values in GeoJSON (e.g. speed, score) +rj.round_geojson_non_geometry(precision=3) + +# Convert float values that are integers (e.g. 1.0 → 1) +rj.denoise_double_0() + +# Remove Z=0 from 2D-only coordinates +rj.strip_geometry_z_0() + +# All of the above in one call +rj.normalize( + sort_keys=True, + round_geojson_geometry=[8, 8, 3], + round_geojson_non_geometry=3, + denoise_double_0=True, + strip_geometry_z_0=True, +) + +# Check for NaN/Inf (returns path string like "features[0].geometry.coordinates[2]", or None) +path = rj.locate_nan_inf() + +# Subset check +is_subset = rj.is_subset_of(other_rj) +``` + +### Bridge with GeoJSON Types + +All GeoJSON objects have `to_rapidjson()` and `from_rapidjson()`: + +```python +fc = geojson.FeatureCollection().load("data.geojson") + +# Convert to rapidjson for manipulation +rj = fc.to_rapidjson() +rj.normalize() +rj.dump("normalized.geojson", indent=True) + +# Or convert back to typed objects +fc2 = geojson.FeatureCollection() +fc2.from_rapidjson(rj) +``` + +--- + +## Coordinate Transforms + +All GeoJSON objects support in-place coordinate transforms. Every transform method returns `self` (fluent interface). + +### Built-in Transforms + +```python +import numpy as np +from pybind11_geobuf import geojson + +anchor = np.array([116.3, 39.9, 0.0]) # anchor point in WGS84 (lon, lat, alt) + +fc = geojson.FeatureCollection().load("data.geojson") + +# WGS84 → local ENU (meters, East/North/Up from anchor) +fc.to_enu(anchor) +fc.to_enu(anchor, cheap_ruler=True) # fast approximation (default) +fc.to_enu(anchor, cheap_ruler=False) # rigorous ECEF transform + +# ENU → WGS84 +fc.to_wgs84(anchor) + +# Affine transform (4x4 matrix) +T = np.eye(4) +fc.affine(T) + +# Translate / scale / rotate +fc.translate(np.array([100.0, 0.0, 0.0])) +fc.scale(np.array([2.0, 2.0, 1.0])) + +R = np.eye(3) # 3x3 rotation matrix +fc.rotate(R) + +# Round coordinates +fc.round(lon=8, lat=8, alt=3) + +# Remove consecutive duplicate points +fc.deduplicate_xyz() +``` + +These methods are available on `GeoJSON`, `Geometry`, all concrete geometry types, `Feature`, and `FeatureCollection`. + +### Custom Transform Function + +Use `transform(fn)` to apply any custom per-feature coordinate transformation: + +```python +def my_transform(coords: np.ndarray) -> np.ndarray | None: + # coords is an Nx3 numpy array (read-write view) + # Option 1: modify in-place and return None + coords[:, 2] += 100.0 + # Option 2: return a new array + # return coords + 1.0 + +fc.transform(my_transform) +``` + +### The `tf` Submodule + +Low-level coordinate conversion functions are available in `pybind11_geobuf.tf`: + +```python +from pybind11_geobuf import tf +import numpy as np + +anchor_lla = np.array([116.3, 39.9, 50.0]) # lon, lat, alt + +# Single point: LLA → ENU +enu = tf.lla2enu(np.array([[116.4, 40.0, 50.0]]), anchor_lla=anchor_lla) +# enu.shape == (1, 3) + +# Batch: ENU → LLA +llas = tf.enu2lla(enu_array, anchor_lla=anchor_lla) + +# ECEF conversions +ecef = tf.lla2ecef(116.3, 39.9, 0.0) # single point +ecef = tf.lla2ecef(lla_array) # batch +lla = tf.ecef2lla(ecef_array) # batch + +# Rotation matrix: ECEF ↔ ENU at given lon/lat +R = tf.R_ecef_enu(116.3, 39.9) # 3x3 numpy array + +# 4×4 homogeneous transform ECEF ↔ ENU +T = tf.T_ecef_enu(116.3, 39.9, 0.0) # 4x4 numpy array + +# cheap_ruler factor at a latitude (for fast lat/lon → meters conversion) +k = tf.cheap_ruler_k(39.9) # shape (3,): [meters_per_lon, meters_per_lat, 1.0] +dlon = 1.0 / k[0] # degrees of longitude per meter at this latitude +dlat = 1.0 / k[1] # degrees of latitude per meter + +# Apply a 4x4 transform to an Nx3 array +out = tf.apply_transform(T, coords) +tf.apply_transform_inplace(T, coords, batch_size=1000) +``` + +--- + +## JSON Normalization + +`normalize_json` standardizes GeoJSON or plain JSON for consistent serialization and comparison. + +### File-Level Normalization + +```python +import pybind11_geobuf as gb + +# Normalize in place (read → transform → write) +gb.normalize_json( + "input.geojson", + "output.geojson", + indent=True, # pretty-print output + sort_keys=True, # sort object keys recursively + denoise_double_0=True, # 1.0 → 1, 0.0 → 0 + strip_geometry_z_0=True, # [lon, lat, 0.0] → [lon, lat] + round_non_geojson=3, # round non-GeoJSON numbers to 3 dp + round_geojson_non_geometry=3, # round non-coordinate GeoJSON numbers to 3 dp + round_geojson_geometry=[8, 8, 3], # round [lon, lat, alt] to [8, 8, 3] dp +) +``` + +### In-Memory Normalization + +```python +rj = gb.rapidjson().load("data.geojson") + +gb.normalize_json( + rj, + sort_keys=True, + round_geojson_geometry=[8, 8, 3], +) +rj.dump("normalized.geojson", indent=True) +``` + +### Subset Check + +```python +# Check if all keys/values in file1 also exist with same values in file2 +result = gb.is_subset_of("subset.geojson", "superset.geojson") # bool +``` + +### PBF Debug Inspection + +```python +raw = open("data.pbf", "rb").read() +print(gb.pbf_decode(raw, indent=" ")) # human-readable protobuf representation +``` + +--- + +## CLI + +```bash +# GeoJSON → Geobuf +python -m pybind11_geobuf json2geobuf input.geojson output.pbf +python -m pybind11_geobuf json2geobuf input.geojson output.pbf --precision=7 --only-xy + +# Geobuf → GeoJSON +python -m pybind11_geobuf geobuf2json input.pbf output.geojson --indent --sort-keys + +# Normalize a GeoJSON file +python -m pybind11_geobuf normalize_json input.geojson output.geojson +python -m pybind11_geobuf normalize_json input.geojson input.geojson # in-place + +# Normalize a Geobuf file (decode → normalize → re-encode) +python -m pybind11_geobuf normalize_geobuf input.pbf --precision=8 + +# Inspect raw protobuf bytes +python -m pybind11_geobuf pbf_decode data.pbf + +# Check if one JSON file is a subset of another +python -m pybind11_geobuf is_subset_of a.geojson b.geojson + +# Roundtrip test (encode → decode, compare result) +python -m pybind11_geobuf round_trip data.geojson --precision=8 + +# Build a spatial index for a geobuf file +python -m pybind11_geobuf index_geobuf input.pbf output.pbf.index +python -m pybind11_geobuf index_geobuf input.pbf output.pbf.index --feature-id=@ --packed-rtree=@ +``` + +--- + +## Custom Properties + +Custom properties are metadata attached to geometry objects and FeatureCollections (not the same as feature `properties`). They survive encoding/decoding and are stored in the protobuf. + +```python +from pybind11_geobuf import geojson + +# On a FeatureCollection +fc = geojson.FeatureCollection().load("data.geojson") +cp = fc.custom_properties() # geojson.value.object_type (C++ map) +cp["source"] = "OSM" # set via [] operator +cp["date"] = "2024-01" +cp["source"]() # -> "OSM" + +# Equivalent via __getitem__/__setitem__ on the FeatureCollection directly +fc["source"] = "OSM" +val = fc["source"]() # -> "OSM" + +# On a Geometry +geom = geojson.Geometry(geojson.LineString()) +geom["road_type"] = "highway" # stored in custom_properties +geom["road_type"]() # -> "highway" + +# Note: geometry custom_properties ≠ feature properties +# f.properties() is for GeoJSON-spec Feature properties (in "properties" key) +# f.custom_properties() is for extra metadata outside the GeoJSON spec +``` + +### Difference: `feature.properties()` vs `feature.custom_properties()` + +| | `feature.properties()` | `feature.custom_properties()` | +|---|---|---| +| GeoJSON spec | Yes — appears under `"properties"` key | No — stored outside the spec | +| Encoded in PBF | Yes | Yes | +| Accessed via `f[key]` | No — `f[key]` goes to custom_properties | Yes | +| Typical use | Feature attributes (name, id, type...) | Internal metadata (source, version...) | + +```python +# properties() — the standard GeoJSON properties dict +f.properties()["name"]() # -> "Beijing" + +# custom_properties() — additional metadata, accessed via f[key] +f["internal_id"] = 42 +f["internal_id"]() # -> 42 +``` + +--- + +## Quick Reference + +### Common Patterns + +```python +# Load any GeoJSON or Geobuf file +fc = geojson.FeatureCollection().load("data.pbf") # or .geojson + +# Iterate features, access properties safely +for f in fc: + props = f.properties() + if "name" not in props: + continue + name = props["name"]() # () is mandatory! + fid = f.id() # int | float | str | None + +# Encode to Geobuf +enc = gb.Encoder(max_precision=10**7) +pbf = enc.encode(fc) +with open("out.pbf", "wb") as fh: + fh.write(pbf) + +# Spatial query (large file) +idx = gb.GeobufIndex() +idx.mmap_init("large.pbf.index", "large.pbf") +hits = idx.query(np.array([lon0, lat0]), np.array([lon1, lat1])) +fc = idx.decode_features(sorted(hits)) + +# Spatial query (in-memory) +planet = gb.Planet(fc) +indices = planet.query(np.array([lon0, lat0]), np.array([lon1, lat1])) +subset = planet.copy(indices) + +# Coordinate transform +anchor = np.array([116.3, 39.9, 0.0]) +fc_enu = fc.clone().to_enu(anchor) # clone to avoid modifying original + +# Normalize and save +rj = fc.to_rapidjson() +rj.normalize().dump("normalized.geojson", indent=True) +``` + +### Converting C++ Objects to Python + +```python +# Always use () to get a plain Python object: +pt() # Point → list +ls() # LineString → list of lists +poly() # Polygon → list of list of lists +f() # Feature → dict +fc() # FeatureCollection → dict +geom() # Geometry → dict +g() # GeoJSON variant → dict + +# For individual property values: +f.properties()["key"]() # geojson.value → Python scalar/list/dict + +# For the whole properties dict: +f.properties().to_rapidjson()() # -> Python dict +# or simply: +f()["properties"] # -> Python dict (from the full feature dict) +``` diff --git a/pyproject.toml b/pyproject.toml index 5f53b98..88456fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "scikit_build_core.build" [project] name = "pybind11_geobuf" -version = "0.2.4" +version = "0.2.5" description="c++ geobuf with python binding" readme = "README.md" authors = [ diff --git a/src/pybind11_geobuf/__init__.pyi b/src/pybind11_geobuf/__init__.pyi new file mode 100644 index 0000000..de4e7b8 --- /dev/null +++ b/src/pybind11_geobuf/__init__.pyi @@ -0,0 +1,15 @@ +from ._core import Decoder as Decoder +from ._core import Encoder as Encoder +from ._core import GeobufIndex as GeobufIndex +from ._core import NodeItem as NodeItem +from ._core import PackedRTree as PackedRTree +from ._core import Planet as Planet +from ._core import __version__ as __version__ +from ._core import geojson as geojson +from ._core import is_subset_of as is_subset_of +from ._core import normalize_json as normalize_json +from ._core import pbf_decode as pbf_decode +from ._core import rapidjson as rapidjson +from ._core import str2geojson2str as str2geojson2str +from ._core import str2json2str as str2json2str +from ._core import tf as tf diff --git a/src/pybind11_geobuf/_core/__init__.pyi b/src/pybind11_geobuf/_core/__init__.pyi index 20bd49d..a00c700 100644 --- a/src/pybind11_geobuf/_core/__init__.pyi +++ b/src/pybind11_geobuf/_core/__init__.pyi @@ -1,7 +1,6 @@ from __future__ import annotations -import collections.abc import numpy -import numpy.typing +import pybind11_stubgen.typing_ext import typing from . import geojson from . import tf @@ -66,7 +65,7 @@ class Decoder: """ def decode_feature( self, bytes: str, only_geometry: bool = False, only_properties: bool = False - ) -> pybind11_geobuf._core.geojson.Feature | None: + ) -> geojson.Feature | None: """ Decode Protocol Buffer (PBF) feature. @@ -152,9 +151,9 @@ class Encoder: def __init__( self, *, - max_precision: typing.SupportsInt = 1000000, + max_precision: int = 1000000, only_xy: bool = False, - round_z: typing.SupportsInt | None = None, + round_z: int | None = None, ) -> None: """ Initialize an Encoder object. @@ -294,12 +293,8 @@ class GeobufIndex: """ @typing.overload def decode_feature( - self, - index: typing.SupportsInt, - *, - only_geometry: bool = False, - only_properties: bool = False, - ) -> pybind11_geobuf._core.geojson.Feature | None: + self, index: int, *, only_geometry: bool = False, only_properties: bool = False + ) -> geojson.Feature | None: """ Decode a feature from the Geobuf file. @@ -314,7 +309,7 @@ class GeobufIndex: @typing.overload def decode_feature( self, bytes: str, *, only_geometry: bool = False, only_properties: bool = False - ) -> pybind11_geobuf._core.geojson.Feature | None: + ) -> geojson.Feature | None: """ Decode a feature from bytes. @@ -328,7 +323,7 @@ class GeobufIndex: """ def decode_feature_of_id( self, id: str, *, only_geometry: bool = False, only_properties: bool = False - ) -> pybind11_geobuf._core.geojson.Feature | None: + ) -> geojson.Feature | None: """ Decode a feature by its ID. @@ -342,7 +337,7 @@ class GeobufIndex: """ def decode_features( self, - index: collections.abc.Sequence[typing.SupportsInt], + index: list[int], *, only_geometry: bool = False, only_properties: bool = False, @@ -387,9 +382,7 @@ class GeobufIndex: Returns: None """ - def mmap_bytes( - self, offset: typing.SupportsInt, length: typing.SupportsInt - ) -> bytes | None: + def mmap_bytes(self, offset: int, length: int) -> bytes | None: """ Read bytes from the memory-mapped file. @@ -425,8 +418,8 @@ class GeobufIndex: """ def query( self, - arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[2, 1]"], - arg1: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[2, 1]"], + arg0: numpy.ndarray[numpy.float64[2, 1]], + arg1: numpy.ndarray[numpy.float64[2, 1]], ) -> set[int]: """ Query features within a bounding box. @@ -497,9 +490,7 @@ class NodeItem: """ Check if this node's bounding box intersects with another node's bounding box """ - def to_numpy( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[4, 1]"]: + def to_numpy(self) -> numpy.ndarray[numpy.float64[4, 1]]: """ Convert the node's bounding box to a numpy array [minX, minY, maxX, maxY] """ @@ -541,11 +532,7 @@ class NodeItem: class PackedRTree: def search( - self, - min_x: typing.SupportsFloat, - min_y: typing.SupportsFloat, - max_x: typing.SupportsFloat, - max_y: typing.SupportsFloat, + self, min_x: float, min_y: float, max_x: float, max_y: float ) -> list[int]: """ Search for items within the given bounding box. @@ -560,9 +547,7 @@ class PackedRTree: list: List of offsets of items within the bounding box. """ @property - def extent( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[4, 1]"]: ... + def extent(self) -> numpy.ndarray[numpy.float64[4, 1]]: ... @property def node_size(self) -> int: ... @property @@ -597,9 +582,7 @@ class Planet: Returns: None """ - def copy( - self, arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.int32, "[m, 1]"] - ) -> geojson.FeatureCollection: + def copy(self, arg0: numpy.ndarray[numpy.int32[m, 1]]) -> geojson.FeatureCollection: """ Create a deep copy of the Planet object. @@ -608,9 +591,7 @@ class Planet: """ def crop( self, - polygon: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, 2]", "flags.c_contiguous" - ], + polygon: numpy.ndarray[numpy.float64[m, 2], numpy.ndarray.flags.c_contiguous], *, clipping_mode: str = "longest", strip_properties: bool = False, @@ -653,9 +634,9 @@ class Planet: """ def query( self, - min: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[2, 1]"], - max: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[2, 1]"], - ) -> typing.Annotated[numpy.typing.NDArray[numpy.int32], "[m, 1]"]: + min: numpy.ndarray[numpy.float64[2, 1]], + max: numpy.ndarray[numpy.float64[2, 1]], + ) -> numpy.ndarray[numpy.int32[m, 1]]: """ Query features within the given bounding box. @@ -701,11 +682,11 @@ class rapidjson: def __getstate__(self) -> int: ... def __hash__(self) -> int: ... def __index__(self) -> int: ... - def __init__(self, value: typing.SupportsInt) -> None: ... + def __init__(self, value: int) -> None: ... def __int__(self) -> int: ... def __ne__(self, other: typing.Any) -> bool: ... def __repr__(self) -> str: ... - def __setstate__(self, state: typing.SupportsInt) -> None: ... + def __setstate__(self, state: int) -> None: ... def __str__(self) -> str: ... @property def name(self) -> str: ... @@ -844,19 +825,19 @@ class rapidjson: """ Set the value to an empty array """ - def SetDouble(self, arg0: typing.SupportsFloat) -> rapidjson: + def SetDouble(self, arg0: float) -> rapidjson: """ Set the value to a double """ - def SetFloat(self, arg0: typing.SupportsFloat) -> rapidjson: + def SetFloat(self, arg0: float) -> rapidjson: """ Set the value to a float """ - def SetInt(self, arg0: typing.SupportsInt) -> rapidjson: + def SetInt(self, arg0: int) -> rapidjson: """ Set the value to an integer """ - def SetInt64(self, arg0: typing.SupportsInt) -> rapidjson: + def SetInt64(self, arg0: int) -> rapidjson: """ Set the value to a 64-bit integer """ @@ -868,11 +849,11 @@ class rapidjson: """ Set the value to an empty object """ - def SetUint(self, arg0: typing.SupportsInt) -> rapidjson: + def SetUint(self, arg0: int) -> rapidjson: """ Set the value to an unsigned integer """ - def SetUint64(self, arg0: typing.SupportsInt) -> rapidjson: + def SetUint64(self, arg0: int) -> rapidjson: """ Set the value to a 64-bit unsigned integer """ @@ -906,7 +887,7 @@ class rapidjson: Delete a member by key """ @typing.overload - def __delitem__(self, arg0: typing.SupportsInt) -> None: + def __delitem__(self, arg0: int) -> None: """ Delete an array element by index """ @@ -920,7 +901,7 @@ class rapidjson: Get a member value by key """ @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> rapidjson: + def __getitem__(self, arg0: int) -> rapidjson: """ Get an array element by index """ @@ -944,7 +925,7 @@ class rapidjson: Compare two RapidJSON values for inequality """ @typing.overload - def __setitem__(self, index: typing.SupportsInt, value: typing.Any) -> typing.Any: + def __setitem__(self, index: int, value: typing.Any) -> typing.Any: """ Set array element by index """ @@ -1010,9 +991,9 @@ class rapidjson: *, sort_keys: bool = True, strip_geometry_z_0: bool = True, - round_geojson_non_geometry: typing.SupportsInt | None = 3, + round_geojson_non_geometry: int | None = 3, round_geojson_geometry: typing.Annotated[ - collections.abc.Sequence[typing.SupportsInt], "FixedSize(3)" + list[int], pybind11_stubgen.typing_ext.FixedSize(3) ] | None = [8, 8, 3], denoise_double_0: bool = True, @@ -1029,11 +1010,7 @@ class rapidjson: Append value to array """ def round( - self, - *, - precision: typing.SupportsFloat = 3, - depth: typing.SupportsInt = 32, - skip_keys: collections.abc.Sequence[str] = [], + self, *, precision: float = 3, depth: int = 32, skip_keys: list[str] = [] ) -> rapidjson: """ Round numeric values in the JSON @@ -1042,15 +1019,13 @@ class rapidjson: self, *, precision: typing.Annotated[ - collections.abc.Sequence[typing.SupportsInt], "FixedSize(3)" + list[int], pybind11_stubgen.typing_ext.FixedSize(3) ] = [8, 8, 3], ) -> rapidjson: """ Round geometry coordinates in GeoJSON """ - def round_geojson_non_geometry( - self, *, precision: typing.SupportsInt = 3 - ) -> rapidjson: + def round_geojson_non_geometry(self, *, precision: int = 3) -> rapidjson: """ Round non-geometry numeric values in GeoJSON """ @@ -1098,10 +1073,10 @@ def normalize_json( sort_keys: bool = True, denoise_double_0: bool = True, strip_geometry_z_0: bool = True, - round_non_geojson: typing.SupportsInt | None = 3, - round_geojson_non_geometry: typing.SupportsInt | None = 3, + round_non_geojson: int | None = 3, + round_geojson_non_geometry: int | None = 3, round_geojson_geometry: typing.Annotated[ - collections.abc.Sequence[typing.SupportsInt], "FixedSize(3)" + list[int], pybind11_stubgen.typing_ext.FixedSize(3) ] | None = [8, 8, 3], ) -> bool: @@ -1130,10 +1105,10 @@ def normalize_json( sort_keys: bool = True, denoise_double_0: bool = True, strip_geometry_z_0: bool = True, - round_non_geojson: typing.SupportsInt | None = 3, - round_geojson_non_geometry: typing.SupportsInt | None = 3, + round_non_geojson: int | None = 3, + round_geojson_non_geometry: int | None = 3, round_geojson_geometry: typing.Annotated[ - collections.abc.Sequence[typing.SupportsInt], "FixedSize(3)" + list[int], pybind11_stubgen.typing_ext.FixedSize(3) ] | None = [8, 8, 3], ) -> rapidjson: @@ -1195,4 +1170,4 @@ def str2json2str( Optional[str]: Converted JSON string, or None if input is invalid. """ -__version__: str = "0.2.4" +__version__: str = "0.2.5" diff --git a/src/pybind11_geobuf/_core/geojson.pyi b/src/pybind11_geobuf/_core/geojson.pyi index a813db5..b440235 100644 --- a/src/pybind11_geobuf/_core/geojson.pyi +++ b/src/pybind11_geobuf/_core/geojson.pyi @@ -1,7 +1,5 @@ from __future__ import annotations -import collections.abc import numpy -import numpy.typing import pybind11_geobuf._core import typing @@ -82,26 +80,21 @@ class Feature: """ Set a custom property value by key """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> Feature: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> Feature: """ Apply 4x4 affine transformation matrix """ def as_numpy( self, - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], - "[m, 3]", - "flags.writeable", - "flags.c_contiguous", + ) -> numpy.ndarray[ + numpy.float64[m, 3], + numpy.ndarray.flags.writeable, + numpy.ndarray.flags.c_contiguous, ]: """ Get a numpy view of the feature geometry """ - def bbox( - self, *, with_z: bool = False - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + def bbox(self, *, with_z: bool = False) -> numpy.ndarray[numpy.float64[m, 1]]: """ Compute the bounding box of the feature """ @@ -133,7 +126,7 @@ class Feature: *, indent: bool = False, sort_keys: bool = False, - precision: typing.SupportsInt = 8, + precision: int = 8, only_xy: bool = False, ) -> bool: """ @@ -208,11 +201,11 @@ class Feature: """ Set the feature ID """ - def items(self) -> collections.abc.Iterator[tuple[str, value]]: + def items(self) -> typing.Iterator[tuple[str, value]]: """ Get an iterator over custom property items """ - def keys(self) -> collections.abc.Iterator[str]: + def keys(self) -> typing.Iterator[str]: """ Get an iterator over custom property keys """ @@ -245,50 +238,31 @@ class Feature: """ Set a property value by key """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> Feature: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> Feature: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> Feature: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> Feature: """ Round the coordinates of the feature geometry """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> Feature: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> Feature: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> Feature: """ Convert WGS84 (lon,lat,alt) to ENU coordinates """ def to_geobuf( - self, - *, - precision: typing.SupportsInt = 8, - only_xy: bool = False, - round_z: typing.SupportsInt | None = None, + self, *, precision: int = 8, only_xy: bool = False, round_z: int | None = None ) -> bytes: """ Convert the feature to Geobuf bytes """ - def to_numpy( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + def to_numpy(self) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert the feature geometry to a numpy array """ @@ -297,10 +271,7 @@ class Feature: Convert the feature to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> Feature: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -309,9 +280,7 @@ class Feature: """ Apply transform function to all coordinates (Nx3 numpy array) """ - def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> Feature: + def translate(self, offset: numpy.ndarray[numpy.float64[3, 1]]) -> Feature: """ Translate all coordinates by offset vector """ @@ -335,7 +304,7 @@ class FeatureCollection(FeatureList): Delete a custom property """ @typing.overload - def __delitem__(self, arg0: typing.SupportsInt) -> None: + def __delitem__(self, arg0: int) -> None: """ Delete the list elements at index ``i`` """ @@ -350,7 +319,7 @@ class FeatureCollection(FeatureList): Get a custom property by key """ @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> Feature: + def __getitem__(self, arg0: int) -> Feature: """ Get a feature from the collection by index """ @@ -370,7 +339,7 @@ class FeatureCollection(FeatureList): Initialize a FeatureCollection from another FeatureCollection """ @typing.overload - def __init__(self, N: typing.SupportsInt) -> None: + def __init__(self, N: int) -> None: """ Initialize a FeatureCollection with N empty features """ @@ -380,7 +349,7 @@ class FeatureCollection(FeatureList): Set a custom property """ @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: Feature) -> None: + def __setitem__(self, arg0: int, arg1: Feature) -> None: """ Set a feature in the collection at the specified index """ @@ -389,9 +358,7 @@ class FeatureCollection(FeatureList): """ Assign list elements using a slice object """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> FeatureCollection: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> FeatureCollection: """ Apply 4x4 affine transformation matrix """ @@ -419,7 +386,7 @@ class FeatureCollection(FeatureList): *, indent: bool = False, sort_keys: bool = False, - precision: typing.SupportsInt = 8, + precision: int = 8, only_xy: bool = False, ) -> bool: """ @@ -435,11 +402,11 @@ class FeatureCollection(FeatureList): """ Load the FeatureCollection from a RapidJSON value """ - def items(self) -> collections.abc.Iterator[tuple[str, value]]: + def items(self) -> typing.Iterator[tuple[str, value]]: """ Return an iterator over the items of custom properties """ - def keys(self) -> collections.abc.Iterator[str]: + def keys(self) -> typing.Iterator[str]: """ Return an iterator over the keys of custom properties """ @@ -447,47 +414,30 @@ class FeatureCollection(FeatureList): """ Load the FeatureCollection from a file (GeoJSON or Geobuf) """ - def resize(self, arg0: typing.SupportsInt) -> FeatureCollection: + def resize(self, arg0: int) -> FeatureCollection: """ Resize the FeatureCollection to contain N features """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> FeatureCollection: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> FeatureCollection: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> FeatureCollection: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> FeatureCollection: """ Round the coordinates of all features in the collection """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> FeatureCollection: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> FeatureCollection: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> FeatureCollection: """ Convert WGS84 (lon,lat,alt) to ENU coordinates """ def to_geobuf( - self, - *, - precision: typing.SupportsInt = 8, - only_xy: bool = False, - round_z: typing.SupportsInt | None = None, + self, *, precision: int = 8, only_xy: bool = False, round_z: int | None = None ) -> bytes: """ Convert the FeatureCollection to Geobuf bytes @@ -497,10 +447,7 @@ class FeatureCollection(FeatureList): Convert the FeatureCollection to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> FeatureCollection: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -510,12 +457,12 @@ class FeatureCollection(FeatureList): Apply transform function to all coordinates (Nx3 numpy array) """ def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] + self, offset: numpy.ndarray[numpy.float64[3, 1]] ) -> FeatureCollection: """ Translate all coordinates by offset vector """ - def values(self) -> collections.abc.Iterator[value]: + def values(self) -> typing.Iterator[value]: """ Return an iterator over the values of custom properties """ @@ -532,7 +479,7 @@ class FeatureList: Return true the container contains ``x`` """ @typing.overload - def __delitem__(self, arg0: typing.SupportsInt) -> None: + def __delitem__(self, arg0: int) -> None: """ Delete the list elements at index ``i`` """ @@ -548,7 +495,7 @@ class FeatureList: Retrieve list elements using a slice object """ @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> Feature: ... + def __getitem__(self, arg0: int) -> Feature: ... @typing.overload def __init__(self) -> None: ... @typing.overload @@ -557,12 +504,12 @@ class FeatureList: Copy constructor """ @typing.overload - def __init__(self, arg0: collections.abc.Iterable) -> None: ... - def __iter__(self) -> collections.abc.Iterator[Feature]: ... + def __init__(self, arg0: typing.Iterable) -> None: ... + def __iter__(self) -> typing.Iterator[Feature]: ... def __len__(self) -> int: ... def __ne__(self, arg0: FeatureList) -> bool: ... @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: Feature) -> None: ... + def __setitem__(self, arg0: int, arg1: Feature) -> None: ... @typing.overload def __setitem__(self, arg0: slice, arg1: FeatureList) -> None: """ @@ -586,11 +533,11 @@ class FeatureList: Extend the list by appending all the items in the given list """ @typing.overload - def extend(self, L: collections.abc.Iterable) -> None: + def extend(self, L: typing.Iterable) -> None: """ Extend the list by appending all the items in the given list """ - def insert(self, i: typing.SupportsInt, x: Feature) -> None: + def insert(self, i: int, x: Feature) -> None: """ Insert an item at a given position. """ @@ -600,7 +547,7 @@ class FeatureList: Remove and return the last item """ @typing.overload - def pop(self, i: typing.SupportsInt) -> Feature: + def pop(self, i: int) -> Feature: """ Remove and return the item at index ``i`` """ @@ -651,9 +598,7 @@ class GeoJSON: """ Check if two GeoJSON objects are not equal """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> GeoJSON: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> GeoJSON: """ Apply 4x4 affine transformation matrix """ @@ -675,10 +620,10 @@ class GeoJSON: """ def crop( self, - polygon: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 3]"], + polygon: numpy.ndarray[numpy.float64[m, 3]], *, clipping_mode: str = "longest", - max_z_offset: typing.SupportsFloat | None = None, + max_z_offset: float | None = None, ) -> ...: """ Crop the GeoJSON object using a polygon @@ -693,7 +638,7 @@ class GeoJSON: *, indent: bool = False, sort_keys: bool = False, - precision: typing.SupportsInt = 8, + precision: int = 8, only_xy: bool = False, ) -> bool: """ @@ -723,43 +668,26 @@ class GeoJSON: """ Load a GeoJSON object from a file """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> GeoJSON: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> GeoJSON: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> GeoJSON: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> GeoJSON: """ Round coordinates to specified decimal places """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> GeoJSON: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> GeoJSON: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> GeoJSON: """ Convert WGS84 (lon,lat,alt) to ENU coordinates """ def to_geobuf( - self, - *, - precision: typing.SupportsInt = 8, - only_xy: bool = False, - round_z: typing.SupportsInt | None = None, + self, *, precision: int = 8, only_xy: bool = False, round_z: int | None = None ) -> bytes: """ Encode the GeoJSON object to a Geobuf byte string @@ -769,10 +697,7 @@ class GeoJSON: Convert the GeoJSON object to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> GeoJSON: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -781,9 +706,7 @@ class GeoJSON: """ Apply transform function to all coordinates (Nx3 numpy array) """ - def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> GeoJSON: + def translate(self, offset: numpy.ndarray[numpy.float64[3, 1]]) -> GeoJSON: """ Translate all coordinates by offset vector """ @@ -875,7 +798,7 @@ class Geometry(GeometryBase): """ Initialize from a Python dictionary """ - def __iter__(self) -> collections.abc.Iterator[str]: + def __iter__(self) -> typing.Iterator[str]: """ Get an iterator over the custom property keys """ @@ -895,9 +818,7 @@ class Geometry(GeometryBase): """ Pickle support for Geometry objects """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> Geometry: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> Geometry: """ Apply 4x4 affine transformation matrix """ @@ -923,11 +844,10 @@ class Geometry(GeometryBase): """ def as_numpy( self, - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], - "[m, 3]", - "flags.writeable", - "flags.c_contiguous", + ) -> numpy.ndarray[ + numpy.float64[m, 3], + numpy.ndarray.flags.writeable, + numpy.ndarray.flags.c_contiguous, ]: """ Get a numpy view of the geometry coordinates @@ -940,9 +860,7 @@ class Geometry(GeometryBase): """ Get this geometry as a polygon (if it is one) """ - def bbox( - self, *, with_z: bool = False - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + def bbox(self, *, with_z: bool = False) -> numpy.ndarray[numpy.float64[m, 1]]: """ Get the bounding box of the geometry """ @@ -974,7 +892,7 @@ class Geometry(GeometryBase): *, indent: bool = False, sort_keys: bool = False, - precision: typing.SupportsInt = 8, + precision: int = 8, only_xy: bool = False, ) -> bool: """ @@ -985,10 +903,7 @@ class Geometry(GeometryBase): Decode a Geobuf byte string into a geometry """ def from_numpy( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> Geometry: """ Set geometry coordinates from a numpy array @@ -1033,11 +948,11 @@ class Geometry(GeometryBase): """ Check if this geometry is of type polygon """ - def items(self) -> collections.abc.Iterator[tuple[str, ...]]: + def items(self) -> typing.Iterator[tuple[str, ...]]: """ Get an iterator over the custom property items """ - def keys(self) -> collections.abc.Iterator[str]: + def keys(self) -> typing.Iterator[str]: """ Get an iterator over the custom property keys """ @@ -1055,18 +970,13 @@ class Geometry(GeometryBase): Add a point to the geometry """ @typing.overload - def push_back( - self, arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"] - ) -> Geometry: + def push_back(self, arg0: numpy.ndarray[numpy.float64[m, 1]]) -> Geometry: """ Add a point to the geometry """ @typing.overload def push_back( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> Geometry: """ Add multiple points to the geometry @@ -1086,54 +996,35 @@ class Geometry(GeometryBase): """ Add a line string to a multi-line string geometry """ - def resize(self, arg0: typing.SupportsInt) -> Geometry: + def resize(self, arg0: int) -> Geometry: """ Resize the geometry """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> Geometry: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> Geometry: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> Geometry: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> Geometry: """ Round coordinates to specified decimal places """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> Geometry: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> Geometry: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> Geometry: """ Convert WGS84 (lon,lat,alt) to ENU coordinates """ def to_geobuf( - self, - *, - precision: typing.SupportsInt = 8, - only_xy: bool = False, - round_z: typing.SupportsInt | None = None, + self, *, precision: int = 8, only_xy: bool = False, round_z: int | None = None ) -> bytes: """ Encode the geometry to a Geobuf byte string """ - def to_numpy( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + def to_numpy(self) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert geometry coordinates to a numpy array """ @@ -1142,10 +1033,7 @@ class Geometry(GeometryBase): Convert the geometry to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> Geometry: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -1154,9 +1042,7 @@ class Geometry(GeometryBase): """ Apply transform function to all coordinates (Nx3 numpy array) """ - def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> Geometry: + def translate(self, offset: numpy.ndarray[numpy.float64[3, 1]]) -> Geometry: """ Translate all coordinates by offset vector """ @@ -1164,7 +1050,7 @@ class Geometry(GeometryBase): """ Get the type of the geometry """ - def values(self) -> collections.abc.Iterator[...]: + def values(self) -> typing.Iterator[...]: """ Get an iterator over the custom property values """ @@ -1196,7 +1082,7 @@ class GeometryCollection(GeometryList): Copy constructor for GeometryCollection """ @typing.overload - def __init__(self, N: typing.SupportsInt) -> None: + def __init__(self, N: int) -> None: """ Construct a GeometryCollection with N empty geometries """ @@ -1205,56 +1091,42 @@ class GeometryCollection(GeometryList): Check if two GeometryCollections are not equal """ @typing.overload - def __setitem__( - self, arg0: typing.SupportsInt, arg1: Geometry - ) -> GeometryCollection: + def __setitem__(self, arg0: int, arg1: Geometry) -> GeometryCollection: """ Set a geometry in the GeometryCollection by index """ @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: Point) -> GeometryCollection: + def __setitem__(self, arg0: int, arg1: Point) -> GeometryCollection: """ Set a geometry in the GeometryCollection by index """ @typing.overload - def __setitem__( - self, arg0: typing.SupportsInt, arg1: MultiPoint - ) -> GeometryCollection: + def __setitem__(self, arg0: int, arg1: MultiPoint) -> GeometryCollection: """ Set a geometry in the GeometryCollection by index """ @typing.overload - def __setitem__( - self, arg0: typing.SupportsInt, arg1: LineString - ) -> GeometryCollection: + def __setitem__(self, arg0: int, arg1: LineString) -> GeometryCollection: """ Set a geometry in the GeometryCollection by index """ @typing.overload - def __setitem__( - self, arg0: typing.SupportsInt, arg1: MultiLineString - ) -> GeometryCollection: + def __setitem__(self, arg0: int, arg1: MultiLineString) -> GeometryCollection: """ Set a geometry in the GeometryCollection by index """ @typing.overload - def __setitem__( - self, arg0: typing.SupportsInt, arg1: Polygon - ) -> GeometryCollection: + def __setitem__(self, arg0: int, arg1: Polygon) -> GeometryCollection: """ Set a geometry in the GeometryCollection by index """ @typing.overload - def __setitem__( - self, arg0: typing.SupportsInt, arg1: MultiPolygon - ) -> GeometryCollection: + def __setitem__(self, arg0: int, arg1: MultiPolygon) -> GeometryCollection: """ Set a geometry in the GeometryCollection by index """ @typing.overload - def __setitem__( - self, arg0: typing.SupportsInt, arg1: GeometryCollection - ) -> GeometryCollection: + def __setitem__(self, arg0: int, arg1: GeometryCollection) -> GeometryCollection: """ Set a geometry in the GeometryCollection by index """ @@ -1262,9 +1134,7 @@ class GeometryCollection(GeometryList): """ Pickle support for GeometryCollection """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> GeometryCollection: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> GeometryCollection: """ Apply 4x4 affine transformation matrix """ @@ -1326,37 +1196,24 @@ class GeometryCollection(GeometryList): """ Add a new geometry to the GeometryCollection """ - def resize(self, arg0: typing.SupportsInt) -> GeometryCollection: + def resize(self, arg0: int) -> GeometryCollection: """ Resize the GeometryCollection to contain N geometries """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> GeometryCollection: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> GeometryCollection: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> GeometryCollection: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> GeometryCollection: """ Round the coordinates of all geometries in the GeometryCollection """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> GeometryCollection: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> GeometryCollection: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> GeometryCollection: """ Convert WGS84 (lon,lat,alt) to ENU coordinates @@ -1366,10 +1223,7 @@ class GeometryCollection(GeometryList): Convert the GeometryCollection to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> GeometryCollection: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -1379,7 +1233,7 @@ class GeometryCollection(GeometryList): Apply transform function to all coordinates (Nx3 numpy array) """ def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] + self, offset: numpy.ndarray[numpy.float64[3, 1]] ) -> GeometryCollection: """ Translate all coordinates by offset vector @@ -1401,7 +1255,7 @@ class GeometryList: Return true the container contains ``x`` """ @typing.overload - def __delitem__(self, arg0: typing.SupportsInt) -> None: + def __delitem__(self, arg0: int) -> None: """ Delete the list elements at index ``i`` """ @@ -1417,7 +1271,7 @@ class GeometryList: Retrieve list elements using a slice object """ @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> Geometry: ... + def __getitem__(self, arg0: int) -> Geometry: ... @typing.overload def __init__(self) -> None: ... @typing.overload @@ -1426,12 +1280,12 @@ class GeometryList: Copy constructor """ @typing.overload - def __init__(self, arg0: collections.abc.Iterable) -> None: ... - def __iter__(self) -> collections.abc.Iterator[Geometry]: ... + def __init__(self, arg0: typing.Iterable) -> None: ... + def __iter__(self) -> typing.Iterator[Geometry]: ... def __len__(self) -> int: ... def __ne__(self, arg0: GeometryList) -> bool: ... @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: Geometry) -> None: ... + def __setitem__(self, arg0: int, arg1: Geometry) -> None: ... @typing.overload def __setitem__(self, arg0: slice, arg1: GeometryList) -> None: """ @@ -1455,11 +1309,11 @@ class GeometryList: Extend the list by appending all the items in the given list """ @typing.overload - def extend(self, L: collections.abc.Iterable) -> None: + def extend(self, L: typing.Iterable) -> None: """ Extend the list by appending all the items in the given list """ - def insert(self, i: typing.SupportsInt, x: Geometry) -> None: + def insert(self, i: int, x: Geometry) -> None: """ Insert an item at a given position. """ @@ -1469,7 +1323,7 @@ class GeometryList: Remove and return the last item """ @typing.overload - def pop(self, i: typing.SupportsInt) -> Geometry: + def pop(self, i: int) -> Geometry: """ Remove and return the item at index ``i`` """ @@ -1496,7 +1350,7 @@ class LineString(coordinates): """ Check if two LineStrings are equal """ - def __getitem__(self, arg0: typing.SupportsInt) -> Point: + def __getitem__(self, arg0: int) -> Point: """ Get a point from the geometry by index """ @@ -1508,15 +1362,12 @@ class LineString(coordinates): """ @typing.overload def __init__( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> None: """ Initialize from a numpy array of points """ - def __iter__(self) -> collections.abc.Iterator[Point]: + def __iter__(self) -> typing.Iterator[Point]: """ Iterate over the points in the geometry """ @@ -1529,16 +1380,14 @@ class LineString(coordinates): Check if two LineStrings are not equal """ @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: Point) -> Point: + def __setitem__(self, arg0: int, arg1: Point) -> Point: """ Set a point in the geometry by index """ @typing.overload def __setitem__( - self, - arg0: typing.SupportsInt, - arg1: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"], - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + self, arg0: int, arg1: numpy.ndarray[numpy.float64[m, 1]] + ) -> numpy.ndarray[numpy.float64[m, 1]]: """ Set a point in the geometry by index using a vector """ @@ -1546,26 +1395,21 @@ class LineString(coordinates): """ Pickle support for serialization """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> LineString: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> LineString: """ Apply 4x4 affine transformation matrix """ def as_numpy( self, - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], - "[m, 3]", - "flags.writeable", - "flags.c_contiguous", + ) -> numpy.ndarray[ + numpy.float64[m, 3], + numpy.ndarray.flags.writeable, + numpy.ndarray.flags.c_contiguous, ]: """ Get a numpy view of the geometry points """ - def bbox( - self, *, with_z: bool = False - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + def bbox(self, *, with_z: bool = False) -> numpy.ndarray[numpy.float64[m, 1]]: """ Compute the bounding box of the geometry """ @@ -1588,10 +1432,7 @@ class LineString(coordinates): Remove duplicate consecutive points based on their XYZ coordinates """ def from_numpy( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> LineString: """ Set the geometry points from a numpy array @@ -1610,50 +1451,33 @@ class LineString(coordinates): Add a point to the end of the geometry """ @typing.overload - def push_back( - self, arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"] - ) -> LineString: + def push_back(self, arg0: numpy.ndarray[numpy.float64[m, 1]]) -> LineString: """ Add a point to the end of the geometry using a vector """ - def resize(self, arg0: typing.SupportsInt) -> LineString: + def resize(self, arg0: int) -> LineString: """ Resize the geometry to the specified size """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> LineString: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> LineString: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> LineString: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> LineString: """ Round coordinates to specified decimal places """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> LineString: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> LineString: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> LineString: """ Convert WGS84 (lon,lat,alt) to ENU coordinates """ - def to_numpy( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + def to_numpy(self) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert the geometry points to a numpy array """ @@ -1662,10 +1486,7 @@ class LineString(coordinates): Convert to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> LineString: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -1674,9 +1495,7 @@ class LineString(coordinates): """ Apply transform function to all coordinates (Nx3 numpy array) """ - def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> LineString: + def translate(self, offset: numpy.ndarray[numpy.float64[3, 1]]) -> LineString: """ Translate all coordinates by offset vector """ @@ -1701,7 +1520,7 @@ class LineStringList: Return true the container contains ``x`` """ @typing.overload - def __delitem__(self, arg0: typing.SupportsInt) -> None: + def __delitem__(self, arg0: int) -> None: """ Delete the list elements at index ``i`` """ @@ -1717,7 +1536,7 @@ class LineStringList: Retrieve list elements using a slice object """ @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> LineString: ... + def __getitem__(self, arg0: int) -> LineString: ... @typing.overload def __init__(self) -> None: ... @typing.overload @@ -1726,12 +1545,12 @@ class LineStringList: Copy constructor """ @typing.overload - def __init__(self, arg0: collections.abc.Iterable) -> None: ... - def __iter__(self) -> collections.abc.Iterator[LineString]: ... + def __init__(self, arg0: typing.Iterable) -> None: ... + def __iter__(self) -> typing.Iterator[LineString]: ... def __len__(self) -> int: ... def __ne__(self, arg0: LineStringList) -> bool: ... @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: LineString) -> None: ... + def __setitem__(self, arg0: int, arg1: LineString) -> None: ... @typing.overload def __setitem__(self, arg0: slice, arg1: LineStringList) -> None: """ @@ -1755,11 +1574,11 @@ class LineStringList: Extend the list by appending all the items in the given list """ @typing.overload - def extend(self, L: collections.abc.Iterable) -> None: + def extend(self, L: typing.Iterable) -> None: """ Extend the list by appending all the items in the given list """ - def insert(self, i: typing.SupportsInt, x: LineString) -> None: + def insert(self, i: int, x: LineString) -> None: """ Insert an item at a given position. """ @@ -1769,7 +1588,7 @@ class LineStringList: Remove and return the last item """ @typing.overload - def pop(self, i: typing.SupportsInt) -> LineString: + def pop(self, i: int) -> LineString: """ Remove and return the item at index ``i`` """ @@ -1796,7 +1615,7 @@ class LinearRing(coordinates): """ Check if two LinearRings are equal """ - def __getitem__(self, arg0: typing.SupportsInt) -> Point: + def __getitem__(self, arg0: int) -> Point: """ Get a point from the geometry by index """ @@ -1804,7 +1623,7 @@ class LinearRing(coordinates): """ Default constructor for LinearRing """ - def __iter__(self) -> collections.abc.Iterator[Point]: + def __iter__(self) -> typing.Iterator[Point]: """ Iterate over the points in the geometry """ @@ -1817,26 +1636,23 @@ class LinearRing(coordinates): Check if two LinearRings are not equal """ @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: Point) -> Point: + def __setitem__(self, arg0: int, arg1: Point) -> Point: """ Set a point in the geometry by index """ @typing.overload def __setitem__( - self, - arg0: typing.SupportsInt, - arg1: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"], - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + self, arg0: int, arg1: numpy.ndarray[numpy.float64[m, 1]] + ) -> numpy.ndarray[numpy.float64[m, 1]]: """ Set a point in the geometry by index using a vector """ def as_numpy( self, - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], - "[m, 3]", - "flags.writeable", - "flags.c_contiguous", + ) -> numpy.ndarray[ + numpy.float64[m, 3], + numpy.ndarray.flags.writeable, + numpy.ndarray.flags.c_contiguous, ]: """ Get a numpy view of the geometry points @@ -1850,10 +1666,7 @@ class LinearRing(coordinates): Create a clone of the object """ def from_numpy( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> LinearRing: """ Set the geometry points from a numpy array @@ -1868,15 +1681,11 @@ class LinearRing(coordinates): Add a point to the end of the geometry """ @typing.overload - def push_back( - self, arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"] - ) -> LinearRing: + def push_back(self, arg0: numpy.ndarray[numpy.float64[m, 1]]) -> LinearRing: """ Add a point to the end of the geometry using a vector """ - def to_numpy( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + def to_numpy(self) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert the geometry points to a numpy array """ @@ -1896,7 +1705,7 @@ class LinearRingList: Return true the container contains ``x`` """ @typing.overload - def __delitem__(self, arg0: typing.SupportsInt) -> None: + def __delitem__(self, arg0: int) -> None: """ Delete the list elements at index ``i`` """ @@ -1912,7 +1721,7 @@ class LinearRingList: Retrieve list elements using a slice object """ @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> LinearRing: ... + def __getitem__(self, arg0: int) -> LinearRing: ... @typing.overload def __init__(self) -> None: ... @typing.overload @@ -1921,12 +1730,12 @@ class LinearRingList: Copy constructor """ @typing.overload - def __init__(self, arg0: collections.abc.Iterable) -> None: ... - def __iter__(self) -> collections.abc.Iterator[LinearRing]: ... + def __init__(self, arg0: typing.Iterable) -> None: ... + def __iter__(self) -> typing.Iterator[LinearRing]: ... def __len__(self) -> int: ... def __ne__(self, arg0: LinearRingList) -> bool: ... @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: LinearRing) -> None: ... + def __setitem__(self, arg0: int, arg1: LinearRing) -> None: ... @typing.overload def __setitem__(self, arg0: slice, arg1: LinearRingList) -> None: """ @@ -1950,11 +1759,11 @@ class LinearRingList: Extend the list by appending all the items in the given list """ @typing.overload - def extend(self, L: collections.abc.Iterable) -> None: + def extend(self, L: typing.Iterable) -> None: """ Extend the list by appending all the items in the given list """ - def insert(self, i: typing.SupportsInt, x: LinearRing) -> None: + def insert(self, i: int, x: LinearRing) -> None: """ Insert an item at a given position. """ @@ -1964,7 +1773,7 @@ class LinearRingList: Remove and return the last item """ @typing.overload - def pop(self, i: typing.SupportsInt) -> LinearRing: + def pop(self, i: int) -> LinearRing: """ Remove and return the item at index ``i`` """ @@ -1991,7 +1800,7 @@ class MultiLineString(LineStringList): """ Check if two MultiLineStrings are equal """ - def __getitem__(self, arg0: typing.SupportsInt) -> LineString: + def __getitem__(self, arg0: int) -> LineString: """ Get a linear ring by index """ @@ -2013,15 +1822,12 @@ class MultiLineString(LineStringList): """ @typing.overload def __init__( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> None: """ Initialize from a numpy array of points """ - def __iter__(self) -> collections.abc.Iterator[LineString]: + def __iter__(self) -> typing.Iterator[LineString]: """ Return an iterator over the linear rings in the geometry """ @@ -2035,13 +1841,9 @@ class MultiLineString(LineStringList): """ def __setitem__( self, - arg0: typing.SupportsInt, - arg1: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ]: + arg0: int, + arg1: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous], + ) -> numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous]: """ Set a linear ring by index using a numpy array of points """ @@ -2049,26 +1851,21 @@ class MultiLineString(LineStringList): """ Pickle support for the geometry """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> MultiLineString: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> MultiLineString: """ Apply 4x4 affine transformation matrix """ def as_numpy( self, - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], - "[m, 3]", - "flags.writeable", - "flags.c_contiguous", + ) -> numpy.ndarray[ + numpy.float64[m, 3], + numpy.ndarray.flags.writeable, + numpy.ndarray.flags.c_contiguous, ]: """ Return a numpy view of the geometry's points """ - def bbox( - self, *, with_z: bool = False - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + def bbox(self, *, with_z: bool = False) -> numpy.ndarray[numpy.float64[m, 1]]: """ Compute the bounding box of the geometry """ @@ -2085,10 +1882,7 @@ class MultiLineString(LineStringList): Remove duplicate consecutive points based on their XYZ coordinates """ def from_numpy( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> MultiLineString: """ Set the geometry from a numpy array of points @@ -2103,10 +1897,7 @@ class MultiLineString(LineStringList): """ @typing.overload def push_back( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> MultiLineString: """ Add a new linear ring from a numpy array of points @@ -2116,40 +1907,25 @@ class MultiLineString(LineStringList): """ Add a new linear ring """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> MultiLineString: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> MultiLineString: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> MultiLineString: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> MultiLineString: """ Round the coordinates of the geometry """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> MultiLineString: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> MultiLineString: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> MultiLineString: """ Convert WGS84 (lon,lat,alt) to ENU coordinates """ - def to_numpy( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + def to_numpy(self) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert the geometry to a numpy array """ @@ -2158,10 +1934,7 @@ class MultiLineString(LineStringList): Convert the geometry to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> MultiLineString: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -2170,9 +1943,7 @@ class MultiLineString(LineStringList): """ Apply transform function to all coordinates (Nx3 numpy array) """ - def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> MultiLineString: + def translate(self, offset: numpy.ndarray[numpy.float64[3, 1]]) -> MultiLineString: """ Translate all coordinates by offset vector """ @@ -2200,7 +1971,7 @@ class MultiPoint(coordinates): """ Check if two MultiPoints are equal """ - def __getitem__(self, arg0: typing.SupportsInt) -> Point: + def __getitem__(self, arg0: int) -> Point: """ Get a point from the geometry by index """ @@ -2212,15 +1983,12 @@ class MultiPoint(coordinates): """ @typing.overload def __init__( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> None: """ Initialize from a numpy array of points """ - def __iter__(self) -> collections.abc.Iterator[Point]: + def __iter__(self) -> typing.Iterator[Point]: """ Iterate over the points in the geometry """ @@ -2233,16 +2001,14 @@ class MultiPoint(coordinates): Check if two MultiPoints are not equal """ @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: Point) -> Point: + def __setitem__(self, arg0: int, arg1: Point) -> Point: """ Set a point in the geometry by index """ @typing.overload def __setitem__( - self, - arg0: typing.SupportsInt, - arg1: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"], - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + self, arg0: int, arg1: numpy.ndarray[numpy.float64[m, 1]] + ) -> numpy.ndarray[numpy.float64[m, 1]]: """ Set a point in the geometry by index using a vector """ @@ -2250,26 +2016,21 @@ class MultiPoint(coordinates): """ Pickle support for serialization """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> MultiPoint: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> MultiPoint: """ Apply 4x4 affine transformation matrix """ def as_numpy( self, - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], - "[m, 3]", - "flags.writeable", - "flags.c_contiguous", + ) -> numpy.ndarray[ + numpy.float64[m, 3], + numpy.ndarray.flags.writeable, + numpy.ndarray.flags.c_contiguous, ]: """ Get a numpy view of the geometry points """ - def bbox( - self, *, with_z: bool = False - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + def bbox(self, *, with_z: bool = False) -> numpy.ndarray[numpy.float64[m, 1]]: """ Compute the bounding box of the geometry """ @@ -2286,10 +2047,7 @@ class MultiPoint(coordinates): Remove duplicate consecutive points based on their XYZ coordinates """ def from_numpy( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> MultiPoint: """ Set the geometry points from a numpy array @@ -2308,50 +2066,33 @@ class MultiPoint(coordinates): Add a point to the end of the geometry """ @typing.overload - def push_back( - self, arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"] - ) -> MultiPoint: + def push_back(self, arg0: numpy.ndarray[numpy.float64[m, 1]]) -> MultiPoint: """ Add a point to the end of the geometry using a vector """ - def resize(self, arg0: typing.SupportsInt) -> MultiPoint: + def resize(self, arg0: int) -> MultiPoint: """ Resize the geometry to the specified size """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> MultiPoint: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> MultiPoint: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> MultiPoint: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> MultiPoint: """ Round coordinates to specified decimal places """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> MultiPoint: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> MultiPoint: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> MultiPoint: """ Convert WGS84 (lon,lat,alt) to ENU coordinates """ - def to_numpy( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + def to_numpy(self) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert the geometry points to a numpy array """ @@ -2360,10 +2101,7 @@ class MultiPoint(coordinates): Convert to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> MultiPoint: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -2372,9 +2110,7 @@ class MultiPoint(coordinates): """ Apply transform function to all coordinates (Nx3 numpy array) """ - def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> MultiPoint: + def translate(self, offset: numpy.ndarray[numpy.float64[3, 1]]) -> MultiPoint: """ Translate all coordinates by offset vector """ @@ -2402,7 +2138,7 @@ class MultiPolygon(PolygonList): """ Check if two MultiPolygons are equal """ - def __getitem__(self, arg0: typing.SupportsInt) -> Polygon: + def __getitem__(self, arg0: int) -> Polygon: """ Get a Polygon from the MultiPolygon by index """ @@ -2424,15 +2160,12 @@ class MultiPolygon(PolygonList): """ @typing.overload def __init__( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> None: """ Construct MultiPolygon from a numpy array of points """ - def __iter__(self) -> collections.abc.Iterator[Polygon]: + def __iter__(self) -> typing.Iterator[Polygon]: """ Return an iterator over the Polygons in the MultiPolygon """ @@ -2445,17 +2178,15 @@ class MultiPolygon(PolygonList): Check if two MultiPolygons are not equal """ @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: Polygon) -> Polygon: + def __setitem__(self, arg0: int, arg1: Polygon) -> Polygon: """ Set a Polygon in the MultiPolygon by index """ @typing.overload def __setitem__( self, - arg0: typing.SupportsInt, - arg1: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + arg0: int, + arg1: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous], ) -> Polygon: """ Set a Polygon in the MultiPolygon by index using a numpy array @@ -2464,26 +2195,21 @@ class MultiPolygon(PolygonList): """ Pickle support for MultiPolygon """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> MultiPolygon: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> MultiPolygon: """ Apply 4x4 affine transformation matrix """ def as_numpy( self, - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], - "[m, 3]", - "flags.writeable", - "flags.c_contiguous", + ) -> numpy.ndarray[ + numpy.float64[m, 3], + numpy.ndarray.flags.writeable, + numpy.ndarray.flags.c_contiguous, ]: """ Return a numpy view of the MultiPolygon coordinates """ - def bbox( - self, *, with_z: bool = False - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + def bbox(self, *, with_z: bool = False) -> numpy.ndarray[numpy.float64[m, 1]]: """ Compute the bounding box of the MultiPolygon """ @@ -2496,10 +2222,7 @@ class MultiPolygon(PolygonList): Create a clone of the object """ def from_numpy( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> MultiPolygon: """ Set MultiPolygon coordinates from a numpy array @@ -2514,10 +2237,7 @@ class MultiPolygon(PolygonList): """ @typing.overload def push_back( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> MultiPolygon: """ Add a new Polygon to the MultiPolygon from a numpy array @@ -2527,40 +2247,25 @@ class MultiPolygon(PolygonList): """ Add a new Polygon to the MultiPolygon """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> MultiPolygon: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> MultiPolygon: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> MultiPolygon: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> MultiPolygon: """ Round the coordinates of the MultiPolygon """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> MultiPolygon: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> MultiPolygon: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> MultiPolygon: """ Convert WGS84 (lon,lat,alt) to ENU coordinates """ - def to_numpy( - self: Polygon, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + def to_numpy(self: Polygon) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert MultiPolygon to a numpy array """ @@ -2569,10 +2274,7 @@ class MultiPolygon(PolygonList): Convert the MultiPolygon to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> MultiPolygon: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -2581,9 +2283,7 @@ class MultiPolygon(PolygonList): """ Apply transform function to all coordinates (Nx3 numpy array) """ - def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> MultiPolygon: + def translate(self, offset: numpy.ndarray[numpy.float64[3, 1]]) -> MultiPolygon: """ Translate all coordinates by offset vector """ @@ -2611,7 +2311,7 @@ class Point: """ Check if two Points are equal """ - def __getitem__(self, index: typing.SupportsInt) -> float: + def __getitem__(self, index: int) -> float: """ Get the coordinate value at the specified index (0: x, 1: y, 2: z) """ @@ -2622,23 +2322,16 @@ class Point: Initialize an empty Point """ @typing.overload - def __init__( - self, - x: typing.SupportsFloat, - y: typing.SupportsFloat, - z: typing.SupportsFloat = 0.0, - ) -> None: + def __init__(self, x: float, y: float, z: float = 0.0) -> None: """ Initialize a Point with coordinates (x, y, z) """ @typing.overload - def __init__( - self, arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"] - ) -> None: + def __init__(self, arg0: numpy.ndarray[numpy.float64[m, 1]]) -> None: """ Initialize a Point from a numpy array or vector """ - def __iter__(self) -> collections.abc.Iterator[float]: + def __iter__(self) -> typing.Iterator[float]: """ Return an iterator over the point's coordinates """ @@ -2650,9 +2343,7 @@ class Point: """ Check if two Points are not equal """ - def __setitem__( - self, index: typing.SupportsInt, value: typing.SupportsFloat - ) -> float: + def __setitem__(self, index: int, value: float) -> float: """ Set the coordinate value at the specified index (0: x, 1: y, 2: z) """ @@ -2660,23 +2351,17 @@ class Point: """ Enable pickling support for Point objects """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> Point: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> Point: """ Apply 4x4 affine transformation matrix """ def as_numpy( self, - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[3, 1]", "flags.writeable" - ]: + ) -> numpy.ndarray[numpy.float64[3, 1], numpy.ndarray.flags.writeable]: """ Get a numpy view of the point coordinates """ - def bbox( - self, *, with_z: bool = False - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + def bbox(self, *, with_z: bool = False) -> numpy.ndarray[numpy.float64[m, 1]]: """ Get the bounding box of the point """ @@ -2692,9 +2377,7 @@ class Point: """ Remove duplicate consecutive points based on their XYZ coordinates """ - def from_numpy( - self, arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"] - ) -> Point: + def from_numpy(self, arg0: numpy.ndarray[numpy.float64[m, 1]]) -> Point: """ Set point coordinates from a numpy array """ @@ -2702,40 +2385,25 @@ class Point: """ Create a Point from a RapidJSON value """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> Point: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> Point: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> Point: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> Point: """ Round coordinates to specified decimal places """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> Point: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> Point: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> Point: """ Convert WGS84 (lon,lat,alt) to ENU coordinates """ - def to_numpy( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[3, 1]"]: + def to_numpy(self) -> numpy.ndarray[numpy.float64[3, 1]]: """ Convert point coordinates to a numpy array """ @@ -2744,10 +2412,7 @@ class Point: Convert the Point to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> Point: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -2756,9 +2421,7 @@ class Point: """ Apply transform function to all coordinates (Nx3 numpy array) """ - def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> Point: + def translate(self, offset: numpy.ndarray[numpy.float64[3, 1]]) -> Point: """ Translate all coordinates by offset vector """ @@ -2773,21 +2436,21 @@ class Point: Get or set the x-coordinate of the point """ @x.setter - def x(self, arg1: typing.SupportsFloat) -> None: ... + def x(self, arg1: float) -> None: ... @property def y(self) -> float: """ Get or set the y-coordinate of the point """ @y.setter - def y(self, arg1: typing.SupportsFloat) -> None: ... + def y(self, arg1: float) -> None: ... @property def z(self) -> float: """ Get or set the z-coordinate of the point """ @z.setter - def z(self, arg1: typing.SupportsFloat) -> None: ... + def z(self, arg1: float) -> None: ... class Polygon(LinearRingList): __hash__: typing.ClassVar[None] = None @@ -2807,7 +2470,7 @@ class Polygon(LinearRingList): """ Check if two Polygons are equal """ - def __getitem__(self, arg0: typing.SupportsInt) -> LinearRing: + def __getitem__(self, arg0: int) -> LinearRing: """ Get a linear ring by index """ @@ -2829,15 +2492,12 @@ class Polygon(LinearRingList): """ @typing.overload def __init__( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> None: """ Initialize from a numpy array of points """ - def __iter__(self) -> collections.abc.Iterator[LinearRing]: + def __iter__(self) -> typing.Iterator[LinearRing]: """ Return an iterator over the linear rings in the geometry """ @@ -2851,13 +2511,9 @@ class Polygon(LinearRingList): """ def __setitem__( self, - arg0: typing.SupportsInt, - arg1: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ]: + arg0: int, + arg1: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous], + ) -> numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous]: """ Set a linear ring by index using a numpy array of points """ @@ -2865,26 +2521,21 @@ class Polygon(LinearRingList): """ Pickle support for the geometry """ - def affine( - self, T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"] - ) -> Polygon: + def affine(self, T: numpy.ndarray[numpy.float64[4, 4]]) -> Polygon: """ Apply 4x4 affine transformation matrix """ def as_numpy( self, - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], - "[m, 3]", - "flags.writeable", - "flags.c_contiguous", + ) -> numpy.ndarray[ + numpy.float64[m, 3], + numpy.ndarray.flags.writeable, + numpy.ndarray.flags.c_contiguous, ]: """ Return a numpy view of the geometry's points """ - def bbox( - self, *, with_z: bool = False - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: + def bbox(self, *, with_z: bool = False) -> numpy.ndarray[numpy.float64[m, 1]]: """ Compute the bounding box of the geometry """ @@ -2901,10 +2552,7 @@ class Polygon(LinearRingList): Remove duplicate consecutive points based on their XYZ coordinates """ def from_numpy( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> Polygon: """ Set the geometry from a numpy array of points @@ -2919,10 +2567,7 @@ class Polygon(LinearRingList): """ @typing.overload def push_back( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> Polygon: """ Add a new linear ring from a numpy array of points @@ -2932,40 +2577,25 @@ class Polygon(LinearRingList): """ Add a new linear ring """ - def rotate( - self, R: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 3]"] - ) -> Polygon: + def rotate(self, R: numpy.ndarray[numpy.float64[3, 3]]) -> Polygon: """ Apply 3x3 rotation matrix to all coordinates """ - def round( - self, - *, - lon: typing.SupportsInt = 8, - lat: typing.SupportsInt = 8, - alt: typing.SupportsInt = 3, - ) -> Polygon: + def round(self, *, lon: int = 8, lat: int = 8, alt: int = 3) -> Polygon: """ Round the coordinates of the geometry """ - def scale( - self, scale: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> Polygon: + def scale(self, scale: numpy.ndarray[numpy.float64[3, 1]]) -> Polygon: """ Scale all coordinates by factors [sx, sy, sz] """ def to_enu( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> Polygon: """ Convert WGS84 (lon,lat,alt) to ENU coordinates """ - def to_numpy( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + def to_numpy(self) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert the geometry to a numpy array """ @@ -2974,10 +2604,7 @@ class Polygon(LinearRingList): Convert the geometry to a RapidJSON value """ def to_wgs84( - self, - anchor: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], - *, - cheap_ruler: bool = True, + self, anchor: numpy.ndarray[numpy.float64[3, 1]], *, cheap_ruler: bool = True ) -> Polygon: """ Convert ENU coordinates to WGS84 (lon,lat,alt) @@ -2986,9 +2613,7 @@ class Polygon(LinearRingList): """ Apply transform function to all coordinates (Nx3 numpy array) """ - def translate( - self, offset: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - ) -> Polygon: + def translate(self, offset: numpy.ndarray[numpy.float64[3, 1]]) -> Polygon: """ Translate all coordinates by offset vector """ @@ -3009,7 +2634,7 @@ class PolygonList: Return true the container contains ``x`` """ @typing.overload - def __delitem__(self, arg0: typing.SupportsInt) -> None: + def __delitem__(self, arg0: int) -> None: """ Delete the list elements at index ``i`` """ @@ -3025,7 +2650,7 @@ class PolygonList: Retrieve list elements using a slice object """ @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> Polygon: ... + def __getitem__(self, arg0: int) -> Polygon: ... @typing.overload def __init__(self) -> None: ... @typing.overload @@ -3034,12 +2659,12 @@ class PolygonList: Copy constructor """ @typing.overload - def __init__(self, arg0: collections.abc.Iterable) -> None: ... - def __iter__(self) -> collections.abc.Iterator[Polygon]: ... + def __init__(self, arg0: typing.Iterable) -> None: ... + def __iter__(self) -> typing.Iterator[Polygon]: ... def __len__(self) -> int: ... def __ne__(self, arg0: PolygonList) -> bool: ... @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: Polygon) -> None: ... + def __setitem__(self, arg0: int, arg1: Polygon) -> None: ... @typing.overload def __setitem__(self, arg0: slice, arg1: PolygonList) -> None: """ @@ -3063,11 +2688,11 @@ class PolygonList: Extend the list by appending all the items in the given list """ @typing.overload - def extend(self, L: collections.abc.Iterable) -> None: + def extend(self, L: typing.Iterable) -> None: """ Extend the list by appending all the items in the given list """ - def insert(self, i: typing.SupportsInt, x: Polygon) -> None: + def insert(self, i: int, x: Polygon) -> None: """ Insert an item at a given position. """ @@ -3077,7 +2702,7 @@ class PolygonList: Remove and return the last item """ @typing.overload - def pop(self, i: typing.SupportsInt) -> Polygon: + def pop(self, i: int) -> Polygon: """ Remove and return the item at index ``i`` """ @@ -3097,7 +2722,7 @@ class coordinates: Return true the container contains ``x`` """ @typing.overload - def __delitem__(self, arg0: typing.SupportsInt) -> None: + def __delitem__(self, arg0: int) -> None: """ Delete the list elements at index ``i`` """ @@ -3113,7 +2738,7 @@ class coordinates: Retrieve list elements using a slice object """ @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> ...: ... + def __getitem__(self, arg0: int) -> ...: ... @typing.overload def __init__(self) -> None: ... @typing.overload @@ -3122,12 +2747,12 @@ class coordinates: Copy constructor """ @typing.overload - def __init__(self, arg0: collections.abc.Iterable) -> None: ... - def __iter__(self) -> collections.abc.Iterator[...]: ... + def __init__(self, arg0: typing.Iterable) -> None: ... + def __iter__(self) -> typing.Iterator[...]: ... def __len__(self) -> int: ... def __ne__(self, arg0: coordinates) -> bool: ... @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: ...) -> None: ... + def __setitem__(self, arg0: int, arg1: ...) -> None: ... @typing.overload def __setitem__(self, arg0: slice, arg1: coordinates) -> None: """ @@ -3139,11 +2764,10 @@ class coordinates: """ def as_numpy( self, - ) -> typing.Annotated[ - numpy.typing.NDArray[numpy.float64], - "[m, 3]", - "flags.writeable", - "flags.c_contiguous", + ) -> numpy.ndarray[ + numpy.float64[m, 3], + numpy.ndarray.flags.writeable, + numpy.ndarray.flags.c_contiguous, ]: """ Get a numpy view of the coordinates @@ -3162,20 +2786,17 @@ class coordinates: Extend the list by appending all the items in the given list """ @typing.overload - def extend(self, L: collections.abc.Iterable) -> None: + def extend(self, L: typing.Iterable) -> None: """ Extend the list by appending all the items in the given list """ def from_numpy( - self, - arg0: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, n]", "flags.c_contiguous" - ], + self, arg0: numpy.ndarray[numpy.float64[m, n], numpy.ndarray.flags.c_contiguous] ) -> coordinates: """ Set coordinates from a numpy array """ - def insert(self, i: typing.SupportsInt, x: ...) -> None: + def insert(self, i: int, x: ...) -> None: """ Insert an item at a given position. """ @@ -3185,7 +2806,7 @@ class coordinates: Remove and return the last item """ @typing.overload - def pop(self, i: typing.SupportsInt) -> ...: + def pop(self, i: int) -> ...: """ Remove and return the item at index ``i`` """ @@ -3193,25 +2814,23 @@ class coordinates: """ Remove the first item from the list whose value is x. It is an error if there is no such item. """ - def to_numpy( - self, - ) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + def to_numpy(self) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert coordinates to a numpy array """ class value: class ItemsView: - def __iter__(self) -> collections.abc.Iterator: ... + def __iter__(self) -> typing.Iterator: ... def __len__(self) -> int: ... class KeysView: def __contains__(self, arg0: typing.Any) -> bool: ... - def __iter__(self) -> collections.abc.Iterator: ... + def __iter__(self) -> typing.Iterator: ... def __len__(self) -> int: ... class ValuesView: - def __iter__(self) -> collections.abc.Iterator: ... + def __iter__(self) -> typing.Iterator: ... def __len__(self) -> int: ... class array_type: @@ -3229,7 +2848,7 @@ class value: Return true the container contains ``x`` """ @typing.overload - def __delitem__(self, arg0: typing.SupportsInt) -> None: + def __delitem__(self, arg0: int) -> None: """ Delete the list elements at index ``i`` """ @@ -3245,9 +2864,9 @@ class value: Retrieve list elements using a slice object """ @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> value: ... + def __getitem__(self, arg0: int) -> value: ... @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> value: + def __getitem__(self, arg0: int) -> value: """ Get an item from the GeoJSON array by index """ @@ -3259,7 +2878,7 @@ class value: Copy constructor """ @typing.overload - def __init__(self, arg0: collections.abc.Iterable) -> None: ... + def __init__(self, arg0: typing.Iterable) -> None: ... @typing.overload def __init__(self) -> None: """ @@ -3270,18 +2889,18 @@ class value: """ Construct a GeoJSON array from a Python iterable """ - def __iter__(self) -> collections.abc.Iterator[value]: ... + def __iter__(self) -> typing.Iterator[value]: ... def __len__(self) -> int: ... def __ne__(self, arg0: value.array_type) -> bool: ... @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: value) -> None: ... + def __setitem__(self, arg0: int, arg1: value) -> None: ... @typing.overload def __setitem__(self, arg0: slice, arg1: value.array_type) -> None: """ Assign list elements using a slice object """ @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: typing.Any) -> value: + def __setitem__(self, arg0: int, arg1: typing.Any) -> value: """ Set an item in the GeoJSON array by index """ @@ -3309,7 +2928,7 @@ class value: Extend the list by appending all the items in the given list """ @typing.overload - def extend(self, L: collections.abc.Iterable) -> None: + def extend(self, L: typing.Iterable) -> None: """ Extend the list by appending all the items in the given list """ @@ -3319,7 +2938,7 @@ class value: """ Set the GeoJSON array from a RapidJSON value """ - def insert(self, i: typing.SupportsInt, x: value) -> None: + def insert(self, i: int, x: value) -> None: """ Insert an item at a given position. """ @@ -3329,7 +2948,7 @@ class value: Remove and return the last item """ @typing.overload - def pop(self, i: typing.SupportsInt) -> value: + def pop(self, i: int) -> value: """ Remove and return the item at index ``i`` """ @@ -3369,7 +2988,7 @@ class value: """ Construct a GeoJSON object from a Python dict """ - def __iter__(self) -> collections.abc.Iterator[str]: ... + def __iter__(self) -> typing.Iterator[str]: ... def __len__(self) -> int: ... @typing.overload def __setitem__(self, arg0: str, arg1: value) -> None: ... @@ -3391,14 +3010,14 @@ class value: @typing.overload def items(self) -> value.ItemsView: ... @typing.overload - def items(self) -> collections.abc.Iterator[tuple[str, value]]: + def items(self) -> typing.Iterator[tuple[str, value]]: """ Get an iterator over the items (key-value pairs) of the GeoJSON object """ @typing.overload def keys(self) -> value.KeysView: ... @typing.overload - def keys(self) -> collections.abc.Iterator[str]: + def keys(self) -> typing.Iterator[str]: """ Get an iterator over the keys of the GeoJSON object """ @@ -3409,7 +3028,7 @@ class value: @typing.overload def values(self) -> value.ValuesView: ... @typing.overload - def values(self) -> collections.abc.Iterator[value]: + def values(self) -> typing.Iterator[value]: """ Get an iterator over the values of the GeoJSON object """ @@ -3456,12 +3075,12 @@ class value: Delete an item from the GeoJSON object by key """ @typing.overload - def __delitem__(self, arg0: typing.SupportsInt) -> None: + def __delitem__(self, arg0: int) -> None: """ Delete an item from the GeoJSON array by index """ @typing.overload - def __getitem__(self, arg0: typing.SupportsInt) -> value: + def __getitem__(self, arg0: int) -> value: """ Get an item from the GeoJSON array by index """ @@ -3490,7 +3109,7 @@ class value: Set an item in the GeoJSON object by key """ @typing.overload - def __setitem__(self, arg0: typing.SupportsInt, arg1: typing.Any) -> typing.Any: + def __setitem__(self, arg0: int, arg1: typing.Any) -> typing.Any: """ Set an item in the GeoJSON array by index """ @@ -3522,11 +3141,11 @@ class value: """ Check if the GeoJSON value is an object """ - def items(self) -> collections.abc.Iterator[tuple[str, value]]: + def items(self) -> typing.Iterator[tuple[str, value]]: """ Get an iterator over the items of the GeoJSON object """ - def keys(self) -> collections.abc.Iterator[str]: + def keys(self) -> typing.Iterator[str]: """ Get an iterator over the keys of the GeoJSON object """ @@ -3546,7 +3165,7 @@ class value: """ Convert the GeoJSON value to a RapidJSON value """ - def values(self) -> collections.abc.Iterator[value]: + def values(self) -> typing.Iterator[value]: """ Get an iterator over the values of the GeoJSON object """ diff --git a/src/pybind11_geobuf/_core/tf.pyi b/src/pybind11_geobuf/_core/tf.pyi index 4170630..e7c81f5 100644 --- a/src/pybind11_geobuf/_core/tf.pyi +++ b/src/pybind11_geobuf/_core/tf.pyi @@ -1,6 +1,5 @@ from __future__ import annotations import numpy -import numpy.typing import typing __all__: list[str] = [ @@ -17,143 +16,118 @@ __all__: list[str] = [ "lla2enu", ] -def R_ecef_enu( - lon: typing.SupportsFloat, lat: typing.SupportsFloat -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[3, 3]"]: +def R_ecef_enu(lon: float, lat: float) -> numpy.ndarray[numpy.float64[3, 3]]: """ Get rotation matrix from ECEF to ENU coordinate system. """ @typing.overload def T_ecef_enu( - lon: typing.SupportsFloat, lat: typing.SupportsFloat, alt: typing.SupportsFloat -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[4, 4]"]: + lon: float, lat: float, alt: float +) -> numpy.ndarray[numpy.float64[4, 4]]: """ Get transformation matrix from ECEF to ENU coordinate system. """ @typing.overload def T_ecef_enu( - lla: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[4, 4]"]: + lla: numpy.ndarray[numpy.float64[3, 1]], +) -> numpy.ndarray[numpy.float64[4, 4]]: """ Get transformation matrix from ECEF to ENU coordinate system using LLA vector. """ def apply_transform( - T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"], - coords: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, 3]", "flags.c_contiguous" - ], -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + T: numpy.ndarray[numpy.float64[4, 4]], + coords: numpy.ndarray[numpy.float64[m, 3], numpy.ndarray.flags.c_contiguous], +) -> numpy.ndarray[numpy.float64[m, 3]]: """ Apply transformation matrix to coordinates. """ def apply_transform_inplace( - T: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[4, 4]"], - coords: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], - "[m, 3]", - "flags.writeable", - "flags.c_contiguous", + T: numpy.ndarray[numpy.float64[4, 4]], + coords: numpy.ndarray[ + numpy.float64[m, 3], + numpy.ndarray.flags.writeable, + numpy.ndarray.flags.c_contiguous, ], *, - batch_size: typing.SupportsInt = 1000, + batch_size: int = 1000, ) -> None: """ Apply transformation matrix to coordinates in-place. """ -def cheap_ruler_k( - latitude: typing.SupportsFloat, -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[3, 1]"]: +def cheap_ruler_k(latitude: float) -> numpy.ndarray[numpy.float64[3, 1]]: """ Get the cheap ruler's unit conversion factor for a given latitude. """ def ecef2enu( - ecefs: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, 3]", "flags.c_contiguous" - ], + ecefs: numpy.ndarray[numpy.float64[m, 3], numpy.ndarray.flags.c_contiguous], *, - anchor_lla: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - | None = None, + anchor_lla: numpy.ndarray[numpy.float64[3, 1]] | None = None, cheap_ruler: bool = False, -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: +) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert ECEF to ENU (East, North, Up) coordinates. """ @typing.overload -def ecef2lla( - x: typing.SupportsFloat, y: typing.SupportsFloat, z: typing.SupportsFloat -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[3, 1]"]: +def ecef2lla(x: float, y: float, z: float) -> numpy.ndarray[numpy.float64[3, 1]]: """ Convert ECEF coordinates to LLA (Longitude, Latitude, Altitude). """ @typing.overload def ecef2lla( - ecefs: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, 3]", "flags.c_contiguous" - ], -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + ecefs: numpy.ndarray[numpy.float64[m, 3], numpy.ndarray.flags.c_contiguous], +) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert multiple ECEF coordinates to LLA (Longitude, Latitude, Altitude). """ def enu2ecef( - enus: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, 3]", "flags.c_contiguous" - ], + enus: numpy.ndarray[numpy.float64[m, 3], numpy.ndarray.flags.c_contiguous], *, - anchor_lla: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], + anchor_lla: numpy.ndarray[numpy.float64[3, 1]], cheap_ruler: bool = False, -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: +) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert ENU (East, North, Up) to ECEF coordinates. """ def enu2lla( - enus: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, 3]", "flags.c_contiguous" - ], + enus: numpy.ndarray[numpy.float64[m, 3], numpy.ndarray.flags.c_contiguous], *, - anchor_lla: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"], + anchor_lla: numpy.ndarray[numpy.float64[3, 1]], cheap_ruler: bool = True, -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: +) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert ENU (East, North, Up) to LLA (Longitude, Latitude, Altitude) coordinates. """ @typing.overload -def lla2ecef( - lon: typing.SupportsFloat, lat: typing.SupportsFloat, alt: typing.SupportsFloat -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[3, 1]"]: +def lla2ecef(lon: float, lat: float, alt: float) -> numpy.ndarray[numpy.float64[3, 1]]: """ Convert LLA (Longitude, Latitude, Altitude) to ECEF coordinates. """ @typing.overload def lla2ecef( - llas: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, 3]", "flags.c_contiguous" - ], -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: + llas: numpy.ndarray[numpy.float64[m, 3], numpy.ndarray.flags.c_contiguous], +) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert multiple LLA (Longitude, Latitude, Altitude) to ECEF coordinates. """ def lla2enu( - llas: typing.Annotated[ - numpy.typing.NDArray[numpy.float64], "[m, 3]", "flags.c_contiguous" - ], + llas: numpy.ndarray[numpy.float64[m, 3], numpy.ndarray.flags.c_contiguous], *, - anchor_lla: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[3, 1]"] - | None = None, + anchor_lla: numpy.ndarray[numpy.float64[3, 1]] | None = None, cheap_ruler: bool = True, -) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 3]"]: +) -> numpy.ndarray[numpy.float64[m, 3]]: """ Convert LLA (Longitude, Latitude, Altitude) to ENU (East, North, Up) coordinates. """