Example #1
0
 private void CanvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args)
 {
     if (currentTile == null)
     {
         args.DrawingSession.Clear(Windows.UI.Colors.CornflowerBlue);
     }
     else
     {
         if (GeometryDecoder.renderList != null)
         {
             System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
             stopwatch.Start();
             //var size = sender.Size;
             //args.DrawingSession.Transform = System.Numerics.Matrix3x2.CreateRotation(angle, new System.Numerics.Vector2((float)size.Width/2f, (float)size.Height/2f));
             args.DrawingSession.Transform = System.Numerics.Matrix3x2.CreateScale(tileScale, canvasScalePoint) * System.Numerics.Matrix3x2.CreateTranslation(canvasOffset);
             args.DrawingSession.DrawImage(GeometryDecoder.renderList);
             GeometryDecoder.ApplyTextLayer(args.DrawingSession);
             args.DrawingSession.DrawImage(GeometryDecoder.renderText);
             stopwatch.Stop();
             System.Diagnostics.Debug.WriteLine($"Render time: {stopwatch.ElapsedMilliseconds} ms");
         }
     }
 }
Example #2
0
        public override bool HandleGeometry(IGeometryHandler handler)
        {
            var decoder = new GeometryDecoder(feature, layer);

            // From https://github.com/mapbox/vector-tile-spec/tree/master/2.1
            //
            // The POINT geometry type encodes a point or multipoint geometry. The geometry command sequence for a point
            // geometry MUST consist of a single MoveTo command with a command count greater than 0.
            //
            // The LINESTRING geometry type encodes a linestring or multilinestring geometry. The geometry command sequence
            // for a linestring geometry MUST consist of one or more repetitions of the following sequence:
            //   1. A MoveTo command with a command count of 1
            //   2. A LineTo command with a command count greater than 0
            //
            // The POLYGON geometry type encodes a polygon or multipolygon geometry, each polygon consisting of exactly one
            // exterior ring that contains zero or more interior rings. The geometry command sequence for a polygon consists
            // of one or more repetitions of the following sequence:
            //   1. An ExteriorRing
            //   2. Zero or more InteriorRings
            // Each ExteriorRing and InteriorRing MUST consist of the following sequence:
            //   1. A MoveTo command with a command count of 1
            //   2. A LineTo command with a command count greater than 1
            //   3. A ClosePath command

            switch (feature.Type)
            {
            case PbfGeomType.Point:
                while (decoder.HasData())
                {
                    decoder.AdvanceCommand();
                    Debug.Assert(decoder.Command == CommandType.MoveTo && decoder.Repeat > 0);
                    for (int i = decoder.Repeat; i > 0; i--)
                    {
                        handler.OnPoint(decoder.AdvanceCursor());
                    }
                }
                break;

            case PbfGeomType.LineString:
                while (decoder.HasData())
                {
                    handler.OnBeginLineString();
                    decoder.AdvanceCommand();
                    Debug.Assert(decoder.Command == CommandType.MoveTo && decoder.Repeat == 1);
                    handler.OnPoint(decoder.AdvanceCursor());
                    decoder.AdvanceCommand();
                    Debug.Assert(decoder.Command == CommandType.LineTo && decoder.Repeat > 0);
                    for (int i = decoder.Repeat; i > 0; i--)
                    {
                        handler.OnPoint(decoder.AdvanceCursor());
                    }
                    handler.OnEndLineString();
                }
                break;

            case PbfGeomType.Polygon:
                // Create temporary storage to hold rings until we determine whether they are interior or exterior.
                var ring             = new List <Point>();
                var isPolygonStarted = false;
                while (decoder.HasData())
                {
                    // Read out the coordinates of the next ring.
                    decoder.AdvanceCommand();
                    Debug.Assert(decoder.Command == CommandType.MoveTo && decoder.Repeat == 1);
                    ring.Add(decoder.AdvanceCursor());
                    decoder.AdvanceCommand();
                    for (int i = decoder.Repeat; i > 0; i--)
                    {
                        ring.Add(decoder.AdvanceCursor());
                    }
                    ring.Add(ring.First());
                    decoder.AdvanceCommand();
                    Debug.Assert(decoder.Command == CommandType.ClosePath && decoder.Repeat == 1);
                    // If ring is exterior, end the current polygon, start a new one, add ring to new polygon.
                    // If ring is interior, add the ring to current polygon.
                    var area = SignedArea(ring);
                    if (area > 0)
                    {
                        if (isPolygonStarted)
                        {
                            handler.OnEndPolygon();
                        }
                        handler.OnBeginPolygon();
                        isPolygonStarted = true;
                    }
                    handler.OnBeginLinearRing();
                    foreach (var point in ring)
                    {
                        handler.OnPoint(point);
                    }
                    handler.OnEndLinearRing();
                    ring.Clear();
                }
                handler.OnEndPolygon();
                break;

            case PbfGeomType.Unknown:
                return(false);
            }
            return(true);
        }
