Python 的 Geodaisy 库转换带负号坐标的WKT时的Bug

Geodaisy是一个Python库,用于创建由类型和坐标表示的地理对象,并在各种标准和表示之间进行转换,包括GeoJSON、Well - Known Text和Python的__geo_interface__协议,它被其他地理库使用。
源码地址:https://gitee.com/mzfly/geodaisy.git
在使用其 converters.wkt_to_geo_interface()方法时转换带符号坐标的wkt字符串时,发现其转换的结果跟预期的不一样:
例如:
> wkt = "MULTILINESTRING ((3146.2134801800566 2556399.9823166174, -2611.53319329879 2564044.0076796883))"
> converters.wkt_to_geo_interface(wkt)
# {'type': 'MultiLineString', 'coordinates': (3146.2134801800566, 2556399.9823166174, -2611.53319329879, 2564044.0076796883)}

我们看到 coordinates 的值并不是我们想要的结果:

{'type': 'MultiLineString', 'coordinates': [(3146.2134801800566, 2556399.9823166174), (-2611.53319329879, 2564044.0076796883)]}

原因是 wkt_to_geo_interface 方法源码采用正则匹配,并没有考虑带负数坐标的情况(或者根本就不考虑),但是在地方坐标系处理偏移的过程中是肯定有出现负值坐标的情况的。

解决方法:

修改wkt_to_geo_interface方法源码的正则匹配(匹配”-“号和数字):

 1 def wkt_to_geo_interface(wkt):
 2     # type: (str) -> dict
 3     """Converts a WKT string to a geo_interface dictionary."""
 4     try:
 5         wkt_type, coords = re.split(r'(?<=[A-Z])\s', wkt)
 6 
 7         geo_type = type_translations[wkt_type]
 8 
 9         # Clean up the strings so they'll covert correctly
10         if geo_type in {'Polygon', 'MultiLineString', 'MultiPolygon'}:
11             # coords = re.sub(r'(?<=\d)\), \((?=\d)', ')), ((', coords)
12             coords = re.sub(r'(?<=[-\d])\), \((?=[-\d])', ')), ((', coords)   # modif by 举个栗子
13 
14         # Pairs of coordinates must be enclosed in parentheses
15         # coords = re.sub(r'(?<=\d), (?=\d)', '), (', coords)
16         coords = re.sub(r'(?<=[-\d]), (?=[-\d])', '), (', coords) # modif by 举个栗子
17 
18         # Coordinates within parentheses must be separated by commas
19         # coords = re.sub(r'(?<=\d) (?=\d)', ', ', coords)
20         coords = re.sub(r'(?<=[-\d]) (?=[-\d])', ', ', coords)    # # modif by 举个栗子
21 
22         # Now we can turn the string into a tuple or a tuple of tuples
23         coords = literal_eval(coords)
24 
25         coords = reformat_coordinates(coords, 'geo_interface')  # type: ignore  # noqa: E501
26 
27         # If we only have a simple polygon (no hole), the coordinate array
28         # won't be deep enough to satisfy the GeoJSON/geo_interface spec, so
29         # we need to enclose it in a list.
30         numbers = {float, int}
31         if geo_type == 'Polygon' and type(coords[0][0]) in numbers:
32             coords = [coords]  # type: ignore
33         elif geo_type == 'MultiPolygon' and type(coords[0][0][0]) in numbers:
34             coords = [coords]  # type: ignore
35 
36     except Exception:
37         raise ValueError('{} is not a WKT string'.format(wkt))
38 
39     return {'type': geo_type, 'coordinates': coords}

 

posted @ 2021-11-18 09:57  橘个栗子  阅读(187)  评论(0编辑  收藏  举报