source: issm/oecreview/Archive/21724-22754/ISSM-21767-21768.diff@ 22755

Last change on this file since 22755 was 22755, checked in by Mathieu Morlighem, 7 years ago

CHG: added 21724-22754

File size: 131.7 KB
  • ../trunk-jpl/src/m/plot/webgl.js

     
    55        canvas = document.getElementById(options.getfieldvalue('canvasid'));
    66        //var canvas = document.getElementById(options.getfieldvalue('canvasid'));
    77        if (!canvas.initialized) {
    8                 typedArraySliceSupport();
    98                if (!isEmptyOrUndefined(canvas.draw) && canvas.draw.handler !== 0)      { window.cancelAnimationFrame(canvas.draw.handler); }
    109                if (!isEmptyOrUndefined(canvas.animation) && canvas.animation.handler !== 0) { clearInterval(canvas.animation.handler); }
    1110                initWebGL(canvas, options);
    1211                initializeMarker(canvas);
    13                 canvas.nodes = [];
    1412                draw(canvas);
    1513                canvas.initialized = true;
    1614        }
     
    1816}
    1917function initWebGL(canvas, options) { //{{{
    2018        //Initialize canvas.gl on page load, reusing gl context on additional runs
    21         var gl;
    22         if (!canvas.gl) {
     19        var gl = canvas.gl;
     20        if (isEmptyOrUndefined(gl)) {
    2321                gl = GL.create({canvas: canvas});
    2422                gl.enable(gl.DEPTH_TEST); // Enable depth testing
    2523                gl.depthFunc(gl.LEQUAL); // Near things obscure far things
     
    3028                gl.textures = {};
    3129               
    3230                // Add event listeners for canvas
    33                 var displayview = options.getfieldvalue('displayview', 'off') == 'on';
    34                 var displayzoom = options.getfieldvalue('displayzoom', 'off') == 'on';
    35                 var mc = new Hammer.Manager(canvas);
    36                
    37                 mc.add( new Hammer.Tap({event: 'singletap' }) );
     31                var displayview = options.getfieldvalue('displayview', 'off') === 'on';
     32                var displayzoom = options.getfieldvalue('displayzoom', 'off') === 'on';
     33                var mc = new Hammer(canvas);   
    3834                mc.add(new Hammer.Pan({threshold: 0, pointers: 0}));
    3935                mc.add(new Hammer.Pinch({threshold: 0})).recognizeWith(mc.get('pan'));
    40                 mc.on('singletap', function (ev) {onTap(ev, canvas);});
     36                mc.on('tap press', function (ev) {onTap(ev, canvas);});
    4137                mc.on('panstart panmove', function (ev) {onPan(ev, canvas, displayview);});
    42                 mc.on('pinchstart pinchmove', function (ev) {onPinch(ev, canvas, displayview);});
    43                
     38                mc.on('pinchstart pinchmove', function (ev) {onPinch(ev, canvas, displayview);});               
    4439                canvas.addEventListener('mousewheel', function (ev) {onZoom(ev, canvas, displayzoom)}, false);
    4540                canvas.addEventListener('DOMMouseScroll', function (ev) {onZoom(ev, canvas, displayzoom)}, false);
     41               
     42                //Add persistent state variables
     43                canvas.nodes = {};
     44                canvas.octrees = {};
     45                canvas.unitNode = {};
     46                canvas.unitData = {};
     47                canvas.unitMovieData = {};
     48                canvas.gl = gl;
     49                canvas.rootPath = options.getfieldvalue('rootpath', '../../../js/');
     50                canvas.id = options.getfieldvalue('canvasid', '.sim-canvas');
     51                canvas.selector = $('#' + canvas.id);
     52                canvas.textcanvas = null;
     53                canvas.overlaycanvas = null;
     54               
     55                typedArraySliceSupport();
    4656        }
    47         else {
    48                 gl = canvas.gl;
    49         }
    5057       
    51         // Add context state variables
    52         canvas.gl = gl;
    53         canvas.textcanvas = null;
    54         canvas.overlaycanvas = null;
    55         canvas.unitNode = {};
    56         canvas.unitData = {};
     58        //Add context state variables
    5759        canvas.controlSensitivity = options.getfieldvalue('controlsensitivity', 1);
    58         canvas.id = options.getfieldvalue('canvasid', '.sim-canvas');
    59         canvas.rootPath = options.getfieldvalue('rootpath', '../../../js/');
    60         canvas.selector = $('#' + canvas.id);
    6160        var backgroundcolor = new RGBColor(options.getfieldvalue('backgroundcolor', 'lightcyan'));
    6261        if (backgroundcolor.ok) { canvas.backgroundcolor = [backgroundcolor.r/255.0, backgroundcolor.g/255.0, backgroundcolor.b/255.0, 1.0]; }
    6362        else { throw Error(sprintf('s%s%s\n','initWebGL error message: cound not find out background color for curent canvas ', canvas)); }
     
    6968                play: defaultFor(animation.play, true),
    7069                increment: defaultFor(animation.increment, true),
    7170                fps: defaultFor(animation.fps, 4),
     71                interval: defaultFor(animation.interval, 1000 / animation.fps),
    7272                loop: defaultFor(animation.loop, true),
    7373                handler: defaultFor(animation.handler, 0)
    7474        }
     
    9898        canvas.clouds = {
    9999                enabled: defaultFor(clouds.enabled, false),
    100100                height: defaultFor(clouds.height, 7500),
    101                 quantity: defaultFor(clouds.quantity, 10)
     101                quantity: defaultFor(clouds.quantity, 10),
     102                hit: defaultFor(clouds.hit, {})
    102103        };
    103104        var dataMarkers = options.getfieldvalue('datamarkers', {});
    104105        canvas.dataMarkers = {
     
    110111                animated: defaultFor(dataMarkers.animated, false),
    111112                labels: defaultFor(dataMarkers.labels, []),
    112113                font: defaultFor(dataMarkers.font, ''),
    113                 marker: defaultFor(dataMarkers.marker, document.getElementById('sim-data-marker-' + canvas.id))
     114                marker: defaultFor(dataMarkers.marker, document.getElementById('sim-data-marker-' + canvas.id)),
     115                reposition: defaultFor(dataMarkers.reposition, true)
    114116        };
    115117        var draw = options.getfieldvalue('draw', {});
    116118        canvas.draw = {
     
    133135        //Override with parameters from URL, if any
    134136        //TODO: Make permalinks more robust and less interdependent on UI
    135137        if (!canvas.usedparemters) {
    136                 function getJsonFromUrl() {
    137                         var query = location.search.substr(1);
    138                         var result = {};
    139                         query.split('&').forEach(function(part) {
    140                                 var item = part.split('=');
    141                                 result[item[0]] = decodeURIComponent(item[1]);
    142                         });
    143                         return result;
    144                 }
    145                 parameters = getJsonFromUrl();
    146                
    147                 if (parameters['view']) {
    148                         canvas.view = JSON.parse(parameters['view']);
    149                 }
     138                var parameters = {};
     139                location.search.substr(1).split('&').forEach(function(part) {
     140                        var item = part.split('=');
     141                        parameters[item[0]] = decodeURIComponent(item[1]);
     142                });
     143
     144                if (parameters['pos']) { canvas.view.position = JSON.parse(parameters['pos']); }
     145                if (parameters['rot']) { canvas.view.rotation = JSON.parse(parameters['rot']); }
     146                if (parameters['zoom']) { canvas.view.zoom = JSON.parse(parameters['zoom']); }
     147                if (parameters['twod']) { canvas.view.twod = JSON.parse(parameters['twod']); }
    150148                if (parameters['initial']) {
    151149                        initial = JSON.parse(parameters['initial']);
    152150                        if (!initial) {
    153                                 if (typeof SolveGlacier == 'function') {
     151                                if (typeof SolveGlacier === 'function') {
    154152                                        SolveGlacier();
    155153                                }
    156                                 if (typeof SolveSlr == 'function') {
     154                                if (typeof SolveSlr === 'function') {
    157155                                        SolveSlr();
    158156                                }
    159157                        }
     
    162160        }
    163161} //}}}
    164162function generatePermalink() { //{{{
    165         var permalink = window.location.origin + window.location.pathname + '&view=' + JSON.stringify(canvas.view) + '&initial=' + JSON.stringify(initial);
     163        var permalink = window.location.origin + window.location.pathname + '?'
     164        + '&pos=' + encodeURIComponent(JSON.stringify(canvas.view.position))
     165        + '&rot=' + encodeURIComponent(JSON.stringify(canvas.view.rotation))
     166        + '&zoom=' + encodeURIComponent(JSON.stringify(canvas.view.zoom))
     167        + '&twod=' + encodeURIComponent(JSON.stringify(canvas.view.twod));
    166168        window.prompt('Share this simulation: ', permalink);
    167169} //}}}
    168170function loadShaders(gl, rootPath) { //{{{
     
    181183        }
    182184        return gl.textures[imageSource];
    183185} //}}}
    184 function Node(gl) { //{{{
    185         //Returns a Node object that contains default display states for webgl object. center represents pivot point of rotation.
    186         return {
    187                 alpha: 1.0,
    188                 buffers: [],
    189                 cullFace: gl.BACK,
    190                 disableDepthTest: false,
    191                 drawMode: gl.TRIANGLES,
    192                 drawOrder: 0,
    193                 enabled: true,
    194                 enableCullFace: true,
    195                 hideOcean: false,
    196                 lineWidth: 1.0,
    197                 maskEnabled: false,
    198                 maskHeight: 150.0,
    199                 maskColor: vec4.fromValues(0.0, 0.0, 1.0, 1.0),
    200                 mesh: null,
    201                 name: 'node',
    202                 shaderName: 'Colored',
    203                 shader: gl.shaders.Colored,
    204                 texture: null,
    205                 useIndexBuffer: true,
    206                 center: vec3.create(),
    207                 scale: vec3.fromValues(1, 1, 1),
    208                 rotation: vec3.create(),
    209                 translation: vec3.create(),
    210                 modelMatrix: mat4.create(),
    211                 rotationMatrix: mat4.create(),
    212                 inverseModelMatrix: mat4.create(),
    213                 inverseRotationMatrix: mat4.create()
    214         };
    215 } //}}}
    216 function debugNodes(canvasid) { //{{{
    217         var canvasid = canvasid || '.sim-canvas';
    218         var nodes = document.getElementById(canvasid).nodes;
    219         console.log(canvasid, 'Nodes:');
    220         for (var node in nodes) {
    221                 console.log('name: ', nodes[node].name, ' node: ', nodes[node], ' mesh: ', nodes[node].mesh, ' translation: ', nodes[node].translation, ' center:', nodes[node].center, ' rotation:', nodes[node].rotation);
    222         }
    223         return nodes;
    224 } //}}}
    225 function updateModelMatrix(node) { //{{{
    226         var modelMatrix = mat4.create();
    227 
    228         var translationMatrix = mat4.create();
    229         mat4.translate(translationMatrix, translationMatrix, vec3.negate(vec3.create(), node.center)); //scale/rotation centering
    230         mat4.multiply(modelMatrix, translationMatrix, modelMatrix);
    231        
    232         var scaleMatrix = mat4.create();
    233         mat4.scale(scaleMatrix, scaleMatrix, node.scale);
    234         mat4.multiply(modelMatrix, scaleMatrix, modelMatrix);
    235        
    236         var rotationMatrix = mat4.create();
    237         var zRotationMatrix = mat4.create();   
    238         mat4.rotate(zRotationMatrix, zRotationMatrix, DEG2RAD * node.rotation[2], [0.0, 0.0, 1.0]);
    239         mat4.multiply(rotationMatrix, zRotationMatrix, rotationMatrix);
    240         var yRotationMatrix = mat4.create();   
    241         mat4.rotate(yRotationMatrix, yRotationMatrix, DEG2RAD * node.rotation[1], [0.0, 1.0, 0.0]);
    242         mat4.multiply(rotationMatrix, yRotationMatrix, rotationMatrix);
    243         var xRotationMatrix = mat4.create();   
    244         mat4.rotate(xRotationMatrix, xRotationMatrix, DEG2RAD * node.rotation[0], [1.0, 0.0, 0.0]);
    245         mat4.multiply(rotationMatrix, xRotationMatrix, rotationMatrix);
    246         mat4.multiply(modelMatrix, rotationMatrix, modelMatrix);       
    247        
    248         mat4.identity(translationMatrix);
    249         mat4.translate(translationMatrix, translationMatrix, node.center); //relative translation
    250         mat4.multiply(modelMatrix, translationMatrix, modelMatrix);
    251        
    252         mat4.identity(translationMatrix);
    253         mat4.translate(translationMatrix, translationMatrix, node.translation); //absolute translation
    254         mat4.multiply(modelMatrix, translationMatrix, modelMatrix);
    255        
    256         node.modelMatrix = modelMatrix;
    257         node.inverseModelMatrix = mat4.invert(mat4.create(), modelMatrix);
    258         node.rotationMatrix = rotationMatrix;
    259         node.inverseRotationMatrix = mat4.invert(mat4.create(), rotationMatrix);
    260 } //}}}
    261186function clamp(value, min, max) { //{{{
    262187        return Math.max(min, Math.min(value, max));
    263188} //}}}
     
    265190        return typeof name !== 'undefined' ? name : value;
    266191} //}}}
    267192function isEmptyOrUndefined(object) { //{{{
    268         return object === undefined || Object.getOwnPropertyNames(object).length === 0;
     193        return object === undefined || isEmpty(object);
    269194} //}}}
     195function isEmpty(object) { //{{{
     196        for (var key in object) {
     197                return false;
     198        }
     199        return true;
     200} //}}}
    270201function recover(canvasid, name, value) { //{{{
    271202        //Traverse canvas object tree for property defined by dot delimited string, returning it, or a default value if it is not found.
    272203        var object = document.getElementById(canvasid);
    273204        var properties = name.split('.');
    274         for (var i = 0; i < properties.length; ++i) {
     205        for (var i = 0; i < properties.length; i++) {
    275206                object = object[properties[i]];
    276                 if (typeof object === 'undefined') { break; }
     207                if (isEmptyOrUndefined(object)) { break; }
    277208    }
    278209        return defaultFor(object, value);
    279210} //}}}
     
    325256function onTap(ev, canvas) { //{{{
    326257        //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.
    327258        ev.preventDefault();
    328         if (!canvas.dataMarkers.enabled) { return; }
    329         var hit = raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY);
    330         canvas.dataMarkers.marker.hit = hit;
     259       
     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
    331272        canvas.brush.hit = hit;
    332         updateMarker(canvas, true);
     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       
    333280        brushModify(canvas);
    334281} //}}}
    335282function onPan(ev, canvas, displaylog) { //{{{
    336283        ev.preventDefault();
    337284       
    338         if (canvas.dataMarkers.enabled == 'on') {
    339                 canvas.brush.hit = raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY);
    340                 brushModify(canvas);
     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                }
    341290        }
    342291       
    343         if (ev.type == 'panstart') {
     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        }
     298       
     299        if (ev.type === 'panstart') {
    344300                canvas.lastDeltaX = 0;
    345301                canvas.lastDeltaY = 0;
    346302        }
    347         if (ev.srcEvent.shiftKey || ev.pointers.length == 2) {
     303        if (ev.srcEvent.shiftKey || ev.pointers.length === 2) {
    348304                if (!canvas.view.panningEnabled) return;
    349305                var deltaX = (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth / canvas.view.zoom * 2 * canvas.controlSensitivity * 6.371e6;
    350306                var deltaY = (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight / canvas.view.zoom * 2 * canvas.controlSensitivity * 6.371e6;
     
    360316        }
    361317       
    362318        else {
    363                 canvas.view.rotation[0] += (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth * -2 * canvas.controlSensitivity * RAD2DEG;
     319                canvas.view.rotation[0] += (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth * 2 * canvas.controlSensitivity * RAD2DEG;
    364320                canvas.view.rotation[1] += (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight * -2 * canvas.controlSensitivity * RAD2DEG;
    365321               
    366322                if (canvas.view.rotation[0] > 360) { canvas.view.rotation[0] -= 360; };
     
    374330        canvas.lastDeltaX = ev.deltaX;
    375331        canvas.lastDeltaY = ev.deltaY;
    376332       
    377         repositionMarker(canvas);
     333        canvas.dataMarkers.reposition = true;
    378334       
    379335        if (displaylog) { console.log(canvas.view.rotation); }
    380336} //}}}
    381337function onPinch(ev, canvas, displaylog) { //{{{
    382338        ev.preventDefault();
    383         if (ev.type == 'pinchstart') { canvas.view.lastZoom = canvas.view.zoom; }
     339        if (ev.type === 'pinchstart') { canvas.view.lastZoom = canvas.view.zoom; }
    384340        else { modifyZoom(ev.scale * canvas.view.lastZoom, canvas, displaylog); }
    385341} //}}}
    386342function onZoom(ev, canvas, displaylog) { //{{{
     
    390346} //}}}
    391347function modifyZoom(value, canvas, displaylog) { //{{{
    392348        canvas.view.zoom = clamp(value, canvas.view.zoomLimits[0], canvas.view.zoomLimits[1]);
    393         repositionMarker(canvas);
     349        canvas.dataMarkers.reposition = true;
    394350        if (displaylog) { console.log(canvas.view.zoom); }
    395351} //}}}
    396352function modifyDataMarkersEnabled(value, canvas) { //{{{
     
    407363                canvas.playButton.find('span').addClass('fa-play');
    408364        }
    409365} //}}}
    410 function onSlideStart(canvas, progressBar) { //{{{
    411         if (!isEmptyOrUndefined(canvas.animation)) {
    412                 canvas.animation.increment = false;     
    413                 canvas.animation.frame = parseInt($(progressBar).val());
    414                 //console.log(canvas.animation.frame);
    415                 //updateMarker(canvas, false);
    416         }
    417 } //}}}
    418 function onSlideChange(canvas, progressBar) { //{{{
    419         if (!isEmptyOrUndefined(canvas.animation)) {
    420                 canvas.animation.frame = parseInt($(progressBar).val());
    421                 //console.log("change");
    422                 updateMarker(canvas, false);
    423         }
    424 } //}}}
    425 function onSlideStop(canvas, progressBar) { //{{{
    426         if (!isEmptyOrUndefined(canvas.animation)) {
    427                 canvas.animation.increment = true;     
    428                 canvas.animation.frame = parseInt($(progressBar).val());
    429                 //console.log(canvas.animation.frame);
    430                 //updateMarker(canvas, false);
    431         }
    432 } //}}}
    433366//}}}
    434367//{{{ Interaction Functions
    435 function raycast(canvas, x, y) { //{{{
     368function raycast(canvas, x, y, node) { //{{{
    436369        //Performs raycast on canvas.unitNode.mesh using x/y screen coordinates. Returns hit objects with hit position, coords, and indicies of ray-triangle intersection.
    437370        //TODO: Diagnose marker issues with orthographic views and slr-eustatic updates when switching between basins.
    438         var inverseMVPMatrix = mat4.invert(mat4.create(), mat4.multiply(mat4.create(), canvas.camera.vpMatrix, canvas.unitNode.modelMatrix));
     371        var inverseMVPMatrix = mat4.invert(mat4.create(), mat4.multiply(mat4.create(), canvas.camera.vpMatrix, node.modelMatrix));
    439372        var origin = vec3.transformMat4(vec3.create(), [(x - canvas.width / 2) / (canvas.width / 2), (canvas.height / 2 - y) / (canvas.height / 2), 0], inverseMVPMatrix);
    440373        var far = far || vec3.transformMat4(vec3.create(), [(x - canvas.width / 2) / (canvas.width / 2), (canvas.height / 2 - y) / (canvas.height / 2), 1.0], inverseMVPMatrix);
    441374        var ray = vec3.subtract(vec3.create(), far, origin);
    442375
    443         var mesh = canvas.unitNode.mesh;
     376        var mesh = node.mesh;
     377
    444378        if (!mesh) { return; }
    445         if (!mesh.octree) { mesh.octree = new GL.Octree(mesh); }
     379        if (!node.octree) { node.octree = new GL.Octree(mesh); }
    446380       
    447         var hit = mesh.octree.testRay(origin, ray, 1e3, 1e10);
     381        var hit = node.octree.testRay(origin, ray, 1e3, 1e10);
    448382       
    449383        if(!hit) { return; }
    450        
     384
     385        if (node.name.startsWith("clouds")) { canvas.clouds.selected = node.name; alert("New selected cloud: " + canvas.clouds.selected); }
     386
    451387        hit.modelPos = vec3.copy(vec3.create(), hit.pos);
    452         vec3.transformMat4(hit.pos, hit.pos, canvas.unitNode.modelMatrix);
    453         vec3.transformMat4(hit.normal, hit.normal, canvas.unitNode.modelMatrix);
     388        vec3.transformMat4(hit.pos, hit.pos, node.modelMatrix);
     389        vec3.transformMat4(hit.normal, hit.normal, node.modelMatrix);
    454390
    455391        return hit;
    456392} //}}}
     393function 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}
    457405function brushModify(canvas) { //{{{
    458406        //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.
    459407        //Currently the brush extends to the raycasted element and its immediate neighbors.
     
    506454                //Update mesh on GPU
    507455                bufferVertices.upload(canvas.gl.DYNAMIC_DRAW);
    508456                bufferCoords.upload(canvas.gl.DYNAMIC_DRAW);
    509                 canvas.unitNode.mesh.octree = new GL.Octree(canvas.unitNode.mesh);     
    510                
    511                 //Update clouds if rendered
    512                 //TODO: Steven, once you update the cloud generation in applyoptions.js, modify this code block to move the clouds as well. We'll want to move them individually later, but moving them all is ok for now.
    513                 for (var i = 0; i < canvas.clouds.quantity; i++) {
    514                         if (canvas.nodes['clouds' + i]) {
    515                                 var v1 = vec3.fromValues(vertices[hit.indices[0] * 3], vertices[hit.indices[0] * 3 + 1], vertices[hit.indices[0] * 3 + 2]);
    516                                 var v2 = vec3.fromValues(vertices[hit.indices[1] * 3], vertices[hit.indices[1] * 3 + 1], vertices[hit.indices[1] * 3 + 2]);
    517                                 var v3 = vec3.fromValues(vertices[hit.indices[2] * 3], vertices[hit.indices[2] * 3 + 1], vertices[hit.indices[2] * 3 + 2]);
    518                                 vec3.transformMat4(v1, v1, canvas.unitNode.modelMatrix);
    519                                 vec3.transformMat4(v2, v2, canvas.unitNode.modelMatrix);
    520                                 vec3.transformMat4(v3, v3, canvas.unitNode.modelMatrix);
    521                                 var x  = (v1[0] + v2[0] + v3[0]) / 3 + Math.floor((Math.random() * (1 + 10000 - (-10000)) + (-10000)));
    522                                 var y  = (v1[1] + v2[1] + v3[1]) / 3 + Math.floor((Math.random() * (1 + 10000 - (-10000)) + (-10000)));
    523                                 var z  = (v1[2] + v2[2] + v3[2]) / 3;
    524                                 canvas.nodes['clouds' + i].translation = [x, y + canvas.clouds.height, z];
    525                                 updateModelMatrix(canvas.nodes['clouds' + i]);
    526                         }
    527                 }
     457                canvas.unitNode.octree = new GL.Octree(canvas.unitNode.mesh);   
    528458        }
    529459} //}}}
     460function 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}
    530477function initializeMarker(canvas) { //{{{
    531478        //Initialize data marker and tooltip display once per page load
    532479        var marker = $('#' + canvas.dataMarkers.marker.id);
     
    562509                marker.on('click touch', function () {
    563510                        marker.fadeOut(175);
    564511                        marker.tooltipster('close');
     512                        marker.closed = true;
    565513                });
     514                marker.closed = false;
    566515                canvas.dataMarkers.marker.selector = marker;
    567516        }
    568517        updateMarker(canvas, true);
     
    569518} //}}}
    570519function repositionMarker(canvas) { //{{{
    571520        //Mover marker to point to mouse position, offset in y by 1 to enable immediate clicking.
    572         if (isEmptyOrUndefined(canvas.dataMarkers.marker.hit) || !canvas.camera.ready) { return; }
     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; }
    573523        var size = canvas.dataMarkers.size;
    574524        var screenPoint = vec3.transformMat4(vec3.create(), canvas.dataMarkers.marker.hit.pos, canvas.camera.vpMatrix);
    575         //console.log(canvas, canvas.selector, $(canvas.id)
    576525        var x = (screenPoint[0] + 1.0) * (canvas.width / 2) + canvas.selector.offset().left;
    577526        var y = (-screenPoint[1] + 1.0) * (canvas.height / 2) + canvas.selector.offset().top;
    578527        canvas.dataMarkers.marker.selector.css({
     
    579528                'left': (Math.round(x) - size[0] / 2) + 'px',
    580529                'top': (Math.round(y) - size[1] + 1) + 'px'
    581530        });
    582        
    583531        if (canvas.dataMarkers.marker.selector.tooltipster('status').state != 'closed') { canvas.dataMarkers.marker.selector.tooltipster('reposition'); }
     532        canvas.dataMarkers.reposition = false;
    584533} //}}}
    585534function updateMarker(canvas, reset) { //{{{
    586535        //Retrieve data value fields and plots them on data marker popup if a hit has been registered.
    587536        //TODO: Automatically pick up any field of size md.mesh.numberofelements
    588537        //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.
    589         if (isEmptyOrUndefined(canvas.dataMarkers.marker.hit)) { return; }
    590         if (isEmptyOrUndefined(canvas.unitNode)) { setTimeout( function(){ updateMarker(canvas, reset); }, 750); return; }
     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; }
    591540       
    592541        var hit = canvas.dataMarkers.marker.hit;
    593542       
     
    605554                velocity = md.initialization.vel;
    606555        }
    607556       
    608         //Determine data values at hit position.
    609         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]];
    610         var hitLatitude = [latitude[hit.indices[0]], latitude[hit.indices[1]], latitude[hit.indices[2]]];
    611         var hitLongitude = [longitude[hit.indices[0]], longitude[hit.indices[1]], longitude[hit.indices[2]]];
    612         var hitThickness = [thickness[hit.indices[0]], thickness[hit.indices[1]], thickness[hit.indices[2]]];
    613         var hitVelocity = [velocity[hit.indices[0]], velocity[hit.indices[1]], velocity[hit.indices[2]]];
    614         var u = hitCoords[0] * hit.uvw[0] + hitCoords[2] * hit.uvw[1] + hitCoords[4] * hit.uvw[2];
    615         var v = hitCoords[1] * hit.uvw[0] + hitCoords[3] * hit.uvw[1] + hitCoords[5] * hit.uvw[2];
    616         var value = canvas.unitNode.caxis[0] * (1.0 - v) + canvas.unitNode.caxis[1] * v;
    617         var valueLatitude = Math.abs(hitLatitude[0] * hit.uvw[0] + hitLatitude[1] * hit.uvw[1] + hitLatitude[2] * hit.uvw[2]);
    618         var valueLongitude = Math.abs(hitLongitude[0] * hit.uvw[0] + hitLongitude[1] * hit.uvw[1] + hitLongitude[2] * hit.uvw[2]);
    619         var valueThickness = hitThickness[0] * hit.uvw[0] + hitThickness[1] * hit.uvw[1] + hitThickness[2] * hit.uvw[2];
    620         var valueVelocity = hitVelocity[0] * hit.uvw[0] + hitVelocity[1] * hit.uvw[1] + hitVelocity[2] * hit.uvw[2];   
    621 
    622557        //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.
    623         var format = canvas.dataMarkers.format.slice();
    624         for (var i = 1; i < format.length; i++) {
    625                 if (format[i].toLowerCase() == 'x') { format[i] = hit.modelPos[0]; }
    626                 else if (format[i].toLowerCase() == 'y') { format[i] = hit.modelPos[1]; }
    627                 else if (format[i].toLowerCase() == 'z') { format[i] = hit.modelPos[2]; }
    628                 else if (format[i].toLowerCase() == 'lat') { format[i] = valueLatitude; }
    629                 else if (format[i].toLowerCase() == 'long') { format[i] = valueLongitude; }
    630                 else if (format[i].toLowerCase() == 'thickness') { format[i] = valueThickness; }
    631                 else if (format[i].toLowerCase() == 'vel') { format[i] = valueVelocity; }
    632                 else if (format[i].toLowerCase() == 'value') { format[i] = value; }
     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                }
    633590        }
    634591       
    635592        //Apply changes to tooltip
    636         $('#tooltip-content-data-marker-' + canvas.id).html(sprintf.apply(null, format));
     593        $('#tooltip-content-data-marker-' + canvas.id).html(sprintf.apply(null, canvas.dataMarkers.format.concat(labels)));
    637594        $('#tooltip-content-data-marker-' + canvas.id).css({'font': canvas.dataMarkers.font});                         
    638595       
    639596        //If animated, setup animation loop to update plot as movie plays.
    640597        if (canvas.dataMarkers.animated) {
    641                 var isEmpty = (canvas.dataMarkers.values.length == 0);
    642                 var lastUpdatedIndex = (canvas.dataMarkers.values.length-1);
     598                var isEmpty = (canvas.dataMarkers.values.length === 0);
     599                var lastUpdatedIndex = (canvas.dataMarkers.values.length - 1);
    643600                var newMovieFrame = (!isEmpty && canvas.dataMarkers.values[lastUpdatedIndex][0] != canvas.animation.frame);
    644601                //If new data marker has been placed, reinitialize plot. If not, push new value into plot value array.
    645602                if (reset) {
     
    646603                        canvas.dataMarkers.values = [];
    647604                        newMovieFrame = true;
    648605                        for (var currentFrame = 0; currentFrame < (canvas.unitNode.movieLength); currentFrame++) {
    649                                 coords = canvas.unitNode.texcoords[currentFrame];
     606                                coords = canvas.unitMovieData[currentFrame];
    650607                                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]];
    651608                                var u = hitCoords[0] * hit.uvw[0] + hitCoords[2] * hit.uvw[1] + hitCoords[4] * hit.uvw[2];
    652609                                var v = hitCoords[1] * hit.uvw[0] + hitCoords[3] * hit.uvw[1] + hitCoords[5] * hit.uvw[2];
     
    655612                        }
    656613                }
    657614                else {
     615                        if (canvas.animation.lastFrame > canvas.animation.frame) {
     616                                canvas.dataMarkers.values = [];
     617                        }
    658618                        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]; 
    659622                                canvas.dataMarkers.values.push([canvas.animation.frame, value]);
    660623                        }
    661624                }
     
    663626                //Replot data marker popup using update data value array.
    664627                if (isEmpty || newMovieFrame) {
    665628                        var dataLabels = {'latitude': valueLatitude, 'longitude': valueLongitude, 'thickness': valueThickness, 'velocity': valueVelocity, 'value': value};
    666                         var dataDisplay = canvas.dataMarkers.values.slice(0, canvas.animation.frame+1);                                
     629                        var dataDisplay = canvas.dataMarkers.values.slice(0, canvas.animation.frame + 1);               
    667630                        plot(
    668631                                'id', '#sim-plot',
    669632                                'type', 'bar',
     
    679642                        );
    680643                }
    681644        }
    682         repositionMarker(canvas);
    683         if (reset) {
     645        canvas.dataMarkers.reposition = true;
     646        if (reset && !canvas.dataMarkers.marker.selector.closed) {
    684647                canvas.dataMarkers.marker.selector.fadeIn(175);
    685648                canvas.dataMarkers.marker.selector.tooltipster('open');
    686649        }
    687650} //}}}
     651function animateValue(current, target, duration, stepCallback, doneCallback) { //{{{
     652        //Animates scalar value for length duration, calling callback each step.
     653        //TODO: Specify lerp easing as option (cubic, linear, cosine).
     654        $({'value':current}).animate({'value':target}, {
     655                duration: duration,
     656                step: stepCallback,
     657                done: doneCallback
     658        });
     659} //}}}
    688660//}}}
    689661//{{{ Drawing Functions
    690662function updateCameraMatrix(canvas) { //{{{
     
    706678       
    707679        //Calculate rotation around camera focal point about worldspace origin
    708680        if (canvas.view.twod) {
    709                 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, DEG2RAD * 0, [0, 1, 0]);
     681                mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -DEG2RAD * 0, [0, 1, 0]);
    710682                mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * 90, [1, 0, 0]);
    711683                mat4.multiply(rotationMatrix, elevationRotationMatrix, azimuthRotationMatrix);
    712684        }
    713685        else {
    714                 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, DEG2RAD * canvas.view.rotation[0], [0, 1, 0]);
     686                mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -DEG2RAD * (canvas.view.rotation[0] + 90), [0, 1, 0]);
    715687                mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * canvas.view.rotation[1], [1, 0, 0]);
    716688                mat4.multiply(rotationMatrix, elevationRotationMatrix, azimuthRotationMatrix);
    717689        }
     
    734706       
    735707        vec3.transformMat4(canvas.camera.position, cameraPosition, canvas.camera.vpInverseMatrix);
    736708        canvas.camera.ready = true;
     709        repositionMarker(canvas);
    737710}//}}}
    738711function drawSceneGraphNode(canvas, node) { //{{{
    739712        if (!node.enabled) { return; }
     
    748721        mat4.multiply(mvMatrix, canvas.camera.vMatrix, node.modelMatrix);
    749722       
    750723        var normalMatrix = mat4.create();
    751         mat4.invert(normalMatrix, mvMatrix);
     724        mat4.invert(normalMatrix, node.modelMatrix);
    752725        mat4.transpose(normalMatrix, normalMatrix);
    753726       
    754727        if (node.texture) { node.texture.bind(0); }
     
    768741        vec3.sub(cameraPositionRelative, origin, node.translation);
    769742        cameraHeight = vec3.length(cameraPositionRelative);
    770743       
    771         var atm = {                                                     //Default Values
    772                                 wavelength_r: 0.65,             //0.65          Red wavelength (micrometers)
    773                                 wavelength_g: 0.57,                     //0.57          Green wavelength (micrometers)
    774                                 wavelength_b: 0.475,            //0.475         Green wavelength (micrometers)
    775                                 eSun: 100.0,                            //20.0          Sun intensity   
    776                                 kRayleigh: 0.0025,                      //0.0025        Rayleigh scattering amount
    777                                 kMie: 0.000,                            //0.01          Mie scattering amount
    778                                 g: -0.99,                                       //-0.99         Mie phase asymmetry/direction factor
    779                                 hdr_exposure: 0.8,                      //0.8           High Dynamic Range Exposure
    780                                 scale: 1.25,                            //1.025         Scale of atmosphere. WARNING: Change atmosphereScale in applyoptions.js, and scaling constants.
    781                                 scaleDepth: 0.25,                       //0.25          Percentage altitude at which the atmosphere's average density is found
    782                                 a: -0.00287,                            //-0.00287      Scaling constant a
    783                                 b: 0.459,                                       //0.459         Scaling constant b
    784                                 c: 3.83,                                        //3.83          Scaling constant c
    785                                 d: -6.80,                                       //-6.80         Scaling constant d
    786                                 e: 3.6,                                         //5.25          Scaling constant e. Lower when increasing atmosphere scale.
    787                                 attenuation: 0.5                        //0.5           Strength of atmospheric scattering on ground shading.
     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.
    788761        };
    789762                       
    790763        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)];
     
    797770                m4MVP: mvpMatrix,
    798771                m4Normal: normalMatrix,
    799772                m4Model: node.modelMatrix,
    800                 //u_lightPosition: [-lightOrigin[0], -lightOrigin[1], -lightOrigin[2]],
    801                 u_lightPosition: [1.0, 1.0, 1.0],
    802                 u_diffuseColor: [1.0, 0.9, 0.9],
     773                u_lightPosition: lightOrigin,
     774                //u_lightPosition: [1.0, 1.0, 1.0],
     775                u_diffuseColor: node.diffuseColor,
    803776                u_texture: 0,
    804777                u_alpha: node.alpha,
     778                u_maskZerosColor: node.maskZerosColor,
     779                u_maskZerosEnabled: node.maskZerosEnabled,
     780                u_maskZerosTolerance: node.maskZerosTolerance,
     781                u_maskZerosZeroValue: node.maskZerosZeroValue,
    805782                u_maskEnabled: node.maskEnabled,
    806783                u_maskHeight: node.maskHeight,
    807784                u_maskColor: node.maskColor,
     785                u_pointSize: node.pointSize,
    808786                v3CameraPosition: origin,
    809787                v3Translate: node.translation,
    810788                v3LightPos: lightOrigin,
     
    840818        //TODO: Come up with better way to check if shaders are ready, or move outside of main draw function
    841819        var nodes = canvas.nodes;
    842820        if (!canvas.draw.ready) {
    843                 if (nodes.length !== 0) {
     821                if (Object.keys(nodes).length !== 0) {
    844822                        canvas.draw.ready = true;
    845823                        for (var node in nodes) {
    846                                 if (nodes[node].shader.ready == false) {
     824                                if (nodes[node].shader.ready === false) {
    847825                                        canvas.draw.ready = false;
    848826                                        break;
    849827                                }
     
    854832       
    855833        //Begin rendering nodes
    856834        if (canvas.draw.ready) {
    857                 if (canvas.textcanvas) { canvas.textcanvas.draw(canvas); }
    858                 if (canvas.overlaycanvas) { canvas.overlaycanvas.draw(canvas); }
    859        
    860835                var rect = canvas.getBoundingClientRect();
    861836                canvas.width  = rect.width;
    862837                canvas.height = rect.height;
     
    869844               
    870845                updateCameraMatrix(canvas);
    871846               
     847                if (canvas.textcanvas) { canvas.textcanvas.draw(canvas); }
     848                if (canvas.overlaycanvas) { canvas.overlaycanvas.draw(canvas); }
     849               
    872850                var drawPassNumber = 3;
    873                 for (var i = drawPassNumber - 1; i >= 0; i--) {
     851                for (var i = drawPassNumber - 1; i >= 0; --i) {
    874852                        for (var node in nodes) {
    875                                 if (nodes[node].drawOrder == i) { drawSceneGraphNode(canvas, nodes[node]); }
     853                                if (nodes[node].drawOrder === i) { drawSceneGraphNode(canvas, nodes[node]); }
    876854                        }
    877855                }
    878856        }
  • ../trunk-jpl/src/m/plot/applyoptions.js

     
    1 function applyoptions(md, data, datatype, options, canvas, gl, node){ //{{{
     1function applyoptions(md, data, options, canvas){ //{{{
    22        //APPLYOPTIONS - apply colobar, text, cloud, and expdisp options to current plot
    33        //
    44        //   Usage:
     
    77        //   See also: PLOTMODEL, PARSE_OPTIONS
    88       
    99        //{{{ colorbar
     10        var gl = canvas.gl;
    1011        if (options.exist('colorbar')) {
    1112                if (options.getfieldvalue('colorbar')==1) {
    12                         //{{{ Handle movie data
    13                         if (datatype == 5) {
    14                                 data = data[0];
    15                         } //}}}
    1613                        //{{{ Variable options initialization
    17                         var caxis = options.getfieldvalue('caxis',[ArrayMin(data), ArrayMax(data)]);
     14                        var caxis = options.getfieldvalue('caxis');
    1815                        var colorbarinnerlabels = options.getfieldvalue('colorbarinnerlabels','off');
    1916                        var ccanvasid, ctitleid, clabelsid, ccanvas, ctitle, clabels, ccontext, cmap, colorbar, cwidth, cheight, cgradient, color, y, x;
    2017                        //}}}
     
    2320                        var cdivisions = options.getfieldvalue('colorbarnticks', 6);
    2421                        var caxisdelta = caxis[1] - caxis[0];
    2522                        var precision = options.getfieldvalue('colorbarprecision', 3);
     23                        var format = options.getfieldvalue('colorbarformat', 'f').toLowerCase();
    2624                        if (options.getfieldvalue('log','off')!='off') {
    2725                                for (var i=cdivisions; i >= 0; i--) {
    2826                                        var scale = (Math.log10(caxis[1])-Math.log10(caxis[0]))/Math.log10(options.getfieldvalue('log', 10));
    29                                         labels[i] = (Math.pow(options.getfieldvalue('log', 10), Math.log10(caxis[0])/Math.log10(options.getfieldvalue('log', 10))+scale*(cdivisions-i)/cdivisions)).toFixed(precision);
     27                                        if (format === 'f') {
     28                                                labels[i] = (Math.pow(options.getfieldvalue('log', 10), Math.log10(caxis[0])/Math.log10(options.getfieldvalue('log', 10))+scale*(cdivisions-i)/cdivisions)).toFixed(precision);
     29                                        }
     30                                        else if (format === 'e') {
     31                                                labels[i] = (Math.pow(options.getfieldvalue('log', 10), Math.log10(caxis[0])/Math.log10(options.getfieldvalue('log', 10))+scale*(cdivisions-i)/cdivisions)).toPrecision(precision);
     32                                        }
     33                                        else {
     34                                                labels[i] = (Math.pow(options.getfieldvalue('log', 10), Math.log10(caxis[0])/Math.log10(options.getfieldvalue('log', 10))+scale*(cdivisions-i)/cdivisions)).toFixed(precision);
     35                                        }
    3036                                }
    3137                        } else {
    3238                                for (var i=cdivisions; i >= 0; i--) {
    33                                         labels[i] = (caxisdelta*(cdivisions-i)/cdivisions+caxis[0]).toFixed(precision);
     39                                        if (format === 'f') {
     40                                                labels[i] = (caxisdelta*(cdivisions-i)/cdivisions+caxis[0]).toFixed(precision);
     41                                        }
     42                                        else if (format === 'e') {
     43                                                labels[i] = (caxisdelta*(cdivisions-i)/cdivisions+caxis[0]).toPrecision(precision);
     44                                        }
     45                                        else {
     46                                                labels[i] = (caxisdelta*(cdivisions-i)/cdivisions+caxis[0]).toFixed(precision);
     47                                        }
    3448                                }
    3549                        } //}}}
    3650                        //{{{ Initialize colorbar canvas
     
    116130        tcontext.fillStyle = tgradient;
    117131        tcontext.fillRect(0, 0, 256, 256);
    118132        tURL = tcanvas.toDataURL();
    119         node.texture = initTexture(gl, tURL);
    120         node.textureCanvas = tcanvas;
    121         node.caxis = options.getfieldvalue('caxis',[ArrayMin(data), ArrayMax(data)]);
     133        canvas.unitNode.texture = initTexture(canvas.gl, tURL);
    122134        //}}}
    123         //{{{ expdisp contours
    124         if (options.exist('expdisp')) {
    125                 canvas.nodes.expdisp = Node(gl, options);
    126                 var node = canvas.nodes.expdisp;
    127                
    128                 //declare variables:  {{{
    129                 var vertices = [];
    130                 var indices = [];
    131                 var colors = [];
    132                 var rgbcolor = [];
    133                 var xmin, xmax;
    134                 var ymin, ymax;
    135                 var zmin, zmax;
    136                 var scale;
    137                
    138                 //Process data and model
    139                 var x = options.getfieldvalue('expdisp').x;
    140                 var y = options.getfieldvalue('expdisp').y;
    141                 var z = Array.apply(null, Array(x.length)).map(Number.prototype.valueOf, 0);
    142                
    143                 if (options.getfieldvalue('expdisp').z) {
    144                         z = options.getfieldvalue('expdisp').z;
    145                 }
    146                 //}}}
    147 
    148                 //Compute coordinates and data range: //{{{
    149                 var modelxlim = [ArrayMin(x), ArrayMax(x)];
    150                 var modelylim = [ArrayMin(y), ArrayMax(y)];
    151                 var modelzlim = [ArrayMin(z), ArrayMax(z)];
    152                 var xlim = options.getfieldvalue('xlim', modelxlim);
    153                 var ylim = options.getfieldvalue('ylim', modelylim);
    154                 var zlim = options.getfieldvalue('zlim', modelzlim);
    155                 xmin = xlim[0];
    156                 xmax = xlim[1];
    157                 ymin = ylim[0];
    158                 ymax = ylim[1];
    159                 zmin = zlim[0];
    160                 zmax = zlim[1];
    161                 //}}}
    162 
    163                 //Compute scaling: //{{{
    164                 var scale = 1 / (xmax - xmin);
    165                 node.shaderName = 'colored';
    166                 node.shader = gl.shaders[node.shaderName].program;
    167                 node.scale = [scale, scale, scale*options.getfieldvalue('heightscale', 1)];
    168                 node.translation = [(xmin + xmax) / (-2 / scale), (ymin + ymax) / (-2 / scale), (zmin + zmax) / (-2 / scale)];
    169                 node.modelMatrix = updateModelMatrix(node);
    170                 node.drawMode = gl.LINE_LOOP;
    171                 node.drawOrder = 0;
    172                 node.useIndexBuffer = false;
    173                 node.disableDepthTest = true;
    174                 //}}}
    175 
    176                 //some defaults:
    177                 colors.itemSize = 4;
    178 
    179                 //retrieve some options
    180                 var linewidth=options.getfieldvalue('linewidth', 1);
    181                 var edgecolor=options.getfieldvalue('edgecolor','black'); //RGBCOLOR?
    182 
    183                 vertices.itemSize = 3;
    184                 for(var i=0; i < x.length; i++){
    185                         vertices[vertices.length] = x[i];
    186                         vertices[vertices.length] = y[i];
    187                         vertices[vertices.length] = z[i];
    188 
    189                         //edgecolor
    190                         rgbcolor = [0.0, 0.0, 0.0];
    191                         colors[colors.length] = rgbcolor[0];
    192                         colors[colors.length] = rgbcolor[1];
    193                         colors[colors.length] = rgbcolor[2];
    194                         colors[colors.length] = 1.0;
    195                 }
    196 
    197                 //Initalize buffers:
    198                 node.arrays = [vertices, colors];
    199                 node.buffers = initBuffers(gl, node.arrays);
    200         } //}}}
    201         //{{{ cloud of points
    202         if (options.exist('cloud')) {
    203                 canvas.nodes.cloud = Node(gl, options);
    204                 var node = canvas.nodes.cloud;
    205 
    206                 //declare variables:  {{{
    207                 var vertices = [];
    208                 var indices = [];
    209                 var colors = [];
    210                 var rgbcolor = [];
    211                 var xmin, xmax;
    212                 var ymin, ymax;
    213                 var zmin, zmax;
    214                 var scale;
    215                
    216                 //Process data and model
    217                 var x = options.getfieldvalue('cloud').x;
    218                 var y = options.getfieldvalue('cloud').y;
    219                 var z = Array.apply(null, Array(x.length)).map(Number.prototype.valueOf, 0);
    220                
    221                 if (options.getfieldvalue('cloud').z) {
    222                         z = options.getfieldvalue('cloud').z;
    223                 }
    224                 //}}}
    225 
    226                 //Compute coordinates and data range: //{{{
    227                 var modelxlim = [ArrayMin(x), ArrayMax(x)];
    228                 var modelylim = [ArrayMin(y), ArrayMax(y)];
    229                 var modelzlim = [ArrayMin(z), ArrayMax(z)];
    230                 var xlim = options.getfieldvalue('xlim', modelxlim);
    231                 var ylim = options.getfieldvalue('ylim', modelylim);
    232                 var zlim = options.getfieldvalue('zlim', modelzlim);
    233                 xmin = xlim[0];
    234                 xmax = xlim[1];
    235                 ymin = ylim[0];
    236                 ymax = ylim[1];
    237                 zmin = zlim[0];
    238                 zmax = zlim[1];
    239                 //}}}
    240 
    241                 //Compute scaling: //{{{
    242                 var scale = 1 / (xmax - xmin);
    243                 node.shaderName = 'colored';
    244                 node.shader = gl.shaders[node.shaderName].program;
    245                 node.scale = [scale, scale, scale*options.getfieldvalue('heightscale', 1)];
    246                 node.translation = [(xmin + xmax) / (-2 / scale), (ymin + ymax) / (-2 / scale), (zmin + zmax) / (-2 / scale)];
    247                 node.modelMatrix = updateModelMatrix(node);
    248                 node.drawMode = gl.POINTS;
    249                 node.drawOrder = 0;
    250                 node.useIndexBuffer = false;
    251                 node.disableDepthTest = true;
    252                 //}}}
    253 
    254                 //some defaults:
    255                 colors.itemSize = 4;
    256 
    257                 //retrieve some options
    258                 var linewidth=options.getfieldvalue('linewidth', 1);
    259                 var edgecolor=options.getfieldvalue('edgecolor','black'); //RGBCOLOR?
    260 
    261                 vertices.itemSize = 3;
    262                 for(var i=0; i < x.length; i++){
    263                         vertices[vertices.length] = x[i];
    264                         vertices[vertices.length] = y[i];
    265                         vertices[vertices.length] = z[i];
    266 
    267                         //edgecolor
    268                         rgbcolor = [0.0, 0.0, 0.0];
    269                         colors[colors.length] = rgbcolor[0];
    270                         colors[colors.length] = rgbcolor[1];
    271                         colors[colors.length] = rgbcolor[2];
    272                         colors[colors.length] = 1.0;
    273                 }
    274 
    275                 //Initalize buffers:
    276                 node.arrays = [vertices, colors];
    277                 node.buffers = initBuffers(gl, node.arrays);
    278         } //}}}
    279135        //{{{ text display
    280136        if (options.exist('textlabels')) {
    281137                var textcanvas, textcanvasid;   
     
    324180                var overlaycanvasid = options.getfieldvalue('latlongoverlayid', options.getfieldvalue('canvasid')+'-overlay');
    325181                var overlaycanvas = $('#'+overlaycanvasid)[0];
    326182                var latitudes = {
    327                         //"-90": 1,
    328                         //"-65": .999,
    329                         "-60": 0.994046875,
    330                         //"-55": 0.983187500000002,
    331                         //"-50": 0.97173550854167,
    332                         "-45": 0.955729166666666,
    333                         //"-40": 0.94218750000000218,
    334                         //"-35": 0.94218750000000218,
    335                         "-30": 0.9226562500000024,
    336                         //"-25": 0.87934895833333526,
    337                         //"-20": 0.856572916666669,
    338                         //"-15": 0.830729166666665,
    339                         //"-10": 0.803552708333336,
    340                         //"-5": 0.77395833333333541,
    341                         "0": 0.74218749999999811,
    342                         //"5": 0.70950364583333347,
    343                         //"10": 0.67479166666666823,
    344                         //"15": 0.63932291666666663,
    345                         //"20": 0.60171875,
    346                         //"25": 0.563453125,
    347                         "30": 0.523390625000001,
    348                         //"35": 0.48401875,
    349                         //"40": 0.44296875,
    350                         "45": 0.4020001,
    351                         //"50": 0.3578125,
    352                         //"55": 0.311875,
    353                         "60": 0.26953124999999978,
    354                         //"65": 0.225390625,
    355                         //"70": 0.18125,
    356                         //"75": 0.13541666666666671,
    357                         //"80": 0.08953125,
    358                         //"85": 0.046250000000000013,
    359                         //"90": 0.0,
     183                        //'-90': 1,
     184                        //'-65': .999,
     185                        '-60': 0.994046875,
     186                        //'-55': 0.983187500000002,
     187                        //'-50': 0.97173550854167,
     188                        '-45': 0.955729166666666,
     189                        //'-40': 0.94218750000000218,
     190                        //'-35': 0.94218750000000218,
     191                        '-30': 0.9226562500000024,
     192                        //'-25': 0.87934895833333526,
     193                        //'-20': 0.856572916666669,
     194                        //'-15': 0.830729166666665,
     195                        //'-10': 0.803552708333336,
     196                        //'-5': 0.77395833333333541,
     197                        '0': 0.74218749999999811,
     198                        //'5': 0.70950364583333347,
     199                        //'10': 0.67479166666666823,
     200                        //'15': 0.63932291666666663,
     201                        //'20': 0.60171875,
     202                        //'25': 0.563453125,
     203                        '30': 0.523390625000001,
     204                        //'35': 0.48401875,
     205                        //'40': 0.44296875,
     206                        '45': 0.4020001,
     207                        //'50': 0.3578125,
     208                        //'55': 0.311875,
     209                        '60': 0.26953124999999978,
     210                        //'65': 0.225390625,
     211                        //'70': 0.18125,
     212                        //'75': 0.13541666666666671,
     213                        //'80': 0.08953125,
     214                        //'85': 0.046250000000000013,
     215                        //'90': 0.0,
    360216                }
    361217                var longitudes = [-150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150, 180];
    362218                overlaycanvas.draw = function(canvas) {
     
    400256                var is2d = meshresults[4];
    401257                var isplanet = meshresults[5];
    402258               
    403                 var modelxlim = [ArrayMin(x), ArrayMax(x)];
    404                 var modelylim = [ArrayMin(y), ArrayMax(y)];
    405                 var modelzlim = [ArrayMin(z), ArrayMax(z)];
    406                 var xlim = options.getfieldvalue('xlim', modelxlim);
    407                 var ylim = options.getfieldvalue('ylim', modelylim);
    408                 var zlim = options.getfieldvalue('zlim', modelzlim);
    409                 xmin = xlim[0];
    410                 xmax = xlim[1];
    411                 ymin = ylim[0];
    412                 ymax = ylim[1];
    413                 zmin = zlim[0];
    414                 zmax = zlim[1];
     259                var xlim = options.getfieldvalue('xlim', [ArrayMin(x), ArrayMax(x)]);
     260                var ylim = options.getfieldvalue('ylim', [ArrayMin(y), ArrayMax(y)]);
     261                var zlim = options.getfieldvalue('zlim', [ArrayMin(z), ArrayMax(z)]);
     262
     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];
    415265               
    416                 var global = vec3.length([(xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2]) < 6371000/10; //tolerance for global models = center is 637100 meters away from center of earth
    417                 var atmosphereScale = 1.25;
    418                 var translation = global ? [(xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2] : [(xmin + xmax) / 2, (ymin + ymax) - 6371000, (zmin + zmax) / 2];
    419                
    420                 if (options.getfieldvalue('render',[]).indexOf('sky')!=-1) {   
    421                         //atmosphere
    422                         var node = Node(gl);
    423                         node.name = "atmosphere";
    424                         node.shaderName = "SkyFromSpace";
    425                         node.shader = gl.shaders[node.shaderName];
    426                         node.drawOrder = 1;
    427                         node.cullFace = gl.FRONT;
    428                         node.enableCullFace = true;
    429                         node.mesh = GL.Mesh.icosahedron({size: 6371000*atmosphereScale, subdivisions: 6});
    430                         node.rotation = [0, 0, 0];
    431                         node.translation = translation;
    432                         node.center = [0, 0, 0];
    433                         updateModelMatrix(node);
    434                         canvas.nodes[node.name] = node;
     266                var renderObjects = options.getfieldvalue('render',{});
     267                if ('sky' in renderObjects && !('sky' in canvas.nodes)) {
     268                        var object = renderObjects.sky;
     269                        object = {
     270                                enabled: defaultFor(object.enabled, true),
     271                                scale: defaultFor(object.scale, 1),
     272                        };
     273                        if (object.enabled) {
     274                                var atmosphereScale = 1.25;
     275                                var mesh = GL.Mesh.icosahedron({size: 6371000 * atmosphereScale, subdivisions: 5});
     276                                var texture = initTexture(gl, canvas.rootPath + 'textures/TychoSkymapII_t4_2k.jpg');
     277                                node = new Node(
     278                                        'canvas', canvas,
     279                                        'options', options,
     280                                        'name', 'sky',
     281                                        'shaderName', 'SkyFromSpace',
     282                                        'cullFace', gl.FRONT,
     283                                        'mesh', mesh,
     284                                        'texture',texture,
     285                                        'translation',translation
     286                                );
     287                        }
    435288                }
    436                 if (options.getfieldvalue('render',[]).indexOf('space')!=-1) { 
    437                         //skysphere
    438                         node = Node(gl);
    439                         node.name = "skysphere";
    440                         node.shaderName = "Textured";
    441                         node.shader = gl.shaders[node.shaderName];
    442                         node.drawOrder = 2;
    443                         node.cullFace = gl.FRONT;
    444                         node.enableCullFace = true;
    445                         node.mesh = GL.Mesh.sphere({size: 6371000*20});
    446                         node.texture = initTexture(gl, canvas.rootPath+'textures/TychoSkymapII_t4_2k.jpg');
    447                         node.rotation = [0, 0, 0];
    448                         node.translation = translation;
    449                         node.center = [0, 0, 0];
    450                         updateModelMatrix(node);
    451                         canvas.nodes[node.name] = node;
     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) {
     296                                var mesh = GL.Mesh.sphere({size: 6371000 * 20});
     297                                var texture = initTexture(gl, canvas.rootPath + 'textures/TychoSkymapII_t4_2k.jpg');
     298                                node = new Node(
     299                                        'canvas', canvas,
     300                                        'options', options,
     301                                        'name', 'space',
     302                                        'shaderName', 'Textured',
     303                                        'cullFace', gl.FRONT,
     304                                        'drawOrder', 2,
     305                                        'mesh', mesh,
     306                                        'texture',texture,
     307                                        'translation',translation
     308                                );
     309                        }
    452310                }
     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,
     324                                        'name', 'coastlines',
     325                                        'shaderName', 'Colored',
     326                                        'drawMode', gl.LINE_STRIP,
     327                                        'lineWidth', options.getfieldvalue('linewidth', 1),
     328                                        'scale', [object.scale, object.scale, object.scale],
     329                                        'rotation', [-90, 0, 0]
     330                                );
     331                                node.patch('Vertices', [object.x, object.y, object.z], 'FaceColor', 'none');
     332                        }
     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,
     347                                        'name', 'graticule',
     348                                        'shaderName', 'Colored',
     349                                        'drawMode', gl.LINE_STRIP,
     350                                        'lineWidth', options.getfieldvalue('linewidth', 1),
     351                                        'scale', [object.scale, object.scale, object.scale],
     352                                        'rotation', [-90, 0, 0]
     353                                );
     354                                node.patch('Vertices', [object.x, object.y, object.z], 'FaceColor', 'none');
     355                        }
     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) {
     370                                var mesh = GL.Mesh.icosahedron({size: object.size, subdivisions: 1});
     371                                node = new Node(
     372                                        'canvas', canvas,
     373                                        'options', options,
     374                                        'name', 'cities',
     375                                        'shaderName', 'Colored',
     376                                        'diffuseColor', object.color,
     377                                        'lineWidth', options.getfieldvalue('linewidth', 1),
     378                                        'scale', [object.scale, object.scale, object.scale],
     379                                        'rotation', [-90, 0, 0]
     380                                );
     381                                node.geometryShader('Mesh', mesh, 'Vertices', [object.x, object.y, object.z], 'Indices', object.indices);
     382                        }
     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) {
     396                                //city
     397                                var mesh = GL.Mesh.sphere({size: object.size});
     398                                node = new Node(
     399                                        'canvas', canvas,
     400                                        'options', options,
     401                                        'name', 'city',
     402                                        'shaderName', 'Colored',
     403                                        'diffuseColor', object.color,
     404                                        'mesh', mesh,
     405                                        'translation', [object.x, object.z, -object.y]
     406                                );
     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');
     415                                        var node = canvas.nodes['city'];
     416                                        node.translation = [object.x, object.z, -object.y];
     417                                        node.updateModelMatrix();
     418                                        var screenPoint = vec3.transformMat4(vec3.create(), node.translation, canvas.camera.vpMatrix);
     419                                        var x = (screenPoint[0] + 1.0) * (canvas.width / 2) + canvas.selector.offset().left;
     420                                        var y = (-screenPoint[1] + 1.0) * (canvas.height / 2) + canvas.selector.offset().top;
     421
     422                                        ctx.font = String(options.getfieldvalue('colorbarfontsize', 22))+'px Arial Black, sans-serif';
     423                                        ctx.fillStyle = options.getfieldvalue('colorbarfontcolor','black');
     424                                        ctx.strokeStyle = 'white';
     425                                        ctx.textAlign = 'center';
     426                                        ctx.textBaseline = 'middle';
     427                                        ctx.fillText(object.name, x, y);
     428                                        ctx.strokeText(object.name, x, y);
     429                                }
     430                                canvas.overlaycanvas = overlaycanvas;
     431                        }
     432                }
    453433                if (canvas.clouds.enabled) {
    454434                        //clouds
    455435                        for (var i = 0; i < canvas.clouds.quantity; i++) {
    456                                 node = Node(gl);
    457                                 node.name = "clouds" + i;
    458                                 node.shaderName = "Clouds";
    459                                 node.shader = gl.shaders[node.shaderName];
    460                                 node.drawOrder = 2;
    461                                 node.cullFace = gl.BACK;
    462                                 node.enableCullFace = true;
    463                                 node.mesh = GL.Mesh.fromURL(canvas.rootPath+'obj/cloud.obj');
    464                                 node.rotation = [0, 0, 0];
    465                                 node.scale = [2500, 2500, 2500];
    466                                 node.translation = [translation[0], translation[1] - 405000, translation[2]];
    467                                 node.center = [0, 0, 0];
    468                                 node.animation = {"time": Date.now(),"target": node.translation,"current": node.translation};
    469                                 updateModelMatrix(node);
    470                                 canvas.nodes[node.name] = node;
    471                                 //canvas.clouds.list
     436                                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                                );
    472449                        }
    473                         //TODO: Steven, please add <canvas.clouds.quantity> total cloud nodes, randomly spread over the mesh, giving each one a new name and adding them to the canvas.clouds.list so that we can track them later.
    474                        
    475450                }
    476                 if (options.getfieldvalue('render',[]).indexOf('latlong')!=-1) {       
    477                         //latlong
    478                         node = Node(gl);
    479                         node.name = "clouds";
    480                         node.shaderName = "Clouds";
    481                         node.shader = gl.shaders[node.shaderName];
    482                         node.drawOrder = 2;
    483                         node.cullFace = gl.BACK;
    484                         node.enableCullFace = true;
    485                         node.mesh = GL.Mesh.fromURL(canvas.rootPath+'obj/cloud.obj');
    486                         node.rotation = [0, 0, 0];
    487                         node.scale = [2500, 2500, 2500];
    488                         node.translation = [translation[0], translation[1] - 405000, translation[2]];
    489                         node.center = [0, 0, 0];
    490                         node.animation = {"time": Date.now(),"target": node.translation,"current": node.translation};
    491                         updateModelMatrix(node);
    492                         canvas.nodes[node.name] = node;
    493                 }
    494451        } //}}}
    495452} //}}}
  • ../trunk-jpl/src/m/plot/plot_transient_movie.m

     
    66%   See also: PLOTMODEL, PLOT_UNIT, PLOT_MANAGER
    77
    88        %prepare subplot
    9         subplot(width,width,i); 
     9        subplot(width,width,i);
    1010
    1111        %xlim
    1212        if exist(options,'transient_movie_field'),
  • ../trunk-jpl/src/m/plot/webgl_node.js

     
     1//NODE class definition //{{{
     2//      Description:
     3//              Contains all information for rendering an object in WebGL, including mesh, materials, shaders, and other attributes.   
     4//      Usage:
     5//              node=new Node('canvas', canvas);
     6
     7function Node() { //{{{
     8        //properties
     9        // {{{
     10        var args = Array.prototype.slice.call(arguments);
     11        var options = new pairoptions(args.slice(0,args.length));
     12
     13        this.canvas = options.getfieldvalue('canvas',                                                           null),
     14        this.options = options.getfieldvalue('options',                                                         null),
     15        this.gl = canvas.gl;
     16       
     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())
     55        //}}}
     56        //initialize {{{
     57        //if (this.name in canvas.nodes) abort?
     58        this.updateModelMatrix();
     59        this.updateDiffuseColor();
     60        canvas.nodes[this.name] = this;
     61        //}}}
     62} //}}}
     63Node.prototype.updateModelMatrix = function() { //{{{
     64        //Update the model matrix if rotation, scale, or translation have been manually modified.
     65        var modelMatrix = mat4.create();
     66
     67        var translationMatrix = mat4.create();
     68        mat4.translate(translationMatrix, translationMatrix, vec3.negate(vec3.create(), this.center)); //scale/rotation centering
     69        mat4.multiply(modelMatrix, translationMatrix, modelMatrix);
     70       
     71        var scaleMatrix = mat4.create();
     72        mat4.scale(scaleMatrix, scaleMatrix, this.scale);
     73        mat4.multiply(modelMatrix, scaleMatrix, modelMatrix);
     74       
     75        var rotationMatrix = mat4.create();
     76        var zRotationMatrix = mat4.create();   
     77        mat4.rotate(zRotationMatrix, zRotationMatrix, DEG2RAD * this.rotation[2], [0.0, 0.0, 1.0]);
     78        mat4.multiply(rotationMatrix, zRotationMatrix, rotationMatrix);
     79        var yRotationMatrix = mat4.create();   
     80        mat4.rotate(yRotationMatrix, yRotationMatrix, DEG2RAD * this.rotation[1], [0.0, 1.0, 0.0]);
     81        mat4.multiply(rotationMatrix, yRotationMatrix, rotationMatrix);
     82        var xRotationMatrix = mat4.create();   
     83        mat4.rotate(xRotationMatrix, xRotationMatrix, DEG2RAD * this.rotation[0], [1.0, 0.0, 0.0]);
     84        mat4.multiply(rotationMatrix, xRotationMatrix, rotationMatrix);
     85        mat4.multiply(modelMatrix, rotationMatrix, modelMatrix);       
     86       
     87        mat4.identity(translationMatrix);
     88        mat4.translate(translationMatrix, translationMatrix, this.center); //relative translation
     89        mat4.multiply(modelMatrix, translationMatrix, modelMatrix);
     90       
     91        mat4.identity(translationMatrix);
     92        mat4.translate(translationMatrix, translationMatrix, this.translation); //absolute translation
     93        mat4.multiply(modelMatrix, translationMatrix, modelMatrix);
     94       
     95        this.modelMatrix = modelMatrix;
     96        this.inverseModelMatrix = mat4.invert(mat4.create(), modelMatrix);
     97        this.rotationMatrix = rotationMatrix;
     98        this.inverseRotationMatrix = mat4.invert(mat4.create(), rotationMatrix);
     99} //}}}
     100Node.prototype.updateDiffuseColor = function() { //{{{
     101        //Update the diffuse color with an RGB color name or vec4 containing r, g, b, and alpha values from 0.0 to 1.0
     102        var color = this.diffuseColor;
     103        if (typeof color === 'string') {
     104                color = new RGBColor(color);
     105                if (color.ok) color = [color.r/255.0, color.g/255.0, color.b/255.0, 1.0];
     106                else throw Error(sprintf("s%s%s\n","initWebGL error message: cound not find out edgecolor color for curent canvas ", canvas));
     107        }
     108        this.diffuseColor = color;
     109} //}}}
     110Node.prototype.transform = function() { //{{{
     111        //Transforms the translation, rotation, or scle fo the node and updates the model matrix.
     112        var args = Array.prototype.slice.call(arguments);
     113        var options = new pairoptions(args.slice(0,args.length));
     114       
     115        var translation = options.getfieldvalue('translation', undefined);
     116        var rotation = options.getfieldvalue('rotation', undefined);
     117        var scale = options.getfieldvalue('scale', undefined);
     118       
     119        if (!isEmptyOrUndefined(translation)) this.translation = translation;
     120        if (!isEmptyOrUndefined(rotation)) this.rotation = rotation;
     121        if (!isEmptyOrUndefined(scale)) this.scale = scale;
     122        this.updateModelMatrix();
     123} //}}}
     124Node.prototype.patch = function() { //{{{
     125        //Emulates the behavior of MATLAB patch function by constructing a mesh from arguments.
     126        //Limitations:
     127        //      -Expects pair labeled arguments ('FaceColor','none',...).
     128        //      -Only handles Face/Vertices/FaceVertexCData element/node plots.
     129        //      -Only supports FaceColor 'interp' and 'none'.
     130       
     131        var args = Array.prototype.slice.call(arguments);
     132        var options = new pairoptions(args.slice(0,args.length));
     133
     134        var faces = options.getfieldvalue('Faces', undefined);
     135        var vertices = options.getfieldvalue('Vertices', undefined);
     136        var faceVertexCData = options.getfieldvalue('FaceVertexCData', undefined);
     137        var faceColor = options.getfieldvalue('FaceColor', 'interp');
     138        var edgeColor = options.getfieldvalue('EdgeColor', this.diffuseColor);
     139        var lineWidth = options.getfieldvalue('linewidth', 1);
     140       
     141        this.faces = faces;
     142        this.vertices = vertices;
     143        this.diffuseColor = edgeColor;
     144        this.updateDiffuseColor();
     145       
     146        this.patchVertices(faceVertexCData, faces, vertices);
     147        this.patchCoords(faceVertexCData, faces, vertices);
     148        this.patchIndices(faces, faceColor);
     149
     150        this.mesh = GL.Mesh.load(this.arrays, null, null, this.gl);
     151        //this.mesh.computeNormals();
     152        this.computeOctree();
     153} //}}}
     154Node.prototype.patchVertices = function(faceVertexCData, faces, vertices) { //{{{
     155        //Patch subfunction for processing xyz vertices.
     156        var vertexArray;
     157        var face;
     158       
     159        if (isEmptyOrUndefined(faceVertexCData)) {
     160                vertexArray = new Float32Array(vertices[0].length * 3);
     161                for(var i = 0, v = 0; i < vertices[0].length; i++) {   
     162                        vertexArray[v++] = vertices[0][i];
     163                        vertexArray[v++] = vertices[1][i];
     164                        vertexArray[v++] = vertices[2][i];
     165                }
     166        }
     167        else if (!Array.isArray(faceVertexCData[0])) { //indexed plot - faceVertexCData = [0, 2.32, 231.1, ...]
     168                if (faceVertexCData.length === faces.length) { //element plot
     169                        vertexArray = new Float32Array(faces.length * 3 * 3);
     170                        for(var i = 0, v = 0, t = 0; i < faces.length; i++) {
     171                                face = [faces[i][0] - 1, faces[i][1] - 1, faces[i][2] - 1];
     172                                for(var j = 0; j < face.length; j++) {
     173                                        if (isNaN(faceVertexCData[i])) {
     174                                                this.nanIndices.add(i);
     175                                                vertexArray[v++] = 0.0;
     176                                                vertexArray[v++] = 0.0;
     177                                                vertexArray[v++] = 0.0;
     178                                        }
     179                                        else {
     180                                                vertexArray[v++] = vertices[0][face[j]];
     181                                                vertexArray[v++] = vertices[1][face[j]];
     182                                                vertexArray[v++] = vertices[2][face[j]];
     183                                        }
     184                                }
     185                        }
     186                        this.computeIndices = false;
     187                }
     188                else if (faceVertexCData.length === vertices[0].length) { //node plot
     189                        vertexArray = new Float32Array(vertices[0].length * 3);
     190                        for(var i = 0, v = 0, t = 0; i < vertices[0].length; i++) {
     191                                if (isNaN(faceVertexCData[i])) {
     192                                        this.nanIndices.add(i);
     193                                        vertexArray[v++] = 0.0;
     194                                        vertexArray[v++] = 0.0;
     195                                        vertexArray[v++] = 0.0;
     196                                }
     197                                else {
     198                                        vertexArray[v++] = vertices[0][i];
     199                                        vertexArray[v++] = vertices[1][i];
     200                                        vertexArray[v++] = vertices[2][i];
     201                                }
     202                        }
     203                }
     204        }
     205        else if (Array.isArray(faceVertexCData[0])) { //JS specific: precomputed UV coord plot - faceVertexCData = [[0, 0.99, 0.4, ...],[0, 0.99, 0.4, ...]]
     206                if (faceVertexCData[0].length === faces.length) { //element plot
     207                        vertexArray = new Float32Array(faces.length * 3 * 3);
     208                        for(var i = 0, v = 0, t = 0; i < faces.length; i++) {
     209                                face = [faces[i][0] - 1, faces[i][1] - 1, faces[i][2] - 1];
     210                                for(var j = 0; j < face.length; j++) {                                 
     211                                        vertexArray[v++] = vertices[0][face[j]];
     212                                        vertexArray[v++] = vertices[1][face[j]];
     213                                        vertexArray[v++] = vertices[2][face[j]];
     214                                }
     215                        }
     216                        this.computeIndices = false;
     217                }
     218                else if (faceVertexCData[0].length === vertices[0].length) { //node plot
     219                        vertexArray = new Float32Array(vertices[0].length * 3);
     220                        for(var i = 0, v = 0, t = 0; i < vertices[0].length; i++) {
     221                                vertexArray[v++] = vertices[0][i];
     222                                vertexArray[v++] = vertices[1][i];
     223                                vertexArray[v++] = vertices[2][i];
     224                        }
     225                }
     226        }
     227        this.arrays.vertices = vertexArray;
     228} //}}}
     229Node.prototype.patchCoords = function(faceVertexCData, faces, vertices) { //{{{
     230        //Patch subfunction for processing texture coords/UVs.
     231        var coordArray;
     232        var cramge;
     233        var caxis = this.caxis;
     234        var face;
     235       
     236        if (isEmptyOrUndefined(faceVertexCData)) { return; }
     237       
     238        //Use logarithmic scaling if it is valid
     239        if (this.log !== false && this.log !== 'off') {
     240                caxis = [
     241                        Math.log10(caxis[0]) / Math.log10(this.log),
     242                        Math.log10(caxis[1]) / Math.log10(this.log)
     243                ];
     244        }
     245       
     246        if (!Array.isArray(faceVertexCData[0])) { //indexed plot - faceVertexCData = [0, 2.32, 231.1, ...]
     247                if (faceVertexCData.length === faces.length) { //element plot
     248                        coordArray = new Float32Array(faces.length * 3 * 2);
     249                        crange = caxis[1] - caxis[0];
     250                        for(var i = 0, v = 0, t = 0; i < faces.length; i++) {
     251                                face = [faces[i][0] - 1, faces[i][1] - 1, faces[i][2] - 1];
     252                                for(var j = 0; j < face.length; j++) {
     253                                        if (isNaN(faceVertexCData[i])) {
     254                                                this.nanIndices.add(i);
     255                                                coordArray[t++] = 0.0;
     256                                                coordArray[t++] = 0.0;
     257                                        }
     258                                        else {
     259                                                coordArray[t++] = 0.5;
     260                                                coordArray[t++] = clamp((faceVertexCData[i] - caxis[0]) / crange, 0.0, 1.0);
     261                                        }
     262                                }
     263                        }
     264                        this.computeIndices = false;
     265                }
     266                else if (faceVertexCData.length === vertices[0].length) { //node plot
     267                        coordArray = new Float32Array(vertices[0].length * 2);
     268                        crange = caxis[1] - caxis[0];
     269                        for(var i = 0, v = 0, t = 0; i < vertices[0].length; i++) {
     270                                if (isNaN(faceVertexCData[i])) {
     271                                        this.nanIndices.add(i);
     272                                        coordArray[t++] = 0.0;
     273                                        coordArray[t++] = 0.0;
     274                                }
     275                                else {
     276                                        coordArray[t++] = 0.5;
     277                                        coordArray[t++] = clamp((faceVertexCData[i] - caxis[0]) / crange, 0.0, 1.0);
     278                                }
     279                        }
     280                }
     281        }
     282        else if (Array.isArray(faceVertexCData[0])) { //JS specific: precomputed UV coord plot - faceVertexCData = [[0, 0.99, 0.4, ...],[0, 0.99, 0.4, ...]]
     283                if (faceVertexCData[0].length === faces.length) { //element plot
     284                        coordArray = new Float32Array(faces.length * 3 * 2);
     285                        for(var i = 0, v = 0, t = 0; i < faces.length; i++) {
     286                                face = [faces[i][0] - 1, faces[i][1] - 1, faces[i][2] - 1];
     287                                for(var j = 0; j < face.length; j++) {                                 
     288                                        coordArray[t++] = faceVertexCData[0][i];
     289                                        coordArray[t++] = faceVertexCData[1][i];
     290                                }
     291                        }
     292                        this.computeIndices = false;
     293                }
     294                else if (faceVertexCData[0].length === vertices[0].length) { //node plot
     295                        coordArray = new Float32Array(vertices[0].length * 2);
     296                        for(var i = 0, v = 0, t = 0; i < vertices[0].length; i++) {
     297                                coordArray[t++] = faceVertexCData[0][i];
     298                                coordArray[t++] = faceVertexCData[1][i];
     299                        }
     300                }
     301        }
     302        this.arrays.coords = coordArray;
     303} //}}}
     304Node.prototype.patchIndices = function(faces, faceColor) { //{{{
     305        //Patch subfunction for processing faces/elements/triangles/indices.
     306        var indexArray;
     307        var face;
     308       
     309        if (faceColor === 'none') { //Check for wireframe mesh rendering
     310                if (this.drawMode === this.gl.TRIANGLES) { //NOTE: Stopgap to allow gl.LINE_STRIP nodes render normally. Only use case for faceColor === 'none' is for plot_mesh
     311                        this.drawMode = this.gl.LINES;
     312                }
     313        }
     314       
     315        if (this.computeIndices === true && !isEmptyOrUndefined(faces)) {
     316                if (!isEmptyOrUndefined(faces[0])) { //Check for 2D format and process if needed
     317                        if (faceColor !== 'none') { //Check for triangle rendering
     318                                indexArray = new Uint16Array(faces.length * 3);
     319                                for(var i = 0, f = 0; i < faces.length; i++) {
     320                                        face = [faces[i][0] - 1, faces[i][1] - 1, faces[i][2] - 1];
     321                                        if (this.nanIndices.has(face[0]) || this.nanIndices.has(face[1]) || this.nanIndices.has(face[2])) continue; //Skip triangle if contains NaN value.
     322                                        indexArray[f++] = faces[i][0] - 1;
     323                                        indexArray[f++] = faces[i][1] - 1;
     324                                        indexArray[f++] = faces[i][2] - 1;
     325                                }
     326                        }
     327                        else { //Check for wireframe mesh rendering
     328                                indexArray = new Uint16Array(faces.length * 6);
     329                                for(var i = 0, f = 0; i < faces.length; i++) {
     330                                        indexArray[f++] = faces[i][0] - 1;
     331                                        indexArray[f++] = faces[i][1] - 1;
     332                                        indexArray[f++] = faces[i][1] - 1;
     333                                        indexArray[f++] = faces[i][2] - 1;
     334                                        indexArray[f++] = faces[i][2] - 1;
     335                                        indexArray[f++] = faces[i][0] - 1;
     336                                }
     337                        }
     338                }
     339                else { //Else, assume face indices have already been processed
     340                        indexArray = faces;
     341                }
     342                this.arrays.triangles = indexArray;
     343        }
     344} //}}}
     345Node.prototype.updateBuffer = function() { //{{{
     346        //Updates the mesh buffers provided in place.
     347        //NOTE: Only support coord buffers currently.
     348        var args = Array.prototype.slice.call(arguments);
     349        var options = new pairoptions(args.slice(0,args.length));
     350
     351        var coords = options.getfieldvalue('Coords', undefined);
     352        var cacheIndex = options.getfieldvalue('CacheIndex', false);
     353       
     354        if (!isEmptyOrUndefined(coords)) {
     355                this.patchCoords(coords, this.faces, this.vertices);
     356                var buffer = this.mesh.getBuffer("coords");
     357                buffer.data = this.arrays.coords;
     358                buffer.upload(this.gl.DYNAMIC_DRAW);
     359        }
     360} //}}}
     361Node.prototype.computeOctree = function() { //{{{
     362        //Computes and caches octrees for a node.
     363        var octree = this.canvas.octrees[this.name];
     364        if (isEmptyOrUndefined(octree)) {
     365                octree = new GL.Octree(this.mesh);
     366        }
     367        this.canvas.octrees[this.name] = octree;
     368        this.octree = octree;
     369} //}}}
     370Node.prototype.geometryShader = function() { //{{{
     371        //Emulates OpenGL geometry shaders by rendering each point as a mesh.
     372        //Parameters:
     373        //      Mesh - the geometry to duplicate for each point.
     374        //      Vertices - the list of points to shade.
     375        //      Indices - (optional) ordered list for non-ordered Vertices objects.
     376       
     377        var args = Array.prototype.slice.call(arguments);
     378        var options = new pairoptions(args.slice(0,args.length));
     379
     380        var mesh = options.getfieldvalue('Mesh', undefined);
     381        var vertices = options.getfieldvalue('Vertices', undefined);
     382        var indices = options.getfieldvalue('Indices', undefined);
     383       
     384        //For handling key-value object arrays, like xcity
     385        for (var i = 0; i < vertices.length; i++) {
     386                if (!Array.isArray(vertices[i])) {
     387                        var array = [];
     388                        var coordinateObject = vertices[i];
     389                        var j = 0;
     390                        if (isEmptyOrUndefined(indices)) {
     391                                for (var key in object) {
     392                                        array[j++] = coordinateObject[key];
     393                                }
     394                        }
     395                        else {
     396                                for (var k = 0; k < indices.length; k++) {
     397                                        array[j++] = coordinateObject[indices[k]];
     398                                }
     399                        }
     400                        vertices[i] = array;
     401                }
     402        }
     403       
     404        var x = vertices[0];
     405        var y = vertices[1];
     406        var z = vertices[2];
     407        var meshVertices = mesh.getBuffer('vertices').data;
     408        var meshIndicies = mesh.getIndexBuffer('triangles').data;
     409        var indicies = new Uint16Array(meshIndicies.length * x.length);
     410        var size = meshVertices.length * x.length / 3;
     411        newX = new Float32Array(size);
     412        newY = new Float32Array(size);
     413        newZ = new Float32Array(size);
     414       
     415        //For each vertex in vertices, instantiate mesh geomtry centered around that point.
     416        for(var i = 0, v = 0, e = 0; i < x.length; i++){
     417                var vector = [x[i], y[i], z[i]];
     418                for (var j = 0; j < meshVertices.length;) {
     419                        newX[v] = meshVertices[j++] + x[i];
     420                        newY[v] = meshVertices[j++] + y[i];
     421                        newZ[v++] = meshVertices[j++] + z[i];
     422                }
     423                var offset = i * meshVertices.length / 3;
     424                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} //}}}
     431Node.prototype.scaleVertices = function(md, x, y, z, scale) { //{{{
     432        //Scales and returns vertices x, y, and z by factor scale. Uses md.geometry.scale for heightscaling in 3d meshes.
     433        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];
     445                }
     446        }
     447        else {
     448                z = z.slice();
     449                var zMin = ArrayMin(md.geometry.surface);
     450                for(var i = 0; i < z.length; i++) {
     451                        z[i] = (z[i] - zMin) * scale + zMin;
     452                }
     453        }
     454        return [x, y, z];
     455} //}}}
     456Node.prototype.mergeVertices = function(x1, y1, z1, elements1, x2, y2, z2, elements2) { //{{{
     457        //Merges and returns two sets of indexed xyz vertices.
     458        elements2 = elements2.slice();
     459        for (var i = 0, offset = x1.length; i < elements2.length; i++) {
     460                elements2[i] = [elements2[i][0] + offset, elements2[i][1] + offset, elements2[i][2] + offset];
     461        }
     462        return {x:x1.concat(x2), y:y1.concat(y2), z:z1.concat(z2), elements:elements1.concat(elements2)};
     463} //}}}
     464//}}}
  • ../trunk-jpl/src/m/plot/plot_manager.js

     
    1313        var data = options.getfieldvalue('data');
    1414        var canvas = initCanvas(options);
    1515        var gl = canvas.gl;
    16         //TODO: each plot_ should add their node to the canvas.node array
     16
    1717        //figure out if this is a special plot
    1818        if (typeof data === 'string'){
    1919               
     
    8080                                plot_mesh(md,options,canvas);
    8181                                return;
    8282                        case 'none':
    83                                 if (!(options.exist('overlay'))){
    84                                         plot_none(md,options,nlines,ncols,i);
    85                                 }
     83                                //if (!(options.exist('overlay'))){
     84                                //      plot_none(md,options,nlines,ncols,i);
     85                                //}
    8686                                return;
    8787                        case 'penalties':
    8888                                plot_penalties(md,options,subplotwidth,i);
     
    150150                                plot_thermaltransient_results(md,options,subplotwidth,i);
    151151                                return;
    152152                        case 'transient_movie':
    153                                 plot_transient_movie(md,options,subplotwidth,i);
     153                                plot_transient_movie(md,options,canvas);
    154154                                return;
    155155                        case 'transient_results':
    156156                                plot_transient_results(md,options,subplotwidth,i);
     
    204204        //plot unit
    205205        plot_unit(md,data2,datatype,options,canvas);
    206206
    207         applyoptions(md,data2,datatype,options,canvas,gl,canvas.nodes[canvas.nodes.length-1]);
     207        applyoptions(md,data2,options,canvas);
    208208} //}}}
  • ../trunk-jpl/src/m/plot/plot_unit.js

     
    66        //
    77        //   See also: PLOTMODEL, PLOT_MANAGER
    88
    9         //{{{ declare variables:
     9        //if ('unit' in canvas.nodes) {
     10        //      if (
     11        //      canvas.nodes.unit.updateBuffer('Coords', data);
     12        //      return;
     13        //}
     14        //else {
     15               
     16        //{{{ declare variables:
    1017        //Process data and model
    1118        var meshresults = processmesh(md, data, options);
    1219        var x = meshresults[0];
     
    1522        var elements = meshresults[3];
    1623        var is2d = meshresults[4];
    1724        var isplanet = meshresults[5];
     25        if (md.mesh.classname() !== 'mesh3dsurface') z = md.geometry.surface;
    1826       
    19         var vertices = new Float32Array(x.length * 3);
    20         var texcoords = new Float32Array(x.length * 2);
    21         var indices = new Uint16Array(elements.length * 3);
    22         var nanindices = {};
    23         var xmin, xmax;
    24         var ymin, ymax;
    25         var zmin, zmax;
    26         var datamin, datamax, datadelta;
    27         var matrixscale, vertexscale;
    28         //Compue scaling through matrices for 2d meshes and vertices for 3d meshes
    29         if (!md.geometry.surface) {
    30                 md.geometry.surface=NewArrayFill(md.mesh.x.length, 0);
     27        //Compute coordinates and data range:
     28        var xlim = options.getfieldvalue('xlim', [ArrayMin(x), ArrayMax(x)]);
     29        var ylim = options.getfieldvalue('ylim', [ArrayMin(y), ArrayMax(y)]);
     30        var zlim = options.getfieldvalue('zlim', [ArrayMin(z), ArrayMax(z)]);
     31       
     32        //Handle heightscale
     33        var vertices, scale;
     34        if (md.mesh.classname() !== 'mesh3dsurface') {
     35                vertices = [x, y, z];
     36                scale = [1, 1, options.getfieldvalue('heightscale', 1)];
    3137        }
    32         if (md.mesh.classname() == 'mesh3dsurface') {
    33                 matrixscale = 1;
    34                 vertexscale = options.getfieldvalue('heightscale', 1);
    35         }
    3638        else {
    37                 if (md.geometry.surface) {
    38                         z=md.geometry.surface;
    39                 }       
    40                 matrixscale = options.getfieldvalue('heightscale', 1);
    41                 vertexscale = 0;
     39                vertices = Node.prototype.scaleVertices(md, x, y, z, options.getfieldvalue('heightscale', 1));
     40                scale = [1, 1, 1];
    4241        }
    43         //}}}
    44 
    45         //Compute coordinates and data range:
    46         var modelxlim = [ArrayMin(x), ArrayMax(x)];
    47         var modelylim = [ArrayMin(y), ArrayMax(y)];
    48         var modelzlim = [ArrayMin(z), ArrayMax(z)];
    49         var xlim = options.getfieldvalue('xlim', modelxlim);
    50         var ylim = options.getfieldvalue('ylim', modelylim);
    51         var zlim = options.getfieldvalue('zlim', modelzlim);
    52         xmin = xlim[0];
    53         xmax = xlim[1];
    54         ymin = ylim[0];
    55         ymax = ylim[1];
    56         zmin = zlim[0];
    57         zmax = zlim[1];
    58         var caxis;
    59 
     42       
    6043        //Compute gl variables:
    61         var gl = canvas.gl;
    62         var node = Node(gl);
    63         canvas.nodes[canvas.nodes.length] = node;
     44        var edgecolor = options.getfieldvalue('edgecolor', 'black');
     45        var maskzeros = options.getfieldvalue('maskzeros', {});
     46        var node = new Node(
     47                'canvas', canvas,
     48                'options', options,
     49                'name', 'unit',
     50                'shaderName', 'Textured',
     51                'alpha', options.getfieldvalue('alpha', 1.0),
     52                'caxis', options.getfieldvalue('caxis',[ArrayMin(data), ArrayMax(data)]),
     53                //'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, md.mesh.classname() === 'mesh3dsurface' ? (zlim[0] + zlim[1]) / 2 : zlim[0]],
     54                'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2],
     55                'diffuseColor', edgecolor,
     56                'enabled', options.getfieldvalue('nodata','off') == 'off',
     57                'log', options.getfieldvalue('log',false),
     58                'maskEnabled', options.getfieldvalue('innermask','off') == 'on',
     59                'maskHeight', options.getfieldvalue('innermaskheight', 150.0) / options.getfieldvalue('heightscale', 1),
     60                'maskColor', options.getfieldvalue('innermaskcolor',[0.0, 0.0, 1.0, 1.0]),
     61                'maskZerosColor', defaultFor(maskzeros.color,[1.0, 1.0, 1.0, 1.0]),
     62                'maskZerosEnabled', defaultFor(maskzeros.enabled,false),
     63                'maskZerosTolerance', defaultFor(maskzeros.tolerance,1e-3),
     64                'maskZerosZeroValue', defaultFor(maskzeros.zeroValue,0.5),
     65                'rotation', [-90, 0, 0],
     66                'scale', scale
     67        );
     68        //}
    6469        canvas.unitNode = node;
    6570        canvas.unitData = data;
    66         node.name = "unit";
    67         node.shaderName = "Textured";
    68         node.shader = gl.shaders[node.shaderName];
    69         node.scale = [1, 1, matrixscale];
    70         node.rotation = [-90, 0, 0];
    71         node.translation = [0, 0, 0];
    72         node.center = [(xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2];
    73         node.alpha = options.getfieldvalue('alpha', 1.0);
    74         node.drawOrder = 1;
    75         node.maskEnabled = options.getfieldvalue('innermask','off') == 'on';
    76         node.maskHeight = options.getfieldvalue('innermaskheight', 150.0);
    77         node.maskColor = options.getfieldvalue('innermaskcolor',[0.0, 0.0, 1.0, 1.0]);
    78         node.enabled = options.getfieldvalue('nodata','off') == 'off';
    79         updateModelMatrix(node);
    80 
     71        //}}}
    8172        switch(datatype){
    8273                //{{{ element plot
    8374                case 1:
     75                        //WARNING: NaN are not properly found (NaN != NaN = true)
    8476                        pos=ArrayFindNot(data, NaN); //needed for element on water
    8577                        if (elements[0].length==6){ //prisms
    8678                        }
    8779                        else if (elements[0].length==4){ //tetras
    8880                        }
    89                         else{ //2D triangular elements
     81                        else{ //triangular elements
     82                                node.patch('Faces', elements, 'Vertices', vertices, 'FaceVertexCData', data, 'FaceColor', 'flat', 'EdgeColor', edgecolor);
    9083                        }
    9184                        break;
    9285                //}}}
     
    9790                        else if (elements[0].length==4){ //tetras
    9891                        }
    9992                        else{ //triangular elements     
    100                                 caxis = options.getfieldvalue('caxis',[ArrayMin(data), ArrayMax(data)]);
    101                                 if (options.getfieldvalue('log','off')!='off') caxis = [Math.log10(caxis[0])/Math.log10(options.getfieldvalue('log', 10)), Math.log10(caxis[1])/Math.log10(options.getfieldvalue('log', 10))];
    102                                 datamin = caxis[0];
    103                                 datamax = caxis[1];
    104                                 datadelta = datamax - datamin;
    105 
    106                                 var xyz = vec3.create();
    107                                 var direction = vec3.create();
    108                                 var vertex = vec3.create();
    109                                 var magnitude;
    110 
    111                                 for(var i = 0, vindex = 0, tindex = 0; i < x.length; i++){
    112                                         //Check for NaN values and remove from indices array as necessary, but preserve vertex array spacing
    113                                         if (isNaN(x[i]) || isNaN(y[i]) || isNaN(z[i]) || isNaN(data[i])) {
    114                                                 nanindices[i] = i;
    115                                                 vertices[vindex++] = vertex[0];
    116                                                 vertices[vindex++] = vertex[1];
    117                                                 vertices[vindex++] = vertex[2];
    118                                                
    119                                                 texcoords[tindex++] = 0.5;
    120                                                 texcoords[tindex++] = 0.0;
    121                                                 continue;
    122                                         }
    123 
    124                                         //Scale vertices
    125                                         xyz = vec3.fromValues(x[i], y[i], z[i]);
    126                                         magnitude = vec3.length(xyz) + md.geometry.surface[i] * vertexscale;
    127                                         vec3.normalize(direction, xyz);
    128                                         vec3.scale(vertex, direction, magnitude);
    129                                         vertices[vindex++] = vertex[0];
    130                                         vertices[vindex++] = vertex[1];
    131                                         vertices[vindex++] = vertex[2];
    132 
    133                                         texcoords[tindex++] = 0.5;
    134                                         texcoords[tindex++] = clamp((data[i] - datamin) / datadelta, 0.0, 1.0);
    135                                 }
    136 
    137                                 //linearize the elements array:
    138                                 var element;
    139                                 for(var i = 0, iindex = 0; i < elements.length; i++){
    140                                         element = [elements[i][0] - 1, elements[i][1] - 1, elements[i][2] - 1];
    141                                         if (element[0] in nanindices || element[1] in nanindices || element[2] in nanindices) continue;
    142                                         indices[iindex++] = element[0];
    143                                         indices[iindex++] = element[1];
    144                                         indices[iindex++] = element[2];
    145                                 }
     93                                node.patch('Faces', elements, 'Vertices', vertices, 'FaceVertexCData', data, 'FaceColor', 'interp', 'EdgeColor', edgecolor);
    14694                        }
    147                         node.mesh = GL.Mesh.load({vertices: vertices, coords: texcoords, triangles: indices}, null, null, gl);
    148                         node.mesh.octree = new GL.Octree(node.mesh);
    14995                        break;
    15096                //}}}
    15197                //{{{ quiver plot
     
    158104                        }
    159105                        break;
    160106                //}}}
    161                 //{{{ node transient plot
    162                 case 5:
    163                         if (elements[0].length==6){ //prisms
    164                         }
    165                         else if (elements[0].length==4){//tetras
    166                         }
    167                         else{ //triangular elements
    168                                 var xyz = vec3.create();
    169                                 var direction = vec3.create();
    170                                 var vertex = vec3.create();
    171                                 var magnitude;
    172                                 var timestamps = data[data.length-1];
    173                                 for(var i = 0, vindex = 0, tindex = 0; i < x.length; i++){
    174                                         //Check for NaN values and remove from indices array as necessary, but preserve vertex array spacing
    175                                         if (isNaN(x[i]) || isNaN(y[i]) || isNaN(z[i]) || isNaN(data[i][0])) {
    176                                                 nanindices[i] = i;
    177                                         }
    178                                         else {
    179                                                 //Scale vertices
    180                                                 xyz = vec3.fromValues(x[i], y[i], z[i]);
    181                                                 magnitude = vec3.length(xyz) + md.geometry.surface[i] * vertexscale;
    182                                                 vec3.normalize(direction, xyz);
    183                                                 vec3.scale(vertex, direction, magnitude);
    184                                         }
    185                                         vertices[vindex++] = vertex[0];
    186                                         vertices[vindex++] = vertex[1];
    187                                         vertices[vindex++] = vertex[2];
    188                                 }       
    189                                 //Transpose data to obtain column addressable data matrix
    190                                 data = data[0].map(function(col, i) {
    191                                         return data.map(function(row) {
    192                                                 return row[i]
    193                                         })
    194                                 });
    195                                 //Prevent evaluation of datasubarray min/max if caxis exists
    196                                 if (options.exist('caxis')) caxis = options.getfieldvalue('caxis');
    197                                 else caxis = [ArrayMin(data[0]), ArrayMax(data[0].slice(0,-1))];
    198                                 if (options.getfieldvalue('log','off')!='off') caxis = [Math.log10(caxis[0])/Math.log10(options.getfieldvalue('log', 10)), Math.log10(caxis[1])/Math.log10(options.getfieldvalue('log', 10))];
    199                                 //Prepare texcoords to hold array of data values
    200                                 texcoords = [];
    201                                 for(var i = 0; i < data.length; i++){                                   
    202                                         datamin = caxis[0];
    203                                         datamax = caxis[1];
    204                                         datadelta = datamax - datamin;
    205                                         //Precalculate arrays for each datasubarray, trimming off timestamp value by using x.length instead of data[i].length
    206                                         texcoords[i] = new Float32Array(x.length * 2);
    207                                         for(var j = 0, index = 0; j < x.length; j++){
    208                                                 texcoords[i][index++] = 0.5;
    209                                                 texcoords[i][index++] = clamp((data[i][j] - datamin) / datadelta, 0.0, 1.0);
    210                                         }
    211                                 }
    212                                
    213                                 //linearize the elements array:
    214                                 var element;
    215                                 for(var i = 0, iindex = 0; i < elements.length; i++){
    216                                         element = [elements[i][0] - 1, elements[i][1] - 1, elements[i][2] - 1];
    217                                         if (element[0] in nanindices || element[1] in nanindices || element[2] in nanindices) continue;
    218                                         indices[iindex++] = element[0];
    219                                         indices[iindex++] = element[1];
    220                                         indices[iindex++] = element[2];
    221                                 }
    222                        
    223                                 //Initialize movie loop
    224                                 node.movieLoop = canvas.animation.loop;
    225                                 node.movieInterval = 1000 / canvas.animation.fps;
    226                                 node.movieTimestamps = timestamps;
    227                                 node.movieLength = timestamps.length;
    228                                 node.movieFrame = 0;
    229                                 canvas.dataMarkers.values = [];
    230                                 var quiverVelFrames = {};
    231                                 for(var i=0; i < md.results.length; i++){
    232                                         quiverVelFrames[Math.floor(md.results[i].time)] = md.results[i];
    233                                 }
    234 
    235                                 if (canvas.animation.handler !== 0) {
    236                                         console.log("clearing...");
    237                                         clearInterval(canvas.animation.handler)
    238                                 }
    239                                 //TODO: Move this into webgl.js
    240                                 canvas.animation.handler = setInterval(function () {
    241                                         node.movieFrame = canvas.animation.frame;
    242                                         if (canvas.animation.play && canvas.animation.increment) {
    243                                                 if (node.movieFrame == node.movieLength - 1) {
    244                                                         if (node.movieLoop) {
    245                                                                 node.movieFrame = 0;
    246                                                         }
    247                                                         else {
    248                                                                 toggleMoviePlay(canvas);
    249                                                         }
    250                                                 }
    251                                                 else {
    252                                                         node.movieFrame = node.movieFrame + 1;
    253                                                 }
    254                                                 if (canvas.animation.lastFrame != canvas.animation.frame) {
    255                                                         updateMarker(canvas, false);
    256                                                 }
    257                                         }
    258                                        
    259                                         if (canvas.progressBar) {
    260                                                 canvas.progressBar.val(node.movieFrame);
    261                                                 canvas.progressBar.slider('refresh');
    262                                         }
    263                                         if (canvas.timeLabel) { canvas.timeLabel.html(node.movieTimestamps[node.movieFrame].toFixed(0) + " " + options.getfieldvalue("movietimeunit","yr")); }
    264                                        
    265                                         var buffer = node.mesh.getBuffer("coords");
    266                                         buffer.data = texcoords[node.movieFrame];
    267                                         buffer.upload(canvas.gl.DYNAMIC_DRAW);
    268                                         node.mesh.octree = new GL.Octree(node.mesh);
    269                                         node.texcoords = texcoords;
    270                                         if(options.getfieldvalue('quiver') == 'on'){
    271                                                 plot_quiver(md, options, canvas, {vel: quiverVelFrames[node.movieFrame].Vel, vx: quiverVelFrames[node.movieFrame].Vx, vy: quiverVelFrames[node.movieFrame].Vy});
    272                                         }
    273                                         canvas.animation.lastFrame = canvas.animation.frame;
    274                                         canvas.animation.frame = node.movieFrame;                                       
    275                                 }, node.movieInterval);
    276                                
    277                                 if (canvas.progressBar) {
    278                                         canvas.animation.frame = 0;
    279                                         canvas.progressBar.val(0);
    280                                         canvas.progressBar.attr('max', node.movieLength-1);
    281                                         canvas.progressBar.slider('refresh');
    282                                 }
    283                                
    284                         }
    285                         node.mesh = GL.Mesh.load({vertices: vertices, coords: texcoords[0], triangles: indices}, null, null, gl);
    286                         node.mesh.octree = new GL.Octree(node.mesh);
    287                         break;
    288                 //}}}
    289107                default:
    290                         throw Error(sprintf("%s%i%s\n",'case ', datatype,' not supported'));
     108                        throw Error(sprintf('%s%i%s\n','case ', datatype,' not supported'));
    291109        }
    292110} //}}}
  • ../trunk-jpl/src/m/plot/plot_overlay.js

     
    66        //
    77        //   See also: PLOTMODEL, PLOT_MANAGER
    88
     9        if ('overlay' in  canvas.nodes && options.getfieldvalue('cachenodes','on') === 'on') return;
     10       
    911        //{{{ declare variables:
    10         var vertices = [];
    11         var indices = [];
    12         var texcoords = [];
    13         var nanindices = {};
    14         var xmin, xmax;
    15         var ymin, ymax;
    16         var zmin, zmax;
    17         var matrixscale, vertexscale;
    18 
    1912        //Process data and model
    20         var meshresults = processmesh(md, data, options);
     13        var meshresults = processmesh(md, [], options);
    2114        var x = meshresults[0];
    2215        var y = meshresults[1];
    2316        var z = meshresults[2];
     
    2417        var elements = meshresults[3];
    2518        var is2d = meshresults[4];
    2619        var isplanet = meshresults[5];
    27 
    28         //Compue scaling through matrices for 2d meshes and vertices for 3d meshes
    29         if (!md.geometry.surface) {
    30                 md.geometry.surface=NewArrayFill(md.mesh.x.length, 0);
     20        if (md.mesh.classname() !== 'mesh3dsurface') z = md.geometry.surface;
     21       
     22        //Compute coordinates and data range:
     23        var xlim = options.getfieldvalue('xlim', [ArrayMin(x), ArrayMax(x)]);
     24        var ylim = options.getfieldvalue('ylim', [ArrayMin(y), ArrayMax(y)]);
     25        var zlim = options.getfieldvalue('zlim', [ArrayMin(md.geometry.surface), ArrayMax(md.geometry.surface)]);
     26       
     27        //Handle radaroverlay
     28        if (md.radaroverlay.outerx) {
     29                var result = Node.prototype.mergeVertices(x, y, z, elements, md.radaroverlay.outerx, md.radaroverlay.outery, md.radaroverlay.outerheight, md.radaroverlay.outerindex);
     30                x = result.x;
     31                y = result.y;
     32                z = result.z;
     33                elements = result.elements;
    3134        }
    32         if (md.mesh.classname() == 'mesh3dsurface') {
    33                 matrixscale = 1;
    34                 vertexscale = options.getfieldvalue('heightscale', 1);
     35       
     36        //Handle heightscale
     37        var vertices, scale;
     38        if (md.mesh.classname() !== 'mesh3dsurface') {
     39                vertices = [x, y, z];
     40                scale = [1, 1, options.getfieldvalue('heightscale', 1)];
    3541        }
    3642        else {
    37                 if (md.geometry.surface) {
    38                         z=md.geometry.surface;
    39                 }       
    40                 matrixscale = options.getfieldvalue('heightscale', 1);
    41                 vertexscale = 0;
     43                vertices = Node.prototype.scaleVertices(md, x, y, z, options.getfieldvalue('heightscale', 1));
     44                scale = [1, 1, 1];
    4245        }
    43         //}}}
    4446       
    45         //Compute coordinates and data range:
    46         var modelxlim = [ArrayMin(x), ArrayMax(x)];
    47         var modelylim = [ArrayMin(y), ArrayMax(y)];
    48         var modelzlim = [ArrayMin(z), ArrayMax(z)];
    49         var xlim = options.getfieldvalue('xlim', modelxlim);
    50         var ylim = options.getfieldvalue('ylim', modelylim);
    51         var zlim = options.getfieldvalue('zlim', modelzlim);
    52         xmin = xlim[0];
    53         xmax = xlim[1];
    54         ymin = ylim[0];
    55         ymax = ylim[1];
    56         zmin = zlim[0];
    57         zmax = zlim[1];
    58                
    5947        //Compute gl variables:
    60         var gl = canvas.gl;
    61         var node = Node(gl);
    62         canvas.nodes[canvas.nodes.length] = node;
    63         node.name = "overlay";
    64         node.shaderName = (options.getfieldvalue('render',[]).indexOf('ground')!=-1) ? "GroundFromSpace" : "Textured";
    65         node.shader = gl.shaders[node.shaderName];
    66         node.scale = [1, 1, matrixscale];
    67         node.rotation = [-90, 0, 0];
    68         node.translation = [0, 0, 0];
    69         node.center = [(xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2];
    70         node.texture = initTexture(gl, options.getfieldvalue('overlay_image'));
    71         node.alpha = options.getfieldvalue('outeralpha', 1.0);
    72         node.drawOrder = 1;
    73         node.maskEnabled = options.getfieldvalue('outermask','off') == 'on';
    74         node.maskHeight = options.getfieldvalue('outermaskheight', 150.0);
    75         node.maskColor = options.getfieldvalue('outermaskcolor',[0.0, 0.0, 1.0, 1.0]);
    76         updateModelMatrix(node);
     48        var edgecolor = options.getfieldvalue('edgecolor', 'black');
     49        var texture = initTexture(gl, options.getfieldvalue('overlay_image'));
     50        var node = new Node(
     51                'canvas', canvas,
     52                'options', options,
     53                'name', 'overlay',
     54                'shaderName', 'ground' in options.getfieldvalue('render', {}) ? 'GroundFromSpace' : 'Textured',
     55                'alpha', options.getfieldvalue('outeralpha', 1.0),
     56                //'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, md.mesh.classname() === 'mesh3dsurface' ? (zlim[0] + zlim[1]) / 2 : zlim[0]],
     57                'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2],
     58                'diffuseColor', 'white',
     59                'maskEnabled', options.getfieldvalue('outermask','off') == 'on',
     60                'maskHeight', options.getfieldvalue('outermaskheight', 150.0),
     61                'maskColor', options.getfieldvalue('outermaskcolor',[0.0, 0.0, 1.0, 1.0]),
     62                'texture', texture,
     63                'rotation', [-90, 0, 0],
     64                'scale', scale
     65        );
     66        //}}}
    7767       
    78         //Handle outer radaroverlay
    79         if (md.radaroverlay.outerx) {
    80                 var newelements = [];
    81                 for (var i = 0; i < md.radaroverlay.outerindex.length; i++) {
    82                         newelements[newelements.length] = [md.radaroverlay.outerindex[i][0] + x.length, md.radaroverlay.outerindex[i][1] + y.length, md.radaroverlay.outerindex[i][2] + z.length];
    83                 }
    84                 x = [].concat(x, md.radaroverlay.outerx);
    85                 y = [].concat(y, md.radaroverlay.outery);
    86                 z = [].concat(z, md.radaroverlay.outerheight);
    87                 elements = [].concat(elements, newelements);
    88                
    89                 //Reclaculate bounds based on otuer radaroverlay
    90                 modelxlim = [ArrayMin(x), ArrayMax(x)];
    91                 modelylim = [ArrayMin(y), ArrayMax(y)];
    92                 modelzlim = [ArrayMin(z), ArrayMax(z)];
    93                 xmin = xlim[0];
    94                 xmax = xlim[1];
    95                 ymin = ylim[0];
    96                 ymax = ylim[1];
    97                 zmin = zlim[0];
    98                 zmax = zlim[1];
    99                
    100                 node.center = [node.center[0], node.center[1], -zmax];
    101         }
     68        var xRange = xlim[1] - xlim[0];
     69        var yRange = ylim[1] - ylim[0];
     70        var coordArray = [new Array(x.length), new Array(x.length)];
     71        //generate mesh:
    10272       
    103         var xrange = modelxlim[1] - modelxlim[0];
    104         var yrange = modelylim[1] - modelylim[0];
    105        
    106         var xyz = vec3.create();
    107         var direction = vec3.create();
    108         var vertex = vec3.create();
    109         var magnitude;
    110 
    111         //generate mesh:
    112         for(var i = 0; i < x.length; i++){
    113                 //Check for NaN values and remove from indices array as necessary, but preserve vertex array spacing
    114                 if (isNaN(x[i]) || isNaN(y[i]) || isNaN(z[i])) {
    115                         nanindices[i] = i;
    116                         vertices[vertices.length] = vertex[0];
    117                         vertices[vertices.length] = vertex[1];
    118                         vertices[vertices.length] = vertex[2];
    119                        
    120                         texcoords[texcoords.length] = 0.0;
    121                         texcoords[texcoords.length] = 0.0;
    122                         continue;
    123                 }
    124 
    125                 if (md.mesh.classname() == 'mesh3dsurface') {
    126                         //Scale vertices
    127                         xyz = vec3.fromValues(x[i], y[i], z[i]);
    128                         magnitude = vec3.length(xyz) + md.geometry.surface[i] * vertexscale;
    129                         vec3.normalize(direction, xyz);
    130                         vec3.scale(vertex, direction, magnitude);
    131                         vertices[vertices.length] = vertex[0];
    132                         vertices[vertices.length] = vertex[1];
    133                         vertices[vertices.length] = vertex[2];
    134                        
    135                         texcoords[texcoords.length] = Math.atan2(vertex[1], vertex[0]) / (2 * Math.PI) + 0.5;
    136                         texcoords[texcoords.length] = Math.asin(vertex[2] / magnitude) / Math.PI + 0.5;
    137                 }
    138                 else {
    139                         //Scale vertices
    140                         xyz = vec3.fromValues(x[i], y[i], z[i]);
     73        if (md.mesh.classname() == 'mesh3dsurface') {
     74                var xyz, magnitude;
     75                for(var i = 0; i < x.length; i++){
     76                        xyz = vec3.fromValues(vertices[0][i], vertices[1][i], vertices[2][i]);
    14177                        magnitude = vec3.length(xyz);
    142                         vec3.normalize(direction, xyz);
    143                         vec3.scale(vertex, direction, magnitude);
    144                         vertices[vertices.length] = vertex[0];
    145                         vertices[vertices.length] = vertex[1];
    146                         vertices[vertices.length] = vertex[2];
    147                        
    148                         texcoords[texcoords.length] = (x[i] - modelxlim[0]) / xrange;
    149                         texcoords[texcoords.length] = (y[i] - modelylim[0]) / yrange;
     78               
     79                        coordArray[0][i] = Math.atan2(xyz[1], xyz[0]) / (2 * Math.PI) + 0.5;
     80                        coordArray[1][i] = Math.asin(xyz[2] / magnitude) / Math.PI + 0.5;
    15081                }
    15182        }
    152         //linearize the elements array:
    153         var element;
    154         for(var i = 0; i < elements.length; i++){
    155                 element = [elements[i][0] - 1, elements[i][1] - 1, elements[i][2] - 1];
    156                 if (element[0] in nanindices || element[1] in nanindices || element[2] in nanindices) continue;
    157                 indices[indices.length] = element[0];
    158                 indices[indices.length] = element[1];
    159                 indices[indices.length] = element[2];
     83        else {
     84                for(var i = 0; i < x.length; i++){
     85                        coordArray[0][i] = (vertices[0][i] - xlim[0]) / xRange;
     86                        coordArray[1][i] = (vertices[1][i] - ylim[0]) / yRange;
     87                }
    16088        }
    161         node.mesh = GL.Mesh.load({vertices: vertices, coords: texcoords, triangles: indices}, null, null, gl);
     89        node.patch('Faces', elements, 'Vertices', vertices, 'FaceVertexCData', coordArray, 'FaceColor', 'interp', 'EdgeColor', edgecolor);
    16290} //}}}
  • ../trunk-jpl/src/m/plot/plot_transient_movie.js

     
     1function plot_transient_movie(md, options, canvas) { //{{{
     2        //PLOT_TRANSIENT_MOVIE - plot a transient result as a movie
     3        //
     4        //   Usage:
     5        //      plot_transient_movie(md, options, canvas);
     6        //
     7        //   See also: PLOTMODEL, PLOT_MANAGER
     8       
     9        //loop over the time steps
     10        var data = options.getfieldvalue('transient_field_data');
     11        var datatype;
     12        var steps = new Array(data.length);
     13        for (i = 0; i < steps.length; i++) {
     14                steps[i] = i;
     15        }
     16       
     17        //calculate caxis
     18        if (!options.exist('caxis')) {
     19                var range = [Infinity, -Infinity];
     20                var     dataresults;
     21                for (var i in steps) {
     22                        dataresults = processdata(md, data[i], options);
     23                        range[1] = Math.min(range[0], ArrayMin(dataresults[0]));
     24                        range[2] = Math.max(range[1], ArrayMax(dataresults[0]));
     25                }
     26                datatype = dataresults[1];
     27                options.addfielddefault('caxis', range);
     28               
     29        }
     30       
     31        //Create unit node if it does not already exist
     32        if (!('unit' in canvas.nodes)) {
     33                var     dataresults = processdata(md, data[i],options);
     34                var     data2 = dataresults[0];
     35                var     datatype = dataresults[1];
     36       
     37                //plot unit
     38                plot_unit(md,data2,datatype,options,canvas);
     39        }
     40       
     41        //display movie
     42        var node = canvas.nodes.unit;
     43        node.options = options;
     44        node.alpha = options.getfieldvalue('alpha', 1.0);
     45        node.caxis = options.getfieldvalue('caxis');
     46        node.enabled = options.getfieldvalue('nodata', 'off') == 'off';
     47        node.log = options.getfieldvalue('log', false);
     48        canvas.unitMovieData = data;
     49        canvas.animation.frame = 0;
     50        canvas.animation.handler = setInterval(function () {
     51                //Update current animation frame
     52                var frame = canvas.animation.frame;
     53                if (canvas.animation.play) {
     54                        if (canvas.animation.increment) {
     55                                if (frame > steps.length - 1) {
     56                                        if (node.movieLoop) {
     57                                                frame = 0;
     58                                        }
     59                                        else {
     60                                                toggleMoviePlay(canvas);
     61                                        }
     62                                }
     63                                else {
     64                                        frame = (frame + 1) % steps.length;
     65                                }
     66                        }
     67                }
     68               
     69                //If frame has changed, update unit node and data marker display.
     70                if (frame !== canvas.animation.lastFrame) {
     71                        node.updateBuffer('Coords', data[frame]);
     72                        canvas.unitData = data[frame];
     73                        if (canvas.dataMarkers.enabled) {
     74                                updateMarker(canvas, false);
     75                        }
     76                        if (canvas.progressBar) {
     77                                canvas.progressBar.val(frame).slider('refresh');
     78                        }
     79                        if (canvas.timeLabel) {
     80                                canvas.timeLabel.html(steps[frame].toFixed(0) + " " + options.getfieldvalue("movietimeunit","yr"));
     81                        }
     82                        if (!isEmptyOrUndefined(canvas.nodes.quiver)) {
     83                                plot_quiver(md,options,canvas,false);
     84                        }
     85                }
     86               
     87                //Save new frame info.
     88                canvas.animation.lastFrame = canvas.animation.frame;
     89                canvas.animation.frame = frame;
     90        }, canvas.animation.interval);
     91       
     92        //Update progress bar with new frame info.
     93        if (canvas.progressBar) {
     94                canvas.progressBar.val(canvas.animation.frame);
     95                canvas.progressBar.attr('max', steps.length - 1);
     96                canvas.progressBar.slider('refresh');
     97        }
     98                               
     99        applyoptions(md, [], options, canvas);
     100} //}}}
  • ../trunk-jpl/src/m/plot/plotdoc.js

     
    44        //   Usage:
    55        //      plotdoc()
    66       
    7         //TODO: Standardize image to overlay_image, heightscale to scaling, colorbarfontsize/color, clarify innermask/outermask, edgecolor implementation, check colormap,
     7        //TODO: rename innermask/outermask/maskzero and combine
    88
    9         console.log(' WARNING: starred methods (*) are experimental and not guarenteed to be stable');
    109        console.log('   Plot usage: plotmodel(model,varargin)');
    1110        console.log('   Options: ');
    1211        console.log('       "canvasid": canvas id');
    1312        console.log('       "data" : what we want to plot');
    14         console.log('                Available values for "data" are: ');
    15         console.log('                  - any field of the model structure. ex: plot(md,"data","vel"), or plot(md,"data",md.initialization.vel)');
    16         console.log('                  - "mesh": draw mesh using trisurf');
    17         console.log('                  - "quiver": quiver plot');
    18         console.log('       "2d": renders orthographic camera with view set to [0, 90] (default "off", ex: "on", "off")');
     13        console.log('           Available values for "data" are: ');
     14        console.log('                   - any field of the model structure. ex: plot(md,"data","vel"), or plot(md,"data",md.initialization.vel)');
     15        console.log('                   - "mesh": draw mesh using trisurf');
     16        console.log('                   - "quiver": quiver plot');
    1917        console.log('       "backgroundcolor": plot background color. (default "lightcyan", ex: "green","blue")');
    2018        console.log('       "brush": specify brush options (default {"strength":0.075,"falloff":0.5})');
     19        console.log('           "enabled": toggle brush (default false, ex: true)');
     20        console.log('           "strength": value that brush will change data points by (ex: 0.075)');
     21        console.log('           "falloff": multiplier that brush will decrease strength by for each successive point away from brush center (ex: 0.5)');
     22        console.log('       "clouds": specify brush options (default {"strength":0.075,"falloff":0.5})');
     23        console.log('           "enabled": toggle clouds (default false, ex: true)');
     24        console.log('           "height": height to spawn clouds at (ex: 7500)');
     25        console.log('           "quantity": quantity of clouds to spawn (ex: 10)');
    2126        console.log('       "caxis": modify  colorbar range. (array of type [a, b] where b>=a)');
    2227        console.log('       "colorbar": add colorbar (default "off", ex: "on", "off")');
    2328        console.log('       "colorbarid": colorbar canvas id (string)');
     
    3136        console.log('       "colorbarheight": multiplier (default 1) to the default height colorbar');
    3237        console.log('       "colormap": same as standard matlab option (default "jet", ex: "hsv","cool","spring","gray","Ala","Rignot",...)');
    3338        console.log('       "controlsensitivity": sensitivty of view/zoom changes as a percentage of default (default 1, ex: 0.5, 2.75)');
    34         console.log('       "datamarkers": toggle data marker displays (default "on", ex: "on", "off")');
    35         console.log('       "datamarkers_image": toggle data marker displays (default "on", ex: "on", "off")');
    36         console.log('       "datamarkerssize": specifiy the width and height of the data markers (default [32,32], ex: [24,32], [105,10])');
    37         console.log('       "datamarkersoptions": specifiy options for data markers (default {"enabled":"on","image":canvas.rootPath+"textures/data_marker.svg","size":[32,32],"format":["X: %.2e<br>Y: %.2e<br>Z: %.2e]<br>Value: %0.1f","x","y","z","value"]}');
     39        console.log('       "datamarkers": object cotaining data marker parameters. See webgl.js for defaults. (ex: {"enabled":true,"format":["<div id="sim-plot"></div>"],"labels":["thickness","velocity","value"],"animated":true})');
     40        console.log('           "enabled": toggle data marker displays (default true, ex: false)');
     41        console.log('           "image": image used for marking the clicked point (ex: "/textures/data_marker.svg")');
     42        console.log('           "labels": when displaying a sim-plot graph, display these model fields. (ex: ["thickness","velocity","value"])');
     43        console.log('           "font": font to be used for display (ex: "24px "Comic Sans MS", cursive")');
     44        console.log('           "format": an array compatible with sprintf that will be displayed as html (ex: ["X: %.2e<br>Y: %.2e<br>Z: %.2e]<br>Value: %0.1f","x","y","z","value"])');
     45        console.log('                   "size": specifiy the width and height of the data markers (default [32,32], ex: [24,32], [105,10])');
    3846        console.log('       "displayview": print view value to console (default "off", ex: "on", "off")');
    3947        console.log('       "displayzoom": print zoom value to console (default "off", ex: "on", "off")');
    4048        console.log('       "edgecolor": same as standard matlab option EdgeColor (default "black", ex: color name: "blue" or RGB array: [0.5, 0.2, 0.8])');
    4149        console.log('       "heightscale": scaling factor to accentuate height. (default 1, ex: 0.5, 100)');
    42         console.log('       "linewidth*": line width for mesh, quiver, and contour plots, currently limited by WebGL to 1. (default 1, ex: 2, 5)');
     50        console.log('       "linewidth": line width for mesh, quiver, and contour plots, currently limited by WebGL to 1. (default 1, ex: 2, 5)');
    4351        console.log('       "log": value of log (default 10, ex: 2, Math.E)');
    4452        console.log('       "mask": list of flags of size numberofnodes or numberofelements. Only "true" values are plotted ');
    45         console.log('       "movieoptions": specify movie options (default {"fps":4,"loop":true})');
     53        console.log('       "movies": object cotaining transient plot animation options (ex: {"fps":4,"loop":true})');
     54        console.log('       "maskzeros": object cotaining transient plot animation options (ex: "enabled":true,"color":[1.0, 1.0, 1.0, 1.0],"tolerance":1e-3,"zeroValue":0.5})');
     55        console.log('           "enabled": toggle maskzeros (default false, ex: true)');
     56        console.log('           "color": RGBA color value array with ranges 0.0 to 1.0 (ex: [1.0, 1.0, 1.0, 1.0])');
     57        console.log('           "tolerance": values within this tolerance of the zeroValue will be masked. (default: 1e-3, ex: 2.5e-2)');
     58        console.log('           "zeroValue": the percentage value with range 0.0, to 1.0 of the caxis value around which the data will be masked with the color. (default: 0.5, ex: 0, 1.0, 0.75)');
    4659        console.log('       "innermask*": Special mask that colors all parts of a data mesh below a height a certain color. provide innermaskheight and innermaskcolor options also (default "off", ex: "on", "off")');
    4760        console.log('       "outermask*": Special mask that colors all parts of a overlay mesh below a height a certain color. provide outermaskheight and outermaskcolor options also (default "off", ex: "on", "off")');
    4861        console.log('       "overlay": overlay a radar amplitude image behind (default "off", ex: "on", "off")');
     
    5063        console.log('       "quiver": add quiver plot overlay for velocities. (default "off", ex: "on", "off")');
    5164        console.log('       "scaling": scaling factor used by quiver plots. Default is 0.4');
    5265        console.log('       "alpha": transparency coefficient 0.0 to 1.0, the lower, the more transparent. (default 1.0, ex: 0.5, 0.25)');
    53         console.log('       "azlim": azimuth view limits (ex: [0, 180])');
    54         console.log('       "ellim": elevation view limits (ex: [-90, 90])');
    55         console.log('       "origin": initial camera offset from model center (default [0,0,0.0], ex: [-2, 1.5, 0.01])');
    56         console.log('       "render": toggle sky, ground, and space rendering. (default [], ex: ["sky", "space"], ["ground"])');
    57         console.log('       "viewPanning": enable view origin panning with two-finger touch or shift+mouse drag. (default "off", ex: "on", "off")');
    58         console.log('       "view": initial azimuth and elevation angles for camera (default [0,90], ex: [90, 180]');
     66        console.log('       "render": a object containing a list of default object to render. (default {}, ex: {"sky", "space"})');
     67        console.log('           "sky": render the atmosphere. (ex: {"enabled":true})');
     68        console.log('                   "enabled": toggle sky (default false, ex: true)');
     69        console.log('           "space": render space. (ex: {"enabled":true})');
     70        console.log('                   "enabled": toggle space (default false, ex: true)');
     71        console.log('           "coastlines": render coastlines. (ex: {"enabled":true})');
     72        console.log('                   "enabled": toggle coastlines (default false, ex: true)');
     73        console.log('                   "scale": scale coastlines factor (default 1.0, ex: 1.004)');
     74        console.log('                   "x": x coordinate array. (ex: [0.0, 10.0, -25.0,...])');
     75        console.log('                   "y": y coordinate array. (ex: [0.0, 10.0, -25.0,...])');
     76        console.log('                   "z": z coordinate array. (ex: [0.0, 10.0, -25.0,...])');
     77        console.log('           "city": render city. (ex: {"enabled":true})');
     78        console.log('                   "enabled": toggle city (default false, ex: true)');
     79        console.log('                   "size": radius of city sphere, in meters (default 1.0, ex: 150000)');
     80        console.log('                   "color": color of city sphere (ex: "magenta")');
     81        console.log('                   "x": x coordinate of city. (ex: 0.0)');
     82        console.log('                   "y": y coordinate of city. (ex: 0.0)');
     83        console.log('                   "z": z coordinate of city. (ex: 6356700.0)');
     84        console.log('           "cities": render cities. (ex: {"enabled":true})');
     85        console.log('                   "enabled": toggle cities (default false, ex: true)');
     86        console.log('                   "size": radius of cities spheres, in meters (default 1.0, ex: 80000)');
     87        console.log('                   "color": color of cities spheres (ex: "darkviolet")');
     88        console.log('                   "x": x coordinate array of cities. (ex: [0.0, 10.0, -25.0,...])');
     89        console.log('                   "y": y coordinate array of cities. (ex: [0.0, 10.0, -25.0,...])');
     90        console.log('                   "z": z coordinate array of cities. (ex: [0.0, 10.0, -25.0,...])');
     91        console.log('           "graticule": render graticule. (ex: {"enabled":true})');
     92        console.log('                   "enabled": toggle graticule (default false, ex: true)');
     93        console.log('                   "scale": scale graticule factor (default 1.0, ex: 1.004)');
     94        console.log('                   "x": x coordinate array. (ex: [0.0, 10.0, -25.0,...])');
     95        console.log('                   "y": y coordinate array. (ex: [0.0, 10.0, -25.0,...])');
     96        console.log('                   "z": z coordinate array. (ex: [0.0, 10.0, -25.0,...])');
     97        console.log('       "view": object cotaining view parameters. See webgl.js for defaults. (ex: {"position":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0],"zoom":1.0,"zoomLimits":[0.01,100.0],"azimuthLimits":[-180,180.0],"elevationLimits":[-90,90.0],"panningEnabled":false,"twod":false})');
     98        console.log('           "position": camera position (ex: [0.0,0.0,0.0])');
     99        console.log('           "rotation": camera rotation (ex: [0.0,0.0,0.0])');
     100        console.log('           "zoom": initial camera zoom as a percentage of default (default 1, ex: 1.5, 0.01)');
     101        console.log('           "zoomLimits": zoom view limits (ex: [0.05, 10])');
     102        console.log('                   "azimuthLimits": zoom view limits (ex: [0.05, 10])');
     103        console.log('           "elevationLimits": zoom view limits (ex: [0.05, 10])');
     104        console.log('           "panningEnabled": controls panning with shift + drag mouse or pan gestures (default: false, ex: true)');
     105        console.log('           "twod": controls twod orthographic view (default: false, ex: true)');
    59106        console.log('       "xlim": x coordinates to fit inside camera (ex: [0, 500])');
    60107        console.log('       "ylim": y coordinates to fit inside camera (ex: [0, 500])');
    61108        console.log('       "zlim": z coordinates to fit inside camera (ex: [0, 500])');
    62         console.log('       "zoomlim": zoom view limits (ex: [0.05, 10])');
    63         console.log('       "zoom": initial camera zoom as a percentage of default (default 1, ex: 1.5, 0.01)');
    64         console.log('       "cloud*": plot a cloud of points, given a flat array of 3d coordinates (ex: [0.0, 0.0, 0.0, 1.0, 1.0, 1.0])');
    65         console.log('       "expdisp*": plot exp file on top of a data plot. provide exp file as an argument (use a cell of strings if more than one)');
    66         console.log('       "textlabels*": plot text labels rendered in 3d space, using an array of text/coordinate pairs (ex: [{"pos":[0.0,0.0,0.0],"text":"origin"}])');
     109        console.log('       "transient_field_data": array of data objects (ex: [[0.0,1.0, 2.5, 12.0...],[0.0,1.0, 2.5, 12.0...],...])');
     110        console.log('       "textlabels": plot text labels rendered in 3d space, using an array of text/coordinate pairs (ex: [{"pos":[0.0,0.0,0.0],"text":"origin"}])');
    67111       
    68112        console.log('  ');
    69113        console.log('   Examples:');
  • ../trunk-jpl/src/m/plot/processdata.js

     
    1414        //
    1515        //   See also: PLOTMODEL, PROCESSMESH
    1616
    17         //variables:
    18         var datatype;
    19        
    2017        //check format
    2118        if ( data.length ==0 | data === [] | typeof data === 'number' | ArrayAnyNaN(data) ){
    2219                throw Error('plotmodel error message: data provided is empty');
     
    3431        }
    3532
    3633        //needed later on
     34        var numberofvertices2d, numberofelements2d;
    3735        if ('numberofvertices2d' in md.mesh){
    3836                numberofvertices2d=md.mesh.numberofvertices2d;
    3937                numberofelements2d=md.mesh.numberofelements2d;
     
    4442        }
    4543
    4644        //initialize datatype
    47         datatype=0;
     45        var datatype=0;
    4846
    4947        //get datasize
    50         datasize=data.length;
     48        var datasize=data.length;
    5149
    5250        //transpose data if necessary
    5351        if (data[0].length > data.length){
     
    6361
    6462
    6563        //quiver?
    66         if (data[0].length>1){
     64        if (Array.isArray(data[0])){
    6765                datatype=3;
    6866
    6967                //check number of columns, add zeros if necessary,
     
    114112        }
    115113
    116114        //element data
    117         if (datasize==md.mesh.numberofelements & data[0].length==1){
     115        if (datasize==md.mesh.numberofelements & !Array.isArray(data[0])){
    118116
    119117                //Initialize datatype if non patch
    120118                if(datatype!=4 & datatype!=5){
     
    157155        }
    158156
    159157        //node data
    160         if (datasize==md.mesh.numberofvertices){
     158        if (datasize==md.mesh.numberofvertices & !Array.isArray(data[0])){
    161159                datatype=2;
    162160
    163161                //Mask?
  • ../trunk-jpl/src/m/plot/plot_quiver.js

     
    1 function plot_quiver(md, options, canvas, updateVel) { //{{{
     1function plot_quiver(md, options, canvas, noCacheNodesOverride) { //{{{
    22        //PLOT_QUIVER - quiver plot with colors
    33        //
    44        //   Usage:
     
    66        //
    77        //   See also: PLOTMODEL, PLOT_MANAGER
    88
     9        if ('quiver' in  canvas.nodes && noCacheNodesOverride && options.getfieldvalue('cachenodes','on') === 'on') return;
     10       
    911        //{{{ declare variables:
    10         var vertices = [];
    11         var indices = [];
    12         var colors = [];
    13         var xmin, xmax;
    14         var ymin, ymax;
    15         var zmin, zmax;
    16         var scale, matrixscale, vertexscale;
    17        
    1812        //Process data and model
    19         var meshresults = processmesh(md,[], options);
    20 
     13        var meshresults = processmesh(md, [], options);
    2114        var x = meshresults[0];
    2215        var y = meshresults[1];
    2316        var z = meshresults[2];
     
    2417        var elements = meshresults[3];
    2518        var is2d = meshresults[4];
    2619        var isplanet = meshresults[5];
    27         var v = updateVel != undefined ? updateVel.vel : md.initialization.vel;
    28         var vx = updateVel != undefined ? updateVel.vx : md.initialization.vx;
    29         var vy = updateVel != undefined ? updateVel.vy : md.initialization.vy;
     20        if (md.mesh.classname() !== 'mesh3dsurface') z = md.geometry.surface;
    3021               
    31         //Compue scaling through matrices for 2d meshes and vertices for 3d meshes
    32         if (!md.geometry.surface) {
    33                 md.geometry.surface=NewArrayFill(md.mesh.x.length, 0);
     22        //Compute coordinates and data range:
     23        var xlim = options.getfieldvalue('xlim', [ArrayMin(x), ArrayMax(x)]);
     24        var ylim = options.getfieldvalue('ylim', [ArrayMin(y), ArrayMax(y)]);
     25        var zlim = options.getfieldvalue('zlim', [ArrayMin(z), ArrayMax(z)]);
     26
     27        //Only displaying velocity fields for now
     28        var v = isEmptyOrUndefined(md.results) ?  md.initialization.vel : md.results[canvas.animation.frame].Vel;
     29        var vx = isEmptyOrUndefined(md.results) ? md.initialization.vx : md.results[canvas.animation.frame].Vx;
     30        var vy = isEmptyOrUndefined(md.results) ? md.initialization.vy : md.results[canvas.animation.frame].Vy;
     31
     32        //Handle heightscale
     33        var vertices, scale;
     34        if (md.mesh.classname() !== 'mesh3dsurface') {
     35                vertices = [x, y, z];
     36                scale = [1, 1, options.getfieldvalue('heightscale', 1)];
    3437        }
    35         if (md.mesh.classname() == 'mesh3dsurface') {
    36                 matrixscale = 1;
    37                 vertexscale = options.getfieldvalue('heightscale', 1);
    38         }
    3938        else {
    40                 if (md.geometry.surface) {
    41                         z=md.geometry.surface;
    42                 }       
    43                 matrixscale = options.getfieldvalue('heightscale', 1);
    44                 vertexscale = 0;
     39                vertices = Node.prototype.scaleVertices(md, x, y, z, options.getfieldvalue('heightscale', 1));
     40                scale = [1, 1, 1];
    4541        }
    46         //}}}
    47 
    48         //Compute coordinates and data range:
    49         var modelxlim = [ArrayMin(x), ArrayMax(x)];
    50         var modelylim = [ArrayMin(y), ArrayMax(y)];
    51         var modelzlim = [ArrayMin(z), ArrayMax(z)];
    52         var xlim = options.getfieldvalue('xlim', modelxlim);
    53         var ylim = options.getfieldvalue('ylim', modelylim);
    54         var zlim = options.getfieldvalue('zlim', modelzlim);
    55         xmin = xlim[0];
    56         xmax = xlim[1];
    57         ymin = ylim[0];
    58         ymax = ylim[1];
    59         zmin = zlim[0];
    60         zmax = zlim[1];
    61 
     42       
    6243        //Compute gl variables:
    63         var gl = canvas.gl;
    64         var node = Node(gl);
    65         canvas.nodes["velocity"] = node;
    66         node.name = "quiver";
    67         node.shaderName = "Colored";
    68         node.shader = gl.shaders[node.shaderName];
    69         node.lineWidth = options.getfieldvalue('linewidth', 1);
    70         node.scale = [1, 1, matrixscale];
    71         node.rotation = [-90, 0, 0];
    72         node.translation = [0, 0, 0];
    73         node.center = [(xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2];
    74         node.drawMode = gl.LINES;
    75         node.useIndexBuffer = false;
    76         node.drawOrder = 0;
    77         node.maskEnabled = options.getfieldvalue('innermask','off') == 'on';
    78         node.maskHeight = options.getfieldvalue('innermaskheight', 150.0)*options.getfieldvalue('heightscale', 1);
    79         node.maskColor = options.getfieldvalue('innermaskcolor',[0.0, 0.0, 1.0, 1.0]);
    80         updateModelMatrix(node);
    81 
    82         //retrieve some options
    83         var edgecolor=new RGBColor(options.getfieldvalue('edgecolor','black'));
    84         if (edgecolor.ok) edgecolor = [edgecolor.r/255.0, edgecolor.g/255.0, edgecolor.b/255.0, 1.0];
    85         else throw Error(sprintf("s%s%s\n","initWebGL error message: cound not find out edgecolor color for curent canvas ", canvas));
    86 
     44        var edgecolor = options.getfieldvalue('edgecolor', 'black');
     45        var node = new Node(
     46                'canvas', canvas,
     47                'options', options,
     48                'name', 'quiver',
     49                'shaderName', 'Colored',
     50                'alpha', options.getfieldvalue('alpha', 1.0),
     51                //'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, md.mesh.classname() === 'mesh3dsurface' ? (zlim[0] + zlim[1]) / 2 : zlim[0]],
     52                'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2],
     53                'drawMode', canvas.gl.LINES,
     54                'diffuseColor', edgecolor,
     55                'lineWidth', options.getfieldvalue('linewidth', 1),
     56                'maskEnabled', options.getfieldvalue('innermask','off') == 'on',
     57                'maskHeight', options.getfieldvalue('innermaskheight', 150.0) / options.getfieldvalue('heightscale', 1),
     58                'maskColor', options.getfieldvalue('innermaskcolor',[0.0, 0.0, 1.0, 1.0]),
     59                'rotation', [-90, 0, 0],
     60                'scale', scale
     61        );
     62       
     63       
    8764        //{{{ node plot
    8865        if (elements[0].length==6){ //prisms
    8966        }
     
    9067        else if (elements[0].length==4){ //tetras
    9168        }
    9269        else{ //2D triangular elements
     70                //Create arow vertices, and use vx/vy to determine rotation before adding to quiver mesh.
     71                var verticesArrow = [vec3.fromValues(0.0, 0.0, 0.0), vec3.fromValues(1.0, 0.0, 0.0), vec3.fromValues(0.667, -0.167, 0.0), vec3.fromValues(1.0, 0.0, 0.0), vec3.fromValues(0.667, 0.166, 0.0), vec3.fromValues(1.0, 0.0, 0.0)];
     72               
     73                var newX = [];
     74                var newY = [];
     75                var newZ = [];
    9376                var xyz = vec3.create();
    94                 var xyz = vec3.create();
    95                 var direction = vec3.create();
    9677                var vertex = vec3.create();
    97                 var vertexBase = vec3.create();
    98                 var verticesArrow = [vec3.fromValues(0.0, 0.0, 0.0), vec3.fromValues(1.0, 0.0, 0.0), vec3.fromValues(0.667, -0.167, 0.0), vec3.fromValues(1.0, 0.0, 0.0), vec3.fromValues(0.667, 0.166, 0.0), vec3.fromValues(1.0, 0.0, 0.0)];
    99                 var magnitude;
    100                 var color = edgecolor;
    10178                var scaling = options.getfieldvalue('scaling', 1);
    102                 var scale;
    103                 for(var i = 0; i < x.length; i++){
    104                         //Check for NaN values and remove from indices array as necessary, but preserve vertex array spacing
    105                         if (isNaN(x[i]) || isNaN(y[i]) || isNaN(z[i])) continue;
    106                         //Scale vertices
     79                var heightScale = options.getfieldvalue('heightscale', 1);
     80                var arrowScale;
     81                var modelMatrix = mat4.create();
     82                var scaleMatrix = mat4.create();
     83                var rotationMatrix = mat4.create();
     84               
     85                for(var i = 0, iX = 0, iY = 0, iZ = 0; i < x.length; i++){
    10786                        xyz = vec3.fromValues(x[i], y[i], z[i]);
    108                         magnitude = vec3.length(xyz) + md.geometry.surface[i] * vertexscale;
    109                         vec3.normalize(direction, xyz);
    110                         vec3.scale(vertex, direction, magnitude);
    111                         vec3.copy(vertexBase, vertex);
    112                        
    113                         scale = scaling*v[i];
    114                         var modelMatrix = mat4.create();
    115                         var scaleMatrix = mat4.create();
    116                         var rotationMatrix = mat4.create();
    117                         mat4.scale(scaleMatrix, scaleMatrix, vec3.fromValues(scale, scale, scale));
    118                         mat4.rotate(rotationMatrix, rotationMatrix, Math.atan2(vy[i], vx[i]), [0.0, 0.0, 1.0]);
     87                        arrowScale = v[i] * scaling;
     88                        scaleMatrix = mat4.create();
     89                        mat4.scale(scaleMatrix, mat4.create(), vec3.fromValues(arrowScale, arrowScale, arrowScale));
     90                        mat4.rotate(rotationMatrix, mat4.create(), Math.atan2(vy[i], vx[i]), [0.0, 0.0, 1.0]);
    11991                        mat4.multiply(modelMatrix, rotationMatrix, scaleMatrix);
    120 
    121                         var temp = vec3.fromValues(0.0, 0.0, 0.0);
    12292                        for (var j = 0; j < 6; j++){
    12393                                vec3.transformMat4(vertex, verticesArrow[j], modelMatrix);
    124                                 vec3.add(vertex, vertex, vertexBase);
    125                                 vertices[vertices.length] = vertex[0];
    126                                 vertices[vertices.length] = vertex[1];
    127                                 vertices[vertices.length] = vertex[2];
    128                                
    129                                 colors[colors.length] = color[0];
    130                                 colors[colors.length] = color[1];
    131                                 colors[colors.length] = color[2];
    132                                 colors[colors.length] = color[3];
     94                                vec3.add(vertex, vertex, xyz);
     95                                newX[iX++] = vertex[0];
     96                                newY[iY++] = vertex[1];
     97                                newZ[iZ++] = vertex[2];
    13398                        }
    13499                }
     100                node.patch('Vertices', [newX, newY, newZ], 'FaceColor', 'none');
    135101        }
    136102        //}}}
    137         node.mesh = GL.Mesh.load({vertices: vertices, colors: colors}, null, null, gl);
    138103} //}}}
  • ../trunk-jpl/src/m/plot/plot_mesh.js

     
    66        //
    77        //   See also: PLOTMODEL, PLOT_MANAGER
    88
     9        if ('mesh' in  canvas.nodes && options.getfieldvalue('cachenodes','on') === 'on') return;
     10       
    911        //{{{ declare variables:
    10         var vertices = [];
    11         var indices = [];
    12         var colors = [];
    13         var nanindices = {};
    14         var xmin, xmax;
    15         var ymin, ymax;
    16         var zmin, zmax;
    17         var scale, matrixscale, vertexscale;
    18        
    1912        //Process data and model
    20         var meshresults = processmesh(md,[], options);
     13        var meshresults = processmesh(md, [], options);
    2114        var x = meshresults[0];
    2215        var y = meshresults[1];
    2316        var z = meshresults[2];
     
    2518        var is2d = meshresults[4];
    2619        var isplanet = meshresults[5];
    2720               
    28         //Compue scaling through matrices for 2d meshes and vertices for 3d meshes
    29         if (!md.geometry.surface) {
    30                 md.geometry.surface=NewArrayFill(md.mesh.x.length, 0);
     21        //Compute coordinates and data range:
     22        var xlim = options.getfieldvalue('xlim', [ArrayMin(x), ArrayMax(x)]);
     23        var ylim = options.getfieldvalue('ylim', [ArrayMin(y), ArrayMax(y)]);
     24        var zlim = options.getfieldvalue('zlim', [ArrayMin(z), ArrayMax(z)]);
     25       
     26        //Handle heightscale
     27        var vertices, scale;
     28        if (md.mesh.classname() !== 'mesh3dsurface') {
     29                vertices = [x, y, z];
     30                scale = [1, 1, options.getfieldvalue('heightscale', 1)];
    3131        }
    32         if (md.mesh.classname() == 'mesh3dsurface') {
    33                 matrixscale = 1;
    34                 vertexscale = options.getfieldvalue('heightscale', 1);
    35         }
    3632        else {
    37                 if (md.geometry.surface) {
    38                         z=md.geometry.surface;
    39                 }       
    40                 matrixscale = options.getfieldvalue('heightscale', 1);
    41                 vertexscale = 0;
     33                vertices = Node.prototype.scaleVertices(md, x, y, z, options.getfieldvalue('heightscale', 1));
     34                scale = [1, 1, 1];
    4235        }
     36       
     37        //Compute gl variables:
     38        var edgecolor = options.getfieldvalue('edgecolor', 'black');
     39        var node = new Node(
     40                'canvas', canvas,
     41                'options', options,
     42                'name', 'mesh',
     43                'shaderName', 'Colored',
     44                'alpha', options.getfieldvalue('alpha', 1.0),
     45                //'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, md.mesh.classname() === 'mesh3dsurface' ? (zlim[0] + zlim[1]) / 2 : zlim[0]],
     46                'center', [(xlim[0] + xlim[1]) / 2, (ylim[0] + ylim[1]) / 2, (zlim[0] + zlim[1]) / 2],
     47                'drawMode', canvas.gl.LINES,
     48                'diffuseColor', edgecolor,
     49                'lineWidth', options.getfieldvalue('linewidth', 1),
     50                'maskEnabled', options.getfieldvalue('innermask','off') == 'on',
     51                'maskHeight', options.getfieldvalue('innermaskheight', 150.0) / options.getfieldvalue('heightscale', 1),
     52                'maskColor', options.getfieldvalue('innermaskcolor',[0.0, 0.0, 1.0, 1.0]),
     53                'rotation', [-90, 0, 0],
     54                'scale', scale
     55        );
    4356        //}}}
    44 
    45         //Compute coordinates and data range:
    46         var modelxlim = [ArrayMin(x), ArrayMax(x)];
    47         var modelylim = [ArrayMin(y), ArrayMax(y)];
    48         var modelzlim = [ArrayMin(z), ArrayMax(z)];
    49         var xlim = options.getfieldvalue('xlim', modelxlim);
    50         var ylim = options.getfieldvalue('ylim', modelylim);
    51         var zlim = options.getfieldvalue('zlim', modelzlim);
    52         xmin = xlim[0];
    53         xmax = xlim[1];
    54         ymin = ylim[0];
    55         ymax = ylim[1];
    56         zmin = zlim[0];
    57         zmax = zlim[1];
    58 
    59         //Compute gl variables:
    60         var gl = canvas.gl;
    61         gl.makeCurrent();
    62         var node = Node(gl);
    63         canvas.nodes[canvas.nodes.length] = node;
    64         node.name = "mesh";
    65         node.shaderName = "Colored";
    66         node.shader = gl.shaders[node.shaderName];
    67         node.lineWidth = options.getfieldvalue('linewidth', 1);
    68         node.scale = [1, 1, matrixscale];
    69         node.rotation = [-90, 0, 0];
    70         node.translation = [0, 0, 0];
    71         node.center = [(xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2];
    72         node.drawMode = gl.LINES;
    73         node.drawOrder = 0;
    74         node.maskEnabled = options.getfieldvalue('innermask','off') == 'on';
    75         node.maskHeight = options.getfieldvalue('innermaskheight', 150.0)*options.getfieldvalue('heightscale', 1);
    76         node.maskColor = options.getfieldvalue('innermaskcolor',[0.0, 0.0, 1.0, 1.0]);
    77         updateModelMatrix(node);
    78 
    79         //retrieve some options
    80         var edgecolor = new RGBColor(options.getfieldvalue('edgecolor','black'));
    81         if (edgecolor.ok) edgecolor = [edgecolor.r/255.0, edgecolor.g/255.0, edgecolor.b/255.0, 1.0];
    82         else throw Error(sprintf("s%s%s\n","initWebGL error message: cound not find out edgecolor color for curent canvas ", canvas));
    83 
    8457        //{{{ node plot
    8558        if (elements[0].length==6){ //prisms
    8659        }
     
    8760        else if (elements[0].length==4){ //tetras
    8861        }
    8962        else{ //2D triangular elements
    90                 var xyz = vec3.create();
    91                 var direction = vec3.create();
    92                 var vertex = vec3.create();
    93                 var magnitude;
    94                 var color = edgecolor;
    95                 for(var i = 0; i < x.length; i++){
    96                         //Check for NaN values and remove from indices array as necessary, but preserve vertex array spacing
    97                         if (isNaN(x[i]) || isNaN(y[i]) || isNaN(z[i])) {
    98                                 nanindices[i] = i;
    99                                 vertices[vertices.length] = vertex[0];
    100                                 vertices[vertices.length] = vertex[1];
    101                                 vertices[vertices.length] = vertex[2];
    102                                
    103                                 colors[colors.length] = color[0];
    104                                 colors[colors.length] = color[1];
    105                                 colors[colors.length] = color[2];
    106                                 colors[colors.length] = color[3];
    107                                 continue;
    108                         }
    109                         //Scale vertices
    110                         xyz = vec3.fromValues(x[i], y[i], z[i]);
    111                         magnitude = vec3.length(xyz) + md.geometry.surface[i] * vertexscale;
    112                         vec3.normalize(direction, xyz);
    113                         vec3.scale(vertex, direction, magnitude);
    114                         vertices[vertices.length] = vertex[0];
    115                         vertices[vertices.length] = vertex[1];
    116                         vertices[vertices.length] = vertex[2];
    117 
    118                         colors[colors.length] = color[0];
    119                         colors[colors.length] = color[1];
    120                         colors[colors.length] = color[2];
    121                         colors[colors.length] = color[3];
    122                 }
    123                
    124                 //linearize the elements array:
    125                 var element;
    126                 for(var i = 0; i < elements.length; i++){
    127                         element = [elements[i][0] - 1, elements[i][1] - 1, elements[i][2] - 1];
    128                         if (element[0] in nanindices || element[1] in nanindices || element[2] in nanindices) continue;
    129                         indices[indices.length] = element[0];
    130                         indices[indices.length] = element[1];
    131                         indices[indices.length] = element[1];
    132                         indices[indices.length] = element[2];
    133                         indices[indices.length] = element[2];
    134                         indices[indices.length] = element[0];
    135                 }
     63                node.patch('Faces', elements, 'Vertices', vertices, 'FaceColor', 'none', 'EdgeColor', edgecolor);
    13664        }
    13765        //}}}
    138         node.mesh = GL.Mesh.load({vertices: vertices, colors: colors, triangles: indices}, null, null, gl);
     66        //options=options.addfielddefault('title','Mesh');
     67        //options=addfielddefault('colorbar','off');
     68        //applyoptions(md,[],options,canvas);
    13969} //}}}
  • ../trunk-jpl/src/m/classes/clusters/generic.js

     
    171171                }
    172172                return buf;
    173173        } //}}}
    174 }
     174} 
Note: See TracBrowser for help on using the repository browser.