├── .gitattributes ├── .gitignore ├── README.md ├── VectorTileToBitmapRenderer.sln ├── VectorTileToBitmapRenderer.sln.DotSettings ├── docs └── psychedelic-tiles.png ├── samples └── VectorTileSample │ ├── App.config │ ├── App.xaml │ ├── App.xaml.cs │ ├── FetchStrategy.cs │ ├── LayerList.xaml │ ├── LayerList.xaml.cs │ ├── LayerListItem.xaml │ ├── LayerListItem.xaml.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings │ ├── VectorTileLayer.cs │ ├── VectorTileSample.csproj │ └── packages.config └── src └── VectorTileToBitmapRenderer ├── GDI └── GeoJsonToGdiRenderer.cs ├── HttpVectorTileSource.cs ├── IGeoJSONRenderer.cs ├── OpenTK.dll.config ├── OpenTK ├── FrameBufferObjectHelper.cs ├── GeoJsonToOpenTKRenderer.cs └── GraphicsContextToBitmapConverter.cs ├── Properties └── AssemblyInfo.cs ├── SphericalMercator.cs ├── VectorTileToBitmapRenderer.csproj ├── VectorTileToBitmapRenderer.csproj.DotSettings ├── app.config └── packages.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | *.vspx 85 | 86 | # TFS 2012 Local Workspace 87 | $tf/ 88 | 89 | # Guidance Automation Toolkit 90 | *.gpState 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper*/ 94 | *.[Rr]e[Ss]harper 95 | *.DotSettings.user 96 | 97 | # JustCode is a .NET coding add-in 98 | .JustCode 99 | 100 | # TeamCity is a build add-in 101 | _TeamCity* 102 | 103 | # DotCover is a Code Coverage Tool 104 | *.dotCover 105 | 106 | # NCrunch 107 | _NCrunch_* 108 | .*crunch*.local.xml 109 | 110 | # MightyMoose 111 | *.mm.* 112 | AutoTest.Net/ 113 | 114 | # Web workbench (sass) 115 | .sass-cache/ 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | 133 | # Publish Web Output 134 | *.[Pp]ublish.xml 135 | *.azurePubxml 136 | ## TODO: Comment the next line if you want to checkin your 137 | ## web deploy settings but do note that will include unencrypted 138 | ## passwords 139 | #*.pubxml 140 | 141 | *.publishproj 142 | 143 | # NuGet Packages 144 | *.nupkg 145 | # The packages folder can be ignored because of Package Restore 146 | **/packages/* 147 | # except build/, which is used as an MSBuild target. 148 | !**/packages/build/ 149 | # Uncomment if necessary however generally it will be regenerated when needed 150 | #!**/packages/repositories.config 151 | 152 | # Windows Azure Build Output 153 | csx/ 154 | *.build.csdef 155 | 156 | # Windows Store app package directory 157 | AppPackages/ 158 | 159 | # Visual Studio cache files 160 | # files ending in .cache can be ignored 161 | *.[Cc]ache 162 | # but keep track of directories ending in .cache 163 | !*.[Cc]ache/ 164 | 165 | # Others 166 | ClientBin/ 167 | [Ss]tyle[Cc]op.* 168 | ~$* 169 | *~ 170 | *.dbmdl 171 | *.dbproj.schemaview 172 | *.pfx 173 | *.publishsettings 174 | node_modules/ 175 | orleans.codegen.cs 176 | 177 | # RIA/Silverlight projects 178 | Generated_Code/ 179 | 180 | # Backup & report files from converting an old project file 181 | # to a newer Visual Studio version. Backup files are not needed, 182 | # because we have git ;-) 183 | _UpgradeReport_Files/ 184 | Backup*/ 185 | UpgradeLog*.XML 186 | UpgradeLog*.htm 187 | 188 | # SQL Server files 189 | *.mdf 190 | *.ldf 191 | 192 | # Business Intelligence projects 193 | *.rdl.data 194 | *.bim.layout 195 | *.bim_*.settings 196 | 197 | # Microsoft Fakes 198 | FakesAssemblies/ 199 | 200 | # Node.js Tools for Visual Studio 201 | .ntvs_analysis.dat 202 | 203 | # Visual Studio 6 build log 204 | *.plg 205 | 206 | # Visual Studio 6 workspace options file 207 | *.opt 208 | 209 | # LightSwitch generated files 210 | GeneratedArtifacts/ 211 | _Pvt_Extensions/ 212 | ModelManifest.xml 213 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VectorTileToBitmapRenderer 2 | Renders vector tiles to PNGs. This makes it easy to render a vector tile in a client that is capable of bitmap rendering. It is not possible to draw the vectors directly on your clients canvas which will reduce quality in some cases. It is however still possible to choose the styling used to render to bitmap. 3 | 4 | It uses [mapbox-vector-tile-cs](https://github.com/bertt/mapbox-vector-tile-cs) to parse vector tiles. This turns is into [GeoJSON.NET](https://github.com/GeoJSON-Net/GeoJSON.Net) objects. 5 | 6 | ## Roadmap 7 | * Do nothing unless a real need arises 8 | * Wait a little more 9 | * Use SkiaSharp rendering, remove GDI and OpenTK 10 | * Add configurable styling 11 | * Use vector tile style 12 | 13 | ## Sample 14 | The repo contains a sample of the awesome psychedelic tile renderer which has value all of its own :) 15 | 16 | ![Alt text](/docs/psychedelic-tiles.png?raw=true "Optional Title") 17 | -------------------------------------------------------------------------------- /VectorTileToBitmapRenderer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VectorTileToBitmapRenderer", "src\VectorTileToBitmapRenderer\VectorTileToBitmapRenderer.csproj", "{CD32D7AD-2B89-4E3A-B204-B9D2B179F3F5}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EE5731D0-11F9-4A36-867F-6AD1260048FF}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{80B98CD5-CFD0-4BA7-A11F-96A9CAED5DAE}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VectorTileSample", "samples\VectorTileSample\VectorTileSample.csproj", "{57D747AA-79C3-4F05-A165-33CCA6158C16}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {CD32D7AD-2B89-4E3A-B204-B9D2B179F3F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {CD32D7AD-2B89-4E3A-B204-B9D2B179F3F5}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {CD32D7AD-2B89-4E3A-B204-B9D2B179F3F5}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {CD32D7AD-2B89-4E3A-B204-B9D2B179F3F5}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {57D747AA-79C3-4F05-A165-33CCA6158C16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {57D747AA-79C3-4F05-A165-33CCA6158C16}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {57D747AA-79C3-4F05-A165-33CCA6158C16}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {57D747AA-79C3-4F05-A165-33CCA6158C16}.Release|Any CPU.Build.0 = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | GlobalSection(NestedProjects) = preSolution 33 | {CD32D7AD-2B89-4E3A-B204-B9D2B179F3F5} = {EE5731D0-11F9-4A36-867F-6AD1260048FF} 34 | {57D747AA-79C3-4F05-A165-33CCA6158C16} = {80B98CD5-CFD0-4BA7-A11F-96A9CAED5DAE} 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /VectorTileToBitmapRenderer.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | JSON -------------------------------------------------------------------------------- /docs/psychedelic-tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OsmSharp/VectorTileToBitmapRenderer/836badf784c49f917334c5a587d41d9637ab2495/docs/psychedelic-tiles.png -------------------------------------------------------------------------------- /samples/VectorTileSample/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/VectorTileSample/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /samples/VectorTileSample/App.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace VectorTileSample 2 | { 3 | /// 4 | /// Interaction logic for App.xaml 5 | /// 6 | public partial class App 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/VectorTileSample/FetchStrategy.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2009 - Paul den Dulk (Geodan) 2 | // 3 | // This file is part of SharpMap. 4 | // Mapsui is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // SharpMap is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with SharpMap; if not, write to the Free Software 16 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | using System.Collections.Generic; 19 | using System.Linq; 20 | using BruTile; 21 | using Mapsui.Fetcher; 22 | using Mapsui.Geometries.Utilities; 23 | using Mapsui.Utilities; 24 | 25 | namespace VectorTileSample 26 | { 27 | public class FetchStrategy : IFetchStrategy 28 | { 29 | public IList GetTilesWanted(ITileSchema schema, Extent extent, string levelId) 30 | { 31 | var infos = new List(); 32 | // Iterating through all levels from current to zero. If lower levels are 33 | // not available the renderer can fall back on higher level tiles. 34 | var resolution = schema.Resolutions[levelId].UnitsPerPixel; 35 | var levels = schema.Resolutions.Where(k => k.Value.UnitsPerPixel >= resolution).OrderBy(x => x.Value.UnitsPerPixel).ToList(); 36 | 37 | foreach (var level in levels) 38 | { 39 | var tileInfos = schema.GetTileInfos(extent, level.Key).OrderBy( 40 | t => Algorithms.Distance(extent.CenterX, extent.CenterY, t.Extent.CenterX, t.Extent.CenterY)); 41 | 42 | foreach (TileInfo info in tileInfos.Where(info => (info.Index.Row >= 0) && (info.Index.Col >= 0))) 43 | { 44 | infos.Add(info); 45 | } 46 | } 47 | 48 | return infos; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /samples/VectorTileSample/LayerList.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /samples/VectorTileSample/LayerList.xaml.cs: -------------------------------------------------------------------------------- 1 | using Mapsui; 2 | using Mapsui.Layers; 3 | 4 | namespace VectorTileSample 5 | { 6 | /// 7 | /// Interaction logic for LayerList.xaml 8 | /// 9 | public partial class LayerList 10 | { 11 | public LayerList() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | public void Initialize(LayerCollection layers) 17 | { 18 | Items.Children.Clear(); 19 | 20 | foreach (var layer in layers) 21 | { 22 | var item = new LayerListItem {LayerName = layer.Name}; 23 | item.Enabled = layer.Enabled; 24 | item.LayerOpacity = layer.Opacity; 25 | item.Layer = layer; 26 | Items.Children.Add(item); 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /samples/VectorTileSample/LayerListItem.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | Text 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /samples/VectorTileSample/LayerListItem.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using Mapsui.Layers; 4 | 5 | namespace VectorTileSample 6 | { 7 | public partial class LayerListItem 8 | { 9 | public ILayer Layer { private get; set; } 10 | 11 | public string LayerName 12 | { 13 | set { TextBlock.Text = value; } 14 | } 15 | 16 | public double LayerOpacity 17 | { 18 | set { OpacitySlider.Value = value; } 19 | } 20 | 21 | public bool? Enabled 22 | { 23 | set { EnabledCheckBox.IsChecked = value; } 24 | } 25 | 26 | public LayerListItem() 27 | { 28 | InitializeComponent(); 29 | OpacitySlider.IsMoveToPointEnabled = true; // mouse click moves slider to that specific position (otherwise only 0 or 1 is selected) 30 | } 31 | 32 | private void OpacitySliderValueChanged(object sender, RoutedPropertyChangedEventArgs e) 33 | { 34 | var tempLayer = Layer; 35 | if (tempLayer != null) 36 | { 37 | tempLayer.Opacity = e.NewValue; 38 | } 39 | } 40 | 41 | private void EnabledCheckBoxClick(object sender, RoutedEventArgs e) 42 | { 43 | var tempLayer = Layer; 44 | if (tempLayer != null) 45 | { 46 | tempLayer.Enabled = ((CheckBox)e.Source).IsChecked != false; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /samples/VectorTileSample/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /samples/VectorTileSample/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using BruTile.Predefined; 3 | using Mapsui.Layers; 4 | using VectorTileToBitmapRenderer; 5 | 6 | namespace VectorTileSample 7 | { 8 | /// 9 | /// Interaction logic for MainWindow.xaml 10 | /// 11 | public partial class MainWindow 12 | { 13 | readonly HttpVectorTileSource _httpVectorTileSource; 14 | readonly ILayer _vectorTileLayer; 15 | public MainWindow() 16 | { 17 | InitializeComponent(); 18 | 19 | MapControl.Map.Layers.Add(new TileLayer(KnownTileSources.Create()) { Name = "OpenStreetMap"}); 20 | 21 | _httpVectorTileSource = CreateVectorTileTileSource(); 22 | // FUTURE_httpVectorTileSource = new HttpTileSource (new GlobalSphericalMercator(), "https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.mvt?api_key=mapzen-tnjqimH"); 23 | 24 | _vectorTileLayer = new TileLayer(_httpVectorTileSource) { Opacity = 0.5, Name = "Mapzen vector tiles"}; 25 | // FUTURE: _vectorTileLayer = new VectorTileLayer(_httpVectorTileSource); 26 | 27 | MapControl.Map.Layers.Add(_vectorTileLayer); 28 | 29 | MapsuiLayerList.Initialize(MapControl.Map.Layers); 30 | } 31 | 32 | public HttpVectorTileSource CreateVectorTileTileSource() 33 | { 34 | return new HttpVectorTileSource( 35 | new GlobalSphericalMercator(), 36 | "http://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.mvt?api_key=mapzen-tnjqimH", 37 | name: "vector tile"); 38 | } 39 | 40 | private void GDI_OnClick(object sender, RoutedEventArgs e) 41 | { 42 | _httpVectorTileSource.UseGdi = true; 43 | _vectorTileLayer.ClearCache(); 44 | MapControl.Refresh(); 45 | } 46 | 47 | private void OpenTK_OnClick(object sender, RoutedEventArgs e) 48 | { 49 | _httpVectorTileSource.UseGdi = false; 50 | _vectorTileLayer.ClearCache(); 51 | MapControl.Refresh(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /samples/VectorTileSample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using System.Windows; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("VectorTileSample")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("VectorTileSample")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | //In order to begin building localizable applications, set 23 | //CultureYouAreCodingWith in your .csproj file 24 | //inside a . For example, if you are using US english 25 | //in your source files, set the to en-US. Then uncomment 26 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 27 | //the line below to match the UICulture setting in the project file. 28 | 29 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 30 | 31 | 32 | [assembly: ThemeInfo( 33 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 34 | //(used if a resource is not found in the page, 35 | // or application resource dictionaries) 36 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 37 | //(used if a resource is not found in the page, 38 | // app, or any theme specific resource dictionaries) 39 | )] 40 | 41 | 42 | // Version information for an assembly consists of the following four values: 43 | // 44 | // Major Version 45 | // Minor Version 46 | // Build Number 47 | // Revision 48 | // 49 | // You can specify all the values or you can default the Build and Revision Numbers 50 | // by using the '*' as shown below: 51 | // [assembly: AssemblyVersion("1.0.*")] 52 | [assembly: AssemblyVersion("1.0.0.0")] 53 | [assembly: AssemblyFileVersion("1.0.0.0")] 54 | -------------------------------------------------------------------------------- /samples/VectorTileSample/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace VectorTileSample.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VectorTileSample.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /samples/VectorTileSample/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /samples/VectorTileSample/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace VectorTileSample.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /samples/VectorTileSample/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /samples/VectorTileSample/VectorTileLayer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using BruTile; 6 | using BruTile.Cache; 7 | using Mapsui.Fetcher; 8 | using Mapsui.Geometries; 9 | using Mapsui.Layers; 10 | using Mapsui.Providers; 11 | using Mapsui.Rendering; 12 | 13 | namespace VectorTileSample 14 | { 15 | public class VectorTileLayer : BaseLayer 16 | { 17 | private readonly ITileSource _tileSource; 18 | private readonly MemoryCache _tileCache = new MemoryCache(); 19 | private readonly IRenderGetStrategy _renderStrategy; 20 | private readonly IFetchStrategy _fetchStrategy = new FetchStrategy(); 21 | private readonly TileFetcher _tileFetcher; 22 | private List _vectorCache = new List(); 23 | 24 | public VectorTileLayer(ITileSource tileSource, RenderGetStrategy renderStrategy = null) 25 | { 26 | _tileSource = tileSource; 27 | _tileFetcher = new TileFetcher(_tileSource, _tileCache, 1, 4, _fetchStrategy); 28 | _tileFetcher.DataChanged += TileFetcherOnDataChanged; 29 | _tileFetcher.PropertyChanged += TileFetcherOnPropertyChanged; 30 | _renderStrategy = renderStrategy ?? new RenderGetStrategy(); 31 | } 32 | 33 | private void TileFetcherOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) 34 | { 35 | if (propertyChangedEventArgs.PropertyName != nameof(Busy)) return; 36 | if (_tileFetcher != null) Busy = _tileFetcher.Busy; 37 | } 38 | 39 | private void TileFetcherOnDataChanged(object sender, DataChangedEventArgs dataChangedEventArgs) 40 | { 41 | 42 | } 43 | 44 | public override IEnumerable GetFeaturesInView(BoundingBox box, double resolution) 45 | { 46 | if (_tileSource?.Schema == null) return Enumerable.Empty(); 47 | 48 | return _renderStrategy.GetFeatures(box, resolution, _tileSource?.Schema, _tileCache); 49 | } 50 | 51 | public override BoundingBox Envelope => _tileSource?.Schema?.Extent.ToBoundingBox(); 52 | 53 | public override void AbortFetch() 54 | { 55 | // method should be removed 56 | } 57 | 58 | public override void ViewChanged(bool majorChange, BoundingBox extent, double resolution) 59 | { 60 | if (Enabled && extent.GetArea() > 0 && _tileFetcher != null && MaxVisible > resolution && MinVisible < resolution) 61 | { 62 | _tileFetcher.ViewChanged(extent, resolution); 63 | } 64 | } 65 | 66 | public override void ClearCache() 67 | { 68 | _tileCache.Clear(); 69 | _vectorCache.Clear(); 70 | } 71 | 72 | public override bool? IsCrsSupported(string crs) 73 | { 74 | return string.Equals(ToSimpleEpsgCode(), crs, StringComparison.CurrentCultureIgnoreCase); 75 | } 76 | 77 | string ToSimpleEpsgCode() 78 | { 79 | var startEpsgCode = _tileSource.Schema.Srs.IndexOf("EPSG:", StringComparison.Ordinal); 80 | if (startEpsgCode < 0) return _tileSource.Schema.Srs; 81 | return _tileSource.Schema.Srs.Substring(startEpsgCode).Replace("::", ":").Trim(); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /samples/VectorTileSample/VectorTileSample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {57D747AA-79C3-4F05-A165-33CCA6158C16} 8 | WinExe 9 | Properties 10 | VectorTileSample 11 | VectorTileSample 12 | v4.5.2 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | true 17 | 18 | 19 | 20 | 21 | AnyCPU 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | 39 | 40 | 41 | ..\..\packages\BruTile.0.22.1\lib\portable-net45+win+WindowsPhoneApp81+Xamarin.iOS10+MonoAndroid10+MonoTouch10\BruTile.dll 42 | 43 | 44 | ..\..\packages\ConcurrentHashSet.1.0.2\lib\netstandard1.0\ConcurrentCollections.dll 45 | 46 | 47 | ..\..\packages\Mapsui.1.1.1\lib\net45\Mapsui.dll 48 | 49 | 50 | ..\..\packages\Mapsui.1.1.1\lib\net45\Mapsui.Geometries.dll 51 | 52 | 53 | ..\..\packages\Mapsui.1.1.1\lib\net45\Mapsui.Rendering.Skia.dll 54 | 55 | 56 | ..\..\packages\Mapsui.1.1.1\lib\net45\Mapsui.Rendering.Xaml.dll 57 | 58 | 59 | ..\..\packages\Mapsui.1.1.1\lib\net45\Mapsui.UI.Wpf.dll 60 | 61 | 62 | ..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll 63 | 64 | 65 | ..\..\packages\SkiaSharp.1.59.1\lib\net45\SkiaSharp.dll 66 | 67 | 68 | ..\..\packages\SkiaSharp.Views.1.59.1.1\lib\net45\SkiaSharp.Views.Desktop.dll 69 | 70 | 71 | ..\..\packages\SkiaSharp.Views.1.59.1.1\lib\net45\SkiaSharp.Views.WPF.dll 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 4.0 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | MSBuild:Compile 91 | Designer 92 | 93 | 94 | 95 | 96 | MSBuild:Compile 97 | Designer 98 | 99 | 100 | MSBuild:Compile 101 | Designer 102 | 103 | 104 | MSBuild:Compile 105 | Designer 106 | 107 | 108 | App.xaml 109 | Code 110 | 111 | 112 | LayerList.xaml 113 | 114 | 115 | LayerListItem.xaml 116 | 117 | 118 | MainWindow.xaml 119 | Code 120 | 121 | 122 | 123 | 124 | Code 125 | 126 | 127 | True 128 | True 129 | Resources.resx 130 | 131 | 132 | True 133 | Settings.settings 134 | True 135 | 136 | 137 | ResXFileCodeGenerator 138 | Resources.Designer.cs 139 | 140 | 141 | 142 | SettingsSingleFileGenerator 143 | Settings.Designer.cs 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | {cd32d7ad-2b89-4e3a-b204-b9d2b179f3f5} 153 | VectorTileToBitmapRenderer 154 | 155 | 156 | 157 | 158 | 159 | 160 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 161 | 162 | 163 | 164 | 171 | -------------------------------------------------------------------------------- /samples/VectorTileSample/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/GDI/GeoJsonToGdiRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.IO; 6 | using GeoJSON.Net; 7 | using GeoJSON.Net.Feature; 8 | using GeoJSON.Net.Geometry; 9 | 10 | namespace VectorTileToBitmapRenderer 11 | { 12 | public class GeoJsonToGdiRenderer : IGeoJsonRenderer 13 | { 14 | private readonly int _canvasWidth; 15 | private readonly int _canvasHeight; 16 | private readonly float _extentMinX; 17 | private readonly float _extentMinY; 18 | private readonly float _extentWidth; 19 | private readonly float _extentHeight; 20 | 21 | public GeoJsonToGdiRenderer(int canvasWidth, int canvasHeight, double[] boundingBox) 22 | { 23 | _canvasWidth = canvasWidth; 24 | _canvasHeight = canvasHeight; 25 | _extentMinX = (float)boundingBox[0]; 26 | _extentMinY = (float) boundingBox[1]; 27 | _extentWidth = (float)boundingBox[2] -_extentMinX; 28 | _extentHeight = (float)boundingBox[3] - _extentMinY; 29 | } 30 | 31 | public byte[] Render(IEnumerable featureCollections) 32 | { 33 | var random = new Random(); 34 | 35 | using (var bitmap = new Bitmap(_canvasWidth, _canvasHeight)) 36 | using (var canvas = Graphics.FromImage(bitmap)) 37 | { 38 | foreach (var featureCollection in featureCollections) 39 | { 40 | foreach (var feature in featureCollection.Features) 41 | { 42 | if (feature.Geometry.Type == GeoJSONObjectType.Polygon) 43 | { 44 | var polygon = (Polygon) feature.Geometry; 45 | 46 | foreach (var lineString in polygon.Coordinates) 47 | { 48 | canvas.Transform = CreateTransformMatrix(_canvasWidth, _canvasHeight, _extentMinX, _extentMinY, _extentWidth, _extentHeight); 49 | using (var brush = new SolidBrush( 50 | Color.FromArgb(random.Next(256), random.Next(256), random.Next(256)))) 51 | { 52 | canvas.FillPolygon(brush, ToGdi(lineString)); 53 | 54 | } 55 | } 56 | } 57 | } 58 | } 59 | return ToBytes(bitmap); 60 | } 61 | } 62 | 63 | private static Matrix CreateTransformMatrix(int canvasWidth, int canvasHeight, float minX, float minY, float width, float height) 64 | { 65 | // The code below needs no comments, it is fully intuitive. 66 | // I wrote in in one go and it ran correctly right away. 67 | var matrix = new Matrix(); 68 | var flipMatrix = new Matrix(1, 0, 0, -1, 0, 0); 69 | matrix.Multiply(flipMatrix); 70 | matrix.Scale(canvasWidth/width, canvasHeight/height); 71 | var maxY = minY + height; 72 | matrix.Translate(-minX, -maxY); 73 | return matrix; 74 | } 75 | 76 | private static PointF[] ToGdi(LineString lineString) 77 | { 78 | var result = new List(); 79 | 80 | foreach (var coordinate in lineString.Coordinates) 81 | { 82 | var position = (GeographicPosition)coordinate; 83 | result.Add(SphericalMercator.FromLonLat(position.Longitude, position.Latitude)); 84 | } 85 | return result.ToArray(); 86 | } 87 | 88 | private static byte[] ToBytes(Image img) 89 | { 90 | using (var stream = new MemoryStream()) 91 | { 92 | img.Save(stream, System.Drawing.Imaging.ImageFormat.Png); 93 | return stream.ToArray(); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/HttpVectorTileSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Http; 7 | using BruTile; 8 | using BruTile.Cache; 9 | using BruTile.Web; 10 | using Mapbox.Vector.Tile; 11 | 12 | namespace VectorTileToBitmapRenderer 13 | { 14 | public class HttpVectorTileSource : HttpTileSource 15 | { 16 | public HttpVectorTileSource(ITileSchema tileSchema, string urlFormatter, IEnumerable serverNodes = null, string apiKey = null, string name = null, IPersistentCache persistentCache = null) 17 | : base(tileSchema, urlFormatter, serverNodes, apiKey, name, persistentCache, FetchTile) 18 | { 19 | } 20 | 21 | private static byte[] FetchTile(Uri url) 22 | { 23 | var gzipWebClient = new HttpClient(new HttpClientHandler() 24 | { 25 | AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate 26 | }); 27 | return gzipWebClient.GetByteArrayAsync(url).Result; 28 | } 29 | 30 | public override byte[] GetTile(TileInfo tileInfo) 31 | { 32 | var bytes = base.GetTile(tileInfo); 33 | var index = tileInfo.Index; 34 | var layerInfos = VectorTileParser.Parse(new MemoryStream(bytes)); 35 | var tileWidth = Schema.GetTileWidth(tileInfo.Index.Level); 36 | var tileHeight = Schema.GetTileHeight(tileInfo.Index.Level); 37 | var geoJSONRenderer = GetGeoJsonRenderer(tileInfo, tileWidth, tileHeight); 38 | return geoJSONRenderer.Render(layerInfos.Select(i => i.ToGeoJSON(index.Col, index.Row, int.Parse(index.Level)))); 39 | } 40 | 41 | private IGeoJsonRenderer GetGeoJsonRenderer(TileInfo tileInfo, int tileWidth, int tileHeight) 42 | { 43 | if (UseGdi) 44 | return new GeoJsonToGdiRenderer(tileWidth, tileHeight, ToGeoJSONArray(tileInfo.Extent)); 45 | return new GeoJsonToOpenTKRenderer(tileWidth, tileHeight, ToGeoJSONArray(tileInfo.Extent)); 46 | } 47 | 48 | public bool UseGdi { private get; set; } = true; 49 | 50 | private static double[] ToGeoJSONArray(Extent extent) 51 | { 52 | // GeoJSON.NET has no class for bounding boxes. It just holds them in a double array. 53 | // The spec says it should first the lowest and then all the highest values for all axes: 54 | // http://geojson.org/geojson-spec.html#bounding-boxes 55 | return new [] {extent.MinX, extent.MinY, extent.MaxX, extent.MaxY }; 56 | 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/IGeoJSONRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using GeoJSON.Net.Feature; 3 | 4 | namespace VectorTileToBitmapRenderer 5 | { 6 | public interface IGeoJsonRenderer 7 | { 8 | byte[] Render(IEnumerable featureCollections); 9 | } 10 | } -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/OpenTK.dll.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/OpenTK/FrameBufferObjectHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using OpenTK.Graphics.ES20; 3 | #pragma warning disable 618 // Not obsolte for Android. It needs to cross compile 4 | 5 | namespace VectorTileToBitmapRenderer 6 | { 7 | internal static class FrameBufferObjectHelper 8 | { 9 | public static void StopFrameBufferObject() 10 | { 11 | GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); // disable rendering into the FBO 12 | GL.Enable(EnableCap.Texture2D); // enable Texture Mapping 13 | GL.BindTexture(TextureTarget.Texture2D, 0); // bind default texture 14 | } 15 | 16 | public static void StartFrameBufferObject(int width, int height) 17 | { 18 | uint colorTexture; 19 | uint depthTexture; 20 | uint fboHandle; 21 | 22 | // Create Color Tex 23 | GL.GenTextures(1, out colorTexture); 24 | GL.BindTexture(TextureTarget.Texture2D, colorTexture); 25 | GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, 26 | PixelType.UnsignedByte, IntPtr.Zero); 27 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, 28 | (int) TextureMinFilter.Linear); 29 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, 30 | (int) TextureMagFilter.Linear); 31 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, 32 | (int) TextureWrapMode.ClampToEdge); 33 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, 34 | (int) TextureWrapMode.ClampToEdge); 35 | // GL.Ext.GenerateMipmap( GenerateMipmapTarget.Texture2D ); 36 | 37 | // Create Depth Tex 38 | GL.GenTextures(1, out depthTexture); 39 | GL.BindTexture(TextureTarget.Texture2D, depthTexture); 40 | GL.TexImage2D(TextureTarget.Texture2D, 0, (PixelInternalFormat) All.DepthComponent32Oes, width, height, 0, 41 | PixelFormat.DepthComponent, PixelType.UnsignedByte, IntPtr.Zero); 42 | // things go horribly wrong if DepthComponent's Bitcount does not match the main Framebuffer's Depth 43 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, 44 | (int) TextureMinFilter.Linear); 45 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, 46 | (int) TextureMagFilter.Linear); 47 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, 48 | (int) TextureWrapMode.ClampToEdge); 49 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, 50 | (int) TextureWrapMode.ClampToEdge); 51 | 52 | // Create a FBO and attach the textures 53 | GL.GenFramebuffers(1, out fboHandle); 54 | GL.BindFramebuffer(All.Framebuffer, fboHandle); 55 | GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, 56 | TextureTarget.Texture2D, 57 | (int) colorTexture, 0); 58 | GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferSlot.DepthAttachment, 59 | TextureTarget.Texture2D, 60 | (int) depthTexture, 0); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/OpenTK/GeoJsonToOpenTKRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using GeoJSON.Net; 4 | using GeoJSON.Net.Feature; 5 | using GeoJSON.Net.Geometry; 6 | using OpenTK; 7 | using OpenTK.Graphics; 8 | using All = OpenTK.Graphics.ES11.All; 9 | using ClearBufferMask = OpenTK.Graphics.ES20.ClearBufferMask; 10 | using GL = OpenTK.Graphics.ES11.GL; 11 | using MatrixMode = OpenTK.Graphics.ES11.MatrixMode; 12 | using StringName = OpenTK.Graphics.ES11.StringName; 13 | #pragma warning disable 618 // Not obsolte for Android. It needs to cross compile 14 | 15 | namespace VectorTileToBitmapRenderer 16 | { 17 | public class GeoJsonToOpenTKRenderer : IGeoJsonRenderer 18 | { 19 | private readonly int _pixelWidth; 20 | private readonly int _pixelHeight; 21 | private readonly float _extentMinX; 22 | private readonly float _extentMinY; 23 | private readonly float _extentWidth; 24 | private readonly float _extentHeight; 25 | private readonly object _syncRoot = new object(); 26 | 27 | public GeoJsonToOpenTKRenderer(int pixelWidth, int pixelHeight, double[] boundingBox) 28 | { 29 | _pixelWidth = pixelWidth; 30 | _pixelHeight = pixelHeight; 31 | _extentMinX = (float)boundingBox[0]; 32 | _extentMinY = (float)boundingBox[1]; 33 | _extentWidth = (float)boundingBox[2] - _extentMinX; 34 | _extentHeight = (float)boundingBox[3] - _extentMinY; 35 | } 36 | 37 | public byte[] Render(IEnumerable featureCollections) 38 | { 39 | lock (_syncRoot) 40 | { 41 | // There needs to be a gamewindow even though we don't write to screen. It is created but not used explicitly in our code. 42 | // ReSharper disable once UnusedVariable 43 | using (var gameWindow = new GameWindow(_pixelWidth, _pixelHeight)) 44 | { 45 | if (!GL.GetString(StringName.Extensions).Contains("GL_EXT_framebuffer_object")) 46 | { 47 | throw new NotSupportedException( 48 | "GL_EXT_framebuffer_object extension is required. Please update your drivers."); 49 | } 50 | 51 | FrameBufferObjectHelper.StartFrameBufferObject(_pixelWidth, _pixelHeight); 52 | 53 | OpenTK.Graphics.ES20.GL.ClearColor(Color4.White); 54 | OpenTK.Graphics.ES20.GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); 55 | 56 | Set2DViewport(_pixelWidth, _pixelHeight); 57 | 58 | GL.PushMatrix(); 59 | 60 | GL.Scale(_pixelWidth / _extentWidth, _pixelHeight / _extentHeight, 1); 61 | GL.Translate(-_extentMinX, -_extentMinY, 0); 62 | 63 | PolygonRenderer(featureCollections); 64 | var byteArray = GraphicsContextToBitmapConverter.ToBitmap(_pixelWidth, _pixelHeight); 65 | 66 | GL.PopMatrix(); 67 | 68 | FrameBufferObjectHelper.StopFrameBufferObject(); 69 | 70 | return byteArray; 71 | } 72 | } 73 | } 74 | 75 | private static void Set2DViewport(int pixelWidth, int pixelHeight) 76 | { 77 | GL.Viewport(0, 0, pixelWidth, pixelHeight); 78 | 79 | GL.MatrixMode(MatrixMode.Projection); 80 | GL.LoadIdentity(); 81 | 82 | OpenTK.Graphics.OpenGL.GL.Ortho(0, pixelWidth, pixelHeight, 0, -1, 1); // This has no effect: OpenTK.Graphics.ES11.GL.Ortho(0, width, height, 0, 0, 1); 83 | } 84 | 85 | private void PolygonRenderer(IEnumerable featureCollections) 86 | { 87 | foreach (var featureCollection in featureCollections) 88 | { 89 | foreach (var feature in featureCollection.Features) 90 | { 91 | if (feature.Geometry.Type == GeoJSONObjectType.Polygon) 92 | { 93 | var polygon = (Polygon)feature.Geometry; 94 | 95 | foreach (var lineString in polygon.Coordinates) 96 | { 97 | RenderPolygon(lineString); 98 | } 99 | } 100 | } 101 | } 102 | } 103 | 104 | private void RenderPolygon(LineString lineString) 105 | { 106 | float lineWidth = 0; 107 | 108 | float[] points = ToOpenTK(lineString); 109 | 110 | GL.LineWidth(lineWidth); 111 | GL.Color4(0, 0, 0, 255); 112 | GL.EnableClientState(All.VertexArray); 113 | GL.VertexPointer(2, All.Float, 0, points); 114 | GL.DrawArrays(All.LineLoop, 0, points.Length / 2); 115 | GL.DisableClientState(All.VertexArray); 116 | } 117 | 118 | private static float[] ToOpenTK(LineString lineString) 119 | { 120 | const int dimensions = 2; // x and y are both in one array 121 | var points = new float[lineString.Coordinates.Count * dimensions]; 122 | 123 | var counter = 0; 124 | foreach (var coordinate in lineString.Coordinates) 125 | { 126 | var position = (GeographicPosition)coordinate; 127 | var point = SphericalMercator.FromLonLat(position.Longitude, position.Latitude); 128 | points[counter * 2 + 0] = point.X; 129 | points[counter * 2 + 1] = point.Y; 130 | counter++; 131 | } 132 | 133 | return points; 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/OpenTK/GraphicsContextToBitmapConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Drawing.Imaging; 3 | using System.IO; 4 | using OpenTK.Graphics; 5 | using OpenTK.Graphics.OpenGL; 6 | using PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat; 7 | 8 | namespace VectorTileToBitmapRenderer 9 | { 10 | static class GraphicsContextToBitmapConverter 11 | { 12 | public static byte[] ToBitmap(int width, int height) 13 | { 14 | var bitmap = GrabScreenshot(width, height); 15 | var byteArray = BitmapToByteArray(bitmap); 16 | return byteArray; 17 | } 18 | 19 | private static byte[] BitmapToByteArray(Bitmap bitmap) 20 | { 21 | var memoryStream = new MemoryStream(); 22 | bitmap.Save(memoryStream, ImageFormat.Png); 23 | memoryStream.Position = 0; 24 | return memoryStream.ToArray(); 25 | } 26 | 27 | private static Bitmap GrabScreenshot(int width, int height) 28 | { 29 | if (GraphicsContext.CurrentContext == null) 30 | throw new GraphicsContextMissingException(); 31 | 32 | var bitmap = new Bitmap(width, height); 33 | BitmapData data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 34 | GL.ReadPixels(0, 0, width, height, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0); 35 | 36 | bitmap.UnlockBits(data); 37 | //bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); 38 | return bitmap; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("VectorTileToBitmapRenderer")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("VectorTileToBitmapRenderer")] 12 | [assembly: AssemblyCopyright("Copyright © 2016")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("cd32d7ad-2b89-4e3a-b204-b9d2b179f3f5")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/SphericalMercator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace VectorTileToBitmapRenderer 5 | { 6 | public class SphericalMercator 7 | { 8 | private const double Radius = 6378137; 9 | private const double D2R = Math.PI / 180; 10 | private const double HalfPi = Math.PI / 2; 11 | 12 | public static PointF FromLonLat(double lon, double lat) 13 | { 14 | var lonRadians = (D2R * lon); 15 | var latRadians = (D2R * lat); 16 | 17 | var x = Radius * lonRadians; 18 | var y = Radius * Math.Log(Math.Tan(Math.PI * 0.25 + latRadians * 0.5)); 19 | 20 | return new PointF((float)x, (float)y); 21 | } 22 | 23 | public static PointF ToLonLat(double x, double y) 24 | { 25 | var ts = Math.Exp(-y / (Radius)); 26 | var latRadians = HalfPi - 2 * Math.Atan(ts); 27 | 28 | var lonRadians = x / (Radius); 29 | 30 | var lon = (lonRadians / D2R); 31 | var lat = (latRadians / D2R); 32 | 33 | return new PointF((float)lon, (float)lat); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/VectorTileToBitmapRenderer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {CD32D7AD-2B89-4E3A-B204-B9D2B179F3F5} 8 | Library 9 | Properties 10 | VectorTileToBitmapRenderer 11 | VectorTileToBitmapRenderer 12 | v4.5.2 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\..\packages\BruTile.0.22.1\lib\portable-net45+win+WindowsPhoneApp81+Xamarin.iOS10+MonoAndroid10+MonoTouch10\BruTile.dll 35 | 36 | 37 | ..\..\packages\GeoJSON.Net.0.1.47\lib\portable-net40+sl5+wp80+win8+wpa81\GeoJSON.Net.dll 38 | 39 | 40 | ..\..\packages\mapbox-vector-tile.3.1.4\lib\portable-net4+sl5+wp8+win8\Mapbox.Vector.Tile.dll 41 | 42 | 43 | ..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll 44 | 45 | 46 | ..\..\packages\OpenTK.3.0.0-pre\lib\net20\OpenTK.dll 47 | 48 | 49 | ..\..\packages\protobuf-net.2.3.2\lib\net40\protobuf-net.dll 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 85 | -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/VectorTileToBitmapRenderer.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/VectorTileToBitmapRenderer/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------