Monday, January 20, 2014

Generic code for WebGL Earth data plotting


In a previous post, I said I would post code for WebGL data presentation, in the style of posts here, here, and here. I supply an HTML fragment which includes the JavaScript (JS) master code; you supply a file with a JS function prescribing data. Apart from opening and closing the function, the JS is just data assignment. You should see that previous post for references and basic explanation of JS, HTML5 and WebGL. I'll call the code Moygl.

With Moygl, you can draw on the Earth surface:
  • POINTS - dots of various size and color
  • LINES - a group of individual line segments
  • TRIANGLES - each individually specified. Normally these will be filled with shading
  • LINE_STRIP - a long list of vertices which will be connected in sequence (can be broken with NaN).
  • LINE_LOOP, TRIANGLE_STRIP and TRIANGLE_FAN
I've given the WebGL names (LINES etc). The last three are just ways of reducing repetition of vertices. I stick to POINTS, TRIANGLES and LINE_STRIP. The native style of WebGL input is as a flat array, so eg TRIANGLES would have for each triangle the first 3 coords, then the second, then the third, and then the next tri. But the scheme here also allows you to point to a list. RGB colors (range 0-1) are similar but again here there is the option of a palette and pointers.

Example

I'll start with an example data file. This draws on the Earth an octahedron of shaded triangles and a cube of blue lines:
function PxDat(p){
 var Octa, Cube;
 Octa=p[1]; 
Cube=p[2]; 
Octa.type=TRIANGLES; 
Octa.nodes=[0,1,0,  1,0,0,  0,0,1,  -1,0,0,  0,0,-1,  0,-1,0] 
Octa.links=[0,1,2,0,2,3,0,3,4,0,4,1,5,4,3,5,3,2,5,2,1,5,1,4] 
Octa.palette=[0,0,0,  1,0,0,  0, 1,0,  0, 0,1,  1,1,0,  1,0,1,  0,1,1] 
Octa.cols=[1,2,3,4,5,0] 
Cube.type=LINE_STRIP; 
Cube.palette=[0,0,1];
Cube.nodes=[NaN,NaN,  40,45,  40,135,  40,-135,  40,-45,  -40,45,  -40,135,  -40,-135,  -40,-45];//lat/lon 
Cube.links=[1,2,3,4,0,5,1,4,8,0,6,5,8,7,0,3,7,6,2] 
}
The first and last lines are in every file; they define a function. The argument p is an array of objects. In JS if you assign an array or object to a variable, the variable is a pointer, not a copy. So the two objects we want are renamed (locally).

Object properties

I'll describe the properties set in this list:
  • .type : You should always set this to one if the types listed above. Default is POINTS.
  • .nodes : Every object will need a list of nodes, in 3D unit sphere coords, or by lat/lon in degrees. I've used both types here. In either case, the numbers provided are a flat list of the coordinates in node by node sequence. See next for usage.
  • .links : Without a .links, the nodes are used in the order supplied. .links is a list of integers, starting at 0, which makes a new vertex vector selected from the nodes list. Nodes can be used several times, or not at all.
  • .palette : This is the specification of RGB colors, range 0-1. Like nodes, the triples are listed in a long sequence. There is an analogous sequence of pointers (.cols, see next), but here it is obligatory, unless the palette has only one color, in which case it is applied uniformly.
  • .cols : A sequence of vertex colors, being integer pointers into the palette. There should be one entry corresponding to each node in .nodes. In GL triangles, the node colors are used to give shading by interpolation. If you want color discontinuity, you can enter the same point more than once into .nodes, and give it different colors.
Those are the important properties, and the ones used in the example. Here are some others you might need:
  • .size : Used with POINTS objects to set the size, in pixels. No effect on other types.
  • .alt : In GL, only the front pixels are seen. .alt lets you raise the object nodes above the surface of the unit sphere (alt=0) to improve visibility, It should rarely be needed,
  • .tags : There is a facility whereby left clicking on the globe locates the nearest node of a POINTS object with this property. The tag is printed top left. So .tags is an array of HTML strings (quotes, commas), one for each entry in the .nodes of that object (no need for .links).
  • .scale : This allows you to attach a color scale to a shaded plot. It is a vector of labels (strings or numbers, they can be mixed). A color bar will be placed bottom right showing the range in the palette, and the labels will be placed at equal intervals. You need at least two - one for top and one for bottom. It only makes sense to provide this property for one object.

