@@ -178,15 +178,43 @@ def __init__(self, value, props, factory):
178178 self .factory = factory
179179
180180 def set_coordinates (self , value ):
181- m = re .fullmatch (r'(POINT|LINESTRING|POLYGON)\((.*)\)' , value )
181+ if value .startswith ('GEOMETRYCOLLECTION(' ):
182+ geoms = []
183+ remain = value [19 :- 1 ]
184+ while remain :
185+ _ , value , remain = self ._parse_simple_wkt (remain )
186+ remain = remain [1 :] # delete comma
187+ geoms .append (value )
188+ self .geom_type = 'GEOMETRYCOLLECTION'
189+ self .value = geoms
190+ else :
191+ self .geom_type , self .value , remain = self ._parse_simple_wkt (value )
192+ if remain :
193+ raise RuntimeError ('trailing content for geometry: ' + value )
194+
195+ def _parse_simple_wkt (self , value ):
196+ m = re .fullmatch (r'(MULTI)?(POINT|LINESTRING|POLYGON)\(([^A-Z]*)\)(.*)' , value )
182197 if not m :
183198 raise RuntimeError (f'Unparsable WKT: { value } ' )
184- if m [1 ] == 'POINT' :
185- self .value = self ._parse_wkt_coord (m [2 ])
186- elif m [1 ] == 'LINESTRING' :
187- self .value = self ._parse_wkt_line (m [2 ])
188- elif m [1 ] == 'POLYGON' :
189- self .value = [self ._parse_wkt_line (ln ) for ln in m [2 ][1 :- 1 ].split ('),(' )]
199+ geom_type = (m [1 ] or '' ) + m [2 ]
200+ if m [1 ] == 'MULTI' :
201+ splitup = m [3 ][1 :- 1 ].split ('),(' )
202+ if m [2 ] == 'POINT' :
203+ value = [self ._parse_wkt_coord (c ) for c in splitup ]
204+ elif m [2 ] == 'LINESTRING' :
205+ value = [self ._parse_wkt_line (c ) for c in splitup ]
206+ elif m [2 ] == 'POLYGON' :
207+ value = [[self ._parse_wkt_line (ln ) for ln in poly [1 :- 1 ].split ('),(' )]
208+ for poly in splitup ]
209+ else :
210+ if m [2 ] == 'POINT' :
211+ value = self ._parse_wkt_coord (m [3 ])
212+ elif m [2 ] == 'LINESTRING' :
213+ value = self ._parse_wkt_line (m [3 ])
214+ elif m [2 ] == 'POLYGON' :
215+ value = [self ._parse_wkt_line (ln ) for ln in m [3 ][1 :- 1 ].split ('),(' )]
216+
217+ return geom_type , value , m [4 ]
190218
191219 def _parse_wkt_coord (self , coord ):
192220 return tuple (DBValueFloat (float (f .strip ()), self .precision ) for f in coord .split ())
@@ -195,14 +223,51 @@ def _parse_wkt_line(self, coords):
195223 return [self ._parse_wkt_coord (pt ) for pt in coords .split (',' )]
196224
197225 def __eq__ (self , other ):
198- if other .find (',' ) < 0 :
199- geom = self ._parse_input_coord (other )
200- elif other .find ('(' ) < 0 :
201- geom = self ._parse_input_line (other )
226+ if other .startswith ('[' ) and other .endswith (']' ):
227+ gtype = 'MULTI'
228+ toparse = other [1 :- 1 ].split (';' )
229+ elif other .startswith ('{' ) and other .endswith ('}' ):
230+ gtype = 'GEOMETRYCOLLECTION'
231+ toparse = other [1 :- 1 ].split (';' )
202232 else :
203- geom = [self ._parse_input_line (ln ) for ln in other .strip ()[1 :- 1 ].split ('),(' )]
204-
205- return self .value == geom
233+ gtype = None
234+ toparse = [other ]
235+
236+ geoms = []
237+ for sub in toparse :
238+ sub = sub .strip ()
239+ if sub .find (',' ) < 0 :
240+ geoms .append (self ._parse_input_coord (sub ))
241+ if gtype is None :
242+ gtype = 'POINT'
243+ elif gtype .startswith ('MULTI' ):
244+ if gtype == 'MULTI' :
245+ gtype = 'MULTIPOINT'
246+ elif gtype != 'MULTIPOINT' :
247+ raise RuntimeError ('MULTI* geometry with different geometry types is not supported.' )
248+ elif sub .find ('(' ) < 0 :
249+ geoms .append (self ._parse_input_line (sub ))
250+ if gtype is None :
251+ gtype = 'LINESTRING'
252+ elif gtype .startswith ('MULTI' ):
253+ if gtype == 'MULTI' :
254+ gtype = 'MULTILINESTRING'
255+ elif gtype != 'MULTILINESTRING' :
256+ raise RuntimeError ('MULTI* geometry with different geometry types is not supported.' )
257+ else :
258+ geoms .append ([self ._parse_input_line (ln ) for ln in sub .strip ()[1 :- 1 ].split ('),(' )])
259+ if gtype is None :
260+ gtype = 'POLYGON'
261+ elif gtype .startswith ('MULTI' ):
262+ if gtype == 'MULTI' :
263+ gtype = 'MULTIPOLYGON'
264+ elif gtype != 'MULTIPOLYGON' :
265+ raise RuntimeError ('MULTI* geometry with different geometry types is not supported.' )
266+
267+ if not gtype .startswith ('MULTI' ) and gtype != 'GEOMETRYCOLLECTION' :
268+ geoms = geoms [0 ]
269+
270+ return gtype == self .geom_type and self .value == geoms
206271
207272 def _parse_input_coord (self , other ):
208273 coords = other .split (' ' )
0 commit comments