User:SiliconFiend/Ruleset

From OpenStreetMap Wiki
Jump to navigation Jump to search

OSM Ruleset

There is a need for a ruleset different from those already used for Osmarender, etc. Those rulesets focus on the tags first and the output actions second. For creating routable formats from OSM data, I need to focus on the output actions first, and check the rules against tags of the element under consideration. This will allow me to have attributes with default values which can be overridden by tags which match tests.

My intent for this ruleset is primarily to use it to control the output for routable Garmin maps, but I can see how it could also be used to create a tag-value filter for Osmosis (or another tool) to only pass elements which match certain tests, or to transform tag values according to rules. The other major use I can see for it is for a tiling task. Different elements have to be treated differently when sliced at a tile boundary. Simple polylines are just hard-clipped at the boundary, closed ways (polygons) are hard-clipped to the boundary, but extended to fill in corners and meet up with its other boundary-clipped nodes, so that butting the tiles together will cause the original polygon to appear correctly (need to also carefully consider multipolygon relations). Routable polylines (roads, etc.) could be split at routing nodes according to some special rules governing which borders (North, East, South, West) clip polylines inside the boundary and which clip outside the boundary. Ideally the same ruleset file could be used for multiple purposes (tiling, tag filtering, routable map generation).

My goal for this ruleset is to make it extensible for developers to come up with new tests, etc. that can easily be plugged into this framework. I intend to write the ruleset interpreter in Java and incorporate it into Osmosis, but with the ruleset defined in XML, there's no reason it couldn't be re-implemented in another language.

Having said that, here is my current idea for a ruleset to process OSM data:

