1

I use the mapViewer from the example of https://docs.geotools.org/latest/userguide/tutorial/map/style.html

I would like to present the current scale (it's works ok in projected CRS), when I set WGS 84 in as map window CRS I'm calculating the scale with the distance in meters that I get from this (QGIS) function:

    private static double calculateGeographicDistance( ReferencedEnvelope mapRectangle) {
    // need to calculate the x distance in meters
    // We'll use the middle latitude for the calculation
    // Note this is an approximation (although very close) but calculating scale
    // for geographic data over large extents is quasi-meaningless
    // The distance between two points on a sphere can be estimated
    // using the Haversine formula. This gives the shortest distance
    // between two points on the sphere. However, what we're after is
    // the distance from the left of the given extent and the right of
    // it. This is not necessarily the shortest distance between two
    // points on a sphere.
    //
    // The code below uses the Haversine formula, but with some changes
    // to cope with the above problem, and also to deal with the extent
    // possibly extending beyond +/-180 degrees:
    //
    // - Use the Halversine formula to calculate the distance from -90 to
    // +90 degrees at the mean latitude.
    // - Scale this distance by the number of degrees between
    // mapRectangle.xMinimum() and mapRectangle.xMaximum();
    // - For a slight improvement, allow for the ellipsoid shape of earth.
    // For a longitude change of 180 degrees
        double lat = (mapRectangle.getMaxY() + mapRectangle.getMinY()) * 0.5;
        double rads = (4.0 * Math.atan(1.0)) / 180.0;
        double a = Math.pow(Math.cos(lat * rads), 2);
        double c = 2.0 * Math.atan2(Math.sqrt(a), Math.sqrt(1.0 - a));
        double ra = 6378000; // [m]
        // The eccentricity. This comes from sqrt(1.0 - rb*rb/(ra*ra)) with rb set
        // to 6357000 m.
        double e = 0.0810820288;
        double radius = ra * (1.0 - e * e) / Math.pow(1.0 - e * e * Math.sin(lat * rads) * 
        Math.sin(lat * rads), 1.5);
        double meters = (mapRectangle.getMaxX() - mapRectangle.getMinX()) / 180.0 * radius * c;
        return meters;
}

Then when I set the Rule of a layer that it should be shown from scale 1:1 to 1:100 000 it works fine when the map window is defined in UTM 33N. When I set WGS84 as the CRS for the map window, the layer turns on/off at the scale (my calculated scale, that I'm presenting) 1:30 000.

Somewere the map application is calculating the map scale since it turns on/off the layer when the scale reaches 1:100 000 (some internal scale calculated by the map application), but when this threshold is reached I'm calculating the scale to 1:30 000.

Shall I calculate the scale (for presentation) in another way? How is the scale calculated internally in the map application, and can I get the hold of this "internal" scale?

5
  • Geotools uses the OGC scale and pixel size of 96dpi, when you are using wgs84 the scale will be in pixels per degree so there will be no metres involved
    – Ian Turton
    Commented May 11, 2022 at 7:39
  • How can I read out this scale?
    – Paul
    Commented May 11, 2022 at 7:58
  • degrees = (mapRectangle.getMaxX() - mapRectangle.getMinX()); int screenWidthInPix = mapFrame.getMapPane().getBounds().width; scale = (double) screenWidthInpix/degrees; // where shall I use pixel size??
    – Paul
    Commented May 11, 2022 at 8:33
  • This did the trick! degrees = (mapRectangle.getMaxX() - mapRectangle.getMinX()); Map hints = new HashMap(); hints.put("dps", 96); double scale = RendererUtilities.calculateOGCScale(mapRectangle, canvasWidth, hints);
    – Paul
    Commented May 11, 2022 at 9:54
  • Add that as the answer
    – Ian Turton
    Commented May 11, 2022 at 10:14

1 Answer 1

2

This seems to show a much more correct scale in WGS 84, it doesn't change while paning though.

degrees = (mapRectangle.getMaxX() - mapRectangle.getMinX()); 
Map hints = new HashMap(); 
hints.put("dps", 96); 
double scale = RendererUtilities.calculateOGCScale(mapRectangle, canvasWidth, hints); 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.