Changeset 495
- Timestamp:
- 02/18/08 15:24:04 (7 months ago)
- Files:
-
- trunk/processing/sketches/modest_maps_interactive/Button.pde (added)
- trunk/processing/sketches/modest_maps_interactive/InteractiveMap.java (moved) (moved from trunk/processing/sketches/modest_maps_interactive/InteractiveMap.pde) (18 diffs)
- trunk/processing/sketches/modest_maps_interactive/modest_maps_interactive.pde (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/processing/sketches/modest_maps_interactive/InteractiveMap.java
r494 r495 1 1 2 class InteractiveMap { 3 4 // pan, zoom and (eventually) rotate 5 double tx = 0, ty = 0; 2 import com.modestmaps.*; 3 import processing.core.*; 4 import java.util.*; 5 6 public 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 6 19 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; 8 30 9 31 // what kinda maps? 10 32 AbstractMapProvider provider; 11 33 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 15 44 Vector recentImages = new Vector(); 16 45 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; 19 59 20 60 // 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)); 33 62 34 63 } … … 36 65 void draw() { 37 66 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(); 39 73 40 74 // 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. 80 91 int zoom = bestZoomForScale((float)sc); 81 92 82 93 // 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: 89 101 float screenMinX = 0; 90 102 float screenMinY = 0; 91 103 float screenMaxX = width; 92 104 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 95 106 96 107 // 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)); 102 112 103 113 // 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); 108 124 109 125 // keep track of what we can see already: … … 118 134 119 135 // 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); 123 139 124 140 // keep this for later: … … 134 150 Coordinate zoomed = coord.zoomTo(i).container(); 135 151 // 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); 139 155 if (images.containsKey(zoomed)) { 140 156 visibleKeys.add(zoomed); … … 143 159 } 144 160 } 145 161 146 162 // or if we have any of the children 147 163 if (!gotParent) { 148 164 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() }; 150 167 for (int i = 0; i < kids.length; i++) { 151 168 zoomed = kids[i]; 152 169 // 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); 156 173 if (images.containsKey(zoomed)) { 157 174 visibleKeys.add(zoomed); … … 159 176 } 160 177 } 161 178 162 179 } 163 180 164 181 } // rows 165 182 } // columns 166 183 167 184 // 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); 175 186 176 187 if (visibleKeys.size() > 0) { 177 188 Coordinate previous = (Coordinate)visibleKeys.get(0); 178 p ushMatrix();189 p.pushMatrix(); 179 190 // 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)); 181 192 for (int i = 0; i < visibleKeys.size(); i++) { 182 193 Coordinate coord = (Coordinate)visibleKeys.get(i); 183 194 184 195 if (coord.zoom != previous.zoom) { 185 p opMatrix();186 p ushMatrix();196 p.popMatrix(); 197 p.pushMatrix(); 187 198 // 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)); 189 200 } 190 201 191 202 if (images.containsKey(coord)) { 192 203 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 // } 194 208 if (recentImages.contains(tile)) { 195 209 recentImages.remove(tile); … … 198 212 } 199 213 } 200 p opMatrix();214 p.popMatrix(); 201 215 } 202 216 203 p opMatrix();217 p.popMatrix(); 204 218 205 219 // println(pending.size() + " pending..."); … … 210 224 211 225 // 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)); 213 227 // println("center: " + center); 214 Collections.sort(queue, new QueueSorter(center));228 Collections.sort(queue, queueSorter); 215 229 216 230 // load up to 4 more things: … … 218 232 219 233 if (recentImages.size() > MAX_IMAGES_TO_KEEP) { 220 println(recentImages.size() + " images in memory, removing...");234 //println(recentImages.size() + " images in memory, removing..."); 221 235 recentImages.subList(0, recentImages.size()-MAX_IMAGES_TO_KEEP).clear(); 222 println(recentImages.size() + " images in memory");236 //println(recentImages.size() + " images in memory"); 223 237 images.values().retainAll(recentImages); 224 238 } 225 239 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(); 255 241 256 242 } … … 261 247 } 262 248 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() { 279 254 float row = (float)(ty*sc/-256.0); 280 255 float column = (float)(tx*sc/-256.0); … … 283 258 } 284 259 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 285 275 /** sets scale according to given zoom level, should leave you with pixel perfect tiles */ 286 276 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); 288 282 } 289 283 290 284 void zoomIn() { 291 sc = p ow(2.0, getZoom()+1);285 sc = p.pow(2.0f, getZoom()+1); 292 286 } 293 287 294 288 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 /////////////////////////////////////////////////////////////////////// 297 406 298 407 float scaleForZoom(int zoom) { 299 return p ow(2.0, zoom);408 return p.pow(2.0f, zoom); 300 409 } 301 410 302 411 float zoomForScale(float scale) { 303 return log(scale) /log(2);412 return p.log(scale) / p.log(2); 304 413 } 305 414 306 415 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 ////////////////////////////////////////////////////////////////////////// 309 420 310 421 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; 313 424 // float angle = radians(-a); 314 425 // float rx = cos(angle)*dx - sin(angle)*dy; … … 320 431 } 321 432 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 ///////////////////////////////////////////////////////////////// 328 434 329 435 void grabTile(Coordinate coord) { … … 340 446 } 341 447 public void run() { 448 p.println("loading " + coord); 342 449 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 } 348 460 } 349 461 tileDone(coord, img); … … 351 463 } 352 464 465 // TODO: there could be issues when this is called from within a thread 466 // probably needs synchronizing on images / pending / queue 353 467 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 } 356 485 } 357 486 … … 365 494 } 366 495 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 376 496 class QueueSorter implements Comparator { 377 497 Coordinate center; 378 QueueSorter(Coordinate center) {498 public void setCenter(Coordinate center) { 379 499 this.center = center; 380 500 } … … 384 504 if (c1.zoom == center.zoom) { 385 505 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); 388 508 return d1 < d2 ? -1 : d1 > d2 ? 1 : 0; 389 509 } … … 396 516 } 397 517 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); 400 520 return d1 < d2 ? -1 : d1 > d2 ? 1 : 0; 401 521 } … … 403 523 } 404 524 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 405 533 } trunk/processing/sketches/modest_maps_interactive/modest_maps_interactive.pde
r494 r495 1 1 2 InteractiveMap map; 2 3 4 ZoomButton in, out; 5 PanButton up, down, left, right; 6 Button[] buttons; 7 3 8 void 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 9 35 } 10 36 11 37 void draw() { 12 38 background(0); 13 cursor(CROSS); 39 14 40 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 15 84 } 16 85 17 86 void 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 } 19 95 } 96 97 void 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 106 void 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 }
