Flex - Display latitude and longitue

3493
12
04-02-2010 09:34 AM
JacksonTrappett
Occasional Contributor II
Hello, I can't seem to search the old forums anymore so I figured I'd try asking on these new ones.

My question:
I have a flex app that is displaying a map in a projected coordinate system (WGS 1984 UTM Zone 12N) which means that my map units are in meters.  I am displaying the coordinate position of the mouse using two <mx:text> elements but of course it is displaying meters.  What my user's would like to see is a display of the latitude and longitude of the mouse while still keeping the map in the projected coordinate system.  Is this possible?
Tags (2)
0 Kudos
12 Replies
RobertScheitlin__GISP
MVP Emeritus
JTrappett,

  There is no way currently or in the next API version to project coordinates to WGS1984 on the client side unless you are using the web mercator (wkid 102100). And you would not want to make a round trip to the server to use the geometry service to re-project the mouse coordinate either as your app would hardly ever stop talking to the server. If you can switch your map services to web mercator than that is your best bet.
0 Kudos
JacksonTrappett
Occasional Contributor II
If you can switch your map services to web mercator than that is your best bet.


Thank you for the reply.  Since there doesn't seem to be a client-side way to do this, and the best bet of using web mercator is not ideal for us, I decided to try the math approach.

Here is a function I wrote to do the conversion from UTM to Lat Long.  This function is set up for WGS_1984_UTM_Zone_12N but should work for other UTM zones/projections if the information for the six variables in the settings section are changed to be correct for that projection.  This function will not work for other coordinate systems such as state plane however, since the math is totally different.

private function UTMtoLATLON(mapPoint:MapPoint):MapPoint
{
 //The math in this function was based off of methods found on http://www.gpsy.com/gpsinfo/geotoutm/ by Karen Nakamura

 //Set easting and northing from the MapPoint
 var easting:Number = mapPoint.x; //the X coordinate from the service in UTM meters
 var northing:Number = mapPoint.y; //the Y coordinate from the service in UTM meters

 //Settings for WGS_1984_UTM_Zone_12N or WKID 32612
 var avflat:Number = 298.257223563; //the Inverse Flattening that ArcGIS provides in the geographic coordinate description
 var semiMAJaxis:Number = 6378137.0; //the Semimajor Axis that ArcGIS provides in the geographic coordinate description
 var meridORIG:Number = -111.0;  //the Central Meridian that ArcGIS provides in the projection description
 var scFACTorig:Number = 0.9996;  //the Scale Factor that ArcGIS provides in the projection description
 var falseNOR:Number = 0.0;   //the False Northing that ArcGIS provides in the projection description
 var falseEST:Number = 500000.0;  //the False Easting that ArcGIS provides in the projection description

 //Calculations
 var flattening:Number = 1.0/avflat; //change Inverse Flattening into flattening
 var eccentricity:Number = (2.0*flattening)-(flattening*flattening); //calculate eccentricity
 var semiMINaxis:Number = semiMAJaxis*(Math.pow((1.0-eccentricity),0.5)); //calculate the Semiminor Axis
 var n:Number = (semiMAJaxis - semiMINaxis)/(semiMAJaxis + semiMINaxis);  //calculate n
 var semiMAJecc:Number = semiMAJaxis*(1.0-eccentricity);      //calculate the Semimajor Eccentricity
 var semiMINecc:Number = 1.0/(Math.sin((1.0/3600.0)*Math.PI/180.0));   //calculate the Semiminor Eccentricity
 var epsilon:Number = 1097.0*(Math.pow(n,4.0))/512.0;             //calculate epsilon
 var delta:Number = 151.0*(Math.pow(n,3.0))/96.0-(417.0*(Math.pow(n,5.0))/128.0);      //calculate delta
 var gamma:Number = 21.0*(Math.pow(n,2.0))/16.0-(55.0*(Math.pow(n,4.0))/32.0);       //calculate gamma
 var beta:Number = 3.0*n/2.0-(27.0*(Math.pow(n,3.0))/32.0)+(269.0*(Math.pow(n,5.0))/512.0);    //calculate beta
 var alpha:Number = (semiMAJaxis + semiMINaxis)/2.0*(1.0+(Math.pow(n,2.0))/4.0+(Math.pow(n,4.0))/64.0); //calculate alpha
 var phiprime:Number = (northing - falseNOR)/(scFACTorig*alpha); //calculate phiprime
 var phiF:Number = phiprime+beta*Math.sin(2.0*phiprime)+gamma*Math.sin(4.0*phiprime)+delta*Math.sin(6.0*phiprime)+epsilon*Math.sin(8.0*phiprime); //calculate phiF
 var v:Number = semiMAJaxis/(Math.pow(1.0-(eccentricity*(Math.pow(Math.sin(phiF),2.0))),0.5)); //calculate v
 var p:Number = semiMAJecc/Math.pow((1.0-(eccentricity*Math.pow(Math.sin(phiF),2.0))),1.5);  //calculate p
 var VII:Number = ((Math.tan(phiF)*Math.pow((easting-falseEST),2.0))/(2.0*Math.pow(scFACTorig,2.0)*v*p))*((1.0/(Math.sin((1.0/3600.0)*Math.PI/180.0)))); //calculate VII
 var VIII:Number = ((Math.tan(phiF)*Math.pow((easting-falseEST),4.0))/(24.0*Math.pow(scFACTorig,4.0)*Math.pow(v,3.0)*p))*(5.0+3.0*Math.pow((Math.tan(phiF)),2.0))*(1.0/(Math.sin((1.0/3600.0)*Math.PI/180.0))); //calculate VIII
 var X:Number = ((1.0/Math.cos(phiF))*Math.pow((easting-falseEST),3.0)*semiMINecc)/(6.0*Math.pow(scFACTorig,3.0)*Math.pow(v,3.0))*((v/p)+2.0*Math.pow((Math.tan(phiF)),2.0)); //calculate X
 var IX:Number = ((1.0/Math.cos(phiF))*(easting-falseEST)*semiMINecc)/(scFACTorig*v); //calculate XI
 var E:Number = ((1.0/Math.cos(phiF))*Math.pow((easting-falseEST),5.0)*semiMINecc)/(120.0*Math.pow(scFACTorig,5.0)*Math.pow(v,5.0))*(5.0+28.0*Math.pow((Math.tan(phiF)),2.0)+24.0*Math.pow((Math.tan(phiF)),4.0)); //calculate E
 var phiFdegrees:Number = phiF*180.0/Math.PI;    //change phiF from radians to degrees
 var DDegLat:Number = phiFdegrees-VII/3600.0+VIII/3600.0; //calculate degrees latitude
 var DDegLon:Number = meridORIG+(IX-X+E)/3600.0;    //calculate degrees longitude
       
 //Set the MapPoint to the new Lat and Lon
 mapPoint.x = DDegLon;
 mapPoint.y = DDegLat;
       
 //Return the MapPoint
 return mapPoint;
}
0 Kudos
PaulFrame
New Contributor
Hi Jackson,

This code is pretty much exactly what I'm looking for.  I'll just have to change it for zone 11N.  One question though, where in Desktop do I put it?  I've never worked with straight code before.  I'm using ArcEditor 9.3 with Spatial Analyst extension.  Any help would be greatly appreciated.

One other question, will this add the lat. lon. coordinates to the attribute table? 

Cheers,
Paul
0 Kudos
JacksonTrappett
Occasional Contributor II
Hi Jackson,

This code is pretty much exactly what I'm looking for.  I'll just have to change it for zone 11N.  One question though, where in Desktop do I put it?  I've never worked with straight code before.  I'm using ArcEditor 9.3 with Spatial Analyst extension.  Any help would be greatly appreciated.

One other question, will this add the lat. lon. coordinates to the attribute table? 

Cheers,
Paul


Paul,
From what I gather from your message, you are working on translating coordinates in desktop ArcGIS.  If this is the case you shouldn't need to use code like this for coordinate conversions.

This code is meant to be used in a web application (flex) where the coordinate conversions that ESRI provides haven't been made available yet.

If you are wanting to add lat long coordinates to your attribute table in ArcMap, just add two columns of type double, one for each, then use the calculate geometry tool to calculate the coordinates and choose decimal degrees as the output.  If there is another reason you are looking for code like this, post more details and I can probably help you out.
0 Kudos
PaulFrame
New Contributor
Thanks Jackson.  You're right.  Your suggesting does what I needed.  After you mention it, I remember knowing how to do this.

Cheers,
0 Kudos
JayGeisen
New Contributor III
Does anyone know how one might go about doing something like this for State Plane?  We do this in our ArcIMS site, so the cursor's location would be converted on the fly to Lat Long.  The numbers for the conversion can be found here.  I'm just not sure how to go about it.  Any help is appreciated. 

Thanks,
Jay
0 Kudos
JacksonTrappett
Occasional Contributor II
It looks like you could take the code that you linked and make a function just like the one I posted.  The code you posted takes an x and y in state plane, does all of the math and you end up with a lat, long.  That should fit perfectly into a similar function in flex and then you can use the mouse move event to pass the x, y to your function and then the results of the function to the banner lat, long coordinates.

Are you using the sample viewer, or making a custom application?
0 Kudos
JayGeisen
New Contributor III
Jackson,

I'm using the Sample Flex Viewer and Robert's Banner widget.  I'm trying to figure out where to put the function and how to make it work with Robert's code, found here

Actually, for that matter, a different widget that returned Lat/Long on a mouseclick (based off the above conversion) and provided a Lat/Long search option would be perhaps more like what I would like to do.  Are you using the Sample Viewer and Coordinate Display/Banner widget?

Jay
0 Kudos
JacksonTrappett
Occasional Contributor II
Here's how I did it:

Step 1: Add your coordinate translation function.  See mine above.  I added it to the MapManager.xml.  I have it taking and returning a MapPoint which is just an x,y pair.

Step 2: Add a mouse move event listener to the map.  In the sample viewer this would be in MapManager.xml.

In the config function add:
map.addEventListener(MouseEvent.MOUSE_MOVE, mapMouseMove);


Then make a mapMouseMove function:
private function mapMouseMove(event:MouseEvent):void
{
        var mapPoint:MapPoint = map.toMapFromStage(event.stageX, event.stageY);
        mapPoint = UTMtoLATLON(mapPoint);  //translate coordinates
        SiteContainer.dispatchEvent(new AppEvent(AppEvent.SET_XY, false, false, mapPoint));
}

I use a MapPoint object because it is provided by the API rather than make my own ordered pair object or send the x and y separately.  The AppEvent SET_XY is dispatched to let the banner know to update.

You'll also need to add the SET_XY event to AppEvent.as:
public static const SET_XY:String = "setxyLoc";


Step 3: In your banner set an event listener for the SET_XY event and then set the [Bindable] x and y variables for your banner display using the data that was dispatched.

In the Banner init:
SiteContainer.addEventListener(AppEvent.SET_XY, setXY);


Add a Banner setXY function:
private function setXY(event:AppEvent):void
{
 if (event.data)
         var mapPoint:MapPoint = event.data as MapPoint;
         xLoc = mapPoint.x.toFixed(6);
                yLoc = mapPoint.y.toFixed(6);
}

xLoc and yLoc are my bindable variables that are displayed in the banner for lat/long.

There may be a better way to do this, but this way has been working great for me.
0 Kudos