Example #3
0
        private async void Map_MapTapped(int tileX, int tileY, int zoomLevel)
        {
            float canvasScale = 1f;
            float canvasSize  = 768;
            float lineScale   = 1f;

            //int zoomLevel = Math.Min(14, Math.Max(1, (int)sender.ZoomLevel));
            //var tileAddr = MapUtil.WorldToTilePos(args.Location.Position.Longitude, args.Location.Position.Latitude, zoomLevel);
            System.Diagnostics.Debug.WriteLine($"{tileX} x {tileY}");
            System.Diagnostics.Debug.WriteLine($"zoom: {zoomLevel}");
            {
                var reader = await db.GetTile((int)tileX, (int)tileY, zoomLevel);

                if (!reader.HasRows)
                {
                    textOutput.Text = DateTime.Now + ": No data";
                }
                var tile = VectorTile.Parse(reader);
                if (tile.tile_data_raw != null)
                {
                    PBF pbf = new PBF(tile.tile_data_raw);
                    currentTile = ProtoBuf.Serializer.Deserialize <Tile>(new MemoryStream(tile.tile_data_raw));

                    if (GeometryDecoder.CanvasTileId != tile.id)
                    {
                        GeometryDecoder.CanvasTileId = tile.id;

                        if (GeometryDecoder.offscreen == null)
                        {
                            CanvasDevice device = CanvasDevice.GetSharedDevice();
                            GeometryDecoder.offscreen = new CanvasRenderTarget(device, canvasSize, canvasSize, Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi *canvasScale);
                            //GeometryDecoder.offscreenText = new CanvasRenderTarget(device, canvasSize, canvasSize, Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi * canvasScale);
                        }


                        //Performance benchmark
                        Tile.Layer layer_buildings           = null;
                        Tile.Layer layer_landcover           = null;
                        Tile.Layer layer_transportation      = null;
                        Tile.Layer layer_transportation_name = null;
                        Tile.Layer layer_housenumber         = null;
                        Tile.Layer layer_poi = null;

                        if (currentTile.Layers.Any(l => l.Name == "building"))
                        {
                            layer_buildings = currentTile.Layers.Where(l => l.Name == "building").ToList()?.First();
                        }
                        if (currentTile.Layers.Any(l => l.Name == "landcover"))
                        {
                            layer_landcover = currentTile.Layers.Where(l => l.Name == "landcover").ToList()?.First();
                        }
                        if (currentTile.Layers.Any(l => l.Name == "transportation"))
                        {
                            layer_transportation = currentTile.Layers.Where(l => l.Name == "transportation").ToList()?.First();
                        }
                        if (currentTile.Layers.Any(l => l.Name == "transportation_name"))
                        {
                            layer_transportation_name = currentTile.Layers.Where(l => l.Name == "transportation_name").ToList()?.First();
                        }
                        if (currentTile.Layers.Any(l => l.Name == "housenumber"))
                        {
                            layer_housenumber = currentTile.Layers.Where(l => l.Name == "housenumber").ToList()?.First();
                        }
                        if (currentTile.Layers.Any(l => l.Name == "poi"))
                        {
                            layer_poi = currentTile.Layers.Where(l => l.Name == "poi").ToList()?.First();
                        }

                        System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
                        stopwatch.Start();

                        Dictionary <string, Windows.UI.Color> landColors = new Dictionary <string, Windows.UI.Color>();
                        landColors.Add("grass", Windows.UI.Colors.LawnGreen);
                        landColors.Add("meadow", Windows.UI.Colors.Green);
                        landColors.Add("wood", Windows.UI.Colors.ForestGreen);
                        landColors.Add("forest", Windows.UI.Colors.DarkGreen);
                        landColors.Add("park", Windows.UI.Colors.LightGreen);
                        landColors.Add("village_green", Windows.UI.Colors.GreenYellow);
                        landColors.Add("wetland", Windows.UI.Colors.CornflowerBlue);
                        landColors.Add("recreation_ground", Windows.UI.Colors.LightYellow);
                        landColors.Add("allotments", Windows.UI.Colors.Red);

                        Dictionary <string, Tuple <Color, float, Color, float> > roadProperties = new Dictionary <string, Tuple <Color, float, Color, float> >();
                        roadProperties.Add("transit", new Tuple <Color, float, Color, float>(Colors.Black, 0.5f, Colors.Black, 0.5f));
                        roadProperties.Add("primary", new Tuple <Color, float, Color, float>(Colors.LightYellow, 3, Colors.SandyBrown, 4.5f));
                        roadProperties.Add("secondary", new Tuple <Color, float, Color, float>(Colors.LightYellow, 2, Colors.SandyBrown, 3f));
                        roadProperties.Add("tertiary", new Tuple <Color, float, Color, float>(Colors.LightYellow, 2, Colors.SandyBrown, 3f));
                        roadProperties.Add("minor", new Tuple <Color, float, Color, float>(Colors.WhiteSmoke, 1.8f, Colors.Gray, 2.5f));
                        roadProperties.Add("service", new Tuple <Color, float, Color, float>(Colors.WhiteSmoke, 1.8f, Colors.Gray, 2.5f));
                        roadProperties.Add("track", new Tuple <Color, float, Color, float>(Colors.LightGray, 1, Colors.Gray, 2));
                        roadProperties.Add("path", new Tuple <Color, float, Color, float>(Colors.LightGray, 1, Colors.Gray, 2));
                        roadProperties.Add("rail", new Tuple <Color, float, Color, float>(Colors.Gainsboro, 0.75f, Colors.DimGray, 1.4f));
                        roadProperties.Add("motorway", new Tuple <Color, float, Color, float>(Colors.Orange, 3, Colors.Red, 4.5f));
                        roadProperties.Add("trunk", new Tuple <Color, float, Color, float>(Colors.Orange, 3, Colors.Red, 4.5f));


                        GeometryDecoder.renderList = new CanvasCommandList(GeometryDecoder.offscreen);
                        GeometryDecoder.renderText = new CanvasCommandList(GeometryDecoder.offscreen);

                        //using (CanvasDrawingSession ds = GeometryDecoder.offscreen.CreateDrawingSession())
                        using (CanvasDrawingSession textDs = GeometryDecoder.renderText.CreateDrawingSession())
                            using (CanvasDrawingSession ds = GeometryDecoder.renderList.CreateDrawingSession())
                                using (CanvasActiveLayer activeLayer = ds.CreateLayer(1, new Rect(0, 0, canvasSize, canvasSize)))
                                    using (CanvasActiveLayer activeTextLayer = textDs.CreateLayer(1, new Rect(0, 0, canvasSize, canvasSize)))
                                    {
                                        ds.Antialiasing = CanvasAntialiasing.Antialiased;
                                        ds.Clear(Windows.UI.Colors.Snow);
                                        for (int it = 0; it < 1; it++)
                                        {
                                            layer_landcover?.Features.ForEach(f =>
                                            {
                                                var tags  = GeometryDecoder.GetTags(f, layer_landcover);
                                                var color = Colors.LightGreen;
                                                if (tags.ContainsKey("subclass"))
                                                {
                                                    color = landColors.ContainsKey(tags["subclass"].StringValue) ? landColors[tags["subclass"].StringValue] : Windows.UI.Colors.LightGreen;
                                                }
                                                GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, color, color);
                                            });

                                            layer_buildings?.Features.ForEach(f =>
                                            {
                                                var tags = GeometryDecoder.GetTags(f, layer_buildings);
                                                GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, Windows.UI.Colors.SandyBrown, Windows.UI.Colors.Brown);
                                            });


                                            List <string> tagsNames = new List <string>();
                                            var           names     = layer_transportation?.Features.ConvertAll <Tuple <string, string> >(f =>
                                            {
                                                var tags = GeometryDecoder.GetTags(f, layer_transportation);

                                                foreach (var t in tags)
                                                {
                                                    tagsNames.Add(t.Key);
                                                }
                                                return(new Tuple <string, string>(tags.ContainsKey("class") ? tags["class"].StringValue : "", tags.ContainsKey("subclass") ? tags["subclass"].StringValue : ""));
                                            }).ToList().Distinct().ToList();

                                            var distinctTagsNames = tagsNames.Distinct().ToList();

                                            Tuple <Color, float, Color, float> rc = new Tuple <Color, float, Color, float>(Colors.Pink, 2, Colors.DeepPink, 2);


                                            Dictionary <int, List <Tile.Feature> > transportationFeatures = new Dictionary <int, List <Tile.Feature> >();
                                            foreach (var f in layer_transportation.Features)
                                            {
                                                var tags  = GeometryDecoder.GetTags(f, layer_transportation);
                                                int layer = tags.ContainsKey("layer") ? (int)tags["layer"].IntValue : 0;
                                                if (!transportationFeatures.ContainsKey(layer))
                                                {
                                                    transportationFeatures.Add(layer, new List <Tile.Feature>());
                                                }
                                                transportationFeatures[layer].Add(f);
                                            }

                                            foreach (int layerNo in transportationFeatures.Keys.OrderBy(k => k))
                                            {
                                                //background / stroke pass
                                                foreach (var f in transportationFeatures[layerNo])
                                                {
                                                    var tags = GeometryDecoder.GetTags(f, layer_transportation);

                                                    if (tags.ContainsKey("class"))
                                                    {
                                                        if (roadProperties.ContainsKey(tags["class"].StringValue))
                                                        {
                                                            var p = roadProperties[tags["class"].StringValue];
                                                            GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, 0, p.Item4 * lineScale, layerNo > 0 ? GeometryDecoder.openStrokeStyle : GeometryDecoder.normalStrokeStyle);
                                                        }
                                                        else
                                                        {
                                                            GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, 0, rc.Item4 * lineScale, GeometryDecoder.normalStrokeStyle);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, 0, rc.Item4 * lineScale, GeometryDecoder.normalStrokeStyle);
                                                    }
                                                }

                                                //foreground / fill pass
                                                foreach (var f in transportationFeatures[layerNo])
                                                {
                                                    var tags = GeometryDecoder.GetTags(f, layer_transportation);
                                                    if (tags.ContainsKey("class"))
                                                    {
                                                        if (roadProperties.ContainsKey(tags["class"].StringValue))
                                                        {
                                                            var p = roadProperties[tags["class"].StringValue];
                                                            if (tags["class"].StringValue == "rail" || tags["class"].StringValue == "transit")
                                                            {
                                                                GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, p.Item2 * lineScale, 0, GeometryDecoder.railStrokeStyle);
                                                                //												System.Diagnostics.Debug.WriteLine(t)
                                                            }
                                                            else
                                                            {
                                                                GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, p.Item2 * lineScale, 0, GeometryDecoder.normalStrokeStyle);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            System.Diagnostics.Debug.WriteLine($"Unsupported class: {tags["class"]}");
                                                            GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, rc.Item2 * lineScale, 0, GeometryDecoder.normalStrokeStyle);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, rc.Item2 * lineScale, 0, GeometryDecoder.normalStrokeStyle);
                                                    }
                                                }
                                            }



                                            //								layer_transportation?.Features.ForEach(f =>
                                            //								{
                                            //									var tags = GeometryDecoder.GetTags(f, layer_transportation);

                                            //									if (tags.ContainsKey("class"))
                                            //									{
                                            //										if (roadProperties.ContainsKey(tags["class"].StringValue))
                                            //										{
                                            //											var p = roadProperties[tags["class"].StringValue];
                                            //											GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, 0, p.Item4 * lineScale);
                                            //										}
                                            //										else
                                            //										{
                                            //											GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, 0, rc.Item4 * lineScale);
                                            //										}
                                            //									}
                                            //									else
                                            //										GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, 0, rc.Item4 * lineScale);
                                            //								});

                                            //								layer_transportation?.Features.ForEach(f =>
                                            //								{
                                            //									var tags = GeometryDecoder.GetTags(f, layer_transportation);
                                            //									if (tags.ContainsKey("class"))
                                            //									{
                                            //										if (roadProperties.ContainsKey(tags["class"].StringValue))
                                            //										{
                                            //											var p = roadProperties[tags["class"].StringValue];
                                            //											if (tags["class"].StringValue == "rail")
                                            //											{
                                            //												GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, p.Item2 * lineScale, 0, GeometryDecoder.railStrokeStyle);
                                            ////												System.Diagnostics.Debug.WriteLine(t)
                                            //											}
                                            //											else
                                            //												GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, p.Item2 * lineScale, 0);
                                            //										}
                                            //										else
                                            //										{
                                            //											System.Diagnostics.Debug.WriteLine($"Unsupported class: {tags["class"]}");
                                            //											GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, rc.Item2 * lineScale, 0);
                                            //										}
                                            //									}
                                            //									else
                                            //										GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, rc.Item2 * lineScale, 0);
                                            //								});



                                            layer_housenumber?.Features.ForEach(f =>
                                            {
                                                var tags    = GeometryDecoder.GetTags(f, layer_housenumber);
                                                string text = tags["housenumber"].StringValue;
                                                //GeometryDecoder.DrawHousenumber(f, canvasSize / 4096f, textDs, Colors.Black, Colors.White, 1, 1.2f, text);
                                                GeometryDecoder.DrawText(f, canvasSize / 4096f, textDs, Colors.Black, Colors.White, 1, 1.2f, text, 2f);
                                            });

                                            layer_poi?.Features.ForEach(f => {
                                                var tags = GeometryDecoder.GetTags(f, layer_poi);
                                                if (tags.ContainsKey("subclass"))
                                                {
                                                    string subclass = tags["subclass"].StringValue;
                                                    if (icons.ContainsKey(subclass + "_11"))
                                                    {
                                                        GeometryDecoder.DrawIcon(f, canvasSize / 4096f, ds, icons[subclass + "_11"], Colors.Black, Colors.DarkGray);
                                                    }
                                                }
                                            });


                                            layer_transportation_name?.Features.ForEach(f =>
                                            {
                                                var tags = GeometryDecoder.GetTags(f, layer_transportation_name);
                                                if (tags.ContainsKey("name"))
                                                {
                                                    string text = tags["name"].StringValue;
                                                    GeometryDecoder.DrawText(f, canvasSize / 4096f, textDs, Colors.Black, Colors.White, 1, 1.2f, text, 3f);
                                                }
                                            });
                                        }
                                    }
                        //StorageFolder storageFolder = KnownFolders.PicturesLibrary;
                        //StorageFile file = await storageFolder.CreateFileAsync("map.bmp", CreationCollisionOption.ReplaceExisting);
                        //var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
                        //await GeometryDecoder.offscreen.SaveAsync(stream, CanvasBitmapFileFormat.Bmp);
                        //stream.Dispose();



                        stopwatch.Stop();


                        System.Diagnostics.Debug.WriteLine($"TIME: {stopwatch.ElapsedMilliseconds} ms");
                        textOutput.Text = $"TIME: {stopwatch.ElapsedMilliseconds} ms";
                    }
                }
                else
                {
                    currentTile = null;
                }
            }

            win2dCanvas.Invalidate();
        }
