Jump to content
  • Advertisement
Sign in to follow this  
EmptyVoid

Will This Work?

This topic is 4104 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I got someone on a math forum to come up with a formula to convert a normal to a spherical coordinate from there I made it into c++ but I'm not sure it will work or if this is the best way so tell me how I can make it better or at least work?
void Normal2Spherical(float x,float y,float z)
{
float radius, latitude, longitude
radius = sqrt((x*x) + (y*y) + (z*z));
latitude = arctan(y/x);
if(y<0 && x<0) 
{ 
latitude += 180; 
} 
if(y>0 && x<0)
{ 
latitude += 180; 
} 
longitude = arccos(z/sqrt((x*x) + (y*y) + (z*z)))
}



[Edited by - EmptyVoid on July 26, 2007 4:54:34 PM]

Share this post


Link to post
Share on other sites
Advertisement
Ok; let's go through it line by line. I'm assuming you haven't actually tested it, since this code wouldn't compile. Additionally, this doesn't look like you want spherical coordinates, it looks like you want geographic coordinates. Which is it?


void Normal2Spherical(float x,float y,float z) {

// No semicolon
float radius, latitude, longitude;

// This line is unnecessary. If it's a normal, the radius will be 1.
radius = sqrt((x*x) + (y*y) + (z*z));

// arctan does not return degrees, it returns radians
latitude = arctan(y/x) * 180.0f / M_PI;

// What range are you trying to keep the latitude in? arctan is in the range
// [-π,π], so I'm guessing that you want to keep it in [0,2π]? Either way,
// adding π isn't the answer. If you want to keep a correct translation, add
// 2π. That and you don't need to test against x and y, just test for latitude.
if( latitude < 0.0f ) {
latitude += 360.0f;
}

// You've already calculated the radius, so why do it again?
// Even still, it's unnecessary, since the radius will be 1.
longitude = arccos(z) * 180.0f / M_PI;
}



That being said, I didn't actually check your math - just your code.

Share this post


Link to post
Share on other sites
OK is this right?


void Normal2Spherical(float x,float y,float z)
{
float latitude, longitude;
latitude = arctan(y/x) * 180.0f / 3.14159f;
if(latitude < 0.0f)
{
latitude += 360.0f;
}
longitude = arccos(z) * 180.0f / 3.14159f;
}






And as I said I don't really know how it works I didn't make the formula. I just made it into c++.

Share this post


Link to post
Share on other sites
Err.. that code doesnt really do anything
It may as well be


void Normal2Spherical(float x,float y,float z)
{
}

Whether latitude and longitude were calculated correctly however I dont really know, sorry. Although it doesnt look like calculating spherical coordinates to me.

That said, the point remains you still need to return whatever output you calculate.

spherical polar coordinates are calculated using a radius, theta and phi:

radius = sqrt(x*x + y*y + z*z)
theta = arctan(y/x)
phi = arccos(z/r)

I think the point you're missing is that in your first example you forgot the quotient z/r within the arccos. << Edit: Actually I was looking at erissians version where the division is missing, in your original version EmptyVoid you calculate the radius twice for some reason.

I'd also rename your function to CartesianToSpherical which makes much more sense.

Edit:
Quote:
arctan is in the range
// [-π,π], so I'm guessing that you want to keep it in [0,2π]? Either way,
// adding π isn't the answer. If you want to keep a correct translation, add
// 2π.

Am i miss-understanding? I think adding Pi is correct?:
-π + π = 0
π + π = 2π

