# 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