Ticket #18138: 18138.3.patch

File 18138.3.patch, 32.3 KB (added by Traaker_L, 6 years ago)

Here's a new svg that should be more recognizable at lower resolutions. It is public domain, and is taken from the wiki.

  • data/defaultpresets.xml

     
    75807580                <role key="to" text="to way" requisite="required" count="1" type="way" />
    75817581            </roles>
    75827582        </item> <!-- Turn Restriction -->
     7583        <item name="Lane Connectivity" type="relation" preset_name_label="true" icon="presets/transport/way/relation_connectivity.svg">
     7584            <link wiki="Relation:connectivity" />
     7585            <space />
     7586            <key key="type" value="connectivity" />
     7587            <optional>
     7588                <text key="connectivity" text="Lane Connectivity" />
     7589            </optional>
     7590            <roles>
     7591                <role key="from" text="from way" requisite="required" count="1" type="way" />
     7592                <role key="via" text="via node or ways" requisite="required" type="way,node" />
     7593                <role key="to" text="to way" requisite="required" count="1" type="way" />
     7594            </roles>
     7595        </item> <!-- Lane Connectivity -->
    75837596        <item name="Enforcement" icon="presets/vehicle/restriction/speed_camera.svg" type="relation" preset_name_label="true">
    75847597            <link wiki="Relation:enforcement" />
    75857598            <space />
  • images/presets/transport/way/relation_connectivity.svg

     
     1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
     2<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
     3<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 640 640" width="640" height="640"><defs><path d="M0 46.49C0 46.49 0 46.49 0 46.49C0 20.82 20.82 0 46.49 0C59.5 0 124.53 0 241.58 0C241.58 0 241.58 0 241.58 0C253.92 0 265.74 4.9 274.46 13.62C283.18 22.34 288.08 34.16 288.08 46.49C288.08 65.09 288.08 213.86 288.08 232.46C288.08 258.14 267.26 278.95 241.58 278.95C222.08 278.95 66 278.95 46.49 278.95C20.82 278.95 0 258.14 0 232.46C0 207.66 0 145.67 0 46.49Z" id="a7taVMJVF2"></path><path d="M0 46.49C0 46.49 0 46.49 0 46.49C0 20.82 20.82 0 46.49 0C59.5 0 124.53 0 241.58 0C241.58 0 241.58 0 241.58 0C253.92 0 265.74 4.9 274.46 13.62C283.18 22.34 288.08 34.16 288.08 46.49C288.08 65.09 288.08 213.86 288.08 232.46C288.08 258.14 267.26 278.95 241.58 278.95C222.08 278.95 66 278.95 46.49 278.95C20.82 278.95 0 258.14 0 232.46C0 207.66 0 145.67 0 46.49Z" id="apgHjUq2Q"></path><path d="M351.92 46.49C351.92 46.49 351.92 46.49 351.92 46.49C351.92 20.82 372.74 0 398.42 0C411.42 0 476.45 0 593.51 0C593.51 0 593.51 0 593.51 0C605.84 0 617.66 4.9 626.38 13.62C635.1 22.34 640 34.16 640 46.49C640 65.09 640 213.86 640 232.46C640 258.14 619.18 278.95 593.51 278.95C574 278.95 417.92 278.95 398.42 278.95C372.74 278.95 351.92 258.14 351.92 232.46C351.92 207.66 351.92 145.67 351.92 46.49Z" id="c2kLrQggK"></path><path d="M351.92 46.49C351.92 46.49 351.92 46.49 351.92 46.49C351.92 20.82 372.74 0 398.42 0C411.42 0 476.45 0 593.51 0C593.51 0 593.51 0 593.51 0C605.84 0 617.66 4.9 626.38 13.62C635.1 22.34 640 34.16 640 46.49C640 65.09 640 213.86 640 232.46C640 258.14 619.18 278.95 593.51 278.95C574 278.95 417.92 278.95 398.42 278.95C372.74 278.95 351.92 258.14 351.92 232.46C351.92 207.66 351.92 145.67 351.92 46.49Z" id="bRf59UWe"></path><path d="M351.92 407.54C351.92 407.54 351.92 407.54 351.92 407.54C351.92 381.86 372.74 361.05 398.42 361.05C411.42 361.05 476.45 361.05 593.51 361.05C593.51 361.05 593.51 361.05 593.51 361.05C605.84 361.05 617.66 365.95 626.38 374.67C635.1 383.39 640 395.21 640 407.54C640 426.14 640 574.91 640 593.51C640 619.18 619.18 640 593.51 640C574 640 417.92 640 398.42 640C372.74 640 351.92 619.18 351.92 593.51C351.92 568.71 351.92 506.72 351.92 407.54Z" id="b3XpfhE8d"></path><path d="M351.92 407.54C351.92 407.54 351.92 407.54 351.92 407.54C351.92 381.86 372.74 361.05 398.42 361.05C411.42 361.05 476.45 361.05 593.51 361.05C593.51 361.05 593.51 361.05 593.51 361.05C605.84 361.05 617.66 365.95 626.38 374.67C635.1 383.39 640 395.21 640 407.54C640 426.14 640 574.91 640 593.51C640 619.18 619.18 640 593.51 640C574 640 417.92 640 398.42 640C372.74 640 351.92 619.18 351.92 593.51C351.92 568.71 351.92 506.72 351.92 407.54Z" id="g6peWbU7wg"></path><path d="M0 407.54C0 407.54 0 407.54 0 407.54C0 381.86 20.82 361.05 46.49 361.05C59.5 361.05 124.53 361.05 241.58 361.05C241.58 361.05 241.58 361.05 241.58 361.05C253.92 361.05 265.74 365.95 274.46 374.67C283.18 383.39 288.08 395.21 288.08 407.54C288.08 426.14 288.08 574.91 288.08 593.51C288.08 619.18 267.26 640 241.58 640C222.08 640 66 640 46.49 640C20.82 640 0 619.18 0 593.51C0 568.71 0 506.72 0 407.54Z" id="b3X9mZS0XS"></path><path d="M0 407.54C0 407.54 0 407.54 0 407.54C0 381.86 20.82 361.05 46.49 361.05C59.5 361.05 124.53 361.05 241.58 361.05C241.58 361.05 241.58 361.05 241.58 361.05C253.92 361.05 265.74 365.95 274.46 374.67C283.18 383.39 288.08 395.21 288.08 407.54C288.08 426.14 288.08 574.91 288.08 593.51C288.08 619.18 267.26 640 241.58 640C222.08 640 66 640 46.49 640C20.82 640 0 619.18 0 593.51C0 568.71 0 506.72 0 407.54Z" id="c2OicV7Ga1"></path><path d="M0 230.92C0 230.92 0 230.92 0 230.92C0 202.89 22.73 180.16 50.77 180.16C104.61 180.16 535.39 180.16 589.23 180.16C602.7 180.16 615.61 185.51 625.13 195.03C634.65 204.55 640 217.46 640 230.92C640 251.23 640 413.67 640 433.98C640 462.01 617.27 484.74 589.23 484.74C535.39 484.74 104.61 484.74 50.77 484.74C22.73 484.74 0 462.01 0 433.98C0 406.9 0 339.22 0 230.92Z" id="aaiiO6LMf9"></path><path d="M165.66 48.01C165.66 48.01 165.66 48.01 165.66 48.01C165.66 21.5 187.16 0 213.68 0C226.48 0 290.5 0 405.73 0C405.73 0 405.73 0 405.73 0C418.46 0 430.67 5.06 439.68 14.06C448.68 23.07 453.74 35.28 453.74 48.01C453.74 102.41 453.74 537.59 453.74 591.99C453.74 618.5 432.25 640 405.73 640C386.52 640 232.88 640 213.68 640C187.16 640 165.66 618.5 165.66 591.99C165.66 519.46 165.66 338.13 165.66 48.01Z" id="abbTqBwz"></path><path d="M202.77 0L428.27 0" id="h8eVNYgClu"></path><path d="M202.77 0L428.27 0" id="b3wCehSi4F"></path><path d="M196.95 640L422.45 640" id="a8ZF3dFoi"></path><path d="M196.95 640L422.45 640" id="g2XjesW754"></path><path d="M640 459.85L639.37 203.2" id="c1aq5Qb0th"></path><path d="M640 459.85L639.37 203.2" id="b5fB0Jggyg"></path><path d="M0.63 466.77L0 210.12" id="e1w7hZayOo"></path><path d="M0.63 466.77L0 210.12" id="dHcZYYnhO"></path><path d="M37.55 47.79C37.55 47.79 37.55 47.79 37.55 47.79C37.55 40.11 43.78 33.88 51.47 33.88C55.18 33.88 73.73 33.88 107.12 33.88C107.12 33.88 107.12 33.88 107.12 33.88C110.81 33.88 114.35 35.34 116.96 37.95C119.57 40.56 121.04 44.1 121.04 47.79C121.04 55.94 121.04 121.1 121.04 129.24C121.04 136.93 114.81 143.16 107.12 143.16C101.56 143.16 57.03 143.16 51.47 143.16C43.78 143.16 37.55 136.93 37.55 129.24C37.55 118.38 37.55 91.23 37.55 47.79Z" id="bGa13pfAK"></path><path d="M519.5 47.79C519.5 47.79 519.5 47.79 519.5 47.79C519.5 40.11 525.73 33.88 533.42 33.88C537.13 33.88 555.68 33.88 589.07 33.88C589.07 33.88 589.07 33.88 589.07 33.88C592.76 33.88 596.3 35.34 598.91 37.95C601.52 40.56 602.99 44.1 602.99 47.79C602.99 55.94 602.99 121.1 602.99 129.24C602.99 136.93 596.76 143.16 589.07 143.16C583.51 143.16 538.98 143.16 533.42 143.16C525.73 143.16 519.5 136.93 519.5 129.24C519.5 118.38 519.5 91.23 519.5 47.79Z" id="d2wCkNoM3P"></path><path d="M37.55 507.57C37.55 507.57 37.55 507.57 37.55 507.57C37.55 499.89 43.78 493.66 51.47 493.66C55.18 493.66 73.73 493.66 107.12 493.66C107.12 493.66 107.12 493.66 107.12 493.66C110.81 493.66 114.35 495.13 116.96 497.74C119.57 500.34 121.04 503.88 121.04 507.57C121.04 515.72 121.04 580.88 121.04 589.02C121.04 596.71 114.81 602.94 107.12 602.94C101.56 602.94 57.03 602.94 51.47 602.94C43.78 602.94 37.55 596.71 37.55 589.02C37.55 578.16 37.55 551.01 37.55 507.57Z" id="g1Te9z9uK"></path><path d="M519.5 507.57C519.5 507.57 519.5 507.57 519.5 507.57C519.5 499.89 525.73 493.66 533.42 493.66C537.13 493.66 555.68 493.66 589.07 493.66C589.07 493.66 589.07 493.66 589.07 493.66C592.76 493.66 596.3 495.13 598.91 497.74C601.52 500.34 602.99 503.88 602.99 507.57C602.99 515.72 602.99 580.88 602.99 589.02C602.99 596.71 596.76 602.94 589.07 602.94C583.51 602.94 538.98 602.94 533.42 602.94C525.73 602.94 519.5 596.71 519.5 589.02C519.5 578.16 519.5 551.01 519.5 507.57Z" id="a5xlHsGyW"></path><path d="M94.04 33.88L545.32 33.88L545.32 602.93L94.04 602.93L94.04 33.88Z" id="i5XppWnd6A"></path><path d="M37.55 98.96L602.99 98.96L602.99 537.35L37.55 537.35L37.55 98.96Z" id="a1npIiv3d"></path><path d="M428.27 157.29L478.88 65.19L529.49 157.29L428.27 157.29Z" id="aGrCMZldo"></path><path d="M264.9 157.29L315.52 65.19L366.13 157.29L264.9 157.29Z" id="a2vqq6wfRW"></path><path d="M309.92 151.76L309.48 563.17" id="a4mZiuAN4"></path><path d="M309.92 151.76L309.48 563.17" id="f2eR1MdjtU"></path><path d="M320.22 151.76L319.78 563.17" id="i1aw7I6IO"></path><path d="M320.22 151.76L319.78 563.17" id="aiXcaY4gb"></path><path d="M474.86 151.76L474.42 563.17" id="g5YujQDwx"></path><path d="M474.86 151.76L474.42 563.17" id="c4xBbdTiNV"></path><path d="M485.16 151.76L484.72 563.17" id="ciAys2Kx0"></path><path d="M485.16 151.76L484.72 563.17" id="b2UTI2pbY"></path><path d="M146.84 453.33C146.84 395.62 187.67 366.76 228.5 337.91C269.34 309.05 310.17 280.19 310.17 222.48" id="a17DFS0xbs"></path><path d="M146.84 453.33C146.84 395.62 187.67 366.76 228.5 337.91C269.34 309.05 310.17 280.19 310.17 222.48" id="asAo4qo53"></path><path d="M155.87 453.33C155.87 395.62 196.7 366.76 237.53 337.91C278.36 309.05 319.19 280.19 319.19 222.48" id="c353BxmIjg"></path><path d="M155.87 453.33C155.87 395.62 196.7 366.76 237.53 337.91C278.36 309.05 319.19 280.19 319.19 222.48" id="bNwkHbP5N"></path><path d="M146.84 450.88L144.54 563.13" id="aRkZLonUJ"></path><path d="M146.84 450.88L144.54 563.13" id="gCYFFvttG"></path><path d="M155.44 434.91L154.84 563.16" id="e4poeBsfvT"></path><path d="M155.44 434.91L154.84 563.16" id="aTTBmkyhq"></path></defs><g><g><g><use xlink:href="#a7taVMJVF2" opacity="1" fill="#ffffff" fill-opacity="1"></use><g><use xlink:href="#a7taVMJVF2" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#apgHjUq2Q" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#apgHjUq2Q" opacity="1" fill-opacity="0" stroke="#595959" stroke-width="1" stroke-opacity="1"></use></g></g><g><use xlink:href="#c2kLrQggK" opacity="1" fill="#ffffff" fill-opacity="1"></use><g><use xlink:href="#c2kLrQggK" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#bRf59UWe" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#bRf59UWe" opacity="1" fill-opacity="0" stroke="#595959" stroke-width="1" stroke-opacity="1"></use></g></g><g><use xlink:href="#b3XpfhE8d" opacity="1" fill="#ffffff" fill-opacity="1"></use><g><use xlink:href="#b3XpfhE8d" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#g6peWbU7wg" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#g6peWbU7wg" opacity="1" fill-opacity="0" stroke="#595959" stroke-width="1" stroke-opacity="1"></use></g></g><g><use xlink:href="#b3X9mZS0XS" opacity="1" fill="#ffffff" fill-opacity="1"></use><g><use xlink:href="#b3X9mZS0XS" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#c2OicV7Ga1" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#c2OicV7Ga1" opacity="1" fill-opacity="0" stroke="#595959" stroke-width="1" stroke-opacity="1"></use></g></g><g><use xlink:href="#aaiiO6LMf9" opacity="1" fill="#ffffff" fill-opacity="1"></use><g><use xlink:href="#aaiiO6LMf9" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#abbTqBwz" opacity="1" fill="#ffffff" fill-opacity="1"></use><g><use xlink:href="#abbTqBwz" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#h8eVNYgClu" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#h8eVNYgClu" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#b3wCehSi4F" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#b3wCehSi4F" opacity="1" fill-opacity="0" stroke="#595959" stroke-width="1" stroke-opacity="1"></use></g></g><g><use xlink:href="#a8ZF3dFoi" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#a8ZF3dFoi" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#g2XjesW754" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#g2XjesW754" opacity="1" fill-opacity="0" stroke="#595959" stroke-width="1" stroke-opacity="1"></use></g></g><g><use xlink:href="#c1aq5Qb0th" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#c1aq5Qb0th" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#b5fB0Jggyg" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#b5fB0Jggyg" opacity="1" fill-opacity="0" stroke="#595959" stroke-width="1" stroke-opacity="1"></use></g></g><g><use xlink:href="#e1w7hZayOo" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#e1w7hZayOo" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#dHcZYYnhO" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#dHcZYYnhO" opacity="1" fill-opacity="0" stroke="#595959" stroke-width="1" stroke-opacity="1"></use></g></g><g><use xlink:href="#bGa13pfAK" opacity="1" fill="#0000ff" fill-opacity="1"></use><g><use xlink:href="#bGa13pfAK" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#d2wCkNoM3P" opacity="1" fill="#0000ff" fill-opacity="1"></use><g><use xlink:href="#d2wCkNoM3P" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#g1Te9z9uK" opacity="1" fill="#0000ff" fill-opacity="1"></use><g><use xlink:href="#g1Te9z9uK" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#a5xlHsGyW" opacity="1" fill="#0000ff" fill-opacity="1"></use><g><use xlink:href="#a5xlHsGyW" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#i5XppWnd6A" opacity="1" fill="#0000ff" fill-opacity="1"></use><g><use xlink:href="#i5XppWnd6A" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#a1npIiv3d" opacity="1" fill="#0000ff" fill-opacity="1"></use><g><use xlink:href="#a1npIiv3d" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#aGrCMZldo" opacity="1" fill="#ffffff" fill-opacity="1"></use><g><use xlink:href="#aGrCMZldo" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#a2vqq6wfRW" opacity="1" fill="#ffffff" fill-opacity="1"></use><g><use xlink:href="#a2vqq6wfRW" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#a4mZiuAN4" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#a4mZiuAN4" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#f2eR1MdjtU" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#f2eR1MdjtU" opacity="1" fill-opacity="0" stroke="#ffffff" stroke-width="24" stroke-opacity="1"></use></g></g><g><use xlink:href="#i1aw7I6IO" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#i1aw7I6IO" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#aiXcaY4gb" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#aiXcaY4gb" opacity="1" fill-opacity="0" stroke="#ffffff" stroke-width="24" stroke-opacity="1"></use></g></g><g><use xlink:href="#g5YujQDwx" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#g5YujQDwx" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#c4xBbdTiNV" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#c4xBbdTiNV" opacity="1" fill-opacity="0" stroke="#ffffff" stroke-width="24" stroke-opacity="1"></use></g></g><g><use xlink:href="#ciAys2Kx0" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#ciAys2Kx0" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#b2UTI2pbY" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#b2UTI2pbY" opacity="1" fill-opacity="0" stroke="#ffffff" stroke-width="24" stroke-opacity="1"></use></g></g><g><use xlink:href="#a17DFS0xbs" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#a17DFS0xbs" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#asAo4qo53" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#asAo4qo53" opacity="1" fill-opacity="0" stroke="#ffffff" stroke-width="24" stroke-opacity="1"></use></g></g><g><use xlink:href="#c353BxmIjg" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#c353BxmIjg" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#bNwkHbP5N" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#bNwkHbP5N" opacity="1" fill-opacity="0" stroke="#ffffff" stroke-width="24" stroke-opacity="1"></use></g></g><g><use xlink:href="#aRkZLonUJ" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#aRkZLonUJ" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#gCYFFvttG" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#gCYFFvttG" opacity="1" fill-opacity="0" stroke="#ffffff" stroke-width="24" stroke-opacity="1"></use></g></g><g><use xlink:href="#e4poeBsfvT" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#e4poeBsfvT" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#aTTBmkyhq" opacity="1" fill="#000000" fill-opacity="0"></use><g><use xlink:href="#aTTBmkyhq" opacity="1" fill-opacity="0" stroke="#ffffff" stroke-width="24" stroke-opacity="1"></use></g></g></g></g></svg>
     4 No newline at end of file
  • src/org/openstreetmap/josm/data/validation/OsmValidator.java

     
    4242import org.openstreetmap.josm.data.validation.tests.BarriersEntrances;
    4343import org.openstreetmap.josm.data.validation.tests.Coastlines;
    4444import org.openstreetmap.josm.data.validation.tests.ConditionalKeys;
     45import org.openstreetmap.josm.data.validation.tests.ConnectivityRelations;
    4546import org.openstreetmap.josm.data.validation.tests.CrossingWays;
    4647import org.openstreetmap.josm.data.validation.tests.DuplicateNode;
    4748import org.openstreetmap.josm.data.validation.tests.DuplicateRelation;
     
    150151        PublicTransportRouteTest.class, // 3600 .. 3699
    151152        RightAngleBuildingTest.class, // 3700 .. 3799
    152153        SharpAngles.class, // 3800 .. 3899
     154        ConnectivityRelations.class, // 3900 .. 3999
    153155    };
    154156
    155157    /**
  • src/org/openstreetmap/josm/data/validation/tests/ConnectivityRelations.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.validation.tests;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.util.Collections;
     7import java.util.Comparator;
     8import java.util.HashMap;
     9import java.util.Map;
     10import java.util.Map.Entry;
     11import java.util.regex.Pattern;
     12
     13import org.openstreetmap.josm.data.osm.Node;
     14import org.openstreetmap.josm.data.osm.OsmPrimitive;
     15import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     16import org.openstreetmap.josm.data.osm.Relation;
     17import org.openstreetmap.josm.data.osm.RelationMember;
     18import org.openstreetmap.josm.data.osm.Way;
     19import org.openstreetmap.josm.data.validation.Severity;
     20import org.openstreetmap.josm.data.validation.Test;
     21import org.openstreetmap.josm.data.validation.TestError;
     22import org.openstreetmap.josm.tools.Logging;
     23
     24/**
     25 * Check for inconsistencies in lane information between relation and members.
     26 */
     27public class ConnectivityRelations extends Test {
     28
     29    protected static final int INCONSISTENT_LANE_COUNT = 3900;
     30
     31    protected static final int UNKNOWN_CONNECTIVITY_ROLE = INCONSISTENT_LANE_COUNT + 1;
     32
     33    protected static final int NO_CONNECTIVITY_TAG = INCONSISTENT_LANE_COUNT + 2;
     34
     35    protected static final int TOO_MANY_ROLES = INCONSISTENT_LANE_COUNT + 3;
     36
     37    private static final String CONNECTIVITY_TAG = "connectivity";
     38    private static final String VIA = "via";
     39    private static final String TO = "to";
     40    private static final String FROM = "from";
     41    private static final Pattern OPTIONAL_LANE_PATTERN = Pattern.compile("\\([0-9]+\\)");
     42    private static final Pattern TO_LANE_PATTERN = Pattern.compile("\\p{Zs}*[,:;]\\p{Zs}*");
     43
     44    /**
     45    * Constructor
     46    */
     47    public ConnectivityRelations() {
     48        super(tr("Connectivity Relation Check"), tr("Checks that lane count of relation matches with lanes of members"));
     49    }
     50
     51    /**
     52     * Convert the connectivity tag into a map of values
     53     *
     54     * @param relation A relation with a {@code connectivity} tag.
     55     * @return A Map in the form of {@code Map<Lane From, Map<Lane To, Optional>>} May contain nulls when errors are encountered
     56     * @since xxx
     57     */
     58    public static Map<Integer, Map<Integer, Boolean>> parseConnectivityTag(Relation relation) {
     59        final String joined = relation.get(CONNECTIVITY_TAG);
     60
     61        if (joined == null) {
     62            return Collections.emptyMap();
     63        }
     64
     65        final Map<Integer, Map<Integer, Boolean>> result = new HashMap<>();
     66        String[] lanes = joined.split("\\|", -1);
     67        for (int i = 0; i < lanes.length; i++) {
     68            String[] lane = lanes[i].split(":", -1);
     69            int laneNumber = Integer.parseInt(lane[0].trim());
     70            Map<Integer, Boolean> connections = new HashMap<>();
     71            String[] toLanes = TO_LANE_PATTERN.split(lane[1]);
     72            for (int j = 0; j < toLanes.length; j++) {
     73                String toLane = toLanes[j].trim();
     74                try {
     75                    if (OPTIONAL_LANE_PATTERN.matcher(toLane).matches()) {
     76                        toLane = toLane.replace("(", "").replace(")", "").trim();
     77                        connections.put(Integer.parseInt(toLane), Boolean.TRUE);
     78                    } else {
     79                        connections.put(Integer.parseInt(toLane), Boolean.FALSE);
     80                    }
     81                } catch (NumberFormatException e) {
     82                    Logging.debug(e);
     83                    connections.put(null, null);
     84                }
     85
     86            }
     87            result.put(laneNumber, connections);
     88        }
     89        return result;
     90    }
     91
     92    @Override
     93    public void visit(Relation r) {
     94        if (r.hasTag("type", CONNECTIVITY_TAG)) {
     95            if (!r.hasKey(CONNECTIVITY_TAG)) {
     96                errors.add(TestError.builder(this, Severity.WARNING, NO_CONNECTIVITY_TAG)
     97                        .message(tr("No connectivity tag in connectivity relation")).primitives(r).build());
     98            } else if (!r.hasIncompleteMembers()) {
     99                boolean badRole = checkForBadRole(r);
     100                if (!badRole)
     101                    checkForInconsistentLanes(r);
     102            }
     103        }
     104    }
     105
     106    private void checkForInconsistentLanes(Relation relation) {
     107        // Lane count from connectivity tag
     108        Map<Integer, Map<Integer, Boolean>> connTagLanes = parseConnectivityTag(relation);
     109        // Lane count from member tags
     110        Map<String, Integer> roleLanes = new HashMap<>();
     111
     112        for (RelationMember rM : relation.getMembers()) {
     113            // Check lanes
     114            if (rM.getType() == OsmPrimitiveType.WAY) {
     115                OsmPrimitive prim = rM.getMember();
     116                if (prim.hasKey("lanes") && !VIA.equals(rM.getRole())) {
     117                    roleLanes.put(rM.getRole(), Integer.parseInt(prim.get("lanes")));
     118                }
     119            }
     120        }
     121        boolean fromCheck = roleLanes.get(FROM) < Collections
     122                .max(connTagLanes.entrySet(), Comparator.comparingInt(Map.Entry::getKey)).getKey();
     123        boolean toCheck = false;
     124        for (Entry<Integer, Map<Integer, Boolean>> to : connTagLanes.entrySet()) {
     125            toCheck = roleLanes.get(TO) < Collections
     126                    .max(to.getValue().entrySet(), Comparator.comparingInt(Map.Entry::getKey)).getKey();
     127        }
     128        if (fromCheck || toCheck) {
     129            errors.add(TestError.builder(this, Severity.WARNING, INCONSISTENT_LANE_COUNT)
     130                    .message(tr("Inconsistent lane numbering between relation and members")).primitives(relation)
     131                    .build());
     132        }
     133    }
     134
     135    private boolean checkForBadRole(Relation relation) {
     136        // Check role names
     137        int viaWays = 0;
     138        int viaNodes = 0;
     139        int toWays = 0;
     140        int fromWays = 0;
     141        for (RelationMember relationMember : relation.getMembers()) {
     142            if (relationMember.getMember() instanceof Way) {
     143                if (relationMember.hasRole(FROM))
     144                    fromWays++;
     145                else if (relationMember.hasRole(TO))
     146                    toWays++;
     147                else if (relationMember.hasRole(VIA))
     148                    viaWays++;
     149                else {
     150                    createUnknownRole(relation, relationMember.getMember());
     151                    return true;
     152                }
     153            } else if (relationMember.getMember() instanceof Node) {
     154                if (!relationMember.hasRole(VIA)) {
     155                    createUnknownRole(relation, relationMember.getMember());
     156                    return true;
     157                }
     158                viaNodes++;
     159            }
     160        }
     161        return mixedViaNodeAndWay(relation, viaWays, viaNodes, toWays, fromWays);
     162    }
     163
     164    private boolean mixedViaNodeAndWay(Relation relation, int viaWays, int viaNodes, int toWays, int fromWays) {
     165        String message = "";
     166        if ((viaWays != 0 && viaNodes != 0) || viaNodes > 1) {
     167            message = tr("Relation contains {1} {0} roles.", VIA, viaWays + viaNodes);
     168        } else if (toWays != 1) {
     169            message = tr("Relation contains too many {0} roles", TO);
     170        } else if (fromWays != 1) {
     171            message = tr("Relation contains too many {0} roles", FROM);
     172        }
     173        if (message.isEmpty()) {
     174            return false;
     175        } else {
     176            errors.add(TestError.builder(this, Severity.WARNING, TOO_MANY_ROLES)
     177                    .message(message).primitives(relation).build());
     178            return true;
     179        }
     180    }
     181
     182    private void createUnknownRole(Relation relation, OsmPrimitive primitive) {
     183        errors.add(TestError.builder(this, Severity.WARNING, UNKNOWN_CONNECTIVITY_ROLE)
     184                .message(tr("Unkown role in connectivity relation")).primitives(relation).highlight(primitive).build());
     185    }
     186}
  • test/unit/org/openstreetmap/josm/data/validation/tests/ConnectivityRelationsTest.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.validation.tests;
     3
     4import org.junit.Assert;
     5import org.junit.Before;
     6import org.junit.Test;
     7import org.openstreetmap.josm.JOSMFixture;
     8import org.openstreetmap.josm.TestUtils;
     9import org.openstreetmap.josm.data.coor.LatLon;
     10import org.openstreetmap.josm.data.osm.Node;
     11import org.openstreetmap.josm.data.osm.Relation;
     12import org.openstreetmap.josm.data.osm.RelationMember;
     13
     14/**
     15 * Test the ConnectivityRelations validation test
     16 *
     17 * @author Taylor Smock
     18 */
     19public class ConnectivityRelationsTest {
     20    private ConnectivityRelations check;
     21    private static final String CONNECTIVITY = "connectivity";
     22    /**
     23     * Setup test.
     24     *
     25     * @throws Exception if an error occurs
     26     */
     27    @Before
     28    public void setUp() throws Exception {
     29        JOSMFixture.createUnitTestFixture().init();
     30        check = new ConnectivityRelations();
     31    }
     32
     33    private Relation createDefaultTestRelation() {
     34        Node connection = new Node(new LatLon(0, 0));
     35        return TestUtils.newRelation("type=connectivity connectivity=1:1",
     36                new RelationMember("from", TestUtils.newWay("lanes=4", new Node(new LatLon(-0.1, -0.1)), connection)),
     37                new RelationMember("via", connection),
     38                new RelationMember("to", TestUtils.newWay("lanes=4", connection, new Node(new LatLon(0.1, 0.1)))));
     39    }
     40
     41    /**
     42     * Test for connectivity relations without a connectivity tag
     43     */
     44    @Test
     45    public void testNoConnectivityTag() {
     46        Relation relation = createDefaultTestRelation();
     47        check.visit(relation);
     48
     49        Assert.assertEquals(0, check.getErrors().size());
     50
     51        relation.remove(CONNECTIVITY);
     52        check.visit(relation);
     53        Assert.assertEquals(1, check.getErrors().size());
     54    }
     55
     56    /**
     57     * Check for lanes that don't make sense
     58     */
     59    @Test
     60    public void testMisMatchedLanes() {
     61        Relation relation = createDefaultTestRelation();
     62        check.visit(relation);
     63        int expectedFailures = 0;
     64
     65        Assert.assertEquals(expectedFailures, check.getErrors().size());
     66
     67        relation.put(CONNECTIVITY, "45000:1");
     68        check.visit(relation);
     69        Assert.assertEquals(++expectedFailures, check.getErrors().size());
     70
     71        relation.put(CONNECTIVITY, "1:45000");
     72        check.visit(relation);
     73        Assert.assertEquals(++expectedFailures, check.getErrors().size());
     74
     75        relation.put(CONNECTIVITY, "1:1,2");
     76        check.visit(relation);
     77        Assert.assertEquals(expectedFailures, check.getErrors().size());
     78
     79        relation.put(CONNECTIVITY, "1:1,(2)");
     80        check.visit(relation);
     81        Assert.assertEquals(expectedFailures, check.getErrors().size());
     82
     83        relation.put(CONNECTIVITY, "1:1,(20000)");
     84        check.visit(relation);
     85        Assert.assertEquals(++expectedFailures, check.getErrors().size());
     86    }
     87
     88    /**
     89     * Check for bad roles (not from/via/to)
     90     */
     91    @Test
     92    public void testForBadRole() {
     93        Relation relation = createDefaultTestRelation();
     94        check.visit(relation);
     95        int expectedFailures = 0;
     96
     97        Assert.assertEquals(expectedFailures, check.getErrors().size());
     98
     99        for (int i = 0; i < relation.getMembers().size(); i++) {
     100            String tRole = replaceMember(relation, i, "badRole");
     101            check.visit(relation);
     102            Assert.assertEquals(++expectedFailures, check.getErrors().size());
     103            replaceMember(relation, i, tRole);
     104            check.visit(relation);
     105            Assert.assertEquals(expectedFailures, check.getErrors().size());
     106        }
     107    }
     108
     109    private String replaceMember(Relation relation, int index, String replacementRole) {
     110        RelationMember relationMember = relation.getMember(index);
     111        String currentRole = relationMember.getRole();
     112        relation.removeMember(index);
     113        relation.addMember(index, new RelationMember(replacementRole, relationMember.getMember()));
     114        return currentRole;
     115    }
     116}