Skip to content

Commit

Permalink
v1.7.2 Added OpenStreetMap plotting
Browse files Browse the repository at this point in the history
  • Loading branch information
e5k committed May 4, 2022
1 parent d226669 commit 206c8a1
Show file tree
Hide file tree
Showing 14 changed files with 281 additions and 17 deletions.
Binary file modified CODE/VAR/prefs.mat
Binary file not shown.
Binary file modified CODE/VAR/tephraProb.mat
Binary file not shown.
4 changes: 3 additions & 1 deletion CODE/conf_grid.m
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,9 @@ function display_map(lat, lon)
set(h1, 'FaceAlpha', .3);
hold on;
%plot(lon, lat, 'xr')
plot_google_map('maptype', 'terrain', 'MapScale', 1);
% plot_google_map('maptype', 'terrain', 'MapScale', 1);
plot_openstreetmap('scale', 2);
uistack(h1,'top')
xlabel('Longitude');
ylabel('Latitude');
axis equal
Expand Down
208 changes: 208 additions & 0 deletions CODE/dependencies/plot_openstreetmap.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
function hgrp = plot_openstreetmap(varargin)
% PLOT_OPENSTREETMAP Plots OpenStreetMap on the background of a figure.
% h = PLOT_OPENSTREETMAP(Property, Value,...)
%
% Properties:
%
% 'Alpha' Transparency level of the map (0 is fully transparent, 1
% is opaque). Default: 1.
% 'BaseUrl' URL for the tiles (Default:
% 'http://a.tile.openstreetmap.org'). More tile URLs:
% https://wiki.openstreetmap.org/wiki/Tiles#Servers
% 'Scale' Resolution scale factor (Default: 1). Using Scale=2 will
% double the resulotion of the map image and will result in
% finer rendering.
% 'MaxZoomLevel' Maximum tile zoom level (Default: 16). This sets the
% maximum zoom level that will be requested from the tile
% server. Note that not all tile servers will support
% high zoom levels.
%
% EXAMPLE
%
% x = [11.6639 11.7078 11.7754 11.8063 11.8797];
% y = [57.6078 57.6473 57.6607 57.6804 57.6886];
% figure('Color', 'w'); plot(x, y, 'o-', 'LineWidth', 2);
% hBase = plot_openstreetmap('Alpha', 0.4, 'Scale', 2)
% hSea = plot_openstreetmap('Alpha', 0.5, 'Scale', 2, 'BaseUrl', "http://tiles.openseamap.org/seamark")
% title('Map data from OpenStreetMap and OpenSeaMap');
%

p = inputParser;
validScalar0to1 = @(x) isnumeric(x) && isscalar(x) && (x >= 0) && (x <=1);
validScalarPos = @(x) isnumeric(x) && isscalar(x);
validMaxZoomLevel = @(x) isnumeric(x) && isscalar(x) && (x >= 0);
addParameter(p, 'BaseUrl','http://a.tile.openstreetmap.org', @isstring);
addParameter(p, 'Alpha', 1, validScalar0to1);
addParameter(p, 'Scale', 1, validScalarPos);
addParameter(p, 'MaxZoomLevel', 16, validMaxZoomLevel);
parse(p,varargin{:});

ax = gca();
curAxis = axis(ax);
verbose = false;
baseurl = p.Results.BaseUrl;
alpha = p.Results.Alpha;
scale = p.Results.Scale;
maxZoomLevel = p.Results.MaxZoomLevel;

%% Convertion from lat lon to tile x and y, and back.
% See: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
% Example tile x=272, y=154: https://a.tile.openstreetmap.org/9/272/154.png

lon2x = @(lon, zoomlevel) floor((lon + 180) / 360 * 2 .^ zoomlevel);
lat2y = @(lat, zoomlevel) floor((1 - log(tan(deg2rad(lat)) + (1 ./ cos(deg2rad(lat)))) / pi) / 2 .* 2 .^ zoomlevel);
x2lon = @(x, zoomlevel) x ./ 2.^zoomlevel * 360 - 180;
y2lat = @(y, zoomlevel) atan(sinh(pi * (1 - 2 * y ./ (2.^zoomlevel)))) * 180 / pi;


%%
oldHold = ishold();
hold on;

%% Adjust aspect ratio.
adjust_axis(ax, curAxis);
ax.PlotBoxAspectRatioMode = 'manual';

