mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-05-07 13:37:47 +00:00
File scoped namespaces
This commit is contained in:
parent
c14377f976
commit
65aba44af6
152 changed files with 11962 additions and 12115 deletions
|
|
@ -24,213 +24,212 @@ using Avalonia.Controls;
|
|||
using Avalonia.Media;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class GroundOverlay : MapPanel
|
||||
{
|
||||
public partial class GroundOverlay : MapPanel
|
||||
private class ImageOverlay
|
||||
{
|
||||
private class ImageOverlay
|
||||
public ImageOverlay(string path, BoundingBox latLonBox, int zIndex)
|
||||
{
|
||||
public ImageOverlay(string path, BoundingBox latLonBox, int zIndex)
|
||||
ImagePath = path;
|
||||
SetBoundingBox(Image, latLonBox);
|
||||
Image.SetValue(Canvas.ZIndexProperty, zIndex);
|
||||
}
|
||||
|
||||
public string ImagePath { get; }
|
||||
|
||||
public Image Image { get; } = new Image { Stretch = Stretch.Fill };
|
||||
|
||||
public async Task LoadImage(Uri docUri)
|
||||
{
|
||||
Image.Source = await ImageLoader.LoadImageAsync(new Uri(docUri, ImagePath));
|
||||
}
|
||||
|
||||
public async Task LoadImage(ZipArchive archive)
|
||||
{
|
||||
var entry = archive.GetEntry(ImagePath);
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
ImagePath = path;
|
||||
SetBoundingBox(Image, latLonBox);
|
||||
Image.SetValue(Canvas.ZIndexProperty, zIndex);
|
||||
}
|
||||
using var memoryStream = new MemoryStream((int)entry.Length);
|
||||
|
||||
public string ImagePath { get; }
|
||||
|
||||
public Image Image { get; } = new Image { Stretch = Stretch.Fill };
|
||||
|
||||
public async Task LoadImage(Uri docUri)
|
||||
{
|
||||
Image.Source = await ImageLoader.LoadImageAsync(new Uri(docUri, ImagePath));
|
||||
}
|
||||
|
||||
public async Task LoadImage(ZipArchive archive)
|
||||
{
|
||||
var entry = archive.GetEntry(ImagePath);
|
||||
|
||||
if (entry != null)
|
||||
using (var zipStream = entry.Open())
|
||||
{
|
||||
using var memoryStream = new MemoryStream((int)entry.Length);
|
||||
|
||||
using (var zipStream = entry.Open())
|
||||
{
|
||||
zipStream.CopyTo(memoryStream); // can't use CopyToAsync with ZipArchive
|
||||
}
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
Image.Source = await ImageLoader.LoadImageAsync(memoryStream);
|
||||
zipStream.CopyTo(memoryStream); // can't use CopyToAsync with ZipArchive
|
||||
}
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
Image.Source = await ImageLoader.LoadImageAsync(memoryStream);
|
||||
}
|
||||
}
|
||||
|
||||
private static ILogger Logger => field ??= ImageLoader.LoggerFactory?.CreateLogger(typeof(GroundOverlay));
|
||||
|
||||
public static readonly DependencyProperty SourcePathProperty =
|
||||
DependencyPropertyHelper.Register<GroundOverlay, string>(nameof(SourcePath), null,
|
||||
async (groundOverlay, oldValue, newValue) => await groundOverlay.LoadAsync(newValue));
|
||||
|
||||
public string SourcePath
|
||||
{
|
||||
get => (string)GetValue(SourcePathProperty);
|
||||
set => SetValue(SourcePathProperty, value);
|
||||
}
|
||||
|
||||
public static async Task<GroundOverlay> CreateAsync(string sourcePath)
|
||||
{
|
||||
var groundOverlay = new GroundOverlay();
|
||||
|
||||
await groundOverlay.LoadAsync(sourcePath);
|
||||
|
||||
return groundOverlay;
|
||||
}
|
||||
|
||||
public async Task LoadAsync(string sourcePath)
|
||||
{
|
||||
List<ImageOverlay> imageOverlays = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(sourcePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var ext = Path.GetExtension(sourcePath).ToLower();
|
||||
|
||||
if (ext == ".kmz")
|
||||
{
|
||||
imageOverlays = await LoadImageOverlaysFromArchive(sourcePath);
|
||||
}
|
||||
else if (ext == ".kml")
|
||||
{
|
||||
imageOverlays = await LoadImageOverlaysFromFile(sourcePath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogError(ex, "Failed loading from {path}", sourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
Children.Clear();
|
||||
|
||||
if (imageOverlays != null)
|
||||
{
|
||||
foreach (var imageOverlay in imageOverlays)
|
||||
{
|
||||
Children.Add(imageOverlay.Image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<List<ImageOverlay>> LoadImageOverlaysFromArchive(string archiveFilePath)
|
||||
{
|
||||
using var archive = ZipFile.OpenRead(archiveFilePath);
|
||||
|
||||
var docEntry = archive.GetEntry("doc.kml") ??
|
||||
archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")) ??
|
||||
throw new ArgumentException($"No KML entry found in {archiveFilePath}.");
|
||||
XElement element;
|
||||
|
||||
using (var stream = docEntry.Open())
|
||||
{
|
||||
element = await XDocument.LoadRootElementAsync(stream);
|
||||
}
|
||||
|
||||
return await LoadImageOverlays(element, imageOverlay => imageOverlay.LoadImage(archive));
|
||||
}
|
||||
|
||||
private static async Task<List<ImageOverlay>> LoadImageOverlaysFromFile(string docFilePath)
|
||||
{
|
||||
var docUri = new Uri(FilePath.GetFullPath(docFilePath));
|
||||
XElement element;
|
||||
|
||||
using (var stream = File.OpenRead(docUri.AbsolutePath))
|
||||
{
|
||||
element = await XDocument.LoadRootElementAsync(stream);
|
||||
}
|
||||
|
||||
return await LoadImageOverlays(element, imageOverlay => imageOverlay.LoadImage(docUri));
|
||||
}
|
||||
|
||||
private static async Task<List<ImageOverlay>> LoadImageOverlays(XElement rootElement, Func<ImageOverlay, Task> loadFunc)
|
||||
{
|
||||
var imageOverlays = ReadImageOverlays(rootElement);
|
||||
|
||||
await Task.WhenAll(imageOverlays.Select(loadFunc));
|
||||
|
||||
return imageOverlays;
|
||||
}
|
||||
|
||||
private static List<ImageOverlay> ReadImageOverlays(XElement rootElement)
|
||||
{
|
||||
var ns = rootElement.Name.Namespace;
|
||||
var docElement = rootElement.Element(ns + "Document") ?? rootElement;
|
||||
var imageOverlays = new List<ImageOverlay>();
|
||||
|
||||
foreach (var folderElement in docElement.Elements(ns + "Folder"))
|
||||
{
|
||||
foreach (var groundOverlayElement in folderElement.Elements(ns + "GroundOverlay"))
|
||||
{
|
||||
var pathElement = groundOverlayElement.Element(ns + "Icon");
|
||||
var path = pathElement?.Element(ns + "href")?.Value;
|
||||
|
||||
var latLonBoxElement = groundOverlayElement.Element(ns + "LatLonBox");
|
||||
var latLonBox = latLonBoxElement != null ? ReadLatLonBox(latLonBoxElement) : null;
|
||||
|
||||
var drawOrder = groundOverlayElement.Element(ns + "drawOrder")?.Value;
|
||||
var zIndex = drawOrder != null ? int.Parse(drawOrder) : 0;
|
||||
|
||||
if (latLonBox != null && path != null)
|
||||
{
|
||||
imageOverlays.Add(new ImageOverlay(path, latLonBox, zIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return imageOverlays;
|
||||
}
|
||||
|
||||
private static BoundingBox ReadLatLonBox(XElement latLonBoxElement)
|
||||
{
|
||||
var ns = latLonBoxElement.Name.Namespace;
|
||||
var north = double.NaN;
|
||||
var south = double.NaN;
|
||||
var east = double.NaN;
|
||||
var west = double.NaN;
|
||||
|
||||
var value = latLonBoxElement.Element(ns + "north")?.Value;
|
||||
if (value != null)
|
||||
{
|
||||
north = double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
value = latLonBoxElement.Element(ns + "south")?.Value;
|
||||
if (value != null)
|
||||
{
|
||||
south = double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
value = latLonBoxElement.Element(ns + "east")?.Value;
|
||||
if (value != null)
|
||||
{
|
||||
east = double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
value = latLonBoxElement.Element(ns + "west")?.Value;
|
||||
if (value != null)
|
||||
{
|
||||
west = double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (double.IsNaN(north) || double.IsNaN(south) ||
|
||||
double.IsNaN(east) || double.IsNaN(west) ||
|
||||
north <= south || east <= west)
|
||||
{
|
||||
throw new FormatException("Invalid LatLonBox");
|
||||
}
|
||||
|
||||
return new BoundingBox(south, west, north, east);
|
||||
}
|
||||
}
|
||||
|
||||
private static ILogger Logger => field ??= ImageLoader.LoggerFactory?.CreateLogger(typeof(GroundOverlay));
|
||||
|
||||
public static readonly DependencyProperty SourcePathProperty =
|
||||
DependencyPropertyHelper.Register<GroundOverlay, string>(nameof(SourcePath), null,
|
||||
async (groundOverlay, oldValue, newValue) => await groundOverlay.LoadAsync(newValue));
|
||||
|
||||
public string SourcePath
|
||||
{
|
||||
get => (string)GetValue(SourcePathProperty);
|
||||
set => SetValue(SourcePathProperty, value);
|
||||
}
|
||||
|
||||
public static async Task<GroundOverlay> CreateAsync(string sourcePath)
|
||||
{
|
||||
var groundOverlay = new GroundOverlay();
|
||||
|
||||
await groundOverlay.LoadAsync(sourcePath);
|
||||
|
||||
return groundOverlay;
|
||||
}
|
||||
|
||||
public async Task LoadAsync(string sourcePath)
|
||||
{
|
||||
List<ImageOverlay> imageOverlays = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(sourcePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var ext = Path.GetExtension(sourcePath).ToLower();
|
||||
|
||||
if (ext == ".kmz")
|
||||
{
|
||||
imageOverlays = await LoadImageOverlaysFromArchive(sourcePath);
|
||||
}
|
||||
else if (ext == ".kml")
|
||||
{
|
||||
imageOverlays = await LoadImageOverlaysFromFile(sourcePath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogError(ex, "Failed loading from {path}", sourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
Children.Clear();
|
||||
|
||||
if (imageOverlays != null)
|
||||
{
|
||||
foreach (var imageOverlay in imageOverlays)
|
||||
{
|
||||
Children.Add(imageOverlay.Image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<List<ImageOverlay>> LoadImageOverlaysFromArchive(string archiveFilePath)
|
||||
{
|
||||
using var archive = ZipFile.OpenRead(archiveFilePath);
|
||||
|
||||
var docEntry = archive.GetEntry("doc.kml") ??
|
||||
archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")) ??
|
||||
throw new ArgumentException($"No KML entry found in {archiveFilePath}.");
|
||||
XElement element;
|
||||
|
||||
using (var stream = docEntry.Open())
|
||||
{
|
||||
element = await XDocument.LoadRootElementAsync(stream);
|
||||
}
|
||||
|
||||
return await LoadImageOverlays(element, imageOverlay => imageOverlay.LoadImage(archive));
|
||||
}
|
||||
|
||||
private static async Task<List<ImageOverlay>> LoadImageOverlaysFromFile(string docFilePath)
|
||||
{
|
||||
var docUri = new Uri(FilePath.GetFullPath(docFilePath));
|
||||
XElement element;
|
||||
|
||||
using (var stream = File.OpenRead(docUri.AbsolutePath))
|
||||
{
|
||||
element = await XDocument.LoadRootElementAsync(stream);
|
||||
}
|
||||
|
||||
return await LoadImageOverlays(element, imageOverlay => imageOverlay.LoadImage(docUri));
|
||||
}
|
||||
|
||||
private static async Task<List<ImageOverlay>> LoadImageOverlays(XElement rootElement, Func<ImageOverlay, Task> loadFunc)
|
||||
{
|
||||
var imageOverlays = ReadImageOverlays(rootElement);
|
||||
|
||||
await Task.WhenAll(imageOverlays.Select(loadFunc));
|
||||
|
||||
return imageOverlays;
|
||||
}
|
||||
|
||||
private static List<ImageOverlay> ReadImageOverlays(XElement rootElement)
|
||||
{
|
||||
var ns = rootElement.Name.Namespace;
|
||||
var docElement = rootElement.Element(ns + "Document") ?? rootElement;
|
||||
var imageOverlays = new List<ImageOverlay>();
|
||||
|
||||
foreach (var folderElement in docElement.Elements(ns + "Folder"))
|
||||
{
|
||||
foreach (var groundOverlayElement in folderElement.Elements(ns + "GroundOverlay"))
|
||||
{
|
||||
var pathElement = groundOverlayElement.Element(ns + "Icon");
|
||||
var path = pathElement?.Element(ns + "href")?.Value;
|
||||
|
||||
var latLonBoxElement = groundOverlayElement.Element(ns + "LatLonBox");
|
||||
var latLonBox = latLonBoxElement != null ? ReadLatLonBox(latLonBoxElement) : null;
|
||||
|
||||
var drawOrder = groundOverlayElement.Element(ns + "drawOrder")?.Value;
|
||||
var zIndex = drawOrder != null ? int.Parse(drawOrder) : 0;
|
||||
|
||||
if (latLonBox != null && path != null)
|
||||
{
|
||||
imageOverlays.Add(new ImageOverlay(path, latLonBox, zIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return imageOverlays;
|
||||
}
|
||||
|
||||
private static BoundingBox ReadLatLonBox(XElement latLonBoxElement)
|
||||
{
|
||||
var ns = latLonBoxElement.Name.Namespace;
|
||||
var north = double.NaN;
|
||||
var south = double.NaN;
|
||||
var east = double.NaN;
|
||||
var west = double.NaN;
|
||||
|
||||
var value = latLonBoxElement.Element(ns + "north")?.Value;
|
||||
if (value != null)
|
||||
{
|
||||
north = double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
value = latLonBoxElement.Element(ns + "south")?.Value;
|
||||
if (value != null)
|
||||
{
|
||||
south = double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
value = latLonBoxElement.Element(ns + "east")?.Value;
|
||||
if (value != null)
|
||||
{
|
||||
east = double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
value = latLonBoxElement.Element(ns + "west")?.Value;
|
||||
if (value != null)
|
||||
{
|
||||
west = double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (double.IsNaN(north) || double.IsNaN(south) ||
|
||||
double.IsNaN(east) || double.IsNaN(west) ||
|
||||
north <= south || east <= west)
|
||||
{
|
||||
throw new FormatException("Invalid LatLonBox");
|
||||
}
|
||||
|
||||
return new BoundingBox(south, west, north, east);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue