-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathgrdimage.jl
More file actions
235 lines (200 loc) · 11.6 KB
/
grdimage.jl
File metadata and controls
235 lines (200 loc) · 11.6 KB
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
"""
grdimage(cmd0::String="", arg1=nothing, arg2=nothing, arg3=nothing; kwargs...)
Produces a gray-shaded (or colored) map by plotting rectangles centered on each grid node and assigning
them a gray-shade (or color) based on the z-value.
Parameters
----------
- **A** | **img_out** | **image_out** :: [Type => Str]
Save an image in a raster format instead of PostScript.
- $(_opt_J)
- $(_opt_B)
- $(opt_C)
- **D** | **img_in** | **image_in** :: [Type => Str]
Specifies that the grid supplied is an image file to be read via GDAL.
- **E** | **dpi** :: [Type => Int]
Sets the resolution of the projected grid that will be created.
- **G** | **bit_color** :: [Type => Int]
- **I** | **shade** | **shading** | **intensity** :: [Type => Bool | Str | GMTgrid]
Gives the name of a grid file or GMTgrid with intensities in the (-1,+1) range,
or a grdgradient shading flags.
- **M** | **monochrome** :: [Type => Bool]
Force conversion to monochrome image using the (television) YIQ transformation.
- **N** | **noclip** :: [Type => Bool]
Do not clip the image at the map boundary.
- $(opt_P)
- **Q** | **alpha_color** | **nan_alpha** :: [Type => Bool | Tuple | Str] ``Q = true | Q = (r,g,b)``
Make grid nodes with z = NaN transparent, or pick a color for transparency in a image.
- $(_opt_R)
- $(opt_savefig)
To see the full documentation type: ``@? grdimage``
"""
grdimage(arg1, arg2=nothing, arg3=nothing; kw...) = grdimage_helper("", arg1, arg2, arg3; first=true, kw...)
grdimage(cmd0::String="", arg1=nothing, arg2=nothing, arg3=nothing; kw...) =
grdimage_helper(cmd0, arg1, arg2, arg3; first=true, kw...)
grdimage!(cmd0::String="", arg1=nothing, arg2=nothing, arg3=nothing; kw...) =
grdimage_helper(cmd0, arg1, arg2, arg3; first=false, kw...)
grdimage!(arg1, arg2=nothing, arg3=nothing; kw...) = grdimage_helper("", arg1, arg2, arg3; first=false, kw...)
function grdimage_helper(cmd0::String, arg1=nothing, arg2=nothing, arg3=nothing; first=true, kwargs...)
d, K, O = init_module(first, kwargs...) # Also checks if the user wants ONLY the HELP mode
(cmd0 != "" && arg1 === nothing && haskey(d, :inset)) && (arg1 = gmtread(cmd0); cmd0 = "")
(isa(arg1, Matrix{<:Real}) && isa(arg2, Matrix{<:Real}) && isa(arg3, Matrix{<:Real})) &&
(arg2 = mat2grid(arg2); arg3 = mat2grid(arg3)) # Because than wrapGrids will convert arg1 to GMTgrid and other two must type agree
grdimage_helper(wrapGrids(cmd0, arg1), arg2, arg3, K, O, d)
end
# ---------------------------------------------------------------------------------------------------
function grdimage_helper(w::wrapGrids, arg2, arg3, K::Bool, O::Bool, d::Dict{Symbol, Any})
cmd0, arg1 = unwrapGrids(w)
common_insert_R!(d, O, cmd0, arg1) # Set -R in 'd' out of grid/images (with coords) if limits was not used
# Remote files with no -R are all global. Set CTRL.limits so we can guess the projection.
(!haskey(d, :R) && any(startswith.(cmd0, ["@earth_", "@mars_", "@pluto_", "@moon_", "@venus_"]))) &&
(CTRL.limits[1:4] = CTRL.limits[7:10] = [-180, 180, -90, 90])
if (arg1 === nothing && (get(d, :R, nothing) !== nothing) && guess_T_from_ext(cmd0) == " -Ti")
_opt_R = d[:R]
t = (isa(_opt_R, Tuple) || isa(_opt_R, VMr)) ?
["$(_opt_R[1])", "$(_opt_R[2])", "$(_opt_R[3])", "$(_opt_R[4])"] : split(_opt_R, '/')
opts = ["-projwin", t[1], t[4], t[2], t[3]] # -projwin <ulx> <uly> <lrx> <lry>
arg1 = cut_with_gdal(cmd0, opts)
cmd0 = ""
end
if (isa(arg1, Matrix{<:Real}) || isa(arg1, Array{<:Real,3}))
if (isa(arg1, Matrix{UInt8}) || isa(arg1, Matrix{UInt16}) || isa(arg1, Array{UInt8,3}))
arg1 = mat2img(arg1; d...)
else
arg1 = mat2grid(arg1)
(isa(arg2, Matrix{<:Real})) && (arg2 = mat2grid(arg2))
(isa(arg3, Matrix{<:Real})) && (arg3 = mat2grid(arg3))
end
elseif (isa(arg1, GMTimage) && size(arg1, 3) <= 3 && eltype(arg1.image) <: UInt16)
arg1 = mat2img(arg1; d...)
(haskey(d, :stretch) || haskey(d, :histo_bounds)) && delete!(d, [:histo_bounds, :stretch])
end
_grdimage(wrapGrids(cmd0, arg1), arg2, arg3, O, K, d)
end
function _grdimage(w::wrapGrids, arg2, arg3, O::Bool, K::Bool, d::Dict{Symbol, Any})
cmd0, arg1 = unwrapGrids(w)
arg4 = nothing # For the r,g,b + intensity case
# Prevent that J=guess is applied to a non-geog grid/image
(arg1 !== nothing && (symb = is_in_dict(d, [:proj :projection])) !== nothing && (d[symb] == "guess" || d[symb] == :guess) && !isgeog(arg1)) &&
delete!(d, symb)
has_opt_B = (is_in_dict(d, [:B :frame :axis :axes]) !== nothing)
(is_in_dict(d, [:A :img_out :image_out]) !== nothing) && (d[:B] = "none") # When -A is used, -B is forbiden
cmd::String, opt_B::String, opt_J::String, opt_R::String = parse_BJR(d, "", "", O, " -JX" * split(DEF_FIG_SIZE, '/')[1] * "/0")
(startswith(opt_J, " -JX") && !contains(opt_J, "/")) && (cmd = replace(cmd, opt_J => opt_J * "/0")) # When sub-regions
sim = (!has_opt_B && isa(arg1, GMTimage) && (isimgsize(arg1) || CTRL.limits[1:4] == zeros(4)) && opt_B == DEF_FIG_AXES_BAK)
if (!sim && cmd0 !== "" && !has_opt_B)
sim = (lowercase(splitext(cmd0)[2]) in [".jpg", ".jpeg", ".png", ".bmp", ".webp"])
end
sim && (cmd = replace(cmd, opt_B => ""))
cmd, = parse_common_opts(d, cmd, [:UVXY :params :margin :c :f :n :p :t]; first=!O)
cmd = parse_these_opts(cmd, d, [[:A :img_out :image_out], [:D :img_in :image_in], [:E :dpi], [:G :bit_color],
[:M :monochrome], [:N :noclip], [:Q :nan_alpha :alpha_color]])
cmd = add_opt(d, cmd, "%", [:layout :mem_layout])
cmd = add_opt(d, cmd, "T", [:T :no_interp :tiles], (skip="_+s", skip_nan="_+s", outlines=("+o", add_opt_pen)))
if (isa(arg1, GMTgrid) && length(opt_R) > 3 && !isapprox(CTRL.limits[1:4], arg1.range[1:4]))
# If a -R is used and grid is in mem, better to crop it right now. Also helps with getting the auto CPT from crop
arg1 = grdcut(arg1, R=opt_R[4:end], J=opt_J[4:end])
got_fname = 0
else
cmd, got_fname, arg1 = find_data(d, cmd0, cmd, arg1) # Find how data was transmitted
if (got_fname == 0 && isa(arg1, Tuple)) # Then it must be using the three r,g,b grids
cmd, got_fname, arg1, arg2, arg3 = find_data(d, cmd0, cmd, arg1, arg2, arg3)
end
end
set_defcpt!(d, cmd0, arg1) # When dealing with a remote grid assign it a default CPT
(isa(arg1, GMTgrid) && arg1.cpt != "") && (d[:this_cpt] = arg1.cpt)
(haskey(d, :this_cpt) && isfile(d[:this_cpt])) && (CURRENT_CPT[] = gmtread(d[:this_cpt]))
cmd, _, arg1, arg2, arg3 = common_get_R_cpt(d, cmd0, cmd, opt_R, got_fname, arg1, arg2, arg3, "grdimage")
cmd, arg1, arg2, arg3, arg4 = common_shade(d, cmd, arg1, arg2, arg3, arg4, "grdimage")
if (isa(arg1, GMTimage) && !occursin("-Q", cmd))
if (!occursin("-D", cmd)) cmd *= " -D" end # Lost track why but need this so gmt_main knows it should init a img
#(!occursin("-D", cmd) && !occursin(" -C", cmd)) && (cmd *= " -D") # Lost track why but need this so gmt_main knows it should init a img
(length(opt_J) > 3 && (opt_J[4] != 'X' && opt_J[4] != 'x')) && (cmd *= "r") # GMT crashes when just -D and proj
end
finish = false
_cmd = ["grdimage " * cmd]
_cmd = frame_opaque(_cmd, opt_B, opt_R, opt_J; bot=false) # No -t in frame
if (!occursin("-A", cmd)) # -A means that we are requesting the image directly
(haskey(d, :inset)) && (pocket_call[][4] = arg1) # If 'inset', it may be needed from next call
(isa(arg1, GMTgrid) && is_in_dict(d, [:contour :contours], del=true) !== nothing) && (d[:grdcontour] = arg1) # Still very rudimentar
_cmd = finish_PS_nested(d, _cmd)
if ((ind = findfirst(startswith.(_cmd, "inset_"))) !== nothing) # inset commands must be the last ones
ins = popat!(_cmd, ind) # Remove the 'inset' command
append!(_cmd, [ins]) # and add it at the end
end
if (startswith(_cmd[end], "inset_") && isa(pocket_call[][4], String))
_cmd = zoom_reactangle(_cmd, false)
end
finish = true
end
if (length(_cmd) > 1 && cmd0 != "") # In these cases no -R is passed so the nested calls set an unknown -R
for k = 2:lastindex(_cmd) _cmd[k] = replace(_cmd[k], "-R " => "-R" * cmd0 * " ") end
end
((r = check_dbg_print_cmd(d, _cmd)) !== nothing) && return r
prep_and_call_finish_PS_module(d, _cmd, "", K, O, finish, arg1, arg2, arg3, arg4)
end
# ---------------------------------------------------------------------------------------------------
function common_insert_R!(d::Dict, O::Bool, cmd0, @nospecialize(I_G); is3D=false)
# Set -R in 'd' under several conditions. We may need this to make -J=:guess to work
O && return
CTRL.limits .= 0.0 # Have to play safe on this because some eventual show calls may have left this non-empty
opt_R::String = ""
# When grdview and -p is used we must set also Z lims in -R. If p does not have 'elev' we do nothing
function add_Zlims_in_R(d, opt_R, zmin, zmax)
((_val = hlp_desnany_arg2str(d, [:p :view :perspective], false)) === "") && return opt_R # Nothing to change
!contains(_val, '/') && return opt_R # Just p=azim, nothing to change in -R
t = round_wesn([zmin zmin zmax zmax]) # Raw numbers gives uggly limits
return @sprintf("%s/%.15g/%.15g", opt_R, t[1], t[4])
end
if ((val = find_in_dict(d, [:R :region :limits], false)[1]) === nothing && (isa(I_G, GItype)))
opt_R = @sprintf("%.15g/%.15g/%.15g/%.15g", I_G.range[1], I_G.range[2], I_G.range[3], I_G.range[4]) # auto inset-zoom needs it
if (isa(I_G, GMTgrid) || !isimgsize(I_G))
is3D && (opt_R = add_Zlims_in_R(d, opt_R, I_G.range[5], I_G.range[6]))
d[:R] = opt_R
end
elseif (val === nothing && IamModern[] && CTRL.limits[13] == 1.0)
# Should it apply also to classic? And should the -R be rebuilt here?
elseif (val === nothing && (isa(cmd0, String) && cmd0 != "") && !CONVERT_SYNTAX[] && snif_GI_set_CTRLlimits(cmd0))
opt_R = @sprintf("%.15g/%.15g/%.15g/%.15g", CTRL.limits[1], CTRL.limits[2], CTRL.limits[3], CTRL.limits[4])
is3D && (opt_R = add_Zlims_in_R(d, opt_R, CTRL.limits[5], CTRL.limits[6]))
d[:R] = opt_R
elseif (val !== nothing)
if (isa(val, StrSymb))
s = string(val)::String
d[:R] = (s == "global" || s == "d") ? (-180.,180.,-90.,90.) : (s == "global360" || s == "g") ? (0.,360.,-90.,90.) : val
elseif (isa(val, Tuple) || isa(val, VMr))
d[:R] = val
end
try # Can't risk to error here
opt_R = @sprintf("%.15g/%.15g/%.15g/%.15g", d[:R][1], d[:R][2], d[:R][3], d[:R][4])
catch
end
delete!(d, [:region, :limits])
end
(opt_R != "") && (CTRL.pocket_R[1] = " -R" * opt_R)
return nothing
end
# ---------------------------------------------------------------------------------------------------
function common_shade(d::Dict, cmd::String, @nospecialize(arg1), @nospecialize(arg2), @nospecialize(arg3), @nospecialize(arg4), prog::String)
# Used both by grdimage and grdview
symbs = [:I :shade :shading :intensity]
(SHOW_KWARGS[]) && return print_kwarg_opts(symbs, "GMTgrid | String"), arg1, arg2, arg3, arg4
if ((val = find_in_dict(d, symbs, false)[1]) !== nothing)
if (!isa(val, GMTgrid)) # Uff, simple. Either a file name or a -A type modifier
if (isa(val, String) || isa(val, Symbol) || isa(val, Bool))
val_str::String = arg2str(val)
(val_str == "" || val_str == "default" || val_str == "auto") ? cmd *= " -I+a-45+nt1" : cmd *= " -I" * val_str
else
cmd = add_opt(d, cmd, "I", [:I :shading :shade :intensity],
(auto = "_+", azim = "+a", azimuth = "+a", norm = "+n", default = "_+d+a-45+nt1"))
end
else
valG::GMTgrid = val
if (prog == "grdimage") cmd, N_used = put_in_slot(cmd, 'I', arg1, arg2, arg3, arg4)
else cmd, N_used = put_in_slot(cmd, 'I', arg1, arg2, arg3)
end
(N_used == 1) ? arg1 = valG : ((N_used == 2) ? arg2 = valG : ((N_used == 3) ? arg3 = valG : arg4 = valG))
end
delete!(d, [:I, :shade, :shading, :intensity])
end
return cmd, arg1, arg2, arg3, arg4
end