Apply `func` to all coordinates of `geom`. Returns a new geometry of the same type from the transformed coordinates. `func` maps x, y, and optionally z to output xp, yp, zp. The input parameters may iterable types like lists or arrays or single values. The output shall be of the sa
(func, geom)
| 208 | |
| 209 | |
| 210 | def transform(func, geom): |
| 211 | """Apply `func` to all coordinates of `geom`. |
| 212 | |
| 213 | Returns a new geometry of the same type from the transformed coordinates. |
| 214 | |
| 215 | `func` maps x, y, and optionally z to output xp, yp, zp. The input |
| 216 | parameters may iterable types like lists or arrays or single values. |
| 217 | The output shall be of the same type. Scalars in, scalars out. |
| 218 | Lists in, lists out. |
| 219 | |
| 220 | For example, here is an identity function applicable to both types |
| 221 | of input. |
| 222 | |
| 223 | def id_func(x, y, z=None): |
| 224 | return tuple(filter(None, [x, y, z])) |
| 225 | |
| 226 | g2 = transform(id_func, g1) |
| 227 | |
| 228 | Using pyproj >= 2.1, this example will accurately project Shapely geometries: |
| 229 | |
| 230 | import pyproj |
| 231 | |
| 232 | wgs84 = pyproj.CRS('EPSG:4326') |
| 233 | utm = pyproj.CRS('EPSG:32618') |
| 234 | |
| 235 | project = pyproj.Transformer.from_crs(wgs84, utm, always_xy=True).transform |
| 236 | |
| 237 | g2 = transform(project, g1) |
| 238 | |
| 239 | Note that the always_xy kwarg is required here as Shapely geometries only support |
| 240 | X,Y coordinate ordering. |
| 241 | |
| 242 | Lambda expressions such as the one in |
| 243 | |
| 244 | g2 = transform(lambda x, y, z=None: (x+1.0, y+1.0), g1) |
| 245 | |
| 246 | also satisfy the requirements for `func`. |
| 247 | """ |
| 248 | if geom.is_empty: |
| 249 | return geom |
| 250 | if geom.geom_type in ("Point", "LineString", "LinearRing", "Polygon"): |
| 251 | # First we try to apply func to x, y, z sequences. When func is |
| 252 | # optimized for sequences, this is the fastest, though zipping |
| 253 | # the results up to go back into the geometry constructors adds |
| 254 | # extra cost. |
| 255 | try: |
| 256 | if geom.geom_type in ("Point", "LineString", "LinearRing"): |
| 257 | return type(geom)(zip(*func(*zip(*geom.coords)))) |
| 258 | elif geom.geom_type == "Polygon": |
| 259 | shell = type(geom.exterior)(zip(*func(*zip(*geom.exterior.coords)))) |
| 260 | holes = [ |
| 261 | type(ring)(zip(*func(*zip(*ring.coords)))) |
| 262 | for ring in geom.interiors |
| 263 | ] |
| 264 | return type(geom)(shell, holes) |
| 265 | |
| 266 | # A func that assumes x, y, z are single values will likely raise a |
| 267 | # TypeError, in which case we'll try again. |
searching dependent graphs…