diff --git a/PYDANTIC_GUIDE.md b/PYDANTIC_GUIDE.md
index 4571b2afe..a7748315c 100644
--- a/PYDANTIC_GUIDE.md
+++ b/PYDANTIC_GUIDE.md
@@ -836,7 +836,7 @@ class RoadSegment(TransportationSegment):
speed_limits: SpeedLimits | None = None
def get_speed_limit(self) -> float:
- return self.speed_limits.max_speed if self.speed_limits else 50.0
+ return self.speed_limits.speed if self.speed_limits else 50.0
# Now only concrete classes can be instantiated
# base_segment = TransportationSegment(...) # TypeError: Can't instantiate abstract class
diff --git a/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-bad-type.yaml b/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-bad-type.yaml
new file mode 100644
index 000000000..38c1a773f
--- /dev/null
+++ b/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-bad-type.yaml
@@ -0,0 +1,19 @@
+---
+id: road segment where road.restrictions.speed_limits contains a rule with an invalid type
+type: Feature
+geometry:
+ type: LineString
+ coordinates: [[0, 0], [1, 1]]
+properties:
+ ext_expected_errors:
+ - "[S#/$defs/propertyDefinitions/speedLimitType/enum]: value must be one of"
+ theme: transportation
+ type: segment
+ version: 1
+ subtype: road
+ class: secondary
+ speed_limits:
+ - type: recommended
+ speed:
+ value: 110
+ unit: mph
diff --git a/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-empty-rule.json b/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-empty-rule.json
index 833e57006..de732a0e8 100644
--- a/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-empty-rule.json
+++ b/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-empty-rule.json
@@ -15,8 +15,7 @@
{}
],
"ext_expected_errors": [
- "anyOf/0/required]: missing property 'min_speed'",
- "anyOf/1/required]: missing property 'max_speed'"
+ "required]: missing properties 'type', 'speed'"
]
}
}
diff --git a/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-mode.yaml b/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-mode.yaml
index 4358421ee..cb50610bb 100644
--- a/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-mode.yaml
+++ b/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-mode.yaml
@@ -21,7 +21,8 @@ properties:
- connector_id: barConnector
at: 1
speed_limits:
- - max_speed:
+ - type: maximum
+ speed:
value: 110
unit: mph
when: {mode: [foo]}
diff --git a/docs/schema/concepts/by-theme/transportation/roads.mdx b/docs/schema/concepts/by-theme/transportation/roads.mdx
index 5b4cb234e..c6ea596b0 100644
--- a/docs/schema/concepts/by-theme/transportation/roads.mdx
+++ b/docs/schema/concepts/by-theme/transportation/roads.mdx
@@ -14,6 +14,7 @@ import ExampleAccessRestrictionAxleLimit from '!!raw-loader!@site/docs/_examples
import ExampleSpeedLimitsSimple from '!!raw-loader!@site/docs/_examples/transportation/docusaurus/speed-limits-01-simple.yaml';
import ExampleSpeedLimitsDirectional from '!!raw-loader!@site/docs/_examples/transportation/docusaurus/speed-limits-02-directional.yaml';
import ExampleSpeedLimitsVariableMax from '!!raw-loader!@site/docs/_examples/transportation/docusaurus/speed-limits-03-variable-max.yaml';
+import ExampleSpeedLimitsAdvisory from '!!raw-loader!@site/docs/_examples/transportation/docusaurus/speed-limits-04-advisory.yaml';
import ExampleTurnRestriction1Source from '!!raw-loader!@site/docs/_examples/transportation/docusaurus/turn-restriction-01-source.yaml';
import ExampleTurnRestriction1Target from '!!raw-loader!@site/docs/_examples/transportation/docusaurus/turn-restriction-01-target.yaml';
import ExampleTurnRestriction1Exit from '!!raw-loader!@site/docs/_examples/transportation/docusaurus/turn-restriction-01-exit.yaml';
@@ -272,9 +273,13 @@ real-world context to the example.*
### Speed limits
Speed limits restrict the speed at which travel is permitted on a road.
-Typically speed limits specify maximum allowed speeds, but the
-Overture also allows minimum speed limits to be set and variable speed
-corridors to be indicated.
+Each speed limit rule has a `type` indicating the kind of speed rule,
+and a `speed` holding the speed value. Typically speed limits specify
+`maximum` allowed speeds, but Overture also supports `minimum` speed
+limits and `advisory` speeds, which are recommended but not regulatory.
+Variable speed corridors and roads without a regulatory maximum speed
+are indicated with the `road_flags` property, using the
+`dynamic_speed` and `unlimited_speed` flags.
Every road segment has an implied speed limit or set of speed limits
defined by its [road class](#road-class) and local rules, norms, and
@@ -306,4 +311,10 @@ As with access restrictions and turn restrictions, speed limits can be specified
{ ExampleSpeedLimitsVariableMax }
+
+
+
+{ ExampleSpeedLimitsAdvisory }
+
+
\ No newline at end of file
diff --git a/docs/schema/concepts/by-theme/transportation/segments.mdx b/docs/schema/concepts/by-theme/transportation/segments.mdx
index 03ebe8231..0fcc34521 100644
--- a/docs/schema/concepts/by-theme/transportation/segments.mdx
+++ b/docs/schema/concepts/by-theme/transportation/segments.mdx
@@ -86,7 +86,7 @@ case, it is similar to, but not the same as, OSM's `highway=*` and `railway=*` t
## Flags
-A segment's flags (`road_flags` for roads, `rail_flags` for rails) are a set of named flag values indicating the presence or absence of simple physical characteristics.
+A segment's flags (`road_flags` for roads, `rail_flags` for rails) are a set of named flag values indicating the presence or absence of simple physical characteristics and other properties of the segment.
For example, a road segment with `road_flags = [is_link, is_under_construction]` is a link segment that is physically under construction.
diff --git a/examples/transportation/docusaurus/geometric-scoping.yaml b/examples/transportation/docusaurus/geometric-scoping.yaml
index 86f5f58d7..ea1678f25 100644
--- a/examples/transportation/docusaurus/geometric-scoping.yaml
+++ b/examples/transportation/docusaurus/geometric-scoping.yaml
@@ -12,10 +12,12 @@ properties:
class: primary
speed_limits:
- between: [0, 0.15]
- max_speed:
+ type: maximum
+ speed:
value: 100
unit: km/h
- between: [0.15, 1]
- max_speed:
+ type: maximum
+ speed:
value: 60
unit: km/h
diff --git a/examples/transportation/docusaurus/speed-limits-01-simple.yaml b/examples/transportation/docusaurus/speed-limits-01-simple.yaml
index 30bea71ce..923ed5727 100644
--- a/examples/transportation/docusaurus/speed-limits-01-simple.yaml
+++ b/examples/transportation/docusaurus/speed-limits-01-simple.yaml
@@ -13,6 +13,7 @@ properties:
subtype: road
class: residential
speed_limits:
- - max_speed:
+ - type: maximum
+ speed:
value: 30
unit: km/h
diff --git a/examples/transportation/docusaurus/speed-limits-02-directional.yaml b/examples/transportation/docusaurus/speed-limits-02-directional.yaml
index 8f30bb69a..822b6b819 100644
--- a/examples/transportation/docusaurus/speed-limits-02-directional.yaml
+++ b/examples/transportation/docusaurus/speed-limits-02-directional.yaml
@@ -1,5 +1,5 @@
---
-id: speed-limits-variable-max
+id: speed-limits-directional
type: Feature
geometry:
type: LineString
@@ -13,8 +13,10 @@ properties:
subtype: road
class: secondary
speed_limits:
- - max_speed: {value: 70, unit: "mph"}
+ - type: maximum
+ speed: {value: 70, unit: "mph"}
- when:
mode: [hgv]
heading: forward
- max_speed: {value: 65, unit: "mph"}
+ type: maximum
+ speed: {value: 65, unit: "mph"}
diff --git a/examples/transportation/docusaurus/speed-limits-03-variable-max.yaml b/examples/transportation/docusaurus/speed-limits-03-variable-max.yaml
index 0aeca3887..5f8251056 100644
--- a/examples/transportation/docusaurus/speed-limits-03-variable-max.yaml
+++ b/examples/transportation/docusaurus/speed-limits-03-variable-max.yaml
@@ -14,8 +14,10 @@ properties:
version: 1
subtype: road
class: motorway
+ road_flags:
+ - values: [dynamic_speed]
speed_limits:
- - max_speed:
+ - type: maximum
+ speed:
value: 100
unit: km/h
- is_max_speed_variable: true
diff --git a/examples/transportation/docusaurus/speed-limits-04-advisory.yaml b/examples/transportation/docusaurus/speed-limits-04-advisory.yaml
new file mode 100644
index 000000000..c0d90ee02
--- /dev/null
+++ b/examples/transportation/docusaurus/speed-limits-04-advisory.yaml
@@ -0,0 +1,25 @@
+---
+id: speed-limits-advisory
+type: Feature
+geometry:
+ type: LineString
+ coordinates:
+ - [-123.36051977110497, 48.42945540586221]
+ - [-123.36053780784551, 48.42906755412086]
+ - [-123.36034842206483, 48.42868269843091]
+properties:
+ theme: transportation
+ type: segment
+ version: 1
+ subtype: road
+ class: secondary
+ speed_limits:
+ - type: maximum
+ speed:
+ value: 60
+ unit: km/h
+ - between: [0.4, 1]
+ type: advisory
+ speed:
+ value: 40
+ unit: km/h
diff --git a/examples/transportation/segment/road/restrictions/road-restrictions-speed-limits.yaml b/examples/transportation/segment/road/restrictions/road-restrictions-speed-limits.yaml
index ac229da48..c89741435 100644
--- a/examples/transportation/segment/road/restrictions/road-restrictions-speed-limits.yaml
+++ b/examples/transportation/segment/road/restrictions/road-restrictions-speed-limits.yaml
@@ -10,29 +10,46 @@ properties:
subtype: road
class: tertiary
version: 3
+ road_flags:
+ - values: [dynamic_speed]
+ when: {heading: forward}
+ - values: [dynamic_speed]
+ between: [0.25, 0.5]
+ when: {heading: forward}
speed_limits:
- - max_speed: {value: 20, unit: 'km/h'}
+ - type: maximum
+ speed: {value: 20, unit: 'km/h'}
between: [ 0, 0.5 ]
- - min_speed: {value: 25, unit: 'mph'}
+ - type: minimum
+ speed: {value: 25, unit: 'mph'}
when:
during: PH
- - max_speed: {value: 100, unit: 'km/h'}
- min_speed: {value: 75, unit: 'km/h'}
+ - type: maximum
+ speed: {value: 100, unit: 'km/h'}
+ when: {heading: forward}
+ - type: minimum
+ speed: {value: 75, unit: 'km/h'}
when: {heading: forward}
- - min_speed: {value: 25, unit: 'mph'}
+ - type: minimum
+ speed: {value: 25, unit: 'mph'}
when:
heading: forward
mode: [car, hgv]
- - max_speed: {value: 60, unit: 'mph'}
- is_max_speed_variable: true
+ - type: maximum
+ speed: {value: 60, unit: 'mph'}
when:
heading: forward
using: [at_destination]
- - min_speed: {value: 25, unit: 'mph'}
+ - type: advisory
+ speed: {value: 45, unit: 'mph'}
+ between: [ 0.5, 1 ]
+ - type: minimum
+ speed: {value: 25, unit: 'mph'}
when:
heading: forward
recognized: [as_employee]
- - min_speed: {value: 40, unit: 'mph'}
+ - type: minimum
+ speed: {value: 40, unit: 'mph'}
when:
heading: forward
vehicle:
@@ -47,9 +64,8 @@ properties:
comparison: less_than
value: 12
unit: 'ft'
- - max_speed: {value: 30, unit: 'km/h'}
- min_speed: {value: 20, unit: 'mph'}
- is_max_speed_variable: true
+ - type: maximum
+ speed: {value: 30, unit: 'km/h'}
between: [0.25, 0.5]
when:
heading: forward
diff --git a/examples/transportation/segment/road/road.yaml b/examples/transportation/segment/road/road.yaml
index eac92f24e..d2b1dd80e 100644
--- a/examples/transportation/segment/road/road.yaml
+++ b/examples/transportation/segment/road/road.yaml
@@ -27,24 +27,27 @@ properties:
road_surface:
- value: gravel
road_flags:
- - values: [is_link, is_tunnel] # Note: `is_link` is deprecated and will be removed in a future release in favor of the link subclass
+ - values: [is_link, is_tunnel, dynamic_speed] # Note: `is_link` is deprecated and will be removed in a future release in favor of the link subclass
level_rules:
- value: -1
width_rules:
- value: 10
speed_limits:
- - min_speed:
+ - type: minimum
+ speed:
value: 90
unit: km/h
- max_speed:
+ - type: maximum
+ speed:
value: 110
unit: mph
- is_max_speed_variable: true
- - max_speed:
+ - type: maximum
+ speed:
value: 55
unit: mph
when: {mode: [ "truck" ]}
- - max_speed:
+ - type: maximum
+ speed:
value: 30
unit: km/h
between: [0.25, 0.50]
diff --git a/packages/overture-schema-codegen/tests/test_pyspark_check_builder.py b/packages/overture-schema-codegen/tests/test_pyspark_check_builder.py
index c4c9f84ef..965d73857 100644
--- a/packages/overture-schema-codegen/tests/test_pyspark_check_builder.py
+++ b/packages/overture-schema-codegen/tests/test_pyspark_check_builder.py
@@ -1605,16 +1605,6 @@ def test_shared_fields_have_no_variant_values(
for node in subtype_nodes:
assert node.guards == ()
- def test_speed_limits_require_any_of_in_model_nodes(
- self, model_nodes: list[ModelCheck]
- ) -> None:
- speed_limit_nodes = [
- n
- for n in _filter_nodes(model_nodes, "check_require_any_of")
- if n.target == _path("speed_limits[]")
- ]
- assert len(speed_limit_nodes) >= 1
-
def test_destinations_require_any_of_in_model_nodes(
self, model_nodes: list[ModelCheck]
) -> None:
diff --git a/packages/overture-schema-common/README.md b/packages/overture-schema-common/README.md
index fccbe9ee4..458af87c0 100644
--- a/packages/overture-schema-common/README.md
+++ b/packages/overture-schema-common/README.md
@@ -33,7 +33,7 @@ from overture.schema.system.numeric import float32
@scoped(Scope.GEOMETRIC_RANGE, Scope.TEMPORAL)
class SpeedLimit(BaseModel):
- max_speed: float32
+ speed: float32
```
This produces a model with `between` (geometric range) and `when.during` (temporal) fields, both optional. The full set of scopes and the fields they inject:
diff --git a/packages/overture-schema-theme-transportation/pyproject.toml b/packages/overture-schema-theme-transportation/pyproject.toml
index 596197bf4..a5b4b5884 100644
--- a/packages/overture-schema-theme-transportation/pyproject.toml
+++ b/packages/overture-schema-theme-transportation/pyproject.toml
@@ -135,8 +135,9 @@ unit = "m"
value = 5.2
[[examples.Segment.speed_limits]]
+type = "maximum"
-[examples.Segment.speed_limits.max_speed]
+[examples.Segment.speed_limits.speed]
unit = "km/h"
value = 60
diff --git a/packages/overture-schema-theme-transportation/src/overture/schema/transportation/__init__.py b/packages/overture-schema-theme-transportation/src/overture/schema/transportation/__init__.py
index 4300f8a12..7e1a22c73 100644
--- a/packages/overture-schema-theme-transportation/src/overture/schema/transportation/__init__.py
+++ b/packages/overture-schema-theme-transportation/src/overture/schema/transportation/__init__.py
@@ -35,6 +35,7 @@
SegmentSubtype,
Speed,
SpeedLimitRule,
+ SpeedLimitType,
TransportationSegment,
WaterSegment,
WidthRule,
@@ -69,6 +70,7 @@
"SegmentSubtype",
"Speed",
"SpeedLimitRule",
+ "SpeedLimitType",
"TransportationSegment",
"WaterSegment",
"WidthRule",
diff --git a/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/__init__.py b/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/__init__.py
index 3bd356872..6fcc64773 100644
--- a/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/__init__.py
+++ b/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/__init__.py
@@ -18,6 +18,7 @@
SegmentSubtype,
Speed,
SpeedLimitRule,
+ SpeedLimitType,
TransportationSegment,
WidthRule,
)
@@ -91,6 +92,7 @@
"SegmentSubtype",
"Speed",
"SpeedLimitRule",
+ "SpeedLimitType",
"TransportationSegment",
"WaterSegment",
"WidthRule",
diff --git a/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/_common.py b/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/_common.py
index 8c21c8317..794fc4028 100644
--- a/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/_common.py
+++ b/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/_common.py
@@ -28,7 +28,7 @@
GeometryType,
GeometryTypeConstraint,
)
-from overture.schema.system.model_constraint import no_extra_fields, require_any_of
+from overture.schema.system.model_constraint import no_extra_fields
from overture.schema.system.numeric import float64, int32
from overture.schema.system.ref import Id, Reference, Relationship
@@ -297,8 +297,18 @@ class Speed(BaseModel):
unit: SpeedUnit
+class SpeedLimitType(str, DocumentedEnum):
+ """The kind of speed limit."""
+
+ ADVISORY = (
+ "advisory",
+ "A recommended safe speed (e.g. before sharp curves or on ramps)",
+ )
+ MAXIMUM = "maximum"
+ MINIMUM = "minimum"
+
+
@no_extra_fields
-@require_any_of("max_speed", "min_speed")
@scoped(
Scope.GEOMETRIC_RANGE,
Scope.HEADING,
@@ -311,17 +321,10 @@ class Speed(BaseModel):
class SpeedLimitRule(BaseModel):
"""An individual speed limit rule."""
- # Optional
+ # Required
- max_speed: Speed | None = None
- min_speed: Speed | None = None
- is_max_speed_variable: Annotated[
- bool | None,
- Field(
- description="Indicates a variable speed corridor",
- strict=True,
- ),
- ] = False
+ type: SpeedLimitType
+ speed: Speed
SpeedLimits = NewType(
diff --git a/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/road.py b/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/road.py
index d29f3d9a7..2b92ec546 100644
--- a/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/road.py
+++ b/packages/overture-schema-theme-transportation/src/overture/schema/transportation/segment/road.py
@@ -86,7 +86,7 @@ class RoadSubclassRule(BaseModel):
class RoadFlag(str, DocumentedEnum):
"""Simple flags that can be on or off for a road segment.
- Specifies physical characteristics and can overlap.
+ Specifies physical characteristics and other properties of the road and can overlap.
"""
IS_BRIDGE = "is_bridge"
@@ -99,12 +99,28 @@ class RoadFlag(str, DocumentedEnum):
IS_ABANDONED = "is_abandoned"
IS_COVERED = "is_covered"
IS_INDOOR = "is_indoor"
+ DYNAMIC_SPEED = (
+ "dynamic_speed",
+ "Speed limits on the road are dynamic (e.g. displayed on variable signs in a dynamic speed corridor)",
+ )
+ UNLIMITED_SPEED = (
+ "unlimited_speed",
+ "No regulatory maximum speed applies (e.g. parts of the German Autobahn)",
+ )
@no_extra_fields
-@scoped(Scope.GEOMETRIC_RANGE)
+@scoped(
+ Scope.GEOMETRIC_RANGE,
+ Scope.HEADING,
+ Scope.PURPOSE_OF_USE,
+ Scope.RECOGNIZED_STATUS,
+ Scope.TEMPORAL,
+ Scope.TRAVEL_MODE,
+ Scope.VEHICLE,
+)
class RoadFlagRule(BaseModel):
- """Road-specific flag rule with geometric scoping only."""
+ """Road-specific flag rule."""
values: Annotated[list[RoadFlag], Field(min_length=1), UniqueItemsConstraint()]
diff --git a/packages/overture-schema-theme-transportation/tests/segment_baseline_schema.json b/packages/overture-schema-theme-transportation/tests/segment_baseline_schema.json
index 0bf9d1962..a350c9e08 100644
--- a/packages/overture-schema-theme-transportation/tests/segment_baseline_schema.json
+++ b/packages/overture-schema-theme-transportation/tests/segment_baseline_schema.json
@@ -755,7 +755,7 @@
"type": "string"
},
"RoadFlag": {
- "description": "Simple flags that can be on or off for a road segment.\n\nSpecifies physical characteristics and can overlap.",
+ "description": "Simple flags that can be on or off for a road segment.\n\nSpecifies physical characteristics and other properties of the road and can overlap.",
"enum": [
"is_bridge",
"is_link",
@@ -763,14 +763,16 @@
"is_under_construction",
"is_abandoned",
"is_covered",
- "is_indoor"
+ "is_indoor",
+ "dynamic_speed",
+ "unlimited_speed"
],
"title": "RoadFlag",
"type": "string"
},
"RoadFlagRule": {
"additionalProperties": false,
- "description": "Road-specific flag rule with geometric scoping only.",
+ "description": "Road-specific flag rule.",
"properties": {
"between": {
"description": "The linearly-referenced sub-segment of the geometry, specified as a range (pair) of percentage displacements from the start of the geometry, that the containing RoadFlagRule applies to.",
@@ -792,6 +794,9 @@
"title": "Values",
"type": "array",
"uniqueItems": true
+ },
+ "when": {
+ "$ref": "#/$defs/overture__schema__transportation__segment__road__RoadFlagRule__When"
}
},
"required": [
@@ -1283,32 +1288,6 @@
},
"SpeedLimitRule": {
"additionalProperties": false,
- "anyOf": [
- {
- "properties": {
- "max_speed": {
- "not": {
- "type": "null"
- }
- }
- },
- "required": [
- "max_speed"
- ]
- },
- {
- "properties": {
- "min_speed": {
- "not": {
- "type": "null"
- }
- }
- },
- "required": [
- "min_speed"
- ]
- }
- ],
"description": "An individual speed limit rule.",
"properties": {
"between": {
@@ -1323,25 +1302,33 @@
"title": "Between",
"type": "array"
},
- "is_max_speed_variable": {
- "default": false,
- "description": "Indicates a variable speed corridor",
- "title": "Is Max Speed Variable",
- "type": "boolean"
- },
- "max_speed": {
+ "speed": {
"$ref": "#/$defs/Speed"
},
- "min_speed": {
- "$ref": "#/$defs/Speed"
+ "type": {
+ "$ref": "#/$defs/SpeedLimitType"
},
"when": {
"$ref": "#/$defs/overture__schema__transportation__segment___common__SpeedLimitRule__When"
}
},
+ "required": [
+ "type",
+ "speed"
+ ],
"title": "SpeedLimitRule",
"type": "object"
},
+ "SpeedLimitType": {
+ "description": "The kind of speed limit.",
+ "enum": [
+ "advisory",
+ "maximum",
+ "minimum"
+ ],
+ "title": "SpeedLimitType",
+ "type": "string"
+ },
"SpeedUnit": {
"description": "Unit of speed.",
"enum": [
@@ -2227,6 +2214,164 @@
],
"title": "DestinationRule.When",
"type": "object"
+ },
+ "overture__schema__transportation__segment__road__RoadFlagRule__When": {
+ "additionalProperties": false,
+ "anyOf": [
+ {
+ "properties": {
+ "heading": {
+ "not": {
+ "type": "null"
+ }
+ }
+ },
+ "required": [
+ "heading"
+ ]
+ },
+ {
+ "properties": {
+ "during": {
+ "not": {
+ "type": "null"
+ }
+ }
+ },
+ "required": [
+ "during"
+ ]
+ },
+ {
+ "properties": {
+ "mode": {
+ "not": {
+ "type": "null"
+ }
+ }
+ },
+ "required": [
+ "mode"
+ ]
+ },
+ {
+ "properties": {
+ "using": {
+ "not": {
+ "type": "null"
+ }
+ }
+ },
+ "required": [
+ "using"
+ ]
+ },
+ {
+ "properties": {
+ "recognized": {
+ "not": {
+ "type": "null"
+ }
+ }
+ },
+ "required": [
+ "recognized"
+ ]
+ },
+ {
+ "properties": {
+ "vehicle": {
+ "not": {
+ "type": "null"
+ }
+ }
+ },
+ "required": [
+ "vehicle"
+ ]
+ }
+ ],
+ "description": "Scopes for RoadFlagRule: Scope.HEADING, Scope.TEMPORAL, Scope.TRAVEL MODE, Scope.PURPOSE OF USE, Scope.RECOGNIZED STATUS and Scope.VEHICLE",
+ "properties": {
+ "during": {
+ "description": "The recurring time span, in the OpenStreetMap opening hours format, that the containing RoadFlagRule applies to. For the OSM opening hours specification, see https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification.",
+ "title": "During",
+ "type": "string"
+ },
+ "heading": {
+ "$ref": "#/$defs/Heading",
+ "description": "The heading, either forward or backward, that the containing RoadFlagRule applies to."
+ },
+ "mode": {
+ "description": "A list of one or more travel modes, such as car, truck, or foot, that the containing RoadFlagRule applies to.",
+ "items": {
+ "$ref": "#/$defs/TravelMode"
+ },
+ "minItems": 1,
+ "title": "Mode",
+ "type": "array",
+ "uniqueItems": true
+ },
+ "recognized": {
+ "description": "A list of one or more recognized status values, such as employee or student, that the containing RoadFlagRule applies to.",
+ "items": {
+ "$ref": "#/$defs/RecognizedStatus"
+ },
+ "minItems": 1,
+ "title": "Recognized",
+ "type": "array",
+ "uniqueItems": true
+ },
+ "using": {
+ "description": "A list of one or more usage purposes, such as delivery or arrival at final destination, that the containing RoadFlagRule applies to.",
+ "items": {
+ "$ref": "#/$defs/PurposeOfUse"
+ },
+ "minItems": 1,
+ "title": "Using",
+ "type": "array",
+ "uniqueItems": true
+ },
+ "vehicle": {
+ "description": "A list of one or more vehicle parameters that limit the vehicles the containing RoadFlagRule applies to.",
+ "items": {
+ "description": "Selects vehicles that a scope applies to based on criteria such as height, weight, or axle count.",
+ "discriminator": {
+ "mapping": {
+ "axle_count": "#/$defs/VehicleAxleCountSelector",
+ "height": "#/$defs/VehicleHeightSelector",
+ "length": "#/$defs/VehicleLengthSelector",
+ "weight": "#/$defs/VehicleWeightSelector",
+ "width": "#/$defs/VehicleWidthSelector"
+ },
+ "propertyName": "dimension"
+ },
+ "oneOf": [
+ {
+ "$ref": "#/$defs/VehicleAxleCountSelector"
+ },
+ {
+ "$ref": "#/$defs/VehicleHeightSelector"
+ },
+ {
+ "$ref": "#/$defs/VehicleLengthSelector"
+ },
+ {
+ "$ref": "#/$defs/VehicleWeightSelector"
+ },
+ {
+ "$ref": "#/$defs/VehicleWidthSelector"
+ }
+ ]
+ },
+ "minItems": 1,
+ "title": "Vehicle",
+ "type": "array",
+ "uniqueItems": true
+ }
+ },
+ "title": "RoadFlagRule.When",
+ "type": "object"
}
},
"oneOf": [
diff --git a/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-bad-type.yaml b/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-bad-type.yaml
new file mode 100644
index 000000000..38c1a773f
--- /dev/null
+++ b/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-bad-type.yaml
@@ -0,0 +1,19 @@
+---
+id: road segment where road.restrictions.speed_limits contains a rule with an invalid type
+type: Feature
+geometry:
+ type: LineString
+ coordinates: [[0, 0], [1, 1]]
+properties:
+ ext_expected_errors:
+ - "[S#/$defs/propertyDefinitions/speedLimitType/enum]: value must be one of"
+ theme: transportation
+ type: segment
+ version: 1
+ subtype: road
+ class: secondary
+ speed_limits:
+ - type: recommended
+ speed:
+ value: 110
+ unit: mph
diff --git a/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-empty-rule.json b/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-empty-rule.json
index eaf9f1a5b..f7dd2e241 100644
--- a/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-empty-rule.json
+++ b/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-empty-rule.json
@@ -17,8 +17,7 @@
"speed_limits": [{}],
"ext_description": "road segment where road.restrictions.speed_limits contains an empty rule",
"ext_expected_errors": [
- "anyOf/0/required]: missing property 'min_speed'",
- "anyOf/1/required]: missing property 'max_speed'"
+ "required]: missing properties 'type', 'speed'"
]
}
}
diff --git a/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-mode.yaml b/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-mode.yaml
index 4358421ee..cb50610bb 100644
--- a/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-mode.yaml
+++ b/reference/counterexamples/transportation/segment/road/restrictions/speed_limits/bad-speed-limits-mode.yaml
@@ -21,7 +21,8 @@ properties:
- connector_id: barConnector
at: 1
speed_limits:
- - max_speed:
+ - type: maximum
+ speed:
value: 110
unit: mph
when: {mode: [foo]}
diff --git a/reference/examples/transportation/docusaurus/geometric-scoping.yaml b/reference/examples/transportation/docusaurus/geometric-scoping.yaml
index 86f5f58d7..ea1678f25 100644
--- a/reference/examples/transportation/docusaurus/geometric-scoping.yaml
+++ b/reference/examples/transportation/docusaurus/geometric-scoping.yaml
@@ -12,10 +12,12 @@ properties:
class: primary
speed_limits:
- between: [0, 0.15]
- max_speed:
+ type: maximum
+ speed:
value: 100
unit: km/h
- between: [0.15, 1]
- max_speed:
+ type: maximum
+ speed:
value: 60
unit: km/h
diff --git a/reference/examples/transportation/docusaurus/speed-limits-01-simple.yaml b/reference/examples/transportation/docusaurus/speed-limits-01-simple.yaml
index 30bea71ce..923ed5727 100644
--- a/reference/examples/transportation/docusaurus/speed-limits-01-simple.yaml
+++ b/reference/examples/transportation/docusaurus/speed-limits-01-simple.yaml
@@ -13,6 +13,7 @@ properties:
subtype: road
class: residential
speed_limits:
- - max_speed:
+ - type: maximum
+ speed:
value: 30
unit: km/h
diff --git a/reference/examples/transportation/docusaurus/speed-limits-02-directional.yaml b/reference/examples/transportation/docusaurus/speed-limits-02-directional.yaml
index 8f30bb69a..822b6b819 100644
--- a/reference/examples/transportation/docusaurus/speed-limits-02-directional.yaml
+++ b/reference/examples/transportation/docusaurus/speed-limits-02-directional.yaml
@@ -1,5 +1,5 @@
---
-id: speed-limits-variable-max
+id: speed-limits-directional
type: Feature
geometry:
type: LineString
@@ -13,8 +13,10 @@ properties:
subtype: road
class: secondary
speed_limits:
- - max_speed: {value: 70, unit: "mph"}
+ - type: maximum
+ speed: {value: 70, unit: "mph"}
- when:
mode: [hgv]
heading: forward
- max_speed: {value: 65, unit: "mph"}
+ type: maximum
+ speed: {value: 65, unit: "mph"}
diff --git a/reference/examples/transportation/docusaurus/speed-limits-03-variable-max.yaml b/reference/examples/transportation/docusaurus/speed-limits-03-variable-max.yaml
index 0aeca3887..5f8251056 100644
--- a/reference/examples/transportation/docusaurus/speed-limits-03-variable-max.yaml
+++ b/reference/examples/transportation/docusaurus/speed-limits-03-variable-max.yaml
@@ -14,8 +14,10 @@ properties:
version: 1
subtype: road
class: motorway
+ road_flags:
+ - values: [dynamic_speed]
speed_limits:
- - max_speed:
+ - type: maximum
+ speed:
value: 100
unit: km/h
- is_max_speed_variable: true
diff --git a/reference/examples/transportation/docusaurus/speed-limits-04-advisory.yaml b/reference/examples/transportation/docusaurus/speed-limits-04-advisory.yaml
new file mode 100644
index 000000000..c0d90ee02
--- /dev/null
+++ b/reference/examples/transportation/docusaurus/speed-limits-04-advisory.yaml
@@ -0,0 +1,25 @@
+---
+id: speed-limits-advisory
+type: Feature
+geometry:
+ type: LineString
+ coordinates:
+ - [-123.36051977110497, 48.42945540586221]
+ - [-123.36053780784551, 48.42906755412086]
+ - [-123.36034842206483, 48.42868269843091]
+properties:
+ theme: transportation
+ type: segment
+ version: 1
+ subtype: road
+ class: secondary
+ speed_limits:
+ - type: maximum
+ speed:
+ value: 60
+ unit: km/h
+ - between: [0.4, 1]
+ type: advisory
+ speed:
+ value: 40
+ unit: km/h
diff --git a/reference/examples/transportation/segment/road/restrictions/road-restrictions-speed-limits.yaml b/reference/examples/transportation/segment/road/restrictions/road-restrictions-speed-limits.yaml
index ac229da48..c89741435 100644
--- a/reference/examples/transportation/segment/road/restrictions/road-restrictions-speed-limits.yaml
+++ b/reference/examples/transportation/segment/road/restrictions/road-restrictions-speed-limits.yaml
@@ -10,29 +10,46 @@ properties:
subtype: road
class: tertiary
version: 3
+ road_flags:
+ - values: [dynamic_speed]
+ when: {heading: forward}
+ - values: [dynamic_speed]
+ between: [0.25, 0.5]
+ when: {heading: forward}
speed_limits:
- - max_speed: {value: 20, unit: 'km/h'}
+ - type: maximum
+ speed: {value: 20, unit: 'km/h'}
between: [ 0, 0.5 ]
- - min_speed: {value: 25, unit: 'mph'}
+ - type: minimum
+ speed: {value: 25, unit: 'mph'}
when:
during: PH
- - max_speed: {value: 100, unit: 'km/h'}
- min_speed: {value: 75, unit: 'km/h'}
+ - type: maximum
+ speed: {value: 100, unit: 'km/h'}
+ when: {heading: forward}
+ - type: minimum
+ speed: {value: 75, unit: 'km/h'}
when: {heading: forward}
- - min_speed: {value: 25, unit: 'mph'}
+ - type: minimum
+ speed: {value: 25, unit: 'mph'}
when:
heading: forward
mode: [car, hgv]
- - max_speed: {value: 60, unit: 'mph'}
- is_max_speed_variable: true
+ - type: maximum
+ speed: {value: 60, unit: 'mph'}
when:
heading: forward
using: [at_destination]
- - min_speed: {value: 25, unit: 'mph'}
+ - type: advisory
+ speed: {value: 45, unit: 'mph'}
+ between: [ 0.5, 1 ]
+ - type: minimum
+ speed: {value: 25, unit: 'mph'}
when:
heading: forward
recognized: [as_employee]
- - min_speed: {value: 40, unit: 'mph'}
+ - type: minimum
+ speed: {value: 40, unit: 'mph'}
when:
heading: forward
vehicle:
@@ -47,9 +64,8 @@ properties:
comparison: less_than
value: 12
unit: 'ft'
- - max_speed: {value: 30, unit: 'km/h'}
- min_speed: {value: 20, unit: 'mph'}
- is_max_speed_variable: true
+ - type: maximum
+ speed: {value: 30, unit: 'km/h'}
between: [0.25, 0.5]
when:
heading: forward
diff --git a/reference/examples/transportation/segment/road/road.yaml b/reference/examples/transportation/segment/road/road.yaml
index eac92f24e..d2b1dd80e 100644
--- a/reference/examples/transportation/segment/road/road.yaml
+++ b/reference/examples/transportation/segment/road/road.yaml
@@ -27,24 +27,27 @@ properties:
road_surface:
- value: gravel
road_flags:
- - values: [is_link, is_tunnel] # Note: `is_link` is deprecated and will be removed in a future release in favor of the link subclass
+ - values: [is_link, is_tunnel, dynamic_speed] # Note: `is_link` is deprecated and will be removed in a future release in favor of the link subclass
level_rules:
- value: -1
width_rules:
- value: 10
speed_limits:
- - min_speed:
+ - type: minimum
+ speed:
value: 90
unit: km/h
- max_speed:
+ - type: maximum
+ speed:
value: 110
unit: mph
- is_max_speed_variable: true
- - max_speed:
+ - type: maximum
+ speed:
value: 55
unit: mph
when: {mode: [ "truck" ]}
- - max_speed:
+ - type: maximum
+ speed:
value: 30
unit: km/h
between: [0.25, 0.50]
diff --git a/schema/transportation/segment.yaml b/schema/transportation/segment.yaml
index 4a959a1a6..85a28182f 100644
--- a/schema/transportation/segment.yaml
+++ b/schema/transportation/segment.yaml
@@ -229,7 +229,7 @@ properties:
- restrooms # 'toilets' in OSM
roadFlag:
description: >-
- Simple flags that can be on or off for a road segment. Specifies physical characteristics and can overlap.
+ Simple flags that can be on or off for a road segment. Specifies physical characteristics and other properties of the road and can overlap.
type: string
enum:
- is_bridge
@@ -239,6 +239,8 @@ properties:
- is_abandoned
- is_covered
- is_indoor
+ - dynamic_speed
+ - unlimited_speed
railFlag:
description: >-
Simple flags that can be on or off for a railway segment. Specifies physical characteristics and can overlap.
@@ -326,6 +328,15 @@ properties:
- value
- unit
unevaluatedProperties: false
+ speedLimitType:
+ description: >-
+ The kind of speed rule. minimum and maximum are regulatory
+ limits, and advisory is a recommended, non-regulatory speed.
+ type: string
+ enum:
+ - maximum
+ - minimum
+ - advisory
purposeOfUse:
description: >-
Reason why a person or entity travelling on the transportation
@@ -573,19 +584,13 @@ properties:
purpose and use it to introduce an optional
direction property in each rule.
type: object
- anyOf:
- - required: [ min_speed ]
- - required: [ max_speed ]
+ required: [ type, speed ]
allOf:
- "$ref": "../defs.yaml#/$defs/propertyContainers/geometricRangeScopeContainer"
unevaluatedProperties: false
properties:
- min_speed: { "$ref": "#/$defs/propertyDefinitions/speed" }
- max_speed: { "$ref": "#/$defs/propertyDefinitions/speed" }
- is_max_speed_variable:
- description: Indicates a variable speed corridor
- type: boolean
- default: false
+ type: { "$ref": "#/$defs/propertyDefinitions/speedLimitType" }
+ speed: { "$ref": "#/$defs/propertyDefinitions/speed" }
when:
allOf:
- "$ref": "#/$defs/propertyContainers/temporalScopeContainer"
@@ -677,6 +682,16 @@ properties:
items: { "$ref": "#/$defs/propertyDefinitions/roadFlag" }
uniqueItems: true
minLength: 1
+ when:
+ allOf:
+ - "$ref": "#/$defs/propertyContainers/temporalScopeContainer"
+ - "$ref": "#/$defs/propertyContainers/headingScopeContainer"
+ - "$ref": "#/$defs/propertyContainers/purposeOfUseScopeContainer"
+ - "$ref": "#/$defs/propertyContainers/recognizedStatusScopeContainer"
+ - "$ref": "#/$defs/propertyContainers/travelModeScopeContainer"
+ - "$ref": "#/$defs/propertyContainers/vehicleScopeContainer"
+ minProperties: 1
+ unevaluatedProperties: false
uniqueItems: true
minLength: 1
railFlagsContainer: