diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f4415f45..947fe9c5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ https://semver.org/spec/v2.0.0.html ### Fixed - Fix broken array slicing inside `addcyclic` (PR [#559], solves issue [#555], thanks to @fragkoul). +- Fix `GeosLibrary` wrapper to also work with GEOS >= 3.7.0 on Windows + and GNU/Linux. +- Fix wrong Antarctica coastline boundary with GEOS >= 3.9.0 (PR [#560], + solves issue [#522]). ## [1.3.4] - 2022-08-10 @@ -930,6 +934,8 @@ https://semver.org/spec/v2.0.0.html - Fix glitches in drawing of parallels and meridians. +[#560]: +https://github.com/matplotlib/basemap/pull/560 [#559]: https://github.com/matplotlib/basemap/pull/559 [#555]: @@ -966,6 +972,8 @@ https://github.com/matplotlib/basemap/issues/527 https://github.com/matplotlib/basemap/issues/526 [#525]: https://github.com/matplotlib/basemap/issues/525 +[#522]: +https://github.com/matplotlib/basemap/issues/522 [#521]: https://github.com/matplotlib/basemap/issues/521 [#518]: diff --git a/packages/basemap/src/mpl_toolkits/basemap/__init__.py b/packages/basemap/src/mpl_toolkits/basemap/__init__.py index 653813f34..e89bd9504 100644 --- a/packages/basemap/src/mpl_toolkits/basemap/__init__.py +++ b/packages/basemap/src/mpl_toolkits/basemap/__init__.py @@ -1336,7 +1336,7 @@ def _readboundarydata(self,name,as_polygons=False): b2 = b.copy() # fix Antartica. if name == 'gshhs' and south < -89: - b = b[4:,:] + b = b[3:,:] b2 = b.copy() poly = Shape(b) # if map boundary polygon is a valid one in lat/lon diff --git a/packages/basemap/utils/GeosLibrary.py b/packages/basemap/utils/GeosLibrary.py index c7e9460e0..84eff4e51 100644 --- a/packages/basemap/utils/GeosLibrary.py +++ b/packages/basemap/utils/GeosLibrary.py @@ -20,6 +20,7 @@ import io import os +import sys import ssl import glob import shutil @@ -126,8 +127,7 @@ def extract(self, overwrite=True): if os.path.exists(zipfold): if not overwrite: raise OSError("folder '{0}' already exists".format(zipfold)) - else: - shutil.rmtree(zipfold) + shutil.rmtree(zipfold) # Decompress zip file. with contextlib.closing(ZipFile(zippath, "r")) as fd: @@ -137,16 +137,6 @@ def extract(self, overwrite=True): for path in sorted(glob.glob(os.path.join(zipfold, "tools", "*.sh"))): os.chmod(path, 0o755) - # Patch CMakeLists so that libgeos_c.so does not depend on libgeos.so. - cmakefile = os.path.join(zipfold, "capi", "CMakeLists.txt") - with io.open(cmakefile, "r", encoding="utf-8") as fd: - lines = fd.readlines() - with io.open(cmakefile, "wb") as fd: - oldtext = "target_link_libraries(geos_c geos)" - newtext = "target_link_libraries(geos_c geos-static)" - for line in lines: - fd.write(line.replace(oldtext, newtext).encode()) - # Apply specific patches for GEOS < 3.6.0. if self.version_tuple < (3, 6, 0): # The SVN revision file is not created on the fly before 3.6.0. @@ -166,66 +156,121 @@ def extract(self, overwrite=True): for line in lines: fd.write(line.replace(oldtext, newtext).encode()) + # Apply specific patches for 3.6.0 <= GEOS < 3.7.0 on Windows. + if (3, 6, 0) <= self.version_tuple < (3, 7, 0) and os.name == "nt": + autogen_file = os.path.join(zipfold, "autogen.bat") + subprocess.call([autogen_file], cwd=zipfold) + cppfile = os.path.join(zipfold, "src", "geomgraph", "DirectedEdgeStar.cpp") + with io.open(cppfile, "r", encoding="utf-8") as fd: + lines = fd.readlines() + with io.open(cppfile, "wb") as fd: + oldtext = "DirectedEdgeStar::print() const" + newtext = oldtext.replace(" const", "") + for line in lines: + fd.write(line.replace(oldtext, newtext).encode()) + hfile = os.path.join(zipfold, "include", "geos", "geomgraph", "DirectedEdgeStar.h") + with io.open(hfile, "r", encoding="utf-8") as fd: + lines = fd.readlines() + with io.open(hfile, "wb") as fd: + oldtext = "virtual std::string print() const;" + newtext = oldtext.replace(" const", "") + for line in lines: + fd.write(line.replace(oldtext, newtext).encode()) + + # Patch CMakeLists to link shared geos_c with static geos. + if self.version_tuple < (3, 8, 0): + cmakefile = os.path.join(zipfold, "capi", "CMakeLists.txt") + oldtext = "target_link_libraries(geos_c geos)" + newtext = "target_link_libraries(geos_c geos-static)" + else: + cmakefile = os.path.join(zipfold, "CMakeLists.txt") + oldtext = 'add_library(geos "")' + newtext = 'add_library(geos STATIC "")' + with io.open(cmakefile, "r", encoding="utf-8") as fd: + lines = fd.readlines() + with io.open(cmakefile, "wb") as fd: + found_sharedline = False + shared_oldtext = "if(BUILD_SHARED_LIBS)" + shared_newtext = "if(FALSE)" + for line in lines: + if not found_sharedline and shared_oldtext in line: + line = line.replace(shared_oldtext, shared_newtext) + found_sharedline = True + fd.write(line.replace(oldtext, newtext).encode()) + + # Patch doc CMakeLists in GEOS 3.8.x series. + if (3, 8, 0) <= self.version_tuple < (3, 9, 0): + cmakefile = os.path.join(zipfold, "doc", "CMakeLists.txt") + oldtext1 = "target_include_directories(test_geos_unit\n" + newtext1 = "if(BUILD_TESTING)\n {0}".format(oldtext1) + oldtext2 = "$)\n" + newtext2 = "{0}endif()\n".format(oldtext2) + with io.open(cmakefile, "r", encoding="utf-8") as fd: + lines = fd.readlines() + with io.open(cmakefile, "wb") as fd: + for line in lines: + line = line.replace(oldtext1, newtext1) + line = line.replace(oldtext2, newtext2) + fd.write(line.encode()) + def build(self, installdir=None, njobs=1): """Build and install GEOS from source.""" # Download and extract zip file if not present. zipfold = os.path.join(self.root, "geos-{0}".format(self.version)) self.extract(overwrite=True) + version = self.version_tuple - # Define build directory. + # Define build and install directory. builddir = os.path.join(zipfold, "build") - - # Define installation directory. if installdir is None: installdir = os.path.expanduser("~/.local/share/libgeos") installdir = os.path.abspath(installdir) - # Define configure options. + # Define generic configure and build options. config_opts = [ - "-DCMAKE_INSTALL_PREFIX={0}".format(installdir), - "-DGEOS_ENABLE_TESTS=OFF", "-DCMAKE_BUILD_TYPE=Release", + "-DCMAKE_INSTALL_PREFIX={0}".format(installdir), + "-D{0}=OFF".format("GEOS_ENABLE_TESTS" if version < (3, 8, 0) + else "BUILD_TESTING") ] - if os.name == "nt" and self.version_tuple < (3, 6, 0): - config_opts = ["-G", "NMake Makefiles"] + config_opts - - # Define build options. - build_env = os.environ.copy() build_opts = [ "--config", "Release", "--target", "install", ] - if os.name != "nt": - build_env["MAKEFLAGS"] = "-j {0:d}".format(njobs) - elif self.version_tuple < (3, 6, 0): - win64 = (8 * struct.calcsize("P") == 64) - build_opts.extend([ - "--", - "WIN64={0}".format("YES" if win64 else "NO"), - "BUILD_BATCH={0}".format("YES" if njobs > 1 else "NO"), - ]) + build_env = os.environ.copy() + + # Define custom configure and build options. + if os.name == "nt": + config_opts += ["-DCMAKE_CXX_FLAGS='/wd4251 /wd4458 /wd4530'"] + if version >= (3, 6, 0) and sys.version_info[:2] >= (3, 3): + build_opts = ["-j", "{0:d}".format(njobs)] + build_opts + else: + win64 = (8 * struct.calcsize("P") == 64) + config_opts = ["-G", "NMake Makefiles"] + config_opts + build_opts.extend([ + "--", + "WIN64={0}".format("YES" if win64 else "NO"), + "BUILD_BATCH={0}".format("YES" if njobs > 1 else "NO"), + ]) + if sys.version_info[:2] < (3, 3): + build_opts += ["MSVC_VER=1500"] else: - build_opts = ["-j", "{0:d}".format(njobs)] + build_opts + build_env["MAKEFLAGS"] = "-j {0:d}".format(njobs) + if version >= (3, 7, 0): + config_opts += ["-DCMAKE_CXX_FLAGS='-fPIC'"] - # Now move to the GEOS source code folder and build with CMake. - cwd = os.getcwd() + # Call cmake configure after ensuring that the build directory exists. try: - # Ensure that the build directory exists. - try: - os.makedirs(builddir) - except OSError: - pass - os.chdir(builddir) - # Call cmake configure. - subprocess.call(["cmake", ".."] + config_opts) - # Ensure that the install directory exists. - try: - os.makedirs(installdir) - except OSError: - pass - # Call cmake build and install. - subprocess.call(["cmake", "--build", "."] + build_opts, - env=build_env) - finally: - os.chdir(cwd) + os.makedirs(builddir) + except OSError: + pass + subprocess.call(["cmake", ".."] + config_opts, cwd=builddir) + + # Call cmake build after ensuring that the install directory exists. + try: + os.makedirs(installdir) + except OSError: + pass + subprocess.call(["cmake", "--build", "."] + build_opts, + cwd=builddir, env=build_env)