Matt
Matt

Reputation: 3557

Circle overlay to map-distance conversion

I have a circular overlay that can change according to the user's preferences: they have a circle of radius 'r' around them and a slider can change 'r' accordingly. So far it works perfectly well.

My problem is I don't know how to find the proper conversion from the circle's radius to the map's metric. As an example, given the circle below, what is the distance covered with the given radius?

enter image description here

Upvotes: 0

Views: 378

Answers (3)

kurtzmarc
kurtzmarc

Reputation: 3137

I think what you're looking for is a meters-to-pixels calculation. You can get this from the projection:

// Get projection
Projection proj = mMapView.getProjection();
// How many pixels in 100 meters for this zoom level
float pixels = proj.metersToPixels(100);
// How many meters in 100 pixels for this zoom level
float meters = 1 / proj.metersToPixels(1 / 100);
// You could also get a raw meters-per-pixels value by using TileSystem.GroundResolution()

Two things to remember - this value will change not only based on what zoom level but based on what latitude you are at on the maps.

Upvotes: 0

Matt
Matt

Reputation: 3557

So here's how you do it...

Jedil is correct you have to find your screen width/height, the dpi of the screen, etc. So, looking through this old osmdroid source I sorta figured out this:

//Get the x and y dpi
this.xdpi = this.context.getResources().getDisplayMetrics().xdpi;
this.ydpi = this.context.getResources().getDisplayMetrics().ydpi;

//Get the screen width/height
this.screenWidth = this.context.getResources().getDisplayMetrics().widthPixels;
this.screenHeight = this.context.getResources().getDisplayMetrics().heightPixels;

 // DPI corrections for specific models
 String manufacturer = null;
 try {
       final Field field = android.os.Build.class.getField("MANUFACTURER");
        manufacturer = (String) field.get(null);
      } catch (final Exception ignore) {
      }

 if ("motorola".equals(manufacturer) && "DROIDX".equals(android.os.Build.MODEL)) {

 // If the screen is rotated, flip the x and y dpi values
 WindowManager windowManager = (WindowManager) this.context
                       .getSystemService(Context.WINDOW_SERVICE);
 if (windowManager.getDefaultDisplay().getOrientation() > 0) {
     this.xdpi = (float) (this.screenWidth / 3.75);
     this.ydpi = (float) (this.screenHeight / 2.1);
 } else {
       this.xdpi = (float) (this.screenWidth / 2.1);
       this.ydpi = (float) (this.screenHeight / 3.75);
 }

 } else if ("motorola".equals(manufacturer) && "Droid".equals(android.os.Build.MODEL)) {
     // http://www.mail-archive.com/[email protected]/msg109497.html
     this.xdpi = 264;
     this.ydpi = 264;
 }

 // set default max length to 1 inch
 maxLength = 2.54f;

That's how you get the 'constants' (at least in the device's eyes). To convert...

 // calculate dots per centimeter
 int xdpcm = (int) ((float) xdpi / 2.54);
 int ydpcm = (int) ((float) ydpi / 2.54);

 // get length in pixel
 int xLen = (int) (maxLength * xdpcm);
 int yLen = (int) (maxLength * ydpcm);


 // Two points, xLen apart, at scale bar screen location
 IGeoPoint p1 = projection.fromPixels((screenWidth / 2) - (xLen / 2), yOffset);
 IGeoPoint p2 = projection.fromPixels((screenWidth / 2) + (xLen / 2), yOffset);

 // get distance in meters between points
 final int xMeters = ((GeoPoint) p1).distanceTo(p2);

...and it's a similar, if not near-identical, matter to get the yMeters (hint: use screenHeight).

Admittedly, I'm not totally sure of what the lines IGeoPoint... are doing but I realize the conversion is there. Hoping this helps someone out in the future. For a better understanding of the above code, please see the link I've posted.

Upvotes: 0

michal.luszczuk
michal.luszczuk

Reputation: 2903

You must know what is the scale of the map you are showing. Having scale of the map you could convert pixels size to metric size. And having this proportion you can convert radius given in pixels to meters.

Upvotes: 1

Related Questions