From 2b100650741c9aa8e49f5e983a1607cb485dbd25 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stephan=20B=C3=B6sch-Plepelits?= <skunk@xover.mud.at>
Date: Sun, 14 Jul 2024 07:59:59 +0200
Subject: [PATCH] cycleway_width: Show left/right cycleway

---
 cycleway_width.yaml | 155 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 149 insertions(+), 6 deletions(-)

diff --git a/cycleway_width.yaml b/cycleway_width.yaml
index 89699c2..1a66141 100644
--- a/cycleway_width.yaml
+++ b/cycleway_width.yaml
@@ -2,15 +2,54 @@ query: |
   (
   way[highway=cycleway];
   way["cycleway:width"];
+  way["cycleway:left"]["cycleway:left"!~"(no|separate)"];
+  way["cycleway:right"]["cycleway:right"!~"(no|separate)"];
+  way["cycleway:both"]["cycleway:both"!~"(no|separate)"];
   )
 feature:
+  pre: |
+    {% set driving_side = 'right' %}
+
+    {% set width = attribute(tags, 'cycleway:width') %}
+    {% if width matches "/'$/" %}
+      {% set width = (width|slice(0, -1)) * 0.3048 %}
+    {% endif %}
+
+    {% set leftCycle = attribute(tags, 'cycleway:left')|default(attribute(tags, 'cycleway:both')) %}
+    {% if leftCycle in ['no', 'separate'] %}
+      {% set leftCycle = '' %}
+    {% endif %}
+    {% set leftOneway = attribute(tags, 'cycleway:left:oneway')|default(attribute(tags, 'cycleway:both:oneway')) %}
+    {% if not leftOneway or leftOneway in ['yes'] %}
+      {% set leftOneway = driving_side ? -1 : 1 %}
+    {% elseif leftOneway in ['no'] %}
+      {% set leftOneway = 0 %}
+    {% endif %}
+    {% set leftWidth = attribute(tags, 'cycleway:left:width')|default(attribute(tags, 'cycleway:both:width')) %}
+    {% if leftWidth matches "/'$/" %}
+      {% set leftWidth = (leftWidth|slice(0, -1)) * 0.3048 %}
+    {% endif %}
+
+    {% set rightCycle = attribute(tags, 'cycleway:right')|default(attribute(tags, 'cycleway:both')) %}
+    {% if rightCycle in ['no', 'separate'] %}
+      {% set rightCycle = '' %}
+    {% endif %}
+    {% set rightOneway = attribute(tags, 'cycleway:right:oneway')|default(attribute(tags, 'cycleway:both:oneway')) %}
+    {% if not rightOneway or rightOneway in ['yes'] %}
+      {% set rightOneway = driving_side ? 1 : -1 %}
+    {% elseif rightOneway in ['no'] %}
+      {% set rightOneway = 0 %}
+    {% endif %}
+    {% set rightWidth = attribute(tags, 'cycleway:right:width')|default(attribute(tags, 'cycleway:both:width')) %}
+    {% if rightWidth matches "/'$/" %}
+      {% set rightWidth = (rightWidth|slice(0, -1)) * 0.3048 %}
+    {% endif %}
+
+  styles: default{% if leftCycle %},left{% endif %}{% if rightCycle %},right{% endif %}
   style:
-    pre: |
-      {% set width = attribute(tags, 'cycleway:width') %}
-      {% if width matches "/'$/" %}
-        {% set width = (width|slice(0, -1)) * 0.3048 %}
-      {% endif %}
     width: 4
+    opacity: |
+      {{ tags.highway == 'cycleway' or attribute(tags, 'cycleway:width') ? 1 : 0 }}
     color: |
       {% set minWidth = tags.oneway in ['yes', 1, -1] ? const.minWidthOneway : const.minWidthBoth %}
       {% set optWidth = tags.oneway in ['yes', 1, -1] ? const.optWidthOneway : const.optWidthBoth %}
@@ -28,7 +67,9 @@ feature:
     noClip: |
       {{ tags.oneway in ['yes', 1, -1] }}
     pattern: |
+      {% if tags.highway == 'cycleway' or attribute(tags, 'cycleway:width') %}
       {% if tags.oneway in ['yes', 1, -1] %}arrowHead{% endif %}
+      {% endif %}
     pattern-offset: |
       {{ tags.oneway in [-1] ? 4 : 30.5 }}
     pattern-repeat: 35
@@ -43,6 +84,80 @@ feature:
       {% else %}black
       {% endif %}
     pattern-path-fillOpacity: 1
