// Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
//
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// SharpMap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.Drawing;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries.Utilities;
namespace SharpMap.Utilities
{
///
/// Class for transforming between world and image coordinate
///
public class Transform
{
///
/// Am abbreviated transform from world coordinate system (WCS) to image coordinates
/// for use ONLY when MapTransformRotation == 0
///
/// Coordinate array in WCS
/// Minimum X value of non-rotated viewport in world coordinates
/// Maximum Y value of non-rotated viewport in world coordinates
/// Apparent width of pixel in world units
/// Apparent height of pixel in world units
/// Point array in image coordinates
internal static PointF[] WorldToMap(Coordinate[] coordinates, double worldLeft, double worldTop,
double pixelWidth, double pixelHeight)
{
// ONLY when MapTransFormRotation == 0
var points = new PointF[coordinates.Length];
for (var i = 0; i < coordinates.Length; i++)
{
var coord = coordinates[i];
if (coord.IsEmpty() || double.IsNaN(coord.X) || double.IsNaN(coord.Y))
{
points[i] = PointF.Empty;
}
else
{
double x = (coord.X - worldLeft) / pixelWidth;
double y = (worldTop - coord.Y) / pixelHeight;
points[i] = new PointF((float) x, (float) y);
}
}
return points;
}
///
/// Full affine transformation from world coordinate system (WCS) to image coordinates taking into
/// account Zoom, Pixel Width/Height, and MapTransformRotation.
///
/// Coordinate array in WCS
/// Appropriate affine transformation as defined by
/// Point array in image coordinates
public static PointF[] WorldToMap(Coordinate[] coordinates, AffineTransformation matrix)
{
var points = new PointF[coordinates.Length];
var transformed = new Coordinate();
for (var i = 0; i < coordinates.Length; i++)
{
matrix.Transform(coordinates[i], transformed);
points[i] = new PointF((float)transformed.X, (float)transformed.Y);
}
return points;
}
///
/// Affine transformation defining complete transformation from world coordinate system (WCS) to image coordinates taking into
/// account Zoom, Pixel Width/Height, and MapTransformRotation. Additionally, if = false,
/// the viewport rotation will be reverted at the end of the transformation, to be re-applied by Graphics object when rendering.
///
/// Map center in WCS
/// Width of pixel in world units
/// Height of pixel in world units
/// map rotation in degrees
/// Map Size when rendered
/// True for coordinate calculations, False if Graphics object will apply MapTransform
/// Affine Transformation
public static AffineTransformation WorldToMapMatrix(Coordinate worldCenter,
double pixelWidth, double pixelHeight, float mapTransformRotation, Size imageSize,
bool careAboutTransform)
{
var rad = NetTopologySuite.Utilities.Degrees.ToRadians(mapTransformRotation);
var trans = new AffineTransformation();
trans.Compose(AffineTransformation.TranslationInstance(-worldCenter.X, -worldCenter.Y));
trans.Compose(AffineTransformation.RotationInstance(-rad));
trans.Compose(AffineTransformation.ScaleInstance(1 / pixelWidth, -1 / pixelHeight));
trans.Compose(AffineTransformation.TranslationInstance(imageSize.Width * 0.5, imageSize.Height * 0.5));
if (!careAboutTransform)
{
// if we DON'T care about transform (implies that rotation in image space WILL be performed by graphics
// object once drawing of ALL objects has been completed) then need to revert rotation (ie MapTransform).
trans.Compose(AffineTransformation.RotationInstance(-rad, imageSize.Width * 0.5, imageSize.Height * 0.5));
}
return trans;
}
///
/// Am abbreviated transform from image coordinates to world coordinate system (WCS)
/// for use ONLY when MapTransformRotation == 0
///
/// Point array in image coordinates
/// Map defining current view properties
public static Coordinate[] MapToWorld(PointF[] points, Map map)
{
return MapToWorld(points, map.Center, map.Zoom, map.MapHeight, map.PixelWidth, map.PixelHeight);
}
///
/// Am abbreviated transform from image coordinates to world coordinate system (WCS)
/// for use ONLY when MapTransformRotation == 0
///
/// Point array in image coordinates
/// Map center in WCS
/// current map zoom (width) in world units
/// current map height in world units
/// Apparent width of pixel in world units
/// Apparent height of pixel in world units
internal static Coordinate[] MapToWorld(PointF[] points, Coordinate worldCenter, double mapZoom,
double mapHeight, double pixelWidth, double pixelHeight)
{
var coords = new Coordinate[points.Length];
if (worldCenter.IsEmpty() || double.IsNaN(mapHeight))
for (var i = 0; i < points.Length; i++)
coords[i] = new Coordinate(0, 0);
else
{
var ul = new Coordinate(worldCenter.X - mapZoom * .5,worldCenter.Y + mapHeight * .5);
for (var i = 0; i < points.Length; i++)
coords[i] = new Coordinate(ul.X + points[i].X * pixelWidth,ul.Y - points[i].Y * pixelHeight);
}
return coords;
}
///
/// Transforms from world coordinate system (WCS) to image coordinates
/// NOTE: This method is only applicable when MapTransformRotation = 0.
///
/// Point in WCS
/// Map reference
/// Point in image coordinates
[Obsolete("Use WorldToMap(Coordinate[], Map)")]
public static PointF WorldToMap(Coordinate p, Map map)
{
var left = map.Center.X - map.Zoom * 0.5;
var top = map.Center.Y + map.MapHeight * 0.5;
var points = WorldToMap(new [] {p}, left, top, map.PixelWidth, map.PixelHeight);
return points[0];
}
///
/// Transforms from image coordinates to world coordinate system (WCS).
/// NOTE: This method is only applicable when MapTransformRotation = 0.
///
/// Point in image coordinate system
/// Map reference
/// Point in WCS
[Obsolete("Use MapToWorld(PointF[], Map)")]
public static Coordinate MapToWorld(PointF p, Map map)
{
var coords = MapToWorld(new [] {p}, map);
return coords[0];
}
///
/// Transforms from image coordinates to world coordinate system (WCS).
/// NOTE: This method is only applicable when MapTransformRotation = 0.
///
/// Point in image coordinate system
/// Map reference
/// Point in WCS
[Obsolete("Use MapToWorld(PointF[], MapViewport)")]
public static Coordinate MapToWorld(PointF p, MapViewport map)
{
var coords = MapToWorld(new [] {p}, map.Center, map.Zoom, map.MapHeight, map.PixelWidth, map.PixelHeight);
return coords[0];
}
}
}