mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Reworked MapProjection
Return nullable Point from LocationToMap. Use MapRect instead of WinUI/UWP Rect replacement. Drop Vector. Add Scale struct.
This commit is contained in:
parent
bab1788334
commit
218a85316c
|
|
@ -24,7 +24,7 @@ namespace MapControl
|
||||||
CrsId = DefaultCrsId;
|
CrsId = DefaultCrsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
{
|
{
|
||||||
return new Point(
|
return new Point(
|
||||||
Wgs84MeterPerDegree * (location.Longitude - Center.Longitude) * Math.Cos(Center.Latitude * Math.PI / 180d),
|
Wgs84MeterPerDegree * (location.Longitude - Center.Longitude) * Math.Cos(Center.Latitude * Math.PI / 180d),
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ namespace MapControl
|
||||||
CrsId = crsId;
|
CrsId = crsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
{
|
{
|
||||||
if (location.Equals(Center))
|
if (location.Equals(Center))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -19,22 +19,34 @@ namespace MapControl
|
||||||
Type = MapProjectionType.Azimuthal;
|
Type = MapProjectionType.Azimuthal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Rect BoundingBoxToRect(BoundingBox boundingBox)
|
public override MapRect BoundingBoxToMapRect(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
var center = LocationToMap(boundingBox.Center);
|
var center = LocationToMap(boundingBox.Center);
|
||||||
|
|
||||||
|
if (!center.HasValue)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var width = boundingBox.Width * Wgs84MeterPerDegree;
|
var width = boundingBox.Width * Wgs84MeterPerDegree;
|
||||||
var height = boundingBox.Height * Wgs84MeterPerDegree;
|
var height = boundingBox.Height * Wgs84MeterPerDegree;
|
||||||
|
|
||||||
return new Rect(center.X - width / 2d, center.Y - height / 2d, width, height);
|
return new MapRect(center.Value.X - width / 2d, center.Value.Y - height / 2d, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override BoundingBox RectToBoundingBox(Rect rect)
|
public override BoundingBox MapRectToBoundingBox(MapRect rect)
|
||||||
{
|
{
|
||||||
var center = MapToLocation(new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d));
|
var center = MapToLocation(new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d));
|
||||||
|
|
||||||
|
if (center == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var width = rect.Width / Wgs84MeterPerDegree;
|
var width = rect.Width / Wgs84MeterPerDegree;
|
||||||
var height = rect.Height / Wgs84MeterPerDegree;
|
var height = rect.Height / Wgs84MeterPerDegree;
|
||||||
|
|
||||||
return center != null ? new CenteredBoundingBox(center, width, height) : null;
|
return new CenteredBoundingBox(center, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,14 @@ namespace MapControl
|
||||||
CrsId = DefaultCrsId;
|
CrsId = DefaultCrsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Vector GetRelativeScale(Location location)
|
public override Scale GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
return new Vector(
|
return new Scale(
|
||||||
1d / Math.Cos(location.Latitude * Math.PI / 180d),
|
1d / Math.Cos(location.Latitude * Math.PI / 180d),
|
||||||
1d);
|
1d);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
{
|
{
|
||||||
return new Point(
|
return new Point(
|
||||||
Wgs84MeterPerDegree * location.Longitude,
|
Wgs84MeterPerDegree * location.Longitude,
|
||||||
|
|
@ -46,7 +46,7 @@ namespace MapControl
|
||||||
point.X / Wgs84MeterPerDegree);
|
point.X / Wgs84MeterPerDegree);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetBboxValue(Rect rect)
|
public override string GetBboxValue(MapRect rect)
|
||||||
{
|
{
|
||||||
return string.Format(CultureInfo.InvariantCulture,
|
return string.Format(CultureInfo.InvariantCulture,
|
||||||
CrsId == "CRS:84" ? "{0},{1},{2},{3}" : "{1},{0},{3},{2}",
|
CrsId == "CRS:84" ? "{0},{1},{2},{3}" : "{1},{0},{3},{2}",
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ namespace MapControl
|
||||||
transform.M21 = 0;
|
transform.M21 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var rect = new Rect(
|
var rect = new MapRect(
|
||||||
transform.Transform(new Point()),
|
transform.Transform(new Point()),
|
||||||
transform.Transform(new Point(bitmap.PixelWidth, bitmap.PixelHeight)));
|
transform.Transform(new Point(bitmap.PixelWidth, bitmap.PixelHeight)));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ namespace MapControl
|
||||||
CrsId = DefaultCrsId;
|
CrsId = DefaultCrsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
{
|
{
|
||||||
if (location.Equals(Center))
|
if (location.Equals(Center))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
#if !WINUI && !UWP
|
#if WINUI || UWP
|
||||||
|
using Windows.Foundation;
|
||||||
|
#else
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -48,30 +50,30 @@ namespace MapControl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var topLeft = new Point(rect.X, rect.Y);
|
var topLeft = new Point(rect.Left, rect.Top);
|
||||||
var topRight = new Point(rect.X + rect.Width, rect.Y);
|
var topRight = new Point(rect.Right, rect.Top);
|
||||||
var bottomLeft = new Point(rect.X, rect.Y + rect.Height);
|
var bottomLeft = new Point(rect.Left, rect.Bottom);
|
||||||
var bottomRight = new Point(rect.X + rect.Width, rect.Y + rect.Height);
|
var bottomRight = new Point(rect.Right, rect.Bottom);
|
||||||
var numIntersections = 0;
|
var numIntersections = 0;
|
||||||
|
|
||||||
if (GetIntersection(ref p1, ref p2, topLeft, bottomLeft, p => p.X <= rect.X)) // left edge
|
if (GetIntersection(ref p1, ref p2, topLeft, bottomLeft, p => p.X <= rect.Left)) // left edge
|
||||||
{
|
{
|
||||||
numIntersections++;
|
numIntersections++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetIntersection(ref p1, ref p2, topLeft, topRight, p => p.Y <= rect.Y)) // top edge
|
if (GetIntersection(ref p1, ref p2, topLeft, topRight, p => p.Y <= rect.Top)) // top edge
|
||||||
{
|
{
|
||||||
numIntersections++;
|
numIntersections++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numIntersections < 2 &&
|
if (numIntersections < 2 &&
|
||||||
GetIntersection(ref p1, ref p2, topRight, bottomRight, p => p.X >= rect.X + rect.Width)) // right edge
|
GetIntersection(ref p1, ref p2, topRight, bottomRight, p => p.X >= rect.Right)) // right edge
|
||||||
{
|
{
|
||||||
numIntersections++;
|
numIntersections++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numIntersections < 2 &&
|
if (numIntersections < 2 &&
|
||||||
GetIntersection(ref p1, ref p2, bottomLeft, bottomRight, p => p.Y >= rect.Y + rect.Height)) // bottom edge
|
GetIntersection(ref p1, ref p2, bottomLeft, bottomRight, p => p.Y >= rect.Bottom)) // bottom edge
|
||||||
{
|
{
|
||||||
numIntersections++;
|
numIntersections++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
#if WINUI
|
#if WINUI
|
||||||
|
using Windows.Foundation;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Microsoft.UI.Xaml.Media.Animation;
|
using Microsoft.UI.Xaml.Media.Animation;
|
||||||
#elif UWP
|
#elif UWP
|
||||||
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
using Windows.UI.Xaml.Media.Animation;
|
using Windows.UI.Xaml.Media.Animation;
|
||||||
|
|
@ -229,7 +231,7 @@ namespace MapControl
|
||||||
/// Gets the map scale as the horizontal and vertical scaling factors from geographic
|
/// Gets the map scale as the horizontal and vertical scaling factors from geographic
|
||||||
/// coordinates to view coordinates at the specified location, as pixels per meter.
|
/// coordinates to view coordinates at the specified location, as pixels per meter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Vector GetScale(Location location)
|
public Scale GetScale(Location location)
|
||||||
{
|
{
|
||||||
return ViewTransform.Scale * MapProjection.GetRelativeScale(location);
|
return ViewTransform.Scale * MapProjection.GetRelativeScale(location);
|
||||||
}
|
}
|
||||||
|
|
@ -237,9 +239,16 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a Location in geographic coordinates to a Point in view coordinates.
|
/// Transforms a Location in geographic coordinates to a Point in view coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Point LocationToView(Location location)
|
public Point? LocationToView(Location location)
|
||||||
{
|
{
|
||||||
return ViewTransform.MapToView(MapProjection.LocationToMap(location));
|
var point = MapProjection.LocationToMap(location);
|
||||||
|
|
||||||
|
if (!point.HasValue)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ViewTransform.MapToView(point.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -265,7 +274,7 @@ namespace MapControl
|
||||||
var y1 = Math.Min(p1.Y, Math.Min(p2.Y, Math.Min(p3.Y, p4.Y)));
|
var y1 = Math.Min(p1.Y, Math.Min(p2.Y, Math.Min(p3.Y, p4.Y)));
|
||||||
var y2 = Math.Max(p1.Y, Math.Max(p2.Y, Math.Max(p3.Y, p4.Y)));
|
var y2 = Math.Max(p1.Y, Math.Max(p2.Y, Math.Max(p3.Y, p4.Y)));
|
||||||
|
|
||||||
return MapProjection.RectToBoundingBox(new Rect(x1, y1, x2 - x1, y2 - y1));
|
return MapProjection.MapRectToBoundingBox(new MapRect(x1, y1, x2 - x1, y2 - y1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -291,7 +300,7 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changes the Center property according to the specified translation in view coordinates.
|
/// Changes the Center property according to the specified translation in view coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TranslateMap(Vector translation)
|
public void TranslateMap(Point translation)
|
||||||
{
|
{
|
||||||
if (transformCenter != null)
|
if (transformCenter != null)
|
||||||
{
|
{
|
||||||
|
|
@ -301,7 +310,8 @@ namespace MapControl
|
||||||
|
|
||||||
if (translation.X != 0d || translation.Y != 0d)
|
if (translation.X != 0d || translation.Y != 0d)
|
||||||
{
|
{
|
||||||
var center = ViewToLocation(viewCenter - translation);
|
var center = ViewToLocation(new Point(viewCenter.X - translation.X, viewCenter.Y - translation.Y));
|
||||||
|
|
||||||
if (center != null)
|
if (center != null)
|
||||||
{
|
{
|
||||||
Center = center;
|
Center = center;
|
||||||
|
|
@ -314,12 +324,14 @@ namespace MapControl
|
||||||
/// view coordinate translation, rotation and scale delta values. Rotation and scaling
|
/// view coordinate translation, rotation and scale delta values. Rotation and scaling
|
||||||
/// is performed relative to the specified center point in view coordinates.
|
/// is performed relative to the specified center point in view coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TransformMap(Point center, Vector translation, double rotation, double scale)
|
public void TransformMap(Point center, Point translation, double rotation, double scale)
|
||||||
{
|
{
|
||||||
if (rotation != 0d || scale != 1d)
|
if (rotation != 0d || scale != 1d)
|
||||||
{
|
{
|
||||||
SetTransformCenter(center);
|
SetTransformCenter(center);
|
||||||
viewCenter += translation;
|
|
||||||
|
viewCenter.X += translation.X;
|
||||||
|
viewCenter.Y += translation.Y;
|
||||||
|
|
||||||
if (rotation != 0d)
|
if (rotation != 0d)
|
||||||
{
|
{
|
||||||
|
|
@ -368,7 +380,7 @@ namespace MapControl
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ZoomToBounds(BoundingBox boundingBox)
|
public void ZoomToBounds(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
var rect = MapProjection.BoundingBoxToRect(boundingBox);
|
var rect = MapProjection.BoundingBoxToMapRect(boundingBox);
|
||||||
var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
||||||
var targetCenter = MapProjection.MapToLocation(center);
|
var targetCenter = MapProjection.MapToLocation(center);
|
||||||
|
|
||||||
|
|
@ -737,9 +749,9 @@ namespace MapControl
|
||||||
|
|
||||||
var mapCenter = projection.LocationToMap(transformCenter ?? Center);
|
var mapCenter = projection.LocationToMap(transformCenter ?? Center);
|
||||||
|
|
||||||
if (MapProjection.IsValid(mapCenter))
|
if (mapCenter.HasValue)
|
||||||
{
|
{
|
||||||
ViewTransform.SetTransform(mapCenter, viewCenter, viewScale, -Heading);
|
ViewTransform.SetTransform(mapCenter.Value, viewCenter, viewScale, -Heading);
|
||||||
|
|
||||||
if (transformCenter != null)
|
if (transformCenter != null)
|
||||||
{
|
{
|
||||||
|
|
@ -774,9 +786,9 @@ namespace MapControl
|
||||||
|
|
||||||
mapCenter = projection.LocationToMap(center);
|
mapCenter = projection.LocationToMap(center);
|
||||||
|
|
||||||
if (MapProjection.IsValid(mapCenter))
|
if (mapCenter.HasValue)
|
||||||
{
|
{
|
||||||
ViewTransform.SetTransform(mapCenter, viewCenter, viewScale, -Heading);
|
ViewTransform.SetTransform(mapCenter.Value, viewCenter, viewScale, -Heading);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@ using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
#if WINUI
|
#if WINUI
|
||||||
|
using Windows.Foundation;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
#elif UWP
|
#elif UWP
|
||||||
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
#else
|
#else
|
||||||
|
|
@ -104,8 +106,7 @@ namespace MapControl
|
||||||
|
|
||||||
private void AddLabel(ICollection<Label> labels, Location location, Point position, double? rotation = null)
|
private void AddLabel(ICollection<Label> labels, Location location, Point position, double? rotation = null)
|
||||||
{
|
{
|
||||||
if (MapProjection.IsValid(position) &&
|
if (position.X >= 0d && position.X <= ParentMap.RenderSize.Width &&
|
||||||
position.X >= 0d && position.X <= ParentMap.RenderSize.Width &&
|
|
||||||
position.Y >= 0d && position.Y <= ParentMap.RenderSize.Height)
|
position.Y >= 0d && position.Y <= ParentMap.RenderSize.Height)
|
||||||
{
|
{
|
||||||
if (!rotation.HasValue)
|
if (!rotation.HasValue)
|
||||||
|
|
@ -115,9 +116,9 @@ namespace MapControl
|
||||||
var pos = ParentMap.LocationToView(
|
var pos = ParentMap.LocationToView(
|
||||||
new Location(location.Latitude, location.Longitude + 10d / PixelPerLongitudeDegree(location)));
|
new Location(location.Latitude, location.Longitude + 10d / PixelPerLongitudeDegree(location)));
|
||||||
|
|
||||||
if (MapProjection.IsValid(pos))
|
if (pos.HasValue)
|
||||||
{
|
{
|
||||||
rotation = Math.Atan2(pos.Y - position.Y, pos.X - position.X) * 180d / Math.PI;
|
rotation = Math.Atan2(pos.Value.Y - position.Y, pos.Value.X - position.X) * 180d / Math.PI;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,9 +163,9 @@ namespace MapControl
|
||||||
var p1 = ParentMap.LocationToView(new Location(lat, bounds.West));
|
var p1 = ParentMap.LocationToView(new Location(lat, bounds.West));
|
||||||
var p2 = ParentMap.LocationToView(new Location(lat, bounds.East));
|
var p2 = ParentMap.LocationToView(new Location(lat, bounds.East));
|
||||||
|
|
||||||
if (MapProjection.IsValid(p1) && MapProjection.IsValid(p2))
|
if (p1.HasValue && p2.HasValue)
|
||||||
{
|
{
|
||||||
figures.Add(CreateLineFigure(p1, p2));
|
figures.Add(CreateLineFigure(p1.Value, p2.Value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,9 +174,9 @@ namespace MapControl
|
||||||
var p1 = ParentMap.LocationToView(new Location(bounds.South, lon));
|
var p1 = ParentMap.LocationToView(new Location(bounds.South, lon));
|
||||||
var p2 = ParentMap.LocationToView(new Location(bounds.North, lon));
|
var p2 = ParentMap.LocationToView(new Location(bounds.North, lon));
|
||||||
|
|
||||||
if (MapProjection.IsValid(p1) && MapProjection.IsValid(p2))
|
if (p1.HasValue && p2.HasValue)
|
||||||
{
|
{
|
||||||
figures.Add(CreateLineFigure(p1, p2));
|
figures.Add(CreateLineFigure(p1.Value, p2.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var lat = latLabelStart; lat <= bounds.North; lat += lineDistance)
|
for (var lat = latLabelStart; lat <= bounds.North; lat += lineDistance)
|
||||||
|
|
@ -183,7 +184,10 @@ namespace MapControl
|
||||||
var location = new Location(lat, lon);
|
var location = new Location(lat, lon);
|
||||||
var position = ParentMap.LocationToView(location);
|
var position = ParentMap.LocationToView(location);
|
||||||
|
|
||||||
AddLabel(labels, location, position, ParentMap.ViewTransform.Rotation);
|
if (position.HasValue)
|
||||||
|
{
|
||||||
|
AddLabel(labels, location, position.Value, ParentMap.ViewTransform.Rotation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -240,10 +244,10 @@ namespace MapControl
|
||||||
var points = new List<Point>();
|
var points = new List<Point>();
|
||||||
var position = ParentMap.LocationToView(location);
|
var position = ParentMap.LocationToView(location);
|
||||||
|
|
||||||
if (MapProjection.IsValid(position))
|
if (position.HasValue)
|
||||||
{
|
{
|
||||||
points.Add(position);
|
points.Add(position.Value);
|
||||||
AddLabel(labels, location, position);
|
AddLabel(labels, location, position.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < lonSegments; j++)
|
for (int j = 0; j < lonSegments; j++)
|
||||||
|
|
@ -254,13 +258,16 @@ namespace MapControl
|
||||||
location = new Location(lat, lon);
|
location = new Location(lat, lon);
|
||||||
position = ParentMap.LocationToView(location);
|
position = ParentMap.LocationToView(location);
|
||||||
|
|
||||||
if (MapProjection.IsValid(position))
|
if (position.HasValue)
|
||||||
{
|
{
|
||||||
points.Add(position);
|
points.Add(position.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddLabel(labels, location, position);
|
if (position.HasValue)
|
||||||
|
{
|
||||||
|
AddLabel(labels, location, position.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (points.Count >= 2)
|
if (points.Count >= 2)
|
||||||
|
|
@ -280,13 +287,13 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
var p = ParentMap.LocationToView(new Location(startLatitude + i * deltaLatitude, longitude));
|
var p = ParentMap.LocationToView(new Location(startLatitude + i * deltaLatitude, longitude));
|
||||||
|
|
||||||
if (MapProjection.IsValid(p))
|
if (p.HasValue)
|
||||||
{
|
{
|
||||||
visible = visible ||
|
visible = visible ||
|
||||||
p.X >= 0d && p.X <= ParentMap.RenderSize.Width &&
|
p.Value.X >= 0d && p.Value.X <= ParentMap.RenderSize.Width &&
|
||||||
p.Y >= 0d && p.Y <= ParentMap.RenderSize.Height;
|
p.Value.Y >= 0d && p.Value.Y <= ParentMap.RenderSize.Height;
|
||||||
|
|
||||||
points.Add(p);
|
points.Add(p.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -305,12 +312,16 @@ namespace MapControl
|
||||||
var northPole = ParentMap.LocationToView(new Location(90d, 0d));
|
var northPole = ParentMap.LocationToView(new Location(90d, 0d));
|
||||||
var southPole = ParentMap.LocationToView(new Location(-90d, 0d));
|
var southPole = ParentMap.LocationToView(new Location(-90d, 0d));
|
||||||
|
|
||||||
if (northPole.X >= 0d && northPole.Y >= 0d && northPole.X <= width && northPole.Y <= height)
|
if (northPole.HasValue &&
|
||||||
|
northPole.Value.X >= 0d && northPole.Value.X <= width &&
|
||||||
|
northPole.Value.Y >= 0d && northPole.Value.Y <= height)
|
||||||
{
|
{
|
||||||
maxLatitude = 90d;
|
maxLatitude = 90d;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (southPole.X >= 0d && southPole.Y >= 0d && southPole.X <= width && southPole.Y <= height)
|
if (southPole.HasValue &&
|
||||||
|
southPole.Value.X >= 0d && southPole.Value.X <= width &&
|
||||||
|
southPole.Value.Y >= 0d && southPole.Value.Y <= height)
|
||||||
{
|
{
|
||||||
minLatitude = -90d;
|
minLatitude = -90d;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,14 @@ using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
#if WINUI
|
#if WINUI
|
||||||
|
using Windows.Foundation;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Microsoft.UI.Xaml.Media.Animation;
|
using Microsoft.UI.Xaml.Media.Animation;
|
||||||
using DispatcherTimer = Microsoft.UI.Dispatching.DispatcherQueueTimer;
|
using DispatcherTimer = Microsoft.UI.Dispatching.DispatcherQueueTimer;
|
||||||
#elif UWP
|
#elif UWP
|
||||||
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
|
|
|
||||||
|
|
@ -203,12 +203,13 @@ namespace MapControl
|
||||||
return finalSize;
|
return finalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Point GetViewPosition(Location location)
|
protected Point? GetViewPosition(Location location)
|
||||||
{
|
{
|
||||||
var position = parentMap.LocationToView(location);
|
var position = parentMap.LocationToView(location);
|
||||||
|
|
||||||
if (parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical &&
|
if (parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical &&
|
||||||
IsOutsideViewport(position))
|
position.HasValue &&
|
||||||
|
IsOutsideViewport(position.Value))
|
||||||
{
|
{
|
||||||
location = new Location(location.Latitude, parentMap.ConstrainedLongitude(location.Longitude));
|
location = new Location(location.Latitude, parentMap.ConstrainedLongitude(location.Longitude));
|
||||||
position = parentMap.LocationToView(location);
|
position = parentMap.LocationToView(location);
|
||||||
|
|
@ -219,10 +220,10 @@ namespace MapControl
|
||||||
|
|
||||||
protected ViewRect GetViewRect(BoundingBox boundingBox)
|
protected ViewRect GetViewRect(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
return GetViewRect(parentMap.MapProjection.BoundingBoxToRect(boundingBox));
|
return GetViewRect(parentMap.MapProjection.BoundingBoxToMapRect(boundingBox));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ViewRect GetViewRect(Rect rect)
|
protected ViewRect GetViewRect(MapRect rect)
|
||||||
{
|
{
|
||||||
var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
||||||
var position = parentMap.ViewTransform.MapToView(center);
|
var position = parentMap.ViewTransform.MapToView(center);
|
||||||
|
|
@ -235,7 +236,12 @@ namespace MapControl
|
||||||
if (location != null)
|
if (location != null)
|
||||||
{
|
{
|
||||||
location.Longitude = parentMap.ConstrainedLongitude(location.Longitude);
|
location.Longitude = parentMap.ConstrainedLongitude(location.Longitude);
|
||||||
position = parentMap.LocationToView(location);
|
var pos = parentMap.LocationToView(location);
|
||||||
|
|
||||||
|
if (pos.HasValue)
|
||||||
|
{
|
||||||
|
position = pos.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,10 +95,11 @@ namespace MapControl
|
||||||
|
|
||||||
if (location != null && parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical)
|
if (location != null && parentMap.MapProjection.Type <= MapProjectionType.NormalCylindrical)
|
||||||
{
|
{
|
||||||
var pos = parentMap.LocationToView(location);
|
var point = parentMap.LocationToView(location);
|
||||||
|
|
||||||
if (pos.X < 0d || pos.X > parentMap.RenderSize.Width ||
|
if (point.HasValue &&
|
||||||
pos.Y < 0d || pos.Y > parentMap.RenderSize.Height)
|
(point.Value.X < 0d || point.Value.X > parentMap.RenderSize.Width ||
|
||||||
|
point.Value.Y < 0d || point.Value.Y > parentMap.RenderSize.Height))
|
||||||
{
|
{
|
||||||
longitudeOffset = parentMap.ConstrainedLongitude(location.Longitude) - location.Longitude;
|
longitudeOffset = parentMap.ConstrainedLongitude(location.Longitude) - location.Longitude;
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +108,7 @@ namespace MapControl
|
||||||
return longitudeOffset;
|
return longitudeOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Point LocationToMap(Location location, double longitudeOffset)
|
protected Point? LocationToMap(Location location, double longitudeOffset)
|
||||||
{
|
{
|
||||||
if (longitudeOffset != 0d)
|
if (longitudeOffset != 0d)
|
||||||
{
|
{
|
||||||
|
|
@ -116,21 +117,24 @@ namespace MapControl
|
||||||
|
|
||||||
var point = parentMap.MapProjection.LocationToMap(location);
|
var point = parentMap.MapProjection.LocationToMap(location);
|
||||||
|
|
||||||
if (point.Y == double.PositiveInfinity)
|
if (point.HasValue && double.IsInfinity(point.Value.Y))
|
||||||
{
|
{
|
||||||
point.Y = 1e9;
|
point = null;
|
||||||
}
|
|
||||||
else if (point.X == double.NegativeInfinity)
|
|
||||||
{
|
|
||||||
point.Y = -1e9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Point LocationToView(Location location, double longitudeOffset)
|
protected Point? LocationToView(Location location, double longitudeOffset)
|
||||||
{
|
{
|
||||||
return parentMap.ViewTransform.MapToView(LocationToMap(location, longitudeOffset));
|
var point = LocationToMap(location, longitudeOffset);
|
||||||
|
|
||||||
|
if (!point.HasValue)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parentMap.ViewTransform.MapToView(point.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
||||||
|
|
@ -49,16 +49,16 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the relative map scale at the specified Location.
|
/// Gets the relative map scale at the specified Location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Vector GetRelativeScale(Location location)
|
public virtual Scale GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
return new Vector(1d, 1d);
|
return new Scale(1d, 1d);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a Location in geographic coordinates to a Point in projected map coordinates.
|
/// Transforms a Location in geographic coordinates to a Point in projected map coordinates.
|
||||||
/// Returns new Point(double.NaN, double.NaN) when the Location can not be transformed.
|
/// Returns null when the Location can not be transformed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract Point LocationToMap(Location location);
|
public abstract Point? LocationToMap(Location location);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a Point in projected map coordinates to a Location in geographic coordinates.
|
/// Transforms a Point in projected map coordinates to a Location in geographic coordinates.
|
||||||
|
|
@ -67,20 +67,22 @@ namespace MapControl
|
||||||
public abstract Location MapToLocation(Point point);
|
public abstract Location MapToLocation(Point point);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a BoundingBox in geographic coordinates to a Rect in projected map coordinates.
|
/// Transforms a BoundingBox in geographic coordinates to a MapRect in projected map coordinates.
|
||||||
|
/// Returns null when the BoundingBox can not be transformed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Rect BoundingBoxToRect(BoundingBox boundingBox)
|
public virtual MapRect BoundingBoxToMapRect(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
return new Rect(
|
var p1 = LocationToMap(new Location(boundingBox.South, boundingBox.West));
|
||||||
LocationToMap(new Location(boundingBox.South, boundingBox.West)),
|
var p2 = LocationToMap(new Location(boundingBox.North, boundingBox.East));
|
||||||
LocationToMap(new Location(boundingBox.North, boundingBox.East)));
|
|
||||||
|
return p1.HasValue && p2.HasValue ? new MapRect(p1.Value, p2.Value) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms a Rect in projected map coordinates to a BoundingBox in geographic coordinates.
|
/// Transforms a MapRect in projected map coordinates to a BoundingBox in geographic coordinates.
|
||||||
/// Returns null when the Rect can not be transformed.
|
/// Returns null when the MapRect can not be transformed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual BoundingBox RectToBoundingBox(Rect rect)
|
public virtual BoundingBox MapRectToBoundingBox(MapRect rect)
|
||||||
{
|
{
|
||||||
var sw = MapToLocation(new Point(rect.X, rect.Y));
|
var sw = MapToLocation(new Point(rect.X, rect.Y));
|
||||||
var ne = MapToLocation(new Point(rect.X + rect.Width, rect.Y + rect.Height));
|
var ne = MapToLocation(new Point(rect.X + rect.Width, rect.Y + rect.Height));
|
||||||
|
|
@ -103,30 +105,10 @@ namespace MapControl
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the BBOX parameter value for a WMS GetMap request.
|
/// Gets the BBOX parameter value for a WMS GetMap request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string GetBboxValue(Rect rect)
|
public virtual string GetBboxValue(MapRect rect)
|
||||||
{
|
{
|
||||||
return string.Format(CultureInfo.InvariantCulture,
|
return string.Format(CultureInfo.InvariantCulture,
|
||||||
"{0},{1},{2},{3}", rect.X, rect.Y, (rect.X + rect.Width), (rect.Y + rect.Height));
|
"{0},{1},{2},{3}", rect.X, rect.Y, (rect.X + rect.Width), (rect.Y + rect.Height));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the X and Y values of a Point are neither NaN nor Infinity.
|
|
||||||
/// </summary>
|
|
||||||
public static bool IsValid(Point point)
|
|
||||||
{
|
|
||||||
return !double.IsNaN(point.X) && !double.IsInfinity(point.X) &&
|
|
||||||
!double.IsNaN(point.Y) && !double.IsInfinity(point.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the X, Y, Width and Height values of a Rect are neither NaN nor Infinity.
|
|
||||||
/// </summary>
|
|
||||||
public static bool IsValid(Rect rect)
|
|
||||||
{
|
|
||||||
return !double.IsNaN(rect.X) && !double.IsInfinity(rect.X) &&
|
|
||||||
!double.IsNaN(rect.Y) && !double.IsInfinity(rect.Y) &&
|
|
||||||
!double.IsNaN(rect.Width) && !double.IsInfinity(rect.Width) &&
|
|
||||||
!double.IsNaN(rect.Height) && !double.IsInfinity(rect.Height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
45
MapControl/Shared/MapRect.cs
Normal file
45
MapControl/Shared/MapRect.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
|
// © 2022 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
using System;
|
||||||
|
#if !WINUI && !UWP
|
||||||
|
using System.Windows;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Map rectangle with double floating point precision, unlike Windows.Foundation.Rect does.
|
||||||
|
/// Used by MapProjection to convert geodetic bounding boxes to/from projected map coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public class MapRect
|
||||||
|
{
|
||||||
|
public MapRect(double x, double y, double width, double height)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapRect(Point p1, Point p2)
|
||||||
|
{
|
||||||
|
X = Math.Min(p1.X, p2.X);
|
||||||
|
Y = Math.Min(p1.Y, p2.Y);
|
||||||
|
Width = Math.Max(p1.X, p2.X) - X;
|
||||||
|
Height = Math.Max(p1.Y, p2.Y) - Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double X { get; }
|
||||||
|
public double Y { get; }
|
||||||
|
public double Width { get; }
|
||||||
|
public double Height { get; }
|
||||||
|
|
||||||
|
public bool Contains(Point p)
|
||||||
|
{
|
||||||
|
return p.X >= X && p.X <= X + Width
|
||||||
|
&& p.Y >= Y && p.Y <= Y + Height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ namespace MapControl
|
||||||
CrsId = DefaultCrsId;
|
CrsId = DefaultCrsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
{
|
{
|
||||||
if (location.Equals(Center))
|
if (location.Equals(Center))
|
||||||
{
|
{
|
||||||
|
|
@ -35,7 +35,7 @@ namespace MapControl
|
||||||
|
|
||||||
if (Math.Abs(lat - lat0) > Math.PI / 2d || Math.Abs(dLon) > Math.PI / 2d)
|
if (Math.Abs(lat - lat0) > Math.PI / 2d || Math.Abs(dLon) > Math.PI / 2d)
|
||||||
{
|
{
|
||||||
return new Point(double.NaN, double.NaN);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Point(
|
return new Point(
|
||||||
|
|
|
||||||
23
MapControl/Shared/Scale.cs
Normal file
23
MapControl/Shared/Scale.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||||
|
// © 2022 Clemens Fischer
|
||||||
|
// Licensed under the Microsoft Public License (Ms-PL)
|
||||||
|
|
||||||
|
namespace MapControl
|
||||||
|
{
|
||||||
|
public struct Scale
|
||||||
|
{
|
||||||
|
public Scale(double x, double y)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double X { get; set; }
|
||||||
|
public double Y { get; set; }
|
||||||
|
|
||||||
|
public static Scale operator *(double f, Scale v)
|
||||||
|
{
|
||||||
|
return new Scale(f * v.X, f * v.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ namespace MapControl
|
||||||
CrsId = DefaultCrsId;
|
CrsId = DefaultCrsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
{
|
{
|
||||||
if (location.Equals(Center))
|
if (location.Equals(Center))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,14 @@ namespace MapControl
|
||||||
CrsId = DefaultCrsId;
|
CrsId = DefaultCrsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Vector GetRelativeScale(Location location)
|
public override Scale GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
var k = 1d / Math.Cos(location.Latitude * Math.PI / 180d); // p.44 (7-3)
|
var k = 1d / Math.Cos(location.Latitude * Math.PI / 180d); // p.44 (7-3)
|
||||||
|
|
||||||
return new Vector(k, k);
|
return new Scale(k, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
{
|
{
|
||||||
return new Point(
|
return new Point(
|
||||||
Wgs84MeterPerDegree * location.Longitude,
|
Wgs84MeterPerDegree * location.Longitude,
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,11 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
#if WINUI
|
#if WINUI
|
||||||
|
using Windows.Foundation;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
#elif UWP
|
#elif UWP
|
||||||
|
using Windows.Foundation;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
#else
|
#else
|
||||||
|
|
@ -237,7 +239,7 @@ namespace MapControl
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual string GetMapRequestUri(BoundingBox boundingBox)
|
protected virtual string GetMapRequestUri(BoundingBox boundingBox)
|
||||||
{
|
{
|
||||||
var mapRect = ParentMap.MapProjection.BoundingBoxToRect(boundingBox);
|
var mapRect = ParentMap.MapProjection.BoundingBoxToMapRect(boundingBox);
|
||||||
var viewScale = ParentMap.ViewTransform.Scale;
|
var viewScale = ParentMap.ViewTransform.Scale;
|
||||||
|
|
||||||
return GetRequestUri(new Dictionary<string, string>
|
return GetRequestUri(new Dictionary<string, string>
|
||||||
|
|
@ -262,7 +264,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
var viewSize = ParentMap.RenderSize;
|
var viewSize = ParentMap.RenderSize;
|
||||||
var boundingBox = ParentMap.ViewRectToBoundingBox(new Rect(0d, 0d, viewSize.Width, viewSize.Height));
|
var boundingBox = ParentMap.ViewRectToBoundingBox(new Rect(0d, 0d, viewSize.Width, viewSize.Height));
|
||||||
var mapRect = ParentMap.MapProjection.BoundingBoxToRect(boundingBox);
|
var mapRect = ParentMap.MapProjection.BoundingBoxToMapRect(boundingBox);
|
||||||
var viewRect = GetViewRect(mapRect);
|
var viewRect = GetViewRect(mapRect);
|
||||||
|
|
||||||
var transform = new Matrix(1, 0, 0, 1, -viewSize.Width / 2, -viewSize.Height / 2);
|
var transform = new Matrix(1, 0, 0, 1, -viewSize.Width / 2, -viewSize.Height / 2);
|
||||||
|
|
@ -296,7 +298,7 @@ namespace MapControl
|
||||||
return ParentMap.MapProjection.GetCrsValue();
|
return ParentMap.MapProjection.GetCrsValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string GetBboxValue(Rect mapRect)
|
protected virtual string GetBboxValue(MapRect mapRect)
|
||||||
{
|
{
|
||||||
return ParentMap.MapProjection.GetBboxValue(mapRect);
|
return ParentMap.MapProjection.GetBboxValue(mapRect);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,16 @@ namespace MapControl
|
||||||
CrsId = DefaultCrsId;
|
CrsId = DefaultCrsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Vector GetRelativeScale(Location location)
|
public override Scale GetRelativeScale(Location location)
|
||||||
{
|
{
|
||||||
var lat = location.Latitude * Math.PI / 180d;
|
var lat = location.Latitude * Math.PI / 180d;
|
||||||
var eSinLat = Wgs84Eccentricity * Math.Sin(lat);
|
var eSinLat = Wgs84Eccentricity * Math.Sin(lat);
|
||||||
var k = Math.Sqrt(1d - eSinLat * eSinLat) / Math.Cos(lat); // p.44 (7-8)
|
var k = Math.Sqrt(1d - eSinLat * eSinLat) / Math.Cos(lat); // p.44 (7-8)
|
||||||
|
|
||||||
return new Vector(k, k);
|
return new Scale(k, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Point LocationToMap(Location location)
|
public override Point? LocationToMap(Location location)
|
||||||
{
|
{
|
||||||
return new Point(
|
return new Point(
|
||||||
Wgs84MeterPerDegree * location.Longitude,
|
Wgs84MeterPerDegree * location.Longitude,
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,9 @@
|
||||||
<Compile Include="..\Shared\MapProjectionFactory.cs">
|
<Compile Include="..\Shared\MapProjectionFactory.cs">
|
||||||
<Link>MapProjectionFactory.cs</Link>
|
<Link>MapProjectionFactory.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\Shared\MapRect.cs">
|
||||||
|
<Link>MapRect.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\Shared\MapScale.cs">
|
<Compile Include="..\Shared\MapScale.cs">
|
||||||
<Link>MapScale.cs</Link>
|
<Link>MapScale.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
@ -143,6 +146,9 @@
|
||||||
<Compile Include="..\Shared\PushpinBorder.cs">
|
<Compile Include="..\Shared\PushpinBorder.cs">
|
||||||
<Link>PushpinBorder.cs</Link>
|
<Link>PushpinBorder.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\Shared\Scale.cs">
|
||||||
|
<Link>Scale.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\Shared\StereographicProjection.cs">
|
<Compile Include="..\Shared\StereographicProjection.cs">
|
||||||
<Link>StereographicProjection.cs</Link>
|
<Link>StereographicProjection.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
@ -242,15 +248,9 @@
|
||||||
<Compile Include="..\WinUI\PushpinBorder.WinUI.cs">
|
<Compile Include="..\WinUI\PushpinBorder.WinUI.cs">
|
||||||
<Link>PushpinBorder.WinUI.cs</Link>
|
<Link>PushpinBorder.WinUI.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\WinUI\Rect.WinUI.cs">
|
|
||||||
<Link>Rect.WinUI.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\WinUI\Tile.WinUI.cs">
|
<Compile Include="..\WinUI\Tile.WinUI.cs">
|
||||||
<Link>Tile.WinUI.cs</Link>
|
<Link>Tile.WinUI.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="..\WinUI\Vector.WinUI.cs">
|
|
||||||
<Link>Vector.WinUI.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\WPF\Timer.WPF.cs">
|
<Compile Include="..\WPF\Timer.WPF.cs">
|
||||||
<Link>Timer.WPF.cs</Link>
|
<Link>Timer.WPF.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ namespace MapControl
|
||||||
private void OnManipulationDelta(object sender, ManipulationDeltaEventArgs e)
|
private void OnManipulationDelta(object sender, ManipulationDeltaEventArgs e)
|
||||||
{
|
{
|
||||||
TransformMap(e.ManipulationOrigin,
|
TransformMap(e.ManipulationOrigin,
|
||||||
e.DeltaManipulation.Translation,
|
(Point)e.DeltaManipulation.Translation,
|
||||||
e.DeltaManipulation.Rotation,
|
e.DeltaManipulation.Rotation,
|
||||||
e.DeltaManipulation.Scale.LengthSquared / 2d);
|
e.DeltaManipulation.Scale.LengthSquared / 2d);
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +95,7 @@ namespace MapControl
|
||||||
var translation = position - mousePosition.Value;
|
var translation = position - mousePosition.Value;
|
||||||
mousePosition = position;
|
mousePosition = position;
|
||||||
|
|
||||||
TranslateMap(translation);
|
TranslateMap((Point)translation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
IEnumerable<Location> Locations { get; }
|
IEnumerable<Location> Locations { get; }
|
||||||
|
|
||||||
Drawing GetDrawing(IList<Point> positions, double scale, double rotation);
|
Drawing GetDrawing(IList<Point> points, double scale, double rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MapItemsImageLayer : MapImageLayer
|
public class MapItemsImageLayer : MapImageLayer
|
||||||
|
|
@ -47,23 +47,27 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
var scale = ParentMap.ViewTransform.Scale;
|
var scale = ParentMap.ViewTransform.Scale;
|
||||||
var rotation = ParentMap.ViewTransform.Rotation;
|
var rotation = ParentMap.ViewTransform.Rotation;
|
||||||
var mapRect = projection.BoundingBoxToRect(boundingBox);
|
var mapRect = projection.BoundingBoxToMapRect(boundingBox);
|
||||||
var drawings = new DrawingGroup();
|
var drawings = new DrawingGroup();
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
var positions = item.Locations.Select(l => projection.LocationToMap(l)).ToList();
|
var points = item.Locations
|
||||||
|
.Select(location => projection.LocationToMap(location))
|
||||||
|
.Where(point => point.HasValue)
|
||||||
|
.Select(point => point.Value)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
if (positions.Any(p => mapRect.Contains(p)))
|
if (points.Any(point => mapRect.Contains(point)))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < positions.Count; i++)
|
for (int i = 0; i < points.Count; i++)
|
||||||
{
|
{
|
||||||
positions[i] = new Point(
|
points[i] = new Point(
|
||||||
scale * (positions[i].X - mapRect.X),
|
scale * (points[i].X - mapRect.X),
|
||||||
scale * (mapRect.Height + mapRect.Y - positions[i].Y));
|
scale * (mapRect.Height + mapRect.Y - points[i].Y));
|
||||||
}
|
}
|
||||||
|
|
||||||
drawings.Children.Add(item.GetDrawing(positions, scale, rotation));
|
drawings.Children.Add(item.GetDrawing(points, scale, rotation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,11 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
if (locations.Count() >= 2)
|
if (locations.Count() >= 2)
|
||||||
{
|
{
|
||||||
var points = locations.Select(location => LocationToView(location, longitudeOffset));
|
var points = locations
|
||||||
|
.Select(location => LocationToView(location, longitudeOffset))
|
||||||
|
.Where(point => point.HasValue)
|
||||||
|
.Select(point => point.Value);
|
||||||
|
|
||||||
var figure = new PathFigure
|
var figure = new PathFigure
|
||||||
{
|
{
|
||||||
StartPoint = points.First(),
|
StartPoint = points.First(),
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Windows.Foundation;
|
||||||
#if WINUI
|
#if WINUI
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
|
|
@ -50,7 +51,10 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
if (locations.Count() >= 2)
|
if (locations.Count() >= 2)
|
||||||
{
|
{
|
||||||
var points = locations.Select(location => LocationToView(location, longitudeOffset));
|
var points = locations
|
||||||
|
.Select(location => LocationToView(location, longitudeOffset))
|
||||||
|
.Where(point => point.HasValue)
|
||||||
|
.Select(point => point.Value);
|
||||||
|
|
||||||
if (closed)
|
if (closed)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -28,31 +28,6 @@ namespace MapControl
|
||||||
return new Point(p.X, p.Y);
|
return new Point(p.X, p.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static explicit operator Point(Vector v)
|
|
||||||
{
|
|
||||||
return new Point(v.X, v.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Point operator -(Point p)
|
|
||||||
{
|
|
||||||
return new Point(-p.X, -p.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Point operator +(Point p, Vector v)
|
|
||||||
{
|
|
||||||
return new Point(p.X + v.X, p.Y + v.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Point operator -(Point p, Vector v)
|
|
||||||
{
|
|
||||||
return new Point(p.X - v.X, p.Y - v.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector operator -(Point p1, Point p2)
|
|
||||||
{
|
|
||||||
return new Vector(p1.X - p2.X, p1.Y - p2.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(Point p1, Point p2)
|
public static bool operator ==(Point p1, Point p2)
|
||||||
{
|
{
|
||||||
return p1.X == p2.X && p1.Y == p2.Y;
|
return p1.X == p2.X && p1.Y == p2.Y;
|
||||||
|
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
|
||||||
// © 2022 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Replaces Windows.Foundation.Rect for double floating point precision.
|
|
||||||
/// </summary>
|
|
||||||
public struct Rect
|
|
||||||
{
|
|
||||||
public Rect(double x, double y, double width, double height)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
Width = width;
|
|
||||||
Height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Rect(Point p, Windows.Foundation.Size s)
|
|
||||||
{
|
|
||||||
X = p.X;
|
|
||||||
Y = p.Y;
|
|
||||||
Width = s.Width;
|
|
||||||
Height = s.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Rect(Point p1, Point p2)
|
|
||||||
{
|
|
||||||
X = Math.Min(p1.X, p2.X);
|
|
||||||
Y = Math.Min(p1.Y, p2.Y);
|
|
||||||
Width = Math.Max(p1.X, p2.X) - X;
|
|
||||||
Height = Math.Max(p1.Y, p2.Y) - Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double X { get; set; }
|
|
||||||
public double Y { get; set; }
|
|
||||||
public double Width { get; set; }
|
|
||||||
public double Height { get; set; }
|
|
||||||
|
|
||||||
public bool Contains(Point p)
|
|
||||||
{
|
|
||||||
return p.X >= X && p.X <= X + Width
|
|
||||||
&& p.Y >= Y && p.Y <= Y + Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator Windows.Foundation.Rect(Rect r)
|
|
||||||
{
|
|
||||||
return new Windows.Foundation.Rect(r.X, r.Y, r.Width, r.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator Rect(Windows.Foundation.Rect r)
|
|
||||||
{
|
|
||||||
return new Rect(r.X, r.Y, r.Width, r.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(Rect r1, Rect r2)
|
|
||||||
{
|
|
||||||
return r1.X == r2.X && r1.Y == r2.Y
|
|
||||||
&& r1.Width == r2.Width && r1.Height == r2.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(Rect r1, Rect r2)
|
|
||||||
{
|
|
||||||
return !(r1 == r2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return obj is Rect r && this == r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return X.GetHashCode() ^ Y.GetHashCode() ^ Width.GetHashCode() ^ Height.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
|
||||||
// © 2022 Clemens Fischer
|
|
||||||
// Licensed under the Microsoft Public License (Ms-PL)
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public struct Vector
|
|
||||||
{
|
|
||||||
public Vector(double x, double y)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double X { get; set; }
|
|
||||||
public double Y { get; set; }
|
|
||||||
|
|
||||||
public static implicit operator Windows.Foundation.Point(Vector v)
|
|
||||||
{
|
|
||||||
return new Windows.Foundation.Point(v.X, v.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator Vector(Windows.Foundation.Point v)
|
|
||||||
{
|
|
||||||
return new Vector(v.X, v.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static explicit operator Vector(Point p)
|
|
||||||
{
|
|
||||||
return new Vector(p.X, p.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector operator -(Vector v)
|
|
||||||
{
|
|
||||||
return new Vector(-v.X, -v.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Point operator +(Vector v, Point p)
|
|
||||||
{
|
|
||||||
return new Point(v.X + p.X, v.Y + p.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector operator +(Vector v1, Vector v2)
|
|
||||||
{
|
|
||||||
return new Vector(v1.X + v2.X, v1.Y + v2.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector operator -(Vector v1, Vector v2)
|
|
||||||
{
|
|
||||||
return new Vector(v1.X - v2.X, v1.Y - v2.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector operator *(double f, Vector v)
|
|
||||||
{
|
|
||||||
return new Vector(f * v.X, f * v.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector operator *(Vector v, double f)
|
|
||||||
{
|
|
||||||
return new Vector(f * v.X, f * v.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(Vector v1, Vector v2)
|
|
||||||
{
|
|
||||||
return v1.X == v2.X && v1.Y == v2.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(Vector v1, Vector v2)
|
|
||||||
{
|
|
||||||
return !(v1 == v2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return obj is Vector v && this == v;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return X.GetHashCode() ^ Y.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue