Coverage for gws-app/gws/plugin/model_field/geometry/__init__.py: 0%
93 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
1"""Geometry field."""
3from typing import Optional, cast
5import gws
6import gws.base.database.model
7import gws.base.model.scalar_field
8import gws.base.shape
9import gws.gis.crs
10import gws.lib.sa as sa
13gws.ext.new.modelField('geometry')
16class Config(gws.base.model.scalar_field.Config):
17 geometryType: Optional[gws.GeometryType]
18 crs: Optional[gws.CrsName]
21class Props(gws.base.model.scalar_field.Props):
22 geometryType: gws.GeometryType
25class Object(gws.base.model.scalar_field.Object):
26 attributeType = gws.AttributeType.geometry
27 supportsGeometrySearch = True
29 geometryType: gws.GeometryType
30 geometryCrs: gws.Crs
32 def configure(self):
33 setattr(self, 'geometryType', None)
34 setattr(self, 'geometryCrs', None)
35 self.configure_geometry_type()
36 self.configure_geometry_crs()
37 if not self.geometryCrs:
38 tab = getattr(self.model, 'tableName', '')
39 raise gws.ConfigurationError(f'unknown CRS for {tab!r}.{self.name!r}')
41 def configure_geometry_type(self):
42 s = self.cfg('geometryType')
43 if s:
44 self.geometryType = s
45 return True
47 col = self.describe()
48 if col and col.geometryType:
49 self.geometryType = col.geometryType
50 return True
52 def configure_geometry_crs(self):
53 s = self.cfg('crs')
54 if s:
55 self.geometryCrs = gws.gis.crs.get(s)
56 return True
58 col = self.describe()
59 if col and col.geometrySrid:
60 crs = gws.gis.crs.get(col.geometrySrid)
61 if crs:
62 self.geometryCrs = crs
63 return True
65 def configure_widget(self):
66 if not super().configure_widget():
67 self.widget = self.root.create_shared(gws.ext.object.modelWidget, type='geometry')
68 return True
70 ##
72 def props(self, user):
73 return gws.u.merge(super().props(user), geometryType=self.geometryType)
75 ##
77 def before_select(self, mc):
78 super().before_select(mc)
80 shape = None
82 if mc.search.shape:
83 shape = mc.search.shape
84 if mc.search.tolerance:
85 tol_value, tol_unit = mc.search.tolerance
86 if tol_unit == gws.Uom.px:
87 tol_value *= mc.search.resolution
88 shape = shape.tolerance_polygon(tol_value)
89 elif mc.search.bounds:
90 shape = gws.base.shape.from_bounds(mc.search.bounds)
92 if shape:
93 shape = shape.transformed_to(self.geometryCrs)
95 model = cast(gws.base.database.model.Object, self.model)
96 col = model.column(self.name)
98 mc.dbSelect.geometryWhere.append(sa.func.st_intersects(
99 col,
100 sa.cast(shape.to_ewkb_hex(), sa.geo.Geometry())))
102 def raw_to_python(self, feature, value, mc):
103 # here, value is a geosa WKBElement
104 return gws.base.shape.from_wkb_hex(str(value))
106 def prop_to_python(self, feature, value, mc):
107 shape = self._prop_to_shape(value)
108 if shape:
109 return shape.transformed_to(self.geometryCrs)
110 return gws.ErrorValue
112 def python_to_raw(self, feature, value, mc):
113 return value.to_ewkb_hex()
115 def python_to_prop(self, feature, value, mc):
116 return cast(gws.Shape, value).to_props()
118 def _prop_to_shape(self, value):
119 if isinstance(value, gws.base.shape.Shape):
120 return value
121 if gws.u.is_data_object(value):
122 try:
123 return gws.base.shape.from_props(value)
124 except gws.Error:
125 pass
126 if gws.u.is_dict(value):
127 try:
128 return gws.base.shape.from_dict(value)
129 except gws.Error:
130 pass