Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Road name label density badly calculated based on text-size #6464

Open
watbywbarif opened this issue Apr 6, 2018 · 9 comments
Open

Road name label density badly calculated based on text-size #6464

watbywbarif opened this issue Apr 6, 2018 · 9 comments
Assignees
Labels

Comments

@watbywbarif
Copy link

v0.44.1 @ Chrome 65 @ Windows 10:

Steps to Trigger Behavior

  1. I have created custom map data and style in Casablanca, and as road name labels in Mapbox examples look bad in that area it can most likely be reproduced with your data also.
  2. I have excluded mostly every other layer for this to be more obvious.
  3. I keep everything as a constant, only thing that changes is text-size : stops for label layer.

Expected Behavior

image
with:

				"text-size": {
					"stops": [ 
						[ 12, 10 ],
						[ 19, 10 ],
						[ 20, 16 ]
					]
				}

Actual Behavior

Now i only change this:

                               "text-size": {
					"stops": [ 
						[ 12, 10 ],
						[ 14, 10 ],
						[ 20, 16 ]
					]
				}

And result is this:

image

How is this possible on zoom level 12, especially with stop [ 14, 10 ]?
And even better how does stop [ 19, 10 ], fixes this problem?
This is simplified example but this effect destroys map quality in certain areas of the globe where there are less POIs and other labels.

@mourner
Copy link
Member

mourner commented Apr 6, 2018

Can you please set up a minimal reproducible test case so that we could diagnose the issue? Also, you might want to set map.showCollisionBoxes = true to see what's going on.

@watbywbarif
Copy link
Author

@mourner
Copy link
Member

mourner commented Apr 6, 2018

Hmm, this looks not related to Mapbox GL — more likely an issue with how Mapbox Streets generalizes road labels on lower zoom levels. cc @ajashton

@watbywbarif
Copy link
Author

I am not sure what "generalizes labels means", but I have same behavior without Mapbox Studio, with my own data, tileset and style where all streets have name attribute, but only 1 in entire tile is displayed.
Crazy thing that changing stop which logically should not have impact on rendering on some level changes density. btw thanks for such fast reaction, did not expect this 👍

@ChrisLoer
Copy link
Contributor

How is this possible on zoom level 12, especially with stop [ 14, 10 ]?
And even better how does stop [ 19, 10 ], fixes this problem?

@watbywbarif That is indeed confusing behavior! The reason the seemingly-unrelated [ 19, 10 ] fixes the problem is that when we're doing layout is that our getAnchors function does its calculations based on a text-size that's always evaluated at zoom level 18. The evaluation happens here:

sizes.textMaxSize = unevaluatedLayoutValues['text-size'].possiblyEvaluate(new EvaluationParameters(18));

The reason we use zoom level 18 regardless of the actual zoom of the tile you're showing is that we want the "anchors" for road labels to show up in similar places as you move between zoom levels, even if the size of the text is changing. There's some discussion of this behavior as "case (4)" at #5683 (comment). In short, we think we should remove the behavior or change it, because it doesn't seem to work that well.

I suspect the reason you're seeing labels drop may be that this "max angle" check is failing:

if (!angleWindowSize || checkMaxAngle(line, anchor, labelLength, angleWindowSize, maxAngle)) {
anchors.push(anchor);
}

The angleWindowSize depends on the text-size at zoom 18, and effectively makes us stricter about how we enforce the text-max-angle style property. The default for that value is "45 degrees" and the docs say it's "the maximum angle change between adjacent characters", but in fact it's an approximation of that based on text-size.

The upshot of all this is that a promising workaround in your case may be to try setting text-max-angle to something higher like "90" to see if that solves the problem!

/cc @nickidlugash @ansis

@ChrisLoer
Copy link
Contributor

On the other hand, it's also possible that the labels are getting filtered out because there doesn't appear to be enough space for even a single label in the middle of the line:

// Check that the point is within the tile boundaries and that
// the label would fit before the beginning and end of the line
// if placed at this point.
if (x >= 0 && x < tileExtent && y >= 0 && y < tileExtent &&
markedDistance - halfLabelLength >= 0 &&
markedDistance + halfLabelLength <= lineLength) {

If that's the case, change text-max-angle won't help.

You could do something really crazy like adjust your zoom stops so the text is small (e.g. 10 point) at exactly zoom 18, but larger at zoom 17.99 and zoom 18.01. Then you could hook the map's zoom events to make it so that the map never actually rendered exactly zoom 18. But hopefully it doesn't come to that, because that's a crazy hack. 🤔

@mb12
Copy link

mb12 commented Apr 6, 2018

@ChrisLoer Is there some way to force the symbol layout engine to generate anchors for lines where the length of line is slightly smaller than the label (perhaps by using negative text-padding)? It would be useful to create a style similar to what the current waze application uses ('Rexford Way, 'Mansfield Dr', 'Princes Anne Dr' etc in the attached screenshot ).

img-0983

@ChrisLoer
Copy link
Contributor

@mb12 unfortunately, no: the relevant code is placeGlyphAlongLine in projection.js -- we use the actual road geometry for placing glyphs, and we hide the whole label if we can't place any one of the glyphs in the label. We'd have to explicitly add support for extrapolating the geometry past the end of the road.

@watbywbarif
Copy link
Author

I did play with text-max-angle even before posting this issue, but it was not nice. I even think that some letters overlapped one over another when angle was big enough.

One solution which I was thinking is to use fixed text-size in three to four size groups (small, ..., large). Then to use zoom level dependent filtering and move road classes between size groups from small to large. In that way i expect go get label size dependent on road importance and also to increase with zoom level. But now I guess it will be bad because the same reason you are using only one size to calculate placement. Labels will be "jumpy" :)

Now I can play and hack, but maybe there is some good solution for future versions.
I can suggest one: Try to calculate label placement in 2-3 steps incrementally. First time at text-size at zl 18 like you are doing now. But then if actual zl is 11-14 you do one more calculation using zl 14 text-size, but keep fixed results you have from zl 18. Any maybe once more same story when you get below zl 10.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants