qgis / QGIS

QGIS is a free, open source, cross platform (lin/win/mac) geographical information system (GIS)
https://qgis.org
GNU General Public License v2.0
10.58k stars 3k forks source link

QGIS 3 "Meters at Scale" incorrect behavior #26749

Closed qgib closed 3 years ago

qgib commented 6 years ago

Author Name: Mark Newbold (@dogfeathers) Original Redmine Issue: 18917 Affected QGIS version: 3.0.2 Redmine category:map_canvas


I tried using "Meters at Scale" to set the sizes of symbols in layer styles. I don't find "Meters at Scale" documented, but what I think it "should" do is set a size in actual meters (on the earth), independent of latitude and independent of CRS. I am finding that "Meters at Scale" does not equal actual meters and its behavior changes depending on the Project CRS, with scaling depending on latitude.

Steps to duplicate:

  1. Create a new QGIS project.
  2. Set the project CRS to WGS 84, EPSG:4326.
  3. Make a new temporary scratch layer with MultiLineString / MultiCurve geometry, with CRS of EPSG:4326 - WGS 84.
  4. Add a horizontal line feature near 48 degrees north latitude. Style the line as "Simple line" with a "Stroke width" of 100 "Meters at Scale".
  5. Zoom in on the line and measure its width with the Measure tool. It measures around 149.5 meters. Shouldn't it be 100 meters wide? The 149.5 meters width seems to be 100/cos(48°).
  6. Now, just for fun, change the project CRS to WGS 84 / Pseudo Mercator, EPSG:3857. When you hit "Apply", the line snaps to a smaller width, which measures as 66.8 meters. It went from too large to too small. The 66.8 meters width seems to be 100*cos(48°) -- now multiplied by the cosine rather than divided. I can't imagine that this kind of CRS dependence is correct behavior.

If I follow the above steps, but draw the line at the equator instead at 48 degrees north latitude, its width measures 100 meters, independent of project CRS.

I also tried it with point geometry, styled with a Simple marker -- a square symbol, sized at 100 "Meters at Scale". Same result.

Regards, --Mark

jekhor commented 4 years ago

Could someone prove that described behavior is incorrect? I want try to fix this, because 'real meters' symbol size is needed for me.

dogfeathers commented 4 years ago

Hi jekhor,

I am glad someone besides me is interested in this. Maybe you can find some documentation, or contact the person who wrote the code. Or inspect the code and identify a mistake. I hope you will be able to fix it. It would be very useful if it could represent actual meters on the surface of the earth.

Thanks, --Mark

jekhor commented 4 years ago

@mj10777, can you comment this please?

mj10777 commented 4 years ago

As far as I remember, the meters are based on the CRS (not independent of). For Lat, Long the default great-circle distance is used.

The goal was: on a map that is georeferenced in a specific CRS, that the meter size would be exact (if CRS in meters).

When switching to Wsg84 (in degrees) it would approximately the same.

The problem was if you set the default CRS and this is in meters, it would become (instead of 1 meter) 1 degree when switching to Wsg84.

jekhor commented 4 years ago

Sounds reasonable but if project use projected CRS where units are not meters really (for example, EPSG:3857 'WGS 84 / Pseudo-Mercator'), then symbols' size will be not in meters and still depended on selected project CRS. Maybe we can redefine behavior of this size option from "unit is real meter if the project CRS is geographic and the CRS unit if a projected CRS is used" to "unit size is real meter regardless of the selected project CRS"?

It looks more convenient and clear for me but will change existing user experience.

mj10777 commented 4 years ago

For me it would have been a desaster, because I needed the width as shown on the map.

The two fold goal was

Meter is a commen denominator., which can be calulated from other CSR's when needed.

Feet, Chains etc. are calculated to meters

A realistic meter on the ground can be calculated from the lat, long position. A pixel result for 1 meter is calculated, multiplied by the value set. That result is then used to paint. (its been quite a while, but this is how I remember it) .

roya0045 commented 3 years ago

Honestly, the code may be improved but this shouldn't be a bug. The suggested behavior makes no sense to me. Disregading CRS, lat and lot and use a magical 'true earth meter' is not a thing. I think this ticket should be closed or turned into a feature request that is impossible to do.

dogfeathers commented 3 years ago

roya0045 nobody here other than you has used the phrase 'true earth meter'. But please explain why you think there's something magical about realistic meters on the ground. --Mark

roya0045 commented 3 years ago

Do tell how do you calculate a meter on the ground without CRS and without taking into lat or long as you suggested. Also lets be honest this is a feature request not a bug.

dogfeathers commented 3 years ago

roya0045: This is about specifying the sizes of symbols in layer styles. How to calculate? Divide Mercator meters by the cosine of the latitude. You can do that regardless of the CRS. And the result is independent of lat/lon.

Feature vs bug? Depends whether "Meters at Scale", as presently coded, has any usefulness. I haven't found a use for it.

When I posted this "issue", I was wanting my QGIS project to use EPSG:4326 (lat/lon degrees) throughout. But, as I recall, QGIS couldn't handle the tiny fractions of a degree that were needed to create reasonable symbol sizes in the 50-100 meter range. So I ended up using EPSG:3857 (Mercator meters), even though that is less intuitive for me.

