// 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]; } } }