{"id":17309813,"url":"https://github.com/bobld/oxyplot-cartography","last_synced_at":"2025-03-27T00:24:13.722Z","repository":{"id":56743344,"uuid":"523859047","full_name":"BobLd/oxyplot-cartography","owner":"BobLd","description":" A cross-platform plotting library for .NET. This is an unofficial library for cartography and maps plotting.","archived":false,"fork":false,"pushed_at":"2023-05-12T07:44:47.000Z","size":9063,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-19T23:16:05.914Z","etag":null,"topics":["c-sharp","cartography","charts","dotnet","map","maps","oxyplot","plot-library","plotting","plotting-library"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BobLd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-08-11T20:25:46.000Z","updated_at":"2024-11-11T22:01:32.000Z","dependencies_parsed_at":"2022-08-16T01:10:44.287Z","dependency_job_id":null,"html_url":"https://github.com/BobLd/oxyplot-cartography","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BobLd%2Foxyplot-cartography","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BobLd%2Foxyplot-cartography/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BobLd%2Foxyplot-cartography/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BobLd%2Foxyplot-cartography/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BobLd","download_url":"https://codeload.github.com/BobLd/oxyplot-cartography/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245757055,"owners_count":20667276,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-sharp","cartography","charts","dotnet","map","maps","oxyplot","plot-library","plotting","plotting-library"],"created_at":"2024-10-15T12:32:50.140Z","updated_at":"2025-03-27T00:24:13.705Z","avatar_url":"https://github.com/BobLd.png","language":"C#","readme":"# OxyPlot.Cartography\nOxyPlot is a plotting library for .NET. This is an **unofficial** library for cartography and maps plotting.\n\n![example-openstreetmap](https://user-images.githubusercontent.com/38405645/184510801-c255316f-6dbb-4955-a064-c2b744c3cb28.png)\n\n# Usage\nSee the [SimpleDemo](https://github.com/BobLd/oxyplot-cartography/tree/master/SimpleDemo) for more details.\nThe below example is implemented using Avalonia, but it will be very similar for other platforms.\n```csharp\nvar model = new PlotModel\n{\n\tIsLegendVisible = true,\n\tPlotType = PlotType.Cartesian\n};\n\nmodel.Legends.Add(new Legend\n{\n\tLegendPlacement = LegendPlacement.Inside,\n\tLegendPosition = LegendPosition.RightTop,\n\tLegendBackground = OxyColor.FromAColor(200, OxyColors.White),\n\tLegendBorder = OxyColors.Black,\n});\n\nmodel.Axes.Add(new LongitudeAxis\n{\n\tPosition = AxisPosition.Bottom,\n\tMinimum = -0.24,\n\tMaximum = 0.04,\n\tTitle = \"Longitude\",\n});\n\nmodel.Axes.Add(new LatitudeWebMercatorAxis\n{\n\tPosition = AxisPosition.Left,\n\tMinimum = 51.42,\n\tMaximum = 51.62,\n\tTitle = \"Latitude\"\n});\n\nvar tileMapImageProvider = new HttpTileMapImageProvider(SynchronizationContext.Current)\n{\n\tUrl = \"https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{Z}/{Y}/{X}\",\n\tMaxNumberOfDownloads = 2,\n\tUserAgent = \"OxyPlot.Cartography\",\n\tImageConverter = new Func\u003cbyte[], byte[]\u003e(bytes =\u003e // Optional\n\t{\n\t\tif (bytes.Length \u003e= 2 \u0026\u0026 bytes[0] == 0x42 \u0026\u0026 bytes[1] == 0x4D)\n\t\t{\n\t\t\treturn bytes; // Bmp\n\t\t}\n\n\t\tif (bytes.Length \u003e= 4 \u0026\u0026 bytes[0] == 0x89 \u0026\u0026 bytes[1] == 0x50 \u0026\u0026 bytes[2] == 0x4E \u0026\u0026 bytes[3] == 0x47)\n\t\t{\n\t\t\treturn bytes; //Png\n\t\t}\n\n\t\tusing (var msInput = new MemoryStream(bytes))\n\t\tusing (var msOutput = new MemoryStream())\n\t\t{\n\t\t\tvar bitmap = Bitmap.DecodeToWidth(msInput, 256);\n\t\t\tbitmap.Save(msOutput);\n\t\t\treturn msOutput.ToArray();\n\t\t}\n\t\treturn bytes;\n\t})\n};\n\nvar loadingImg = new Uri(\"avares://SimpleDemo/Assets/live-view.png\");\nvar asset = AvaloniaLocator.Current.GetService\u003cIAssetLoader\u003e();\nusing (var streamImg = asset.Open(loadingImg))\n{\n\t// Add the tile map annotation\n\tmodel.Annotations.Add(new MapTileAnnotation(streamImg, tileMapImageProvider)\n\t{\n\t\tCopyrightNotice = \"OpenStreetMap\",\n\t\tMinZoomLevel = 0,\n\t\tMaxZoomLevel = 19, // max OpenStreetMap value\n\t\tIsTileGridVisible = true,\n\t\tTileGridThickness = 3\n\t});\n}\n```\n\n## Map Tiles\n### MapTileAnnotation\n![example-arcgisonline-sat](https://user-images.githubusercontent.com/38405645/184510820-e1616724-46e5-46a8-8169-fa408bb26d8d.png)\n\n\n#### Usage\n```csharp\nmodel.Annotations.Add(new MapTileAnnotation(streamImg, tileMapImageProvider)\n{\n\tCopyrightNotice = \"OpenStreetMap\",\n\tMinZoomLevel = 0,\n\tMaxZoomLevel = 19, // max OpenStreetMap value\n\tIsTileGridVisible = true,\n\tTileGridThickness = 3\n});\n```\n#### Setting a tile loading image\n![loading_images](https://user-images.githubusercontent.com/38405645/184518394-55c89ba6-2a36-4a0a-97f7-e1785dfb5b0f.png)\n\n##### Usage (Avalonia)\n```csharp\nvar loadingImg = new Uri(\"avares://SimpleDemo/Assets/live-view.png\");\nvar asset = AvaloniaLocator.Current.GetService\u003cIAssetLoader\u003e();\nusing (var streamImg = asset.Open(loadingImg))\n{\n\t// Add the tile map annotation\n\tmodel.Annotations.Add(new MapTileAnnotation(streamImg, tileMapImageProvider)\n\t{\n\t\tCopyrightNotice = \"OpenStreetMap\",\n\t\tMinZoomLevel = 0,\n\t\tMaxZoomLevel = 19, // max OpenStreetMap value\n\t\tIsTileGridVisible = true,\n\t\tTileGridThickness = 3\n\t});\n}\n```\n\n## Axis\n### LatitudeWebMercatorAxis\nMap tiles are rendered as true squares, axis is not linear. You can use it in combination with `LongitudeAxis`, which is basically a `LinearAxis`.\n\u003e **Spherical Pseudo-Mercator projection**\u003cbr\u003e\n\u003e Most of OSM, including the main tiling system, uses a Pseudo-Mercator projection where the Earth is modelized as if it was a perfect a sphere. Combined with the zoom level, the system is known as a Web Mercator on Wikipedia.\u003cbr\u003e\n\u003e This produces a fast approximation to the truer, but heavier elliptical projection, where the Earth would be projected on a more accurate ellipsoid (flattened on poles). As a consequence, direct mesurements of distances in this projection will be approximative, except on the Equator, and the aspect ratios on the rendered map for true squares measured on the surface on Earth will slightly change with latitude and angles not so precisely preserved by this spherical projection.\nhttps://wiki.openstreetmap.org/wiki/Mercator\n![example-openstreetmap-latitude-mercator-axis](https://user-images.githubusercontent.com/38405645/184510844-ef039e92-198f-471c-bfd1-b7c141aa2995.png)\n\n\n#### Usage\n```csharp\nmodel.Axes.Add(new LatitudeWebMercatorAxis\n{\n\tPosition = AxisPosition.Left,\n\tMinimum = 51.42,\n\tMaximum = 51.62,\n\tTitle = \"Latitude\"\n});\n```\n\n#### Label formating\n##### Default\ne.g. 48.86°N, 02.35°E\n\n##### Degrees Minutes Seconds (DMS) Coordinates System\ne.g. 38°53′23″N, 77°00′32″W\n```csharp\nmodel.Axes.Add(new LongitudeAxis\n{\n\tPosition = AxisPosition.Bottom,\n\tMinimum = -0.24,\n\tMaximum = 0.04,\n\tTitle = \"Longitude\",\n\tLabelFormatter = (decDegrees) =\u003e CartographyHelper.DecimalDegreesToDegreesMinutesSeconds(decDegrees, false, 3)\n});\n\nmodel.Axes.Add(new LatitudeWebMercatorAxis\n{\n\tPosition = AxisPosition.Left,\n\tMinimum = 51.42,\n\tMaximum = 51.62,\n\tTitle = \"Latitude\",\n\tLabelFormatter = (decDegrees) =\u003e CartographyHelper.DecimalDegreesToDegreesMinutesSeconds(decDegrees, true, 3)\n});\n```\n##### Decimal Degrees (DD) Coordinates System\ne.g. 38.8897°, -77.0089° or 38.8897,-77.0089\n\n### LinearAxis\nWhen using the basic Oxyplot `LinearAxis`, the map tiles are not rendered as true squares.\n![example-openstreetmap-linear-axis](https://user-images.githubusercontent.com/38405645/184510852-5003c17e-4b7d-4de7-a248-1855a3fcb014.png)\n\n## Data\n### LocalTileMapImageProvider\n#### Usage\n```csharp\nvar tileMapImageProvider = new LocalTileMapImageProvider(pathToFolder);\n```\n### HttpTileMapImageProvider\n#### Usage\n```csharp\nvar tileMapImageProvider = new HttpTileMapImageProvider(SynchronizationContext.Current)\n{\n\tUrl = \"https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{Z}/{Y}/{X}\",\n\tMaxNumberOfDownloads = 2,\n\tUserAgent = \"OxyPlot.Cartography\"\n};\n```\n\n### Unsuported image format by OxyPlot (mainly Jpeg)\n#### Usage (Avalonia)\n```csharp\nvar tileMapImageProvider = new HttpTileMapImageProvider(SynchronizationContext.Current)\n{\n\tUrl = \"https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{Z}/{Y}/{X}\",\n\tMaxNumberOfDownloads = 2,\n\tUserAgent = \"OxyPlot.Cartography\",\n\tImageConverter = new Func\u003cbyte[], byte[]\u003e(bytes =\u003e\n\t{\n\t\tif (bytes.Length \u003e= 2 \u0026\u0026 bytes[0] == 0x42 \u0026\u0026 bytes[1] == 0x4D)\n\t\t{\n\t\t\treturn bytes; // Bmp\n\t\t}\n\n\t\tif (bytes.Length \u003e= 4 \u0026\u0026 bytes[0] == 0x89 \u0026\u0026 bytes[1] == 0x50 \u0026\u0026 bytes[2] == 0x4E \u0026\u0026 bytes[3] == 0x47)\n\t\t{\n\t\t\treturn bytes; //Png\n\t\t}\n\n\t\tusing (var msInput = new MemoryStream(bytes))\n\t\tusing (var msOutput = new MemoryStream())\n\t\t{\n\t\t\tvar bitmap = Bitmap.DecodeToWidth(msInput, 256);\n\t\t\tbitmap.Save(msOutput);\n\t\t\treturn msOutput.ToArray();\n\t\t}\n\t\treturn bytes;\n\t})\n};\n```\n\n## Tile Images APIs\n- http://tile.openstreetmap.org/{Z}/{X}/{Y}.png\n- https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{Z}/{Y}/{X}\n   - https://developers.arcgis.com/documentation/mapping-apis-and-services/data-hosting/services/image-tile-service/\n- https://maptiles.finncdn.no/tileService/1.0.3/norortho/{Z}/{X}/{Y}.png\n- https://maptiles.finncdn.no/tileService/1.0.3/normap/{Z}/{X}/{Y}.png\n\n## References\n- https://stackoverflow.com/questions/39101368/oxyplot-how-to-programmatically-get-the-scale-of-a-linearaxis-and-use-it-in-an\n- https://gis.stackexchange.com/questions/110730/mercator-scale-factor-is-changed-along-the-meridians-as-a-function-of-latitude\n- https://wiki.openstreetmap.org/wiki/Mercator\n- https://en.wikipedia.org/wiki/Web_Mercator_projection\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbobld%2Foxyplot-cartography","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbobld%2Foxyplot-cartography","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbobld%2Foxyplot-cartography/lists"}