/// <summary> /// Encodes a form of way into binary data. /// </summary> /// <param name="formOfWay"></param> /// <param name="data"></param> /// <param name="startIndex"></param> /// <param name="byteIndex"></param> public static void Encode(FormOfWay formOfWay, byte[] data, int startIndex, int byteIndex) { if (byteIndex > 5) { throw new ArgumentOutOfRangeException("byteIndex", "byteIndex has to be a value in the range of [0-5]."); } int value = 0; switch (formOfWay) { case FormOfWay.Undefined: value = 0; break; case FormOfWay.Motorway: value = 1; break; case FormOfWay.MultipleCarriageWay: value = 2; break; case FormOfWay.SingleCarriageWay: value = 3; break; case FormOfWay.Roundabout: value = 4; break; case FormOfWay.TrafficSquare: value = 5; break; case FormOfWay.SlipRoad: value = 6; break; case FormOfWay.Other: value = 7; break; } byte target = data[startIndex]; byte mask = (byte)(7 << (5 - byteIndex)); target = (byte)(target & ~mask); // set to zero. value = (byte)(value << (5 - byteIndex)); // move value to correct position. target = (byte)(target | value); // add to byte. data[startIndex] = target; }
/// <summary> /// Calculates a match between the tags collection and the properties of the OpenLR location reference. /// </summary> /// <param name="tags"></param> /// <param name="fow"></param> /// <param name="frc"></param> /// <returns></returns> public override float MatchArc(TagsCollectionBase tags, FormOfWay fow, FunctionalRoadClass frc) { FormOfWay actualFow; FunctionalRoadClass actualFrc; if (NWBMapping.ToOpenLR(tags, out actualFow, out actualFrc)) { // a mapping was found. match and score. return(MatchScoring.MatchAndScore(frc, fow, actualFrc, actualFow)); } return(0); }
/// <summary> /// Matches nwb/fow. /// </summary> public virtual float Match(IAttributeCollection attributes, FormOfWay fow, FunctionalRoadClass frc) { FormOfWay actualFow; FunctionalRoadClass actualFrc; if (this.Extract(attributes, out actualFrc, out actualFow)) { // a mapping was found. match and score. return(MatchScoring.MatchAndScore(frc, fow, actualFrc, actualFow)); } return(0); }
/// <summary> /// Calculates a matching and score by comparing the expected agains the actual FRC's and FOW's. /// </summary> /// <param name="expectedFrc"></param> /// <param name="expectedFow"></param> /// <param name="actualFrc"></param> /// <param name="actualFow"></param> /// <returns></returns> public static float MatchAndScore(FunctionalRoadClass expectedFrc, FormOfWay expectedFow, FunctionalRoadClass actualFrc, FormOfWay actualFow) { if (expectedFow == actualFow && expectedFrc == actualFrc) { // perfect score. return(1); } // sore frc and fow seperately and take frc for 75% and fow for 25%. float frcWeight = .75f, fowWeight = .25f; return(MatchScoring.MatchAndScore(expectedFrc, actualFrc) * frcWeight + MatchScoring.MatchAndScore(expectedFow, actualFow) * fowWeight); }
/// <summary> /// Tries to match the given tags and figure out a corresponding frc and fow. /// </summary> /// <param name="tags"></param> /// <param name="frc"></param> /// <param name="fow"></param> /// <returns>False if no matching was found.</returns> public override bool TryMatching(TagsCollectionBase tags, out FunctionalRoadClass frc, out FormOfWay fow) { return(NWBMapping.ToOpenLR(tags, out fow, out frc)); }
/// <summary> /// Tries to match the given tags and figure out a corresponding frc and fow. /// </summary> /// <param name="tags"></param> /// <param name="frc"></param> /// <param name="fow"></param> /// <returns>False if no matching was found.</returns> protected bool TryMatching(TagsCollectionBase tags, out FunctionalRoadClass frc, out FormOfWay fow) { return(_mainEncoder.TryMatching(tags, out frc, out fow)); }
/// <summary> /// Calculates a matching and score by comparing the expected agains the actual FOW's. /// </summary> /// <param name="expected"></param> /// <param name="actual"></param> /// <returns></returns> public static float MatchAndScore(FormOfWay expected, FormOfWay actual) { if (expected == actual) { // perfect score. return(1); } float scoreMatch = 0.8f; float scoreAlmostMatch = 0.6f; float other = 0.2f; switch (expected) { case FormOfWay.Motorway: switch (actual) { case FormOfWay.MultipleCarriageWay: return(scoreMatch); case FormOfWay.SingleCarriageWay: return(scoreAlmostMatch); default: return(other); } case FormOfWay.MultipleCarriageWay: switch (actual) { case FormOfWay.Motorway: return(scoreMatch); case FormOfWay.SingleCarriageWay: return(scoreMatch); default: return(other); } case FormOfWay.SingleCarriageWay: switch (actual) { case FormOfWay.Motorway: return(scoreAlmostMatch); case FormOfWay.MultipleCarriageWay: return(scoreMatch); default: return(other); } case FormOfWay.Roundabout: switch (actual) { case FormOfWay.SingleCarriageWay: return(scoreAlmostMatch); case FormOfWay.SlipRoad: return(scoreMatch); default: return(other); } case FormOfWay.SlipRoad: switch (actual) { case FormOfWay.SingleCarriageWay: return(scoreAlmostMatch); case FormOfWay.Roundabout: return(scoreMatch); default: return(other); } default: return(other); } }
/// <summary> /// Tries to extract fow/frc from the given attributes. /// </summary> public abstract bool Extract(IAttributeCollection tags, out FunctionalRoadClass frc, out FormOfWay fow);
/// <summary> /// Finds candidate edges starting at a given vertex matching a given fow and frc. /// </summary> /// <param name="vertex"></param> /// <param name="forward"></param> /// <param name="fow"></param> /// <param name="frc"></param> /// <param name="bearing"></param> /// <returns></returns> public virtual IEnumerable <CandidateEdge> FindCandidateEdgesFor(long vertex, bool forward, FormOfWay fow, FunctionalRoadClass frc, Degree bearing) { var relevantEdges = new List <CandidateEdge>(); foreach (var arc in this.Graph.GetEdges(vertex)) { var tags = this.Graph.TagsIndex.Get(arc.Value.Tags); // check one-way. if (_vehicle.CanTraverse(tags)) { // yay! can traverse. var oneway = _vehicle.IsOneWay(tags); if (oneway == null || (forward && oneway.Value == arc.Value.Forward) || (!forward && oneway.Value != arc.Value.Forward)) { var score = Score.New(Score.MATCH_ARC, "Metric indicating a match with fow, frc etc...", this.MatchArc(tags, fow, frc), 2); if (score.Value > 0) { // ok, there is a match. // check bearing. var shape = this.Graph.GetEdgeShape(vertex, arc.Key); var localBearing = this.GetBearing(vertex, arc.Value, shape, arc.Key, true); var localBearingDiff = (float)System.Math.Abs(localBearing.SmallestDifference(bearing)); relevantEdges.Add(new CandidateEdge() { TargetVertex = arc.Key, Score = score + Score.New(Score.BEARING_DIFF, "Bearing difference (0=0 & 180=1)", ((180f - localBearingDiff) / 180f), 1), Edge = arc.Value }); } } } } return(relevantEdges); }
/// <summary> /// Calculates a match between the tags collection and the properties of the OpenLR location reference. /// </summary> /// <param name="tags"></param> /// <param name="fow"></param> /// <param name="frc"></param> /// <returns></returns> public abstract float MatchArc(TagsCollectionBase tags, FormOfWay fow, FunctionalRoadClass frc);
/// <summary> /// Calculates a match between the tags collection and the properties of the OpenLR location reference. /// </summary> /// <param name="tags"></param> /// <param name="fow"></param> /// <param name="frc"></param> /// <returns></returns> public override float MatchArc(TagsCollectionBase tags, FormOfWay fow, FunctionalRoadClass frc) { string highway; if (!tags.TryGetValue("highway", out highway)) { // not even a highway tag! return(0); } // TODO: take into account form of way? Maybe not for OSM-data? switch (frc) { // check there reference values against OSM: http://wiki.openstreetmap.org/wiki/Highway case FunctionalRoadClass.Frc0: // main road. if (highway == "motorway" || highway == "trunk") { return(1); } break; case FunctionalRoadClass.Frc1: // first class road. if (highway == "primary" || highway == "primary_link") { return(1); } break; case FunctionalRoadClass.Frc2: // second class road. if (highway == "secondary" || highway == "secondary_link") { return(1); } break; case FunctionalRoadClass.Frc3: // third class road. if (highway == "tertiary" || highway == "tertiary_link") { return(1); } break; case FunctionalRoadClass.Frc4: if (highway == "road" || highway == "road_link" || highway == "unclassified" || highway == "residential") { return(1); } break; case FunctionalRoadClass.Frc5: if (highway == "road" || highway == "road_link" || highway == "unclassified" || highway == "residential" || highway == "living_street") { return(1); } break; case FunctionalRoadClass.Frc6: if (highway == "road" || highway == "track" || highway == "unclassified" || highway == "residential" || highway == "living_street") { return(1); } break; case FunctionalRoadClass.Frc7: // other class road. if (highway == "footway" || highway == "bridleway" || highway == "steps" || highway == "path" || highway == "living_street") { return(1); } break; } if (highway != null && highway.Length > 0) { // for any other highway return a low match. return(0.2f); } return(0); }
/// <summary> /// Tries to match the given tags and figure out a corresponding frc and fow. /// </summary> /// <param name="tags"></param> /// <param name="frc"></param> /// <param name="fow"></param> /// <returns>False if no matching was found.</returns> public abstract bool TryMatching(TagsCollectionBase tags, out FunctionalRoadClass frc, out FormOfWay fow);
/// <summary> /// Tries to match the given tags and figure out a corresponding frc and fow. /// </summary> /// <param name="tags"></param> /// <param name="frc"></param> /// <param name="fow"></param> /// <returns>False if no matching was found.</returns> public override bool TryMatching(TagsCollectionBase tags, out FunctionalRoadClass frc, out FormOfWay fow) { frc = FunctionalRoadClass.Frc7; fow = FormOfWay.Undefined; string highway; if (tags.TryGetValue("highway", out highway)) { switch (highway) { // check there reference values against OSM: http://wiki.openstreetmap.org/wiki/Highway case "motorway": case "trunk": frc = FunctionalRoadClass.Frc0; break; case "primary": case "primary_link": frc = FunctionalRoadClass.Frc1; break; case "secondary": case "secondary_link": frc = FunctionalRoadClass.Frc2; break; case "tertiary": case "tertiary_link": frc = FunctionalRoadClass.Frc3; break; case "road": case "road_link": case "unclassified": case "residential": frc = FunctionalRoadClass.Frc4; break; case "living_street": frc = FunctionalRoadClass.Frc5; break; default: frc = FunctionalRoadClass.Frc7; break; } switch (highway) { // check there reference values against OSM: http://wiki.openstreetmap.org/wiki/Highway case "motorway": case "trunk": fow = FormOfWay.Motorway; break; case "primary": case "primary_link": fow = FormOfWay.MultipleCarriageWay; break; case "secondary": case "secondary_link": case "tertiary": case "tertiary_link": fow = FormOfWay.SingleCarriageWay; break; default: fow = FormOfWay.SingleCarriageWay; break; } return(true); // should never fail on a highway tag. } return(false); }
/// <summary> /// Extracts nwb/fow. /// </summary> public override bool Extract(IAttributeCollection attributes, out FunctionalRoadClass frc, out FormOfWay fow) { fow = FormOfWay.Undefined; frc = FunctionalRoadClass.Frc7; string baansubsrt = string.Empty, wegbeerder = string.Empty, wegnummer = string.Empty, rijrichting = string.Empty, dvkletter_ = string.Empty; if (!attributes.TryGetValue(BAANSUBSRT, out baansubsrt) & !attributes.TryGetValue(WEGBEHSRT, out wegbeerder) & !attributes.TryGetValue(WEGNUMMER, out wegnummer) & !attributes.TryGetValue(HECTOLTTR, out dvkletter_) & !attributes.TryGetValue(RIJRICHTNG, out rijrichting)) { // not even a BAANSUBSRT tag! // defaults: FRC5, OTHER. fow = FormOfWay.Other; frc = FunctionalRoadClass.Frc5; return(true); } // make sure everything is lowercase. char?dvkletter = null; // assume dkv letter is the suffix used for exits etc. see: http://www.wegenwiki.nl/Hectometerpaal#Suffix if (!string.IsNullOrWhiteSpace(wegbeerder)) { wegbeerder = wegbeerder.ToLowerInvariant(); } if (!string.IsNullOrWhiteSpace(baansubsrt)) { baansubsrt = baansubsrt.ToLowerInvariant(); } if (!string.IsNullOrWhiteSpace(wegnummer)) { wegnummer = wegnummer.ToLowerInvariant(); if (!string.IsNullOrEmpty(dvkletter_)) { dvkletter = dvkletter_[0]; } } if (!string.IsNullOrWhiteSpace(rijrichting)) { rijrichting = rijrichting.ToLowerInvariant(); } fow = FormOfWay.Other; frc = FunctionalRoadClass.Frc5; if (wegbeerder == "r") { if (baansubsrt == "hr") { fow = FormOfWay.Motorway; frc = FunctionalRoadClass.Frc0; } else if (baansubsrt == "nrb" || baansubsrt == "mrb") { fow = FormOfWay.Roundabout; frc = FunctionalRoadClass.Frc0; } else if (baansubsrt == "pst") { if (dvkletter.HasValue) { fow = FormOfWay.SlipRoad; if (dvkletter == 'a' || dvkletter == 'b' || dvkletter == 'c' || dvkletter == 'd') { // r pst (a|b|c|d) frc = FunctionalRoadClass.Frc3; } else { // r pst !(a|b|c|d) frc = FunctionalRoadClass.Frc0; } } else if (!string.IsNullOrWhiteSpace(rijrichting)) { // r pst !(a|b|c|d) fow = FormOfWay.SlipRoad; frc = FunctionalRoadClass.Frc0; } } else if (baansubsrt == "opr" || baansubsrt == "afr") { frc = FunctionalRoadClass.Frc3; fow = FormOfWay.SlipRoad; } else if (baansubsrt.StartsWith("vb")) { if (!string.IsNullOrWhiteSpace(rijrichting)) { fow = FormOfWay.SlipRoad; frc = FunctionalRoadClass.Frc0; } } } else if (wegbeerder == "p") { if (baansubsrt == "hr") { frc = FunctionalRoadClass.Frc3; fow = FormOfWay.MultipleCarriageWay; if (string.IsNullOrWhiteSpace(rijrichting)) { frc = FunctionalRoadClass.Frc2; fow = FormOfWay.SingleCarriageWay; } } else if (baansubsrt == "nrb" || baansubsrt == "mrb") { frc = FunctionalRoadClass.Frc3; fow = FormOfWay.Roundabout; } else if (baansubsrt == "opr" || baansubsrt == "afr") { frc = FunctionalRoadClass.Frc3; fow = FormOfWay.SlipRoad; } else if (baansubsrt == "pst" || baansubsrt.StartsWith("vb")) { frc = FunctionalRoadClass.Frc3; fow = FormOfWay.SlipRoad; } } return(true); }
/// <summary> /// Finds candidate edges starting at a given vertex matching a given fow and frc. /// </summary> public static IEnumerable <CandidatePathSegment> FindCandidatePathSegmentsFor(this Coder coder, CandidateLocation location, bool forward, FormOfWay fow, FunctionalRoadClass frc, float bearing) { var profile = coder.Profile; var relevantEdges = new List <CandidatePathSegment>(); if (location.Location.IsVertex()) { // location is a vertex, probably 99% of the time. var vertex = location.Location.VertexId(coder.Router.Db); var edgeEnumerator = coder.Router.Db.Network.GetEdgeEnumerator(vertex); foreach (var edge in edgeEnumerator) { var edgeProfile = coder.Router.Db.EdgeProfiles.Get(edge.Data.Profile); var factor = profile.Profile.Factor(edgeProfile); if (factor.Value > 0 && (factor.Direction == 0 || (forward && (factor.Direction == 1) != edge.DataInverted) || (!forward && (factor.Direction == 1) == edge.DataInverted))) { var matchScore = Score.New(Score.MATCH_ARC, "Metric indicating a match with fow, frc etc...", profile.Match(edgeProfile, fow, frc), 2); if (matchScore.Value > 0) { // ok, there is a match. // check bearing. var shape = coder.Router.Db.Network.GetShape(edge); var localBearing = BearingEncoder.EncodeBearing(shape, false); var localBearingDiff = System.Math.Abs(Extensions.AngleSmallestDifference(localBearing, bearing)); var bearingScore = Score.New(Score.BEARING_DIFF, "Bearing difference score (0=1 & 180=0)", (1f - (localBearingDiff / 180f)) * 2, 2); relevantEdges.Add(new CandidatePathSegment() { Score = location.Score * (matchScore + bearingScore), Location = location.Location, Path = new EdgePath <float>(edge.To, factor.Value * edge.Data.Distance, edge.IdDirected(), new EdgePath <float>(vertex)) }); } } } } else { // location is not a vertex but a virtual point, try available directions. var paths = location.Location.ToEdgePaths(coder.Router.Db, coder.Profile.Profile.DefaultWeightHandlerCached(coder.Router.Db), forward); var edgeEnumerator = coder.Router.Db.Network.GetEdgeEnumerator(); var locationOnNetwork = location.Location.LocationOnNetwork(coder.Router.Db); foreach (var path in paths) { if (path.From == null) { throw new Exception("An LRP was resolved while at the same time it resolved to an exact vertex."); } edgeEnumerator.MoveToEdge(path.Edge); var edge = edgeEnumerator.Current; var edgeProfile = coder.Router.Db.EdgeProfiles.Get(edge.Data.Profile); var matchScore = Score.New(Score.MATCH_ARC, "Metric indicating a match with fow, frc etc...", profile.Match(edgeProfile, fow, frc), 2); if (matchScore.Value > 0) { // ok, there is a match. // check bearing. // get shape from location -> path. var shape = location.Location.ShapePointsTo(coder.Router.Db, path.Vertex); shape.Insert(0, locationOnNetwork); shape.Add(coder.Router.Db.Network.GetVertex(path.Vertex)); var localBearing = BearingEncoder.EncodeBearing(shape, false); var localBearingDiff = System.Math.Abs(Extensions.AngleSmallestDifference(localBearing, bearing)); var bearingScore = Score.New(Score.BEARING_DIFF, "Bearing difference score (0=1 & 180=0)", (1f - (localBearingDiff / 180f)) * 2, 2); relevantEdges.Add(new CandidatePathSegment() { Score = location.Score * (matchScore + bearingScore), Location = location.Location, Path = path }); } } } return(relevantEdges); }
/// <summary> /// Calculates a match between the tags collection and the properties of the OpenLR location reference. /// </summary> /// <param name="tags"></param> /// <param name="fow"></param> /// <param name="frc"></param> /// <returns></returns> public override float MatchArc(TagsCollectionBase tags, FormOfWay fow, FunctionalRoadClass frc) { string frcString; if (!tags.TryGetValue("FRC", out frcString)) { // not even an FRC column. return(0); } float frcOneDifferent = 0.8f; float frcTwoDifferent = 0.6f; float frcMoreDifferent = 0.4f; var frcScore = 0.0f; switch (frcString) { case "0": // main road. if (frc == FunctionalRoadClass.Frc0) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc1) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc2) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "1": // first class road. if (frc == FunctionalRoadClass.Frc1) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc0 || frc == FunctionalRoadClass.Frc2) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc3) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "2": // second class road. if (frc == FunctionalRoadClass.Frc2) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc1 || frc == FunctionalRoadClass.Frc3) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc4 || frc == FunctionalRoadClass.Frc0) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "3": if (frc == FunctionalRoadClass.Frc3) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc2 || frc == FunctionalRoadClass.Frc4) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc1 || frc == FunctionalRoadClass.Frc5) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "4": if (frc == FunctionalRoadClass.Frc4) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc3 || frc == FunctionalRoadClass.Frc5) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc2 || frc == FunctionalRoadClass.Frc6) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "5": if (frc == FunctionalRoadClass.Frc5) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc4 || frc == FunctionalRoadClass.Frc6) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc3 || frc == FunctionalRoadClass.Frc7) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "6": if (frc == FunctionalRoadClass.Frc6) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc5 || frc == FunctionalRoadClass.Frc7) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc4) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "7": if (frc == FunctionalRoadClass.Frc7) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc6) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc5) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "8": if (frc == FunctionalRoadClass.Frc7) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc6) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; } float fowOneDifferent = 0.8f; float fowMoreDifferent = 0.4f; var fowScore = 0.0f; string fowString; if (tags.TryGetValue("FOW", out fowString)) { fowScore = 0.2f; switch (fowString) { case "1": if (fow == FormOfWay.Motorway) { fowScore = 1; } else if (fow == FormOfWay.MultipleCarriageWay) { fowScore = fowOneDifferent; } break; case "2": if (fow == FormOfWay.MultipleCarriageWay) { fowScore = 1; } else if (fow == FormOfWay.Motorway || fow == FormOfWay.SingleCarriageWay) { fowScore = fowOneDifferent; } break; case "3": if (fow == FormOfWay.SingleCarriageWay) { fowScore = 1; } else if (fow == FormOfWay.MultipleCarriageWay) { fowScore = fowOneDifferent; } break; case "4": if (fow == FormOfWay.Roundabout) { fowScore = 1; } fowScore = fowMoreDifferent; break; case "8": if (fow == FormOfWay.TrafficSquare) { fowScore = 1; } fowScore = fowMoreDifferent; break; case "10": if (fow == FormOfWay.SlipRoad) { fowScore = 1; } fowScore = fowMoreDifferent; break; case "6": case "7": case "9": case "11": case "12": case "14": case "15": if (fow == FormOfWay.Other) { fowScore = fowOneDifferent; } break; default: if (fow == FormOfWay.Undefined) { fowScore = fowMoreDifferent; } break; } } return(frcScore + fowScore); }
/// <summary> /// Tries to match the given tags and figure out a corresponding frc and fow. /// </summary> /// <param name="tags"></param> /// <param name="frc"></param> /// <param name="fow"></param> /// <returns>False if no matching was found.</returns> public override bool TryMatching(TagsCollectionBase tags, out FunctionalRoadClass frc, out FormOfWay fow) { frc = FunctionalRoadClass.Frc7; fow = FormOfWay.Undefined; string frcValue; if (tags.TryGetValue("FRC", out frcValue)) { switch (frcValue) { case "0": // main road. frc = FunctionalRoadClass.Frc0; break; case "1": // main road. frc = FunctionalRoadClass.Frc1; break; case "2": // main road. frc = FunctionalRoadClass.Frc2; break; case "3": // main road. frc = FunctionalRoadClass.Frc3; break; case "4": // main road. frc = FunctionalRoadClass.Frc4; break; case "5": // main road. frc = FunctionalRoadClass.Frc5; break; case "6": // main road. frc = FunctionalRoadClass.Frc6; break; case "7": // main road. frc = FunctionalRoadClass.Frc7; break; } } string fowValue; if (tags.TryGetValue("FOW", out fowValue)) { switch (fowValue) { case "1": // main road. fow = FormOfWay.Motorway; break; case "2": fow = FormOfWay.MultipleCarriageWay; break; case "3": fow = FormOfWay.SingleCarriageWay; break; case "4": fow = FormOfWay.Roundabout; break; case "8": fow = FormOfWay.TrafficSquare; break; case "10": fow = FormOfWay.SlipRoad; break; case "6": case "7": case "9": case "11": case "12": case "14": case "15": fow = FormOfWay.Other; break; } } return(true); }