//vodafone call visualisation // //Tim Redfern Jan 2012 // //scale of wall 10.57x2.8m - some parts are obscured // //416 x 110 in. ~ 62400x16500 ~ 1029 mpx ~ 2945 MB ram to open // //CousinMarriageWorld.svg, nominally 940 × 470 pixels, file size: 1.99 MB //World_map_(Miller_cylindrical_projection,_blank).svg‎, nominally 634 × 477 pixels, file size: 1.84 MB //wikimedia // //http://www.vectortemplates.com/vector-world-map.php //requirements - //must be able to transform points to a new projection // maybe not through normal shape library //must be able to find a random point within the shape // //250112 so far so good, can iterate children. //safest thing is to establish that I can place a point as being inside or outside of a shape //(are they closed properly!) //If we can find points in them then we can start the main task: //connecting parts of the SVG with rows in the spreadsheet //maybe next first I should look at projections (to keep them happy) //I have a map with rectangular coords, //is easy to enough to play with the projection // public boolean contains(RGeomElem shp) // public geomerative.RRectangle getBounds() // --> this is kind of hidden. why? anyway, it should be possible to use it //another option is to use the OUTLINE of the country (as a purely geometric thing). /* http://en.wikipedia.org/wiki/3D_projection a- the 3D position of a point A that is to be projected. c- the 3D position of a point C representing the camera. O- The orientation of the camera (represented, for instance, by Tait–Bryan angles). e- the viewer's position relative to the display surface.[1] http://williams.best.vwh.net/avform.htm#Crs ==good stuff Intermediate points on a great circle Here we find points (lat,lon) a given fraction of the distance (d) between them. Suppose the starting point is (lat1,lon1) and the final point (lat2,lon2) and we want the point a fraction f along the great circle route. f=0 is point 1. f=1 is point 2. The two points cannot be antipodal ( i.e. lat1+lat2=0 and abs(lon1-lon2)=pi) because then the route is undefined. The intermediate latitude and longitude is then given by: A=sin((1-f)*d)/sin(d) B=sin(f*d)/sin(d) x = A*cos(lat1)*cos(lon1) + B*cos(lat2)*cos(lon2) y = A*cos(lat1)*sin(lon1) + B*cos(lat2)*sin(lon2) z = A*sin(lat1) + B*sin(lat2) lat=atan2(z,sqrt(x^2+y^2)) lon=atan2(y,x) //find RPoint sp,ep,mp; float f=0.8; //fraction along path; float d=acos(sin(sp.y)*sin(ep.y)+cos(sp.y)*cos(ep.y)*cos(sp.x-ep.x)); float A=sin((1-f)*d)/sin(d); float B=sin(f*d)/sin(d); float x = A*cos(lat1)*cos(lon1) + B*cos(lat2)*cos(lon2); float y = A*cos(lat1)*sin(lon1) + B*cos(lat2)*sin(lon2); float z = A*sin(lat1) + B*sin(lat2); mp.y=atan2(z,sqrt(x^2+y^2)); mp.x=atan2(y,x); drawing - circles (fixed diameter), closed shape made of 2 bezier curves paths above 3d globe fix missing countries render above map colours sort lines according to destination ? match 3D map or render texture out of processing or export 3d lines - dx cache points! */ import processing.pdf.*; import geomerative.*; RShape shp; pointNormalise pnorm; pointTransform ptrans; sphereMap smap; String mode; csvloader data; calldata calls; bitmapcountry Ireland; bezierstroke bstroke; greatcirclestroke3D gstroke; float hw,hh; PImage lightmap; color bg,fg; void setup(){ println("vodaviz v0.6"); RG.init(this); mode="PDF"; if (mode=="PDF") size(832,220,PDF, "vodaviz_circles_270212.pdf"); //P3D); //832,220); //nb pdf is 800x600 else size(832,220); //,PDF, "testoutput.pdf"); //P3D); //832,220); //nb pdf is 800x600 // C. 33 - M. 3 - Y. 0 - K. 0 bg=color(164,215,244); fg=color(#D2131D); hw=width/2; hh=height/2; smooth(); float m = millis(); shp = RG.loadShape("countries_named_mercator_fixup.svg"); //test_drawing.svg"); //world_countries_outlines_split.svg"); pnorm = new pointNormalise(18.279,746.302,109,374.293); ptrans = new pointTransform(); smap = new sphereMap(); lightmap=loadImage("earth_lights.gif"); float startsize=0.2; float endsize=0.1; float linewidth=0.05; float mpfract=0.5; float raisefract=0.1; float bezierfract=0.25; bstroke = new bezierstroke(startsize,endsize,linewidth,mpfract,raisefract,bezierfract); startsize=.2; endsize=.02; float[] transpos={0.0,0.25,0.75,1.0}; float[] transamt={1.0,1.0,1.0,1.0}; //{0.5,0.05,0.05,0.5}; color col=color(0,0,0); gstroke=new greatcirclestroke3D(startsize,transpos,transamt,col,smap); RG.ignoreStyles(); println("loaded svg in "+((millis()-m)*.001)+" seconds"); Ireland=new bitmapcountry("Ireland",0,0,0,0,0,0,shp.children[0]); Ireland.analyse(18.279,746.302,109,374.293,5); data=new csvloader("calls.csv"); calls=new calldata(data.data,shp,"countries5.xml",5,this); background(255,255,255); noFill(); stroke(255); strokeWeight(.002); if (false) { //check worked example http://williams.best.vwh.net/avform.htm#Example RPoint LAX=new RPoint(2.066470,0.592539); RPoint JFK=new RPoint(1.287762,0.709186); println("LAX to JFK:"+GSphereDist(LAX,JFK)+" radians"); RPoint LmJ=GCircFract(LAX,JFK,0.4); println("40% of LAX to JFK:"+LmJ.y+","+LmJ.x+" radians"); } } int i=0; int j=0; void draw() { if (calls.loaded) { // wait for 1st xmlevent noStroke(); float hw=getWidth()/2; float hh=getHeight()/2; if (i==0) { //image(lightmap,0,0,getWidth(),getHeight()); //fill(bg); //rect(0,0,width,height); //background(0); if (false) { //render lightmap in 3D float pw=0.5/lightmap.width; float ph=0.5/lightmap.height; for (int j=0;j0&&e.x>0){ //point found RPoint sp=ptrans.form(pnorm.alise(s)); RPoint ep=ptrans.form(pnorm.alise(e)); RPoint Sp=smap.per(sp,4); RPoint Ep=smap.per(ep,4); RPoint Mp=smap.per(GCircFract(sp,ep,0.8),4.1); beginShape(); line(Sp.x+(getWidth()/2),Sp.y+(getHeight()/2),Mp.x+(getWidth()/2),Mp.y+(getHeight()/2)); line(Mp.x+(getWidth()/2),Mp.y+(getHeight()/2),Ep.x+(getWidth()/2),Ep.y+(getHeight()/2)); endShape(); } } //println("plotting "+calls.countries.get(i).name+": "+calls.countries.get(i).calls+" calls"); } if (false) { //draw gradient 3D lines if (calls.countries.get(i).points.size()>0) { for (int j=0;j0) { float area=calls.countries.get(i).calls; while (area>0) { weightedpixel px=calls.countries.get(i).getpixel(); RPoint Sp=px.randompt(0.0); //float b=min(px.bright,pow(area,0.5)/ascale); float b=100; area-=(pow(b,2)*ascale)+1; float cdiam=(b*.02)+.1; //scale shapes at edges boolean fits=false; while (!fits) { RPoint[] tc=new RPoint[4]; tc[0]=new RPoint(Sp.x-cdiam,Sp.y-cdiam); tc[1]=new RPoint(Sp.x+cdiam,Sp.y-cdiam); tc[2]=new RPoint(Sp.x+cdiam,Sp.y+cdiam); tc[3]=new RPoint(Sp.x-cdiam,Sp.y+cdiam); if (calls.countries.get(i).outline.contains(Sp)) fits=true; else { cdiam*=0.8; print("."); } } //ellipse3d(Sp,(b*.00002)+.000002,4); RPoint Dp=smap.per(ptrans.form(pnorm.alise(Sp)),4); ellipse(Dp.x+hw,Dp.y+hh,cdiam,cdiam); } } } } else //draw 2D { if (false) { //draw countries beginShape(); for (int k=0;k0&&e.x>0){ //point found RPoint Sp=screenMapper(pnorm.alise(s)); RPoint Ep=screenMapper(pnorm.alise(e)); RPoint Mp=plerp(Sp,Ep,0.75); //beginShape(); //line(Sp.x+(getWidth()/2),Sp.y+(getHeight()/2),Mp.x+(getWidth()/2),Mp.y+(getHeight()/2)); //line(Mp.x+(getWidth()/2),Mp.y+(getHeight()/2),Ep.x+(getWidth()/2),Ep.y+(getHeight()/2)); //bezier(Sp.x, Sp.y, Sp.x, Sp.y-((getHeight()-Sp.y)*.1), Ep.x, Ep.y-((getHeight()-Ep.y)*.1), Ep.x, Ep.y); //endShape(); bstroke.drawstroke(Sp,Ep); } } //println("plotting "+calls.countries.get(i).name+": "+calls.countries.get(i).calls+" calls"); } if (false) { //fill country for (int j=0;j