package uk.ac.leeds.ccg.widgets; import java.awt.*; import uk.ac.leeds.ccg.geotools.*; import java.util.*; import java.util.HashSet; import java.util.Iterator; import java.io.*; public class BuildCartogram { private final static boolean DEBUG=true; int bodies,maxN; final double friction; final double ratio; int body,number, end_pointer, distance; int x[],y[]; double radius[]; int list[]; Leaf tree[]; Hashtable ht = new Hashtable(); public BuildCartogram(Theme t,GeoData data) { if(DEBUG)System.out.println("---->uk.ac.leeds.ccg.widgets.BuildCartogram constructed. Will identify itself as BC-->"); PolygonLayer pl = (PolygonLayer)t.getLayer(); Vector shapes = pl.getGeoShapes(); bodies = shapes.size(); ContiguityMatrix matrix = pl.getContiguityMatrix(); maxN = matrix.getMaxN()+1; bodies = pl.countFeatures()+1; friction = 0.25; ratio = 0.4; x = new int[bodies]; y = new int[bodies]; radius = new double[bodies]; list = new int[bodies]; tree = new Leaf[bodies]; for(int i=1;idata "+pop.getSize()); for(body = 1;body size "+size); CircleLayer cl = new CircleLayer(); GeoCircle circles[] = new GeoCircle[bodies]; for(body = 1;body "+cent); radius[body] = (people[body]+1.0)*size; circles[body] = new GeoCircle(id,x[body],y[body],radius[body]); cl.addGeoCircle(circles[body]); Vector neighs = gp.getContiguityList(polys); nbours[body] = neighs.size(); if(DEBUG)System.out.println("BC-->"+nbours[body]); perimeter[body]=0; GeoPolygon temp; for(nb =1; nb 0){ if(nbour[body][nb] < body){ xd = (float)(x[body] - x[nbour[body][nb]]); yd = (float)(y[body] - y[nbour[body][nb]]); tDist += Math.sqrt(xd*xd+yd*yd); tRadius += Math.sqrt(people[body]/Math.PI)+Math.sqrt(people[nbour[body][nb]]/Math.PI); } } } } scale = tDist / tRadius; widest = 0.0; for(body = 1; body < bodies;body++){ if(radius[body]>widest) widest = radius[body]; xvector[body] = 0; yvector[body] = 0; } if(DEBUG)System.out.println("BC-->Scaling by "+scale+" widest is "+widest); // set up the visualization stuff... Frame fr = new Frame(); Viewer rview = new Viewer(); Viewer lview = new Viewer(); Theme rt = new Theme(pl); Theme lt = new Theme(cl); rt.getShadeStyle().setIsOutlined(false); lt.getShadeStyle().setIsOutlined(false); Shader ss = new HSVShader(Color.green,Color.yellow); ss.setRange(pop); //ss.setMissingValueCode(errors.getMissingValueCode()); //ss.setMissingValueColor(Color.white); Key k = ss.getKey(); k.setSize(60,200); rt.setGeoData(pop); lt.setGeoData(pop); rt.setShader(ss); lt.setShader(ss); lview.addTheme(lt); rview.addTheme(rt); HighlightManager he = new HighlightManager(); SelectionManager se = new SelectionManager(); rt.setTipData(pop); lt.setTipData(pop); rt.setHighlightManager(he); rt.setSelectionManager(se); lt.setHighlightManager(he); lt.setSelectionManager(se); //fr.setSize(600,600); Panel p = new Panel(); lview.setSize(200,200); rview.setSize(200,200); p.add(lview); p.add(k); p.add(rview); fr.setLayout(new BorderLayout()); Panel p2 = new Panel(); p2.setLayout(new GridLayout(1,3)); p2.add(new ToolBar(lview,true)); GeoFormLabel gf = new GeoFormLabel(); gf.addHighlightManager(he,pop); p2.add(gf); p2.add(new ToolBar(rview,true)); fr.add(p,"Center"); fr.add(p2,"South"); fr.pack(); fr.show(); lview.setMapExtentFull(); rview.setMapExtentFull(); //start the big loop, creating the tree each iter for(itter = 1;itter <= itters; itter++){ for(body = 1;body < bodies; body++){ tree[body].id = 0; } end_pointer = 1; for (body = 1;body < bodies; body++){ addPoint(1,1); } displacement = 0.0; for (body = 1;body < bodies; body++){ //get of neighboues within inti number = 0; distance = (int)(widest + radius[body]); getPoint(1,1); /* if(body == 1){ System.out.println("body 1 number "+number+" distance "+distance+" radius "+radius[body]); }*/ // initalise a few vectors xrepel = yrepel = 0.0; xattract = yattract = 0.0; closest = widest; //work out repelling force of overlapping neighbours // System.out.println("Number"); if(number > 0){ for(nb = 1; nb <= number; nb++){ other = list[nb]; if (other != body){ xd = x[other]-x[body]; yd = y[other]-y[body]; dist = Math.sqrt(xd*xd+yd*yd); closest = Math.min(closest,dist); overlap = radius[body] +radius[other] - dist; if(overlap > 0 && dist > 1){ xrepel = xrepel - overlap*(x[other]-x[body])/dist; yrepel = yrepel - overlap*(y[other]-y[body])/dist; } } } } // work out forces of attraction between neighbours for (nb = 1; nb <= nbours[body] ; nb++){ other = nbour[body][nb]; if(other != 0)//opt this { xd = (x[body]-x[other]); yd = (y[body]-y[other]); dist = Math.sqrt(xd*xd+yd*yd); overlap = dist -radius[body] - radius[other]; if(overlap>0){ overlap = overlap * border[body][nb]/perimeter[body]; xattract = xattract+overlap*(x[other]-x[body])/dist; yattract = yattract + overlap*(y[other]-y[body])/dist; } } } //work out commbined effect of attraction and repulsion atrdst = Math.sqrt(xattract * xattract + yattract * yattract); repdst = Math.sqrt(xrepel * xrepel+ yrepel * yrepel); if (repdst > closest){ xrepel = closest * xrepel / (repdst +1); yrepel = closest * yrepel / (repdst +1); repdst = closest; } if(repdst > 0){ xtotal = (1-ratio) * xrepel +ratio*(repdst*xattract/(atrdst+1)); ytotal = (1-ratio) * yrepel +ratio*(repdst*yattract/(atrdst+1)); } else{ if(atrdst > closest){ xattract = closest *xattract/(atrdst+1); yattract = closest *yattract/(atrdst+1); } xtotal = xattract; ytotal = yattract; } xvector[body] = friction * (xvector[body]+xtotal); yvector[body] = friction * (yvector[body]+ytotal); displacement += Math.sqrt(xtotal * xtotal +ytotal * ytotal); } //update positions for(body = 1;body < bodies;body++){ x[body] +=xvector[body] +0.5; y[body] +=yvector[body] +0.5; } done++; displacement = displacement / bodies; if(done%100==1){ for(int i=1;idisplacement is now "+displacement+" after "+done+ "itterations"); } } } //lets see what we have got public void addPoint(int pointer,int axis){ if(tree[pointer].id == 0) { tree[pointer].id = body; tree[pointer].left = 0; tree[pointer].right = 0; tree[pointer].xpos = x[body]; tree[pointer].ypos = y[body]; } else{ if(axis == 1){ if (x[body] >= tree[pointer].xpos){ if(tree[pointer].left == 0){ end_pointer +=1; tree[pointer].left = end_pointer; } addPoint(tree[pointer].left,3-axis); } else { if (tree[pointer].right == 0){ end_pointer+=1; tree[pointer].right = end_pointer; } addPoint(tree[pointer].right,3-axis); } } else{ if(y[body] >= tree[pointer].ypos){ if(tree[pointer].left == 0){ end_pointer +=1; tree[pointer].left = end_pointer; } addPoint(tree[pointer].left,3-axis); } else{ if(tree[pointer].right == 0){ end_pointer+=1; tree[pointer].right = end_pointer; } addPoint(tree[pointer].right, 3-axis); } } } } public void getPoint(int pointer, int axis){ if(pointer > 0){ if(tree[pointer].id > 0){ if (axis == 1){ if(x[body]-distance < tree[pointer].xpos){ getPoint(tree[pointer].right,3-axis); } if(x[body]+distance >= tree[pointer].xpos){ getPoint(tree[pointer].left,3-axis); } } if(axis == 2){ if(y[body]-distance < tree[pointer].ypos){ getPoint(tree[pointer].right,3-axis); } if(y[body]+distance >= tree[pointer].ypos){ getPoint(tree[pointer].left,3-axis); } } if ((x[body]-distance < tree[pointer].xpos) && (x[body]+distance>= tree[pointer].xpos)){ if((y[body]-distance < tree[pointer].ypos) && (y[body]+distance>= tree[pointer].ypos)){ number ++; list[number] = tree[pointer].id; } } } } } class Leaf { int id; int xpos; int ypos; int left; int right; } }