Updated MapsforgeTiles

This commit is contained in:
ClemensFischer 2026-02-12 18:57:19 +01:00
parent 215ea1428f
commit 08bb0fe8de
15 changed files with 224 additions and 241 deletions

View file

@ -1,24 +0,0 @@
using System;
using Avalonia;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
namespace MapControl.MapsforgeTiles
{
public partial class MapsforgeTileSource
{
private static Bitmap CreateImage(int[] pixels)
{
var size = (int)Math.Sqrt(pixels.Length);
unsafe
{
fixed (int* ptr = pixels)
{
return new Bitmap(PixelFormat.Bgra8888, AlphaFormat.Opaque, (nint)ptr,
new PixelSize(size, size), new Vector(96d, 96d), size * 4);
}
}
}
}
}

View file

@ -0,0 +1,42 @@
using Avalonia;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using MapsforgeWrapper;
using System;
using System.Threading.Tasks;
namespace MapControl.MapsforgeTiles
{
public class MapsforgeTileSource(string theme, int cacheCapacity = 200) : TileSource
{
private readonly TileRenderer renderer = new(theme, cacheCapacity);
public static void Initialize(string mapFilePath, float dpiScale)
{
TileRenderer.Initialize(mapFilePath, dpiScale);
}
public override Task<IImage> LoadImageAsync(int zoomLevel, int column, int row)
{
var pixels = renderer.RenderTile(zoomLevel, column, row);
IImage image = pixels != null ? CreateImage(pixels) : null;
return Task.FromResult(image);
}
private static Bitmap CreateImage(int[] pixels)
{
var size = (int)Math.Sqrt(pixels.Length);
unsafe
{
fixed (int* ptr = pixels)
{
return new Bitmap(PixelFormat.Bgra8888, AlphaFormat.Opaque, (nint)ptr,
new PixelSize(size, size), new Vector(96d, 96d), size * 4);
}
}
}
}
}

View file

@ -7,23 +7,8 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\MapControl\Avalonia\MapControl.Avalonia.csproj" />
<ProjectReference Include="..\MapsforgeWrapper\MapsforgeWrapper.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="IKVM" Version="8.15.0" />
</ItemGroup>
<ItemGroup>
<IkvmReference Include="..\target\mapsforge-tilerenderer-0.1.0-jar-with-dependencies.jar" />
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="cd ..&#xD;&#xA;mvn package" />
</Target>
</Project>

View file

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IKVM" Version="8.15.0" />
</ItemGroup>
<ItemGroup>
<IkvmReference Include="target\mapsforge-dependencies-0.27.0.jar" />
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="mvn package" />
</Target>
</Project>

View file

@ -0,0 +1,75 @@
using org.mapsforge.map.awt.graphics;
using org.mapsforge.map.datastore;
using org.mapsforge.map.layer.cache;
using org.mapsforge.map.layer.renderer;
using org.mapsforge.map.model;
using org.mapsforge.map.reader;
using org.mapsforge.map.rendertheme.@internal;
using org.mapsforge.map.rendertheme.rule;
using System.IO;
namespace MapsforgeWrapper
{
public class TileRenderer
{
private static DisplayModel displayModel;
private static MapDataStore dataStore;
public static void Initialize(string mapFilePath, float dpiScale)
{
DisplayModel.setDeviceScaleFactor(dpiScale);
displayModel = new DisplayModel();
if (mapFilePath.EndsWith(".map"))
{
dataStore = new MapFile(mapFilePath);
}
else
{
var multiMapDataStore = new MultiMapDataStore(MultiMapDataStore.DataPolicy.DEDUPLICATE);
foreach (var file in Directory.EnumerateFiles(mapFilePath, "*.map"))
{
multiMapDataStore.addMapDataStore(new MapFile(file), false, false);
}
dataStore = multiMapDataStore;
}
}
private readonly InMemoryTileCache tileCache;
private readonly DatabaseRenderer renderer;
private readonly RenderThemeFuture renderThemeFuture;
public TileRenderer(string theme, int cacheCapacity = 200)
{
tileCache = new InMemoryTileCache(cacheCapacity);
renderer = new DatabaseRenderer(dataStore, AwtGraphicFactory.INSTANCE, tileCache, null, true, false, null);
renderThemeFuture = new RenderThemeFuture(AwtGraphicFactory.INSTANCE, MapsforgeThemes.valueOf(theme.ToUpper()), displayModel);
}
public int[] RenderTile(int zoomLevel, int column, int row)
{
if (!renderThemeFuture.isDone())
{
renderThemeFuture.run();
}
int[] imageBuffer = null;
var tile = new org.mapsforge.core.model.Tile(column, row, (byte)zoomLevel, displayModel.getTileSize());
var job = new RendererJob(tile, dataStore, renderThemeFuture, displayModel, 1f, false, false);
var bitmap = tileCache.get(job) ?? renderer.executeJob(job);
if (bitmap != null)
{
var image = AwtGraphicFactory.getBitmap(bitmap);
if (image != null)
{
imageBuffer = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
}
}
return imageBuffer;
}
}
}

