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

Support for highway=track #717

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
7 changes: 7 additions & 0 deletions scripts/taginfo_template.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@
"description": "Major roads under construction have a dotted line pattern and a more prominent color.",
"doc_url": "https://openmaptiles.org/schema/#transportation"
},
{
"key": "highway",
"value": "track",
"object_types": ["way"],
"description": "Track roads have a two-track line pattern that is dashed if unpaved and solid if paved.",
"doc_url": "https://openmaptiles.org/schema/#transportation"
},
Copy link
Member

Choose a reason for hiding this comment

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

Also add an entry for ford=yes, as well as a second entry for surface that describes the stylistic variation on tracks.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for the feedback. Added these taginfo entries in ab1e133.

{
"key": "railway",
"value": "rail",
Expand Down
2 changes: 2 additions & 0 deletions src/js/legend_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as PlaceLayers from "../layer/place.js";
import * as LanduseLayers from "../layer/landuse.js";
import * as BoundaryLayers from "../layer/boundary.js";
import * as RoadLayers from "../layer/road.js";
import * as TrackLayers from "../layer/track.js";
import * as ConstructionLayers from "../layer/construction.js";
import * as HighwayExitLayers from "../layer/highway_exit.js";
import * as RailLayers from "../layer/rail.js";
Expand All @@ -27,6 +28,7 @@ export const sections = [
name: "Roads",
entries: [
...RoadLayers.legendEntries,
...TrackLayers.legendEntries,
...ConstructionLayers.legendEntries,
...HighwayExitLayers.legendEntries,
],
Expand Down
10 changes: 10 additions & 0 deletions src/layer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as lyrPlace from "./place.js";
import * as lyrPoi from "./poi.js";
import * as lyrRail from "./rail.js";
import * as lyrRoad from "./road.js";
import * as lyrTrack from "./track.js";
import * as lyrTransportationLabel from "./transportation_label.js";
import * as lyrWater from "./water.js";
import * as lyrBuilding from "./building.js";
Expand Down Expand Up @@ -86,6 +87,9 @@ export function build(locales) {
lyrAeroway.taxiway,
lyrAeroway.taxiwayArea,

lyrTrack.track,
lyrTrack.pavedTrack,

lyrRoad.motorwayLink.casing(),
lyrRoad.trunkLink.casing(),

Expand Down Expand Up @@ -143,6 +147,9 @@ export function build(locales) {
var bridgeLayers = [
lyrRail.bridgeCasing,

lyrTrack.bridgeCasing,
lyrTrack.bridgeFill,

lyrRoad.trunkLinkBridge.casing(),
lyrRoad.motorwayLinkBridge.casing(),

Expand Down Expand Up @@ -178,6 +185,9 @@ export function build(locales) {

lyrRoad.roadBridge.surface(),

lyrTrack.trackBridge,
lyrTrack.pavedTrackBridge,

lyrRail.railBridge.dashes(),
lyrRail.railServiceBridge.dashes(),

Expand Down
147 changes: 147 additions & 0 deletions src/layer/track.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
"use strict";

import * as Color from "../constants/color.js";

const trackSelect = ["==", ["get", "class"], "track"];
const unpavedSelect = ["!=", ["get", "surface"], "paved"];
const pavedSelect = ["==", ["get", "surface"], "paved"];
const bridgeSelect = ["==", ["get", "brunnel"], "bridge"];
const fordSelect = ["==", ["get", "brunnel"], "ford"];
const notFordSelect = ["!=", ["get", "brunnel"], "ford"];
const opacity = ["interpolate", ["exponential", 1.2], ["zoom"], 12, 0, 13, 1];
const getBrunnel = ["get", "brunnel"];

export const track = {
id: "highway-track",
type: "line",
source: "openmaptiles",
"source-layer": "transportation",
filter: ["all", trackSelect, unpavedSelect],
minzoom: 12,
paint: {
"line-color": ["match", getBrunnel, "ford", Color.waterLine, "#d4b791"],
"line-opacity": opacity,
"line-blur": 0.75,
"line-width": 0.5,
"line-dasharray": [12, 3],
"line-offset": 0,
"line-gap-width": [
"interpolate",
["exponential", 1.2],
["zoom"],
13,
0.7,
20,
6,
],
},
};

export const pavedTrack = {
id: "highway-track-paved",
type: "line",
source: "openmaptiles",
"source-layer": "transportation",
filter: ["all", trackSelect, pavedSelect],
minzoom: 12,
paint: { ...track.paint },
};
pavedTrack["paint"]["line-dasharray"] = [1, 0];

export const trackBridge = {
id: "highway-track-bridge",
type: "line",
source: "openmaptiles",
"source-layer": "transportation",
filter: ["all", trackSelect, unpavedSelect, bridgeSelect],
minzoom: 12,
paint: { ...track.paint },
};

export const pavedTrackBridge = {
id: "highway-track-paved-bridge",
type: "line",
source: "openmaptiles",
"source-layer": "transportation",
filter: ["all", trackSelect, pavedSelect, bridgeSelect],
minzoom: 12,
paint: { ...pavedTrack.paint },
};

// Bridge casing layers
export const bridgeCasing = {
id: "track-bridge-casing",
type: "line",
source: "openmaptiles",
"source-layer": "transportation",
filter: ["all", bridgeSelect, trackSelect],
minzoom: 13,
layout: {
"line-cap": "butt",
"line-join": "bevel",
visibility: "visible",
},
paint: {
"line-color": "black",
"line-opacity": opacity,
"line-width": [
"interpolate",
["exponential", 1.2],
["zoom"],
13,
1.1,
20,
11,
],
},
};
// Bridge casing layers
export const bridgeFill = {
id: "track-bridge-fill",
type: "line",
source: "openmaptiles",
"source-layer": "transportation",
filter: ["all", bridgeSelect, trackSelect],
minzoom: 13,
layout: {
"line-cap": "butt",
"line-join": "bevel",
visibility: "visible",
},
paint: {
"line-color": Color.backgroundFill,
"line-opacity": opacity,
"line-width": [
"interpolate",
["exponential", 1.2],
["zoom"],
13,
1.0,
20,
10,
],
},
};

export const legendEntries = [
{
description: "Land access track",
Copy link
Member

Choose a reason for hiding this comment

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

This diplomatic wording is more appropriate in contexts like id-tagging-schema and the OSM Wiki, where it’s important for mappers to apply the right tag and not apply the wrong tag. But we have much more latitude in a legend, where the reader just has to get the gist of what distinguishes this entry from the ones above it. For comparison, the entry for expressways condenses an entire highly technical wiki article into just a few words. That’s what you’ve done here, but out of context, “land access” raises more questions than it answers.

In my opinion, even a description as simple as “Unpaved track” or “Unpaved off-road track” would suffice. I don’t think the reader would be left with the impression that they’re looking at running tracks or railroad tracks (which has its own section). Many print maps say things like “Vehicle tracks” or “4×4 tracks”, but we aren’t distinguishing by mode of transportation here.

Copy link
Member

Choose a reason for hiding this comment

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

"track" isn't really a word we use for that here though. The closest American-ism is a "two-track road" in my vernacular.

Copy link
Member

Choose a reason for hiding this comment

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

“Track” or “tracks” is a word in American English. It’s more general than highway=track (e.g., train tracks, farm tracks, animal tracks), but still close enough that the reader would not be mislead by seeing these lines described as tracks. As a preset name, it would cause mappers to dilute the tag, but dilution doesn’t happen quite like that with a map legend.

Part of the reason we’re in this quandary is that conventional transportation maps don’t even distinguish this notion of a highway=track. They do distinguish local roads by surface or access with captions like “unpaved local road” or “trail”, or they omit them from the map in the first place.

Utah DOT 2007 Hallwag California NMDOT 2010 compact Clermont County Engineer (Engels) 2004 Arizona Office of Tourism 2021

This outdoors-oriented atlas exemplifies the kitchen-sink approach:

Benchmark Arizona

* Other roads in urban areas are typically paved public streets. In rural areas they include local back roads, rough 4WD routes, private roads, and logging roads. Some of these roads are usable, but others are closed to public use, or seasonally impassable, or both. Inquire locally before attempting to drive “Other Roads.”

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for the feedback. Shortened to Unpaved track and Paved track in 15a832e.

layers: [track.id],
filter: notFordSelect,
},
{
description: "Land access track - ford",
Copy link
Member

Choose a reason for hiding this comment

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

So far we’ve omitted brunnels from the legend because taking them out of context can be confusing. (A road bridge, for one thing, looks just like a normal road on its own.) We’d need to add some functionality to the legend to place another linear feature across the spotlighted feature. But I think the ford treatment you’ve implemented looks intuitive enough on its own.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

For now I've left the ford-specific legend entries to avoid the case of ford-styling ending up in the legend when both unpaved ford and non-ford are present (such as at this location) as well as allow a concrete ford surrounded by unpaved tracks to get an entry noting that it is paved (such as at this location). Maybe this isn't ideal, but dropping any filters and sometimes showing blue for tracks felt particularly wrong.

Copy link
Member

Choose a reason for hiding this comment

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

I certainly agree with filtering out fords from the general track entries, but in the absence of the crossing lines capability I described above, it’s probably less confusing overall to omit any entries about the fords.

The main issue is actually that the legend is depicting the track as a single dashed line, whereas it’s actually two parallel lines. I assume that’s because it doesn’t honor the line-offset and line-gap-width properties. If we fix that, then at least the ford entry won’t look like an intermittent creek.

If we keep the ford entries around, we might be able to combine them into one entry. There are other examples where we avoided breaking out combinations of attributes – for example, there’s only one expressway entry, even though multiple classes of roads that render differently can be expressways. This works because the entry clearly is about a particular aspect of the line, not trying to visually represent every possible expressway.

Copy link
Member

Choose a reason for hiding this comment

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

#770 tracks the incorrect implementation of line-gap-width in the legend.

layers: [track.id],
filter: fordSelect,
},
{
description: "Paved land access track",
layers: [pavedTrack.id],
filter: notFordSelect,
},
{
description: "Paved land access track - ford",
layers: [pavedTrack.id],
filter: fordSelect,
},
];
2 changes: 1 addition & 1 deletion src/layer/transportation_label.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const highwaySelector = ["match", ["get", "class"]];
const motorwayToTrunk = ["motorway", "trunk"];
const motorwayToPrimary = [...motorwayToTrunk, "primary"];
const motorwayToSecondary = [...motorwayToPrimary, "secondary"];
const motorwayToMinor = [...motorwayToSecondary, "tertiary", "minor"];
const motorwayToMinor = [...motorwayToSecondary, "tertiary", "minor", "track"];
const motorwayToService = [...motorwayToMinor, "service"];

const majorConstruction = ["motorway_construction", "trunk_construction"];
Expand Down