Changeset 495

Show
Ignore:
Timestamp:
02/18/08 15:24:04 (7 months ago)
Author:
tom
Message:

copied as3 Map API into processing InteractiveMap?

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/processing/sketches/modest_maps_interactive/InteractiveMap.java

    r494 r495  
    11 
    2 class InteractiveMap { 
    3  
    4   // pan, zoom and (eventually) rotate 
    5   double tx = 0, ty = 0; 
     2import com.modestmaps.*; 
     3import processing.core.*; 
     4import java.util.*; 
     5 
     6public class InteractiveMap implements PConstants { 
     7 
     8  // I have made the dumb mistake of getting these wrong before... 
     9  // it's REALLY unlikely you'll want to change them: 
     10  int TILE_WIDTH = 256; 
     11  int TILE_HEIGHT = 256; 
     12   
     13  // unavoidable right now, for loadImage and float maths 
     14  PApplet p; 
     15 
     16  // pan and zoom 
     17  double tx = -TILE_WIDTH/2; // half the world width, at zoom 0 
     18  double ty = -TILE_HEIGHT/2; // half the world height, at zoom 0 
    619  double sc = 1; 
    7   //  float a = 0.0; 
     20 
     21  // limit simultaneous calls to loadImage 
     22  int MAX_PENDING = 4; 
     23   
     24  // limit tiles in memory 
     25  // 256 would be 64 MB, you may want to lower this quite a bit for your app 
     26  int MAX_IMAGES_TO_KEEP = 256; 
     27 
     28  // upping this can help appearances when zooming out, but also loads many more tiles 
     29  int GRID_PADDING = 1; 
    830 
    931  // what kinda maps? 
    1032  AbstractMapProvider provider; 
    1133 
    12   int MAX_PENDING = 4; 
    13   int MAX_IMAGES_TO_KEEP = 256; // 256 would be 64 MB, you may want to lower this quite a bit for your app 
    14    
     34  // how big? 
     35  float width, height; 
     36 
     37  // loading tiles 
     38  Hashtable pending = new Hashtable(); // coord -> TileLoader 
     39  // loaded tiles 
     40  Hashtable images = new Hashtable();  // coord -> PImage 
     41  // coords waiting to load 
     42  Vector queue = new Vector(); 
     43  // a list of the most recent MAX_IMAGES_TO_KEEP PImages we've seen 
    1544  Vector recentImages = new Vector(); 
    1645 
    17   InteractiveMap() { 
    18     provider = new Microsoft.HybridProvider(); 
     46  // for sorting coordinates by zoom 
     47  ZoomComparator zoomComparator = new ZoomComparator(); 
     48 
     49  // for loading tiles from the inside first 
     50  QueueSorter queueSorter = new QueueSorter(); 
     51 
     52  /** make a new interactive map, using the given provider, of the given width and height */ 
     53  InteractiveMap(PApplet p, AbstractMapProvider provider, float width, float height) { 
     54 
     55    this.p = p; 
     56    this.provider = provider; 
     57    this.width = width; 
     58    this.height = height; 
    1959 
    2060    // fit to screen 
    21     sc = ceil(min(height/256.0, width/256.0)); 
    22  
    23     // center the center! 
    24     tx = -128; 
    25     ty = -128; 
    26  
    27     addMouseWheelListener(new java.awt.event.MouseWheelListener() {  
    28       public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {  
    29         mouseWheel(evt.getWheelRotation()); 
    30       } 
    31     } 
    32     );  
     61    sc = p.ceil(p.min(height/(float)TILE_WIDTH, width/(float)TILE_HEIGHT)); 
    3362 
    3463  } 
     
    3665  void draw() { 
    3766 
    38     PMatrix m = new PMatrix(); 
     67    // remember smooth setting so it can be reset  
     68    boolean smooth = p.g.smooth; 
     69 
     70    // !!! VERY IMPORTANT 
     71    // (all the renderers apart from OpenGL will choke if you ask for smooth scaling of image calls) 
     72    p.noSmooth(); 
    3973 
    4074    // translate and scale, from the middle 
    41     pushMatrix(); 
    42     translate(width/2, height/2); 
    43     scale((float)sc); 
    44     translate((float)tx, (float)ty); 
    45  
    46     //    println("p5: "); 
    47     //    printMatrix(); 
    48  
    49     m.push(); 
    50     m.translate(width/2, height/2); 
    51     m.scale((float)sc); 
    52     m.translate((float)tx,(float)ty); 
    53  
    54     //    println("m: "); 
    55     //    m.print(); 
    56  
    57     // find the world bounds in screen-space: 
    58     float minX = screenX(0,0); 
    59     float minY = screenY(0,0); 
    60     float maxX = screenX(256,256); 
    61     float maxY = screenY(256,256); 
    62  
    63     //    println("map p5: " + nf(minX,1,3) + " " + nf(minY,1,3) + " : " + nf(maxX,1,3) + " " + nf(maxY,1,3)); 
    64  
    65     /*    float[] in1 = { 0, 0, 0 }; 
    66       
    67      float[] out = new float[3]; 
    68      m.mult3(in1, out); 
    69      minX = out[0]; 
    70      minY = out[1]; 
    71       
    72      float[] in2 = { 256, 256, 0 }; 
    73      m.mult3(in2, out); 
    74      maxX = out[0]; 
    75      maxY = out[1]; 
    76       
    77      println("map m: " + nf(minX,1,3) + " " + nf(minY,1,3) + " : " + nf(maxX,1,3) + " " + nf(maxY,1,3)); */ 
    78  
    79     // 0 when scale is 1, 1 when scale is 2, 2 when scale is 4, 3 when scale is 8, etc. 
     75    p.pushMatrix(); 
     76    p.translate(width/2, height/2); 
     77    p.scale((float)sc); 
     78    p.translate((float)tx, (float)ty); 
     79 
     80    // find the bounds of the ur-tile in screen-space: 
     81    float minX = p.screenX(0,0); 
     82    float minY = p.screenY(0,0); 
     83    float maxX = p.screenX(TILE_WIDTH, TILE_HEIGHT); 
     84    float maxY = p.screenY(TILE_WIDTH, TILE_HEIGHT); 
     85    p.println(minX + " " + minY); 
     86    p.println(maxX + " " + maxY); 
     87 
     88    // what power of 2 are we at? 
     89    // 0 when scale is around 1, 1 when scale is around 2,  
     90    // 2 when scale is around 4, 3 when scale is around 8, etc. 
    8091    int zoom = bestZoomForScale((float)sc); 
    8192 
    8293    // how many columns and rows of tiles at this zoom? 
    83     int cols = (int)pow(2,zoom); 
    84     int rows = (int)pow(2,zoom); 
    85     //  println("rows/cols: " + rows + "/" + cols); 
    86     //  println("tileCount: " + (rows * cols)); 
    87  
    88     // find the biggest box the screen would fit in, aligned with the map: 
     94    // (this is basically (int)sc, but let's derive from zoom to be sure  
     95    int cols = (int)p.pow(2,zoom); 
     96    int rows = (int)p.pow(2,zoom); 
     97 
     98//    p.println(cols + " " + rows); 
     99 
     100    // find the biggest box the screen would fit in:, aligned with the map: 
    89101    float screenMinX = 0; 
    90102    float screenMinY = 0; 
    91103    float screenMaxX = width; 
    92104    float screenMaxY = height; 
    93     //  println("screen: " + nf(screenMinX,1,3) + " " + nf(screenMinY,1,3) + " : " + nf(screenMaxX,1,3) + " " + nf(screenMaxY,1,3)); 
    94     // TODO align this box and re-enable rotations!? 
     105    // TODO: align this, and fix the next bit to work with rotated maps 
    95106 
    96107    // find start and end columns 
    97     int minCol = (int)floor(cols * (screenMinX-minX) / (maxX-minX)); 
    98     int maxCol = (int)ceil(cols * (screenMaxX-minX) / (maxX-minX)); 
    99     int minRow = (int)floor(rows * (screenMinY-minY) / (maxY-minY)); 
    100     int maxRow = (int)ceil(rows * (screenMaxY-minY) / (maxY-minY)); 
    101     //  println("row/col: " + minCol + ", " + minRow + " : " + maxCol + ", " + maxRow); 
     108    int minCol = (int)p.floor(cols * (screenMinX-minX) / (maxX-minX)); 
     109    int maxCol = (int)p.ceil(cols * (screenMaxX-minX) / (maxX-minX)); 
     110    int minRow = (int)p.floor(rows * (screenMinY-minY) / (maxY-minY)); 
     111    int maxRow = (int)p.ceil(rows * (screenMaxY-minY) / (maxY-minY)); 
    102112 
    103113    // pad a bit, for luck (well, because we might be zooming out between zoom levels) 
    104     minCol -= 1; 
    105     minRow -= 1; 
    106     maxCol += 1; 
    107     maxRow += 1; 
     114    minCol -= GRID_PADDING; 
     115    minRow -= GRID_PADDING; 
     116    maxCol += GRID_PADDING; 
     117    maxRow += GRID_PADDING; 
     118 
     119    // we don't wrap around the world yet, so: 
     120    minCol = p.constrain(minCol, 0, cols); 
     121    maxCol = p.constrain(maxCol, 0, cols); 
     122    minRow = p.constrain(minRow, 0, rows); 
     123    maxRow = p.constrain(maxRow, 0, rows); 
    108124 
    109125    // keep track of what we can see already: 
     
    118134 
    119135        // let's make sure we still have ints: 
    120         coord.row = round(coord.row); 
    121         coord.column = round(coord.column); 
    122         coord.zoom = round(coord.zoom); 
     136        coord.row = p.round(coord.row); 
     137        coord.column = p.round(coord.column); 
     138        coord.zoom = p.round(coord.zoom); 
    123139 
    124140        // keep this for later: 
     
    134150            Coordinate zoomed = coord.zoomTo(i).container(); 
    135151            // make sure we still have ints: 
    136             zoomed.row = round(zoomed.row); 
    137             zoomed.column = round(zoomed.column); 
    138             zoomed.zoom = round(zoomed.zoom); 
     152            zoomed.row = p.round(zoomed.row); 
     153            zoomed.column = p.round(zoomed.column); 
     154            zoomed.zoom = p.round(zoomed.zoom); 
    139155            if (images.containsKey(zoomed)) { 
    140156              visibleKeys.add(zoomed); 
     
    143159            } 
    144160          } 
    145            
     161 
    146162          // or if we have any of the children 
    147163          if (!gotParent) { 
    148164            Coordinate zoomed = coord.zoomBy(1).container(); 
    149             Coordinate[] kids = new Coordinate[] { zoomed, zoomed.right(), zoomed.down(), zoomed.right().down() };  
     165            Coordinate[] kids = new Coordinate[] {  
     166              zoomed, zoomed.right(), zoomed.down(), zoomed.right().down()                         };  
    150167            for (int i = 0; i < kids.length; i++) { 
    151168              zoomed = kids[i]; 
    152169              // make sure we still have ints: 
    153               zoomed.row = round(zoomed.row); 
    154               zoomed.column = round(zoomed.column); 
    155               zoomed.zoom = round(zoomed.zoom); 
     170              zoomed.row = p.round(zoomed.row); 
     171              zoomed.column = p.round(zoomed.column); 
     172              zoomed.zoom = p.round(zoomed.zoom); 
    156173              if (images.containsKey(zoomed)) { 
    157174                visibleKeys.add(zoomed); 
     
    159176            }             
    160177          } 
    161            
     178 
    162179        } 
    163          
     180 
    164181      } // rows 
    165182    } // columns 
    166183 
    167184    // sort by zoom so we draw small zoom levels (big tiles) first: 
    168     Collections.sort(visibleKeys, new Comparator() { 
    169       public int compare(Object o1, Object o2) { 
    170         Coordinate c1 = (Coordinate)o1; 
    171         Coordinate c2 = (Coordinate)o2; 
    172         return c1.zoom < c2.zoom ? -1 : c1.zoom > c2.zoom ? 1 : 0; 
    173       } 
    174     }); 
     185    Collections.sort(visibleKeys, zoomComparator); 
    175186 
    176187    if (visibleKeys.size() > 0) { 
    177188      Coordinate previous = (Coordinate)visibleKeys.get(0); 
    178       pushMatrix(); 
     189      p.pushMatrix(); 
    179190      // correct the scale for this zoom level: 
    180       scale(1.0/pow(2, previous.zoom)); 
     191      p.scale(1.0f/p.pow(2, previous.zoom)); 
    181192      for (int i = 0; i < visibleKeys.size(); i++) { 
    182193        Coordinate coord = (Coordinate)visibleKeys.get(i); 
    183194 
    184195        if (coord.zoom != previous.zoom) { 
    185           popMatrix(); 
    186           pushMatrix(); 
     196          p.popMatrix(); 
     197          p.pushMatrix(); 
    187198          // correct the scale for this zoom level: 
    188           scale(1.0/pow(2,coord.zoom)); 
     199          p.scale(1.0f/p.pow(2,coord.zoom)); 
    189200        } 
    190        
     201 
    191202        if (images.containsKey(coord)) { 
    192203          PImage tile = (PImage)images.get(coord); 
    193           image(tile,coord.column*256,coord.row*256,256,256); 
     204          p.image(tile,coord.column*256,coord.row*256,256,256); 
     205//          if (p.frameCount % 100 == 0) { 
     206//            p.println(p.screenX(coord.column*256,coord.row*256) + ", " + p.screenY(coord.column*256,coord.row*256)); 
     207//          } 
    194208          if (recentImages.contains(tile)) { 
    195209            recentImages.remove(tile); 
     
    198212        } 
    199213      } 
    200       popMatrix(); 
     214      p.popMatrix(); 
    201215    }     
    202216 
    203     popMatrix(); 
     217    p.popMatrix(); 
    204218 
    205219    //  println(pending.size() + " pending..."); 
     
    210224 
    211225    // sort what's left by distance from center: 
    212     Coordinate center = new Coordinate( (minRow + maxRow) / 2.0, (minCol + maxCol) / 2.0, zoom);     
     226    queueSorter.setCenter(new Coordinate( (minRow + maxRow) / 2.0f, (minCol + maxCol) / 2.0f, zoom)); 
    213227    //    println("center: " + center); 
    214     Collections.sort(queue, new QueueSorter(center)); 
     228    Collections.sort(queue, queueSorter); 
    215229 
    216230    // load up to 4 more things: 
     
    218232 
    219233    if (recentImages.size() > MAX_IMAGES_TO_KEEP) { 
    220       println(recentImages.size() + " images in memory, removing..."); 
     234      //println(recentImages.size() + " images in memory, removing..."); 
    221235      recentImages.subList(0, recentImages.size()-MAX_IMAGES_TO_KEEP).clear(); 
    222       println(recentImages.size() + " images in memory"); 
     236      //println(recentImages.size() + " images in memory"); 
    223237      images.values().retainAll(recentImages); 
    224238    } 
    225239 
    226     if (keyPressed) { 
    227       /*    if (key == CODED) { 
    228        if (keyCode == LEFT) { 
    229        a -= 1; 
    230        } 
    231        else if (keyCode == RIGHT) { 
    232        a += 1;         
    233        } 
    234        }  
    235        else */      if (key == '+' || key == '=') { 
    236         sc *= 1.05; 
    237       } 
    238       else if (key == '_' || key == '-' && sc > 0.1) { 
    239         sc *= 1.0/1.05; 
    240       } 
    241       else if (key == 'z' || key == 'Z') { 
    242         sc = pow(2, getZoom()); 
    243       } 
    244       else if (key == ' ') { 
    245         sc = 1.0; 
    246         tx = 0; 
    247         ty = 0;  
    248         //        a = 0; 
    249       } 
    250     } 
    251  
    252     /*    println("sc: " + sc +  
    253      " tx: " + tx +  
    254      " ty: " + ty); */ 
     240    if (smooth) p.smooth(); 
    255241 
    256242  }  
     
    261247  } 
    262248 
    263   void setCenter(Coordinate center) { 
    264     println("setting center to " + center); 
    265     sc = pow(2.0, center.zoom); 
    266     tx = -256.0*center.column/sc; 
    267     ty = -256.0*center.row/sc; 
    268   } 
    269  
    270   void setCenter(Location location) { 
    271     setCenter(provider.locationCoordinate(location).zoomTo(getZoom())); 
    272   } 
    273    
    274   void setCenterZoom(Location location, int zoom) { 
    275     setCenter(provider.locationCoordinate(location).zoomTo(zoom)); 
    276   } 
    277  
    278   Coordinate getCenter() { 
     249  Location getCenter() { 
     250    return provider.coordinateLocation(getCenterCoordinate()); 
     251  } 
     252 
     253  Coordinate getCenterCoordinate() { 
    279254    float row = (float)(ty*sc/-256.0); 
    280255    float column = (float)(tx*sc/-256.0); 
     
    283258  } 
    284259 
     260  void setCenter(Coordinate center) { 
     261    //println("setting center to " + center); 
     262    sc = p.pow(2.0f, center.zoom); 
     263    tx = -256.0*center.column/sc; 
     264    ty = -256.0*center.row/sc; 
     265  } 
     266 
     267  void setCenter(Location location) { 
     268    setCenter(provider.locationCoordinate(location).zoomTo(getZoom())); 
     269  } 
     270 
     271  void setCenterZoom(Location location, int zoom) { 
     272    setCenter(provider.locationCoordinate(location).zoomTo(zoom)); 
     273  } 
     274 
    285275  /** sets scale according to given zoom level, should leave you with pixel perfect tiles */ 
    286276  void setZoom(int zoom) { 
    287     sc = pow(2.0, zoom-1);  
     277    sc = p.pow(2.0f, zoom-1);  
     278  } 
     279 
     280  void zoom(int dir) { 
     281    sc = p.pow(2.0f, getZoom()+dir);  
    288282  } 
    289283 
    290284  void zoomIn() { 
    291     sc = pow(2.0, getZoom()+1);  
     285    sc = p.pow(2.0f, getZoom()+1);  
    292286  }   
    293287 
    294288  void zoomOut() { 
    295     sc = pow(2.0, getZoom()-1);  
    296   }   
     289    sc = p.pow(2.0f, getZoom()-1);  
     290  } 
     291 
     292  //        public function setExtent(extent:MapExtent):void 
     293  //        public function getExtent():MapExtent 
     294 
     295  /* 
     296            protected function coordinatePosition(centerCoord:Coordinate):MapPosition 
     297            public function locationsPosition(locations:Array):MapPosition 
     298            protected function extentPosition(extent:MapExtent):MapPosition 
     299   */ 
     300 
     301  //        public function getCenterZoom():Array 
     302 
     303  AbstractMapProvider getMapProvider() { 
     304    return this.provider; 
     305  } 
     306 
     307  void setMapProvider(AbstractMapProvider provider) { 
     308    this.provider = provider; 
     309    images.clear(); 
     310    queue.clear(); 
     311    pending.clear(); 
     312  } 
     313 
     314  // TODO: move constructor args to match: 
     315  //float width, float height, boolean draggable, AbstractMapProvider provider, Location[] extent 
     316 
     317  Point2f locationPoint(Location location) { 
     318    PMatrix m = new PMatrix(); 
     319    m.translate(width/2, height/2); 
     320    m.scale((float)sc); 
     321    m.translate((float)tx, (float)ty); 
     322 
     323    Coordinate coord = provider.locationCoordinate(location).zoomTo(0); 
     324    float[] out = new float[3]; 
     325    m.mult3(new float[] { 
     326      coord.column*256.0f, coord.row*256.0f, 0    } 
     327    , out); 
     328 
     329    return new Point2f(out[0], out[1]); 
     330  } 
     331 
     332  Location pointLocation(Point2f point) { 
     333 
     334    // TODO: create this matrix once and keep it around for drawing and projecting 
     335    PMatrix m = new PMatrix(); 
     336    m.translate(width/2, height/2); 
     337    m.scale((float)sc); 
     338    m.translate((float)tx, (float)ty); 
     339 
     340    // find top left and bottom right positions of map in screenspace: 
     341    float tl[] = new float[3]; 
     342    m.mult3(new float[] {  
     343      0,0,0     } 
     344    , tl); 
     345    float br[] = new float[3];     
     346    m.mult3(new float[] {  
     347      256,256,0     } 
     348    , br); 
     349 
     350    float col = (point.x - tl[0]) / (br[0] - tl[0]); 
     351    float row = (point.y - tl[1]) / (br[1] - tl[1]); 
     352    Coordinate coord = new Coordinate(row, col, 0); 
     353 
     354    return provider.coordinateLocation(coord);     
     355  } 
     356 
     357  // TODO: pan by proportion of screen size, not by coordinate grid 
     358  void panUp() { 
     359    setCenter(getCenterCoordinate().up()); 
     360  } 
     361  void panDown() { 
     362    setCenter(getCenterCoordinate().down()); 
     363  } 
     364  void panLeft() { 
     365    setCenter(getCenterCoordinate().left()); 
     366  } 
     367  void panRight() { 
     368    setCenter(getCenterCoordinate().right()); 
     369  } 
     370 
     371  void panAndZoomIn(Location location) { 
     372    // TODO: animate 
     373    setCenterZoom(location, getZoom() + 1); 
     374  } 
     375 
     376  void panTo(Location location) { 
     377    // TODO: animate 
     378    setCenter(location); 
     379  } 
     380 
     381  /* 
     382            public function putMarker(location:Location, marker:DisplayObject=null):void 
     383                public function getMarker(id:String):DisplayObject 
     384            public function removeMarker(id:String):void 
     385    
     386            public function setCopyright(copyright:String):void { 
     387   */ 
     388 
     389  /* 
     390            public function onStartZoom():void 
     391            public function onStopZoom():void 
     392            public function onZoomed(delta:Number):void 
     393    
     394            public function onStartPan():void 
     395            public function onStopPan():void 
     396            public function onPanned(delta:Point):void 
     397    
     398            public function onResized():void 
     399    
     400            public function onExtentChanged(extent:MapExtent):void 
     401   */ 
     402 
     403 
     404 
     405  /////////////////////////////////////////////////////////////////////// 
    297406 
    298407  float scaleForZoom(int zoom) { 
    299     return pow(2.0, zoom); 
     408    return p.pow(2.0f, zoom); 
    300409  } 
    301410 
    302411  float zoomForScale(float scale) { 
    303     return log(scale) / log(2); 
     412    return p.log(scale) / p.log(2); 
    304413  } 
    305414 
    306415  int bestZoomForScale(float scale) { 
    307     return (int)min(20, max(1, (int)round(log(scale) / log(2)))); 
    308   } 
     416    return (int)p.min(20, p.max(1, (int)p.round(p.log(scale) / p.log(2)))); 
     417  } 
     418 
     419  ////////////////////////////////////////////////////////////////////////// 
    309420 
    310421  void mouseDragged() { 
    311     double dx = (double)(mouseX - pmouseX) / sc; 
    312     double dy = (double)(mouseY - pmouseY) / sc; 
     422    double dx = (double)(p.mouseX - p.pmouseX) / sc; 
     423    double dy = (double)(p.mouseY - p.pmouseY) / sc; 
    313424    //    float angle = radians(-a); 
    314425    //    float rx = cos(angle)*dx - sin(angle)*dy; 
     
    320431  } 
    321432 
    322   // loading tiles 
    323   Hashtable pending = new Hashtable(); // coord.toString() -> TileLoader 
    324   // loaded tiles 
    325   Hashtable images = new Hashtable();  // coord.toString() -> PImage 
    326   // coords waiting to load 
    327   Vector queue = new Vector(); // coord 
     433  ///////////////////////////////////////////////////////////////// 
    328434 
    329435  void grabTile(Coordinate coord) { 
     
    340446    } 
    341447    public void run() { 
     448      p.println("loading " + coord); 
    342449      String[] urls = provider.getTileUrls(coord); 
    343       println("loading " + urls[0]); 
    344       PImage img = loadImage(urls[0], "unknown"); 
    345       for (int i = 1; i < urls.length; i++) { 
    346         println("loading " + urls[i]); 
    347         img.blend(loadImage(urls[i], "unknown"), 0, 0, img.width, img.height, 0, 0, img.width, img.height, BLEND); 
     450      //      p.println("loading " + urls[0]); 
     451      PImage img = p.loadImage(urls[0], "unknown"); 
     452      if (img != null) { 
     453        for (int i = 1; i < urls.length; i++) { 
     454          //          p.println("loading " + urls[i]); 
     455          PImage img2 = p.loadImage(urls[i], "unknown"); 
     456          if (img2 != null) { 
     457            img.blend(img2, 0, 0, img.width, img.height, 0, 0, img.width, img.height, BLEND); 
     458          } 
     459        } 
    348460      } 
    349461      tileDone(coord, img); 
     
    351463  } 
    352464 
     465  // TODO: there could be issues when this is called from within a thread 
     466  // probably needs synchronizing on images / pending / queue 
    353467  void tileDone(Coordinate coord, PImage img) { 
    354     images.put(coord, img); 
    355     pending.remove(coord);   
     468    // check if we're still waiting for this (new provider clears pending) 
     469    // also check if we got something 
     470    if (pending.containsKey(coord) && img != null) { 
     471      //      p.println("got " + coord + " image"); 
     472      images.put(coord, img); 
     473      pending.remove(coord);   
     474    } 
     475    else { 
     476      //      p.println("failed to get " + coord + " image"); 
     477      //      if (img == null) { 
     478      //        p.println("but got a null one"); 
     479      //      } 
     480      // try again? 
     481      // but this is a bit risky, TODO: keep track of attempts 
     482      queue.add(coord); 
     483      pending.remove(coord);   
     484    } 
    356485  } 
    357486 
     
    365494  } 
    366495 
    367   void mouseWheel(int delta) { 
    368     if (delta > 0) { 
    369       sc *= 1.05; 
    370     } 
    371     else if (delta < 0) { 
    372       sc *= 1.0/1.05;  
    373     } 
    374   } 
    375  
    376496  class QueueSorter implements Comparator { 
    377497    Coordinate center; 
    378     QueueSorter(Coordinate center) { 
     498    public void setCenter(Coordinate center) { 
    379499      this.center = center; 
    380500    }  
     
    384504      if (c1.zoom == center.zoom) { 
    385505        if (c2.zoom == center.zoom) { 
    386           float d1 = dist(center.column, center.row, c1.column, c1.row); 
    387           float d2 = dist(center.column, center.row, c2.column, c2.row); 
     506          float d1 = p.dist(center.column, center.row, c1.column, c1.row); 
     507          float d2 = p.dist(center.column, center.row, c2.column, c2.row); 
    388508          return d1 < d2 ? -1 : d1 > d2 ? 1 : 0; 
    389509        }  
     
    396516      } 
    397517      else { 
    398         float d1 = abs(c1.zoom - center.zoom); 
    399         float d2 = abs(c2.zoom - center.zoom); 
     518        float d1 = p.abs(c1.zoom - center.zoom); 
     519        float d2 = p.abs(c2.zoom - center.zoom); 
    400520        return  d1 < d2 ? -1 : d1 > d2 ? 1 : 0; 
    401521      } 
     
    403523  } 
    404524 
     525  class ZoomComparator implements Comparator { 
     526    public int compare(Object o1, Object o2) { 
     527      Coordinate c1 = (Coordinate)o1; 
     528      Coordinate c2 = (Coordinate)o2; 
     529      return c1.zoom < c2.zoom ? -1 : c1.zoom > c2.zoom ? 1 : 0; 
     530    } 
     531  } 
     532 
    405533} 
  • trunk/processing/sketches/modest_maps_interactive/modest_maps_interactive.pde

    r494 r495  
     1 
    12InteractiveMap map; 
    23 
     4ZoomButton in, out; 
     5PanButton up, down, left, right; 
     6Button[] buttons; 
     7 
    38void setup() { 
    4   size(screen.width/2, screen.height/2); 
    5 //  smooth(); // REALLY BAD IDEA 
    6   map = new InteractiveMap(); 
    7 //  map.setCenter(new Coordinate(3165, 1313, 13)); // oakland 
    8   map.setCenterZoom(new Location(37.784393009165576, -122.40649223327637), 18); // san francisco 
     9  size(screen.width, screen.height); 
     10  smooth(); 
     11 
     12  addMouseWheelListener(new java.awt.event.MouseWheelListener() {  
     13    public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {  
     14      mouseWheel(evt.getWheelRotation()); 
     15    } 
     16  });  
     17 
     18  map = new InteractiveMap(this, new Microsoft.HybridProvider(), width, height); 
     19 
     20  Location location = new Location(37.784, -122.406); // san francisco 
     21 
     22  map.setCenterZoom(location, 18);  
     23 
     24  out = new ZoomButton(5,5,14,14,false); 
     25  in = new ZoomButton(22,5,14,14,true); 
     26 
     27  up = new PanButton(14,25,14,14,UP); 
     28  down = new PanButton(14,57,14,14,DOWN); 
     29  left = new PanButton(5,41,14,14,LEFT); 
     30  right = new PanButton(22,41,14,14,RIGHT); 
     31 
     32  buttons = new Button[] {  
     33    in, out, up, down, left, right     }; 
     34 
    935} 
    1036 
    1137void draw() { 
    1238  background(0); 
    13   cursor(CROSS); 
     39 
    1440  map.draw(); 
     41 
     42  boolean hand = false; 
     43  for (int i = 0; i < buttons.length; i++) { 
     44    buttons[i].draw(); 
     45    hand = hand || buttons[i].mouseOver(); 
     46  } 
     47 
     48  cursor(hand ? HAND : CROSS); 
     49 
     50  if (keyPressed) { 
     51    if (key == CODED) { 
     52      if (keyCode == LEFT) { 
     53        map.tx += 5.0/map.sc; 
     54      } 
     55      else if (keyCode == RIGHT) { 
     56        map.tx -= 5.0/map.sc; 
     57      } 
     58      else if (keyCode == UP) { 
     59        map.ty += 5.0/map.sc; 
     60      } 
     61      else if (keyCode == DOWN) { 
     62        map.ty -= 5.0/map.sc; 
     63      } 
     64    }   
     65    else if (key == '+' || key == '=') { 
     66      map.sc *= 1.05; 
     67    } 
     68    else if (key == '_' || key == '-' && map.sc > 2) { 
     69      map.sc *= 1.0/1.05; 
     70    } 
     71    else if (key == 'z' || key == 'Z') { 
     72      map.sc = pow(2, map.getZoom()); 
     73    } 
     74    else if (key == ' ') { 
     75      map.sc = 2.0; 
     76      map.tx = -128; 
     77      map.ty = -128;  
     78    } 
     79  } 
     80 
     81  //  println(map.getCenter());   
     82  //  println(map.pointLocation(new Point2f(width/2, height/2))); 
     83 
    1584} 
    1685 
    1786void mouseDragged() { 
    18   map.mouseDragged();  
     87  boolean hand = false; 
     88  for (int i = 0; i < buttons.length; i++) { 
     89    hand = hand || buttons[i].mouseOver(); 
     90    if (hand) break; 
     91  } 
     92  if (!hand) { 
     93    map.mouseDragged();  
     94  } 
    1995} 
     96 
     97void mouseWheel(int delta) { 
     98  if (delta > 0) { 
     99    map.sc *= 1.05; 
     100  } 
     101  else if (delta < 0) { 
     102    map.sc *= 1.0/1.05;  
     103  } 
     104} 
     105 
     106void mouseClicked() { 
     107  if (in.mouseOver()) { 
     108    map.zoomIn(); 
     109  } 
     110  else if (out.mouseOver()) { 
     111    map.zoomOut(); 
     112  } 
     113  else if (up.mouseOver()) { 
     114    map.panUp(); 
     115  } 
     116  else if (down.mouseOver()) { 
     117    map.panDown(); 
     118  } 
     119  else if (left.mouseOver()) { 
     120    map.panLeft(); 
     121  } 
     122  else if (right.mouseOver()) { 
     123    map.panRight(); 
     124  } 
     125}