mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-04-06 06:55:04 +00:00
General map graticule for WPF
This commit is contained in:
parent
c998f19fe5
commit
a07948be02
11 changed files with 414 additions and 122 deletions
|
|
@ -31,7 +31,7 @@ namespace MapControl
|
|||
var width = rect.Width / Wgs84MeterPerDegree;
|
||||
var height = rect.Height / Wgs84MeterPerDegree;
|
||||
|
||||
return new CenteredBoundingBox(center, width, height);
|
||||
return center != null ? new CenteredBoundingBox(center, width, height) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ namespace MapControl
|
|||
public void SetTransformCenter(Point center)
|
||||
{
|
||||
transformCenter = ViewToLocation(center);
|
||||
viewCenter = center;
|
||||
viewCenter = transformCenter != null ? center : new Point(RenderSize.Width / 2d, RenderSize.Height / 2d);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -304,7 +304,11 @@ namespace MapControl
|
|||
|
||||
if (translation.X != 0d || translation.Y != 0d)
|
||||
{
|
||||
Center = ViewToLocation(viewCenter - translation);
|
||||
var center = ViewToLocation(viewCenter - translation);
|
||||
if (center != null)
|
||||
{
|
||||
Center = center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -317,8 +321,8 @@ namespace MapControl
|
|||
{
|
||||
if (rotation != 0d || scale != 1d)
|
||||
{
|
||||
transformCenter = ViewToLocation(center);
|
||||
viewCenter = center + translation;
|
||||
SetTransformCenter(center);
|
||||
viewCenter += translation;
|
||||
|
||||
if (rotation != 0d)
|
||||
{
|
||||
|
|
@ -367,11 +371,16 @@ namespace MapControl
|
|||
{
|
||||
var rect = MapProjection.BoundingBoxToRect(boundingBox);
|
||||
var center = new Point(rect.X + rect.Width / 2d, rect.Y + rect.Height / 2d);
|
||||
var scale = Math.Min(RenderSize.Width / rect.Width, RenderSize.Height / rect.Height);
|
||||
var targetCenter = MapProjection.MapToLocation(center);
|
||||
|
||||
TargetZoomLevel = ViewTransform.ScaleToZoomLevel(scale);
|
||||
TargetCenter = MapProjection.MapToLocation(center);
|
||||
TargetHeading = 0d;
|
||||
if (targetCenter != null)
|
||||
{
|
||||
var scale = Math.Min(RenderSize.Width / rect.Width, RenderSize.Height / rect.Height);
|
||||
|
||||
TargetZoomLevel = ViewTransform.ScaleToZoomLevel(scale);
|
||||
TargetCenter = targetCenter;
|
||||
TargetHeading = 0d;
|
||||
}
|
||||
}
|
||||
|
||||
internal double ConstrainedLongitude(double longitude)
|
||||
|
|
@ -700,46 +709,58 @@ namespace MapControl
|
|||
private void UpdateTransform(bool resetTransformCenter = false, bool projectionChanged = false)
|
||||
{
|
||||
var viewScale = ViewTransform.ZoomLevelToScale(ZoomLevel);
|
||||
var center = transformCenter ?? Center;
|
||||
var projection = MapProjection;
|
||||
|
||||
projection.Center = ProjectionCenter ?? Center;
|
||||
|
||||
ViewTransform.SetTransform(projection.LocationToMap(center), viewCenter, viewScale, Heading);
|
||||
var mapCenter = projection.LocationToMap(transformCenter ?? Center);
|
||||
|
||||
if (transformCenter != null)
|
||||
if (MapProjection.IsValid(mapCenter))
|
||||
{
|
||||
center = ViewToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
|
||||
center.Longitude = Location.NormalizeLongitude(center.Longitude);
|
||||
ViewTransform.SetTransform(mapCenter, viewCenter, viewScale, Heading);
|
||||
|
||||
if (center.Latitude < -projection.MaxLatitude || center.Latitude > projection.MaxLatitude)
|
||||
if (transformCenter != null)
|
||||
{
|
||||
center.Latitude = Math.Min(Math.Max(center.Latitude, -projection.MaxLatitude), projection.MaxLatitude);
|
||||
resetTransformCenter = true;
|
||||
var center = ViewToLocation(new Point(RenderSize.Width / 2d, RenderSize.Height / 2d));
|
||||
|
||||
if (center != null)
|
||||
{
|
||||
center.Longitude = Location.NormalizeLongitude(center.Longitude);
|
||||
|
||||
if (center.Latitude < -projection.MaxLatitude || center.Latitude > projection.MaxLatitude)
|
||||
{
|
||||
center.Latitude = Math.Min(Math.Max(center.Latitude, -projection.MaxLatitude), projection.MaxLatitude);
|
||||
resetTransformCenter = true;
|
||||
}
|
||||
|
||||
SetValueInternal(CenterProperty, center);
|
||||
|
||||
if (centerAnimation == null)
|
||||
{
|
||||
SetValueInternal(TargetCenterProperty, center);
|
||||
}
|
||||
|
||||
if (resetTransformCenter)
|
||||
{
|
||||
ResetTransformCenter();
|
||||
|
||||
projection.Center = ProjectionCenter ?? center;
|
||||
mapCenter = projection.LocationToMap(center);
|
||||
|
||||
if (MapProjection.IsValid(mapCenter))
|
||||
{
|
||||
ViewTransform.SetTransform(mapCenter, viewCenter, viewScale, Heading);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetValueInternal(CenterProperty, center);
|
||||
SetViewScale(ViewTransform.Scale);
|
||||
|
||||
if (centerAnimation == null)
|
||||
{
|
||||
SetValueInternal(TargetCenterProperty, center);
|
||||
}
|
||||
OnViewportChanged(new ViewportChangedEventArgs(projectionChanged, Center.Longitude - centerLongitude));
|
||||
|
||||
if (resetTransformCenter)
|
||||
{
|
||||
ResetTransformCenter();
|
||||
|
||||
projection.Center = ProjectionCenter ?? center;
|
||||
|
||||
ViewTransform.SetTransform(projection.LocationToMap(center), viewCenter, viewScale, Heading);
|
||||
}
|
||||
centerLongitude = Center.Longitude;
|
||||
}
|
||||
|
||||
SetViewScale(ViewTransform.Scale);
|
||||
|
||||
OnViewportChanged(new ViewportChangedEventArgs(projectionChanged, Center.Longitude - centerLongitude));
|
||||
|
||||
centerLongitude = Center.Longitude;
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
||||
|
|
|
|||
|
|
@ -33,15 +33,9 @@ namespace MapControl
|
|||
|
||||
private double GetLineDistance()
|
||||
{
|
||||
var pixelPerDegree = ParentMap.ViewTransform.Scale * MapProjection.Wgs84MeterPerDegree;
|
||||
var minDistance = MinLineDistance / pixelPerDegree;
|
||||
var scale = 1d;
|
||||
|
||||
if (minDistance < 1d)
|
||||
{
|
||||
scale = minDistance < 1d / 60d ? 3600d : 60d;
|
||||
minDistance *= scale;
|
||||
}
|
||||
var minDistance = MinLineDistance / PixelPerLongitudeDegree(ParentMap.Center);
|
||||
var scale = minDistance < 1d / 60d ? 3600d : minDistance < 1d ? 60d : 1d;
|
||||
minDistance *= scale;
|
||||
|
||||
var lineDistances = new double[] { 1d, 2d, 5d, 10d, 15d, 30d, 60d };
|
||||
var i = 0;
|
||||
|
|
@ -51,7 +45,14 @@ namespace MapControl
|
|||
i++;
|
||||
}
|
||||
|
||||
return lineDistances[i] / scale;
|
||||
return Math.Min(lineDistances[i] / scale, 30d);
|
||||
}
|
||||
|
||||
private double PixelPerLongitudeDegree(Location location)
|
||||
{
|
||||
return Math.Max(1d, // a reasonable lower limit
|
||||
ParentMap.GetScale(location).X *
|
||||
Math.Cos(location.Latitude * Math.PI / 180d) * MapProjection.Wgs84MeterPerDegree);
|
||||
}
|
||||
|
||||
private static string GetLabelFormat(double lineDistance)
|
||||
|
|
@ -64,6 +65,8 @@ namespace MapControl
|
|||
{
|
||||
var hemisphere = hemispheres[0];
|
||||
|
||||
value = (value + 540d) % 360d - 180d;
|
||||
|
||||
if (value < -1e-8) // ~1mm
|
||||
{
|
||||
value = -value;
|
||||
|
|
|
|||
|
|
@ -147,9 +147,11 @@ namespace MapControl
|
|||
if (parentMap.MapProjection.IsNormalCylindrical && IsOutsideViewport(position))
|
||||
{
|
||||
var location = parentMap.MapProjection.MapToLocation(center);
|
||||
location.Longitude = parentMap.ConstrainedLongitude(location.Longitude);
|
||||
|
||||
position = parentMap.LocationToView(location);
|
||||
if (location != null)
|
||||
{
|
||||
location.Longitude = parentMap.ConstrainedLongitude(location.Longitude);
|
||||
position = parentMap.LocationToView(location);
|
||||
}
|
||||
}
|
||||
|
||||
var width = rect.Width * parentMap.ViewTransform.Scale;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ namespace MapControl
|
|||
|
||||
/// <summary>
|
||||
/// Transforms a Point in cartesian map coordinates to a Location in geographic coordinates.
|
||||
/// Returns null when the Point can not be transformed.
|
||||
/// </summary>
|
||||
public abstract Location MapToLocation(Point point);
|
||||
|
||||
|
|
@ -79,13 +80,16 @@ namespace MapControl
|
|||
|
||||
/// <summary>
|
||||
/// Transforms a Rect in cartesian map coordinates to a BoundingBox in geographic coordinates.
|
||||
/// Returns null when the Rect can not be transformed.
|
||||
/// </summary>
|
||||
public virtual BoundingBox RectToBoundingBox(Rect rect)
|
||||
{
|
||||
var sw = MapToLocation(new Point(rect.X, rect.Y));
|
||||
var ne = MapToLocation(new Point(rect.X + rect.Width, rect.Y + rect.Height));
|
||||
|
||||
return new BoundingBox(sw.Latitude, sw.Longitude, ne.Latitude, ne.Longitude);
|
||||
return sw != null && ne != null
|
||||
? new BoundingBox(sw.Latitude, sw.Longitude, ne.Latitude, ne.Longitude)
|
||||
: null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -106,5 +110,25 @@ namespace MapControl
|
|||
return string.Format(CultureInfo.InvariantCulture,
|
||||
"{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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ namespace MapControl
|
|||
var lat = location.Latitude * Math.PI / 180d;
|
||||
var dLon = (location.Longitude - Center.Longitude) * Math.PI / 180d;
|
||||
|
||||
if (Math.Abs(lat - lat0) > Math.PI / 2d || Math.Abs(dLon) > Math.PI / 2d)
|
||||
{
|
||||
return new Point(double.NaN, double.NaN);
|
||||
}
|
||||
|
||||
return new Point(
|
||||
Wgs84EquatorialRadius * Math.Cos(lat) * Math.Sin(dLon),
|
||||
Wgs84EquatorialRadius * (Math.Cos(lat0) * Math.Sin(lat) - Math.Sin(lat0) * Math.Cos(lat) * Math.Cos(dLon)));
|
||||
|
|
@ -51,7 +56,7 @@ namespace MapControl
|
|||
|
||||
if (r2 > 1d)
|
||||
{
|
||||
return new Location(double.NaN, double.NaN);
|
||||
return null;
|
||||
}
|
||||
|
||||
var r = Math.Sqrt(r2);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue