srsCodeInput = $srsCode; //check to see if $this is a WKT string if( (strpos( $srsCode, 'GEOGCS' ) !== false) || (strpos( $srsCode, 'GEOCCS' ) !== false) || (strpos( $srsCode, 'PROJCS' ) !== false) || (strpos( $srsCode, 'LOCAL_CS' ) !== false) ) { $this->parseWKT( $srsCode ); $this->deriveConstants(); $this->loadProjCode( $this->projName ); return; } // DGR 2008-08-03 : support urn and url if( strpos( $srsCode, 'urn:' ) === 0 ) { //urn:ORIGINATOR:def:crs:CODESPACE:VERSION:ID $urn = explode( ':', $srsCode ); if( ($urn[1] == 'ogc' || $urn[1] == 'x-ogc') && ($urn[2] == 'def') && ($urn[3] == 'crs') ) { $srsCode = $urn[4] . ':' . $urn[strlen( $urn ) - 1]; } } else if( strpos( $srsCode, 'http://' ) === 0 ) { //url#ID $url = explode( '#', $srsCode ); if( preg_match( "/epsg.org/", $url[0] ) ) { // http://www.epsg.org/# $srsCode = 'EPSG:' . $url[1]; } else if( preg_match( "/RIG.xml/", $url[0] ) ) { //http://librairies.ign.fr/geoportail/resources/RIG.xml# //http://interop.ign.fr/registers/ign/RIG.xml# $srsCode = 'IGNF:' . $url[1]; } } $this->srsCode = strtoupper( $srsCode ); if( strpos( $this->srsCode, "EPSG" ) === 0 ) { $this->srsCode = $this->srsCode; $this->srsAuth = 'epsg'; $this->srsProjNumber = substr( $this->srsCode, 5 ); // DGR 2007-11-20 : authority IGNF } else if( strpos( $this->srsCode, "IGNF" ) === 0 ) { $this->srsCode = $this->srsCode; $this->srsAuth = 'IGNF'; $this->srsProjNumber = substr( $this->srsCode, 5 ); // DGR 2008-06-19 : pseudo-authority CRS for WMS } else if( strpos( $this->srsCode, "CRS" ) === 0 ) { $this->srsCode = $this->srsCode; $this->srsAuth = 'CRS'; $this->srsProjNumber = substr( $this->srsCode, 4 ); } else { $this->srsAuth = ''; $this->srsProjNumber = $this->srsCode; } $this->loadProjDefinition(); } /** * Function: loadProjDefinition * Loads the coordinate system initialization string if required. * Note that dynamic loading happens asynchronously so an application must * wait for the readyToUse property is set to true. * To prevent dynamic loading, include the defs through a script tag in * your application. * */ public function loadProjDefinition() { //check in memory if( array_key_exists( $this->srsCode, Proj4php::$defs ) ) { $this->defsLoaded(); return; } //else check for def on the server $filename = dirname( __FILE__ ) . '/defs/' . strtoupper( $this->srsAuth ) . $this->srsProjNumber . '.php'; try { Proj4php::loadScript( $filename ); $this->defsLoaded(); // succes } catch ( Exception $e ) { $this->loadFromService(); // fail } } /** * Function: loadFromService * Creates the REST URL for loading the definition from a web service and * loads it. * * * DO IT AGAIN. : SHOULD PHP CODE BE GET BY WEBSERVICES ? */ public function loadFromService() { //else load from web service $url = Proj4php::$defsLookupService . '/' . $this->srsAuth . '/' . $this->srsProjNumber . '/proj4/'; try { Proj4php::$defs[strtoupper($this->srsAuth) . ":" . $this->srsProjNumber] = Proj4php::loadScript( $url ); } catch ( Exception $e ) { $this->defsFailed(); } } /** * Function: defsLoaded * Continues the Proj object initilization once the def file is loaded * */ public function defsLoaded() { $this->parseDefs(); $this->loadProjCode( $this->projName ); } /** * Function: checkDefsLoaded * $this is the loadCheck method to see if the def object exists * */ public function checkDefsLoaded() { return isset(Proj4php::$defs[$this->srsCode]) && !empty(Proj4php::$defs[$this->srsCode]); } /** * Function: defsFailed * Report an error in loading the defs file, but continue on using WGS84 * */ public function defsFailed() { Proj4php::reportError( 'failed to load projection definition for: ' . $this->srsCode ); Proj4php::$defs[$this->srsCode] = Proj4php::$defs['WGS84']; //set it to something so it can at least continue $this->defsLoaded(); } /** * Function: loadProjCode * Loads projection class code dynamically if required. * Projection code may be included either through a script tag or in * a built version of proj4php * * An exception occurs if the projection is not found. */ public function loadProjCode( $projName ) { if( array_key_exists( $projName, Proj4php::$proj ) ) { $this->initTransforms(); return; } //the filename for the projection code $filename = dirname( __FILE__ ) . '/projCode/' . $projName . '.php'; try { Proj4php::loadScript( $filename ); $this->loadProjCodeSuccess( $projName ); } catch ( Exception $e ) { $this->loadProjCodeFailure( $projName ); } } /** * Function: loadProjCodeSuccess * Loads any proj dependencies or continue on to final initialization. * */ public function loadProjCodeSuccess( $projName ) { if( isset(Proj4php::$proj[$projName]->dependsOn) && !empty(Proj4php::$proj[$projName]->dependsOn)) { $this->loadProjCode( Proj4php::$proj[$projName]->dependsOn ); } else { $this->initTransforms(); } } /** * Function: defsFailed * Report an error in loading the proj file. Initialization of the Proj * object has failed and the readyToUse flag will never be set. * */ public function loadProjCodeFailure( $projName ) { Proj4php::reportError( "failed to find projection file for: " . $projName ); //TBD initialize with identity transforms so proj will still work? } /** * Function: checkCodeLoaded * $this is the loadCheck method to see if the projection code is loaded * */ public function checkCodeLoaded( $projName ) { return isset(Proj4php::$proj[$projName]) && !empty(Proj4php::$proj[$projName]); } /** * Function: initTransforms * Finalize the initialization of the Proj object * */ public function initTransforms() { $this->projection = clone(Proj4php::$proj[$this->projName]); Proj4php::extend( $this->projection, $this ); $this->init(); // initiate depending class if( false !== ($dependsOn = isset($this->projection->dependsOn) && !empty($this->projection->dependsOn) ? $this->projection->dependsOn : false) ) { Proj4php::extend( Proj4php::$proj[$dependsOn], $this->projection) && Proj4php::$proj[$dependsOn]->init() && Proj4php::extend( $this->projection, Proj4php::$proj[$dependsOn] ); } $this->readyToUse = true; } /** * */ public function init() { $this->projection->init(); } /** * * @param type $pt * @return type */ public function forward( $pt ) { return $this->projection->forward( $pt ); } /** * * @param type $pt * @return type */ public function inverse( $pt ) { return $this->projection->inverse( $pt ); } /** * Function: parseWKT * Parses a WKT string to get initialization parameters * */ public function parseWKT( $wkt ) { if( false === ($match = preg_match( $this->wktRE, $wkt, $wktMatch )) ) return; $wktObject = $wktMatch[1]; $wktContent = $wktMatch[2]; $wktTemp = explode( ",", $wktContent ); $wktName = (strtoupper($wktObject) == "TOWGS84") ? "TOWGS84" : array_shift( $wktTemp ); $wktName = preg_replace( '/^\"/', "", $wktName ); $wktName = preg_replace( '/\"$/', "", $wktName ); /* $wktContent = implode(",",$wktTemp); $wktArray = explode("],",$wktContent); for ($i=0; iprojName = 'identity'; $this->localCS = true; $this->srsCode = $wktName; break; case 'GEOGCS': $this->projName = 'longlat'; $this->geocsCode = $wktName; if( !$this->srsCode ) $this->srsCode = $wktName; break; case 'PROJCS': $$this->srsCode = $wktName; break; case 'GEOCCS': break; case 'PROJECTION': $this->projName = Proj4php::$wktProjections[$wktName]; break; case 'DATUM': $this->datumName = $wktName; break; case 'LOCAL_DATUM': $this->datumCode = 'none'; break; case 'SPHEROID': $this->ellps = $wktName; $this->a = floatval( array_shift( $wktArray ) ); $this->rf = floatval( array_shift( $wktArray ) ); break; case 'PRIMEM': $this->from_greenwich = floatval( array_shift( $wktArray ) ); //to radians? break; case 'UNIT': $this->units = $wktName; $this->unitsPerMeter = floatval( array_shift( $wktArray ) ); break; case 'PARAMETER': $name = strtolower( $wktName ); $value = floatval( array_shift( $wktArray ) ); //there may be many variations on the wktName values, add in case //statements as required switch( $name ) { case 'false_easting': $this->x0 = $value; break; case 'false_northing': $this->y0 = $value; break; case 'scale_factor': $this->k0 = $value; break; case 'central_meridian': $this->long0 = $value * Proj4php::$common->D2R; break; case 'latitude_of_origin': $this->lat0 = $value * Proj4php::$common->D2R; break; case 'more_here': break; default: break; } break; case 'TOWGS84': $this->datum_params = $wktArray; break; //DGR 2010-11-12: AXIS case 'AXIS': $name = strtolower( $wktName ); $value = array_shift( $wktArray ); switch( $value ) { case 'EAST' : $value = 'e'; break; case 'WEST' : $value = 'w'; break; case 'NORTH': $value = 'n'; break; case 'SOUTH': $value = 's'; break; case 'UP' : $value = 'u'; break; case 'DOWN' : $value = 'd'; break; case 'OTHER': default : $value = ' '; break; //FIXME } if( !$this->axis ) { $this->axis = "enu"; } switch( $name ) { case 'X': $this->axis = $value . substr( $this->axis, 1, 2 ); break; case 'Y': $this->axis = substr( $this->axis, 0, 1 ) . $value . substr( $this->axis, 2, 1 ); break; case 'Z': $this->axis = substr( $this->axis, 0, 2 ) . $value; break; default : break; } case 'MORE_HERE': break; default: break; } foreach( $wktArray as $wktArrayContent ) $this->parseWKT( $wktArrayContent ); } /** * Function: parseDefs * Parses the PROJ.4 initialization string and sets the associated properties. * */ public function parseDefs() { $this->defData = Proj4php::$defs[$this->srsCode]; #$paramName; #$paramVal; if( !$this->defData ) { return; } $paramArray = explode( "+", $this->defData ); for( $prop = 0; $prop < sizeof( $paramArray ); $prop++ ) { if( strlen( $paramArray[$prop] ) == 0 ) continue; $property = explode( "=", $paramArray[$prop] ); $paramName = strtolower( $property[0] ); if( sizeof( $property ) >= 2 ) { $paramVal = $property[1]; } switch( trim( $paramName ) ) { // trim out spaces case "": break; // throw away nameless parameter case "title": $this->title = $paramVal; break; case "proj": $this->projName = trim( $paramVal ); break; case "units": $this->units = trim( $paramVal ); break; case "datum": $this->datumCode = trim( $paramVal ); break; case "nadgrids": $this->nagrids = trim( $paramVal ); break; case "ellps": $this->ellps = trim( $paramVal ); break; case "a": $this->a = floatval( $paramVal ); break; // semi-major radius case "b": $this->b = floatval( $paramVal ); break; // semi-minor radius // DGR 2007-11-20 case "rf": $this->rf = floatval( paramVal ); break; // inverse flattening rf= a/(a-b) case "lat_0": $this->lat0 = $paramVal * Proj4php::$common->D2R; break; // phi0, central latitude case "lat_1": $this->lat1 = $paramVal * Proj4php::$common->D2R; break; //standard parallel 1 case "lat_2": $this->lat2 = $paramVal * Proj4php::$common->D2R; break; //standard parallel 2 case "lat_ts": $this->lat_ts = $paramVal * Proj4php::$common->D2R; break; // used in merc and eqc case "lon_0": $this->long0 = $paramVal * Proj4php::$common->D2R; break; // lam0, central longitude case "alpha": $this->alpha = floatval( $paramVal ) * Proj4php::$common->D2R; break; //for somerc projection case "lonc": $this->longc = paramVal * Proj4php::$common->D2R; break; //for somerc projection case "x_0": $this->x0 = floatval( $paramVal ); break; // false easting case "y_0": $this->y0 = floatval( $paramVal ); break; // false northing case "k_0": $this->k0 = floatval( $paramVal ); break; // projection scale factor case "k": $this->k0 = floatval( $paramVal ); break; // both forms returned case "r_a": $this->R_A = true; break; // sphere--area of ellipsoid case "zone": $this->zone = intval( $paramVal, 10 ); break; // UTM Zone case "south": $this->utmSouth = true; break; // UTM north/south case "towgs84": $this->datum_params = explode( ",", $paramVal ); break; case "to_meter": $this->to_meter = floatval( $paramVal ); break; // cartesian scaling case "from_greenwich": $this->from_greenwich = $paramVal * Proj4php::$common->D2R; break; // DGR 2008-07-09 : if pm is not a well-known prime meridian take // the value instead of 0.0, then convert to radians case "pm": $paramVal = trim( $paramVal ); $this->from_greenwich = Proj4php::$primeMeridian[$paramVal] ? Proj4php::$primeMeridian[$paramVal] : floatval( $paramVal ); $this->from_greenwich *= Proj4php::$common->D2R; break; // DGR 2010-11-12: axis case "axis": $paramVal = trim( $paramVal ); $legalAxis = "ewnsud"; if( strlen( paramVal ) == 3 && strpos( $legalAxis, substr( $paramVal, 0, 1 ) ) !== false && strpos( $legalAxis, substr( $paramVal, 1, 1 ) ) !== false && strpos( $legalAxis, substr( $paramVal, 2, 1 ) ) !== false ) { $this->axis = $paramVal; } //FIXME: be silent ? break; case "no_defs": break; default: //alert("Unrecognized parameter: " . paramName); } // switch() } // for paramArray $this->deriveConstants(); } /** * Function: deriveConstants * Sets several derived constant values and initialization of datum and ellipse parameters. * */ public function deriveConstants() { if( isset( $this->nagrids ) && $this->nagrids == '@null' ) $this->datumCode = 'none'; if( isset( $this->datumCode ) && $this->datumCode != 'none' ) { $datumDef = Proj4php::$datum[$this->datumCode]; if( is_array($datumDef ) ) { $this->datum_params = array_key_exists( 'towgs84', $datumDef ) ? explode( ',', $datumDef['towgs84'] ) : null; $this->ellps = $datumDef['ellipse']; $this->datumName = array_key_exists( 'datumName', $datumDef ) ? $datumDef['datumName'] : $this->datumCode; } } if( !isset( $this->a ) ) { // do we have an ellipsoid? if( !isset( $this->ellps ) || strlen( $this->ellps ) == 0 || !array_key_exists( $this->ellps, Proj4php::$ellipsoid ) ) $ellipse = Proj4php::$ellipsoid['WGS84']; else { $ellipse = Proj4php::$ellipsoid[$this->ellps]; } Proj4php::extend( $this, $ellipse ); } if( isset( $this->rf ) && !isset( $this->b ) ) $this->b = (1.0 - 1.0 / $this->rf) * $this->a; if ( (isset($this->rf) && $this->rf === 0) || abs($this->a - $this->b) < Proj4php::$common->EPSLN) { $this->sphere = true; $this->b = $this->a; } $this->a2 = $this->a * $this->a; // used in geocentric $this->b2 = $this->b * $this->b; // used in geocentric $this->es = ($this->a2 - $this->b2) / $this->a2; // e ^ 2 $this->e = sqrt( $this->es ); // eccentricity if( isset( $this->R_A ) ) { $this->a *= 1. - $this->es * (Proj4php::$common->SIXTH + $this->es * (Proj4php::$common->RA4 + $this->es * Proj4php::$common->RA6)); $this->a2 = $this->a * $this->a; $this->b2 = $this->b * $this->b; $this->es = 0.0; } $this->ep2 = ($this->a2 - $this->b2) / $this->b2; // used in geocentric if( !isset( $this->k0 ) ) $this->k0 = 1.0; //default value //DGR 2010-11-12: axis if( !isset( $this->axis ) ) { $this->axis = "enu"; } $this->datum = new Proj4phpDatum( $this ); } }