<!-- Example rule: -->
<action type="r_polyline" name="unpaved_road"> <!-- This declares the result or output -->
  <!-- This match element applies rules against the key-value pairs of the element being
  considered to see if it should be assigned the action. For ways, the nodelist may also
  be considered (to identify closed ways). If the result of the match is true, then the
  action is instantiated and its attributes can be processed. -->
  <match type="way">
    <!-- set of rules/tests, could be any/all/not, no tag, text match, regex, etc. -->
    <test type="simple_match" key="highway" value="track"/>
  </match>
  <!-- Actions can have attributes. If the attribute is mandatory, it must have a default value. -->
  <attribute name="garmin_type"> <!-- Which underlying GPS line type to use -->
    <default value="unpaved-road"/>
  </attribute>
  <attribute name="garmin_zoom"> <!-- Ending zoom level on GPS -->
    <default value="300m"/>
  </attribute>
  <attribute name="label">
    <tagval key="name"/> <!-- The attribute takes the value of the listed tag -->
      <!-- Could use a queue of names to fill the primary label slot, then the remaining items to fill alternate labels 2 through 4 -->
      <!-- There's also the "StreetDesc" attribute--how is it used? -->
  </attribute>
  <!-- Road class definitions, defines importance for routing. The following guidelines should be used:
       Class 4: 0.5% - 1.5% of roads (for motorways/highways)
       Class 3: 1% - 3% of roads
       Class 2: 4% - 7% of roads
       Class 1: 10% - 20% of roads
       Class 0: 60% - 85% of roads
  -->
  <attribute name="road_class"> <!-- Routing class, 0..4 -->
    <default value="0"/>
      <!-- could consider paved/unpaved or other tags here to modify routing class -->
  </attribue>
  <!-- Speed class definitions (default values; classes 2 through 6 can be redefined in MapSource)
       Class 7: 128 km/h	
       Class 6: 108 km/h
       Class 5: 93 km/h
       Class 4: 72 km/h
       Class 3: 56 km/h
       Class 2: 40 km/h
       Class 1: 20 km/h
       Class 0: 8 km/h (ferry)
  -->
  <attribute name="speed_class"> <!-- Speed class, 0..7 -->
    <!-- this set of attribute rules is a good candidate for turning into a link/subroutine -->
    <default value="1"/>
    <!-- Attributes can have zero or more attval elements. The first attval with a successful match
         wins, otherwise the default value is used. If no match and no default, then no attribute. -->
    <attval value="0">
      <match>
        <test type="leq" key="maxspeed" value="8"/> <!-- less than or equal, assumes numeric value -->
      </match>
    </attval>
    <attval value="1">
      <match>
        <all>
          <test type="leq" key="maxspeed" value="20"/>
          <test type="gt" key="maxspeed" value="8"/> <!-- greater than -->
            <!-- if the first attval with a successful match wins, the "greater than" test should be
                 unnecessary, because the "less than or equal" test in the previous attval would catch it. -->
        </all>
      </match>
    </attval>
    <attval value="2">
      <match>
        <all>
          <test type="leq" key="maxspeed" value="40"/>
          <test type="gt" key="maxspeed" value="20"/>
        </all>
      </match>
    </attval>
    <attval value="3">
      <match>
        <all>
          <test type="leq" key="maxspeed" value="56"/>
          <test type="gt" key="maxspeed" value="40"/>
        </all>
      </match>
    </attval>
    <attval value="4">
      <match>
        <all>
          <test type="leq" key="maxspeed" value="72"/>
          <test type="gt" key="maxspeed" value="56"/>
        </all>
      </match>
    </attval>
    <attval value="5">
      <match>
        <all>
          <test type="leq" key="maxspeed" value="93"/>
          <test type="gt" key="maxspeed" value="72"/>
        </all>
      </match>
    </attval>	
    <attval value="6">
      <match>
        <all>
          <test type="leq" key="maxspeed" value="108"/>
          <test type="gt" key="maxspeed" value="93"/>
        </all>
      </match>
    </attval>	
    <attval value="7">
      <match>
        <all>
          <test type="gt" key="maxspeed" value="108"/> <!-- No need to check less than; all we care is that it's the top speed class -->
        </all>
      </match>
    </attval>
  </attribue>
  <attribute name="oneway">
    <attval value="yes">
      <match>
        <test type="parse_boolean" key="oneway"/> <!-- The values "yes", "true", or "1" will return true, anything else returns false -->
      </match>
    </attval>
    <attval value="reverse"> <!-- reverse the way nodes when processed -->
      <match>
        <test type="simple_match" key="oneway" value="-1"/> <!-- Oneway in the opposite direction of the way -->
      </match>
    </attval>
  </attribute>
  <attribute name="toll">
    <attval value="yes">
      <match>
        <test type="parse_boolean" key="toll"/> <!-- How is this tagged, other than just tagging toll booths? -->
      </match>
    </attval>
  </attribute>
  <attribute name="access:emergency">
    <!-- This is just one example, for emergency vehicles. Note that Garmin supports restrictions for the 
         following types, shown with the default proposed mapping to the OSM access keys:
         Garmin Type      OSM access key
         Emergency        emergency
         Delivery         goods
         Car/Motorcycle   motorcar
         Bus              psv
         Taxi             ??? No "taxi"-specific approved access tag, maybe use motorcar?
         Pedestrian       foot
         Bicycle          bicycle
         Truck            hgv

         Sorry, Garmin has no separate treatment of motorcycle, but someone could make a motorcycle-specific rules file if they wanted.
    -->
    <default value="yes"/>
    <attval value="no">
      <match>
        <any>
          <test type="simple_match" key="access" value="no"/>
          <test type="simple_match" key="access" value="false"/>
          <test type="simple_match" key="emergency" value="no"/>
          <test type="simple_match" key="emergency" value="false"/>
        </any>
      </match>
    </attval>
  </attribute>
  <!-- The remainder of this <action> definition is attributes currently infeasible with OSM data:
  <attribute name="city_name_left">
  </attribute>
  <attribute name="city_name_right">
  </attribute>
  -->
  <!-- The region names would be states or provinces, etc. -->
  <!--
  <attribute name="region_name_left">
  </attribute>
  <attribute name="region_name_right">
  </attribute>
  <attribute name="country_name_left">
  </attribute>
  <attribute name="country_name_right">
  </attribute>
  -->
  <!-- The postal codes may be possible with TIGER data. -->
  <!--
  <attribute name="postal_code_left">
  </attribute>
  <attribute name="postal_code_right">
  </attribute>
  -->
  <!-- House/street numbers are probably best handled by relations, no agreed OSM tagging format yet
       cGPSMapper format supports none/odd/even/both numbering schemes
  <!-- Turn restrictions need to be handled by relations
       Can theoretically have time-dependent restrictions, but the cGPSmapper format/support is unclear
       Can exempt certain vehicle types from the turn restrictions using RestrParam=1,0,0,0,0,0,0,0 for 
       vehicle types Emergency, Delivery, Car/Motorcycle, Bus, Taxi, Pedestrian, Bicycle, Truck
       (example exempts emergency vehicles from the turn restriction)
  -->
  <!-- Highway exit information is not (yet) supported, although it might not be too difficult to do so.
       It would probably just involve detecting the exit nodes and ref numbers, then collecting the
       amenity nodes within a certain radius to add to the exit services list.
  -->
</action>

<!--
 More stuff to do:
   Linked rulesets or attribute definitions (for reuse), like subroutines
   Create temporary variables for use by the ruleset (i.e., output of a pregreplace)
   Some way to create derived values, such as parsing the ref tag for inclusion in the name.
   Create tests which inspect waynodes (such as test for closed way)
   Create tests which inspect tags on waynodes (to test for things such as stop signs, bridge clearance, etc.)
-->