Is there a Math.atan2 substitute for j2ME? Blackberry development

Posted by Kai on Stack Overflow See other posts from Stack Overflow or by Kai
Published on 2010-06-03T00:15:58Z Indexed on 2010/06/03 0:24 UTC
Read the original article Hit count: 1167

Filed under:
|
|

I have a wide variety of locations stored in my persistent object that contain latitudes and longitudes in double(43.7389, 7.42577) format. I need to be able to grab the user's latitude and longitude and select all items within, say 1 mile. Walking distance. I have done this in PHP so I snagged my PHP code and transferred it to Java, where everything plugged in fine until I figured out J2ME doesn't support atan2(double, double). So, after some searching, I find a small snippet of code that is supposed to be a substitute for atan2. Here is the code:

public double atan2(double y, double x) {
        double coeff_1 = Math.PI / 4d;
        double coeff_2 = 3d * coeff_1;
        double abs_y = Math.abs(y)+ 1e-10f;
        double r, angle;
        if (x >= 0d) {
            r = (x - abs_y) / (x + abs_y);
            angle = coeff_1;
        } else {
            r = (x + abs_y) / (abs_y - x);
            angle = coeff_2;
        }

        angle += (0.1963f * r * r - 0.9817f) * r;

        return y < 0.0f ? -angle : angle;
    }

I am getting odd results from this. My min and max latitude and longitudes are coming back as incredibly low numbers that can't possibly be right. Like 0.003785746 when I am expecting something closer to the original lat and long values (43.7389, 7.42577).

Since I am no master of advanced math, I don't really know what to look for here. Perhaps someone else may have an answer.

Here is my complete code:

package store_finder;

import java.util.Vector;

import javax.microedition.location.Criteria;
import javax.microedition.location.Location;
import javax.microedition.location.LocationException;
import javax.microedition.location.LocationListener;
import javax.microedition.location.LocationProvider;
import javax.microedition.location.QualifiedCoordinates;

import net.rim.blackberry.api.invoke.Invoke;
import net.rim.blackberry.api.invoke.MapsArguments;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.RichTextField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;

public class nearBy extends MainScreen {
    private HorizontalFieldManager _top;
    private VerticalFieldManager _middle;
    private int horizontalOffset;
    private final static long animationTime = 300;
    private long animationStart = 0;
    private double latitude = 43.7389;
    private double longitude = 7.42577;
    private int _interval = -1;

    private double max_lat;
    private double min_lat;
    private double max_lon;
    private double min_lon;
    private double latitude_in_degrees;
    private double longitude_in_degrees;


    public nearBy()
    {
        super();

        horizontalOffset = Display.getWidth();

        _top = new HorizontalFieldManager(Manager.USE_ALL_WIDTH | Field.FIELD_HCENTER)
        {
            public void paint(Graphics gr)
            {
                Bitmap bg = Bitmap.getBitmapResource("bg.png");
                gr.drawBitmap(0, 0, Display.getWidth(), Display.getHeight(), bg, 0, 0);
                subpaint(gr);
            }           
        };
        _middle = new VerticalFieldManager()
        {
            public void paint(Graphics graphics)
            {
                graphics.setBackgroundColor(0xFFFFFF);
                graphics.setColor(Color.BLACK);
                graphics.clear();
                super.paint(graphics);

            }
            protected void sublayout(int maxWidth, int maxHeight)
            {
                int displayWidth = Display.getWidth();
                int displayHeight = Display.getHeight();

                super.sublayout( displayWidth, displayHeight);
                setExtent( displayWidth, displayHeight);
            }  
        };

        add(_top);
        add(_middle);

        Bitmap lol = Bitmap.getBitmapResource("logo.png");
        BitmapField lolfield = new BitmapField(lol);
        _top.add(lolfield);

        Criteria cr= new Criteria();
        cr.setCostAllowed(true);
        cr.setPreferredResponseTime(60);
        cr.setHorizontalAccuracy(5000);
        cr.setVerticalAccuracy(5000);
        cr.setAltitudeRequired(true);
        cr.isSpeedAndCourseRequired();
        cr.isAddressInfoRequired();

        try{    
            LocationProvider lp = LocationProvider.getInstance(cr);
            if( lp!=null ){
                lp.setLocationListener(new LocationListenerImpl(), _interval, 1, 1); 
            }           
        }
        catch(LocationException le)
        {
            add(new RichTextField("Location exception "+le));
        }

        //_middle.add(new RichTextField("this is a map " + Double.toString(latitude) + " " + Double.toString(longitude)));
        int lat = (int) (latitude * 100000);
        int lon = (int) (longitude * 100000);
        String document = "<location-document>" + "<location lon='" + lon + "' lat='" + lat + "' label='You are here' description='You' zoom='0' />" + "<location lon='742733' lat='4373930' label='Hotel de Paris' description='Hotel de Paris' address='Palace du Casino' postalCode='98000' phone='37798063000' zoom='0' />" + "</location-document>";
       // Invoke.invokeApplication(Invoke.APP_TYPE_MAPS, new MapsArguments( MapsArguments.ARG_LOCATION_DOCUMENT, document));

        _middle.add(new SeparatorField());
        surroundingVenues();
        _middle.add(new RichTextField("max lat: " + max_lat));
        _middle.add(new RichTextField("min lat: " + min_lat));
        _middle.add(new RichTextField("max lon: " + max_lon));
        _middle.add(new RichTextField("min lon: " + min_lon));
    }