+  style:left:
+    offset: -5
+    width: |
+      {{ leftCycle in ['no', 'separate'] ? 0 : 3 }}
+    color: |
+      {% set minWidth = const.minWidthOneway %}
+      {% set optWidth = const.optWidthOneway %}
+
+      {% if leftWidth %}
+      {{ colorInterpolate(const.colorScheme, (leftWidth - minWidth) / (optWidth - minWidth)) }}
+      {% else %}black
+      {% endif %}
+    lineCap: |
+      {{ leftOneway ? 'butt' : 'round' }}
+    dashArray: |
+      {{ leftOneway ? '27,8' : '' }}
+    dashOffset: |
+      {{ leftOneway in [-1] ? 28 : 0 }}
+    noClip: |
+      {{ leftOneway }}
+    pattern: |
+      {% if leftOneway %}arrowHead{% endif %}
+    pattern-offset: |
+      {{ leftOneway == -1 ? 4 : 30.5 }}
+    pattern-lineOffset: -5
+    pattern-repeat: 35
+    pattern-polygon: true
+    pattern-pixelSize: 9
+    pattern-angleCorrection: |
+      {{ leftOneway == -1 ? 180 : 0 }}
+    pattern-path-width: 0
+    pattern-path-color: |
+      {% if leftWidth %}
+      {{ colorInterpolate(const.colorScheme, (leftWidth - minWidth) / (optWidth - minWidth)) }}
+      {% else %}black
+      {% endif %}
+    pattern-path-fillOpacity: 1
+  style:right:
+    offset: 5
+    width: |
+      {{ rightCycle in ['no', 'separate'] ? 0 : 3 }}
+    color: |
+      {% set minWidth = const.minWidthOneway %}
+      {% set optWidth = const.optWidthOneway %}
+
+      {% if rightWidth %}
+      {{ colorInterpolate(const.colorScheme, (rightWidth - minWidth) / (optWidth - minWidth)) }}
+      {% else %}black
+      {% endif %}
+    lineCap: |
+      {{ rightOneway ? 'butt' : 'round' }}
+    dashArray: |
+      {{ rightOneway ? '27,8' : '' }}
+    dashOffset: |
+      {{ rightOneway in [-1] ? 28 : 0 }}
+    noClip: |
+      {{ rightOneway }}
+    pattern: |
+      {% if rightOneway %}arrowHead{% endif %}
+    pattern-offset: |
+      {{ rightOneway == -1 ? 4 : 30.5 }}
+    pattern-lineOffset: 5
+    pattern-repeat: 35
+    pattern-polygon: true
+    pattern-pixelSize: 9
+    pattern-angleCorrection: |
+      {{ rightOneway == -1 ? 180 : 0 }}
+    pattern-path-width: 0
+    pattern-path-color: |
+      {% if rightWidth %}
+      {{ colorInterpolate(const.colorScheme, (rightWidth - minWidth) / (optWidth - minWidth)) }}
+      {% else %}black
+      {% endif %}
+    pattern-path-fillOpacity: 1
   markerSymbol: false
   listMarkerSymbol: line
   description: |
@@ -56,6 +171,7 @@ feature:
     {% endif %}
   body: |
     <ul>
+    {% if tags.highway in ['cycleway'] or attribute(tags, 'cycleway:width') %}
     <li>
       {{ keyTrans('cycleway:width') }}:
       {% if not attribute(tags, 'cycleway:width') %}
@@ -65,6 +181,33 @@ feature:
       {% else %}
         {{ attribute(tags, 'cycleway:width') }}m
       {% endif %}
+    </li>
+    {% endif %}
+
+    {% if leftCycle %}
+    <li>
+      {{ keyTrans('cycleway:left:width') }}:
+      {% if not leftWidth %}
+        {{ trans('unknown') }}
+      {% elseif attribute(tags, 'cycleway:left:width')|default(attribute(tags, 'cycleway:both:width')) matches "/(m|')$/" %}
+        {{ attribute(tags, 'cycleway:left:width')|default(attribute(tags, 'cycleway:both:width')) }}
+      {% else %}
+        {{ leftWidth }}m
+      {% endif %}
+    </li>
+    {% endif %}
+    {% if rightCycle %}
+    <li>
+      {{ keyTrans('cycleway:right:width') }}:
+      {% if not rightWidth %}
+        {{ trans('unknown') }}
+      {% elseif attribute(tags, 'cycleway:right:width')|default(attribute(tags, 'cycleway:both:width')) matches "/(m|')$/" %}
+        {{ attribute(tags, 'cycleway:right:width')|default(attribute(tags, 'cycleway:both:width')) }}
+      {% else %}
+        {{ rightWidth }}m
+      {% endif %}
+    </li>
+    {% endif %}
     </ul>
 info: |
   <table>
@@ -94,4 +237,4 @@ const:
   optWidthBoth: 5
   minWidthOneway: 0.75
   optWidthOneway: 3
-  colorScheme: ['#ff0000', '#7f7fff', '#0000ff']
+  colorScheme: ['#ff0000', '#ff00ff', '#0000ff']