File: io.py

package info (click to toggle)
python-shapely 2.1.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,528 kB
  • sloc: python: 18,648; ansic: 6,615; makefile: 88; sh: 62
file content (408 lines) | stat: -rw-r--r-- 15,108 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
"""Input/output functions for Shapely geometries."""

import numpy as np

from shapely import geos_version, lib
from shapely._enum import ParamEnum

# include ragged array functions here for reference documentation purpose
from shapely._ragged_array import from_ragged_array, to_ragged_array
from shapely.decorators import requires_geos
from shapely.errors import UnsupportedGEOSVersionError

__all__ = [
    "from_geojson",
    "from_ragged_array",
    "from_wkb",
    "from_wkt",
    "to_geojson",
    "to_ragged_array",
    "to_wkb",
    "to_wkt",
]


# Allowed options for handling WKB/WKT decoding errors
# Note: cannot use standard constructor since "raise" is a keyword
DecodingErrorOptions = ParamEnum(
    "DecodingErrorOptions", {"ignore": 0, "warn": 1, "raise": 2, "fix": 3}
)

WKBFlavorOptions = ParamEnum("WKBFlavorOptions", {"extended": 1, "iso": 2})


def to_wkt(
    geometry,
    rounding_precision=6,
    trim=True,
    output_dimension=None,
    old_3d=False,
    **kwargs,
):
    """Convert to the Well-Known Text (WKT) representation of a Geometry.

    The Well-known Text format is defined in the `OGC Simple Features
    Specification for SQL <https://www.opengeospatial.org/standards/sfs>`__.

    The following limitations apply to WKT serialization:

    - only simple empty geometries can be 3D, empty collections are always 2D

    Parameters
    ----------
    geometry : Geometry or array_like
        Geometry or geometries to convert to WKT.
    rounding_precision : int, default 6
        The rounding precision when writing the WKT string. Set to a value of
        -1 to indicate the full precision.
    trim : bool, default True
        If True, trim unnecessary decimals (trailing zeros). If False,
        use fixed-precision number formatting.
    output_dimension : int, default None
        The output dimension for the WKT string. Supported values are 2, 3 and
        4 for GEOS 3.12+. Default None will automatically choose 3 or 4,
        depending on the version of GEOS.
        Specifying 3 means that up to 3 dimensions will be written but 2D
        geometries will still be represented as 2D in the WKT string.
    old_3d : bool, default False
        Enable old style 3D/4D WKT generation. By default, new style 3D/4D WKT
        (ie. "POINT Z (10 20 30)") is returned, but with ``old_3d=True``
        the WKT will be formatted in the style "POINT (10 20 30)".
    **kwargs
        See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.

    Examples
    --------
    >>> import shapely
    >>> from shapely import Point
    >>> shapely.to_wkt(Point(0, 0))
    'POINT (0 0)'
    >>> shapely.to_wkt(Point(0, 0), rounding_precision=3, trim=False)
    'POINT (0.000 0.000)'
    >>> shapely.to_wkt(Point(0, 0), rounding_precision=-1, trim=False)
    'POINT (0.0000000000000000 0.0000000000000000)'
    >>> shapely.to_wkt(Point(1, 2, 3), trim=True)
    'POINT Z (1 2 3)'
    >>> shapely.to_wkt(Point(1, 2, 3), trim=True, output_dimension=2)
    'POINT (1 2)'
    >>> shapely.to_wkt(Point(1, 2, 3), trim=True, old_3d=True)
    'POINT (1 2 3)'

    Notes
    -----
    The defaults differ from the default of some GEOS versions. To mimic this for
    versions before GEOS 3.12, use::

        shapely.to_wkt(geometry, rounding_precision=-1, trim=False, output_dimension=2)

    """
    if not np.isscalar(rounding_precision):
        raise TypeError("rounding_precision only accepts scalar values")
    if not np.isscalar(trim):
        raise TypeError("trim only accepts scalar values")
    if output_dimension is None:
        output_dimension = 3 if geos_version < (3, 12, 0) else 4
    elif not np.isscalar(output_dimension):
        raise TypeError("output_dimension only accepts scalar values")
    if not np.isscalar(old_3d):
        raise TypeError("old_3d only accepts scalar values")

    return lib.to_wkt(
        geometry,
        np.intc(rounding_precision),
        np.bool_(trim),
        np.intc(output_dimension),
        np.bool_(old_3d),
        **kwargs,
    )


