Coverage for qubalab/objects/geometry.py: 88%
34 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-10-07 15:29 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-10-07 15:29 +0000
1import geojson.geometry
2import geojson
3from typing import Union, Optional
6class ImagePlane(dict):
7 """
8 An additional property of a geometry containing z and t indices.
9 """
11 def __init__(self, z: int = 0, t: int = 0):
12 """
13 :param z: the z-stack of the geometry
14 :param t: the time point of the geometry
15 """
16 dict.__init__(self, z=z, t=t)
18 def __getattr__(self, name):
19 try:
20 return self[name]
21 except KeyError:
22 raise AttributeError(name)
24 def __setattr__(self, name, value):
25 raise AttributeError("ImagePlane is immutable")
27 def __delattr__(self, name):
28 raise AttributeError("ImagePlane is immutable")
31def add_plane_to_geometry(
32 geometry: Union[geojson.geometry.Geometry, geojson.Feature],
33 z: Optional[int] = None,
34 t: Optional[int] = None,
35 preferred_geometry_key: Optional[str] = None,
36) -> Optional[geojson.geometry.Geometry]:
37 """
38 Create a GeoJSON Geometry object with an additional 'plane' property containing z and t indices.
40 If indices are unspecified, they will be taken from the geometry's 'plane' property, if present,
41 or else z or t attributes otherwise.
42 If z and t values cannot be found in either of these locations, defaults (z=0 and t=0) will be
43 used instead.
45 The 'plane' property is immutable.
47 :param geometry: a GeoJSON feature or geometry. It must not be a FeatureCollection
48 :param z: the z-stack index this geometry should have
49 :param t: the timepoint this geometry should have
50 :param preferred_geometry_key: if the provided geometry is a feature, and this feature has a 'extra_geometries'
51 property, then this parameter can be used as a key to retrieve the geometry to
52 consider from the 'extra_geometries' dictionnary
53 :return: a GeoJSON Geometry containing an additional 'plane' property containing z and t indices
54 :raises ValueError: when the provided geometry is a FeatureCollection
55 """
56 if geometry is None:
57 return None
59 if isinstance(geometry, geojson.Feature):
60 feature = geometry
61 if (
62 preferred_geometry_key is not None
63 and "extra_geometries" in feature.properties
64 ):
65 geometry = feature.properties["extra_geometries"].get(
66 preferred_geometry_key, feature.geometry
67 )
68 else:
69 geometry = feature.geometry
70 elif isinstance(geometry, geojson.FeatureCollection):
71 raise ValueError("Cannot convert FeatureCollection to single Geometry")
73 if z is None or t is None:
74 plane = getattr(geometry, "plane", None)
75 if z is None:
76 z = (
77 getattr(plane, "z", 0)
78 if plane is not None
79 else getattr(geometry, "z", 0)
80 )
81 if t is None:
82 t = (
83 getattr(plane, "t", 0)
84 if plane is not None
85 else getattr(geometry, "t", 0)
86 )
88 geometry = geojson.GeoJSON.to_instance(geometry, strict=False)
89 geometry.plane = ImagePlane(z, t)
90 return geometry