    private void surroundingVenues()
    {
        double point_1_latitude_in_degrees = latitude;
        double point_1_longitude_in_degrees= longitude;

        // diagonal distance +  error margin
        double distance_in_miles = (5 * 1.90359441) + 10;

        getCords (point_1_latitude_in_degrees, point_1_longitude_in_degrees, distance_in_miles, 45);
        double lat_limit_1 = latitude_in_degrees;
        double lon_limit_1 = longitude_in_degrees;

        getCords (point_1_latitude_in_degrees, point_1_longitude_in_degrees, distance_in_miles, 135);
        double lat_limit_2 = latitude_in_degrees;
        double lon_limit_2 = longitude_in_degrees;

        getCords (point_1_latitude_in_degrees, point_1_longitude_in_degrees, distance_in_miles, -135);
        double lat_limit_3 = latitude_in_degrees;
        double lon_limit_3 = longitude_in_degrees;

        getCords (point_1_latitude_in_degrees, point_1_longitude_in_degrees, distance_in_miles, -45);
        double lat_limit_4 = latitude_in_degrees;
        double lon_limit_4 = longitude_in_degrees;

        double mx1 = Math.max(lat_limit_1, lat_limit_2);
        double mx2 = Math.max(lat_limit_3, lat_limit_4);
        max_lat = Math.max(mx1, mx2);

        double mm1 = Math.min(lat_limit_1, lat_limit_2);
        double mm2 = Math.min(lat_limit_3, lat_limit_4);
        min_lat = Math.max(mm1, mm2);

        double mlon1 = Math.max(lon_limit_1, lon_limit_2);
        double mlon2 = Math.max(lon_limit_3, lon_limit_4);
        max_lon = Math.max(mlon1, mlon2);

        double minl1 = Math.min(lon_limit_1, lon_limit_2);
        double minl2 = Math.min(lon_limit_3, lon_limit_4);
        min_lon = Math.max(minl1, minl2);

        //$qry = "SELECT DISTINCT zip.zipcode, zip.latitude, zip.longitude, sg_stores.* FROM zip JOIN store_finder AS sg_stores ON sg_stores.zip=zip.zipcode WHERE zip.latitude<=$lat_limit_max AND zip.latitude>=$lat_limit_min AND zip.longitude<=$lon_limit_max AND zip.longitude>=$lon_limit_min";
    }