View file

@ -5,11 +5,10 @@
<modelVersion>4.0.0</modelVersion>
<groupId>xaml.mapcontrol</groupId>
<artifactId>mapsforge-tilerenderer</artifactId>
<version>0.1.0</version>
<artifactId>mapsforge-dependencies</artifactId>
<version>0.27.0</version>
<properties>
<maven.compiler.release>8</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -46,6 +45,7 @@
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>

View file

@ -1,32 +0,0 @@
using System.Threading.Tasks;
using TileRenderer;
#if WPF
using System.Windows.Media;
#elif UWP
using Windows.UI.Xaml.Media;
#elif WINUI
using Microsoft.UI.Xaml.Media;
#elif AVALONIA
using ImageSource = Avalonia.Media.IImage;
#endif
namespace MapControl.MapsforgeTiles
{
public partial class MapsforgeTileSource(string mapDirectory, string theme, int cacheCapacity = 200) : TileSource
{
private readonly MapsforgeTileRenderer renderer = new(mapDirectory, theme, cacheCapacity);
public static void SetDpiScale(float scale)
{
MapsforgeTileRenderer.SetDpiScale(scale);
}
public override Task<ImageSource> LoadImageAsync(int zoomLevel, int column, int row)
{
var pixels = renderer.RenderTile(zoomLevel, column, row);
ImageSource image = pixels != null ? CreateImage(pixels) : null;
return Task.FromResult(image);
}
}
}

View file

@ -11,23 +11,11 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" />
<Compile Include="..\WinUI\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\MapControl\UWP\MapControl.UWP.csproj" />
<ProjectReference Include="..\MapsforgeWrapper\MapsforgeWrapper.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="IKVM" Version="8.15.0" />
</ItemGroup>
<ItemGroup>
<IkvmReference Include="..\target\mapsforge-tilerenderer-0.1.0-jar-with-dependencies.jar" />
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="cd ..&#xD;&#xA;mvn package" />
</Target>
</Project>

View file

@ -1,17 +0,0 @@
using System;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace MapControl.MapsforgeTiles
{
public partial class MapsforgeTileSource
{
private static BitmapSource CreateImage(int[] pixels)
{
var size = (int)Math.Sqrt(pixels.Length);
var image = BitmapSource.Create(size, size, 96d, 96d, PixelFormats.Bgra32, null, pixels, size * 4);
image.Freeze();
return image;
}
}
}

View file

@ -0,0 +1,34 @@
using MapsforgeWrapper;
using System;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace MapControl.MapsforgeTiles
{
public class MapsforgeTileSource(string theme, int cacheCapacity = 200) : TileSource
{
private readonly TileRenderer renderer = new(theme, cacheCapacity);
public static void Initialize(string mapFilePath, float dpiScale)
{
TileRenderer.Initialize(mapFilePath, dpiScale);
}
public override Task<ImageSource> LoadImageAsync(int zoomLevel, int column, int row)
{
var pixels = renderer.RenderTile(zoomLevel, column, row);
ImageSource image = pixels != null ? CreateImage(pixels) : null;
return Task.FromResult(image);
}
private static BitmapSource CreateImage(int[] pixels)
{
var size = (int)Math.Sqrt(pixels.Length);
var image = BitmapSource.Create(size, size, 96d, 96d, PixelFormats.Bgra32, null, pixels, size * 4);
image.Freeze();
return image;
}
}
}

View file

@ -7,23 +7,8 @@
<AssemblyTitle>XAML Map Control Mapsforge Library for WPF</AssemblyTitle>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\MapControl\WPF\MapControl.WPF.csproj" />
<ProjectReference Include="..\MapsforgeWrapper\MapsforgeWrapper.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="IKVM" Version="8.15.0" />
</ItemGroup>
<ItemGroup>
<IkvmReference Include="..\target\mapsforge-tilerenderer-0.1.0-jar-with-dependencies.jar" />
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="cd ..&#xD;&#xA;mvn package" />
</Target>
</Project>

View file

@ -1,30 +0,0 @@
using System;
using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;
#if UWP
using Windows.UI.Xaml.Media.Imaging;
#elif WINUI
using Microsoft.UI.Xaml.Media.Imaging;
#endif
namespace MapControl.MapsforgeTiles
{
public partial class MapsforgeTileSource
{
private static WriteableBitmap CreateImage(int[] pixels)
{
var size = (int)Math.Sqrt(pixels.Length);
var bitmap = new WriteableBitmap(size, size);
using var stream = bitmap.PixelBuffer.AsStream();
using var writer = new BinaryWriter(stream);
foreach (var pixel in pixels)
{
writer.Write(pixel);
}
return bitmap;
}
}
}