%% Compute zoom level.
[width, height] = ax_width_pixels(ax);
width = width * scale;
height = height * scale;
zoomlevel = get_zoomlevel(curAxis, width, height, maxZoomLevel);

%% Memoize downloaded tiles, to save bandwidth.
memoizedImread = memoize(@imread);
memoizedImread.CacheSize = 200;

%% Get tiles and display them.
minmaxX = lon2x(curAxis(1:2), zoomlevel);
minmaxY = lat2y(curAxis(3:4), zoomlevel);

hgrp = hggroup;

for x = min(minmaxX):max(minmaxX)
for y = min(minmaxY):max(minmaxY)

url = sprintf("%s/%d/%d/%d.png", baseurl, zoomlevel, x, y);
if verbose
disp(url)
end

[indices, cmap, imAlpha] = memoizedImread(url);

% Some files, t.ex. from openseamap with transparency, come without
% colormap. They have three dimensions in indices already.
if size(indices, 3) > 1
imagedata = indices;
else
imagedata = ind2rgb(indices, cmap);
end

if numel(imAlpha) == 0
imAlpha = 1;
end

im = image(ax, ...
x2lon([x, x+1], zoomlevel), ...
y2lat([y, y+1], zoomlevel), ...
imagedata, ...
'AlphaData', alpha*imAlpha...
);
set(im,'tag','osm_map_tile')
set(im,'Parent',hgrp)
uistack(im, 'bottom') % move map to bottom (so it doesn't hide previously drawn annotations)
end
end
set(hgrp,'tag','osm_map')


%%

function [width, height] = ax_width_pixels(axHandle)
orig_units = get(axHandle,'Units');
set(axHandle,'Units','Pixels')
ax_position = get(axHandle,'position');
set(axHandle,'Units',orig_units)
width = ax_position(3);
height = ax_position(4);
end

function adjust_axis(axHandle, curAxis)
% adjust current axis limit to avoid strectched maps
[xExtent,yExtent] = latLonToMeters(curAxis(3:4), curAxis(1:2) );
xExtent = diff(xExtent); % just the size of the span
yExtent = diff(yExtent);
% get axes aspect ratio
drawnow
orig_units = get(axHandle,'Units');
set(axHandle,'Units','Pixels')
ax_position = get(axHandle,'position');
set(axHandle,'Units',orig_units)
aspect_ratio = ax_position(4) / ax_position(3);

if xExtent*aspect_ratio > yExtent
centerX = mean(curAxis(1:2));
centerY = mean(curAxis(3:4));
spanX = (curAxis(2)-curAxis(1))/2;
spanY = (curAxis(4)-curAxis(3))/2;

% enlarge the Y extent
spanY = spanY*xExtent*aspect_ratio/yExtent; % new span
if spanY > 85
spanX = spanX * 85 / spanY;
spanY = spanY * 85 / spanY;
end
curAxis(1) = centerX-spanX;
curAxis(2) = centerX+spanX;
curAxis(3) = centerY-spanY;
curAxis(4) = centerY+spanY;
elseif yExtent > xExtent*aspect_ratio

centerX = mean(curAxis(1:2));
centerY = mean(curAxis(3:4));
spanX = (curAxis(2)-curAxis(1))/2;
spanY = (curAxis(4)-curAxis(3))/2;
% enlarge the X extent
spanX = spanX*yExtent/(xExtent*aspect_ratio); % new span
if spanX > 180
spanY = spanY * 180 / spanX;
spanX = spanX * 180 / spanX;
end

curAxis(1) = centerX-spanX;
curAxis(2) = centerX+spanX;
curAxis(3) = centerY-spanY;
curAxis(4) = centerY+spanY;
end
% Enforce Latitude constraints of EPSG:900913
if curAxis(3) < -85
curAxis(3:4) = curAxis(3:4) + (-85 - curAxis(3));
end
if curAxis(4) > 85
curAxis(3:4) = curAxis(3:4) + (85 - curAxis(4));
end
axis(axHandle, curAxis); % update axis as quickly as possible, before downloading new image
drawnow
end

function zoomlevel = get_zoomlevel(curAxis, width, height, maxZoomLevel)
[xExtent,yExtent] = latLonToMeters(curAxis(3:4), curAxis(1:2) );
minResX = diff(xExtent) / width;
minResY = diff(yExtent) / height;
minRes = max([minResX minResY]);
tileSize = 256;
initialResolution = 2 * pi * 6378137 / tileSize; % 156543.03392804062 for tileSize 256 pixels
zoomlevel = floor(log2(initialResolution/minRes));

% Enforce valid zoom levels: 1 <= zoom <= maxZoomLevel (Default: 16)
zoomlevel = min(max(zoomlevel, 1), maxZoomLevel);
end

function [x,y] = latLonToMeters(lat, lon )
% Converts given lat/lon in WGS84 Datum to XY in Spherical Mercator EPSG:900913"
originShift = 2 * pi * 6378137 / 2.0; % 20037508.342789244
x = lon * originShift / 180;
y = log(tan((90 + lat) * pi / 360 )) / (pi / 180);
y = y * originShift / 180;
end

end
10 changes: 10 additions & 0 deletions CODE/dwind/analyze_wind.m
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@

load([FilePath, filesep, FileName]);

% Make sure time is as datevec
if size(stor_time, 2) == 1
stor_time = datevec(stor_time);
end

scr = get(0,'ScreenSize');
w = 650;
h = 600;
Expand Down Expand Up @@ -719,6 +724,11 @@ function CHG_DIR(hObject, ~)
% Typ 1 -> Years
% Typ 2 -> Months

% Make sure time is as datevec
if size(stor_time, 2) == 1
stor_time = datevec(stor_time)
end

sel_val = get(w2.subtime_table, 'Value');
sel_str = get(w2.subtime_table, 'String');
subset = str2double(sel_str(sel_val));
Expand Down
2 changes: 1 addition & 1 deletion CODE/dwind/dwind.m
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ function download(wind)

% Offline mode
elseif strcmp(wind.db, 'InterimOff') || strcmp(wind.db, 'ERA5Off')

copyfile(fullfile(wind.ncDir, '*.nc'), fullfile(wind.folder, 'nc'))
%% NOAA
else
% Work on input coordinates
Expand Down
2 changes: 1 addition & 1 deletion CODE/dwind/process_wind.m
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ function process_wind(varargin)
stor(i).HGT = ncread(fullfile(in_path, fl(i).name), 'z')/9.80665;
stor(i).UWND = ncread(fullfile(in_path, fl(i).name), 'u');
stor(i).VWND = ncread(fullfile(in_path, fl(i).name), 'v');
stor(i).time = double(ncread(fullfile(in_path, fl(i).name), 'time'))/24 + datenum(1900,1,1,0,0,0);
stor(i).time = double(ncread(fullfile(in_path, fl(i).name), 'time'))/24 + datenum(1900,1,1,0,0,0);
end

% Do some tests to see if the timestamp is correct
Expand Down
25 changes: 23 additions & 2 deletions CODE/get_prefs.m
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@
'ForegroundColor', [1 1 1],...
'BackgroundColor', [.25 .25 .25],...
'Tooltip', 'Choose the basemap',...
'String', {'None', 'Google Map'},...
'String', {'None', 'Google Map', 'OSM'},...
'Value', 2);

p.GE_export_txt = uicontrol(...
Expand Down Expand Up @@ -397,8 +397,28 @@
'BackgroundColor', [.25 .25 .25],...
'Value', 1,...
'Tooltip', 'Attempt to open Google Earth to display the results');

p.OSM_scale_txt = uicontrol(...
'parent', p.pan_map,...
'style', 'text',...
'units', 'normalized',...
'position', [.55 .66 .3 .05],...
'HorizontalAlignment', 'left',...
'BackgroundColor', [.25 .25 .25],...
'ForegroundColor', [1 1 1],...
'String', 'OSM scale:');


p.OSM_scale = uicontrol(...
'parent', p.pan_map,...
'style', 'popup',...
'unit', 'normalized',...
'position', [.75 .63 .22 .08],...
'ForegroundColor', [1 1 1],...
'BackgroundColor', [.25 .25 .25],...
'Tooltip', 'OSM scale',...
'String', {'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'},...
'Value', 4);

p.prb_title = uicontrol(...
'parent', p.pan_map,...
'style', 'text',...
Expand Down Expand Up @@ -623,6 +643,7 @@ function but_ok(~, ~, p)
prefs.maps.GE_show = p.GE_show.Value;

prefs.maps.basemap = p.basemap.Value;
prefs.maps.OSM_scale = p.OSM_scale.Value;

prefs.files.nbDigits = str2double(get(p.prob_digits, 'String'));

Expand Down
3 changes: 3 additions & 0 deletions CODE/plotMap.m
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ function plotMap(mapType)
% Plot basemap
if prefs.maps.basemap == 2
plot_google_map('maptype', 'terrain', 'MapScale', 1);
elseif prefs.maps.basemap == 3
a = plot_openstreetmap('scale', prefs.maps.OSM_scale);
uistack(a, 'bottom')
end

% Plot vent
Expand Down
30 changes: 19 additions & 11 deletions CODE/runProb.m
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,10 @@
mkdir(fullfile(out_pth, 'CONF', seas_str{seas}));
mkdir(fullfile(out_pth, 'GS', seas_str{seas}));
mkdir(fullfile(out_pth, 'LOG', seas_str{seas}));
% % Should probably move these out of the loop
% mkdir(fullfile(out_pth, 'FIG'));
% mkdir(fullfile(out_pth, 'KML'));
% % --------

mkdir(fullfile(out_pth, 'FIG/ESP', seas_str{seas}));
mkdir(fullfile(out_pth, 'FIG/MAPS', seas_str{seas}));
mkdir(fullfile(out_pth, 'SUM', seas_str{seas}));
%mkdir(fullfile(out_pth, 'CURVES', seas_str{seas}));
% if ~exist(fullfile(out_pth, 'PROB'), 'dir')
% mkdir(fullfile(out_pth, 'PROB'));
% end

% Get the wind vector for the season considered
if strcmp(seas_str{seas}, 'all')
Expand Down Expand Up @@ -261,7 +254,7 @@
% MER and mass calculation
for j = 1:nb_sim
wind_prof = load(fullfile(data.wind_pth, [num2str(wind_vec(j), '%05i'), '.gen'])); % Loads wind profile

% Get the closest value to tropopause (assumed 15 km asl over Iceland)
level = find(abs(wind_prof(:,1)-data.trop_height) == min(abs(wind_prof(:,1)-data.trop_height)));
if length(level) > 1
Expand All @@ -280,7 +273,7 @@

speed_tmp(j)= wind_prof(level,2); % Maximum wind speed at the tropopause
mer_tmp(j) = get_mer((ht_tmp(j) - data.vent_ht), speed_tmp(j)); % Calculate MER from the method of Degruyter and Bonadonna (2012)
dir_tmp(j) = median(wind_prof(level3:level2,3)); % Median wind direction below the plume
dir_tmp(j) = median(wind_prof(level3:level2,3)); % Median wind direction below the plume

% Here, either sample the mass or calculate it from MER
% and duration
Expand Down Expand Up @@ -558,6 +551,17 @@
function load_data(~, ~, ~)
prepare_data(1);

function choose_wind(~,~,f)
pth = uigetdir('WIND', 'Select the ascii/ wind folder containing the wind files');
id = strfind(pth, 'WIND/');
f.tab.Data{4,2} = pth(id:end);

function choose_grid(~,~,f)
[fl, pth] = uigetfile('GRID/*.utm', 'Select the .utm grid file');
id = strfind(pth, 'GRID/');
f.tab.Data{3,2} = [pth(id:end),fl];


% Get run number
function run_nb = get_run_nb(run_path)
l = dir(run_path);
Expand Down Expand Up @@ -593,7 +597,9 @@ function data_gui(tab_data)
% Menu
t.menu = uimenu(t.fig, 'Label', 'File');
t.m11 = uimenu(t.menu, 'Label', 'Load', 'Accelerator', 'O');

t.m12 = uimenu(t.menu, 'Label', 'Choose wind file');
t.m13 = uimenu(t.menu, 'Label', 'Choose grid file');

% Main panel
t.main = uipanel(...
'parent', t.fig,...
Expand Down Expand Up @@ -636,6 +642,8 @@ function data_gui(tab_data)
% Callback for ok button
set(t.ok, 'callback', {@test_param, t})
set(t.m11, 'callback', {@load_data, t})
set(t.m12, 'callback', {@choose_wind, t})
set(t.m13, 'callback', {@choose_grid, t})
uiwait(t.fig);

% Test input parameters
Expand Down
Binary file modified MODEL/forward_src/new_tephra.o
Binary file not shown.
Binary file modified MODEL/forward_src/tephra2_calc.o
Binary file not shown.
Loading

0 comments on commit 206c8a1

Please sign in to comment.