Source code for sedona.spark.utils.geometry_serde

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

import os
import sys
from typing import Optional
from warnings import warn

import shapely
from shapely.geometry.base import BaseGeometry

speedup_enabled = False


# Use geomserde_speedup when available, otherwise fallback to general pure
# python implementation.
try:
    from . import geomserde_speedup

[docs] def find_geos_c_dll(): packages_dir = os.path.dirname(os.path.dirname(shapely.__file__)) for lib_dirname in ["shapely.libs", "Shapely.libs"]: lib_dirpath = os.path.join(packages_dir, lib_dirname) if not os.path.exists(lib_dirpath): continue for filename in os.listdir(lib_dirpath): if filename.lower().startswith("geos_c") and filename.lower().endswith( ".dll" ): return os.path.join(lib_dirpath, filename) raise RuntimeError(f"geos_c DLL not found in {packages_dir}\\[S|s]hapely.libs")
if shapely.__version__.startswith("2."): if sys.platform != "win32": # We load geos_c library indirectly by loading shapely.lib import shapely.lib geomserde_speedup.load_libgeos_c(shapely.lib.__file__) else: # Find geos_c library and load it geos_c_dllpath = find_geos_c_dll() geomserde_speedup.load_libgeos_c(geos_c_dllpath) from .geomserde_speedup import serialize def deserialize(buf: bytearray) -> Optional[BaseGeometry]: if buf is None: return None return geomserde_speedup.deserialize(buf) speedup_enabled = True elif shapely.__version__.startswith("1."): # Shapely 1.x uses ctypes.CDLL to load geos_c library. We can obtain the # handle of geos_c library from `shapely.geos._lgeos._handle` import shapely.geometry.base import shapely.geos from shapely.geometry import ( GeometryCollection, LinearRing, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon, ) lgeos_handle = shapely.geos._lgeos._handle geomserde_speedup.load_libgeos_c(lgeos_handle) GEOMETRY_CLASSES = [ Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection, ] def serialize(geom: BaseGeometry) -> Optional[bytearray]: if geom is None: return None return geomserde_speedup.serialize_1(geom._geom)
[docs] def deserialize(buf: bytearray) -> Optional[BaseGeometry]: if buf is None: return None g, geom_type_id, has_z, bytes_read = geomserde_speedup.deserialize_1(buf) # The following code is mostly taken from the geom_factory function # in shapely/geometry/base.py, with a few tweaks to eliminate # invocations to GEOS functions. We've also replaced direct # attribute reference with __dict__['attr'] to get rid of the extra # cost of __setattr__ in shapely 1.8. if not g: raise ValueError("No Shapely geometry can be created from null value") ob = BaseGeometry() geom_type = shapely.geometry.base.GEOMETRY_TYPES[geom_type_id] ob.__class__ = GEOMETRY_CLASSES[geom_type_id] ob.__dict__["__geom__"] = g ob.__dict__["__p__"] = None if has_z != 0: ob.__dict__["_ndim"] = 3 else: ob.__dict__["_ndim"] = 2 ob.__dict__["_is_empty"] = False return ob, bytes_read
speedup_enabled = True else: # fallback to our general pure python implementation from .geometry_serde_general import deserialize, serialize except Exception as e: warn( f"Cannot load geomserde_speedup, fallback to general python implementation. Reason: {e}" ) from .geometry_serde_general import deserialize, serialize