[Edited by - dmatter on July 26, 2007 7:55:33 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by dmatter
Edit:
Quote:
arctan is in the range
// [-π,π], so I'm guessing that you want to keep it in [0,2π]? Either way,
// adding π isn't the answer. If you want to keep a correct translation, add
// 2π.

Am i miss-understanding? I think adding Pi is correct?:
-π + π = 0
π + π = 2π

Angles in the range [0,PI] are correct. You will have only to translate negative angles to the equivalent positive value (keeping it smaller than 2*PI), which is done by adding 2*PI. You keep your [0,PI] and replace [-PI,0) with [PI,2*PI), resulting in an interval of [0,2*PI).

Share this post


Link to post
Share on other sites
OK I have added all your ideas to the code but made some changes I need the values in the range of 0-1. I also tested it and it works. this is what I have:


#include "math.h"

struct SPHCOORD
{
float theta, phi;
};

SPHCOORD CartesianToSpherical(float x,float y,float z)
{
SPHCOORD SphericalPos;
SphericalPos.theta = atan(x/z)/6.28318f;
if(SphericalPos.theta < 0.0f)
SphericalPos.theta += 0.5f;

//Fix for problem #1
if(z== -1.0f)
SphericalPos.theta += 0.5f;

//Fix for problem #2
if(x<0)
SphericalPos.theta += 0.5f;

SphericalPos.phi = acos(y)/3.14159f;
return SphericalPos;
}




But there are 2 problems with it.

1. When it's exactly 0, 0, -1 it returns 0.0, 0.5 but it needs to be 0.5, 0.5 so I added this code:


if(z== -1.0f)
SphericalPos.theta += 0.5f;



2. When x less then 0 it starts back at 0 like when it's set to -0.1, 0, -0.9 it returns 0.017612, 0.5 so I added this code:


if(x<0)
SphericalPos.theta += 0.5f;



So how can I make this more mathematically perfect?


[Edited by - EmptyVoid on July 27, 2007 6:38:45 PM]

Share this post


Link to post
Share on other sites
Well, this time around I'm going to assume that you want spherical coordinates. They are subtly different from geographic coordinates.

Geographic coordinates have only two values, longitude and latitude. Latitude is measured in degrees north or south of the equator, giving it a range of [-90,90]. Longitude is measured in degrees east or west of the meridian, giving it a range of [-180,180]. The radius is non-existent because it is assumed to be whatever the radius of the surface of the object is at that point, but you could implement it anyways for a more abstract system, but it's much easier to deal with genuine spherical coordinates.

Spherical coordinates are defined by three values, θ (theta), φ (phi), and ρ (radius). Theta denotes the angle from the top of the sphere (or Z axis) in radians, so it has a range of [0,π]. Phi denotes the angle from the X axis (typically) giving it a range of [0,2π]. The radius denotes the distance from the center of the sphere to the point being described. It has a range of [0,∞).

You are converting a rectilinear normal to spherical coordinates in this function. Because it's a normal, it has a radius of 1 by definition, so we can skip anything that deals with it. I'll still mention it where appropriate, but I won't put it in the resulting code. dmatter is correct that your code doesn't return anything, but I'm assuming that this is example code anyways.

The first thing we'll do it figure out phi, or the angle between the vector and the X axis. This is done by projecting the vector onto the XY plane (assuming your "up" is Z. If it isn't, then just mentally switch all my Ys and Zs). This projection is pretty easy, just ignore the Z component of the vector. Now if you remember what a tangent is (if not, look it up now), then we can use two parts of a triangle to find the angle using the arctangent (atan2f). In this case the opposite angle will be the Y component, and the adjacent angle will be the X component, therefore:

phi = atan2f(y,x);


After that, we need to find theta. This is done is the same manner, but on the plane between the Z axis and our vector. Also, we'll need not the length of our vector, but the vector we projected onto the XY plane earlier.

theta = atan2f(sqrtf(x*x+y*y),z);






Share this post


Link to post
Share on other sites
lol erissian you posted like 1 secound after me ok I put all of your ideas into one perfect function and here it is:

[source c++]
#include "math.h"

struct SPHCOORD
{
float theta, phi;
};

SPHCOORD CartesianToSpherical(float x, float y, float z)
{
SPHCOORD SphericalPos;
SphericalPos.phi = atan2f(x,z)/6.28318f;
if(SphericalPos.phi < 0.0f)
SphericalPos.phi += 1.0f;
SphericalPos.theta = atan2f(sqrtf(x*x+z*z),y)/3.14159f;
return SphericalPos;
}




So it works perfect. I can't see how it could be any better but if anyone else has an idea please tell me.

[Edited by - EmptyVoid on July 28, 2007 5:37:35 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!