Changeset 21911


Ignore:
Timestamp:
08/03/17 15:17:23 (8 years ago)
Author:
dlcheng
Message:

CHG: Updating js scripts.

Location:
issm/trunk-jpl/src/m
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk-jpl/src/m/array/arrayoperations.js

    r19887 r21911  
    11function ArrayMax(array){ //{{{
    2         return Math.max.apply(null,array);
     2        //Calculate array max using for loop instead of Math.max.apply(null, array) to avoid recursive stack overflow in mobile browsers
     3       
     4        var max=-Infinity;
     5       
     6        for (var i=0;i<array.length; i++) {
     7                max=Math.max(max,array[i]);
     8        }
     9       
     10        return max;
    311} //}}}
    412function ArrayMax2D(array){ //{{{
    513       
    6         var max=0;
     14        var max=-Infinity;
    715
    816        for (var i=0;i<array.length;i++){
     
    1422} //}}}
    1523function ArrayMin(array){ //{{{
    16         return Math.min.apply(null,array);
     24        //Calculate array min using for loop instead of Math.min.apply(null, array) to avoid recursive stack overflow in mobile browsers
     25       
     26        var min=Infinity;
     27       
     28        for (var i=0;i<array.length; i++) {
     29                min=Math.min(min,array[i]);
     30        }
     31       
     32        return min;
     33} //}}}
     34function ArrayMin2D(array){ //{{{
     35       
     36        var min=Infinity;
     37
     38        for (var i=0;i<array.length;i++){
     39                var subarray=array[i];
     40                min=Math.min(min,ArrayMin(subarray));
     41        }
     42
     43        return min;
    1744} //}}}
    1845function ArraySum(array){ //{{{
     
    6693        return or;
    6794
    68 } //}}}
    69 function ArrayMin2D(array){ //{{{
    70        
    71         var min=ArrayMax2D(array);
    72 
    73         for (var i=0;i<array.length;i++){
    74                 var subarray=array[i];
    75                 min=Math.min(min,ArrayMin(subarray));
    76         }
    77 
    78         return min;
    7995} //}}}
    8096function ListToMatrix(list, elementsPerSubArray) { //{{{
     
    126142function ArrayNot(array) { //{{{
    127143
    128         var notarray=array;
     144        var notarray=array.slice();
    129145        for (var i=0;i<array.length;i++)notarray[i]=-array[i];
    130146        return notarray;
     
    138154function ArrayPow(array,coefficient) { //{{{
    139155
    140         var powarray=array;
     156        var powarray=array.slice();
    141157        for (var i=0;i<array.length;i++)powarray[i]=Math.pow(array[i],coefficient);
    142158        return powarray;
     
    144160function ArraySqrt(array) { //{{{
    145161
    146         var sqrtarray=array;
     162        var sqrtarray=array.slice();
    147163        for (var i=0;i<array.length;i++)sqrtarray[i]=Math.sqrt(array[i]);
    148164        return sqrtarray;
     
    150166function ArrayScale(array,alpha) { //{{{
    151167
    152         for (var i=0;i<array.length;i++)array[i]=array[i]*alpha;
    153 
     168        var scalearray=array.slice();
     169        for (var i=0;i<array.length;i++)scalearray[i]=array[i]*alpha;
     170        return scalearray;
    154171} //}}}
    155172function ArrayMag(array1,array2) { //{{{
     
    250267} //}}}
    251268function NewArrayFill(size,value) { //{{{
    252 
    253         return new Array(size).fill(value);
     269       
     270        var array = new Array(size);
     271       
     272        for (var i = 0; i < size; i++) {
     273                array[i] = value;
     274        }
     275       
     276        return array;
    254277} //}}}
    255278function NewArrayFillIncrement(size,start,increment) { //{{{
  • issm/trunk-jpl/src/m/classes/clusters/generic.js

    r21768 r21911  
    5353                } //}}}
    5454                var request = new XMLHttpRequest();
     55                request.open("POST", this.url, true);
    5556                $(callbackid).html(sprintf("%-16s", "CONNECTING...")).prop("disabled", true);
    5657                request.position = 0; //Keep track of current parsing position in repsonseText
     
    157158                var data = new Blob([nplength,npbuffer,codeversionlength,codeversionbuffer,runtimenamelength,runtimenamebuffer,namelength,namebuffer,toolkitslength,toolkitsbuffer,solutionlength,solutionbuffer,binlength,binbuffer]);
    158159               
    159                 request.open("POST", this.url, true);
    160160                request.responseType = 'application/octet-stream';
    161161                request.send(data);
  • issm/trunk-jpl/src/m/plot/applyoptions.js

    r21768 r21911  
    66        //
    77        //   See also: PLOTMODEL, PARSE_OPTIONS
    8        
     8
    99        //{{{ colorbar
    1010        var gl = canvas.gl;
     
    1616                        var ccanvasid, ctitleid, clabelsid, ccanvas, ctitle, clabels, ccontext, cmap, colorbar, cwidth, cheight, cgradient, color, y, x;
    1717                        //}}}
    18                         //{{{ Create colorbar labels 
     18                        //{{{ Create colorbar labels
    1919                        var labels = [];
    2020                        var cdivisions = options.getfieldvalue('colorbarnticks', 6);
     
    4949                        } //}}}
    5050                        //{{{ Initialize colorbar canvas
    51                         ccanvasid = options.getfieldvalue('colorbarid', options.getfieldvalue('canvasid').replace('canvas','colorbar-canvas'));                 
     51                        ccanvasid = options.getfieldvalue('colorbarid', options.getfieldvalue('canvasid').replace('canvas','colorbar-canvas'));
    5252                        ccanvas = $('#'+ccanvasid)[0];
    5353                        cwidth = ccanvas.width*options.getfieldvalue('colorbarwidth', 1);
     
    6363                        for (var i=0; i < colorbar.length; i++) {
    6464                                color = colorbar[colorbar.length-i-1];
    65                                 color = [Math.round(color[0]*255), Math.round(color[1]*255), Math.round(color[2]*255)]; 
     65                                color = [Math.round(color[0]*255), Math.round(color[1]*255), Math.round(color[2]*255)];
    6666                                cgradient.addColorStop(i/colorbar.length*(cdivisions/(cdivisions+1.0))+(1.0/(cdivisions+1.0)),'rgba('+color.toString()+', 1.0)');
    6767                        }
     
    107107                        if (options.exist('colorbartitle')) { ctitle.html(options.getfieldvalue('colorbartitle')); }
    108108                        //}}}
    109                 } 
     109                }
    110110        } //}}}
    111111        //{{{ texture canvas
     
    119119        tcontext = tcanvas.getContext('2d');
    120120        tgradient = tcontext.createLinearGradient(0, 0, 0, 256);
    121                
     121
    122122        var cmap = options.getfieldvalue('colormap','jet');
    123123        var colorbar = colorbars[cmap];
    124124        for (var i=0; i < colorbar.length; i++) {
    125125                color = colorbar[colorbar.length-i-1];
    126                 color = [Math.round(color[0]*255), Math.round(color[1]*255), Math.round(color[2]*255)]; 
     126                color = [Math.round(color[0]*255), Math.round(color[1]*255), Math.round(color[2]*255)];
    127127                tgradient.addColorStop(i/colorbar.length,'rgba('+color.toString()+', 1.0)');
    128128        }
    129        
     129
    130130        tcontext.fillStyle = tgradient;
    131131        tcontext.fillRect(0, 0, 256, 256);
     
    134134        //}}}
    135135        //{{{ text display
    136         if (options.exist('textlabels')) {
    137                 var textcanvas, textcanvasid;   
    138                 textcanvasid = options.getfieldvalue('textcanvasid', options.getfieldvalue('canvasid')+'-text');
    139                 textcanvas = $('#'+textcanvasid);
    140                 textcanvas.textlabels = options.getfieldvalue('textlabels',[]);
     136        var overlaycanvasid = options.getfieldvalue('overlayid', options.getfieldvalue('canvasid')+'-overlay');
     137        var overlaycanvas = $('#'+overlaycanvasid)[0];
     138        if (!isEmptyOrUndefined(overlaycanvas)) {
     139                //Get drawing context and save reference on main WebGL canvas
     140                var ctx = overlaycanvas.getContext('2d');
     141                canvas.overlaycanvas = overlaycanvas;
    141142               
    142                 //setup drawing function for text canvas draw calls
    143                 textcanvas.draw = function(canvas) {
    144                         var textcontext, textlabels, textlabel, textcanvaswidth, textcanvasheight, textcoordinates;     
    145                         var textposition = vec3.create();
    146                         var mvpMatrix = mat4.create();
    147                        
    148                         //ensure correct canvas coordinate scaling
    149                         textcanvaswidth = this[0].clientWidth;
    150                         textcanvasheight = this[0].clientHeight;
    151                         this[0].width  = textcanvaswidth;
    152                         this[0].height = textcanvasheight;
    153                        
    154                         textcontext = this[0].getContext('2d');
    155                         textlabels = options.getfieldvalue('textlabels',[]);
    156                         textcontext.clearRect(0, 0, textcanvaswidth, textcanvasheight);
    157                        
    158                         //worldspace to screenspace transformation for text
    159                         for (text in textlabels) {
    160                                 textlabel = textlabels[text];
    161                                 mat4.multiply(mvpMatrix, canvas.camera.vpMatrix, canvas.nodes.overlay.modelMatrix);
    162                                 textposition = vec3.transformMat4(textposition, textlabel.pos, mvpMatrix);
    163                                 if (textposition[2] > 1) { //clip coordinates with z > 1
    164                                         continue;
    165                                 }
    166                                 textcoordinates = [(textposition[0]+1.0)/2.0*textcanvaswidth, (-textposition[1]+1.0)/2.0*textcanvasheight]; //NDC to screenspace
    167                                 textcontext.font = String(options.getfieldvalue('colorbarfontsize', 18))+'px "Lato", Helvetica, Arial, sans-serif';
    168                                 textcontext.fillStyle = options.getfieldvalue('colorbarfontcolor','black');
    169                                 textcontext.strokeStyle = options.getfieldvalue('colorbarfontcolor','black');
    170                                 textcontext.textAlign = 'center';
    171                                 textcontext.textBaseline = 'middle';
    172                                 textcontext.fillText(textlabel.text, textcoordinates[0], textcoordinates[1]);
    173                                 textcontext.strokeText(textlabel.text, textcoordinates[0], textcoordinates[1]);
    174                         }
    175                 }
    176                 canvas.textcanvas = textcanvas;
    177         } //}}}
     143                //Resize interal viewport coordinates to match screenspace coordinates
     144                var rect = overlaycanvas.getBoundingClientRect();
     145                overlaycanvas.width  = rect.width;
     146                overlaycanvas.height = rect.height;
     147               
     148                //Clear canvas each frame for any new drawings
     149                canvas.overlayHandlers['draw'] = function(overlaycanvas) {
     150                        ctx.clearRect(0, 0, overlaycanvas.width, overlaycanvas.height);
     151                }
     152        }
    178153        //{{{ lat long overlay
    179154        if (options.exist('latlongoverlay')) {
    180                 var overlaycanvasid = options.getfieldvalue('latlongoverlayid', options.getfieldvalue('canvasid')+'-overlay');
    181                 var overlaycanvas = $('#'+overlaycanvasid)[0];
    182155                var latitudes = {
    183156                        //'-90': 1,
    184157                        //'-65': .999,
    185158                        '-60': 0.994046875,
    186                         //'-55': 0.983187500000002,
    187                         //'-50': 0.97173550854167,
    188159                        '-45': 0.955729166666666,
    189                         //'-40': 0.94218750000000218,
    190                         //'-35': 0.94218750000000218,
    191160                        '-30': 0.9226562500000024,
    192                         //'-25': 0.87934895833333526,
    193                         //'-20': 0.856572916666669,
    194161                        //'-15': 0.830729166666665,
    195                         //'-10': 0.803552708333336,
    196                         //'-5': 0.77395833333333541,
    197162                        '0': 0.74218749999999811,
    198                         //'5': 0.70950364583333347,
    199                         //'10': 0.67479166666666823,
    200163                        //'15': 0.63932291666666663,
    201                         //'20': 0.60171875,
    202                         //'25': 0.563453125,
    203164                        '30': 0.523390625000001,
    204                         //'35': 0.48401875,
    205                         //'40': 0.44296875,
    206165                        '45': 0.4020001,
    207                         //'50': 0.3578125,
    208                         //'55': 0.311875,
    209166                        '60': 0.26953124999999978,
    210167                        //'65': 0.225390625,
    211                         //'70': 0.18125,
    212                         //'75': 0.13541666666666671,
    213                         //'80': 0.08953125,
    214                         //'85': 0.046250000000000013,
    215168                        //'90': 0.0,
    216169                }
    217170                var longitudes = [-150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150, 180];
    218                 overlaycanvas.draw = function(canvas) {
    219                         var rect = overlaycanvas.getBoundingClientRect();
    220                         overlaycanvas.width  = rect.width;
    221                         overlaycanvas.height = rect.height;
    222                         var ctx = overlaycanvas.getContext('2d');
     171                canvas.overlayHandlers['latlong'] = function(canvas) {
     172                        //Transform from world space to viewport space
    223173                        var centerx = overlaycanvas.width / 2;
    224174                        var centery = overlaycanvas.height / 2;
    225175                        var radius = (overlaycanvas.height) / 2;
     176
     177                        //Draw latitudes
    226178                        ctx.setLineDash([5, 10]);
    227179                        for(latitude in latitudes) {
     
    229181                                ctx.arc(centerx, centery, radius * latitudes[latitude], 0, 2 * Math.PI);
    230182                                ctx.stroke();
    231                                 ctx.font = String(options.getfieldvalue('colorbarfontsize', 18))+'px "Lato", Helvetica, Arial, sans-serif';
     183                                ctx.font = 'bold ' + String(options.getfieldvalue('colorbarfontsize', 18))+'px "Lato", Helvetica, Arial, sans-serif';
    232184                                ctx.fillStyle = options.getfieldvalue('colorbarfontcolor','black');
    233185                                ctx.strokeStyle = options.getfieldvalue('colorbarfontcolor','black');
     
    237189                                ctx.strokeText(latitude, centerx, centery + radius * latitudes[latitude]);
    238190                        }
     191                        //Draw longitudes
    239192                        ctx.setLineDash([1, 0]);
    240193                        for (longitude in longitudes) {
     
    245198                        }
    246199                }
    247                 canvas.overlaycanvas = overlaycanvas;
     200        } //}}}
     201        if (options.exist('textlabels')) {
     202                //Attatch new overlay handler to display text labels
     203                var textLabels = options.getfieldvalue('textlabels',[]);
     204                canvas.overlayHandlers['text'] = function(canvas) {
     205                        for (var i = 0; i < textLabels.length; i++) {
     206                                //Get text label to display
     207                                var textLabel = textLabels[i];
     208                                textLabel = {
     209                                        position: defaultFor(textLabel.position, vec3.create()),
     210                                        text: defaultFor(textLabel.text, ''),
     211                                        fontSize: defaultFor(textLabel.fontSize, 18),
     212                                        fontColor: defaultFor(textLabel.fontColor, 'black'),
     213
     214                                };
     215                               
     216                                // function declared in slr-gfm sim-front-end-controller.js
     217                                // if labels are behind the globe sphere then skip iteartion and do not display them
     218                                if (isLabelVisible(textLabel)) {
     219                                        //Transform from world space to viewport space
     220                                        var screenPoint = vec3.transformMat4(vec3.create(), textLabel.position, canvas.camera.vpMatrix);
     221                                        var x = (screenPoint[0] + 1.0) * (canvas.width / 2) + canvas.selector.offset().left;
     222                                        var y = (-screenPoint[1] + 1.0) * (canvas.height / 2) + canvas.selector.offset().top;
     223                                       
     224                                        //Draw text
     225                                        ctx.font = 'bold ' + String(textLabel.fontSize) + 'px Arial Black, sans-serif';
     226                                        ctx.fillStyle = textLabel.fontColor;
     227                                        ctx.strokeStyle = 'white';
     228                                        ctx.textAlign = 'center';
     229                                        ctx.textBaseline = 'middle';
     230                                        ctx.fillText(textLabel.text, x, y);
     231                                        ctx.strokeText(textLabel.text, x, y);
     232                                }
     233                        }
     234                }
    248235        } //}}}
    249236        //{{{ additional rendering nodes
    250237        if (options.exist('render')) {
    251238                var meshresults = processmesh(md, data, options);
    252                 var x = meshresults[0]; 
    253                 var y = meshresults[1]; 
    254                 var z = meshresults[2]; 
     239                var x = meshresults[0];
     240                var y = meshresults[1];
     241                var z = meshresults[2];
    255242                var elements = meshresults[3];
    256                 var is2d = meshresults[4]; 
     243                var is2d = meshresults[4];
    257244                var isplanet = meshresults[5];
    258                
     245
    259246                var xlim = options.getfieldvalue('xlim', [ArrayMin(x), ArrayMax(x)]);
    260247                var ylim = options.getfieldvalue('ylim', [ArrayMin(y), ArrayMax(y)]);
    261248                var zlim = options.getfieldvalue('zlim', [ArrayMin(z), ArrayMax(z)]);
    262249
    263                 var global = vec3.length([(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2]) < 6371000/10; //tolerance for global models = center is 637100 meters away from center of earth   
    264                 var translation = global ? [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2] : [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) - 6371000, (zlim[0] + zlim[1]) / 2];
    265                
     250                var global = vec3.length([(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2]) < 6371000/10; //tolerance for global models = center is 637100 meters away from center of earth
     251                var translation = global ? [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2] : canvas.view.position;
     252
    266253                var renderObjects = options.getfieldvalue('render',{});
    267                 if ('sky' in renderObjects && !('sky' in canvas.nodes)) {
    268                         var object = renderObjects.sky;
     254                for (var renderObject in renderObjects) {
     255                        //Modify renderObejct?
     256                        var object = renderObjects[renderObject];
    269257                        object = {
    270                                 enabled: defaultFor(object.enabled, true),
    271                                 scale: defaultFor(object.scale, 1),
     258                                enabled: defaultFor(object.enabled, true),                                      //Toggle display of the render object node
     259                                scale: defaultFor(object.scale, 1),                                                     //Model matrix scaling
     260                                x: defaultFor(object.x, [0.0, 1.0, 0.0, 0.0, 0.0, 0.0]),        //x coordinate array
     261                                y: defaultFor(object.y, [0.0, 0.0, 0.0, 1.0, 0.0, 0.0]),        //y coordinate array
     262                                z: defaultFor(object.z, [0.0, 0.0, 0.0, 0.0, 0.0, 1.0]),        //z coordinate array
     263                                indices: defaultFor(object.indices, []),                                        //indices array
     264                                name: defaultFor(object.name, 'NY'),                                            //Text to display for cities.
     265                                size: defaultFor(object.size, 1),                                                       //Physical size of the object in meters
     266                                color: defaultFor(object.color, 'black'),                                       //Diffuse color of object
     267                                height: defaultFor(object.height, 25000),                                       //Height of object along y axis, currently for clouds only
     268                                range: defaultFor(object.range, 120000),                                                //Range of sz plane to spawn object, currently for clouds only
     269                                quantity: defaultFor(object.quantity, 15)                                       //Quantity of objects to display, currently for clouds only
    272270                        };
    273                         if (object.enabled) {
    274                                 var atmosphereScale = 1.25;
    275                                 var mesh = GL.Mesh.icosahedron({size: 6371000 * atmosphereScale, subdivisions: 5});
     271                        if (!object.enabled) { continue; }
     272                        if ('sky' === renderObject && !('sky' in canvas.nodes)) {
     273                                var mesh = GL.Mesh.icosahedron({size: 6371000 * canvas.atmosphere.scaleHeight, subdivisions: 5});
    276274                                var texture = initTexture(gl, canvas.rootPath + 'textures/TychoSkymapII_t4_2k.jpg');
    277275                                node = new Node(
    278276                                        'canvas', canvas,
    279277                                        'options', options,
     278                                        'renderObject', object,
    280279                                        'name', 'sky',
    281280                                        'shaderName', 'SkyFromSpace',
     
    286285                                );
    287286                        }
    288                 }
    289                 if ('space' in renderObjects && !('space' in canvas.nodes)) {
    290                         var object = renderObjects.space;
    291                         object = {
    292                                 enabled: defaultFor(object.enabled, true),
    293                                 scale: defaultFor(object.scale, 1),
    294                         };
    295                         if (object.enabled) {
     287                        if ('space' === renderObject && !('space' in canvas.nodes)) {
    296288                                var mesh = GL.Mesh.sphere({size: 6371000 * 20});
    297289                                var texture = initTexture(gl, canvas.rootPath + 'textures/TychoSkymapII_t4_2k.jpg');
     
    299291                                        'canvas', canvas,
    300292                                        'options', options,
     293                                        'renderObject', object,
    301294                                        'name', 'space',
    302295                                        'shaderName', 'Textured',
     
    308301                                );
    309302                        }
    310                 }
    311                 if ('coastlines' in renderObjects && !('coastlines' in canvas.nodes)) {
    312                         var object = renderObjects.coastlines;
    313                         object = {
    314                                 enabled: defaultFor(object.enabled, false),
    315                                 scale: defaultFor(object.scale, 1),
    316                                 x: defaultFor(object.x, {}),
    317                                 y: defaultFor(object.y, {}),
    318                                 z: defaultFor(object.z, {})
    319                         };
    320                         if (object.enabled) {
    321                                 node = new Node(
    322                                         'canvas', canvas,
    323                                         'options', options,
     303                        if ('coastlines' === renderObject && !('coastlines' in canvas.nodes)) {
     304                                node = new Node(
     305                                        'canvas', canvas,
     306                                        'options', options,
     307                                        'renderObject', object,
    324308                                        'name', 'coastlines',
    325309                                        'shaderName', 'Colored',
     
    331315                                node.patch('Vertices', [object.x, object.y, object.z], 'FaceColor', 'none');
    332316                        }
    333                 }
    334                 if ('graticule' in renderObjects && !('graticule' in canvas.nodes)) {
    335                         var object = renderObjects.graticule;
    336                         object = {
    337                                 enabled: defaultFor(object.enabled, false),
    338                                 scale: defaultFor(object.scale, 1),
    339                                 x: defaultFor(object.x, {}),
    340                                 y: defaultFor(object.y, {}),
    341                                 z: defaultFor(object.z, {})
    342                         };
    343                         if (object.enabled) {                   
    344                                 node = new Node(
    345                                         'canvas', canvas,
    346                                         'options', options,
     317                        if ('graticule' === renderObject && !('graticule' in canvas.nodes)) {
     318                                node = new Node(
     319                                        'canvas', canvas,
     320                                        'options', options,
     321                                        'renderObject', object,
    347322                                        'name', 'graticule',
    348323                                        'shaderName', 'Colored',
     
    350325                                        'lineWidth', options.getfieldvalue('linewidth', 1),
    351326                                        'scale', [object.scale, object.scale, object.scale],
    352                                         'rotation', [-90, 0, 0]
     327                                        'rotation', [-90, 180, 0]
    353328                                );
    354329                                node.patch('Vertices', [object.x, object.y, object.z], 'FaceColor', 'none');
    355330                        }
    356                 }
    357                 if ('cities' in renderObjects && !('cities' in canvas.nodes)) {
    358                         var object = renderObjects.cities;
    359                         object = {
    360                                 enabled: defaultFor(object.enabled, false),
    361                                 scale: defaultFor(object.scale, 1),
    362                                 size: defaultFor(object.size, 1.5),
    363                                 color: defaultFor(object.color, 'black'),
    364                                 x: defaultFor(object.x, {}),
    365                                 y: defaultFor(object.y, {}),
    366                                 z: defaultFor(object.z, {}),
    367                                 indices: defaultFor(object.indices, {})
    368                         };
    369                         if (object.enabled) {
     331                        if ('cities' === renderObject && !('cities' in canvas.nodes)) {
    370332                                var mesh = GL.Mesh.icosahedron({size: object.size, subdivisions: 1});
    371333                                node = new Node(
    372334                                        'canvas', canvas,
    373335                                        'options', options,
     336                                        'renderObject', object,
    374337                                        'name', 'cities',
    375                                         'shaderName', 'Colored',
     338                                        'shaderName', 'ColoredDiffuse',
    376339                                        'diffuseColor', object.color,
    377340                                        'lineWidth', options.getfieldvalue('linewidth', 1),
     
    381344                                node.geometryShader('Mesh', mesh, 'Vertices', [object.x, object.y, object.z], 'Indices', object.indices);
    382345                        }
    383                 }
    384                 if ('city' in renderObjects) {
    385                         var object = renderObjects.city;
    386                         object = {
    387                                 enabled: defaultFor(object.enabled, false),
    388                                 name: defaultFor(object.name, 'NY'),
    389                                 size: defaultFor(object.size, 15000),
    390                                 color: defaultFor(object.color, 'magenta'),
    391                                 x: defaultFor(object.x, {}),
    392                                 y: defaultFor(object.y, {}),
    393                                 z: defaultFor(object.z, {})
    394                         };
    395                         if (object.enabled) {
     346                        if ('axis' === renderObject && !('axis' in canvas.nodes)) {             
     347                                node = new Node(
     348                                        'canvas', canvas,
     349                                        'options', options,
     350                                        'renderObject', object,
     351                                        'name', 'axis',
     352                                        'shaderName', 'Colored',
     353                                        'drawMode', gl.LINES,
     354                                        'lineWidth', options.getfieldvalue('linewidth', 1),
     355                                        'scale', [object.scale, object.scale, object.scale],
     356                                        'rotation', [0, 0, 0]
     357                                );
     358                                node.patch('Vertices', [object.x, object.y, object.z], 'FaceColor', 'none');
     359                        }
     360                        if ('city' === renderObject) {
    396361                                //city
    397362                                var mesh = GL.Mesh.sphere({size: object.size});
     
    399364                                        'canvas', canvas,
    400365                                        'options', options,
     366                                        'renderObject', object,
    401367                                        'name', 'city',
    402                                         'shaderName', 'Colored',
     368                                        'shaderName', 'ColoredDiffuse',
    403369                                        'diffuseColor', object.color,
    404370                                        'mesh', mesh,
    405371                                        'translation', [object.x, object.z, -object.y]
    406372                                );
    407                                
    408                                 var overlaycanvasid = options.getfieldvalue('overlayid', options.getfieldvalue('canvasid')+'-overlay');
    409                                 var overlaycanvas = $('#'+overlaycanvasid)[0];
    410                                 overlaycanvas.draw = function(canvas) {
    411                                         var rect = overlaycanvas.getBoundingClientRect();
    412                                         overlaycanvas.width  = rect.width;
    413                                         overlaycanvas.height = rect.height;
    414                                         var ctx = overlaycanvas.getContext('2d');
     373                                //Attatch new overlay handler to display city name
     374                                canvas.overlayHandlers['city'] = function(canvas) {
    415375                                        var node = canvas.nodes['city'];
    416                                         node.translation = [object.x, object.z, -object.y];
    417                                         node.updateModelMatrix();
     376                                        var object = node.renderObject;
    418377                                        var screenPoint = vec3.transformMat4(vec3.create(), node.translation, canvas.camera.vpMatrix);
    419378                                        var x = (screenPoint[0] + 1.0) * (canvas.width / 2) + canvas.selector.offset().left;
    420379                                        var y = (-screenPoint[1] + 1.0) * (canvas.height / 2) + canvas.selector.offset().top;
    421380
    422                                         ctx.font = String(options.getfieldvalue('colorbarfontsize', 22))+'px Arial Black, sans-serif';
     381                                        ctx.font = 'bold ' + String(options.getfieldvalue('colorbarfontsize', 22))+'px Arial Black, sans-serif';
    423382                                        ctx.fillStyle = options.getfieldvalue('colorbarfontcolor','black');
    424383                                        ctx.strokeStyle = 'white';
     
    428387                                        ctx.strokeText(object.name, x, y);
    429388                                }
    430                                 canvas.overlaycanvas = overlaycanvas;
    431                         }
    432                 }
    433                 if (canvas.clouds.enabled) {
    434                         //clouds
    435                         for (var i = 0; i < canvas.clouds.quantity; i++) {
     389                        }
     390                        if ('clouds' === renderObject && !('clouds0' in canvas.nodes)) {
     391                                //clouds                               
    436392                                var mesh = GL.Mesh.fromURL(canvas.rootPath+'obj/cloud.obj');
    437                                 translation = [translation[0] + Math.floor((Math.random() * (1 + 12000 - (-12000)) + (-12000))), translation[1] - 405000, translation[2]  + Math.floor((Math.random() * (1 + 12000 - (-12000)) + (-12000)))];
    438                                 node = new Node(
    439                                         'canvas', canvas,
    440                                         'options', options,
    441                                         'name', 'clouds' + i,
    442                                         'shaderName', 'Textured',
    443                                         'animation', {'time': Date.now(),'target': translation,'current': translation},
    444                                         'diffuseColor', [0.7,0.7,0.7,1.0],
    445                                         'mesh', mesh,
    446                                         'scale', [2500, 2500, 2500],
    447                                         'translation', translation
    448                                 );
     393                                for (var i = 0; i < object.quantity; i++) {
     394                                        //TODO: More options, less magic numbers. Add animation. Better shading.
     395                                        var offset = [  translation[0] + (Math.random() - 0.5) * 2 * object.range,
     396                                                                        translation[1] + object.height + (Math.random() - 0.5) * 0.2 * object.range,
     397                                                                        translation[2] + (Math.random() - 0.5) * 2 * object.range];
     398                                        node = new Node(
     399                                                'canvas', canvas,
     400                                                'options', options,
     401                                                'renderObject', object,
     402                                                'name', 'clouds' + i,
     403                                                'shaderName', 'ColoredDiffuse',
     404                                                'animation', {'time': Date.now(),'target': translation,'current': translation},
     405                                                'diffuseColor', [0.7,0.7,0.7,1.0],
     406                                                'specularColor', [0.0,0.0,0.0,1.0],
     407                                                'mesh', mesh,
     408                                                'scale', [object.scale, object.scale, object.scale],
     409                                                'translation', offset
     410                                        );
     411                                }
    449412                        }
    450413                }
  • issm/trunk-jpl/src/m/plot/plot_mesh.js

    r21768 r21911  
    3131        }
    3232        else {
    33                 vertices = Node.prototype.scaleVertices(md, x, y, z, options.getfieldvalue('heightscale', 1));
     33                vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskscale',{}));
    3434                scale = [1, 1, 1];
    3535        }
  • issm/trunk-jpl/src/m/plot/plot_overlay.js

    r21768 r21911  
    4141        }
    4242        else {
    43                 vertices = Node.prototype.scaleVertices(md, x, y, z, options.getfieldvalue('heightscale', 1));
     43                vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskscale',{}));
    4444                scale = [1, 1, 1];
    4545        }
     
    5252                'options', options,
    5353                'name', 'overlay',
    54                 'shaderName', 'ground' in options.getfieldvalue('render', {}) ? 'GroundFromSpace' : 'Textured',
     54                'shaderName', 'ground' in options.getfieldvalue('render', {}) ? 'GroundFromSpace' : 'TexturedDiffuse',
    5555                'alpha', options.getfieldvalue('outeralpha', 1.0),
    5656                //'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, md.mesh.classname() === 'mesh3dsurface' ? (zlim[0] + zlim[1]) / 2 : zlim[0]],
    5757                'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2],
    58                 'diffuseColor', 'white',
     58                'ambientColor', [0.1, 0.1, 0.1 ,1.0],
     59                'diffuseColor', [1.0, 1.0, 1.0 ,1.0],
     60                'specularStrength', 0.0,
    5961                'maskEnabled', options.getfieldvalue('outermask','off') == 'on',
    6062                'maskHeight', options.getfieldvalue('outermaskheight', 150.0),
     
    6567        );
    6668        //}}}
    67        
     69
    6870        var xRange = xlim[1] - xlim[0];
    6971        var yRange = ylim[1] - ylim[0];
    7072        var coordArray = [new Array(x.length), new Array(x.length)];
     73       
    7174        //generate mesh:
    72        
    7375        if (md.mesh.classname() == 'mesh3dsurface') {
    7476                var xyz, magnitude;
     
    8789                }
    8890        }
    89         node.patch('Faces', elements, 'Vertices', vertices, 'FaceVertexCData', coordArray, 'FaceColor', 'interp', 'EdgeColor', edgecolor);
     91        node.patch('Faces', elements, 'Vertices', vertices, 'FaceVertexCData', coordArray, 'FaceColor', 'interp');
    9092} //}}}
  • issm/trunk-jpl/src/m/plot/plot_quiver.js

    r21768 r21911  
    3737        }
    3838        else {
    39                 vertices = Node.prototype.scaleVertices(md, x, y, z, options.getfieldvalue('heightscale', 1));
     39                vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskscale',{}));
    4040                scale = [1, 1, 1];
    4141        }
  • issm/trunk-jpl/src/m/plot/plot_unit.js

    r21768 r21911  
    1313        //}
    1414        //else {
    15                
     15
    1616        //{{{ declare variables:
    1717        //Process data and model
     
    3737        }
    3838        else {
    39                 vertices = Node.prototype.scaleVertices(md, x, y, z, options.getfieldvalue('heightscale', 1));
     39                vertices = Node.prototype.scaleVertices(md, x, y, z, elements, options.getfieldvalue('heightscale', 1), options.getfieldvalue('maskscale',{}));
    4040                scale = [1, 1, 1];
    4141        }
    4242       
    4343        //Compute gl variables:
    44         var edgecolor = options.getfieldvalue('edgecolor', 'black');
     44        var edgecolor = options.getfieldvalue('edgecolor', [1.0, 1.0, 1.0 ,1.0]);
    4545        var maskzeros = options.getfieldvalue('maskzeros', {});
    4646        var node = new Node(
     
    4848                'options', options,
    4949                'name', 'unit',
    50                 'shaderName', 'Textured',
     50                'shaderName', 'TexturedDiffuse',
    5151                'alpha', options.getfieldvalue('alpha', 1.0),
    5252                'caxis', options.getfieldvalue('caxis',[ArrayMin(data), ArrayMax(data)]),
    5353                //'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, md.mesh.classname() === 'mesh3dsurface' ? (zlim[0] + zlim[1]) / 2 : zlim[0]],
    5454                'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2],
     55                'lightingBias', 0.8,
    5556                'diffuseColor', edgecolor,
     57                'specularStrength', 0.0,
    5658                'enabled', options.getfieldvalue('nodata','off') == 'off',
    5759                'log', options.getfieldvalue('log',false),
  • issm/trunk-jpl/src/m/plot/webgl.js

    r21768 r21911  
    99                if (!isEmptyOrUndefined(canvas.animation) && canvas.animation.handler !== 0) { clearInterval(canvas.animation.handler); }
    1010                initWebGL(canvas, options);
    11                 initializeMarker(canvas);
    1211                draw(canvas);
    1312                canvas.initialized = true;
     13               
     14                //The onStart event triggers once per plotmodel call load after WebGL and canvas initialization are complete
     15                canvas.selector.trigger('onStart', [canvas]);
    1416        }
    1517        return canvas;
     
    3436                mc.add(new Hammer.Pan({threshold: 0, pointers: 0}));
    3537                mc.add(new Hammer.Pinch({threshold: 0})).recognizeWith(mc.get('pan'));
    36                 mc.on('tap press', function (ev) {onTap(ev, canvas);});
     38                mc.on('tap', function (ev) {onTap(ev, canvas);});
    3739                mc.on('panstart panmove', function (ev) {onPan(ev, canvas, displayview);});
    38                 mc.on('pinchstart pinchmove', function (ev) {onPinch(ev, canvas, displayview);});               
     40                mc.on('pinchstart pinchmove', function (ev) {onPinch(ev, canvas, displayview);});
    3941                canvas.addEventListener('mousewheel', function (ev) {onZoom(ev, canvas, displayzoom)}, false);
    4042                canvas.addEventListener('DOMMouseScroll', function (ev) {onZoom(ev, canvas, displayzoom)}, false);
     
    4648                canvas.unitData = {};
    4749                canvas.unitMovieData = {};
     50               
    4851                canvas.gl = gl;
    4952                canvas.rootPath = options.getfieldvalue('rootpath', '../../../js/');
     
    5760       
    5861        //Add context state variables
     62        canvas.render = options.getfieldvalue('render', {});
    5963        canvas.controlSensitivity = options.getfieldvalue('controlsensitivity', 1);
     64        canvas.overlayHandlers = {};
    6065        var backgroundcolor = new RGBColor(options.getfieldvalue('backgroundcolor', 'lightcyan'));
    6166        if (backgroundcolor.ok) { canvas.backgroundcolor = [backgroundcolor.r/255.0, backgroundcolor.g/255.0, backgroundcolor.b/255.0, 1.0]; }
     
    6368       
    6469        //Property intiialization, using values from options first, then from default values.
     70        var atmosphere = options.getfieldvalue('atmosphere', {});
     71        canvas.atmosphere = {                                                                                           //Default Values
     72                wavelength_r: defaultFor(atmosphere.wavelength_r,                       0.65),          //0.65          Red wavelength (micrometers)
     73                wavelength_g: defaultFor(atmosphere.wavelength_g,                       0.57),          //0.57          Green wavelength (micrometers)
     74                wavelength_b: defaultFor(atmosphere.wavelength_b,                       0.475),         //0.475         Green wavelength (micrometers)
     75                eSun:   defaultFor(atmosphere.eSun,                                             100.0),         //20.0          Sun intensity   
     76                kRayleigh: defaultFor(atmosphere.kRayleigh,                             0.0025),        //0.0025        Rayleigh scattering amount
     77                kMie: defaultFor(atmosphere.kMie,                                                       0.000),         //0.01          Mie scattering amount
     78                g: defaultFor(atmosphere.g,                                                             -0.99),         //-0.99         Mie phase asymmetry/direction factor
     79                hdr_exposure: defaultFor(atmosphere.hdr_exposure,                       0.8),           //0.8           High Dynamic Range Exposure
     80                scaleHeight: defaultFor(atmosphere.scaleHeight,                         1.25),          //1.025         Scale of height of atmosphere to earth radius.
     81                scaleDepth: defaultFor(atmosphere.scaleDepth,                           0.25),          //0.25          Percentage altitude at which the atmosphere's average density is found
     82                a: defaultFor(atmosphere.a,                                                             -0.00287),      //-0.00287      Scaling constant a
     83                b: defaultFor(atmosphere.b,                                                             0.459),         //0.459         Scaling constant b
     84                c: defaultFor(atmosphere.c,                                                             3.83),          //3.83          Scaling constant c
     85                d: defaultFor(atmosphere.d,                                                             -6.80),         //-6.80         Scaling constant d
     86                e: defaultFor(atmosphere.e,                                                             3.6),           //5.25          Scaling constant e. Lower when increasing atmosphere scale.
     87                attenuation: defaultFor(atmosphere.attenuation,                         0.5)            //0.5           Strength of atmospheric scattering on ground shading.
     88        };
     89        updateAtmosphereParameters(canvas);
    6590        var animation = options.getfieldvalue('movies', {});
    6691        canvas.animation = {
    67                 frame: defaultFor(animation.frame, 0),
    68                 play: defaultFor(animation.play, true),
    69                 increment: defaultFor(animation.increment, true),
    70                 fps: defaultFor(animation.fps, 4),
    71                 interval: defaultFor(animation.interval, 1000 / animation.fps),
    72                 loop: defaultFor(animation.loop, true),
    73                 handler: defaultFor(animation.handler, 0)
     92                frame: defaultFor(animation.frame,                                                      0),
     93                play: defaultFor(animation.play,                                                        true),
     94                increment: defaultFor(animation.increment,                                      true),
     95                fps: defaultFor(animation.fps,                                                          4),
     96                interval: defaultFor(animation.interval,                                        1000 / defaultFor(animation.fps, 4)),
     97                loop: defaultFor(animation.loop,                                                        true),
     98                handler: defaultFor(animation.handler,                                          0)
    7499        }
    75100        var brush = options.getfieldvalue('brush', {});
    76101        canvas.brush = {
    77                 enabled: defaultFor(brush.enabled, false),
    78                 strength: defaultFor(brush.strength, 0.075),
    79                 falloff: defaultFor(brush.falloff, 0.5),
    80                 hit: defaultFor(brush.hit, {})
     102                enabled: defaultFor(brush.enabled,                                                      false),
     103                strength: defaultFor(brush.strength,                                            0.075),
     104                falloff: defaultFor(brush.falloff,                                                      0.5),
     105                hit: defaultFor(brush.hit,                                                                      {})
    81106        };
    82107        var camera = options.getfieldvalue('camera', {});
    83108        canvas.camera = {
    84                 position: defaultFor(camera.position, vec3.create()),
    85                 rotation: defaultFor(camera.rotation, vec3.create()),
    86                 near: defaultFor(camera.near, 1e3),
    87                 far: defaultFor(camera.far, 1e10),
    88                 fov: defaultFor(camera.fov, 45),
    89                 vMatrix: defaultFor(camera.vMatrix, mat4.create()),
    90                 pMatrix: defaultFor(camera.pMatrix, mat4.create()),
    91                 vpMatrix: defaultFor(camera.vpMatrix, mat4.create()),
    92                 vInverseMatrix: defaultFor(camera.vInverseMatrix, mat4.create()),
    93                 pInverseMatrix: defaultFor(camera.pInverseMatrix, mat4.create()),
    94                 vpInverseMatrix: defaultFor(camera.vpInverseMatrix, mat4.create()),
    95                 ready: defaultFor(camera.ready, false)
    96         };
    97         var clouds = options.getfieldvalue('clouds', {});
    98         canvas.clouds = {
    99                 enabled: defaultFor(clouds.enabled, false),
    100                 height: defaultFor(clouds.height, 7500),
    101                 quantity: defaultFor(clouds.quantity, 10),
    102                 hit: defaultFor(clouds.hit, {})
     109                position: defaultFor(camera.position,                                           vec3.create()),
     110                rotation: defaultFor(camera.rotation,                                           quat.create()),
     111                relativePosition: defaultFor(camera.relativePosition,           vec3.create()),
     112                direction: defaultFor(camera.direction,                                         vec3.create()),
     113                near: defaultFor(camera.near,                                                           1e3),
     114                far: defaultFor(camera.far,                                                             1e10),
     115                fov: defaultFor(camera.fov,                                                             45),
     116                vMatrix: defaultFor(camera.vMatrix,                                             mat4.create()),
     117                pMatrix: defaultFor(camera.pMatrix,                                             mat4.create()),
     118                vpMatrix: defaultFor(camera.vpMatrix,                                           mat4.create()),
     119                vInverseMatrix: defaultFor(camera.vInverseMatrix,                       mat4.create()),
     120                pInverseMatrix: defaultFor(camera.pInverseMatrix,                       mat4.create()),
     121                vpInverseMatrix: defaultFor(camera.vpInverseMatrix,             mat4.create()),
     122                ready: defaultFor(camera.ready,                                                         false)
    103123        };
    104124        var dataMarkers = options.getfieldvalue('datamarkers', {});
    105125        canvas.dataMarkers = {
    106                 enabled: defaultFor(dataMarkers.enabled, true),
    107                 values: defaultFor(dataMarkers.values, []),
    108                 image: defaultFor(dataMarkers.image, canvas.rootPath+'textures/data_marker.svg'),
    109                 size: defaultFor(dataMarkers.size, [32, 32]),
    110                 format: defaultFor(dataMarkers.format, ['X: %.2e<br>Y: %.2e<br>Z: %.2e<br>Value: %0.1f', 'x', 'y', 'z', 'value']),
    111                 animated: defaultFor(dataMarkers.animated, false),
    112                 labels: defaultFor(dataMarkers.labels, []),
    113                 font: defaultFor(dataMarkers.font, ''),
    114                 marker: defaultFor(dataMarkers.marker, document.getElementById('sim-data-marker-' + canvas.id)),
    115                 reposition: defaultFor(dataMarkers.reposition, true)
     126                enabled: defaultFor(dataMarkers.enabled,                                        true),
     127                values: defaultFor(dataMarkers.values,                                          []),
     128                image: defaultFor(dataMarkers.image,                                            canvas.rootPath + 'textures/data_marker.svg'),
     129                size: defaultFor(dataMarkers.size,                                                      [32, 32]),
     130                format: defaultFor(dataMarkers.format,                                          ['X: %.2e<br>Y: %.2e<br>Z: %.2e<br>Value: %0.1f', 'x', 'y', 'z', 'value']),
     131                animated: defaultFor(dataMarkers.animated,                                      false),
     132                labels: defaultFor(dataMarkers.labels,                                          []),
     133                font: defaultFor(dataMarkers.font,                                                      ''),
     134                marker: defaultFor(dataMarkers.marker,                                          document.getElementById('sim-data-marker-' + canvas.id)),
     135                reposition: defaultFor(dataMarkers.reposition,                          true)
    116136        };
    117137        var draw = options.getfieldvalue('draw', {});
    118138        canvas.draw = {
    119                 ready: defaultFor(draw.ready, false),
    120                 handler: defaultFor(draw.handler, null)
     139                ready: defaultFor(draw.ready,                                                           false),
     140                handler: defaultFor(draw.handler,                                                       null)
    121141        };
    122142        var view = options.getfieldvalue('view', {});
    123143        canvas.view = {
    124                 position: defaultFor(view.position, [0.0, 0.0, 0.0]),
    125                 rotation: defaultFor(view.rotation, [0, 90]),
    126                 zoom: defaultFor(view.zoom, 1.0),
    127                 zoomLimits: defaultFor(view.zoomLimits, [0.001, 100.0]),
    128                 lastZoom: defaultFor(view.lastZoom, 1.0),
    129                 azimuthLimits: defaultFor(view.azimuthLimits, [0, 360]),
    130                 elevationLimits: defaultFor(view.elevationLimits, [-180, 180]),
    131                 panningEnabled: defaultFor(view.panningEnabled, false),
    132                 twod: defaultFor(view.twod, false)
     144                position: defaultFor(view.position,                                             [0.0, 0.0, 0.0]),
     145                rotation: defaultFor(view.rotation,                                             [0, 90]),
     146                zoom: defaultFor(view.zoom,                                                             1.0),
     147                zoomLimits: defaultFor(view.zoomLimits,                                         [0.001, 100.0]),
     148                lastZoom: defaultFor(view.lastZoom,                                             1.0),
     149                azimuthLimits: defaultFor(view.azimuthLimits,                           [0, 360]),
     150                elevationLimits: defaultFor(view.elevationLimits,                       [-180, 180]),
     151                panningEnabled: defaultFor(view.panningEnabled,                         false),
     152                preventDefaultOnPan: defaultFor(view.preventDefaultOnPan,       false),
     153                twod: defaultFor(view.twod,                                                             false)
    133154        };
    134155
     
    171192        var shaders = {};
    172193        shaders.Colored = new GL.Shader.fromURL(rootPath+'shaders/Colored.vsh', rootPath+'shaders/Colored.fsh', null, gl);
     194        shaders.ColoredDiffuse = new GL.Shader.fromURL(rootPath+'shaders/ColoredDiffuse.vsh', rootPath+'shaders/ColoredDiffuse.fsh', null, gl);
    173195        shaders.Textured = new GL.Shader.fromURL(rootPath+'shaders/Textured.vsh', rootPath+'shaders/Textured.fsh', null, gl);
     196        shaders.TexturedDiffuse = new GL.Shader.fromURL(rootPath+'shaders/TexturedDiffuse.vsh', rootPath+'shaders/TexturedDiffuse.fsh', null, gl);
    174197        shaders.SkyFromSpace = new GL.Shader.fromURL(rootPath+'shaders/SkyFromSpace.vert', rootPath+'shaders/SkyFromSpace.frag', null, gl);
    175198        shaders.GroundFromSpace = new GL.Shader.fromURL(rootPath+'shaders/GroundFromSpace.vert', rootPath+'shaders/GroundFromSpace.frag', null, gl);
    176         shaders.Clouds = new GL.Shader.fromURL(rootPath+'shaders/Clouds.vert', rootPath+'shaders/Clouds.frag', null, gl);
    177199        return shaders;
    178200} //}}}
     
    184206        return gl.textures[imageSource];
    185207} //}}}
     208function updateAtmosphereParameters(canvas) {
     209        //Precalculate derived atmosphere shader parameters
     210        //TODO: Find a better way to structure this
     211        var atm = canvas.atmosphere;
     212        atm.inv_wavelength4 = [1.0 / Math.pow(atm.wavelength_r, 4), 1.0 / Math.pow(atm.wavelength_g, 4), 1.0 / Math.pow(atm.wavelength_b, 4)];
     213        atm.innerRadius = 6.371e6;
     214        atm.innerRadius2 = atm.innerRadius * atm.innerRadius;
     215        atm.outerRadius = atm.innerRadius * atm.scaleHeight;
     216        atm.outerRadius2 = atm.outerRadius * atm.outerRadius;
     217        atm.krESun = atm.kRayleigh * atm.eSun;
     218        atm.kmESun = atm.kMie * atm.eSun;
     219        atm.kr4PI = atm.kRayleigh * 4 * Math.PI;
     220        atm.km4PI = atm.kMie * 4 * Math.PI;
     221        atm.scale = 1.0 / (atm.outerRadius - atm.innerRadius);
     222        atm.scaleOverScaleDepth = atm.scale / atm.scaleDepth;
     223        atm.g2 = atm.g * atm.g;
     224        canvas.atmosphere = atm;
     225}
    186226function clamp(value, min, max) { //{{{
    187227        return Math.max(min, Math.min(value, max));
     
    253293} //}}}
    254294//}}}
    255 //{{{ Interface Functions
     295//{{{ Interaction Functions
    256296function onTap(ev, canvas) { //{{{
    257         //Sets up a marker on a canvas that will track a point on the mesh. Can be dismissed by closing the display or clicking the marker.
    258297        ev.preventDefault();
    259298       
    260         if (canvas.clouds.enabled) {
    261                 for (var i = 0; i < canvas.clouds.quantity; i++) {
    262                         raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.nodes["clouds" + i]);
    263                 }
    264         }
    265         var hit = raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.unitNode);
    266         if ('cities' in canvas.nodes) {
    267                 var hitCities = raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.nodes.cities);
    268                 canvas.nodes.cities.hit = hitCities;
    269                 updateCities(canvas);
    270         }
    271 
    272         canvas.brush.hit = hit;
    273        
    274         if (canvas.dataMarkers.enabled) {
    275                 canvas.dataMarkers.marker.selector.closed = false;
    276                 canvas.dataMarkers.marker.hit = hit;
    277                 updateMarker(canvas, true);
    278         }
    279        
    280         brushModify(canvas);
     299        var hit = raycastXY(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.unitNode);
     300
     301        //Trigger any handlers attatched to this canvas event.
     302        canvas.selector.trigger('onTap', [ev, canvas, hit]);
    281303} //}}}
    282304function onPan(ev, canvas, displaylog) { //{{{
    283305        ev.preventDefault();
    284        
    285         if (canvas.dataMarkers.enabled) {
    286                 if (!isEmptyOrUndefined(canvas.unitNode)) {
    287                         canvas.brush.hit = raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.unitNode);
    288                         brushModify(canvas);
    289                 }
    290         }
    291        
    292         if (canvas.clouds.enabled) {
    293                 if (!isEmptyOrUndefined(canvas.nodes['overlay'])) {
    294                         canvas.clouds.hit = raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.nodes['overlay']);
    295                         updateClouds(canvas);
    296                 }
    297         }
    298306       
    299307        if (ev.type === 'panstart') {
     
    301309                canvas.lastDeltaY = 0;
    302310        }
    303         if (ev.srcEvent.shiftKey || ev.pointers.length === 2) {
    304                 if (!canvas.view.panningEnabled) return;
    305                 var deltaX = (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth / canvas.view.zoom * 2 * canvas.controlSensitivity * 6.371e6;
    306                 var deltaY = (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight / canvas.view.zoom * 2 * canvas.controlSensitivity * 6.371e6;
    307                
    308                 if (canvas.view.twod) {
    309                         canvas.view.position[0] += Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaX - Math.sin(DEG2RAD * 0) * deltaY;
    310                         canvas.view.position[2] += Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaX + Math.cos(DEG2RAD * 0) * deltaY;
     311       
     312        //Trigger any handlers attatched to this canvas event.
     313        canvas.selector.trigger('onPan', [ev, canvas]);
     314       
     315        //If any onPan handler sets preventDefaultOnPan to true, skips default onPan camera behavior
     316        if (!canvas.view.preventDefaultOnPan) {
     317                //If panning with two fingers or shift key, translate camera center
     318                if (ev.srcEvent.shiftKey || ev.pointers.length === 2) {
     319                        if (canvas.view.panningEnabled) {
     320                                var deltaX = (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth / canvas.view.zoom * 2 * canvas.controlSensitivity * 6.371e6;
     321                                var deltaY = (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight / canvas.view.zoom * 2 * canvas.controlSensitivity * 6.371e6;
     322                               
     323                                //TODO: convert canvas.view.rotation from az/el euler to quaternion
     324                                if (canvas.view.twod) {
     325                                        canvas.view.position[0] += Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaX - Math.sin(DEG2RAD * 0) * deltaY;
     326                                        canvas.view.position[2] += Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaX + Math.cos(DEG2RAD * 0) * deltaY;
     327                                }
     328                                else {
     329                                        canvas.view.position[0] += Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaX - Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaY;
     330                                        canvas.view.position[2] += Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaX + Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaY;
     331                                }
     332                        }
    311333                }
     334                //Else, rotate around camera center
    312335                else {
    313                         canvas.view.position[0] += Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaX - Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaY;
    314                         canvas.view.position[2] += Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaX + Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaY;
     336                        canvas.view.rotation[0] += (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth * 2 * canvas.controlSensitivity * RAD2DEG;
     337                        canvas.view.rotation[1] += (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight * -2 * canvas.controlSensitivity * RAD2DEG;
     338                       
     339                        if (canvas.view.rotation[0] > 360) { canvas.view.rotation[0] -= 360; };
     340                        if (canvas.view.rotation[0] < -360) { canvas.view.rotation[0] += 360; };
     341                        if (canvas.view.rotation[1] > 180) { canvas.view.rotation[1] -= 360; };
     342                        if (canvas.view.rotation[1] < -180) { canvas.view.rotation[1] += 360; };
     343                       
     344                        canvas.view.rotation[0] = clamp(canvas.view.rotation[0], canvas.view.azimuthLimits[0], canvas.view.azimuthLimits[1]);
     345                        canvas.view.rotation[1] = clamp(canvas.view.rotation[1], canvas.view.elevationLimits[0], canvas.view.elevationLimits[1]);
     346                       
     347                        if (displaylog) { console.log(canvas.view.rotation); }
    315348                }
    316         }
    317        
    318         else {
    319                 canvas.view.rotation[0] += (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth * 2 * canvas.controlSensitivity * RAD2DEG;
    320                 canvas.view.rotation[1] += (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight * -2 * canvas.controlSensitivity * RAD2DEG;
    321                
    322                 if (canvas.view.rotation[0] > 360) { canvas.view.rotation[0] -= 360; };
    323                 if (canvas.view.rotation[0] < -360) { canvas.view.rotation[0] += 360; };
    324                 if (canvas.view.rotation[1] > 180) { canvas.view.rotation[1] -= 360; };
    325                 if (canvas.view.rotation[1] < -180) { canvas.view.rotation[1] += 360; };
    326                
    327                 canvas.view.rotation[0] = clamp(canvas.view.rotation[0], canvas.view.azimuthLimits[0], canvas.view.azimuthLimits[1]);
    328                 canvas.view.rotation[1] = clamp(canvas.view.rotation[1], canvas.view.elevationLimits[0], canvas.view.elevationLimits[1])
    329         }
     349        }       
     350       
     351        canvas.view.preventDefaultOnPan = false;
    330352        canvas.lastDeltaX = ev.deltaX;
    331353        canvas.lastDeltaY = ev.deltaY;
    332        
    333         canvas.dataMarkers.reposition = true;
    334        
    335         if (displaylog) { console.log(canvas.view.rotation); }
    336354} //}}}
    337355function onPinch(ev, canvas, displaylog) { //{{{
    338356        ev.preventDefault();
    339357        if (ev.type === 'pinchstart') { canvas.view.lastZoom = canvas.view.zoom; }
    340         else { modifyZoom(ev.scale * canvas.view.lastZoom, canvas, displaylog); }
     358        else { modifyZoom(ev.scale * canvas.view.lastZoom, canvas, displaylog, ev, 0); }
    341359} //}}}
    342360function onZoom(ev, canvas, displaylog) { //{{{
    343361        ev.preventDefault();
    344         var delta = clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.view.zoom / 20;
    345         modifyZoom(canvas.view.zoom + delta, canvas, displaylog);
    346 } //}}}
    347 function modifyZoom(value, canvas, displaylog) { //{{{
    348         canvas.view.zoom = clamp(value, canvas.view.zoomLimits[0], canvas.view.zoomLimits[1]);
    349         canvas.dataMarkers.reposition = true;
    350         if (displaylog) { console.log(canvas.view.zoom); }
    351 } //}}}
    352 function modifyDataMarkersEnabled(value, canvas) { //{{{
    353         canvas.dataMarkers.enabled = value;
     362        var delta = clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.view.zoom / 2;
     363        modifyZoom(canvas.view.zoom + delta, canvas, displaylog, ev, 0);
     364} //}}}
     365function modifyZoom(value, canvas, displaylog, ev, duration) { //{{{
     366        if (isEmptyOrUndefined(duration)) duration = 200;
     367        var targetZoom = clamp(value, canvas.view.zoomLimits[0], canvas.view.zoomLimits[1]);
     368        var currentZoom = canvas.view.zoom;
     369        animateValue(
     370                0,
     371                1.0,
     372                duration,
     373                function(value, info) {
     374                        canvas.view.zoom = currentZoom * (1 - value) + targetZoom * value;
     375                        if (displaylog) { console.log(canvas.view.zoom); }
     376                       
     377                        //Trigger any handlers attatched to this canvas event.
     378                        canvas.selector.trigger('onZoom', [ev, canvas]);
     379                }
     380        );
    354381} //}}}
    355382function toggleMoviePlay(canvas) { //{{{
     
    364391        }
    365392} //}}}
    366 //}}}
    367 //{{{ Interaction Functions
    368 function raycast(canvas, x, y, node) { //{{{
    369         //Performs raycast on canvas.unitNode.mesh using x/y screen coordinates. Returns hit objects with hit position, coords, and indicies of ray-triangle intersection.
     393function screenToWorldPoint(canvas, x, y) { //{{{
     394        var viewportX = (x - canvas.width / 2) / (canvas.width / 2);
     395        var viewportY = (canvas.height / 2 - y) / (canvas.height / 2);
     396        var origin = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 0], canvas.camera.vpInverseMatrix);
     397        return origin;
     398} //}}}
     399function screenToModelRay(canvas, x, y, node) { //{{{
     400        var inverseMVPMatrix = mat4.invert(mat4.create(), mat4.multiply(mat4.create(), canvas.camera.vpMatrix, node.modelMatrix));
     401        var viewportX = (x - canvas.width / 2) / (canvas.width / 2);
     402        var viewportY = (canvas.height / 2 - y) / (canvas.height / 2);
     403        var origin = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 0], inverseMVPMatrix);
     404        var far = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 1.0], inverseMVPMatrix);
     405        var direction = vec3.subtract(vec3.create(), far, origin);
     406        return {'origin':origin, 'direction':direction};
     407} //}}}
     408function raycast(canvas, origin, direction, node) { //{{{
     409        //Performs raycast on given node using ray origin and direction vectors.
     410        //Returns hit objects with hit position, normals, barycentric coordinates, element number, and indices of ray-triangle intersection.
    370411        //TODO: Diagnose marker issues with orthographic views and slr-eustatic updates when switching between basins.
    371         var inverseMVPMatrix = mat4.invert(mat4.create(), mat4.multiply(mat4.create(), canvas.camera.vpMatrix, node.modelMatrix));
    372         var origin = vec3.transformMat4(vec3.create(), [(x - canvas.width / 2) / (canvas.width / 2), (canvas.height / 2 - y) / (canvas.height / 2), 0], inverseMVPMatrix);
    373         var far = far || vec3.transformMat4(vec3.create(), [(x - canvas.width / 2) / (canvas.width / 2), (canvas.height / 2 - y) / (canvas.height / 2), 1.0], inverseMVPMatrix);
    374         var ray = vec3.subtract(vec3.create(), far, origin);
    375 
    376         var mesh = node.mesh;
    377 
    378         if (!mesh) { return; }
    379         if (!node.octree) { node.octree = new GL.Octree(mesh); }
    380        
    381         var hit = node.octree.testRay(origin, ray, 1e3, 1e10);
    382        
    383         if(!hit) { return; }
    384 
    385         if (node.name.startsWith("clouds")) { canvas.clouds.selected = node.name; alert("New selected cloud: " + canvas.clouds.selected); }
     412        if (!node.octree) { node.octree = new GL.Octree(node.mesh); }
     413       
     414        var hit = node.octree.testRay(origin, direction, 1e3, 1e10);
     415        if (!hit) { return; }
    386416
    387417        hit.modelPos = vec3.copy(vec3.create(), hit.pos);
    388418        vec3.transformMat4(hit.pos, hit.pos, node.modelMatrix);
    389         vec3.transformMat4(hit.normal, hit.normal, node.modelMatrix);
    390 
     419       
    391420        return hit;
    392421} //}}}
    393 function updateCities(canvas) {
    394         //Update selected city
    395         var hit = canvas.nodes.cities.hit;
    396         if (hit) {
    397                 citiesIndex = Math.floor(hit.indices[0] / ((ArrayMax(canvas.nodes.cities.mesh.getIndexBuffer('triangles').data) + 1) / cities.length));
    398                 cityName = cities[citiesIndex];
    399                 if (cityName !== $('#gfm-sim-controls-select-city').val()) {
    400                         $('#gfm-sim-controls-select-city').val(cityName).selectmenu("refresh");
    401                         changeCity(canvas);
    402                 }
    403         }
    404 }
    405 function brushModify(canvas) { //{{{
    406         //This function takes in the canvas and x/y coordinates, performing a raycast against the mesh, and modifies the mesh using a the canvas.brush.strength and canvas.brush.falloff properties.
    407         //Currently the brush extends to the raycasted element and its immediate neighbors.
    408         //TODO: Allow variable brush size/additional neighbors. Allow the function to work on multiple models (currently hardcoded to md model).
    409         if (!canvas.unitNode || canvas.brush.enabled != 'on') { return; }
    410        
    411         var hit = canvas.brush.hit;
    412 
    413         if (hit) {
    414                 var bufferVertices = canvas.unitNode.mesh.getBuffer('vertices');
    415                 var vertices = bufferVertices.data;
    416                 var bufferCoords = canvas.unitNode.mesh.getBuffer('coords');
    417                 var coords = bufferCoords.data;
    418 
    419                 //Query nearby elements and store indicies of affected vertices using pregenerated vertexconnectivity list (from NodeConnectivity)
    420                 var baseIndices = new Set(hit.indices);
    421                 var connectedIndices = new Set(hit.indices);
    422                 var connectedElement;
    423                 var indices;
    424                 var lengthIndex = md.mesh.vertexconnectivity[0].length - 1;
    425                 var length;
    426                 for (var i = 0; i < 3; i++) {
    427                         length = md.mesh.vertexconnectivity[hit.indices[i]][lengthIndex];
    428                         for (var j = 0; j < length; j++) {
    429                                 //Shift elements down by one (matlab 1-based index to 0-based index)
    430                                 connectedElement = md.mesh.vertexconnectivity[hit.indices[i]][j] - 1;
    431                                 indices = md.mesh.elements[connectedElement];
    432                                 connectedIndices.add(indices[0] - 1);
    433                                 connectedIndices.add(indices[1] - 1);
    434                                 connectedIndices.add(indices[2] - 1);
    435                         }
    436                 }
    437 
    438                 //Apply modifications to included vertices in mesh using brush strength and falloff.
    439                 var strength;
    440                 for (var index of connectedIndices) {
    441                         if (!baseIndices.has(index)) {
    442                                 strength = canvas.brush.strength * canvas.brush.falloff;
    443                         }
    444                         else {
    445                                 strength = canvas.brush.strength;
    446                         }
    447                         vertices[index*3+2] += strength * 100;
    448                         md.geometry.surface[index] += strength;
    449                         md.geometry.thickness[index] += strength;
    450                         coords[index*2+1] += strength;
    451                         canvas.unitData[index] += strength;
    452                 }
    453                
    454                 //Update mesh on GPU
    455                 bufferVertices.upload(canvas.gl.DYNAMIC_DRAW);
    456                 bufferCoords.upload(canvas.gl.DYNAMIC_DRAW);
    457                 canvas.unitNode.octree = new GL.Octree(canvas.unitNode.mesh);   
    458         }
    459 } //}}}
    460 function updateClouds(canvas) {
    461         //Update clouds if rendered
    462         //TODO: Steven, the hit now queries the radaroverlay.
    463         if (canvas.nodes[canvas.clouds.selected]) {
    464                 var v1 = vec3.fromValues(vertices[hit.indices[0] * 3], vertices[hit.indices[0] * 3 + 1], vertices[hit.indices[0] * 3 + 2]);
    465                 var v2 = vec3.fromValues(vertices[hit.indices[1] * 3], vertices[hit.indices[1] * 3 + 1], vertices[hit.indices[1] * 3 + 2]);
    466                 var v3 = vec3.fromValues(vertices[hit.indices[2] * 3], vertices[hit.indices[2] * 3 + 1], vertices[hit.indices[2] * 3 + 2]);
    467                 vec3.transformMat4(v1, v1, canvas.unitNode.modelMatrix);//move out of brushModify, perhaps onto onPan
    468                 vec3.transformMat4(v2, v2, canvas.unitNode.modelMatrix);
    469                 vec3.transformMat4(v3, v3, canvas.unitNode.modelMatrix);
    470                 var x  = (v1[0] + v2[0] + v3[0]) / 3;// + Math.floor((Math.random() * (1 + 10000 - (-10000)) + (-10000)));
    471                 var y  = (v1[1] + v2[1] + v3[1]) / 3;// + Math.floor((Math.random() * (1 + 10000 - (-10000)) + (-10000)));
    472                 var z  = (v1[2] + v2[2] + v3[2]) / 3;
    473                 canvas.nodes[canvas.clouds.selected].translation = [x, y + canvas.clouds.height, z];
    474                 updateModelMatrix(canvas.nodes[canvas.clouds.selected]);
    475         }
    476 }
    477 function initializeMarker(canvas) { //{{{
    478         //Initialize data marker and tooltip display once per page load
    479         var marker = $('#' + canvas.dataMarkers.marker.id);
    480         var size = canvas.dataMarkers.size;
    481         if (!marker.hasClass('tooltipstered')) {
    482                 marker.css({
    483                         'position': 'absolute',
    484                         'left': -size[0] + 'px',
    485                         'top': -size[1] + '0px',
    486                         'width': size[0] + 'px',
    487                         'height': size[1] + 'px',
    488                         'pointer-events': 'all',
    489                         'cursor': 'pointer',
    490                         'display': 'none'
    491                 });
    492                 marker.tooltipster({
    493                         contentAsHTML: true,
    494                         maxWidth: 320,
    495                         maxHeight: 320,
    496                         zIndex: 1000,
    497                         trigger: 'custom',
    498                         triggerOpen: {
    499                                 mouseenter: false,
    500                                 originClick: true,
    501                                 touchstart: false
    502                         },
    503                         triggerClose: {
    504                                 mouseleave: false,
    505                                 originClick: true,
    506                                 touchleave: false
    507                         },
    508                 });
    509                 marker.on('click touch', function () {
    510                         marker.fadeOut(175);
    511                         marker.tooltipster('close');
    512                         marker.closed = true;
    513                 });
    514                 marker.closed = false;
    515                 canvas.dataMarkers.marker.selector = marker;
    516         }
    517         updateMarker(canvas, true);
    518 } //}}}
    519 function repositionMarker(canvas) { //{{{
    520         //Mover marker to point to mouse position, offset in y by 1 to enable immediate clicking.
    521         //Return if no marker hit exists, the camera is not rendering, or if no reposition has been scheduled.
    522         if (isEmptyOrUndefined(canvas.dataMarkers.marker.hit) || !canvas.camera.ready || !canvas.dataMarkers.reposition) { return; }
    523         var size = canvas.dataMarkers.size;
    524         var screenPoint = vec3.transformMat4(vec3.create(), canvas.dataMarkers.marker.hit.pos, canvas.camera.vpMatrix);
    525         var x = (screenPoint[0] + 1.0) * (canvas.width / 2) + canvas.selector.offset().left;
    526         var y = (-screenPoint[1] + 1.0) * (canvas.height / 2) + canvas.selector.offset().top;
    527         canvas.dataMarkers.marker.selector.css({
    528                 'left': (Math.round(x) - size[0] / 2) + 'px',
    529                 'top': (Math.round(y) - size[1] + 1) + 'px'
    530         });
    531         if (canvas.dataMarkers.marker.selector.tooltipster('status').state != 'closed') { canvas.dataMarkers.marker.selector.tooltipster('reposition'); }
    532         canvas.dataMarkers.reposition = false;
    533 } //}}}
    534 function updateMarker(canvas, reset) { //{{{
    535         //Retrieve data value fields and plots them on data marker popup if a hit has been registered.
    536         //TODO: Automatically pick up any field of size md.mesh.numberofelements
    537         //If no marker has been placed, no update is needed. If canvas is resimulating and unitNode has not been set yet, wait and try again.
    538         if (!canvas.dataMarkers.enabled || isEmptyOrUndefined(canvas.dataMarkers.marker.hit)) { return; }
    539         if (isEmptyOrUndefined(canvas.unitNode) || isEmptyOrUndefined(canvas.unitNode.mesh)) { setTimeout( function(){ updateMarker(canvas, reset); }, 750); return; }
    540        
    541         var hit = canvas.dataMarkers.marker.hit;
    542        
    543         var coords = canvas.unitNode.mesh.vertexBuffers.coords.data;
    544         var latitude = md.mesh.lat;
    545         var longitude = md.mesh.long;
    546         var thickness;
    547         var velocity;
    548         if (md.results[0]) {
    549                 thickness = md.results[canvas.animation.frame].Thickness;
    550                 velocity = md.results[canvas.animation.frame].Vel;
    551         }
    552         else {
    553                 thickness = md.geometry.thickness;
    554                 velocity = md.initialization.vel;
    555         }
    556        
    557         //Construct new argument array of the data display format for sprintf using first first argument as the formatSpecifier string and the rest as the additional arguments.
    558         var labels = canvas.dataMarkers.labels.slice();
    559         for (var i = 0; i < labels.length; i++) {
    560                 if (labels[i].toLowerCase() === 'x') { labels[i] = hit.modelPos[0]; }
    561                 else if (labels[i].toLowerCase() === 'y') { labels[i] = hit.modelPos[1]; }
    562                 else if (labels[i].toLowerCase() === 'z') { labels[i] = hit.modelPos[2]; }
    563                 else if (labels[i].toLowerCase() === 'latitude') {
    564                         var hitLatitude = [latitude[hit.indices[0]], latitude[hit.indices[1]], latitude[hit.indices[2]]];
    565                         var valueLatitude = Math.abs(hitLatitude[0] * hit.uvw[0] + hitLatitude[1] * hit.uvw[1] + hitLatitude[2] * hit.uvw[2]);
    566                         labels[i] = valueLatitude;
    567                 }
    568                 else if (labels[i].toLowerCase() === 'longitude') {
    569                         var hitLongitude = [longitude[hit.indices[0]], longitude[hit.indices[1]], longitude[hit.indices[2]]];
    570                         var valueLongitude = Math.abs(hitLongitude[0] * hit.uvw[0] + hitLongitude[1] * hit.uvw[1] + hitLongitude[2] * hit.uvw[2]);
    571                         labels[i] = valueLongitude;
    572                 }
    573                 else if (labels[i].toLowerCase() === 'thickness') {
    574                         var hitThickness = [thickness[hit.indices[0]], thickness[hit.indices[1]], thickness[hit.indices[2]]];
    575                         var valueThickness = hitThickness[0] * hit.uvw[0] + hitThickness[1] * hit.uvw[1] + hitThickness[2] * hit.uvw[2];
    576                         labels[i] = valueThickness;
    577                 }
    578                 else if (labels[i].toLowerCase() === 'velocity') {
    579                         var hitVelocity = [velocity[hit.indices[0]], velocity[hit.indices[1]], velocity[hit.indices[2]]];
    580                         var valueVelocity = hitVelocity[0] * hit.uvw[0] + hitVelocity[1] * hit.uvw[1] + hitVelocity[2] * hit.uvw[2];   
    581                         labels[i] = valueVelocity;
    582                 }
    583                 else if (labels[i].toLowerCase() === 'value') {
    584                         var hitCoords = [coords[hit.indices[0]*2], coords[hit.indices[0]*2+1], coords[hit.indices[1]*2], coords[hit.indices[1]*2+1], coords[hit.indices[2]*2], coords[hit.indices[2]*2+1]];
    585                         var u = hitCoords[0] * hit.uvw[0] + hitCoords[2] * hit.uvw[1] + hitCoords[4] * hit.uvw[2];
    586                         var v = hitCoords[1] * hit.uvw[0] + hitCoords[3] * hit.uvw[1] + hitCoords[5] * hit.uvw[2];
    587                         var value = canvas.unitNode.caxis[0] * (1.0 - v) + canvas.unitNode.caxis[1] * v;
    588                         labels[i] = value;
    589                 }
    590         }
    591        
    592         //Apply changes to tooltip
    593         $('#tooltip-content-data-marker-' + canvas.id).html(sprintf.apply(null, canvas.dataMarkers.format.concat(labels)));
    594         $('#tooltip-content-data-marker-' + canvas.id).css({'font': canvas.dataMarkers.font});                         
    595        
    596         //If animated, setup animation loop to update plot as movie plays.
    597         if (canvas.dataMarkers.animated) {
    598                 var isEmpty = (canvas.dataMarkers.values.length === 0);
    599                 var lastUpdatedIndex = (canvas.dataMarkers.values.length - 1);
    600                 var newMovieFrame = (!isEmpty && canvas.dataMarkers.values[lastUpdatedIndex][0] != canvas.animation.frame);
    601                 //If new data marker has been placed, reinitialize plot. If not, push new value into plot value array.
    602                 if (reset) {
    603                         canvas.dataMarkers.values = [];
    604                         newMovieFrame = true;
    605                         for (var currentFrame = 0; currentFrame < (canvas.unitNode.movieLength); currentFrame++) {
    606                                 coords = canvas.unitMovieData[currentFrame];
    607                                 var hitCoords = [coords[hit.indices[0]*2], coords[hit.indices[0]*2+1], coords[hit.indices[1]*2], coords[hit.indices[1]*2+1], coords[hit.indices[2]*2], coords[hit.indices[2]*2+1]];
    608                                 var u = hitCoords[0] * hit.uvw[0] + hitCoords[2] * hit.uvw[1] + hitCoords[4] * hit.uvw[2];
    609                                 var v = hitCoords[1] * hit.uvw[0] + hitCoords[3] * hit.uvw[1] + hitCoords[5] * hit.uvw[2];
    610                                 var value = canvas.unitNode.caxis[0] * (1.0 - v) + canvas.unitNode.caxis[1] * v;
    611                                 canvas.dataMarkers.values.push([currentFrame, value]);
    612                         }
    613                 }
    614                 else {
    615                         if (canvas.animation.lastFrame > canvas.animation.frame) {
    616                                 canvas.dataMarkers.values = [];
    617                         }
    618                         if (isEmpty || newMovieFrame) {
    619                                 coords = canvas.unitMovieData[canvas.animation.frame];
    620                                 var hitValues = [coords[hit.indices[0]], coords[hit.indices[1]], coords[hit.indices[2]]];
    621                                 var value = hitValues[0] * hit.uvw[0] + hitValues[1] * hit.uvw[1] + hitValues[2] * hit.uvw[2]; 
    622                                 canvas.dataMarkers.values.push([canvas.animation.frame, value]);
    623                         }
    624                 }
    625                
    626                 //Replot data marker popup using update data value array.
    627                 if (isEmpty || newMovieFrame) {
    628                         var dataLabels = {'latitude': valueLatitude, 'longitude': valueLongitude, 'thickness': valueThickness, 'velocity': valueVelocity, 'value': value};
    629                         var dataDisplay = canvas.dataMarkers.values.slice(0, canvas.animation.frame + 1);               
    630                         plot(
    631                                 'id', '#sim-plot',
    632                                 'type', 'bar',
    633                                 'width', 400,
    634                                 'height', 300,
    635                                 'nticks', 25,
    636                                 'xlabel', 'Time',
    637                                 'ylabel', 'Value',
    638                                 'title', 'Changes Over Time',
    639                                 'datalabels', canvas.dataMarkers.labels,
    640                                 'labelvalues', dataLabels,
    641                                 'data', dataDisplay
    642                         );
    643                 }
    644         }
    645         canvas.dataMarkers.reposition = true;
    646         if (reset && !canvas.dataMarkers.marker.selector.closed) {
    647                 canvas.dataMarkers.marker.selector.fadeIn(175);
    648                 canvas.dataMarkers.marker.selector.tooltipster('open');
    649         }
     422function raycastXY(canvas, x, y, node) { //{{{
     423        //Performs raycast on given node using x and y screenspace coordinates.
     424        //Returns hit objects with hit position, normals, barycentric coordinates, element number, and indices of ray-triangle intersection.
     425        //TODO: Diagnose marker issues with orthographic views and slr-eustatic updates when switching between basins.
     426        var ray = screenToModelRay(canvas, x, y, node);
     427        return raycast(canvas, ray.origin, ray.direction, node);
    650428} //}}}
    651429function animateValue(current, target, duration, stepCallback, doneCallback) { //{{{
     
    669447        var elevationRotationMatrix = mat4.create();
    670448        var aspectRatio = canvas.clientWidth / canvas.clientHeight;
    671         var cameraPosition = vec3.create();
    672 
    673         if (canvas.view.twod) { mat4.ortho(pMatrix, -aspectRatio*6.371e6/canvas.view.zoom, aspectRatio*6.371e6/canvas.view.zoom, -6.371e6/canvas.view.zoom, 6.371e6/canvas.view.zoom, canvas.camera.near, canvas.camera.far); }
    674         else { mat4.perspective(pMatrix, canvas.camera.fov * DEG2RAD, aspectRatio, canvas.camera.near, canvas.camera.far); }
     449        var camera = canvas.camera;
     450        var view = canvas.view;
     451
     452        if (view.twod) { mat4.ortho(pMatrix, -aspectRatio*6.371e6/view.zoom, aspectRatio*6.371e6/view.zoom, -6.371e6/view.zoom, 6.371e6/view.zoom, camera.near, camera.far); }
     453        else { mat4.perspective(pMatrix, camera.fov * DEG2RAD, aspectRatio, camera.near, camera.far); }
    675454       
    676455        //Apply worldspace translation
    677         mat4.translate(vMatrix, translateMatrix, vec3.negate(vec3.create(), canvas.view.position));
     456        mat4.translate(vMatrix, translateMatrix, vec3.negate(vec3.create(), view.position));
    678457       
    679458        //Calculate rotation around camera focal point about worldspace origin
    680         if (canvas.view.twod) {
     459        if (view.twod) {
    681460                mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -DEG2RAD * 0, [0, 1, 0]);
    682461                mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * 90, [1, 0, 0]);
     
    684463        }
    685464        else {
    686                 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -DEG2RAD * (canvas.view.rotation[0] + 90), [0, 1, 0]);
    687                 mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * canvas.view.rotation[1], [1, 0, 0]);
     465                mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -DEG2RAD * (view.rotation[0] + 90), [0, 1, 0]);
     466                mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * view.rotation[1], [1, 0, 0]);
    688467                mat4.multiply(rotationMatrix, elevationRotationMatrix, azimuthRotationMatrix);
     468                //var quaternionWorldX = Node.prototype.eulerToQuaternion(0, 0, DEG2RAD * (view.rotation[0]));
     469                //var quaternionWorldY = Node.prototype.eulerToQuaternion(0, DEG2RAD * (view.rotation[1]), 0);
     470                //var quaternionWorldZ = Node.prototype.eulerToQuaternion(DEG2RAD * (view.rotation[2]), 0, 0);
     471                //var quaternionTemp = quat.multiply(quat.create(), quaternionWorldY, quaternionWorldX);
     472                //quat.multiply(camera.rotation, quaternionWorldZ, quaternionTemp);
     473                //mat4.fromQuat(rotationMatrix, camera.rotation);       
    689474        }
    690475
     
    694479        //Apply screenspace translation to emulate rotation around point
    695480        mat4.identity(translateMatrix);
    696         mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -6.371e6/canvas.view.zoom]);
     481        mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -6.371e6/view.zoom]);
    697482        mat4.multiply(vMatrix, translateMatrix, vMatrix);
    698483       
    699484        //Apply projection matrix to get camera matrix
    700         mat4.copy(canvas.camera.vMatrix, vMatrix);
    701         mat4.multiply(canvas.camera.vpMatrix, pMatrix, vMatrix);
     485        mat4.copy(camera.vMatrix, vMatrix);
     486        mat4.multiply(camera.vpMatrix, pMatrix, vMatrix);
    702487       
    703488        //Calculate inverse view matrix fields for lighting and raycasts
    704         mat4.invert(canvas.camera.vInverseMatrix, canvas.camera.vMatrix);
    705         mat4.invert(canvas.camera.vpInverseMatrix, canvas.camera.vpMatrix);
    706        
    707         vec3.transformMat4(canvas.camera.position, cameraPosition, canvas.camera.vpInverseMatrix);
    708         canvas.camera.ready = true;
    709         repositionMarker(canvas);
     489        mat4.invert(camera.vInverseMatrix, camera.vMatrix);
     490        mat4.invert(camera.vpInverseMatrix, camera.vpMatrix);
     491       
     492        vec3.transformMat4(camera.position, vec3.create(), camera.vInverseMatrix);
     493        vec3.sub(camera.relativePosition, camera.position, view.position);
     494        vec3.normalize(camera.direction, camera.relativePosition);
     495       
     496        camera.ready = true;
    710497}//}}}
    711498function drawSceneGraphNode(canvas, node) { //{{{
     
    718505        mat4.multiply(mvpMatrix, canvas.camera.vpMatrix, node.modelMatrix);
    719506       
    720         var mvMatrix = mat4.create();
    721         mat4.multiply(mvMatrix, canvas.camera.vMatrix, node.modelMatrix);
    722        
    723         var normalMatrix = mat4.create();
    724         mat4.invert(normalMatrix, node.modelMatrix);
    725         mat4.transpose(normalMatrix, normalMatrix);
     507        var normalMatrix = mat3.create();
     508        var tempMatrix = mat4.create();
     509        mat4.invert(tempMatrix, node.modelMatrix);
     510        mat4.transpose(tempMatrix, tempMatrix);
     511        mat3.fromMat4(normalMatrix, tempMatrix);
    726512       
    727513        if (node.texture) { node.texture.bind(0); }
     
    732518        gl.lineWidth(node.lineWidth);
    733519        gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    734 
     520       
    735521        //Setup for light that originates from camera
    736         var origin = vec3.fromValues(0, 0, 0);
    737         var lightOrigin = vec3.fromValues(0, 0, 0);
    738         var cameraPositionRelative = vec3.create();
    739         vec3.transformMat4(origin, origin, canvas.camera.vInverseMatrix);
    740         vec3.normalize(lightOrigin, lightOrigin);
    741         vec3.sub(cameraPositionRelative, origin, node.translation);
    742         cameraHeight = vec3.length(cameraPositionRelative);
    743        
    744         var atm = {                                     //Default Values
    745                 wavelength_r: 0.65,             //0.65          Red wavelength (micrometers)
    746                 wavelength_g: 0.57,                     //0.57          Green wavelength (micrometers)
    747                 wavelength_b: 0.475,            //0.475         Green wavelength (micrometers)
    748                 eSun: 100.0,                            //20.0          Sun intensity   
    749                 kRayleigh: 0.0025,                      //0.0025        Rayleigh scattering amount
    750                 kMie: 0.000,                            //0.01          Mie scattering amount
    751                 g: -0.99,                                       //-0.99         Mie phase asymmetry/direction factor
    752                 hdr_exposure: 0.8,                      //0.8           High Dynamic Range Exposure
    753                 scale: 1.25,                            //1.025         Scale of atmosphere. WARNING: Change atmosphereScale in applyoptions.js, and scaling constants.
    754                 scaleDepth: 0.25,                       //0.25          Percentage altitude at which the atmosphere's average density is found
    755                 a: -0.00287,                            //-0.00287      Scaling constant a
    756                 b: 0.459,                                       //0.459         Scaling constant b
    757                 c: 3.83,                                        //3.83          Scaling constant c
    758                 d: -6.80,                                       //-6.80         Scaling constant d
    759                 e: 3.6,                                         //5.25          Scaling constant e. Lower when increasing atmosphere scale.
    760                 attenuation: 0.5                        //0.5           Strength of atmospheric scattering on ground shading.
    761         };
    762                        
    763         var inv_wavelength4 = [1.0 / Math.pow(atm.wavelength_r, 4), 1.0 / Math.pow(atm.wavelength_g, 4), 1.0 / Math.pow(atm.wavelength_b, 4)];
    764         var innerRadius = 6.371e6;
    765         var outerRadius = innerRadius*atm.scale;
    766         var scale = 1.0 / (outerRadius - innerRadius);
    767         var scaleDepth = atm.scaleDepth;
     522        var atm = canvas.atmosphere;
     523        var lightOrigin = vec3.create();
    768524       
    769525        node.shader.uniforms({
    770                 m4MVP: mvpMatrix,
    771                 m4Normal: normalMatrix,
    772                 m4Model: node.modelMatrix,
    773                 u_lightPosition: lightOrigin,
    774                 //u_lightPosition: [1.0, 1.0, 1.0],
    775                 u_diffuseColor: node.diffuseColor,
    776                 u_texture: 0,
    777                 u_alpha: node.alpha,
    778                 u_maskZerosColor: node.maskZerosColor,
    779                 u_maskZerosEnabled: node.maskZerosEnabled,
    780                 u_maskZerosTolerance: node.maskZerosTolerance,
    781                 u_maskZerosZeroValue: node.maskZerosZeroValue,
    782                 u_maskEnabled: node.maskEnabled,
    783                 u_maskHeight: node.maskHeight,
    784                 u_maskColor: node.maskColor,
    785                 u_pointSize: node.pointSize,
    786                 v3CameraPosition: origin,
    787                 v3Translate: node.translation,
    788                 v3LightPos: lightOrigin,
    789                 v3InvWavelength: inv_wavelength4,
    790                 fOuterRadius: outerRadius,
    791                 fOuterRadius2: outerRadius * outerRadius,
    792                 fInnerRadius: innerRadius,
    793                 fInnerRadius2: innerRadius * innerRadius,
    794                 fKrESun: atm.kRayleigh * atm.eSun,
    795                 fKmESun: atm.kMie * atm.eSun,
    796                 fKr4PI: atm.kRayleigh * 4 * Math.PI,
    797                 fKm4PI: atm.kMie * 4 * Math.PI,
    798                 fScale: scale,
    799                 fScaleDepth: scaleDepth,
    800                 fScaleOverScaleDepth: scale/scaleDepth,
    801                 v3LightPosFrag: lightOrigin,
    802                 fHdrExposure: atm.hdr_exposure,
    803                 g: atm.g,                       
    804                 g2: atm.g * atm.g,
    805                 a: atm.a,
    806                 b: atm.b,
    807                 c: atm.c,
    808                 d: atm.d,               
    809                 e: atm.e,
    810                 attenuation: atm.attenuation
     526                m4MVP:                                  mvpMatrix,
     527                m3Normal:                               normalMatrix,
     528                m4Model:                                node.modelMatrix,
     529                u_alpha:                                node.alpha,
     530                u_ambientColor:                 node.ambientColor,
     531                u_cameraPosition:               canvas.camera.position,
     532                u_diffuseColor:                 node.diffuseColor,
     533                u_lightDirection:               canvas.camera.direction,
     534                u_lightingBias:                 node.lightingBias,
     535                u_maskZerosColor:               node.maskZerosColor,
     536                u_maskZerosEnabled:     node.maskZerosEnabled,
     537                u_maskZerosTolerance:   node.maskZerosTolerance,
     538                u_maskZerosZeroValue:   node.maskZerosZeroValue,
     539                u_maskEnabled:                  node.maskEnabled,
     540                u_maskHeight:                   node.maskHeight,
     541                u_maskColor:                    node.maskColor,
     542                u_pointSize:                    node.pointSize,
     543                u_specularColor:                node.specularColor,
     544                u_specularPower:                node.specularPower,
     545                u_specularStrength:     node.specularStrength,
     546                u_texture:                              0,
     547                v3CameraPosition:               canvas.camera.position,
     548                v3Translate:                    node.translation,
     549                v3LightPos:                     lightOrigin,
     550                v3InvWavelength:                atm.inv_wavelength4,
     551                fOuterRadius:                   atm.outerRadius,
     552                fOuterRadius2:                  atm.outerRadius2,
     553                fInnerRadius:                   atm.innerRadius,
     554                fInnerRadius2:                  atm.innerRadius2,
     555                fKrESun:                                atm.krESun,
     556                fKmESun:                                atm.kmESun,
     557                fKr4PI:                                 atm.kr4PI,
     558                fKm4PI:                                 atm.km4PI,
     559                fScale:                                 atm.scale,
     560                fScaleDepth:                    atm.scaleDepth,
     561                fScaleOverScaleDepth:   atm.scaleOverScaleDepth,
     562                v3LightPosFrag:                 lightOrigin,
     563                fHdrExposure:                   atm.hdr_exposure,       
     564                g:                                              atm.g,                 
     565                g2:                                     atm.g2,
     566                a:                                              atm.a,
     567                b:                                              atm.b,
     568                c:                                              atm.c,
     569                d:                                              atm.d,         
     570                e:                                              atm.e,
     571                attenuation:                    atm.attenuation
    811572        }).draw(node.mesh, node.drawMode, 'triangles');
    812573       
     
    814575        gl.disable(gl.CULL_FACE);
    815576} //}}}
     577function canvasResize(canvas) {
     578        var rect = canvas.getBoundingClientRect();
     579        canvas.width  = rect.width;
     580        canvas.height = rect.height;
     581        canvas.gl.viewport(0, 0, canvas.width, canvas.height);
     582       
     583        if (!isEmptyOrUndefined(canvas.overlaycanvas)) {
     584                rect = canvas.overlaycanvas.getBoundingClientRect();
     585                canvas.overlaycanvas.width  = rect.width;
     586                canvas.overlaycanvas.height = rect.height;
     587        }
     588}
    816589function draw(canvas) { //{{{
    817590        //Ensure all nodes are ready to render
     
    833606        //Begin rendering nodes
    834607        if (canvas.draw.ready) {
    835                 var rect = canvas.getBoundingClientRect();
    836                 canvas.width  = rect.width;
    837                 canvas.height = rect.height;
     608                //Handle canvas resizing and viewport/screenspace coordinate synchronization
     609                canvasResize(canvas);   
    838610               
    839611                var gl = canvas.gl;
    840612                gl.makeCurrent(); //litegl function to handle switching between multiple canvases
    841                 gl.viewport(0, 0, canvas.width, canvas.height);
    842613                gl.clearColor(canvas.backgroundcolor[0], canvas.backgroundcolor[1], canvas.backgroundcolor[2], canvas.backgroundcolor[3]);
    843614                gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
     
    845616                updateCameraMatrix(canvas);
    846617               
    847                 if (canvas.textcanvas) { canvas.textcanvas.draw(canvas); }
    848                 if (canvas.overlaycanvas) { canvas.overlaycanvas.draw(canvas); }
     618                //Trigger any handlers attatched to this canvas event.
     619                canvas.selector.trigger('onPreRender', [canvas]);
     620               
     621                for (var handler in canvas.overlayHandlers) { canvas.overlayHandlers[handler](canvas); }
    849622               
    850623                var drawPassNumber = 3;
  • issm/trunk-jpl/src/m/plot/webgl_node.js

    r21768 r21911  
    66
    77function Node() { //{{{
    8         //properties 
     8        //properties
    99        // {{{
    1010        var args = Array.prototype.slice.call(arguments);
     
    1515        this.gl = canvas.gl;
    1616       
    17         this.alpha = options.getfieldvalue('alpha',                                                             1.0),
    18         this.animation = options.getfieldvalue('animation',                                             {}),
    19         this.arrays = options.getfieldvalue('arrays',                                                           {}),
    20         this.caxis = options.getfieldvalue('caxis',                                                             [0.0, 1.0]),
    21         this.center = options.getfieldvalue('center',                                                           vec3.create()),
    22         this.cullFace = options.getfieldvalue('cullFace',                                                       this.gl.BACK),
    23         this.computeIndices = options.getfieldvalue('computeIndices',                           true),
    24         this.disableDepthTest = options.getfieldvalue('disableDepthTest',                       false),
    25         this.diffuseColor = options.getfieldvalue('diffuseColor',                                       [0.0, 0.0, 0.0, 1.0]),
    26         this.drawMode = options.getfieldvalue('drawMode',                                                       this.gl.TRIANGLES),
    27         this.drawOrder = options.getfieldvalue('drawOrder',                                             1),
    28         this.enabled = options.getfieldvalue('enabled',                                                         true),
    29         this.enableCullFace = options.getfieldvalue('enableCullFace',                           true),
    30         this.hideOcean = options.getfieldvalue('hideOcean',                                             false),
    31         this.lineWidth = options.getfieldvalue('lineWidth',                                             1.0),
    32         this.log = options.getfieldvalue('log',                                                                         false),
    33         this.maskColor = options.getfieldvalue('maskColor',                                             vec4.fromValues(0.0, 0.0, 1.0, 1.0)),
    34         this.maskEnabled = options.getfieldvalue('maskEnabled',                                         false),
    35         this.maskHeight = options.getfieldvalue('maskHeight',                                           150.0),
    36         this.maskZerosColor = options.getfieldvalue('maskZerosColor',                           [1.0, 1.0, 1.0, 1.0]),
    37         this.maskZerosEnabled = options.getfieldvalue('maskZerosEnabled',                       false),
    38         this.maskZerosTolerance = options.getfieldvalue('maskZerosTolerance',           1e-6),
    39         this.maskZerosZeroValue = options.getfieldvalue('maskZerosZeroValue',           0.5),
    40         this.mesh = options.getfieldvalue('mesh',                                                                       undefined),
    41         this.name = options.getfieldvalue('name',                                                                       'node'),
    42         this.nanIndices = options.getfieldvalue('nanIndices',                                           new Set()),
    43         this.octree = options.getfieldvalue('octree',                                                           undefined),
    44         this.pointSize = options.getfieldvalue('pointSize',                                             15.0),
    45         this.shaderName = options.getfieldvalue('shaderName',                                           'Colored'),
    46         this.shader = options.getfieldvalue('shader',                                                           this.gl.shaders[this.shaderName]),
    47         this.texture = options.getfieldvalue('texture',                                                         undefined),
    48         this.scale = options.getfieldvalue('scale',                                                             vec3.fromValues(1, 1, 1)),
    49         this.rotation = options.getfieldvalue('rotation',                                                       vec3.create()),
    50         this.translation = options.getfieldvalue('translation',                                         vec3.create()),
    51         this.modelMatrix = options.getfieldvalue('modelMatrix',                                         mat4.create()),
    52         this.rotationMatrix = options.getfieldvalue('rotationMatrix',                           mat4.create()),
    53         this.inverseModelMatrix = options.getfieldvalue('inverseModelMatrix',           mat4.create()),
    54         this.inverseRotationMatrix = options.getfieldvalue('inverseRotationMatrix', mat4.create())
     17        this.alpha = options.getfieldvalue('alpha',                                                             1.0);                                                                   //Shading transparency.
     18        this.ambientColor = options.getfieldvalue('ambientColor',                                       [0.0, 0.0, 0.0, 1.0]);                                  //Ambient color used in lighting.
     19        this.animation = options.getfieldvalue('animation',                                             {});                                                                    //Animtation parameters.
     20        this.arrays = options.getfieldvalue('arrays',                                                           {});                                                                    //Storage for webgl arrays.
     21        this.caxis = options.getfieldvalue('caxis',                                                             [0.0, 1.0]);                                                    //Color axis for texturing.
     22        this.center = options.getfieldvalue('center',                                                           vec3.create());                                                 //Center of rotation/scaling.
     23        this.cullFace = options.getfieldvalue('cullFace',                                                       this.gl.BACK);                                                  //GL enum for face culling back/front faces.
     24        this.computeIndices = options.getfieldvalue('computeIndices',                           true);                                                                  //Specifies whether or not indices need to be computed during patching.
     25        this.disableDepthTest = options.getfieldvalue('disableDepthTest',                       false);                                                                 //GL enum for enabling/disabling depth testing.
     26        this.diffuseColor = options.getfieldvalue('diffuseColor',                                       [0.0, 0.0, 0.0, 1.0]);                                  //Diffuse color in vec4 rgba format.
     27        this.drawMode = options.getfieldvalue('drawMode',                                                       this.gl.TRIANGLES);                                             //GL enum for draw mode.
     28        this.drawOrder = options.getfieldvalue('drawOrder',                                             1);                                                                             //Drawing order for non-depth tested/transparent objects. Higher numbers are drawn. first.
     29        this.enabled = options.getfieldvalue('enabled',                                                         true);                                                                  //Toggles display of this nodde.
     30        this.enableCullFace = options.getfieldvalue('enableCullFace',                           true);                                                                  //Toggles use of face culling.
     31        this.hideOcean = options.getfieldvalue('hideOcean',                                             false);                                                                 //ISSM shader uniform controlling ocean masking
     32        this.lineWidth = options.getfieldvalue('lineWidth',                                             1.0);                                                                   //Controls width of gl lines. No reliable support across windows platforms.
     33        this.lightingBias = options.getfieldvalue('lightingBias',                                       0.0);                                                                   //Controls width of gl lines. No reliable support across windows platforms.
     34        this.log = options.getfieldvalue('log',                                                                         false);                                                                 //Controls logarithmic color axis scaling for texturing.
     35        this.maskColor = options.getfieldvalue('maskColor',                                             vec4.fromValues(0.0, 0.0, 1.0, 1.0));   //ISSM shader uniform controlling ocean masking color.
     36        this.maskEnabled = options.getfieldvalue('maskEnabled',                                         false);                                                                 //ISSM shader uniform toggling ocean masking.
     37        this.maskHeight = options.getfieldvalue('maskHeight',                                           150.0);                                                                 //ISSM shader uniform controlling height at which ocean masking is cut off.
     38        this.maskZerosColor = options.getfieldvalue('maskZerosColor',                           [1.0, 1.0, 1.0, 1.0]);                                  //ISSM shader uniform controlling value masking color.
     39        this.maskZerosEnabled = options.getfieldvalue('maskZerosEnabled',                       false);                                                                 //ISSM shader uniform toggling value masking.
     40        this.maskZerosTolerance = options.getfieldvalue('maskZerosTolerance',           1e-6);                                                                  //ISSM shader uniform controlling tolerance of value to zero value when masking.
     41        this.maskZerosZeroValue = options.getfieldvalue('maskZerosZeroValue',           0.5);                                                                   //ISSM shader uniform controlling zero value masking offset.
     42        this.mesh = options.getfieldvalue('mesh',                                                                       undefined);                                                             //Litegl GL.Mesh class used for drawing.
     43        this.name = options.getfieldvalue('name',                                                                       'node');                                                                //Name of node.
     44        this.nanIndices = options.getfieldvalue('nanIndices',                                           new Set());                                                             //Set of NaN indices to mask out of mesh.
     45        this.octree = options.getfieldvalue('octree',                                                           undefined);                                                             //Fast raytracing octree object.
     46        this.pointSize = options.getfieldvalue('pointSize',                                             15.0);                                                                  //Size of points when displaying GL.POINTS.
     47        this.shaderName = options.getfieldvalue('shaderName',                                           'Colored');                                                             //Name of shader to use.
     48        this.shader = options.getfieldvalue('shader',                                                           this.gl.shaders[this.shaderName]);              //Compiled shader object.
     49        this.specularColor = options.getfieldvalue('specularColor',                             [1.0, 1.0, 1.0, 1.0]);                                  //Specular reflection color used in lighting.
     50        this.specularStrength = options.getfieldvalue('specularStrength',                       1.0);                                                                   //Specular reflection power - represents specular highlight sharpness.
     51        this.specularPower = options.getfieldvalue('specularPower',                             5);                                                                             //Specular reflection power - represents specular highlight sharpness.
     52        this.texture = options.getfieldvalue('texture',                                                         undefined);                                                             //GL texture object.
     53        this.scale = options.getfieldvalue('scale',                                                             vec3.fromValues(1, 1, 1));                              //XYZ scaling of the node.
     54        this.renderObject = options.getfieldvalue('renderObject',                                       {});                                                                    //Field for additional render object state information not necessarily related to node display.
     55        this.rotation = options.getfieldvalue('rotation',                                                       vec3.create());                                                 //XYZ rotation of the node.
     56        this.rotationQuaternion = options.getfieldvalue('rotationQuaternion',           quat.create());                                                 //Quaternion rotation of the node. Not currently in use.
     57        this.translation = options.getfieldvalue('translation',                                         vec3.create());                                                 //XYZ translation of the node.
     58        this.modelMatrix = options.getfieldvalue('modelMatrix',                                         mat4.create());                                                 //Model matrix computed from updateModelMatrix function.
     59        this.translationMatrix = options.getfieldvalue('translationMatrix',             mat4.create());                                                 //Intermediate translation matrix computed from updateModelMatrix function.
     60        this.rotationMatrix = options.getfieldvalue('rotationMatrix',                           mat4.create());                                                 //Intermediate rotation matrix computed from updateModelMatrix function.
     61        this.scaleMatrix = options.getfieldvalue('scaleMatrix',                                         mat4.create());                                                 //Intermediate scale matrix computed from updateModelMatrix function.
     62        this.inverseModelMatrix = options.getfieldvalue('inverseModelMatrix',           mat4.create());                                                 //Inverse model matrix.
     63        this.inverseRotationMatrix = options.getfieldvalue('inverseRotationMatrix', mat4.create());                                                     //Inverse rotation matrix.
    5564        //}}}
    5665        //initialize {{{
    57         //if (this.name in canvas.nodes) abort? 
     66        //if (this.name in canvas.nodes) abort?
    5867        this.updateModelMatrix();
    5968        this.updateDiffuseColor();
    6069        canvas.nodes[this.name] = this;
    6170        //}}}
     71} //}}}
     72Node.prototype.eulerToQuaternion = function(pitch, roll, yaw) { //{{{
     73        var t0 = Math.cos(yaw * 0.5);
     74        var t1 = Math.sin(yaw * 0.5);
     75        var t2 = Math.cos(roll * 0.5);
     76        var t3 = Math.sin(roll * 0.5);
     77        var t4 = Math.cos(pitch * 0.5);
     78        var t5 = Math.sin(pitch * 0.5);
     79
     80        var w = t0 * t2 * t4 + t1 * t3 * t5;
     81        var x = t0 * t3 * t4 - t1 * t2 * t5;
     82        var y = t0 * t2 * t5 + t1 * t3 * t4;
     83        var z = t1 * t2 * t4 - t0 * t3 * t5;
     84        return quat.fromValues(x, y, z, w);
     85} //}}}
     86Node.prototype.quaternionToEuler = function(q) { //{{{
     87        var ysqr = q[1] * q[1];
     88
     89        // roll (x-axis rotation)
     90        var t0 = +2.0 * (q[3] * q[0] + q[1] * q[2]);
     91        var t1 = +1.0 - 2.0 * (q[0] * q[0] + ysqr);
     92        var roll = Math.atan2(t0, t1);
     93
     94        // pitch (y-axis rotation)
     95        var t2 = +2.0 * (q[3] * q[1] - q[2] * q[0]);
     96        t2 = t2 > 1.0 ? 1.0 : t2;
     97        t2 = t2 < -1.0 ? -1.0 : t2;
     98        var pitch = Math.asin(t2);
     99
     100        // yaw (z-axis rotation)
     101        var t3 = +2.0 * (q[3] * q[2] + q[0] * q[1]);
     102        var t4 = +1.0 - 2.0 * (ysqr + q[2] * q[2]);
     103        var yaw = Math.atan2(t3, t4);
     104       
     105        return [pitch * RAD2DEG, roll * RAD2DEG, yaw * RAD2DEG];
    62106} //}}}
    63107Node.prototype.updateModelMatrix = function() { //{{{
     
    83127        mat4.rotate(xRotationMatrix, xRotationMatrix, DEG2RAD * this.rotation[0], [1.0, 0.0, 0.0]);
    84128        mat4.multiply(rotationMatrix, xRotationMatrix, rotationMatrix);
    85         mat4.multiply(modelMatrix, rotationMatrix, modelMatrix);       
     129        mat4.multiply(modelMatrix, rotationMatrix, modelMatrix);
     130
     131        //var rotationQuaternionX = this.eulerToQuaternion(0, -DEG2RAD * this.rotation[0], 0);
     132        //var rotationQuaternionY = this.eulerToQuaternion(DEG2RAD * this.rotation[1], 0, 0);
     133        //mat4.fromQuat(this.rotationMatrix, quat.multiply(quat.create(), rotationQuaternionY, rotationQuaternionX));
     134
     135        //mat4.multiply(this.modelMatrix, this.rotationMatrix, this.modelMatrix);       
     136               
    86137       
    87138        mat4.identity(translationMatrix);
     
    124175Node.prototype.patch = function() { //{{{
    125176        //Emulates the behavior of MATLAB patch function by constructing a mesh from arguments.
    126         //Limitations: 
     177        //Limitations:
    127178        //      -Expects pair labeled arguments ('FaceColor','none',...).
    128179        //      -Only handles Face/Vertices/FaceVertexCData element/node plots.
     
    149200
    150201        this.mesh = GL.Mesh.load(this.arrays, null, null, this.gl);
    151         //this.mesh.computeNormals();
     202        this.mesh.computeNormals();
    152203        this.computeOctree();
    153204} //}}}
     
    239290        if (this.log !== false && this.log !== 'off') {
    240291                caxis = [
    241                         Math.log10(caxis[0]) / Math.log10(this.log), 
     292                        Math.log10(caxis[0]) / Math.log10(this.log),
    242293                        Math.log10(caxis[1]) / Math.log10(this.log)
    243294                ];
     
    389440                        var j = 0;
    390441                        if (isEmptyOrUndefined(indices)) {
    391                                 for (var key in object) {
     442                                for (var key in coordinateObject) {
     443                                        console.log(key);
    392444                                        array[j++] = coordinateObject[key];
    393445                                }
     
    407459        var meshVertices = mesh.getBuffer('vertices').data;
    408460        var meshIndicies = mesh.getIndexBuffer('triangles').data;
    409         var indicies = new Uint16Array(meshIndicies.length * x.length);
     461        var indices = new Uint16Array(meshIndicies.length * x.length);
    410462        var size = meshVertices.length * x.length / 3;
    411463        newX = new Float32Array(size);
     
    423475                var offset = i * meshVertices.length / 3;
    424476                for (var j = 0; j < meshIndicies.length;) {
    425                         indicies[e++] = meshIndicies[j++] + offset;
    426                 }
    427         }
    428        
    429         this.patch('Faces', indicies, 'Vertices', [newX, newY, newZ], 'FaceColor', 'interp');
    430 } //}}}
    431 Node.prototype.scaleVertices = function(md, x, y, z, scale) { //{{{
     477                        indices[e++] = meshIndicies[j++] + offset;
     478                }
     479        }
     480       
     481        this.patch('Faces', indices, 'Vertices', [newX, newY, newZ], 'FaceColor', 'interp');
     482} //}}}
     483Node.prototype.scaleVertices = function(md, x, y, z, elements, scale, maskObject) { //{{{
    432484        //Scales and returns vertices x, y, and z by factor scale. Uses md.geometry.scale for heightscaling in 3d meshes.
    433485        if (md.mesh.classname() === 'mesh3dsurface') {
    434                 var xyz, magnitude;
    435                 x = x.slice();
    436                 y = y.slice();
    437                 z = z.slice();
    438                 for(var i = 0; i < x.length; i++) {
    439                         xyz = vec3.fromValues(x[i], y[i], z[i]);
    440                         magnitude = 1 + md.geometry.surface[i] * scale / vec3.length(xyz);
    441                         vec3.scale(xyz, xyz, magnitude);
    442                         x[i] = xyz[0];
    443                         y[i] = xyz[1];
    444                         z[i] = xyz[2];
     486                if (!maskObject.enabled) {
     487                        var xyz, magnitude;
     488                        x = x.slice();
     489                        y = y.slice();
     490                        z = z.slice();
     491                        for(var i = 0; i < x.length; i++) {
     492                                xyz = vec3.fromValues(x[i], y[i], z[i]);
     493                                magnitude = 1 + md.geometry.surface[i] * scale / vec3.length(xyz);
     494                                vec3.scale(xyz, xyz, magnitude);
     495                                x[i] = xyz[0];
     496                                y[i] = xyz[1];
     497                                z[i] = xyz[2];
     498                        }
     499                }
     500                else {
     501                        var mask = maskObject.mask;
     502                        var maskScale = maskObject.scale;
     503                        var element;
     504                        for (var i = 0; i < mask.length; i++) {
     505                                if (mask[i] === 1) {
     506                                        element = elements[i];
     507                                        for (var j = 0; j < 3; j++) {
     508                                                xyz = vec3.fromValues(x[element[j] - 1], y[element[j] - 1], z[element[j] - 1]);
     509                                                magnitude = 1 + md.geometry.surface[element[j] - 1] * scale * maskScale / vec3.length(xyz);
     510                                                vec3.scale(xyz, xyz, magnitude);
     511                                                x[element[j] - 1] = xyz[0];
     512                                                y[element[j] - 1] = xyz[1];
     513                                                z[element[j] - 1] = xyz[2];
     514                                        }
     515                                       
     516                                }
     517                        }
    445518                }
    446519        }
  • issm/trunk-jpl/src/m/solve/WriteData.js

    r21147 r21911  
    6060                else{
    6161                        if (!IsArray(data)) data=data*scale;
    62                         else ArrayScale(data,scale);
     62                        else data=ArrayScale(data,scale);
    6363                }
    6464        }
Note: See TracChangeset for help on using the changeset viewer.