Drawing issues

POINTS are drawn with size defined in pixels by ,size (default 3). Lines are drawn width 1 (no choice), in segments approximating a great circle. Triangles are drawn plane, with shading. There is a pale blue disc (object 0, built-in) which separates the seen hemisphere from the unseen. It means you don't see points and lines from the other side.

Usage

Update - I've made a change to the file arrangements here. There are now 2 files Moygl.html and Moygl.js. The html file is short and ends with the call to the data file and to Moygl.js. It's that data file call where you insert your own address.

If you look at about line 8 of Moygl.html, you'll see
<script type="text/javascript" src="octa.js">
</script> octa.js is the above data file. You can replace with your file given by relative addressing, or an absolute URL.Then you just paste Moygl.html into your own HTML, and display in a browser. Moygl includes a HTML table structure that you can modify. The sphere that appears is a trackball. You can rotate it with the left mouse button, or zoom with the right (up is bigger).
As said about, if there is a .tags, clicking will show the nearest tag top right. Free rotation is a mixed blessing; it takes a while to sort out messed up orientation. Clicking the orient button, top right, rotates the visible hemisphere till N is up at the centre.

Examples displayed.

Here is the octa/cube example from above, displayed:

 

It shows how the lines forming the cube are almost great circle segments, while the triangles are plane. This is less problematic for real shading applications where the triangles will be much smaller. 

Here is an example showing more features. It is derived from the recent "Just 60" post, which uses a triangle mesh to cover the Earth and derived a station-centred tessellation. Since this is just a graphics illustration, I have started using all GHCN land stations with 50 years data and refined to get reasonably uniform coverage. The points reprsent the stations, the lines the area subdivision, and the shading is by latitude. I chose this to show the merits and deficiencies of the shading for a known variable - I think it is quite good for a coarse mesh. But effects are visible especially where big triangles are at the edge of the disc.

 Extra features included are tags - you can click for station names - and the color key. I'll show below how the data file looks.

 


This time the numerical data is bulky. I have truncated the long lines:
function PxDat(p){ 
var Tess, Stats, Mesh, Map; 
Tess=p[1]; 
Stats=p[2]; 
Mesh=p[3]; 
Map=p[4]; 
Tess.type=Map.type=LINE_STRIP; 
Stats.type=POINTS; 
Mesh.type=TRIANGLES; 

Stats.palette=[0,.1,0]; 
Stats.size=3; 
Stats.nodes=[0.0967,0.6008,-0.7935,0.0145,0.5563,-0.8309, 
Stats.tags=[" SKIKDA"," GERYVILLE ALGERIA "," ADRAR ", 
Tess.palette=[1,0,0]; 
Tess.nodes=[NaN,NaN,NaN,-0.4178,-0.6069,-0.6761,-0.4763, 
Tess.links=[727,729,728,955,1180,1179,727,0,165,418,954,
 Map.palette=[.5,.5,.5]; 
Map.nodes=[55.9217,-130.005,55.9117,-130.0131,NaN,NaN,52.8378, 
Mesh.links=[76,325,296,305,624,559,299,305,559,542,299,559, 
Mesh.nodes=[0.0967,0.6008,-0.7935,0.0145,0.5563,-0.8309, 
Mesh.palette=[1,0,0,1,0.0196,0,1,0.0392,0,1,0.0549,0,1,
 Mesh.cols=[205,199,188,187,187,181,178,108,94,142,84,78, 
Mesh.scale=["-90",-45,"0",45,"90"]
 }
The complete Moygl HTML/JS code and example data files are on this zipfile.





2 comments:

  1. For once GISS and NS are in close agreement!

    JCH

    ReplyDelete
    Replies
    1. Yes, for a two-month up then down sequence.

      Delete