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

Don't use ceremonial name when way is interstate #291

Closed
wants to merge 6 commits into from
Closed

Conversation

bsudekum
Copy link
Contributor

In cases where the user is coming up to a highway, we should not show the ceremonial highway name.

What should the text say? Right now it says US-280 and also shows the shield image.

/cc @1ec5 @frederoni @ericrwolfe

@bsudekum bsudekum added the ⚠️ DO NOT MERGE PR should not be merged! label Jun 20, 2017
@frederoni
Copy link
Contributor

What should the text say?

This is unclear to me as well. We should add a snapshot test for this case when we figured out what the correct way is.

@@ -119,7 +119,11 @@ class RouteManeuverViewController: UIViewController {

public func updateStreetNameForStep() {
if let name = step?.names?.first {
streetLabel.unabridgedText = name
if let step = step, let ref = step.codes?.first, ["i", "us"].contains(ref.lowercased().components(separatedBy: " ").first!) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we’re on solid footing with Interstates, but I’m not so sure about doing this for U.S. highways. Sure, a few like U.S. 1 and U.S. 101 are freeways in some places, but not in others, and the vast majority are surface streets where the name matters more. (Think Van Ness in San Francisco or Constitution Ave. NW in D.C.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

screen shot 2017-06-20 at 2 29 34 pm

Could we filter and display the US-101 for segments of type `highway` and use the ceremonial name in other cases? `Redwood Highway` in this screenshot is confusing, but to your point the other street names should show their proper names.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, the Directions API doesn’t provide any information about the “type” of a road segment. #297 for example must query the map’s vector tiles for this information, but it can only do so for features currently visible on the map, not roads that may be far out of view.

@@ -119,7 +119,11 @@ class RouteManeuverViewController: UIViewController {

public func updateStreetNameForStep() {
if let name = step?.names?.first {
streetLabel.unabridgedText = name
if let step = step, let ref = step.codes?.first, ["i", "us"].contains(ref.lowercased().components(separatedBy: " ").first!) {
Copy link
Contributor

@1ec5 1ec5 Jun 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be a bit simpler: let ref = step.codes?.first, ref.hasPrefix("I ").

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@1ec5 this does not account for ref.hasPrefix("US ") though. contains allows us to add more cases to this array.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn’t unconditionally remove the name from U.S. Routes. See #291 (comment). But I agree with this approach if we end up needing to remove the name from multiple networks.

@@ -119,7 +119,11 @@ class RouteManeuverViewController: UIViewController {

public func updateStreetNameForStep() {
if let name = step?.names?.first {
streetLabel.unabridgedText = name
if let step = step, let ref = step.codes?.first, ["i", "us"].contains(ref.lowercased().components(separatedBy: " ").first!) {
streetLabel.unabridgedText = ref.components(separatedBy: " ").joined(separator: "-")
Copy link
Contributor

@1ec5 1ec5 Jun 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

U.S. Routes are written “US 123” in most states. Only a few states like Oklahoma and Kansas hyphenate them.

@@ -119,7 +119,11 @@ class RouteManeuverViewController: UIViewController {

public func updateStreetNameForStep() {
if let name = step?.names?.first {
streetLabel.unabridgedText = name
if let step = step, let ref = step.codes?.first, ["i", "us"].contains(ref.lowercased().components(separatedBy: " ").first!) {
streetLabel.unabridgedText = ref.components(separatedBy: " ").joined(separator: "-")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we try to fall back to the step’s destinations, since the shield will already be visible to the right?

@ericrwolfe
Copy link
Contributor

Eventually we should show the highway icon + the direction ( East), but until we can scoot the highway icon to the left, let's just show text on the left plus the highway icon on the right as is currently implemented.

Ultimately, we want our turn banner to match the highway sign overhead as closely as possible, so the banner text should take the following order of precedence, when the appropriate data is available:

  • I-5 S / Los Angeles: always show direction + destination when available
  • I-5 South: always show direction when available
  • I-5: Fallback if no other data is available

Voice announcements should take similar levels of precedence:

  • I 5 South towards Los Angeles
  • I 5 South
  • I 5

We should also take care to combine/coalesce maneuvers where the highway ref stays the same but only the ceremonial name changes.

Per #291 (comment), can we check the road class for highway or motorway before displaying the highway ref and fall back to the ceremonial name for smaller streets?

@1ec5
Copy link
Contributor

1ec5 commented Jun 20, 2017

Given the limited information we get from the Directions API, I think we can only address the Interstate case reliably. If we show both the name and shield for a U.S. Route that’s a freeway, there’s a chance that we’d look pedantic, but at least we wouldn’t be hiding any information that might be required for wayfinding.

@1ec5
Copy link
Contributor

1ec5 commented Jun 20, 2017

It’s a bit less reliable, but the other approach I mentioned in Project-OSRM/osrm-text-instructions#51 (comment) would also be feasible: the step’s expected distance divided by expected duration yields an average expected speed. If the speed is at least 50 mph (or the equivalent in metric), treat the way as a freeway. The reason it’s less reliable is that traffic-aware directions might (correctly) increase the expected duration along a congested highway, causing the speed to drop below freeway speed.

@ericrwolfe
Copy link
Contributor

I'm game for speed as a proxy/hack to road class until we can get more detailed responses back from the directions API or OSRMTextInstructions.

@ericrwolfe
Copy link
Contributor

Having highway shields inline like we used to do would be the preferred approach, except with the shields on the left and with a direction suffix and destination <I-5> S / Los Angeles instead of the ceremonial name at highway speeds.

One of the most important points in fixing this issue is adding a direction suffix and destination information when available. It's common to see highways where both directions are served by the same initial offramp, and our current ceremonial name approach does a poor job differentiating those.

Here's some logic we've used in the past to estimate if the current step is a highway:

let speed = currentStep.distance / currentStep.expectedTravelTime
// Convert 47.5mph to m/s 
if speed > 47.5 * 1609.344 / 3600.0 {
}

In the case of the ambiguous us prefix, we could default to the following logic (<> indicates an inline shield):

  • <US-101> N / Portland: highway speeds: always show direction + destination when available
  • <US-101> North: highway speeds: always show direction when available
  • Van Ness Ave <US-101>: local speeds: use name + show the highway shield inlined to the right
  • <US-101> Van Ness Ave: Fallback: highway shield on the left, ceremonial name on the right

@1ec5
Copy link
Contributor

1ec5 commented Jun 21, 2017

One of the most important points in fixing this issue is adding a direction suffix and destination information when available.

I think this may rely on one of the more fragile parts of the exit tagging scheme. OSM has specific, structured tags for destination refs, but there's no dedicated tag for the direction. (This information is encoded in route relations, but OSRM lacks the ability to process relations.) So mappers have generally taken to saying "US 101 North" as the ref. Anything that requires string munging on our end will have uneven reliability: consider that the direction is usually given as a suffix in California, whereas it may be given as a prefix in other parts of the U.S. due to differing signage standards.


if let destinations = step?.destinations {
let dest = destinations.prefix(min(streetLabelLines, destinations.count)).joined(separator: "\n")
streetLabel.unabridgedText = stepRef != nil ? "\(String(describing: stepRef)) - \(dest)" : dest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could result in a string like:

Optional(I) - Mobile
Biloxi

@bsudekum bsudekum removed the ⚠️ DO NOT MERGE PR should not be merged! label Jun 23, 2017
streetLabel.unabridgedText = stepRef != nil ? "\(String(describing: stepRef)) - \(dest)" : dest

if let stepRef = stepRef {
streetLabel.unabridgedText = "\(String(describing: stepRef)) - \(dest)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stepRef is already a String; no need to create a new string out of it.

streetLabel.unabridgedText = stepRef != nil ? "\(String(describing: stepRef)) - \(dest)" : dest

if let stepRef = stepRef {
streetLabel.unabridgedText = "\(String(describing: stepRef)) - \(dest)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with #291 (comment) that / would be a more aesthetically pleasing delimiter than -.

@bsudekum
Copy link
Contributor Author

bsudekum commented Jul 6, 2017

@1ec5 I think this ready to go.

} else if let destinations = step?.destinations {
destinationLabel.unabridgedText = destinations.prefix(min(numberOfDestinationLines, destinations.count)).joined(separator: "\n")
var stepRef: String?
if let step = step, let ref = step.codes?.first, ["i", "us"].contains(ref.lowercased().components(separatedBy: " ").first!) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't remove the name from all U.S. routes. That would be a severe usability regression, because the vast majority of U.S. routes are surface streets, and in urban areas they're much more likely to be identified by name than by route number.

A proper solution to this problem appears to be coming soon in Project-OSRM/osrm-text-instructions#51, based on Project-OSRM/osrm-backend#4204. If we can't wait until then to solve the relatively few cases of U.S. routes on freeways, then we should only omit the name of a U.S. route if it contains the word "freeway", "expressway", or "highway".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't wait until then to solve the relatively few cases of U.S. routes on freeways, then we should only omit the name of a U.S. route if it contains the word "freeway", "expressway", or "highway".

I'm game for this approach 😃 @bsudekum.

@bsudekum
Copy link
Contributor Author

@1ec5 @ericrwolfe updated this, now:

  • We prioritize destination over name
  • If there is no destination but there is a name with one of the keywords, use the ref
  • If not, use the name.

@bsudekum
Copy link
Contributor Author

I played around with getting the voice instructions to follow this logic as well. It looks like this will require a change to osrm-text-instructions.

@bsudekum
Copy link
Contributor Author

@1ec5 updated this to attempt to change the bottom label to be consistent with the maneuver text.

I'm finding it difficult to to go from 280 to I-280 though.

Bobby Sudekum added 2 commits July 18, 2017 14:43
<key>us-highway-duplex</key>
<string>US</string>
<key>us-highway-alternate</key>
<string>US</string>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given:

shield: us-highway-alternate
ref: 50

the label will incorrectly say “US 50”, whereas it would be more accurate to say “US 50 Alt” or “Alt US 50”. Same for the other banners below.


var isFreeway: Bool {
return self.components(separatedBy: " ").filter {
["freeway", "expressway", "highway", "fwy", "hwy"].contains($0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Mapbox Streets source abbreviates “expressway” as “Expy”.

@@ -28,4 +25,10 @@ extension String {
("'", "&apos;")
])
}

var isFreeway: Bool {
return self.components(separatedBy: " ").filter {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: drop self..

@1ec5
Copy link
Contributor

1ec5 commented Jul 18, 2017

#291 (comment):

A proper solution to this problem appears to be coming soon in Project-OSRM/osrm-text-instructions#51, based on Project-OSRM/osrm-backend#4204.

Underlying support for this feature is happening in mapbox/mapbox-directions-swift#154 and will also require changes to OSRM Text Instructions in Swift.

} else {
currentName = nil
}
}
}
}

if smallestLabelDistance < 5 && currentName != nil {
if smallestLabelDistance < 10 && currentName != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, nope.

if let highwayName = HighwayNamesByPrefix[shield] {
currentName = "\(highwayName) \(ref)"
} else {
currentName = ref
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For any country outside the U.S., this logic would display only the number. Even inside the U.S., something like a county road would get just the number, which is opposite what I would expect. I think it would be preferable in all these cases to either show the name and number or to show nothing at all.

@1ec5
Copy link
Contributor

1ec5 commented Jul 21, 2017

#410 is an alternative to this PR, at least as far as the turn banner is concerned. We can pick this PR back up later to deal with the current road name label, but I don’t think it’s a huge deal compared to the turn banner, since the base map also displays freeway names.

@bsudekum
Copy link
Contributor Author

Let's close this out. A followup PR will most likely go in another direction than the one started here.

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

Successfully merging this pull request may close these issues.

4 participants