Skip to content

Commit

Permalink
Fix: stamen basemap not working (#2451)
Browse files Browse the repository at this point in the history
  • Loading branch information
lixun910 authored Aug 17, 2023
1 parent 8095b6d commit 32cbeaf
Show file tree
Hide file tree
Showing 15 changed files with 240 additions and 179 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ BuildTools/macosx/build/
BuildTools/macosx/GeoDa.xcodeproj/
BuildTools/macosx/GeoDa.xcodeproj/xcuserdata/
BuildTools/macosx/GeoDa-leopard.xcodeproj/
BuildTools/reactgeoda
BuildTools/node_modules

build/

*.dmg
*.mode1v3
Expand Down
6 changes: 3 additions & 3 deletions BuildTools/macosx/GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ build-geoda-mac:
cp /usr/local/opt/gdal/share/gdal/* build/GeoDa.app/Contents/Resources/gdaldata
cp libraries/lib/libwx_osx_cocoau-3.1.4.0.0.dylib build/GeoDa.app/Contents/Frameworks/libwx_osx_cocoau-3.1.dylib
cp libraries/lib/libwx_osx_cocoau_gl-3.1.4.0.0.dylib build/GeoDa.app/Contents/Frameworks/libwx_osx_cocoau_gl-3.1.dylib
cp /usr/local/opt/gdal/lib/libgdal.32.dylib build/GeoDa.app/Contents/Frameworks
cp /usr/local/opt/gdal/lib/libgdal.33.dylib build/GeoDa.app/Contents/Frameworks
install_name_tool -id "GeoDa" build/GeoDa.app/Contents/MacOS/GeoDa
install_name_tool -change "$(GEODA_HOME)/libraries/lib/libwx_osx_cocoau_gl-3.1.dylib" "@executable_path/../Frameworks/libwx_osx_cocoau_gl-3.1.dylib" build/GeoDa.app/Contents/MacOS/GeoDa
install_name_tool -change "$(GEODA_HOME)/libraries/lib/libwx_osx_cocoau-3.1.dylib" "@executable_path/../Frameworks/libwx_osx_cocoau-3.1.dylib" build/GeoDa.app/Contents/MacOS/GeoDa
install_name_tool -change "/usr/local/opt/gdal/lib/libgdal.32.dylib" "@executable_path/../Frameworks/libgdal.32.dylib" build/GeoDa.app/Contents/MacOS/GeoDa
install_name_tool -change "/opt/homebrew/opt/gdal/lib/libgdal.32.dylib" "@executable_path/../Frameworks/libgdal.32.dylib" build/GeoDa.app/Contents/MacOS/GeoDa
install_name_tool -change "/usr/local/opt/gdal/lib/libgdal.33.dylib" "@executable_path/../Frameworks/libgdal.33.dylib" build/GeoDa.app/Contents/MacOS/GeoDa
install_name_tool -change "/opt/homebrew/opt/gdal/lib/libgdal.33.dylib" "@executable_path/../Frameworks/libgdal.33.dylib" build/GeoDa.app/Contents/MacOS/GeoDa
python3 install_name.py $(GEODA_HOME)/build/GeoDa.app/Contents/Frameworks "Developer ID Application: Geodapress LLC (26M5NG43GP)"
install_name_tool -change "@executable_path/../Frameworks/libwx_osx_cocoau-3.1.4.0.0.dylib" "@executable_path/../Frameworks/libwx_osx_cocoau-3.1.dylib" build/GeoDa.app/Contents/Frameworks/libwx_osx_cocoau_gl-3.1.dylib
codesign -f --timestamp -o runtime -s "Developer ID Application: Geodapress LLC (26M5NG43GP)" build/GeoDa.app/Contents/Frameworks/libwx_osx_cocoau_gl-3.1.dylib
Expand Down
4 changes: 4 additions & 0 deletions BuildTools/macosx/code_sign.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ def ProcessDependency(dylib_path, cid):
m = re.search('@rpath/(libaws.*)', dylib_path)
if m:
dylib_path = '/usr/local/opt/aws-sdk-cpp/lib/' + m.group(1)

m = re.search('@loader_path/../../../../(opt*)', dylib_path)
if m:
dylib_path = '/usr/local/' + m.group(1)


print("Process:", dylib_path)
Expand Down
92 changes: 65 additions & 27 deletions BuildTools/macosx/install_name.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,44 @@
'''
Update the install name of dependent libraries of libgdal and libwx
Code sign each dependent library
'''
import subprocess
import os, sys, re
import os
import sys
import re
from pathlib import Path
from shutil import copyfile

framework_path = sys.argv[1] #e.g. '/Users/xun/Github/geoda/BuildTools/macosx/build/GeoDa.app/Contents/Frameworks'
id = sys.argv[2]
codesign_only = bool(sys.argv[3]) if len(sys.argv) > 3 else False
# e.g. '/Users/xun/Github/geoda/BuildTools/macosx/build/GeoDa.app/Contents/Frameworks'
FRAMEWORK_PATH = sys.argv[1]
CODESIGN_ID = sys.argv[2]
CODESIGN_ONLY = bool(sys.argv[3]) if len(sys.argv) > 3 else False

print(id, codesign_only)
print(CODESIGN_ID, CODESIGN_ONLY)

def ProcessDependency(dir_path, dylib_name):
dylib_path = dir_path + '/' + dylib_name
dep_libs = subprocess.check_output(['otool', '-L', dylib_path]).decode('utf-8')
items = dep_libs.split('\n')[2:-1]
PROCESSED_DYLIBS = {}


def process_dependency(framework_path, dylib_name):
"""_Process each dependent library_
Args:
framework_path (_str_): _Framework path_
dylib_name (_str_): _dylib file name_
"""
if dylib_name in PROCESSED_DYLIBS:
print(f'{dylib_name} has been processed')
return
PROCESSED_DYLIBS[dylib_name] = True
dylib_path = framework_path + '/' + dylib_name
dep_libs = subprocess.check_output(
['otool', '-L', dylib_path]).decode('utf-8')
all_items = dep_libs.split('\n')
# e.g. '\t/opt/homebrew/opt/gdal/lib/libgdal.33.dylib (compatibility version 33.0.0, current version 33.3.7)'
current_item = all_items[1].strip().split(" ")[0]
items = all_items[2:-1]
for item in items:
# e.g. '@loader_path/../../../../opt/libarchive/lib/libarchive.13.dylib (compatibility version 20.0.0, current version 20.2.0)'
item = item.strip().split(" ")[0]

# workaround for gdal 3.3.3 that @rpath/libgeos.3.10.2.dylib was used instead of dir path
Expand Down Expand Up @@ -62,33 +88,45 @@ def ProcessDependency(dir_path, dylib_name):
if item == '@rpath/libabsl_base.2301.0.0.dylib':
copyitem = '/usr/local/opt/abseil/lib/libabsl_base.2301.0.0.dylib'

m = re.search('@rpath/(libabsl.*)', item)
if m:
copyitem = '/usr/local/opt/abseil/lib/' + m.group(1)

m = re.search('@rpath/(libaws.*)', item)
if m:
copyitem = '/usr/local/opt/aws-sdk-cpp/lib/' + m.group(1)
name_matches = re.search('@rpath/(libabsl.*)', item)
if name_matches:
copyitem = '/usr/local/opt/abseil/lib/' + name_matches.group(1)

name_matches = re.search('@rpath/(libaws.*)', item)
if name_matches:
copyitem = '/usr/local/opt/aws-sdk-cpp/lib/' + \
name_matches.group(1)

if item.startswith('@loader_path'):
item_filename = os.path.basename(item)
upper_levels = item.count('../')
copy_dir = str(Path(current_item).parent)
if upper_levels - 1 >= 0:
current_dir = Path(current_item).parents[upper_levels - 1]
copy_dir = str(current_dir)
item_filename = item[item.rindex('../') + 3:]
copyitem = f'{copy_dir}/{item_filename}'

if item.startswith('/usr/lib') == False and item.startswith('/System') == False and (codesign_only or item.startswith('@executable_path/')==False):
if not item.startswith('/usr/lib') and not item.startswith('/System') \
and not (CODESIGN_ONLY or item.startswith('@executable_path/')):
print("Process:", item)
file_name = os.path.basename(item)
# Copy the dylib to Frameworks if needed
dest = dir_path + '/' + file_name
if os.path.exists(dest) == False and not codesign_only:
dest = framework_path + '/' + file_name
if not os.path.exists(dest) and not CODESIGN_ONLY:
copyfile(copyitem, dest, follow_symlinks=True)
# install_name_tool current item
new_path = "@executable_path/../Frameworks/{}".format(file_name)
cmd = "install_name_tool -change \"{}\" \"{}\" {}".format(item, new_path, dylib_path)
if not codesign_only:
new_path = f"@executable_path/../Frameworks/{file_name}"
cmd = f'install_name_tool -change "{item}" "{new_path}" {dylib_path}'
if not CODESIGN_ONLY:
os.system(cmd)
# process item
ProcessDependency(dir_path, file_name)
process_dependency(framework_path, file_name)
print("codesign {}", dylib_path)
cmd = 'codesign --force --timestamp -o runtime -s "{}" {}'.format(id, dylib_path)
cmd = f'codesign --force --timestamp -o runtime -s "{CODESIGN_ID}" {dylib_path}'
os.system(cmd)


ProcessDependency(framework_path, "libwx_osx_cocoau_gl-3.1.dylib")
ProcessDependency(framework_path, "libwx_osx_cocoau-3.1.dylib")
ProcessDependency(framework_path, "libgdal.32.dylib")
process_dependency(FRAMEWORK_PATH, "libwx_osx_cocoau_gl-3.1.dylib")
process_dependency(FRAMEWORK_PATH, "libwx_osx_cocoau-3.1.dylib")
process_dependency(FRAMEWORK_PATH, "libgdal.33.dylib")
26 changes: 21 additions & 5 deletions Explore/Basemap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
#include <ogr_spatialref.h>

#include <curl/curl.h>
#include "../GdaConst.h"
#include "../GeneralWxUtils.h"
#include "../ShapeOperations/OGRDataAdapter.h"
#include "Basemap.h"

Expand Down Expand Up @@ -156,8 +158,6 @@ XYFraction::XYFraction(double _x, double _y)
yfrac = modf(_y, &yint);
}

const char *Basemap::USER_AGENT = "GeoDa 1.14 contact [email protected]";

Basemap::Basemap(BasemapItem& _basemap_item,
Screen* _screen,
MapLayer* _map,
Expand Down Expand Up @@ -612,6 +612,21 @@ size_t curlCallback(void *ptr, size_t size, size_t nmemb, void* userdata)
return written;
}

wxString Basemap::GetUserAgent(const wxString& url)
{
if (url.Find("openstreetmap") != wxNOT_FOUND) {
return GdaConst::gda_basemap_osm_useragent;
}
if (GeneralWxUtils::isWindows()) {
return GdaConst::gda_basemap_win_useragent;
} else if (GeneralWxUtils::isMac()) {
return GdaConst::gda_basemap_mac_useragent;
} else {
return GdaConst::gda_basemap_linux_useragent;
}

}

wxString Basemap::GetContentType()
{
wxString url = GetTileUrl(16, 11); // guerry
Expand All @@ -621,7 +636,8 @@ wxString Basemap::GetContentType()
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.ToUTF8().data());
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
curl_easy_setopt(curl, CURLOPT_USERAGENT, Basemap::USER_AGENT);
curl_easy_setopt(curl, CURLOPT_USERAGENT, GetUserAgent(url).ToUTF8().data());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1L);
Expand Down Expand Up @@ -670,10 +686,10 @@ void Basemap::DownloadTile(int x, int y)
if (fp) {
curl_easy_setopt(image, CURLOPT_URL, url.ToUTF8().data());
curl_easy_setopt(image, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
curl_easy_setopt(image, CURLOPT_USERAGENT, Basemap::USER_AGENT);
curl_easy_setopt(image, CURLOPT_USERAGENT, GetUserAgent(url).ToUTF8().data());
curl_easy_setopt(image, CURLOPT_WRITEFUNCTION, curlCallback);
curl_easy_setopt(image, CURLOPT_WRITEDATA, fp);
//curl_easy_setopt(image, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(image, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(image, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(image, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(image, CURLOPT_CONNECTTIMEOUT, 1L);
Expand Down
26 changes: 13 additions & 13 deletions Explore/Basemap.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,11 @@ namespace Gda {
east = _e;
south = _s;
}
OGRSpatialReference* s1 = poCT->GetTargetCS();
OGRSpatialReference* s2 = poCT->GetSourceCS();
const OGRSpatialReference* s1 = poCT->GetTargetCS();
const OGRSpatialReference* s2 = poCT->GetSourceCS();
#ifdef __PROJ6__
s1->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
s2->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
const_cast<OGRSpatialReference*>(s1)->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
const_cast<OGRSpatialReference*>(s2)->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
#endif
poCT_rev = OGRCreateCoordinateTransformation(s1, s2);
}
Expand Down Expand Up @@ -327,20 +327,20 @@ namespace Gda {
poCT_rev = NULL;
if (other) {
if (other->poCT) {
OGRSpatialReference* s1 = other->poCT->GetSourceCS();
OGRSpatialReference* s2 = other->poCT->GetTargetCS();
const OGRSpatialReference* s1 = other->poCT->GetSourceCS();
const OGRSpatialReference* s2 = other->poCT->GetTargetCS();
#ifdef __PROJ6__
s1->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
s2->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
const_cast<OGRSpatialReference*>(s1)->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
const_cast<OGRSpatialReference*>(s2)->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
#endif
poCT = OGRCreateCoordinateTransformation(s1, s2);
}
if (other->poCT_rev) {
OGRSpatialReference* s1 = other->poCT_rev->GetSourceCS();
OGRSpatialReference* s2 = other->poCT_rev->GetTargetCS();
const OGRSpatialReference* s1 = other->poCT_rev->GetSourceCS();
const OGRSpatialReference* s2 = other->poCT_rev->GetTargetCS();
#ifdef __PROJ6__
s1->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
s2->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
const_cast<OGRSpatialReference*>(s1)->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
const_cast<OGRSpatialReference*>(s2)->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
#endif
poCT_rev = OGRCreateCoordinateTransformation(s1, s2);
}
Expand Down Expand Up @@ -377,7 +377,6 @@ namespace Gda {
double scale_factor = 1.0);
~Basemap();

static const char* USER_AGENT;
OGRCoordinateTransformation *poCT;
BasemapItem basemap_item;
wxString basemapName;
Expand Down Expand Up @@ -439,6 +438,7 @@ namespace Gda {

void CleanCache();
wxString GetContentType();
wxString GetUserAgent(const wxString& url);
};

}
Expand Down
4 changes: 4 additions & 0 deletions GdaConst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,10 @@ wxString GdaConst::gda_basemap_sources =
"\nOther (China).GaoDe,http://webst{s}.is.autonavi.com/appmaptile?style=8&x={x}&y={y}&z={z}"
"\nOther (China).GaoDe(Satellite),http://webst{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}"
;
const wxString GdaConst::gda_basemap_osm_useragent = "GeoDa 1.14 contact [email protected]";
const wxString GdaConst::gda_basemap_win_useragent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36";
const wxString GdaConst::gda_basemap_mac_useragent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36";
const wxString GdaConst::gda_basemap_linux_useragent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36";

const wxString GdaConst::gda_lbl_not_sig = _("Not Significant");
const wxString GdaConst::gda_lbl_undefined = _("Undefined");
Expand Down
6 changes: 6 additions & 0 deletions GdaConst.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,12 @@ class GdaConst {
static const int ShpHeaderSize = 50; // size of the header record in Shapefile
static const int ShpObjIdLen = 20; // length of the ID of shape object

// Basemap
static const wxString gda_basemap_osm_useragent;
static const wxString gda_basemap_win_useragent;
static const wxString gda_basemap_mac_useragent;
static const wxString gda_basemap_linux_useragent;

static wxCursor zoomInCursor;
static wxCursor zoomOutCursor;

Expand Down
7 changes: 2 additions & 5 deletions Project.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,6 @@ rtree_box_2d_t& Project::GetBBoxRtree()
void Project::CalcEucPlaneRtreeStats()
{
wxLogMessage("Project::CalcEucPlaneRtreeStats()");
using namespace std;

GetCentroids();
size_t num_obs = centroids.size();
Expand All @@ -451,7 +450,6 @@ void Project::CalcEucPlaneRtreeStats()
void Project::CalcUnitSphereRtreeStats()
{
wxLogMessage("Project::CalcUnitSphereRtreeStats()");
using namespace std;
GetCentroids();
size_t num_obs = centroids.size();
std::vector<pt_lonlat> pts_ll(num_obs);
Expand Down Expand Up @@ -992,10 +990,9 @@ CovSpHLStateProxy* Project::GetPairsHLState()

TableBase* Project::FindTableBase()
{
using namespace std;
if (frames_manager == NULL) return NULL;
list<FramesManagerObserver*> observers(frames_manager->getCopyObservers());
list<FramesManagerObserver*>::iterator it;
std::list<FramesManagerObserver*> observers(frames_manager->getCopyObservers());
std::list<FramesManagerObserver*>::iterator it;
for (it=observers.begin(); it != observers.end(); ++it) {
if (TableFrame* w = dynamic_cast<TableFrame*>(*it)) {
return w->GetTableBase();
Expand Down
Loading

0 comments on commit 32cbeaf

Please sign in to comment.