Example #4
0
        public override bool HandleGeometry(IGeometryHandler handler)
        {
            var decoder = new GeometryDecoder(feature, layer);

            // From https://github.com/mapbox/vector-tile-spec/tree/master/2.1
            //
            // The POINT geometry type encodes a point or multipoint geometry. The geometry command sequence for a point
            // geometry MUST consist of a single MoveTo command with a command count greater than 0.
            //
            // The LINESTRING geometry type encodes a linestring or multilinestring geometry. The geometry command sequence
            // for a linestring geometry MUST consist of one or more repetitions of the following sequence:
            //   1. A MoveTo command with a command count of 1
            //   2. A LineTo command with a command count greater than 0
            //
            // The POLYGON geometry type encodes a polygon or multipolygon geometry, each polygon consisting of exactly one
            // exterior ring that contains zero or more interior rings. The geometry command sequence for a polygon consists
            // of one or more repetitions of the following sequence:
            //   1. An ExteriorRing
            //   2. Zero or more InteriorRings
            // Each ExteriorRing and InteriorRing MUST consist of the following sequence:
            //   1. A MoveTo command with a command count of 1
            //   2. A LineTo command with a command count greater than 1
            //   3. A ClosePath command

            switch (feature.Type)
            {
            case PbfGeomType.Point:
                if (decoder.AdvanceCommand() && decoder.Command == CommandType.MoveTo)
                {
                    for (int i = 0; i < decoder.Repeat; i++)
                    {
                        decoder.AdvanceCursor();
                        handler.OnPoint(decoder.CurrentPoint());
                    }
                }
                break;

            case PbfGeomType.LineString:
                while (decoder.AdvanceCommand() && (decoder.Command == CommandType.MoveTo && decoder.Repeat == 1))
                {
                    decoder.AdvanceCursor();
                    if (decoder.AdvanceCommand() && (decoder.Command == CommandType.LineTo && decoder.Repeat > 0))
                    {
                        handler.OnBeginLineString();
                        handler.OnPoint(decoder.CurrentPoint());
                        for (int i = 0; i < decoder.Repeat; i++)
                        {
                            decoder.AdvanceCursor();
                            handler.OnPoint(decoder.CurrentPoint());
                        }
                        handler.OnEndLineString();
                    }
                }
                break;

            case PbfGeomType.Polygon:
                while (decoder.AdvanceCommand() && (decoder.Command == CommandType.MoveTo && decoder.Repeat == 1))
                {
                    handler.OnBeginPolygon();
                    decoder.AdvanceCursor();
                    if (decoder.AdvanceCommand() && (decoder.Command == CommandType.LineTo && decoder.Repeat > 0))
                    {
                        handler.OnBeginLinearRing();
                        var start = decoder.CurrentPoint();
                        handler.OnPoint(start);
                        for (int i = 0; i < decoder.Repeat; i++)
                        {
                            decoder.AdvanceCursor();
                            handler.OnPoint(decoder.CurrentPoint());
                        }
                        handler.OnPoint(start);
                        handler.OnEndLinearRing();
                    }
                    if (decoder.AdvanceCommand() && decoder.Command == CommandType.ClosePath)
                    {
                        // We should assert that this condition holds.
                    }
                    handler.OnEndPolygon();
                }
                break;

            case PbfGeomType.Unknown:
                break;
            }
            return(true);
        }