--Mark

dogfeathers commented 3 years ago

Feature vs bug? Depends whether "Meters at Scale", as presently coded, has any usefulness. Also its behavior should be what people would expect, based its name.

kannes commented 3 years ago

This is one of my pet peeves and a cause for confusion for both expert and non-expert users everywhere. See also https://github.com/openlayers/openlayers/pull/11926

For anyone but a pedantic geodesist 1 meter is clearly what a 1 meter ruler placed on the ground would equal to. I prefer to call the "other" meters "fake meters" :clown_face: ...

Map projections are distorted and while users should be aware of that, they should not be expected to know that this will trickle down to the meaning of units also being distorted.

This is a very hard problem but a greatly important one as people do use features like these without knowing what they do and this can have huge implications down the line. It is very similar to people buffering on geographic coordinates (https://disastermapping.wordpress.com/2012/12/06/possible-north-korea-missile-launch-next-week-so-how-close-is-10000km-anyways/, https://www.esri.com/news/arcuser/0111/geodesic.html)

richard-thomas commented 3 years ago

For anyone but a pedantic geodesist 1 meter is clearly what a 1 meter ruler placed on the ground would equal to.

Because the majority of freely available streamed raster base maps such as OpenStreetMap (e.g. looking in Quick Map Services) are in EPSG3857 (Web Mercator), projection I think this issue is much more than a question of semantics. If a user wants to dimension features by their measured dimensions (e.g. I am trying to represent pathways on a site which I measure as 0.8m wide), then there should be a way to define these as a centre-line geometry and set width in the layer symbology as 0.8m - without having to write an expression such as 0.8*fiddle_factor_for_current_latitude. (Yes I have indeed been driven to introduce such a global variable in some of my QGIS maps!)

It seems intuitive given the wording of the current documentation that just using width=0.8 "metres at scale" should do what I want: https://docs.qgis.org/testing/en/docs/user_manual/introduction/general_tools.html#unit-selector

"Meters at Scale: This allows you to always set the size in meters, regardless of what the underlying map units are (e.g. they can be in inches, feet, geographic degrees, …). The size in meters is calculated based on the current project ellipsoid setting and a projection of the distances in meters at the center of the current map extent."

This would also be consistent with the screen hints for the "Measure" tool which (in QGIS 3.18) in Default "ellipsoidal" mode even if I set ellipsoid to "WGS84 (EPSG7030)" (rather than a more locally specific one) gives the expected measurement. It specifies:

"The coordinates are transformed to the chosen ellipsoid (EPSG:7030) and the distance is calculated in meters" And this does indeed measure an aerial photo of a 0.8m wide path on the ground as being 0.8m wide.

Hence, even if QGIS behaviour is to remain unchanged, the current documentation / screen hints are currently misleading and should be modified. I can understand that adjusting feature dimensions displayed across a wide range of latitudes (such as the 2000km circles around Greenland in the openlayers example above) could be difficult to implement. However, adjusting them (as described above for the "Measure" tool) based on "distance in meters at the center of the current map extent" would be so much more useful (and more consistent) than the current behaviour.

nyalldawson commented 3 years ago

@dogfeathers

I am glad someone besides me is interested in this. Maybe you can find some documentation, or contact the person who wrote the code. Or inspect the code and identify a mistake. I hope you will be able to fix it. It would be very useful if it could represent actual meters on the surface of the earth.

stepping back from the rest of the discussion here -- there's an easy answer to your question: the size is calculated based on a VERTICAL distance, not horizontal. Draw a vertical line instead of a horizontal one, measure it, and you'll see the result is exactly 100m wide.

Consequently I'm closing this ticket as a "wont fix", with the solution being to use a projected coordinate system for your map.

kannes commented 3 years ago

Should the option be disabled on non-projected CRS then maybe? I would love it if QGIS has as few trip holes as possible and this is a big one.

nyalldawson commented 3 years ago

@kannes

I'd propose instead showing a little help ? icon next to the option, with a tooltip stating something like "calculates map sizes in meters based on the current map scale. For maps in a projected coordinate system this is calculated using projected units. For maps in a geographic (latitude/longitude) based system the size is approximated by calculating meter sizes using ellipsoidal calculations for the vertical scale of the map."

kannes commented 3 years ago

Oh that would be nice! One problem I see though is that CRS like EPSG:3857 are projected (I glanced over that for a moment in my previous comment) but their meters aren't really (SI) meters and that they are of variable length within the same map canvas. Of course that's true for many many systems in varying degree (pun intended!).

Where exactly is the "sample" for the length calculation (or scale) taken? Maybe that would be a good addition to the note (e. g. "sampled at the center of the map canvas"). Now that I think about it, this would be a good tooltip on the map scale label as well.

GIS is hard :|

mj10777 commented 3 years ago

@kannes Are you asking where in the code it is being done (I don't remember) or how it is being done?

As far as I remember, when a meter, foot etc. value was not available (lat,long projection):


One question would be, what projection is the Measure tool using when it returns 149.5 meters?

If it is the Haversin formula (the great-circle distance), then it should not be surprising that there is a ratical difference.