public void EncodedReferencedPointAlongLineLocation()
        {
            // build a graph to encode from.
            var  tags            = new TagsTableCollectionIndex();
            var  graphDataSource = new DynamicGraphRouterDataSource <LiveEdge>(tags);
            uint vertex1         = graphDataSource.AddVertex(49.60597f, 6.12829f);
            uint vertex2         = graphDataSource.AddVertex(49.60521f, 6.12779f);

            graphDataSource.AddEdge(vertex1, vertex2, new LiveEdge()
            {
                Distance = 10,
                Forward  = true,
                Tags     = tags.Add(new TagsCollection(
                                        Tag.Create("BAANSUBSRT", "VBD"),
                                        Tag.Create("WEGBEHSRT", "R"),
                                        Tag.Create("WEGNUMMER", string.Empty),
                                        Tag.Create("RIJRICHTNG", "N")))
            }, null);
            graphDataSource.AddEdge(vertex2, vertex1, new LiveEdge()
            {
                Distance = 10,
                Forward  = false,
                Tags     = tags.Add(new TagsCollection(
                                        Tag.Create("BAANSUBSRT", "VBD"),
                                        Tag.Create("WEGBEHSRT", "R"),
                                        Tag.Create("WEGNUMMER", string.Empty),
                                        Tag.Create("RIJRICHTNG", "N"),
                                        Tag.Create("HECTOLTTR", string.Empty)))
            }, null);

            // create a referenced location and encode it.
            var graph = new BasicRouterDataSource <LiveEdge>(graphDataSource);
            var referencedPointAlongLineLocation = new ReferencedPointAlongLine();

            referencedPointAlongLineLocation.Route          = new ReferencedLine(graph);
            referencedPointAlongLineLocation.Route.Edges    = new LiveEdge[1];
            referencedPointAlongLineLocation.Route.Edges[0] = new LiveEdge()
            {
                Distance = 10,
                Forward  = true,
                Tags     = tags.Add(new TagsCollection(
                                        Tag.Create("BAANSUBSRT", "VBD"),
                                        Tag.Create("WEGBEHSRT", "R"),
                                        Tag.Create("WEGNUMMER", string.Empty),
                                        Tag.Create("RIJRICHTNG", "N"),
                                        Tag.Create("HECTOLTTR", string.Empty)))
            };
            referencedPointAlongLineLocation.Route.EdgeShapes    = new GeoCoordinateSimple[1][];
            referencedPointAlongLineLocation.Route.EdgeShapes[0] = new GeoCoordinateSimple[0];
            referencedPointAlongLineLocation.Route.Vertices      = new long[2];
            referencedPointAlongLineLocation.Route.Vertices[0]   = vertex1;
            referencedPointAlongLineLocation.Route.Vertices[1]   = vertex2;
            referencedPointAlongLineLocation.Latitude            = (49.60597f + 49.60521f) / 2f;
            referencedPointAlongLineLocation.Longitude           = (6.12829f + 6.12779f) / 2f;

            // encode location.
            var encoder           = new PointAlongLineEncoder();
            var mainEncoder       = new ReferencedNWBEncoder(graph, null);
            var referencedEncoder = new ReferencedPointAlongLineEncoder(mainEncoder, encoder);
            var location          = referencedEncoder.EncodeReferenced(referencedPointAlongLineLocation);

            // test result.
            Assert.IsNotNull(location);
            Assert.AreEqual(SideOfRoad.OnOrAbove, location.SideOfRoad);
            Assert.AreEqual(Orientation.NoOrientation, location.Orientation);
            Assert.AreEqual(50, location.PositiveOffsetPercentage.Value, 0.5f);

            Assert.AreEqual(49.60597f, location.First.Coordinate.Latitude);
            Assert.AreEqual(6.12829f, location.First.Coordinate.Longitude);
            Assert.AreEqual(91, location.First.DistanceToNext);
            Assert.AreEqual(FormOfWay.SlipRoad, location.First.FormOfWay);
            Assert.AreEqual(FunctionalRoadClass.Frc0, location.First.FuntionalRoadClass);
            Assert.AreEqual(FunctionalRoadClass.Frc0, location.First.LowestFunctionalRoadClassToNext);

            Assert.AreEqual(49.60521f, location.Last.Coordinate.Latitude);
            Assert.AreEqual(6.12779f, location.Last.Coordinate.Longitude);

            // TODO: encode location with a point on or at the first and last points.
        }
        public void EncodeBase64Test()
        {
            double delta = 0.0001;

            // create a location.
            var location = new PointAlongLineLocation();

            location.First            = new LocationReferencePoint();
            location.First.Coordinate = new Coordinate()
            {
                Latitude  = 49.60597,
                Longitude = 6.12829
            };
            location.First.FuntionalRoadClass = FunctionalRoadClass.Frc2;
            location.First.FormOfWay          = FormOfWay.MultipleCarriageWay;
            location.First.LowestFunctionalRoadClassToNext = FunctionalRoadClass.Frc2;
            location.First.Bearing        = 17;
            location.First.DistanceToNext = (int)(58.6 * 2) + 1;

            location.Last            = new LocationReferencePoint();
            location.Last.Coordinate = new Coordinate()
            {
                Latitude  = 49.60521,
                Longitude = 6.12779
            };
            location.Last.FuntionalRoadClass = FunctionalRoadClass.Frc2;
            location.Last.FormOfWay          = FormOfWay.MultipleCarriageWay;
            location.Last.Bearing            = 3;
            location.Last.DistanceToNext     = 0;

            location.Orientation = Orientation.NoOrientation;
            location.SideOfRoad  = SideOfRoad.Left;
            location.PositiveOffsetPercentage = 30.19f;

            // encode.
            var encoder    = new PointAlongLineEncoder();
            var stringData = encoder.Encode(location);

            // decode again (decoding was tested above).
            var decoder         = new PointAlongLineDecoder();
            var decodedLocation = decoder.Decode(stringData);

            Assert.IsNotNull(decodedLocation);
            Assert.IsInstanceOf <PointAlongLineLocation>(decodedLocation);
            var pointAlongLineLocation = (decodedLocation as PointAlongLineLocation);

            // check first reference.
            Assert.IsNotNull(pointAlongLineLocation.First);
            Assert.AreEqual(location.First.Coordinate.Longitude, pointAlongLineLocation.First.Coordinate.Longitude, delta); // 6.12829°
            Assert.AreEqual(location.First.Coordinate.Latitude, pointAlongLineLocation.First.Coordinate.Latitude, delta);   // 49.60597°
            Assert.AreEqual(location.First.FuntionalRoadClass, pointAlongLineLocation.First.FuntionalRoadClass);
            Assert.AreEqual(location.First.FormOfWay, pointAlongLineLocation.First.FormOfWay);
            Assert.AreEqual(location.First.LowestFunctionalRoadClassToNext, pointAlongLineLocation.First.LowestFunctionalRoadClassToNext);
            Assert.AreEqual(location.First.Bearing.Value, pointAlongLineLocation.First.Bearing.Value, 11.25); // binary encode loses accuracy for bearing.
            Assert.AreEqual(location.First.DistanceToNext, pointAlongLineLocation.First.DistanceToNext);

            // check second reference.
            Assert.IsNotNull(pointAlongLineLocation.Last);
            Assert.AreEqual(location.Last.Coordinate.Longitude, pointAlongLineLocation.Last.Coordinate.Longitude, delta); // 6.12779°
            Assert.AreEqual(location.Last.Coordinate.Latitude, pointAlongLineLocation.Last.Coordinate.Latitude, delta);   // 49.60521°
            Assert.AreEqual(location.Last.FuntionalRoadClass, pointAlongLineLocation.Last.FuntionalRoadClass);
            Assert.AreEqual(location.Last.FormOfWay, pointAlongLineLocation.Last.FormOfWay);
            Assert.AreEqual(location.Last.Bearing.Value, pointAlongLineLocation.Last.Bearing.Value, 11.25); // binary encode loses accuracy for bearing.
            Assert.AreEqual(location.Last.DistanceToNext, pointAlongLineLocation.Last.DistanceToNext);

            // check other properties.
            Assert.AreEqual(location.Orientation, pointAlongLineLocation.Orientation);
            Assert.AreEqual(location.SideOfRoad, pointAlongLineLocation.SideOfRoad);
            Assert.AreEqual(location.PositiveOffsetPercentage.Value, pointAlongLineLocation.PositiveOffsetPercentage.Value, 0.5f); // binary encode loses accuracy.

            // compare again with reference encoded string.
            var referenceStringData      = "KwRbnyNGfhJBAv/P/7WSAEw=";
            var referenceDecodedLocation = decoder.Decode(referenceStringData);

            var referenceBinary = System.Convert.FromBase64String(referenceStringData);
            var encodedBinary   = System.Convert.FromBase64String(stringData);

            // check first reference.
            Assert.IsNotNull(pointAlongLineLocation.First);
            Assert.AreEqual(referenceDecodedLocation.First.Coordinate.Longitude, pointAlongLineLocation.First.Coordinate.Longitude, delta); // 6.12829°
            Assert.AreEqual(referenceDecodedLocation.First.Coordinate.Latitude, pointAlongLineLocation.First.Coordinate.Latitude, delta);   // 49.60597°
            Assert.AreEqual(referenceDecodedLocation.First.FuntionalRoadClass, pointAlongLineLocation.First.FuntionalRoadClass);
            Assert.AreEqual(referenceDecodedLocation.First.FormOfWay, pointAlongLineLocation.First.FormOfWay);
            Assert.AreEqual(referenceDecodedLocation.First.LowestFunctionalRoadClassToNext, pointAlongLineLocation.First.LowestFunctionalRoadClassToNext);
            Assert.AreEqual(referenceDecodedLocation.First.Bearing.Value, pointAlongLineLocation.First.Bearing.Value, 11.25); // binary encode loses accuracy for bearing.

            // check second reference.
            Assert.IsNotNull(pointAlongLineLocation.Last);
            Assert.AreEqual(referenceDecodedLocation.Last.Coordinate.Longitude, pointAlongLineLocation.Last.Coordinate.Longitude, delta); // 6.12779°
            Assert.AreEqual(referenceDecodedLocation.Last.Coordinate.Latitude, pointAlongLineLocation.Last.Coordinate.Latitude, delta);   // 49.60521°
            Assert.AreEqual(referenceDecodedLocation.Last.FuntionalRoadClass, pointAlongLineLocation.Last.FuntionalRoadClass);
            Assert.AreEqual(referenceDecodedLocation.Last.FormOfWay, pointAlongLineLocation.Last.FormOfWay);
            Assert.AreEqual(referenceDecodedLocation.Last.Bearing.Value, pointAlongLineLocation.Last.Bearing.Value, 11.25); // binary encode loses accuracy for bearing.

            // check other properties.
            Assert.AreEqual(referenceDecodedLocation.Orientation, pointAlongLineLocation.Orientation);
            Assert.AreEqual(referenceDecodedLocation.SideOfRoad, pointAlongLineLocation.SideOfRoad);
            Assert.AreEqual(referenceDecodedLocation.PositiveOffsetPercentage.Value, pointAlongLineLocation.PositiveOffsetPercentage.Value, 0.5f); // binary encode loses accuracy.
        }
        public void EncodeReferencedPointAlongLineLocation()
        {
            // build a graph to encode from.
            var  tags            = new TagsTableCollectionIndex();
            var  graphDataSource = new DynamicGraphRouterDataSource <LiveEdge>(tags);
            uint vertex1         = graphDataSource.AddVertex(49.60597f, 6.12829f);
            uint vertex2         = graphDataSource.AddVertex(49.60521f, 6.12779f);

            graphDataSource.AddEdge(vertex1, vertex2, new LiveEdge()
            {
                Distance = 10,
                Forward  = true,
                Tags     = tags.Add(new TagsCollection(Tag.Create("highway", "tertiary")))
            }, null);
            graphDataSource.AddEdge(vertex2, vertex1, new LiveEdge()
            {
                Distance = 10,
                Forward  = false,
                Tags     = tags.Add(new TagsCollection(Tag.Create("highway", "tertiary")))
            }, null);

            // create a referenced location and encode it.
            var graph = new BasicRouterDataSource <LiveEdge>(graphDataSource);
            var referencedPointAlongLineLocation = new ReferencedPointAlongLine();

            referencedPointAlongLineLocation.Route          = new ReferencedLine(graph);
            referencedPointAlongLineLocation.Route.Edges    = new LiveEdge[1];
            referencedPointAlongLineLocation.Route.Edges[0] = new LiveEdge()
            {
                Distance = 10,
                Forward  = true,
                Tags     = tags.Add(new TagsCollection(Tag.Create("highway", "tertiary")))
            };
            referencedPointAlongLineLocation.Route.EdgeShapes    = new GeoCoordinateSimple[1][];
            referencedPointAlongLineLocation.Route.EdgeShapes[0] = new GeoCoordinateSimple[0];
            referencedPointAlongLineLocation.Route.Vertices      = new long[2];
            referencedPointAlongLineLocation.Route.Vertices[0]   = vertex1;
            referencedPointAlongLineLocation.Route.Vertices[1]   = vertex2;
            referencedPointAlongLineLocation.Latitude            = (49.60597f + 49.60521f) / 2f;
            referencedPointAlongLineLocation.Longitude           = (6.12829f + 6.12779f) / 2f;

            // encode location.
            var encoder           = new PointAlongLineEncoder();
            var router            = new Dykstra();
            var mainEncoder       = new ReferencedOsmEncoder(graph, null);
            var referencedEncoder = new ReferencedPointAlongLineEncoder(mainEncoder, encoder);
            var location          = referencedEncoder.EncodeReferenced(referencedPointAlongLineLocation);

            // test result.
            Assert.IsNotNull(location);
            Assert.AreEqual(SideOfRoad.OnOrAbove, location.SideOfRoad);
            Assert.AreEqual(Orientation.NoOrientation, location.Orientation);
            Assert.AreEqual(50, location.PositiveOffsetPercentage.Value, 0.5f);

            Assert.AreEqual(49.60597f, location.First.Coordinate.Latitude);
            Assert.AreEqual(6.12829f, location.First.Coordinate.Longitude);
            Assert.AreEqual(91, location.First.DistanceToNext);
            Assert.AreEqual(203, location.First.Bearing);
            Assert.AreEqual(FormOfWay.SingleCarriageWay, location.First.FormOfWay);
            Assert.AreEqual(FunctionalRoadClass.Frc3, location.First.FuntionalRoadClass);
            Assert.AreEqual(FunctionalRoadClass.Frc3, location.First.LowestFunctionalRoadClassToNext);

            Assert.AreEqual(49.60521f, location.Last.Coordinate.Latitude);
            Assert.AreEqual(6.12779f, location.Last.Coordinate.Longitude);
            Assert.AreEqual(23, location.Last.Bearing);

            // encode location with a point on the first point.
            referencedPointAlongLineLocation                = new ReferencedPointAlongLine();
            referencedPointAlongLineLocation.Route          = new ReferencedLine(graph);
            referencedPointAlongLineLocation.Route.Edges    = new LiveEdge[1];
            referencedPointAlongLineLocation.Route.Edges[0] = new LiveEdge()
            {
                Distance = 10,
                Forward  = true,
                Tags     = tags.Add(new TagsCollection(Tag.Create("highway", "tertiary")))
            };
            referencedPointAlongLineLocation.Route.EdgeShapes    = new GeoCoordinateSimple[1][];
            referencedPointAlongLineLocation.Route.EdgeShapes[0] = new GeoCoordinateSimple[0];
            referencedPointAlongLineLocation.Route.Vertices      = new long[2];
            referencedPointAlongLineLocation.Route.Vertices[0]   = vertex1;
            referencedPointAlongLineLocation.Route.Vertices[1]   = vertex2;
            referencedPointAlongLineLocation.Latitude            = 49.60597f;
            referencedPointAlongLineLocation.Longitude           = 6.12829f;

            // encode location.
            location = referencedEncoder.EncodeReferenced(referencedPointAlongLineLocation);

            // test result.
            Assert.IsNotNull(location);
            Assert.AreEqual(SideOfRoad.OnOrAbove, location.SideOfRoad);
            Assert.AreEqual(Orientation.NoOrientation, location.Orientation);
            Assert.AreEqual(0, location.PositiveOffsetPercentage);

            Assert.AreEqual(49.60597f, location.First.Coordinate.Latitude);
            Assert.AreEqual(6.12829f, location.First.Coordinate.Longitude);
            Assert.AreEqual(91, location.First.DistanceToNext);
            Assert.AreEqual(FormOfWay.SingleCarriageWay, location.First.FormOfWay);
            Assert.AreEqual(FunctionalRoadClass.Frc3, location.First.FuntionalRoadClass);
            Assert.AreEqual(FunctionalRoadClass.Frc3, location.First.LowestFunctionalRoadClassToNext);

            Assert.AreEqual(49.60521f, location.Last.Coordinate.Latitude);
            Assert.AreEqual(6.12779f, location.Last.Coordinate.Longitude);

            // encode location with a point on the last point.
            referencedPointAlongLineLocation                = new ReferencedPointAlongLine();
            referencedPointAlongLineLocation.Route          = new ReferencedLine(graph);
            referencedPointAlongLineLocation.Route.Edges    = new LiveEdge[1];
            referencedPointAlongLineLocation.Route.Edges[0] = new LiveEdge()
            {
                Distance = 10,
                Forward  = true,
                Tags     = tags.Add(new TagsCollection(Tag.Create("highway", "tertiary")))
            };
            referencedPointAlongLineLocation.Route.EdgeShapes    = new GeoCoordinateSimple[1][];
            referencedPointAlongLineLocation.Route.EdgeShapes[0] = new GeoCoordinateSimple[0];
            referencedPointAlongLineLocation.Route.Vertices      = new long[2];
            referencedPointAlongLineLocation.Route.Vertices[0]   = vertex1;
            referencedPointAlongLineLocation.Route.Vertices[1]   = vertex2;
            referencedPointAlongLineLocation.Latitude            = 49.60521f;
            referencedPointAlongLineLocation.Longitude           = 6.12779f;

            // encode location.
            location = referencedEncoder.EncodeReferenced(referencedPointAlongLineLocation);

            // test result.
            Assert.IsNotNull(location);
            Assert.AreEqual(SideOfRoad.OnOrAbove, location.SideOfRoad);
            Assert.AreEqual(Orientation.NoOrientation, location.Orientation);
            Assert.AreEqual(99, location.PositiveOffsetPercentage.Value);

            Assert.AreEqual(49.60597f, location.First.Coordinate.Latitude);
            Assert.AreEqual(6.12829f, location.First.Coordinate.Longitude);
            Assert.AreEqual(91, location.First.DistanceToNext);
            Assert.AreEqual(FormOfWay.SingleCarriageWay, location.First.FormOfWay);
            Assert.AreEqual(FunctionalRoadClass.Frc3, location.First.FuntionalRoadClass);
            Assert.AreEqual(FunctionalRoadClass.Frc3, location.First.LowestFunctionalRoadClassToNext);

            Assert.AreEqual(49.60521f, location.Last.Coordinate.Latitude);
            Assert.AreEqual(6.12779f, location.Last.Coordinate.Longitude);
        }