View file

@ -0,0 +1,49 @@
using System;
using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using MapsforgeWrapper;
#if UWP
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
#elif WINUI
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
#endif
namespace MapControl.MapsforgeTiles
{
public class MapsforgeTileSource(string theme, int cacheCapacity = 200) : TileSource
{
private readonly TileRenderer renderer = new(theme, cacheCapacity);
public static void Initialize(string mapFilePath, float dpiScale)
{
TileRenderer.Initialize(mapFilePath, dpiScale);
}
public override Task<ImageSource> LoadImageAsync(int zoomLevel, int column, int row)
{
var pixels = renderer.RenderTile(zoomLevel, column, row);
ImageSource image = pixels != null ? CreateImage(pixels) : null;
return Task.FromResult(image);
}
private static WriteableBitmap CreateImage(int[] pixels)
{
var size = (int)Math.Sqrt(pixels.Length);
var bitmap = new WriteableBitmap(size, size);
using var stream = bitmap.PixelBuffer.AsStream();
using var writer = new BinaryWriter(stream);
foreach (var pixel in pixels)
{
writer.Write(pixel);
}
return bitmap;
}
}
}

View file

@ -7,23 +7,8 @@
<AssemblyTitle>XAML Map Control Mapsforge Library for WinUI</AssemblyTitle>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\MapControl\WinUI\MapControl.WinUI.csproj" />
<ProjectReference Include="..\MapsforgeWrapper\MapsforgeWrapper.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="IKVM" Version="8.15.0" />
</ItemGroup>
<ItemGroup>
<IkvmReference Include="..\target\mapsforge-tilerenderer-0.1.0-jar-with-dependencies.jar" />
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="cd ..&#xD;&#xA;mvn package" />
</Target>
</Project>

View file

@ -1,74 +0,0 @@
package TileRenderer;
import org.mapsforge.core.graphics.TileBitmap;
import org.mapsforge.core.model.Tile;
import org.mapsforge.map.awt.graphics.AwtGraphicFactory;
import org.mapsforge.map.datastore.MapDataStore;
import org.mapsforge.map.datastore.MultiMapDataStore;
import org.mapsforge.map.layer.cache.InMemoryTileCache;
import org.mapsforge.map.layer.renderer.DatabaseRenderer;
import org.mapsforge.map.layer.renderer.RendererJob;
import org.mapsforge.map.model.DisplayModel;
import org.mapsforge.map.reader.MapFile;
import org.mapsforge.map.rendertheme.internal.MapsforgeThemes;
import org.mapsforge.map.rendertheme.rule.RenderThemeFuture;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class MapsforgeTileRenderer {
public static void SetDpiScale(float scale) {
DisplayModel.setDeviceScaleFactor(scale);
}
private final MapDataStore dataStore;
private final DisplayModel displayModel;
private final InMemoryTileCache tileCache;
private final DatabaseRenderer renderer;
private final RenderThemeFuture renderThemeFuture;
public MapsforgeTileRenderer(String mapFilePath, String theme, int cacheCapacity) {
if (mapFilePath.endsWith(".map")) {
dataStore = new MapFile(mapFilePath);
} else {
MultiMapDataStore multiMapDataStore = new MultiMapDataStore(MultiMapDataStore.DataPolicy.DEDUPLICATE);
File dir = new File(mapFilePath);
for (File mapFile : dir.listFiles((file, name) -> name.endsWith(".map"))) {
multiMapDataStore.addMapDataStore(new MapFile(mapFile), false, false);
}
dataStore = multiMapDataStore;
}
displayModel = new DisplayModel();
tileCache = new InMemoryTileCache(cacheCapacity);
renderer = new DatabaseRenderer(dataStore, AwtGraphicFactory.INSTANCE, tileCache, null, true, false, null);
renderThemeFuture = new RenderThemeFuture(AwtGraphicFactory.INSTANCE, MapsforgeThemes.valueOf(theme.toUpperCase()), displayModel);
}
public int[] RenderTile(int zoomLevel, int x, int y) throws IOException {
if (!renderThemeFuture.isDone()) {
renderThemeFuture.run();
}
int[] imageBuffer = null;
Tile tile = new Tile(x, y, (byte) zoomLevel, displayModel.getTileSize());
RendererJob job = new RendererJob(tile, dataStore, renderThemeFuture, displayModel, 1f, false, false);
TileBitmap bitmap = tileCache.get(job);
if (bitmap == null) {
bitmap = renderer.executeJob(job);
}
if (bitmap != null) {
BufferedImage image = AwtGraphicFactory.getBitmap(bitmap);
if (image != null) {
imageBuffer = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
}
}
return imageBuffer;
}
}