Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
4
Question by Catlard · Nov 28, 2011 at 01:22 AM · scale

Polar (spherical) coordinates to xyz, and vice versa.

Hello everybody!

I've been working at this math for two days now, with no luck. I'm writing a program that puts markers onto a sphere gameObject according to latitude and longitude positions--and there's somewhere I've gone wrong. Converting XYZ to lat and longitude works VERY approximately (it gets the the longitude correct, but latitude is off by about 20 degrees) and lat and longitude to XYZ, not at all. There are really three functions I'm using here. I've had a look at the wikipedia and stack overflow pages on this topic, and I'm not sure what I've done wrong...perhaps someone could point me in the right direction? I really feel lost with this stuff. Never had a class on it. Thanks so much for your time!

Simon

XYZ TO LAT/LONGITUDE: This function converts raycastHits to Lat and longitude data. (When the player clicks on the globe in view, my program must generate this information, irrespective of rotation).

 function determineGISCoordinates()
 {
     //determines attributes of the earth-sphere.
     var earthPosition = earth.position;
     //THIS IS BASED ON THE EARTH TEXTURE WE'RE USING. when the earth stands at this rotation, the 0,0 point of latitude and longitude sit directly in front of the camera.
     var originRotation = Vector3(0.00,105.00,0.00);
     var currentRotation = earth.transform.localEulerAngles;
     var rotationOffset = currentRotation;
     rotationOffset.x -= originRotation.x;
     rotationOffset.y -= originRotation.y;
     rotationOffset.z -= originRotation.z;
     //get the point of the raycasthit as though the circle were at the origin, and determine the radial distance.
     var localSurfacePointVector = myNewPointer.transform.position-earthPosition;
     var radialDistance = Mathf.Sqrt(Mathf.Pow(localSurfacePointVector.x, 2) + Mathf.Pow(localSurfacePointVector.y,2) + Mathf.Pow(localSurfacePointVector.z, 2));
     //get degree positions on sphere, irrespective of rotation or the lat/long system.
     var lat = Mathf.Rad2Deg * (Mathf.Acos(localSurfacePointVector.y / radialDistance)); //theta
     var lon = Mathf.Rad2Deg * (Mathf.Atan(localSurfacePointVector.x / localSurfacePointVector.z)); //phi
     //apply lat/long as though the sphere were standing still at the origin rotation. Negative numbers mean south or west. i have to do this because when i raycast, without this it's only detecting the north pole as 65 degrees...so i've got to re-scale  the numbers to fit lat and longitude, which go up to 90 and 180. i don't know why this happens. perhaps because the sphere the earth is on has a scale of approximately 2?
     lat = ((lat-90)/65) * 90 * -1;
     lon = ((lon)/65) * 90 * -1;
     //adjust for current rotation (only works for longitude right now).
     lon+= rotationOffset.y;
     if(lon > 180) lon= -1* (180-(lon%180));
     if(lat > 90) lat= -1* (90-(lat%90));
 }

LAT/LONGITUDE TO XYZ: This function takes Minutes and second values and converts them to XYZ coordinates on the same sphere as previously mentioned. Then it sends them to a function that places them. It takes the array infoArray, and turns it into longitude / latitude numbers.

 function determinePosition(infoArray : Array)
 {
     var positionToPlaceMarker : Vector3;
         //convert infoArray to lat and longitude data.
         var latitude = infoArray[0] + infoArray[1]/60;
     if(infoArray[2] == "S") latitude *= -1;
     var longitude = infoArray[3] + infoArray[4]/60;
     if(infoArray[5] == "W") latitude *= -1;
         var earthRadius = earth.collider.radius * earth.transform.localScale.x;
     //because the earth isn't at the origin, we have to add the offset position data.
     //I SUSPECT THESE THREE EQUATIONS ARE WHERE THE PROBLEM IS.
     positionToPlaceMarker.z = earthRadius * Mathf.Cos(latitude) * Mathf.Cos(longitude);
     positionToPlaceMarker.y = earthRadius * -1 * Mathf.Sin(latitude);
     positionToPlaceMarker.x = earthRadius * Mathf.Cos(latitude) * Mathf.Sin(longitude);
     positionToPlaceMarker=positionToPlaceMarker + GameObject.Find("earth").transform.position;
     //sends the data to the function that comes next.
     GameObject.Find("Main Camera").GetComponent("earthGISRaycaster").placeMarker(positionToPlaceMarker);
 }

THE PLACING FUNCTION:

 function placeMarker(location : Vector3)
 {
     //print("Placed a marker!");
     myNewPointer = Instantiate(pointerIcon, location, Quaternion.identity);
     generateTextureColor(myNewPointer); //assigns a random color to the object. assigns the shader to specular.
     myNewPointer.transform.LookAt(earth);
     myNewPointer.transform.Rotate(0,90,0);
     myNewPointer.parent = earth;
     determineGISCoordinates(); // calls the function above, that translates these XYZ coordinates into lat and longitude data. As i've said, this works very very approximately. For example, the correct coordinates for Melbourne, Australia are approximately 30 degrees north of where they should be, somewhere in the australian desert :).
     myNewPointer.gameObject.layer = 2;
 }
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
16
Best Answer

