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

1"""Geometry field.""" 

2 

3from typing import Optional, cast 

4 

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 

11 

12 

13gws.ext.new.modelField('geometry') 

14 

15 

16class Config(gws.base.model.scalar_field.Config): 

17 geometryType: Optional[gws.GeometryType] 

18 crs: Optional[gws.CrsName] 

19 

20 

21class Props(gws.base.model.scalar_field.Props): 

22 geometryType: gws.GeometryType 

23 

24 

25class Object(gws.base.model.scalar_field.Object): 

26 attributeType = gws.AttributeType.geometry 

27 supportsGeometrySearch = True 

28 

29 geometryType: gws.GeometryType 

30 geometryCrs: gws.Crs 

31 

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}') 

40 

41 def configure_geometry_type(self): 

42 s = self.cfg('geometryType') 

43 if s: 

44 self.geometryType = s 

45 return True 

46 

47 col = self.describe() 

48 if col and col.geometryType: 

49 self.geometryType = col.geometryType 

50 return True 

51 

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 

57 

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 

64 

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 

69 

70 ## 

71 

72 def props(self, user): 

73 return gws.u.merge(super().props(user), geometryType=self.geometryType) 

74 

75 ## 

76 

77 def before_select(self, mc): 

78 super().before_select(mc) 

79 

80 shape = None 

81 

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) 

91 

92 if shape: 

93 shape = shape.transformed_to(self.geometryCrs) 

94 

95 model = cast(gws.base.database.model.Object, self.model) 

96 col = model.column(self.name) 

97 

98 mc.dbSelect.geometryWhere.append(sa.func.st_intersects( 

99 col, 

100 sa.cast(shape.to_ewkb_hex(), sa.geo.Geometry()))) 

101 

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)) 

105 

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 

111 

112 def python_to_raw(self, feature, value, mc): 

113 return value.to_ewkb_hex() 

114 

115 def python_to_prop(self, feature, value, mc): 

116 return cast(gws.Shape, value).to_props() 

117 

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 

131