Tiny Float values, how can I normalize the range? [SOLVED]

I am working on an iPhone game that uses the Longitude and Latitudes to place objects and detect when the user is near. What I’m finding is all kinds of problems detecting small changes in the float values and translating that into Unity’s game space. I have a feeling that it is relating to floating point precision and would like to know if there is a mathematical formula to normalize tiny value differences in floats?

This seems to work on a static longitude and latitude:

transform.position.x = (39.758179 -39.75) * 10000.0;
transform.position.z = (-104.897064 +104.89) * 10000.0;

With the above code I get a decent number for positioning, like 81.79 and -70.64. But, it does not work at all on iPhoneInput.lastLocation:

transform.position.x = (iPhoneInput.lastLocation.longitude -39.75) * 10000.0;
transform.position.z = (iPhoneInput.lastLocation.latitude +104.89) * 10000.0;

My numbers in the App are in the hundreds of thousands. I’ve tried re-ordering the calculations, subtracting first into a variable and then multiplying and it still produces useless numbers. This is a pain to test because Unity Remote does not seem to support location services and I have to recompile to test.

If I could use the raw data I would, but the float differences are so tiny they are invisible. For example, 39.758179 is one object, another is 39.758530.

I’m getting the coordinates from GoogleMaps and trying to compare with my iPhone.

I’ve even thought of stripping off the first 4 characters of the floats, like you might do with Character data, but that seems like a hack and a lot of work for the application. I’d prefer a fairly simple math equation, which if I knew math better I might be able to wrap my head around. Any help is much appeciated!

Bryan

An easy way to compare two floats while ignoring trivial differences is to use the Mathf.Approximately function. The comparison succeeds if the difference between the numbers is less than Mathf.Epsilon. Alternatively, you can just subtract one value from the other and compare against your own “near enough” value.

Thank you for your reply. Can you elaborate on how I might use Mathf.Epsilon to track changes from iPhone location data? As I have found, I have to compile the Xcode project to run this on my iPhone and the only way I know to check the data is to have it display in the GUI once compiled. Trouble-shooting is difficult, in other words.

For example, if I have 36.00001 and the movement picked up via GPS is 36.00002. My guess is Mathf.Approximately could round this, but I’m not clear how Mathf.Epsilon will help me use the number change. I would like the transform.x to move 10 units with the movement above.

I guess what I am trying to do is amplify tiny float changes, not necessarily trying eliminate them.

Bryan

Sorry, I misunderstood what you were looking for there (I thought you were comparing two approximate values rather than extracting the low order digits.)

Single precision floats (ie, the float type used in Unity and elsewhere) give you the equivalent of about seven decimal digits of accuracy. This will give you four or five correct digits after the decimal point, so multiplying by 10000 should be OK, at least for the integer part.

What range of values do you need? Are you representing objects to a very accurate location over a very large distance range? What scale are you using within Unity? If, say, you need to represent a world location down to single metre accuracy, you will likely find a single Unity scene doesn’t have the required precision. You may be able to break the overall range down into smaller “tiles”, each of which works comfortably in a Unity scene.

I’ve been able to compare my iphone’s current location using vector2.distance with coordinates in the range below. It works reasonably well to multiply the result by 10000 and use that to create a new vector2.

But I will have about 20 objects in about a 1km range and i think it would be more efficient to simply place the objects on a plane and scale the iPhones current location. The idea is a player needs to physically relocate near the objects to play the game.

39.731289, -104.961356

39.731608, -104.961622

39.731739, -104.960689

39.732169, -104.960933

39.732517, -104.960444

39.732281, -104.960422

39.731789, -104.960244

To sort of answer my own question, I have found something that seems like it could be worth investigation in HiggyB’s OrbitSim project. I noticed his Cameras have a really tiny View Port:

Normalized View Port Rect X=0.008169935 Y=0.0610998

Maybe I can keep the original coordinates and just make my Unity world really tiny. It seems odd though, and if I start to use Physics or a jointed character things might get strange at such a tiny world level.

Bryan

OK, Here’s the solution for anyone trying to do something similar. My goal was to use the iPhone as THE Player. You move around and the player moves and corresponds to what you are doing in real time. The problem is that the GPS data changes are so small it’s really hard (impossible) to translate that into a normal game space.

One way is to just multiply the GPS by 100,000, that gives decent movement but things get weird out around transform.x = 3,987,123. The camera distorts and beyond that the movement is so jumpy to be unusable.

The solution is to use two sets of Vectors. Use the raw GPS and do a Vector3.Distance check to see if the device is “near” the target. It’s a tiny float difference, but works pretty well at just detecting that I am < .00001 from the target.

For the placement of the targets, I use the GPS data from a Google Map and subtraction to figure out how to place everything. The code below goes through an array of coordinates finding min and max values. I subtract the target coordinate from the max value to figure out where it is relative to the others. The min value is naturally zero for both x and y. That gives me a tiny difference float that I then multiply by 100,000 to place it around x = 150.4.

I also use those min and max bounds to scale the playing field. Works a treat, and it could easily be scaled appropriately to use cities or just your backyard.

The drawback is that I am not really using the GPS for the players location although I suppose the same math could be used for that. I do use GPS to check how close I am to the targets original GPS coordinates.

var vectorArray : Vector3[] = vectors.ToBuiltin(Vector3);
    
    print("Built-in Array: " + vectorArray[0]);
    
    //Step through vectors to find minX and maxX, plus minZ and maxZ. First set the values arbitrarily high or low
    var minX : double = 1000000.0;
       var maxX : double = -100000.0;
       var minZ : double = 1000000.0;
       var maxZ : double = -1000000.0;
       
    for( var s=0; s < vectors.length; s++){
        
        if(vectorArray[s].x < minX){
            minX=vectorArray[s].x;
        }
        if(vectorArray[s].x > maxX){
            maxX=vectorArray[s].x;
        }
        if(vectorArray[s].z < minZ){
            minZ=vectorArray[s].z;
        }
        if(vectorArray[s].z > maxZ){
            maxZ=vectorArray[s].z;
        }
        
    }
    
    var lengthX : float = maxX - minX;
    var lengthZ : float = maxZ - minZ;
    
            
    //Step through and Scale/Normalize the Vectors to a standard range, I do this by subtracting the Vector3 from the max values 
    for( var n=0; n < vectorArray.length; n++){
        
        var nvector : Vector3 = (Vector3(maxX, 0.0, maxZ) - vectorArray[n])*100000;
        nvector.z = -nvector.z;
        vectorArray[n]=nvector;
        
    }
    
    playerObject.transform.position = Vector3(lengthX*50000, 0.0,-(lengthZ*50000));
    
        
    createContainer(lengthX, lengthZ);
      
    //Don't forget to cast the Array to our new function (vector Array)
    createTarget(vectorArray.length, vectorArray);