Answer by WillTAtl · Nov 28, 2011 at 04:19 AM

I should note this is not, strictly speaking, a unity question at all, but a general math programming question! I got a little carried away working on an answer for this one, though, because I found it interesting, so here's your answer anyway. :)

There's clearly some errors in your math there, more than I care to go through and try to straighten out, so I'm just going to give you, for reference, a pair of working functions that convert between the two.

A note on trig functions: you usually want to use Atan2 for this kind of thing, as it accepts x and y as separate values rather than a single x/y value. This allows it to return a full and correct 360-degree range; doing the division before passing to Atan loses the sign data of each component and will just return a 180-degree range. For example, Atan can't differentiate between (-2,2) and (2,-2), because both when divided give just -1, but they're definitely different angles, and Atan2 correctly handles these cases, saving you the trouble of sorting it out yourself!

Threw this example together, it doesn't do everything you need but it should give you a working reference for basic conversion between polar and cartesian coordinates. I'm using Vector2s to represent the polar coordinates, x being latitude and y longitude. For the conversion back from polar, the easiest, and likely most efficient, approach is to use unity's built-in vector rotation methods, which is what I did.

 function CartesianToPolar(point:Vector3):Vector2
 {
     var polar:Vector2;
 
     //calc longitude
     polar.y = Mathf.Atan2(point.x,point.z);
 
     //this is easier to write and read than sqrt(pow(x,2), pow(y,2))!
     var xzLen = Vector2(point.x,point.z).magnitude; 
     //atan2 does the magic
     polar.x = Mathf.Atan2(-point.y,xzLen);
 
     //convert to deg
     polar *= Mathf.Rad2Deg;
 
     return polar;
 }
 
 
 function PolarToCartesian(polar:Vector2):Vector3
 {
 
     //an origin vector, representing lat,lon of 0,0. 
 
     var origin=Vector3(0,0,1);
     //build a quaternion using euler angles for lat,lon
     var rotation = Quaternion.Euler(polar.x,polar.y,0);
     //transform our reference vector by the rotation. Easy-peasy!
     var point:Vector3=rotation*origin;
 
     return point;
 }


These are written to assume (0,0,1) is latitude and longitude of 0; if you need to change this, you'll need to change the origin vector in PolarToCartesian, and then rekajigger the order and sign of x and y terms when calling Atan2 to calculate longitude to correspond.

Hope this is helpful!

Comment
Add comment · Show 9 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Catlard · Nov 28, 2011 at 05:12 AM 0
Share

Holy frijoles! Thanks for all your hard work on this one, will. I agree, my math errors are legion. I think I've needed to start over. I'll start with the functions you've given me, and get back to you shortly. Thanks!

S

avatar image Catlard · Nov 28, 2011 at 06:42 AM 0
Share

Hmm...I've been fidgeting with this, Will, and it appears to be doing something, but the values I'm getting out of the Cartesian to $$anonymous$$r function are all between about -176.6 and 175.8. The $$anonymous$$r to Cartesian seems to place markers that are just too far away from the earth--I think it's trying to use a radius that's too large. I totally understand I'm being kind of wimpy about this, but I think I've got to take a break and actually show my work to someone. I'm a bit confused by the math, so it's likely the problem. Regardless, I'm sure you're right...I just can't figure out how to get it to work in my project. In any case, thanks!

Cheers

Simon

avatar image Catlard · Nov 28, 2011 at 06:43 AM 0
Share

Oh, yes, and I totally agree it's primarily a math problem rather than program$$anonymous$$g. But I had no where else to turn...and I wanted ot talk to Unity program$$anonymous$$g people about it, so here I am!

avatar image WillTAtl · Nov 28, 2011 at 07:17 AM 2
Share

I know what you mean, I still fall into the trap of wasting unreasonable amounts of time trying to fix bits of code that it would be faster to scrap, rethink, and rewrite from scratch. Just as easy to err the other way sometimes, with bigger tasks, but when it's a contained set of functionality like this, the choice is often an easy one. I spent a few $$anonymous$$utes at my whiteboard working out the math and making sure I had it straight in my head, and had the basic functions working in no time.

Where I spent an unreasonable amount of time was building a test scene, with objects to visualize the process and test the functions; it exposes a position vector3 called point and a vector2 with the pair of angles called polar, which can be edited in the inspector. It draws a reference sphere in the center, a cube that marks the current position specified in point, and a crude arrow that indicates direction of the lat/lon. Dropped in the standard asset script $$anonymous$$ouseOrbit, modified slightly to only operate when the mouse button is held down, and added a pair of buttons that use the functions I pasted in the answer to copy from point to polar and vice-versa. I'll be glad to zip it up and share it if you have trouble adapting this to your needs and think it might help. In fact, here, I'll just go ahead and do it, even if you don't need it someone might get some value out of the time I spent on it!

avatar image CHPedersen · Nov 28, 2011 at 07:54 AM 0
Share
  • for great dedication! :)

Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

6 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

how to know latitude and longitude ? 0 Answers

Get updated values from gps as moving 5 Answers

How to use Locationinfo in unity. 0 Answers

Centering a texture on Sphere on X axis 0 Answers

Scale Objects become flat. 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges