-
Notifications
You must be signed in to change notification settings - Fork 9
/
scarclick.m
488 lines (422 loc) · 14.1 KB
/
scarclick.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
function [htext] = scarclick(varargin)
% scarclick labels features on a map of Antarctica using mouse clicks.
% This function searches the Scienfitic Committee on Antarctic Research
% (SCAR) Composite Gazetteer database for feature names. Information
% for citing this dataset is provided below.
%
%% * * * SCARCLICK Operators * * *
%
% Mouse click Labels nearest point.
% Carriage return Terminates data entry.
% Backspace Deletes previous label.
% + Zooms in, centered on current cursor location.
% - Zooms out, centered on current cursor location.
%
%
%% Syntax
%
% scarclick
% scarclick('FeatureType')
% scarclick('keep')
% scarclick('TextProperty',TextValue)
% h = scarclick(...)
%
%% Description
%
% scarclick labels whichever features are closest to where you click on a
% map. Each click deletes the previous label and places a new one. When
% you're done clicking, hit return to exit scarclick.
%
% scarclick('FeatureType') limits labeled objects to a specific feature
% type. Note that not all features have a type associated with them,
% so if you select 'ice stream' as a feature type and click directly
% on Kamb Ice Stream, a label will appear on the closest identified ice
% stream, Nimrod Ice Stream. Using scarlabel('kamb ice stream') works
% fine, but only three features are officially identified as ice streams,
% despite many more ice streams having "ice stream" in their names.
%
% The following are the most common FeatureTypes:
% 'Anchorage'
% 'Archipelago'
% 'Bank'
% 'Basin'
% 'Bay'
% 'Beach'
% 'Bight'
% 'Bluff'
% 'Building'
% 'Butte'
% 'Buttress'
% 'Camp'
% 'Canyon'
% 'Cape'
% 'Channel'
% 'Cirque'
% 'Cliff'
% 'Coast'
% 'Cone'
% 'Corner'
% 'Cove'
% 'Crag'
% 'Crater'
% 'Crevasse'
% 'Dome'
% 'Escarpment'
% 'Fjord'
% 'Glacier'
% 'Gulf'
% 'Gully'
% 'Harbour'
% 'Head'
% 'Heights'
% 'Hill'
% 'Hillock'
% 'Ice field'
% 'Ice front'
% 'Ice rise'
% 'Ice shelf'
% 'Icefall'
% 'Inlet'
% 'Island'
% 'Knob'
% 'Knoll'
% 'Land'
% 'Massif'
% 'Mesa'
% 'Moraine'
% 'Mountain'
% 'Neve'
% 'Nunatak'
% 'Pass'
% 'Passage'
% 'Peak'
% 'Peninsula'
% 'Piedmont'
% 'Plain'
% 'Plateau'
% 'Platform'
% 'Point'
% 'Promontory'
% 'Range'
% 'Reef'
% 'Ridge'
% 'Rock'
% 'Saddle'
% 'Sea'
% 'Shoal'
% 'Slope'
% 'Snowfield'
% 'Sound'
% 'Spit'
% 'Spur'
% 'Stack'
% 'Station'
% 'Strait'
% 'Terrace'
% 'Tongue'
% 'Valley'
% 'Wall'
% 'Water body'
%
% scarclick('keep') does not automatically delete labels.
%
% scarclick('TextProperty',TextValue) formats text labels with
% property-value pairs. (e.g., 'fontsize',30,'color','b')
%
% h = scarclick(...) returns a handle h of text labels.
%
%% Examples:
%
% First, initialize a map of the grounding line. If you don't have
% the Bedmap2 Toolbox, you'll have to find some other way to make
% a map of Antarctica:
%
% bedmap2 gl
%
% Then type clickz and start clicking away:
%
% clickz % (Hit return when you get bored with clicking.)
%
% Don't automatically delete labels:
%
% clickz('keep')
%
% Combine commands if you'd like. Here we only label glaciers, using
% boldface red font, and don't automatically delete them. If you
% accidentally click on something you do not want labeled, hit backspace
% to remove the last label:
%
% clickz('glacier','keep','fontweight','bold','color','red')
%
%% Known Issues:
%
% 1. This function is awfully slow when you start clicking around on a
% large dataset. If you've plotted a modismoa image and overlain measures
% ice speeds, scarclick will probably respond slowly.
%
% 2. When specifying a feature type, it may be tempting to write the plural
% form of the feature. That would certainly be more intuitive, but for now,
% you'll have to specify 'glacier', not 'glaciers'. If you accidentally
% type a plural form, or the singular form of some feature that is not officially
% categorized by SCAR (i.e., 'Pizza Hut'), there will be no helpful error
% message. Sorry about that.
%
% 3. Not all features are associated with a FeatureType.
%
% 4. In some cases, the SCAR Composite Gazetteer contains multiple entries
% for the same feature, and sometimes the coordinates of the multiple
% entries do not match exactly. I have dealt with this issue by arbitrarily
% picking one entry for each unique feature name and deleting duplicates. I did the
% same kind of arbitrary culling for a previous release of Antarctic Mapping
% Tools, but I did not necessarily choose to keep the same entries in both
% cullings. As a result, if you have used a previous version of scarloc
% or scarlabel, it is possible that a few features may appear to have moved in
% this release.
%
%% Author Info
% This function was written by Chad A. Greene of the University of Texas at
% Austin's Institute for Geophysics (UTIG), January 2015. Drop me a line
% if you'd like. If you do a minimal amount of digging, you can find my contact
% info via http://www.chadagreene.com.
%
%% References
%
% This function was developed for Antarctic Mapping Tools for Matlab (AMT). If AMT is useful for you,
% please cite our paper:
%
% Greene, C. A., Gwyther, D. E., & Blankenship, D. D. Antarctic Mapping Tools for Matlab.
% Computers & Geosciences. 104 (2017) pp.151-157.
% http://dx.doi.org/10.1016/j.cageo.2016.08.003
%
% @article{amt,
% title={{Antarctic Mapping Tools for \textsc{Matlab}}},
% author={Greene, Chad A and Gwyther, David E and Blankenship, Donald D},
% journal={Computers \& Geosciences},
% year={2017},
% volume={104},
% pages={151--157},
% publisher={Elsevier},
% doi={10.1016/j.cageo.2016.08.003},
% url={http://www.sciencedirect.com/science/article/pii/S0098300416302163}
% }
%
% The SCAR database can be found here: http://www.scar.org/cga
% SCAR has kindly requested that Gazetteer data should be cited as:
%
% Secretariat SCAR (1992, updated 2015). Composite Gazetteer of Antarctica,
% Scientific Committee on Antarctic Research. GCMD Metadata
% http://gcmd.nasa.gov/records/SCAR_Gazetteer.html
%
% See also inputm, ginput, gdistm, clickz, scarlabel, and scarloc.
%% Error checks:
assert(license('test','map_toolbox') ==1,'It looks like you do not have the Mapping Toolbox. As such, this will not work.')
assert(ismap==1,'A map must be open to use scarclick.')
%% Load SCAR data
sn = load('scarnames.mat');
%% Set defaults:
keepPoints = false;
htext = [];
if nargin>0
% determine whether labels should be kept on the figure
tmp = strcmpi(varargin,'keep');
if any(tmp)
keepPoints = true;
varargin = varargin(~tmp);
end
% Is a feature type requested?
if ~isempty(varargin)
typeDeclared = strcmpi(varargin{1},sn.featureType);
if any(typeDeclared)
sn.x = sn.x(typeDeclared);
sn.y = sn.y(typeDeclared);
sn.names = sn.names(typeDeclared);
sn.lat = sn.lat(typeDeclared);
sn.lon = sn.lon(typeDeclared);
varargin(1) = [];
end
end
end
%% Begin work
fig = gcf;
axes_handle = gca;
how_many = -1; % This is a counter that is leftover from ginput. It never changes in the scarclick function.
InitialAxes = axis;
% Setup the figure to disable interactive modes and activate pointers.
initialState = setupFcn(fig);
% onCleanup object to restore everything to original state in event of
% completion, closing of figure errors or ctrl+c.
c = onCleanup(@() restoreFcn(initialState));
% We need to pump the event queue on unix
% before calling WAITFORBUTTONPRESS
drawnow
char = 0;
while how_many ~= 0
% Use no-side effect WAITFORBUTTONPRESS
waserr = 0;
try
keydown = wfbp;
catch %#ok<CTCH>
waserr = 1;
end
if(waserr == 1)
if(ishghandle(fig))
cleanup(c);
error(message('MATLAB:clickz:Interrupted'));
else
cleanup(c);
error(message('MATLAB:clickz:FigureDeletionPause'));
end
end
% g467403 - clickz failed to discern clicks/keypresses on the figure it was
% registered to operate on and any other open figures whose handle
% visibility were set to off
figchildren = allchild(0);
if ~isempty(figchildren)
ptr_fig = figchildren(1);
else
error(message('MATLAB:clickz:FigureUnavailable'));
end
% old code -> ptr_fig = get(0,'CurrentFigure'); Fails when the
% clicked figure has handlevisibility set to callback
if(ptr_fig == fig)
if keydown
char = get(fig, 'CurrentCharacter');
end
if ismember(char,[122 90 43 61]) % 122 and 90 are z and Z, 43 and 61 are + and =.
lim = axis; % get current axis limits
pti=get(axes_handle, 'CurrentPoint'); % get current cursor point
axis([pti(1,1)+diff(lim(1:2))/2*[-1 1] pti(1,2)+diff(lim(3:4))/2*[-1 1]]); % reset axis limits
zoom(2) % zoom in
elseif ismember(char,[120 88 45]) % lowercase x is 120, uppercase is 88 minus is 45
lim = axis; % get current axis limits
pti=get(axes_handle, 'CurrentPoint'); % get current cursor point
axis([pti(1,1)+diff(lim(1:2))/2*[-1 1] pti(1,2)+diff(lim(3:4))/2*[-1 1]]); % reset axis limits
zoom(.5)
elseif char==8
try
delete(htext(end));
htext(end)=[];
end
else
drawnow;
pt = get(axes_handle, 'CurrentPoint');
if(char == 13) % & how_many ~= 0)
% if the return key was pressed, char will == 13,
% and that's our signal to break out of here whether
% or not we have collected all the requested data
% points.
% If this was an early breakout, don't include
% the <Return> key info in the return arrays.
% We will no longer count it if it's the last input.
break;
end
% Get current x/y click points:
[latclick,lonclick] = minvtran(pt(1,1),pt(1,2));
[xclick,yclick] = ll2ps(latclick,lonclick);
% Get indices of nearest feature:
[~,nearind] = min(hypot(sn.x -xclick,sn.y-yclick));
% Place text
if keepPoints
htext(length(htext)+1) = textm(sn.lat(nearind),sn.lon(nearind),1,sn.names(nearind),'vert','middle','horiz','center');
else
try; delete(htext); end
htext = textm(sn.lat(nearind),sn.lon(nearind),1,sn.names(nearind),'vert','middle','horiz','center');
end
if ~isempty(varargin)
try
set(htext,varargin{:})
end
end
set(fig,'Pointer','crosshair')
end
char = [];
end
end
% Cleanup and Restore
cleanup(c);
%% Clean up:
% Reset initial axes if user zoomed in or out:
axis(InitialAxes);
% delete labels unless 'keep' was requested by user:
if ~keepPoints
delete(htext)
clear htext
end
% delete text handles unless requested by user:
if nargout==0
clear htext
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function key = wfbp
%WFBP Replacement for WAITFORBUTTONPRESS that has no side effects.
fig = gcf;
current_char = []; %#ok<NASGU>
% Now wait for that buttonpress, and check for error conditions
waserr = 0;
try
h=findall(fig,'Type','uimenu','Accelerator','C'); % Disabling ^C for edit menu so the only ^C is for
set(h,'Accelerator',''); % interrupting the function.
keydown = waitforbuttonpress;
current_char = double(get(fig,'CurrentCharacter')); % Capturing the character.
if~isempty(current_char) && (keydown == 1) % If the character was generated by the
if(current_char == 3) % current keypress AND is ^C, set 'waserr'to 1
waserr = 1; % so that it errors out.
end
end
set(h,'Accelerator','C'); % Set back the accelerator for edit menu.
catch %#ok<CTCH>
waserr = 1;
end
drawnow;
if(waserr == 1)
set(h,'Accelerator','C'); % Set back the accelerator if it errored out.
error(message('MATLAB:clickz:Interrupted'));
end
if nargout>0, key = keydown; end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end
function initialState = setupFcn(fig)
% Store Figure Handle.
initialState.figureHandle = fig;
% Suspend figure functions
initialState.uisuspendState = uisuspend(fig);
% Disable Plottools Buttons
initialState.toolbar = findobj(allchild(fig),'flat','Type','uitoolbar');
if ~isempty(initialState.toolbar)
initialState.ptButtons = [uigettool(initialState.toolbar,'Plottools.PlottoolsOff'), ...
uigettool(initialState.toolbar,'Plottools.PlottoolsOn')];
initialState.ptState = get (initialState.ptButtons,'Enable');
set (initialState.ptButtons,'Enable','off');
end
% Setup FullCrosshair Pointer without warning.
oldwarnstate = warning('off', 'MATLAB:hg:Figure:Pointer');
set(fig,'Pointer','crosshair');
warning(oldwarnstate);
% Adding this to enable automatic updating of currentpoint on the figure
set(fig,'WindowButtonMotionFcn',@(o,e) dummy());
% Get the initial Figure Units
initialState.fig_units = get(fig,'Units');
end
function restoreFcn(initialState)
if ishghandle(initialState.figureHandle)
% Figure Units
set(initialState.figureHandle,'Units',initialState.fig_units);
set(initialState.figureHandle,'WindowButtonMotionFcn','');
% Plottools Icons
if ~isempty(initialState.toolbar) && ~isempty(initialState.ptButtons)
set (initialState.ptButtons(1),'Enable',initialState.ptState{1});
set (initialState.ptButtons(2),'Enable',initialState.ptState{2});
end
% UISUSPEND
uirestore(initialState.uisuspendState);
end
end
function dummy()
% do nothing, this is there to update the clickz WindowButtonMotionFcn.
end
function cleanup(c)
if isvalid(c)
delete(c);
end
end