Understand shapefiles in different projections (notably OSGB)
[potlatch2.git] / com / gradoservice / proj4as / ProjProjection.as
1 package com.gradoservice.proj4as
2 {
3         import com.gradoservice.proj4as.proj.*;
4         
5         public class ProjProjection
6         {
7         /**
8            * Property: readyToUse
9            * Flag to indicate if initialization is complete for this Proj object
10            */
11           public var readyToUse:Boolean = false;   
12           
13           /**
14            * Property: title
15            * The title to describe the projection
16            */
17          protected var projParams:ProjParams = new ProjParams();
18           
19          static public const defs:Object = {
20                         'EPSG:900913': "+title=Google Mercator EPSG:900913 +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs",
21                         'WGS84': "+title=long/lat:WGS84 +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees",
22                         'EPSG:4326': "+title=long/lat:WGS84 +proj=longlat +a=6378137.0 +b=6356752.31424518 +ellps=WGS84 +datum=WGS84 +units=degrees",
23                         'EPSG:4269': "+title=long/lat:NAD83 +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees",                   
24                         'EPSG:32639': "+title=WGS 84 / UTM zone 39N +proj=utm +zone=39 +ellps=WGS84 +datum=WGS84 +units=m +no_defs",
25                         'EPSG:27700': "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs"
26                 }
27                          
28
29           
30           protected var proj:IProjection;       
31           
32                 public function get srsCode():String
33                 {
34                         return projParams.srsCode;
35                 }
36                 
37                 public function get srsProjNumber():String
38                 {
39                         return projParams.srsProjNumber;
40                 }
41                 
42                 public function get projName():String
43                 {
44                         return projParams.projName;
45                 }               
46                 
47                 public function get datum():Datum
48                 {
49                         return projParams.datum;                
50                 }
51                 
52                 public function get datumCode():String
53                 {
54                         return projParams.datumCode;            
55                 }       
56                 
57                 public function get from_greenwich():Number
58                 {
59                         return projParams.from_greenwich;               
60                 }
61                 
62                 public function get to_meter():Number
63                 {
64                         return projParams.to_meter;             
65                 }
66                 
67                 public function get a():Number
68                 {
69                         return projParams.a;            
70                 }
71                 
72                 public function get b():Number
73                 {
74                         return projParams.b;            
75                 }
76                 
77                 public function get ep2():Number
78                 {
79                         return projParams.ep2;                  
80                 }
81                 
82                 public function get es():Number
83                 {
84                         return projParams.es;           
85                 }                               
86                 
87                 public function get datum_params():Array
88                 {
89                         return projParams.datum_params;                 
90                 }                                                                                       
91                 
92                 public function ProjProjection(srsCode:String)
93                 {
94                         this.projParams.srsCode = srsCode.toUpperCase();
95                         
96                       if (this.projParams.srsCode.indexOf("EPSG") == 0) {
97                           this.projParams.srsAuth = 'epsg';
98                           this.projParams.srsProjNumber = this.projParams.srsCode.substring(5);
99                       // DGR 2007-11-20 : authority IGNF
100                       } else if (this.projParams.srsCode.indexOf("IGNF") == 0) {
101                           this.projParams.srsAuth = 'IGNF';
102                           this.projParams.srsProjNumber = this.projParams.srsCode.substring(5);
103                       // DGR 2008-06-19 : pseudo-authority CRS for WMS
104                       } else if (this.projParams.srsCode.indexOf("CRS") == 0) {
105                           this.projParams.srsAuth = 'CRS';
106                           this.projParams.srsProjNumber = this.projParams.srsCode.substring(4);
107                       } else {
108                           this.projParams.srsAuth = '';
109                           this.projParams.srsProjNumber = this.projParams.srsCode;
110                       }
111                       this.loadProjDefinition();                                
112                 }
113                 
114                 private function loadProjDefinition():void
115                 {                       
116                         if (this.srsCode!=null && ProjProjection.defs[this.srsCode]!=null)
117                         {
118                                 this.parseDef(ProjProjection.defs[this.projParams.srsCode]);
119                                 this.initTransforms();
120                         }
121                 }
122                 
123                 protected function initTransforms():void 
124                         {
125                         switch (this.projParams.projName)
126                         {
127                                 case "aea": this.proj = new ProjAea(this.projParams); break;
128                                 case "aeqd": this.proj = new ProjAeqd(this.projParams); break;                          
129                                 case "eqc": this.proj = new ProjEqc(this.projParams); break;                            
130                                 case "eqdc": this.proj = new ProjEqdc(this.projParams); break;                          
131                                 case "equi": this.proj = new ProjEqui(this.projParams); break;                          
132                                 case "gauss": this.proj = new ProjGauss(this.projParams); break;                                
133                                 case "gstmerc": this.proj = new ProjGstmerc(this.projParams); break;                            
134                                 case "laea": this.proj = new ProjLaea(this.projParams); break;                          
135                                 case "lcc": this.proj = new ProjLcc(this.projParams); break;                            
136                                 case "longlat": this.proj = new ProjLonglat(this.projParams); break;                            
137                                 case "merc": this.proj = new ProjMerc(this.projParams); break;                          
138                                 case "mill": this.proj = new ProjMill(this.projParams); break;                          
139                                 case "moll": this.proj = new ProjMoll(this.projParams); break;                          
140                                 case "nzmg": this.proj = new ProjNzmg(this.projParams); break;                          
141                                 case "omerc": this.proj = new ProjOmerc(this.projParams); break;                                
142                                 case "ortho": this.proj = new ProjOrtho(this.projParams); break;                                
143                                 case "sinu": this.proj = new ProjSinu(this.projParams); break;                          
144                                 case "omerc": this.proj = new ProjOmerc(this.projParams); break;                                
145                                 case "stere": this.proj = new ProjStere(this.projParams); break;                                
146                                 case "sterea": this.proj = new ProjSterea(this.projParams); break;                              
147                                 case "tmerc": this.proj = new ProjTmerc(this.projParams); break;                                
148                                 case "utm": this.proj = new ProjUtm(this.projParams); break;
149                                 case "vandg": this.proj = new ProjVandg(this.projParams); break;                                
150                         }
151                         if (this.proj!=null) {
152                                 this.proj.init();
153                                 this.readyToUse = true;                         
154                         }
155                         }
156                                 
157                 private function parseDef(definition:String):void
158                 {
159                 var paramName:String = '';
160                 var paramVal:String = '';
161                 var paramArray:Array=definition.split("+");
162                         for (var prop:int=0; prop<paramArray.length; prop++) {
163                                   var property:Array = paramArray[prop].split("=");
164                                   paramName = property[0].toLowerCase();
165                                   paramVal = property[1];
166                         
167                                   switch (paramName.replace(/\s/gi,"")) {  // trim out spaces
168                                       case "": break;   // throw away nameless parameter
169                                       case "title":  this.projParams.title = paramVal; break;
170                                       case "proj":   this.projParams.projName =  paramVal.replace(/\s/gi,""); break;
171                                       case "units":  this.projParams.units = paramVal.replace(/\s/gi,""); break;
172                                       case "datum":  this.projParams.datumCode = paramVal.replace(/\s/gi,""); break;
173                                       case "nadgrids": this.projParams.nagrids = paramVal.replace(/\s/gi,""); break;
174                                       case "ellps":  this.projParams.ellps = paramVal.replace(/\s/gi,""); break;
175                                       case "a":      this.projParams.a =  parseFloat(paramVal); break;  // semi-major radius
176                                       case "b":      this.projParams.b =  parseFloat(paramVal); break;  // semi-minor radius
177                                       // DGR 2007-11-20
178                                       case "rf":     this.projParams.rf = parseFloat(paramVal); break; // inverse flattening rf= a/(a-b)
179                                       case "lat_0":  this.projParams.lat0 = parseFloat(paramVal)*ProjConstants.D2R; break;        // phi0, central latitude
180                                       case "lat_1":  this.projParams.lat1 = parseFloat(paramVal)*ProjConstants.D2R; break;        //standard parallel 1
181                                       case "lat_2":  this.projParams.lat2 = parseFloat(paramVal)*ProjConstants.D2R; break;        //standard parallel 2
182                                       case "lat_ts": this.projParams.lat_ts = parseFloat(paramVal)*ProjConstants.D2R; break;      // used in merc and eqc
183                                       case "lon_0":  this.projParams.long0 = parseFloat(paramVal)*ProjConstants.D2R; break;       // lam0, central longitude
184                                       case "alpha":  this.projParams.alpha =  parseFloat(paramVal)*ProjConstants.D2R; break;  //for somerc projection
185                                       case "lonc":   this.projParams.longc = parseFloat(paramVal)*ProjConstants.D2R; break;       //for somerc projection
186                                       case "x_0":    this.projParams.x0 = parseFloat(paramVal); break;  // false easting
187                                       case "y_0":    this.projParams.y0 = parseFloat(paramVal); break;  // false northing
188                                       case "k_0":    this.projParams.k0 = parseFloat(paramVal); break;  // projection scale factor
189                                       case "k":      this.projParams.k0 = parseFloat(paramVal); break;  // both forms returned
190                                       case "R_A":    this.projParams.R_A = true; break;   //Spheroid radius 
191                                       case "zone":   this.projParams.zone = parseInt(paramVal); break;  // UTM Zone
192                                       case "south":   this.projParams.utmSouth = true; break;  // UTM north/south
193                                       case "towgs84":this.projParams.datum_params = paramVal.split(","); break;
194                                       case "to_meter": this.projParams.to_meter = parseFloat(paramVal); break; // cartesian scaling
195                                       case "from_greenwich": this.projParams.from_greenwich = parseFloat(paramVal)*ProjConstants.D2R; break;
196                                       // DGR 2008-07-09 : if pm is not a well-known prime meridian take
197                                       // the value instead of 0.0, then convert to radians
198                                       case "pm":     paramVal = paramVal.replace(/\s/gi,"");
199                                                      this.projParams.from_greenwich = ProjConstants.PrimeMeridian[paramVal] ?
200                                                         ProjConstants.PrimeMeridian[paramVal] : parseFloat(paramVal);
201                                                      this.projParams.from_greenwich *= ProjConstants.D2R; 
202                                                      break;
203                                       case "no_defs": break; 
204                                       default: trace("Unrecognized parameter: " + paramName); break;
205                                   } // switch()
206                               } // for paramArray
207                               this.deriveConstants();
208
209                 }
210                 
211                 private function deriveConstants():void 
212                 {
213                 if (this.projParams.nagrids == '@null') this.projParams.datumCode = 'none';
214                 if (this.projParams.datumCode && this.projParams.datumCode != 'none') 
215                 {
216                 var datumDef:Object = ProjConstants.Datum[this.projParams.datumCode];
217                 if (datumDef) 
218                         {
219                         this.projParams.datum_params = datumDef.towgs84.split(',');
220                         this.projParams.ellps = datumDef.ellipse;
221                         this.projParams.datumName = datumDef.datumName ? datumDef.datumName : this.projParams.datumCode;
222                         }
223                 }
224       
225               if (!this.projParams.a) {    // do we have an ellipsoid?
226                   var ellipse:Object = ProjConstants.Ellipsoid[this.projParams.ellps] ? ProjConstants.Ellipsoid[this.projParams.ellps] : ProjConstants.Ellipsoid['WGS84'];
227                   extend(this.projParams, ellipse);
228               }
229               if (this.projParams.rf && !this.projParams.b) this.projParams.b = (1.0 - 1.0/this.projParams.rf) * this.projParams.a;
230               if (Math.abs(this.projParams.a - this.projParams.b)<ProjConstants.EPSLN) {
231                 this.projParams.sphere = true;
232                 this.projParams.b= this.projParams.a;
233               }
234               this.projParams.a2 = this.projParams.a * this.projParams.a;          // used in geocentric
235               this.projParams.b2 = this.projParams.b * this.projParams.b;          // used in geocentric
236               this.projParams.es = (this.projParams.a2-this.projParams.b2)/this.projParams.a2;  // e ^ 2
237               this.projParams.e = Math.sqrt(this.projParams.es);        // eccentricity
238               if (this.projParams.R_A) {
239                 this.projParams.a *= 1. - this.projParams.es * (ProjConstants.SIXTH + this.projParams.es * (ProjConstants.RA4 + this.projParams.es * ProjConstants.RA6));
240                 this.projParams.a2 = this.projParams.a * this.projParams.a;
241                 this.projParams.b2 = this.projParams.b * this.projParams.b;
242                 this.projParams.es = 0.;
243               }
244               this.projParams.ep2=(this.projParams.a2-this.projParams.b2)/this.projParams.b2; // used in geocentric
245               if (!this.projParams.k0) this.projParams.k0 = 1.0;    //default value
246         
247               this.projParams.datum = new Datum(this);
248                 }
249
250                 private function extend(destination:Object, source:Object):void 
251                 {
252               destination = destination || {};
253               if(source) {
254                   for(var property:String in source) {
255                       var value:Object = source[property];
256                       if(value != null) {
257                           destination[property] = value;
258                       }
259                   }
260               }
261             }
262             
263                 public function forward(p:ProjPoint):ProjPoint
264                         {
265                         if (this.proj!=null)
266                                 {                                       
267                                 return this.proj.forward(p);
268                                 }
269                         return p;
270                         }
271                 
272                 public function inverse(p:ProjPoint):ProjPoint
273                         {
274                         if (this.proj!=null)
275                                 {                                       
276                                 return this.proj.inverse(p);
277                                 }
278                         return p;
279                         }                       
280
281         }
282 }