def to_wkb(
    geometry,
    hex=False,
    output_dimension=None,
    byte_order=-1,
    include_srid=False,
    flavor="extended",
    **kwargs,
):
    r"""Convert to the Well-Known Binary (WKB) representation of a Geometry.

    The Well-Known Binary format is defined in the `OGC Simple Features
    Specification for SQL <https://www.opengeospatial.org/standards/sfs>`__.

    The following limitations apply to WKB serialization:

    - linearrings will be converted to linestrings
    - a point with only NaN coordinates is converted to an empty point

    Parameters
    ----------
    geometry : Geometry or array_like
        Geometry or geometries to convert to WKB.
    hex : bool, default False
        If true, export the WKB as a hexadecimal string. The default is to
        return a binary bytes object.
    output_dimension : int, default None
        The output dimension for the WKB. Supported values are 2, 3 and 4 for
        GEOS 3.12+. Default None will automatically choose 3 or 4, depending on
        the version of GEOS.
        Specifying 3 means that up to 3 dimensions will be written but 2D
        geometries will still be represented as 2D in the WKB representation.
    byte_order : int, default -1
        Defaults to native machine byte order (-1). Use 0 to force big endian
        and 1 for little endian.
    include_srid : bool, default False
        If True, the SRID is be included in WKB (this is an extension
        to the OGC WKB specification). Not allowed when flavor is "iso".
    flavor : {"iso", "extended"}, default "extended"
        Which flavor of WKB will be returned. The flavor determines how
        extra dimensionality is encoded with the type number, and whether
        SRID can be included in the WKB. ISO flavor is "more standard" for
        3D output, and does not support SRID embedding.
        Both flavors are equivalent when ``output_dimension=2`` (or with 2D
        geometries) and ``include_srid=False``.
        The `from_wkb` function can read both flavors.
    **kwargs
        See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.

    Examples
    --------
    >>> import shapely
    >>> from shapely import Point
    >>> point = Point(1, 1)
    >>> shapely.to_wkb(point, byte_order=1)
    b'\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?'
    >>> shapely.to_wkb(point, hex=True, byte_order=1)
    '0101000000000000000000F03F000000000000F03F'

    """
    if not np.isscalar(hex):
        raise TypeError("hex only accepts scalar values")
    if output_dimension is None:
        output_dimension = 3 if geos_version < (3, 12, 0) else 4
    elif not np.isscalar(output_dimension):
        raise TypeError("output_dimension only accepts scalar values")
    if not np.isscalar(byte_order):
        raise TypeError("byte_order only accepts scalar values")
    if not np.isscalar(include_srid):
        raise TypeError("include_srid only accepts scalar values")
    if not np.isscalar(flavor):
        raise TypeError("flavor only accepts scalar values")
    if lib.geos_version < (3, 10, 0) and flavor == "iso":
        raise UnsupportedGEOSVersionError(
            'The "iso" option requires at least GEOS 3.10.0'
        )
    if flavor == "iso" and include_srid:
        raise ValueError('flavor="iso" and include_srid=True cannot be used together')
    flavor = WKBFlavorOptions.get_value(flavor)

    return lib.to_wkb(
        geometry,
        np.bool_(hex),
        np.intc(output_dimension),
        np.intc(byte_order),
        np.bool_(include_srid),
        np.intc(flavor),
        **kwargs,
    )


@requires_geos("3.10.0")
def to_geojson(geometry, indent=None, **kwargs):
    """Convert to the GeoJSON representation of a Geometry.

    The GeoJSON format is defined in the `RFC 7946 <https://geojson.org/>`__.
    NaN (not-a-number) coordinates will be written as 'null'.

    The following are currently unsupported:

    - Geometries of type LINEARRING: these are output as 'null'.
    - Three-dimensional geometries: the third dimension is ignored.

    Parameters
    ----------
    geometry : str, bytes or array_like
        Geometry or geometries to convert to GeoJSON.
    indent : int, optional
        If indent is a non-negative integer, then GeoJSON will be formatted.
        An indent level of 0 will only insert newlines. None (the default)
        selects the most compact representation.
    **kwargs
        See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.

    Examples
    --------
    >>> import shapely
    >>> from shapely import Point
    >>> point = Point(1, 1)
    >>> shapely.to_geojson(point)
    '{"type":"Point","coordinates":[1.0,1.0]}'
    >>> print(shapely.to_geojson(point, indent=2))
    {
      "type": "Point",
      "coordinates": [
          1.0,
          1.0
      ]
    }

    """
    # GEOS Tickets:
    # - handle linearrings: https://trac.osgeo.org/geos/ticket/1140
    # - support 3D: https://trac.osgeo.org/geos/ticket/1141
    if indent is None:
        indent = -1
    elif not np.isscalar(indent):
        raise TypeError("indent only accepts scalar values")
    elif indent < 0:
        raise ValueError("indent cannot be negative")

    return lib.to_geojson(geometry, np.intc(indent), **kwargs)


