Skip to content

Commit

Permalink
Improved WPF tile rendering
Browse files Browse the repository at this point in the history
Improved rendering of tiles to hide lines between tiles.
Added IViewport.WorldToScreenUnrotated() which goes along with
IViewport.WorldToScreen(). The first converts world coordinates to
screen coordinates assuming the screen isn't rotated while the later
does a full conversion taking rotation into account. The
WorldToScreenUnrotated() is useful for placing WPF elements in cases
where a transform will handle the rotation portion of the positioning.
  • Loading branch information
scottdewald committed Sep 13, 2014
1 parent 8320c07 commit e7be589
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 22 deletions.
14 changes: 7 additions & 7 deletions Mapsui.Rendering.Xaml/GeometryRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -429,26 +429,26 @@ public static void PositionPoint(UIElement renderedGeometry, Point point, IStyle

public static void PositionRaster(UIElement renderedGeometry, BoundingBox boundingBox, IViewport viewport)
{
PositionElement(renderedGeometry, boundingBox, viewport);
UpdateRenderTransform(renderedGeometry, viewport);

// position the rect relative the tile's center since it is translated above
// since the render transform will take care of the rotation, calculate top-left using unrotated viewport
var topLeft = viewport.WorldToScreenUnrotated(boundingBox.TopLeft);
var rectWidthPixels = boundingBox.Width / viewport.Resolution;
var rectHeightPixels = boundingBox.Height / viewport.Resolution;
((XamlMedia.RectangleGeometry)((XamlShapes.Path)renderedGeometry).Data).Rect =
RoundToPixel(new Rect(0, 0, rectWidthPixels, rectHeightPixels));
RoundToPixel(new Rect(topLeft.X, topLeft.Y, rectWidthPixels, rectHeightPixels));
}

public static void PositionElement(UIElement renderedGeometry, BoundingBox boundingBox, IViewport viewport)
private static void UpdateRenderTransform(UIElement renderedGeometry, IViewport viewport)
{
var matrix = new XamlMedia.Matrix();
var boundingBoxTopLeftScreen = viewport.WorldToScreen(boundingBox.TopLeft);

if (viewport.IsRotated)
{
MatrixHelper.RotateAt(ref matrix, viewport.Rotation);
var center = viewport.WorldToScreen(viewport.Center);
MatrixHelper.RotateAt(ref matrix, viewport.Rotation, center.X, center.Y);
}

MatrixHelper.Translate(ref matrix, boundingBoxTopLeftScreen.X, boundingBoxTopLeftScreen.Y);
renderedGeometry.RenderTransform = new XamlMedia.MatrixTransform { Matrix = matrix };
}

Expand Down
18 changes: 8 additions & 10 deletions Mapsui.Rendering.Xaml/StackedLabelLayerRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Mapsui.Providers;
using Mapsui.Styles;
using Mapsui.Styles.Thematics;
using Point = Mapsui.Geometries.Point;
#if !NETFX_CORE
using System.Windows.Controls;
using System.Windows.Media;
Expand Down Expand Up @@ -95,22 +96,19 @@ private static UIElement RenderBox(BoundingBox box, IViewport viewport)
const int symbolSize = 32; // todo: determine margin by symbol size
const int boxMargin = symbolSize / 2;

var rectangle = new Rectangle
var path = new Path
{
Width = box.Width / viewport.Resolution + symbolSize,
Height = box.Height / viewport.Resolution + symbolSize
Stroke = new SolidColorBrush(Colors.White),
StrokeThickness = 2,
Data = new RectangleGeometry()
};

// offset the bounding box left and up by the box margin
var offset = boxMargin * viewport.Resolution;
var offsetBox = new BoundingBox(box.Min.X - offset, box.Min.Y + offset, box.Max.X - offset, box.Max.Y + offset);
var offsetBox = box.Grow(boxMargin * viewport.Resolution);

GeometryRenderer.PositionElement(rectangle, offsetBox, viewport);
GeometryRenderer.PositionRaster(path, offsetBox, viewport);

rectangle.Stroke = new SolidColorBrush(Colors.White);
rectangle.StrokeThickness = 2;

return rectangle;
return path;
}

private static void ClusterFeatures(
Expand Down
2 changes: 2 additions & 0 deletions Mapsui/IViewport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ namespace Mapsui
public interface IViewport
{
Point WorldToScreen(Point point);
Point WorldToScreenUnrotated(Point point);
Point ScreenToWorld(Point point);
Point WorldToScreen(double x, double y);
Point WorldToScreenUnrotated(double x, double y);
Point ScreenToWorld(double x, double y);
void Transform(double screenX, double screenY, double previousScreenX, double previousScreenY,
double deltaScale = 1);
Expand Down
10 changes: 10 additions & 0 deletions Mapsui/NotifyingViewport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,21 @@ public Point WorldToScreen(double x, double y)
return _viewport.WorldToScreen(x, y);
}

public Point WorldToScreenUnrotated(double x, double y)
{
return _viewport.WorldToScreenUnrotated(x, y);
}

public Point WorldToScreen(Point point)
{
return _viewport.WorldToScreen(point);
}

public Point WorldToScreenUnrotated(Point point)
{
return _viewport.WorldToScreenUnrotated(point);
}

public void Transform(double screenX, double screenY, double previousScreenX, double previousScreenY, double deltaScale = 1)
{
_viewport.Transform(screenX, screenY, previousScreenX, previousScreenY, deltaScale);
Expand Down
23 changes: 18 additions & 5 deletions Mapsui/Viewport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,27 +137,40 @@ public Point WorldToScreen(Point worldPosition)
return WorldToScreen(worldPosition.X, worldPosition.Y);
}

public Point WorldToScreenUnrotated(Point worldPosition)
{
return WorldToScreenUnrotated(worldPosition.X, worldPosition.Y);
}

public Point ScreenToWorld(Point screenPosition)
{
return ScreenToWorld(screenPosition.X, screenPosition.Y);
}

public Point WorldToScreen(double worldX, double worldY)
{
var screenCenterX = Width / 2.0;
var screenCenterY = Height / 2.0;
var screenX = (worldX - Center.X) / _resolution + screenCenterX;
var screenY = (Center.Y - worldY) / _resolution + screenCenterY;
var p = new Point(screenX, screenY);
var p = WorldToScreenUnrotated(worldX, worldY);

if (IsRotated)
{
var screenCenterX = Width / 2.0;
var screenCenterY = Height / 2.0;
p = p.Rotate(-_rotation, screenCenterX, screenCenterY);
}

return p;
}

public Point WorldToScreenUnrotated(double worldX, double worldY)
{
var screenCenterX = Width / 2.0;
var screenCenterY = Height / 2.0;
var screenX = (worldX - Center.X) / _resolution + screenCenterX;
var screenY = (Center.Y - worldY) / _resolution + screenCenterY;

return new Point(screenX, screenY);
}

public Point ScreenToWorld(double screenX, double screenY)
{
var screenCenterX = Width / 2.0;
Expand Down

0 comments on commit e7be589

Please sign in to comment.