/src/com/google/maps/extras/arcgislink/ArcGISTileConfig.as
ActionScript | 209 lines | 100 code | 24 blank | 85 comment | 18 complexity | 6e6ce677a3bd712c9a9de57160b2973f MD5 | raw file
1/* 2 * ArcGIS for Google Maps Flash API 3 * 4 * License http://www.apache.org/licenses/LICENSE-2.0 5 */ 6 /** 7 * @author nianwei at gmail dot com 8 */ 9 10package com.google.maps.extras.arcgislink { 11 import com.google.maps.*; 12 import com.google.maps.interfaces.*; 13 14 import flash.geom.Point; 15 16 /** 17 * This class is a bridge between Google's projection and ArcGIS's spatial reference system. 18 */ 19 public class ArcGISTileConfig extends ProjectionBase { 20 private var tileInfo_:*; 21 private var spatialReference_:SpatialReference; 22 internal var zoomOffset_:int; //used in TileLayer 23 private var fullExtent_:*; 24 25 26 public function ArcGISTileConfig( /*TileInfo*/ tileInfo:*, /*Envelope*/ opt_fullExtent:*=null) { 27 super(); 28 if (!tileInfo) { 29 throw new Error('map service is not tiled'); 30 } 31 this.tileInfo_=tileInfo; 32 this.spatialReference_=SpatialReferences.getSpatialReference(tileInfo.spatialReference.wkid); 33 if (!this.spatialReference_) { 34 throw new Error('unsupported Spatial Reference: ' + tileInfo.spatialReference.wkid); 35 } 36 this.zoomOffset_=Math.floor(Math.log(this.spatialReference_.getCircumference() / this.tileInfo_.lods[0].resolution / 256) / Math.LN2 + 0.5); 37 this.fullExtent_=opt_fullExtent; 38 39 40 } 41 42 43 44 /** 45 * See <a href = 'http://code.google.com/apis/maps/documentation/reference.html#GProjection'>GProjection</a>. 46 * @param {GLatLng} gLatLng 47 * @param {Number} zoom 48 * @return {GPoint} pixel 49 */ 50 override public function fromLatLngToPixel(gLatLng:LatLng, zoom:Number):flash.geom.Point { 51 if (!gLatLng || isNaN(gLatLng.lat()) || isNaN(gLatLng.lng())) { 52 return null; 53 } 54 var coords:Array=this.spatialReference_.forward([gLatLng.lng(), gLatLng.lat()]); 55 var zoomIdx:int=zoom - this.zoomOffset_; 56 var res:Number=this.getUnitsPerPixel(zoom); 57 //!!!! must NOT round to integer, even it is fine in JS version, Flex version 58 // will cause HUGE shift! 59 var px:Number=(coords[0] - (this.tileInfo_.origin.x as Number)) / res; 60 var py:Number=((this.tileInfo_.origin.y as Number) - coords[1]) / res; 61 62 return new Point(px, py); 63 } 64 65 /** 66 * Get resolution (Units per Pixel) at given zoom level. 67 * @param {Number} zoom 68 * @return Number 69 */ 70 public function getUnitsPerPixel(zoom:int):Number { 71 var zoomIdx:int=zoom - this.zoomOffset_; 72 var res:Number=Number.MAX_VALUE; 73 var factor:Number = 1; 74 if (zoomIdx <0){ 75 // trace('invalid zoom: ' +zoom); 76 factor = Math.pow(2, -zoomIdx); 77 res=this.tileInfo_.lods[0].resolution * factor; 78 79 } else if (zoomIdx > this.tileInfo_.lods.length-1){ 80 // trace('invalid zoom: ' +zoom); 81 factor=Math.pow(2, zoom - this.maxResolution()); 82 res=this.tileInfo_.lods[this.tileInfo_.lods.length - 1].resolution / factor; 83 84 } else { 85 res=this.tileInfo_.lods[zoomIdx].resolution; 86 } 87 return res; 88 } 89 90 /** 91 * Get the scale at given level; 92 * @param {Number} zoom 93 * @return {Number} 94 95 public function getScale(zoom:int):Number { 96 var zoomIdx:int=zoom - this.zoomOffset_; 97 var res:Number=0; 98 if (this.tileInfo_.lods[zoomIdx]) { 99 res=this.tileInfo_.lods[zoomIdx].scale; 100 } else { 101 //this is a special case when the maxZoom is set larger than what's actually defined in the tiling scheme. 102 // the goal is to allow map continue to zoom to extremely detail level by using ArcGISMapOverlay. 103 var factor:Number=Math.pow(2, zoom - this.maxResolution()); 104 res=this.tileInfo_.lods[this.tileInfo_.lods.length - 1].scale / factor; 105 } 106 return res; 107 } 108 */ 109 /** 110 * See <a href = 'http://code.google.com/apis/maps/documentation/reference.html#GProjection'>GProjection</a>. 111 * @param {GPoint} pixel 112 * @param {Number} zoom 113 * @param {Boolean} unbound 114 * @return {GLatLng} gLatLng 115 */ 116 override public function fromPixelToLatLng(pixel:flash.geom.Point, zoom:Number, unbound:Boolean=false):LatLng { 117 if (pixel === null) { 118 return null; 119 } 120 var zoomIdx:int=zoom - this.zoomOffset_; 121 var res:Number=this.getUnitsPerPixel(zoom); 122 var x:Number=pixel.x * res + (this.tileInfo_.origin.x as Number); 123 var y:Number=(this.tileInfo_.origin.y as Number)- pixel.y * res; 124 var ll:Array=this.spatialReference_.reverse([x, y]); 125 return new LatLng(ll[1], ll[0]); 126 } 127 128 /** 129 * See <a href = 'http://code.google.com/apis/maps/documentation/reference.html#GProjection'>GProjection</a>. 130 * @param {Object} tile 131 * @param {Number} zoom 132 * @param {Number} tilesize 133 */ 134 override public function tileCheckRange(tile:flash.geom.Point, zoom:Number, tilesize:Number):Boolean { 135 var zoomIdx:Number=zoom - this.zoomOffset_; 136 if (this.tileInfo_.lods[zoomIdx]) { 137 var b:*=this.fullExtent_; 138 if (!b) { 139 return true; 140 } 141 var minX:Number=tile.x * tilesize * this.tileInfo_.lods[zoomIdx].resolution + this.tileInfo_.origin.x; 142 var minY:Number=this.tileInfo_.origin.y - (tile.y + 1) * tilesize * this.tileInfo_.lods[zoomIdx].resolution; 143 var maxX:Number=(tile.x + 1) * tilesize * this.tileInfo_.lods[zoomIdx].resolution + this.tileInfo_.origin.x; 144 var maxY:Number=this.tileInfo_.origin.y - tile.y * tilesize * this.tileInfo_.lods[zoomIdx].resolution; 145 var ret:Boolean=!(b.xmin > maxX || b.xmax < minX || b.ymax < minY || b.ymin > maxY); 146 return ret; 147 } else { 148 return false; 149 } 150 } 151 152 /** 153 * See <a href = 'http://code.google.com/apis/maps/documentation/reference.html#GProjection'>GProjection</a>. 154 * @param {Number} zoom 155 * @return {Number} numOfpixel 156 */ 157 override public function getWrapWidth(zoom:Number):Number { 158 var zoomIdx:Number=zoom - this.zoomOffset_; 159 if (this.tileInfo_.lods[zoomIdx]) { 160 return this.spatialReference_.getCircumference() / this.tileInfo_.lods[zoomIdx].resolution; 161 } else { 162 return Number.MAX_VALUE; 163 } 164 } 165 166 /** 167 * Get the tile size used by this Projection. Shortcut to tileInfo.rows; 168 * @return {Number} 169 */ 170 public function getTileSize():Number { 171 return this.tileInfo_.rows; 172 } 173 174 /** 175 * Get min zoom level of actual tiles 176 * @return {Number} 177 */ 178 public function minResolution():Number { 179 return this.zoomOffset_; 180 } 181 182 /** 183 * Get max zoom level of actual tiles 184 * @return {Number} 185 */ 186 public function maxResolution():Number { 187 return this.zoomOffset_ + this.tileInfo_.lods.length - 1; 188 } 189 190 /** 191 * Get the underline {@link ArcGISSpatialReference} 192 * @return {ArcGISSpatialReference} 193 */ 194 public function getSpatialReference():SpatialReference { 195 return this.spatialReference_; 196 } 197 198 /** 199 *tile configuration used by Google Maps 200 */ 201 public static const GOOGLE_MAPS:ArcGISTileConfig=new ArcGISTileConfig({"rows": 256, "cols": 256, "dpi": 96, "format": "PNG8", "compressionQuality": 0, "origin": {"x": -20037508.342787, "y": 20037508.342787}, "spatialReference": {"wkid": 102113}, "lods": [{"level": 0, "resolution": 156543.033928, "scale": 591657527.591555}, {"level": 1, "resolution": 78271.5169639999, "scale": 295828763.795777}, {"level": 2, "resolution": 39135.7584820001, "scale": 147914381.897889}, {"level": 3, "resolution": 19567.8792409999, "scale": 73957190.948944}, {"level": 4, "resolution": 9783.93962049996, "scale": 36978595.474472}, {"level": 5, "resolution": 4891.96981024998, "scale": 18489297.737236}, {"level": 6, "resolution": 2445.98490512499, "scale": 9244648.868618}, {"level": 7, "resolution": 1222.99245256249, "scale": 4622324.434309}, {"level": 8, "resolution": 611.49622628138, "scale": 2311162.217155}, {"level": 9, "resolution": 305.748113140558, "scale": 1155581.108577}, {"level": 10, "resolution": 152.874056570411, "scale": 577790.554289}, {"level": 11, "resolution": 76.4370282850732, "scale": 288895.277144}, {"level": 12, "resolution": 38.2185141425366, "scale": 144447.638572}, {"level": 13, "resolution": 19.1092570712683, "scale": 72223.819286}, {"level": 14, "resolution": 9.55462853563415, "scale": 36111.909643}, {"level": 15, "resolution": 4.77731426794937, "scale": 18055.954822}, {"level": 16, "resolution": 2.38865713397468, "scale": 9027.977411}, {"level": 17, "resolution": 1.19432856685505, "scale": 4513.988705}, {"level": 18, "resolution": 0.597164283559817, "scale": 2256.994353}, {"level": 19, "resolution": 0.298582141647617, "scale": 1128.497176}]}, null); 202 /** 203 *tile configuration used by ArcGIS online 204 */ 205 public static const ARCGIS_ONLINE:ArcGISTileConfig=new ArcGISTileConfig({"rows": 512, "cols": 512, "dpi": 96, "origin": {"x": -180, "y": 90}, "spatialReference": {"wkid": 4326}, "lods": [{"level": 0, "resolution": 0.351562499999999, "scale": 147748799.285417}, {"level": 1, "resolution": 0.17578125, "scale": 73874399.6427087}, {"level": 2, "resolution": 0.0878906250000001, "scale": 36937199.8213544}, {"level": 3, "resolution": 0.0439453125, "scale": 18468599.9106772}, {"level": 4, "resolution": 0.02197265625, "scale": 9234299.95533859}, {"level": 5, "resolution": 0.010986328125, "scale": 4617149.97766929}, {"level": 6, "resolution": 0.0054931640625, "scale": 2308574.98883465}, {"level": 7, "resolution": 0.00274658203124999, "scale": 1154287.49441732}, {"level": 8, "resolution": 0.001373291015625, "scale": 577143.747208662}, {"level": 9, "resolution": 0.0006866455078125, "scale": 288571.873604331}, {"level": 10, "resolution": 0.000343322753906249, "scale": 144285.936802165}, {"level": 11, "resolution": 0.000171661376953125, "scale": 72142.9684010827}, {"level": 12, "resolution": 8.58306884765626E-05, "scale": 36071.4842005414}, {"level": 13, "resolution": 4.29153442382813E-05, "scale": 18035.7421002707}, {"level": 14, "resolution": 2.14576721191406E-05, "scale": 9017.87105013534}, {"level": 15, "resolution": 1.07288360595703E-05, "scale": 4508.93552506767}]}); 206 207 208 } 209}