comparison scripts/plot/colorbar.m @ 17100:33037eddecd2

Overhaul colorbar function. Colorbar now accepts an input colorbar handle or an input axis and will act appropriately. Updated docstring. Added Matlab compatible options "hide" and "delete". Stopped random failures by deleting all listeners when cbar is deleted. Added listener to monitor SIZE of colormap. Cleaned up coding style. Used less vague internal variable name __cbar_hax__ instead of __my_handle__ for out-of-band communication with __actual_axis_position__.m. * scripts/plot/colorbar.m: Colorbar now accepts an input colorbar handle or an input axis and will act appropriately. Updated docstring. Added Matlab compatible options "hide" and "delete". Stopped random failures by deleting all listeners when cbar is deleted. Added listener to monitor SIZE of colormap. Cleaned up coding style. Used less vague internal variable name __cbar_hax__ instead of __my_handle__ for out-of-band communication with __actual_axis_position__.m. * scripts/plot/private/__actual_axis_position__.m: Rename __my_handle__ to __cbar_hax__ for clarity.
author Rik <rik@octave.org>
date Fri, 26 Jul 2013 13:15:07 -0700
parents f3b5cadfd6d5
children eaab03308c0b
comparison
equal deleted inserted replaced
17097:e38820d1124c 17100:33037eddecd2
15 ## You should have received a copy of the GNU General Public License 15 ## You should have received a copy of the GNU General Public License
16 ## along with Octave; see the file COPYING. If not, see 16 ## along with Octave; see the file COPYING. If not, see
17 ## <http://www.gnu.org/licenses/>. 17 ## <http://www.gnu.org/licenses/>.
18 18
19 ## -*- texinfo -*- 19 ## -*- texinfo -*-
20 ## @deftypefn {Function File} {} colorbar (@var{s}) 20 ## @deftypefn {Function File} {} colorbar
21 ## @deftypefnx {Function File} {} colorbar ("peer", @var{h}, @dots{}) 21 ## @deftypefnx {Function File} {} colorbar (@var{loc})
22 ## Add a colorbar to the current axes. Valid values for @var{s} are 22 ## @deftypefnx {Function File} {} colorbar (@var{delete_option})
23 ## @deftypefnx {Function File} {} colorbar (@var{hcb}, @dots{})
24 ## @deftypefnx {Function File} {} colorbar (@var{hax}, @dots{})
25 ## @deftypefnx {Function File} {} colorbar (@dots{}, "peer", @var{hax}, @dots{})
26 ## @deftypefnx {Function File} {} colorbar (@dots{}, "location", @var{loc}, @dots{})
27 ## @deftypefnx {Function File} {} colorbar (@dots{}, @var{prop}, @var{val}, @dots{})
28 ## @deftypefnx {Function File} {@var{h} =} colorbar (@dots{})
29 ## Add a colorbar to the current axes.
30 ##
31 ## A colorbar displays the current colormap along with numerical rulings
32 ## so that the color scale can be interpreted.
33 ##
34 ## The optional input @var{loc} determines the location of the colorbar.
35 ## Valid values for @var{loc} are
23 ## 36 ##
24 ## @table @asis 37 ## @table @asis
25 ## @item "EastOutside" 38 ## @item "EastOutside"
26 ## Place the colorbar outside the plot to the right. This is the default. 39 ## Place the colorbar outside the plot to the right. This is the default.
27 ## 40 ##
43 ## @item "SouthOutside" 56 ## @item "SouthOutside"
44 ## Place the colorbar under the plot. 57 ## Place the colorbar under the plot.
45 ## 58 ##
46 ## @item "South" 59 ## @item "South"
47 ## Place the colorbar at the bottom of the plot. 60 ## Place the colorbar at the bottom of the plot.
48 ##
49 ## @item "Off", "None"
50 ## Remove any existing colorbar from the plot.
51 ## @end table 61 ## @end table
52 ## 62 ##
63 ## To remove a colorbar from a plot use any one of the following keywords for
64 ## the @var{delete_option}: "delete", "hide", "off".
65 ##
53 ## If the argument "peer" is given, then the following argument is treated 66 ## If the argument "peer" is given, then the following argument is treated
54 ## as the axes handle on which to add the colorbar. 67 ## as the axes handle in which to add the colorbar. Alternatively,
68 ## If the first argument @var{hax} is an axes handle, then the colorbar is
69 ## added to this axis, rather than the current axes returned by @code{gca}.
70 ##
71 ## If the first argument @var{hcb} is a handle to a colorbar object, then
72 ## operate on this colorbar directly.
73 ##
74 ## Additional property/value pairs are passed directly to the underlying axes
75 ## object.
76 ##
77 ## The optional return value @var{h} is a graphics handle to the created
78 ## colorbar object.
79 ##
80 ## Implementation Note: A colorbar is created as an additional axes to the
81 ## current figure with the "tag" property set to "colorbar". The created
82 ## axes object has the extra property "location" which controls the positioning
83 ## of the colorbar.
84 ## @seealso{colormap}
55 ## @end deftypefn 85 ## @end deftypefn
56 86
57 function h = colorbar (varargin) 87 function h = colorbar (varargin)
58 ax = []; 88
59 loc = "eastoutside"; 89 [hcb, varargin, nargin] = __plt_get_axis_arg__ ("colorbar", varargin{:});
90
91 if (hcb && ! strcmp (get (hcb, "tag"), "colorbar"))
92 ax = hcb;
93 hcb = [];
94 else
95 ax = [];
96 endif
97 loc = "";
60 args = {}; 98 args = {};
61 deleting = false; 99 deleting = false;
62 100
63 i = 1; 101 i = 1;
64 while (i <= nargin) 102 while (i <= nargin)
65 arg = varargin {i++}; 103 arg = varargin{i++};
66 if (ischar (arg)) 104 if (ischar (arg))
67 if (strcmpi (arg, "peer")) 105 switch (tolower (arg))
68 if (i > nargin) 106 case "peer"
69 error ("colorbar: missing axes handle after \"peer\""); 107 if (i > nargin)
70 else 108 error ('colorbar: missing axes handle after "peer"');
71 ax = varargin{i++}; 109 else
72 if (!isscalar (ax) || ! ishandle (ax) 110 ax = varargin{i++};
73 || ! strcmp (get (ax, "type"), "axes")) 111 if (! isscalar (ax) || ! ishandle (ax)
74 error ("colorbar: expecting an axes handle following \"peer\""); 112 || ! strcmp (get (ax, "type"), "axes"))
113 error ('colorbar: expecting an axes handle following "peer"');
114 endif
75 endif 115 endif
76 endif 116 case {"north", "south", "east", "west",
77 elseif (strcmpi (arg, "north") || strcmpi (arg, "south") 117 "northoutside", "southoutside", "eastoutside", "westoutside"}
78 || strcmpi (arg, "east") || strcmpi (arg, "west") 118 loc = tolower (arg);
79 || strcmpi (arg, "northoutside") || strcmpi (arg, "southoutside") 119 case "location"
80 || strcmpi (arg, "eastoutside") || strcmpi (arg, "westoutside")) 120 if (i > nargin)
81 loc = tolower (arg); 121 error ('colorbar: missing value after "location"');
82 elseif (strcmpi (arg, "location") && i <= nargin) 122 else
83 loc = tolower (varargin{i++}); 123 loc = tolower (varargin{i++});
84 elseif (strcmpi (arg, "off") || strcmpi (arg, "none")) 124 endif
85 deleting = true; 125 case {"delete", "hide", "off", "none"}
86 else 126 deleting = true;
87 args{end+1} = arg; 127 otherwise
128 args{end+1} = arg;
129 endswitch
130 else
131 args{end+1} = arg;
132 endif
133 endwhile
134
135 ## Handle changes to existing colorbar
136 if (! isempty (hcb))
137 if (deleting)
138 delete (hcb);
139 if (nargout > 0)
140 h = hcb;
88 endif 141 endif
89 else 142 return;
90 args{end+1} = arg; 143 else
91 endif 144 ## FIXME: No listener on location property so have to re-create
92 endwhile 145 ## colorbar whenever an option changes.
93 146 ## re-instate this code if listener is developed.
147 # if (! isempty (loc))
148 # set (hcb, "location", loc);
149 # endif
150 # if (! isempty (args))
151 # set (hcb, args{:});
152 # endif
153 ax = get (get (hcb, "parent"), "currrentaxes");
154 endif
155 endif
156
157 if (isempty (loc))
158 loc = "eastoutside";
159 endif
94 if (isempty (ax)) 160 if (isempty (ax))
95 ax = gca (); 161 ax = gca ();
96 endif 162 endif
97 163
98 showhiddenhandles = get (0, "showhiddenhandles"); 164 showhiddenhandles = get (0, "showhiddenhandles");
105 unwind_protect_cleanup 171 unwind_protect_cleanup
106 set (0, "showhiddenhandles", showhiddenhandles); 172 set (0, "showhiddenhandles", showhiddenhandles);
107 end_unwind_protect 173 end_unwind_protect
108 174
109 if (! deleting) 175 if (! deleting)
110 ## FIXME - Matlab does not require the "position" property to be active. 176 ## FIXME: Matlab does not require the "position" property to be active.
111 ## Is there a way to determine the plotbox position for the 177 ## Is there a way to determine the plotbox position for the
112 ## gnuplot graphics toolkit with the outerposition is active? 178 ## gnuplot graphics toolkit with the outerposition is active?
113 set (ax, "activepositionproperty", "position"); 179 set (ax, "activepositionproperty", "position");
114 obj = get (ax); 180 obj = get (ax);
115 obj.__my_handle__ = ax; 181 obj.__cbar_hax__ = ax;
116 position = obj.position; 182 position = obj.position;
117 clen = rows (get (get (ax, "parent"), "colormap")); 183 ## FIXME: Should this be ancestor to accommodate hggroups?
184 hpar = get (ax, "parent");
185 clen = rows (get (hpar, "colormap"));
118 cext = get (ax, "clim"); 186 cext = get (ax, "clim");
119 cdiff = (cext(2) - cext(1)) / clen / 2; 187 cdiff = (cext(2) - cext(1)) / clen / 2;
120 cmin = cext(1) + cdiff; 188 cmin = cext(1) + cdiff;
121 cmax = cext(2) - cdiff; 189 cmax = cext(2) - cdiff;
122 190
123 [pos, cpos, vertical, mirror] = ... 191 [pos, cpos, vertical, mirror] = ...
124 __position_colorbox__ (loc, obj, ancestor (ax, "figure")); 192 __position_colorbox__ (loc, obj, ancestor (ax, "figure"));
125 set (ax, "position", pos); 193 set (ax, "position", pos);
126 194
127 cax = __go_axes__ (get (ax, "parent"), "tag", "colorbar", 195 cax = __go_axes__ (hpar, "tag", "colorbar",
128 "handlevisibility", "on", 196 "handlevisibility", "on",
129 "activepositionproperty", "position", 197 "activepositionproperty", "position",
130 "position", cpos); 198 "position", cpos);
131 addproperty ("location", cax, "radio", 199 addproperty ("location", cax, "radio",
132 "eastoutside|east|westoutside|west|northoutside|north|southoutside|south", 200 "eastoutside|east|westoutside|west|northoutside|north|southoutside|south",
133 loc); 201 loc);
134 addproperty ("axes", cax, "handle", ax); 202 addproperty ("axes", cax, "handle", ax);
135 203
136 if (vertical) 204 if (vertical)
137 hi = image (cax, [0,1], [cmin, cmax], [1 : clen]'); 205 hi = image (cax, [0,1], [cmin, cmax], [1 : clen]');
138 if (mirror) 206 if (mirror)
139 set (cax, "xtick", [], "xdir", "normal", "ydir", "normal", 207 set (cax, "xtick", [], "xdir", "normal", "ydir", "normal",
140 "ylim", cext, "ylimmode", "manual", 208 "ylim", cext, "ylimmode", "manual",
141 "yaxislocation", "right", args{:}); 209 "yaxislocation", "right", args{:});
142 else 210 else
143 set (cax, "xtick", [], "xdir", "normal", "ydir", "normal", 211 set (cax, "xtick", [], "xdir", "normal", "ydir", "normal",
144 "ylim", cext, "ylimmode", "manual", 212 "ylim", cext, "ylimmode", "manual",
145 "yaxislocation", "left", args{:}); 213 "yaxislocation", "left", args{:});
146 endif 214 endif
147 else 215 else
148 hi = image (cax, [cmin, cmax], [0,1], [1 : clen]); 216 hi = image (cax, [cmin, cmax], [0,1], [1 : clen]);
149 if (mirror) 217 if (mirror)
150 set (cax, "ytick", [], "xdir", "normal", "ydir", "normal", 218 set (cax, "ytick", [], "xdir", "normal", "ydir", "normal",
151 "xlim", cext, "xlimmode", "manual", 219 "xlim", cext, "xlimmode", "manual",
152 "xaxislocation", "top", args{:}); 220 "xaxislocation", "top", args{:});
153 else 221 else
154 set (cax, "ytick", [], "xdir", "normal", "ydir", "normal", 222 set (cax, "ytick", [], "xdir", "normal", "ydir", "normal",
155 "xlim", cext, "xlimmode", "manual", 223 "xlim", cext, "xlimmode", "manual",
156 "xaxislocation", "bottom", args{:}); 224 "xaxislocation", "bottom", args{:});
157 endif 225 endif
158 endif 226 endif
159 227
160 ctext = text (0, 0, "", "tag", "colorbar","visible", "off", 228 ## Dummy object placed in axis to delete colorbar when axis is deleted.
161 "handlevisibility", "off", "xliminclude", "off", 229 ctext = text (0, 0, "", "tag", "colorbar",
162 "yliminclude", "off", "zliminclude", "off", 230 "visible", "off", "handlevisibility", "off",
231 "xliminclude", "off", "yliminclude", "off",
232 "zliminclude", "off",
163 "deletefcn", {@deletecolorbar, cax, obj}); 233 "deletefcn", {@deletecolorbar, cax, obj});
164 234
165 set (cax, "deletefcn", {@resetaxis, ax, obj}); 235 set (cax, "deletefcn", {@resetaxis, ax, obj});
166 236
237 addlistener (hpar, "colormap", {@update_colorbar_cmap, hi, vertical, clen});
167 addlistener (ax, "clim", {@update_colorbar_clim, hi, vertical}); 238 addlistener (ax, "clim", {@update_colorbar_clim, hi, vertical});
239 addlistener (ax, "dataaspectratio", {@update_colorbar_axis, cax, obj});
240 addlistener (ax, "dataaspectratiomode", {@update_colorbar_axis, cax, obj});
168 addlistener (ax, "plotboxaspectratio", {@update_colorbar_axis, cax, obj}); 241 addlistener (ax, "plotboxaspectratio", {@update_colorbar_axis, cax, obj});
169 addlistener (ax, "plotboxaspectratiomode", {@update_colorbar_axis, cax, obj}); 242 addlistener (ax, "plotboxaspectratiomode", {@update_colorbar_axis, cax, obj});
170 addlistener (ax, "dataaspectratio", {@update_colorbar_axis, cax, obj});
171 addlistener (ax, "dataaspectratiomode", {@update_colorbar_axis, cax, obj});
172 addlistener (ax, "position", {@update_colorbar_axis, cax, obj}); 243 addlistener (ax, "position", {@update_colorbar_axis, cax, obj});
173 244
174 endif 245 endif
175 246
176 if (nargout > 0) 247 if (nargout > 0)
177 h = cax; 248 h = cax;
178 endif 249 endif
250
179 endfunction 251 endfunction
180 252
181 function deletecolorbar (h, d, hc, orig_props) 253 function deletecolorbar (h, d, hc, orig_props)
182 ## Don't delete the colorbar and reset the axis size if the 254 ## Don't delete the colorbar and reset the axis size if the
183 ## parent figure is being deleted. 255 ## parent figure is being deleted.
184 if (ishandle (hc) && strcmp (get (hc, "type"), "axes") 256 if (ishandle (hc) && strcmp (get (hc, "type"), "axes")
185 && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"),"off"))) 257 && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"), "off")))
186 if (strcmp (get (hc, "beingdeleted"), "off")) 258 if (strcmp (get (hc, "beingdeleted"), "off"))
187 delete (hc); 259 delete (hc);
188 endif 260 endif
189 if (!isempty (ancestor (h, "axes")) 261 if (!isempty (ancestor (h, "axes"))
190 && strcmp (get (ancestor (h, "axes"), "beingdeleted"), "off")) 262 && strcmp (get (ancestor (h, "axes"), "beingdeleted"), "off"))
191 set (ancestor (h, "axes"), "position", orig_props.position, ... 263 ax = ancestor (h, "axes");
192 "outerposition", orig_props.outerposition, ... 264 units = get (ax, "units");
193 "activepositionproperty", orig_props.activepositionproperty); 265 set (ax, "units", orig_props.units);
266 set (ancestor (h, "axes"), "position", orig_props.position,
267 "outerposition", orig_props.outerposition,
268 "activepositionproperty", orig_props.activepositionproperty);
269 set (ax, "units", units);
194 endif 270 endif
195 endif 271 endif
196 endfunction 272 endfunction
197 273
198 function resetaxis (cax, d, ax, orig_props) 274 function resetaxis (cax, d, ax, orig_props)
199 if (ishandle (ax) && strcmp (get (ax, "type"), "axes")) 275 if (ishandle (ax) && strcmp (get (ax, "type"), "axes"))
276 ## FIXME: Probably don't want to delete everyone's listeners on colormap.
277 dellistener (get (ax, "parent"), "colormap");
278 dellistener (ax, "clim");
279 dellistener (ax, "dataaspectratio");
280 dellistener (ax, "dataaspectratiomode");
281 dellistener (ax, "plotboxaspectratio");
282 dellistener (ax, "plotboxaspectratiomode");
200 dellistener (ax, "position"); 283 dellistener (ax, "position");
284
201 units = get (ax, "units"); 285 units = get (ax, "units");
202 set (ax, "units", orig_props.units); 286 set (ax, "units", orig_props.units);
203 set (ax, "position", orig_props.position, ... 287 set (ax, "position", orig_props.position,
204 "outerposition", orig_props.outerposition, ... 288 "outerposition", orig_props.outerposition,
205 "activepositionproperty", orig_props.activepositionproperty); 289 "activepositionproperty", orig_props.activepositionproperty);
206 set (ax, "units", units); 290 set (ax, "units", units);
207 endif 291 endif
208 endfunction 292 endfunction
209 293
210 function update_colorbar_clim (h, d, hi, vert) 294 function update_colorbar_clim (hax, d, hi, vert)
211 if (ishandle (h) && strcmp (get (h, "type"), "image") 295 if (ishandle (hax) && strcmp (get (hax, "type"), "axes")
212 && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"),"off"))) 296 && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"), "off")))
213 clen = rows (get (get (h, "parent"), "colormap")); 297 clen = rows (get (get (hax, "parent"), "colormap"));
214 cext = get (h, "clim"); 298 cext = get (hax, "clim");
215 cdiff = (cext(2) - cext(1)) / clen / 2; 299 cdiff = (cext(2) - cext(1)) / clen / 2;
216 cmin = cext(1) + cdiff; 300 cmin = cext(1) + cdiff;
217 cmax = cext(2) - cdiff; 301 cmax = cext(2) - cdiff;
218 302
219 if (vert) 303 if (vert)
220 set (hi, "ydata", [cmin, cmax]); 304 set (hi, "ydata", [cmin, cmax]);
221 set (get (hi, "parent"), "ylim", cext); 305 set (get (hi, "parent"), "ylim", cext);
222 else 306 else
223 set (hi, "xdata", [cmin, cmax]); 307 set (hi, "xdata", [cmin, cmax]);
224 set (get (hi, "parent"), "xlim", cext); 308 set (get (hi, "parent"), "xlim", cext);
309 endif
310 endif
311 endfunction
312
313 function update_colorbar_cmap (hf, d, hi, vert, init_sz)
314 persistent sz = init_sz;
315
316 if (ishandle (hf) && strcmp (get (hf, "type"), "figure")
317 && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"), "off")))
318 clen = rows (get (hf, "colormap"));
319 if (clen != sz)
320 if (vert)
321 set (hi, "cdata", [1:clen]');
322 else
323 set (hi, "cdata", [1:clen]);
324 endif
325 sz = clen;
326 ## Also update limits on axis or there will be white gaps
327 update_colorbar_clim (get (hi, "parent"), d, hi, vert);
225 endif 328 endif
226 endif 329 endif
227 endfunction 330 endfunction
228 331
229 function update_colorbar_axis (h, d, cax, orig_props) 332 function update_colorbar_axis (h, d, cax, orig_props)
230 333
231 if (ishandle (cax) && strcmp (get (cax, "type"), "axes") 334 if (ishandle (cax) && strcmp (get (cax, "type"), "axes")
232 && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"),"off"))) 335 && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"),"off")))
233 loc = get (cax, "location"); 336 loc = get (cax, "location");
234 obj = get (h); 337 obj = get (h);
235 obj.__my_handle__ = h; 338 obj.__cbar_hax__ = h;
236 obj.position = orig_props.position; 339 obj.position = orig_props.position;
237 obj.outerposition = orig_props.outerposition; 340 obj.outerposition = orig_props.outerposition;
238 [pos, cpos, vertical, mirror] = ... 341 [pos, cpos, vertical, mirror] = ...
239 __position_colorbox__ (loc, obj, ancestor (h, "figure")); 342 __position_colorbox__ (loc, obj, ancestor (h, "figure"));
240 343
241 if (vertical) 344 if (vertical)
242 if (mirror) 345 if (mirror)
243 set (cax, "xtick", [], "xdir", "normal", "ydir", "normal", 346 set (cax, "xtick", [], "xdir", "normal", "ydir", "normal",
244 "yaxislocation", "right", "position", cpos); 347 "yaxislocation", "right", "position", cpos);
245 else 348 else
246 set (cax, "xtick", [], "xdir", "normal", "ydir", "normal", 349 set (cax, "xtick", [], "xdir", "normal", "ydir", "normal",
247 "yaxislocation", "left", "position", cpos); 350 "yaxislocation", "left", "position", cpos);
248 endif 351 endif
249 else 352 else
250 if (mirror) 353 if (mirror)
251 set (cax, "ytick", [], "xdir", "normal", "ydir", "normal", 354 set (cax, "ytick", [], "xdir", "normal", "ydir", "normal",
252 "xaxislocation", "top", "position", cpos); 355 "xaxislocation", "top", "position", cpos);
253 else 356 else
254 set (cax, "ytick", [], "xdir", "normal", "ydir", "normal", 357 set (cax, "ytick", [], "xdir", "normal", "ydir", "normal",
255 "xaxislocation", "bottom", "position", cpos); 358 "xaxislocation", "bottom", "position", cpos);
256 endif 359 endif
257 endif 360 endif
258 361
259 endif 362 endif
260 endfunction 363 endfunction
263 366
264 ## This will always represent the position prior to adding the colorbar. 367 ## This will always represent the position prior to adding the colorbar.
265 pos = obj.position; 368 pos = obj.position;
266 sz = pos(3:4); 369 sz = pos(3:4);
267 370
268 if (strcmpi (obj.plotboxaspectratiomode, "manual") 371 if (strcmp (obj.plotboxaspectratiomode, "manual")
269 || strcmpi (obj.dataaspectratiomode, "manual")) 372 || strcmp (obj.dataaspectratiomode, "manual"))
270 if (isempty (strfind (cbox, "outside"))) 373 if (isempty (strfind (cbox, "outside")))
271 scale = 1.0; 374 scale = 1.0;
272 else 375 else
273 scale = 0.8; 376 scale = 0.8;
274 endif 377 endif
338 vertical = true; 441 vertical = true;
339 endswitch 442 endswitch
340 443
341 cpos = [origin, sz]; 444 cpos = [origin, sz];
342 445
343 if (strcmpi (obj.plotboxaspectratiomode, "manual") 446 if (strcmp (obj.plotboxaspectratiomode, "manual")
344 || strcmpi (obj.dataaspectratiomode, "manual")) 447 || strcmp (obj.dataaspectratiomode, "manual"))
345 obj.position = pos; 448 obj.position = pos;
346 actual_pos = __actual_axis_position__ (obj); 449 actual_pos = __actual_axis_position__ (obj);
347 if (strfind (cbox, "outside")) 450 if (strfind (cbox, "outside"))
348 scale = 1.0; 451 scale = 1.0;
349 else 452 else