    private void getCords(double point_1_latitude, double point_1_longitude, double distance, int degs)
    {
        double m_EquatorialRadiusInMeters = 6366564.86; 
        double m_Flattening=0;

        double distance_in_meters   = distance * 1609.344 ;

        double direction_in_radians = Math.toRadians( degs );

        double eps = 0.000000000000005;

        double r = 1.0 - m_Flattening;

        double point_1_latitude_in_radians  = Math.toRadians( point_1_latitude   );
        double point_1_longitude_in_radians = Math.toRadians( point_1_longitude );

        double tangent_u = (r * Math.sin( point_1_latitude_in_radians ) ) / Math.cos( point_1_latitude_in_radians );

        double sine_of_direction = Math.sin( direction_in_radians );

        double cosine_of_direction = Math.cos( direction_in_radians );

        double heading_from_point_2_to_point_1_in_radians = 0.0;

        if ( cosine_of_direction != 0.0 )
        {
            heading_from_point_2_to_point_1_in_radians = atan2( tangent_u, cosine_of_direction ) * 2.0;
        }

             double cu = 1.0 / Math.sqrt( ( tangent_u * tangent_u ) + 1.0 );
             double su = tangent_u * cu;
             double sa = cu * sine_of_direction;
             double c2a = ( (-sa) * sa ) + 1.0;
            double x= Math.sqrt( ( ( ( 1.0 /r /r ) - 1.0 ) * c2a ) + 1.0 ) + 1.0;
           x= (x- 2.0 ) / x;
            double c= 1.0 - x;
           c= ( ( (x * x) / 4.0 ) + 1.0 ) / c;
            double d= ( ( 0.375 * (x * x) ) -1.0 ) * x;

         tangent_u = distance_in_meters /r / m_EquatorialRadiusInMeters /c;

            double y= tangent_u;

            boolean exit_loop = false;

            double cosine_of_y = 0.0;
            double cz          = 0.0;
            double e          = 0.0;
            double term_1      = 0.0;
            double term_2      = 0.0;
            double term_3      = 0.0;
            double sine_of_y   = 0.0;

            while( exit_loop != true )
            {
               sine_of_y = Math.sin(y);
              cosine_of_y = Math.cos(y);
              cz = Math.cos( heading_from_point_2_to_point_1_in_radians + y);
              e = (cz * cz * 2.0 ) - 1.0;
              c = y;
              x = e * cosine_of_y;
              y = (e + e) - 1.0;

              term_1 = ( sine_of_y * sine_of_y * 4.0 ) - 3.0;
              term_2 = ( ( term_1 * y * cz * d) / 6.0 ) + x;
              term_3 = ( ( term_2 * d) / 4.0 ) -cz;
              y= ( term_3 * sine_of_y * d) + tangent_u;

               if ( Math.abs(y - c) > eps )
               {
                  exit_loop = false;
               }
               else
               {
                  exit_loop = true;
               }
            }

            heading_from_point_2_to_point_1_in_radians = ( cu * cosine_of_y * cosine_of_direction ) - ( su * sine_of_y );

           c = r * Math.sqrt( ( sa * sa ) + ( heading_from_point_2_to_point_1_in_radians * heading_from_point_2_to_point_1_in_radians ) );
           d = ( su * cosine_of_y ) + ( cu * sine_of_y * cosine_of_direction );

           double point_2_latitude_in_radians = atan2(d, c);

           c = ( cu * cosine_of_y ) - ( su * sine_of_y * cosine_of_direction );
           x = atan2( sine_of_y * sine_of_direction, c);
           c = ( ( ( ( ( -3.0 * c2a ) + 4.0 ) * m_Flattening ) + 4.0 ) * c2a * m_Flattening ) / 16.0;
           d = ( ( ( (e * cosine_of_y * c) + cz ) * sine_of_y * c) + y) * sa;

           double point_2_longitude_in_radians = ( point_1_longitude_in_radians + x) - ( ( 1.0 - c) * d * m_Flattening );

           heading_from_point_2_to_point_1_in_radians = atan2( sa, heading_from_point_2_to_point_1_in_radians ) + Math.PI;

           latitude_in_degrees    = Math.toRadians( point_2_latitude_in_radians  );
           longitude_in_degrees = Math.toRadians( point_2_longitude_in_radians );

    }

    public double atan2(double y, double x) {
        double coeff_1 = Math.PI / 4d;
        double coeff_2 = 3d * coeff_1;
        double abs_y = Math.abs(y)+ 1e-10f;
        double r, angle;
        if (x >= 0d) {
            r = (x - abs_y) / (x + abs_y);
            angle = coeff_1;
        } else {
            r = (x + abs_y) / (abs_y - x);
            angle = coeff_2;
        }

        angle += (0.1963f * r * r - 0.9817f) * r;

        return y < 0.0f ? -angle : angle;
    }



    private Vector fetchVenues(double max_lat, double min_lat, double max_lon, double min_lon)
    {
        return new Vector();
    }

    private class LocationListenerImpl implements LocationListener { 
        public void locationUpdated(LocationProvider provider, Location location) {
            if(location.isValid()) {
                nearBy.this.longitude = location.getQualifiedCoordinates().getLongitude();
                nearBy.this.latitude = location.getQualifiedCoordinates().getLatitude();

                //double altitude = location.getQualifiedCoordinates().getAltitude();
                //float speed = location.getSpeed(); 
            }
        }

        public void providerStateChanged(LocationProvider provider, int newState) {
            // MUST implement this.  Should probably do something useful with it as well.
        }
    }




}

please excuse the mess. I have the user lat long hard coded since I do not have GPS functional yet. You can see the SQL query commented out to know how I plan on using the min and max lat and long values.

Any help is appreciated.

Thanks

© Stack Overflow or respective owner

Related posts about blackberry

Related posts about gps