def from_wkt(geometry, on_invalid="raise", **kwargs):
    """Create geometries from the Well-Known Text (WKT) representation.

    The Well-known Text format is defined in the `OGC Simple Features
    Specification for SQL <https://www.opengeospatial.org/standards/sfs>`__.

    Parameters
    ----------
    geometry : str or array_like
        The WKT string(s) to convert.
    on_invalid : {"raise", "warn", "ignore", "fix"}, default "raise"
        Indicates what to do when an invalid WKT string is encountered. Note
        that the validations involved are very basic, e.g. the minimum number of
        points for the geometry type. For a thorough check, use
        :func:`is_valid` after conversion to geometries. Valid options are:

        - raise: an exception will be raised if any input geometry is invalid.
        - warn: a warning will be raised and invalid WKT geometries will be
          returned as ``None``.
        - ignore: invalid geometries will be returned as ``None`` without a
          warning.
        - fix: an effort is made to fix invalid input geometries (currently just
          unclosed rings). If this is not possible, they are returned as
          ``None`` without a warning. Requires GEOS >= 3.11.

          .. versionadded:: 2.1.0
    **kwargs
        See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.

    Examples
    --------
    >>> import shapely
    >>> shapely.from_wkt('POINT (0 0)')
    <POINT (0 0)>

    """
    if not np.isscalar(on_invalid):
        raise TypeError("on_invalid only accepts scalar values")

    invalid_handler = np.uint8(DecodingErrorOptions.get_value(on_invalid))

    return lib.from_wkt(geometry, invalid_handler, **kwargs)


def from_wkb(geometry, on_invalid="raise", **kwargs):
    r"""Create geometries from the Well-Known Binary (WKB) representation.

    The Well-Known Binary format is defined in the `OGC Simple Features
    Specification for SQL <https://www.opengeospatial.org/standards/sfs>`__.

    Parameters
    ----------
    geometry : str or array_like
        The WKB byte object(s) to convert.
    on_invalid : {"raise", "warn", "ignore", "fix"}, default "raise"
        Indicates what to do when an invalid WKB is encountered. Note that the
        validations involved are very basic, e.g. the minimum number of points
        for the geometry type. For a thorough check, use :func:`is_valid` after
        conversion to geometries. Valid options are:

        - raise: an exception will be raised if any input geometry is invalid.
        - warn: a warning will be raised and invalid WKT geometries will be
          returned as ``None``.
        - ignore: invalid geometries will be returned as ``None`` without a
          warning.
        - fix: an effort is made to fix invalid input geometries (currently just
          unclosed rings). If this is not possible, they are returned as
          ``None`` without a warning. Requires GEOS >= 3.11.

          .. versionadded:: 2.1.0
    **kwargs
        See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.

    Examples
    --------
    >>> import shapely
    >>> shapely.from_wkb(b'\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?')
    <POINT (1 1)>

    """  # noqa: E501
    if not np.isscalar(on_invalid):
        raise TypeError("on_invalid only accepts scalar values")

    invalid_handler = np.uint8(DecodingErrorOptions.get_value(on_invalid))

    # ensure the input has object dtype, to avoid numpy inferring it as a
    # fixed-length string dtype (which removes trailing null bytes upon access
    # of array elements)
    geometry = np.asarray(geometry, dtype=object)
    return lib.from_wkb(geometry, invalid_handler, **kwargs)


@requires_geos("3.10.1")
def from_geojson(geometry, on_invalid="raise", **kwargs):
    """Create geometries from GeoJSON representations (strings).

    If a GeoJSON is a FeatureCollection, it is read as a single geometry
    (with type GEOMETRYCOLLECTION). This may be unpacked using
    :meth:`shapely.get_parts`. Properties are not read.

    The GeoJSON format is defined in `RFC 7946 <https://geojson.org/>`__.

    The following are currently unsupported:

    - Three-dimensional geometries: the third dimension is ignored.
    - Geometries having 'null' in the coordinates.

    Parameters
    ----------
    geometry : str, bytes or array_like
        The GeoJSON string or byte object(s) to convert.
    on_invalid : {"raise", "warn", "ignore"}, default "raise"
        - raise: an exception will be raised if an input GeoJSON is invalid.
        - warn: a warning will be raised and invalid input geometries will be
          returned as ``None``.
        - ignore: invalid input geometries will be returned as ``None`` without
          a warning.
    **kwargs
        See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.

    See Also
    --------
    get_parts

    Examples
    --------
    >>> import shapely
    >>> shapely.from_geojson('{"type": "Point","coordinates": [1, 2]}')
    <POINT (1 2)>

    """
    # GEOS Tickets:
    # - support 3D: https://trac.osgeo.org/geos/ticket/1141
    # - handle null coordinates: https://trac.osgeo.org/geos/ticket/1142
    if not np.isscalar(on_invalid):
        raise TypeError("on_invalid only accepts scalar values")

    invalid_handler = np.uint8(DecodingErrorOptions.get_value(on_invalid))

    # ensure the input has object dtype, to avoid numpy inferring it as a
    # fixed-length string dtype (which removes trailing null bytes upon access
    # of array elements)
    geometry = np.asarray(geometry, dtype=object)

    return lib.from_geojson(geometry, invalid_handler, **kwargs)