// 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.Globalization; namespace GeoAPI.CoordinateSystems { /// /// Parameters for a geographic transformation into WGS84. The Bursa Wolf parameters should be applied /// to geocentric coordinates, where the X axis points towards the Greenwich Prime Meridian, the Y axis /// points East, and the Z axis points North. /// /// /// These parameters can be used to approximate a transformation from the horizontal datum to the /// WGS84 datum using a Bursa Wolf transformation. However, it must be remembered that this transformation /// is only an approximation. For a given horizontal datum, different Bursa Wolf transformations can be /// used to minimize the errors over different regions. /// If the DATUM clause contains a TOWGS84 clause, then this should be its “preferred” transformation, /// which will often be the transformation which gives a broad approximation over the whole area of interest /// (e.g. the area of interest in the containing geographic coordinate system). /// Sometimes, only the first three or six parameters are defined. In this case the remaining /// parameters must be zero. If only three parameters are defined, then they can still be plugged into the /// Bursa Wolf formulas, or you can take a short cut. The Bursa Wolf transformation works on geocentric /// coordinates, so you cannot apply it onto geographic coordinates directly. If there are only three /// parameters then you can use the Molodenski or abridged Molodenski formulas. /// If a datums ToWgs84Parameters parameter values are zero, then the receiving /// application can assume that the writing application believed that the datum is approximately equal to /// WGS84. /// public class Wgs84ConversionInfo : IEquatable { private const double SEC_TO_RAD = 4.84813681109535993589914102357e-6; /// /// Initializes an instance of Wgs84ConversionInfo with default parameters (all values = 0) /// public Wgs84ConversionInfo() : this(0,0,0,0,0,0,0,String.Empty) { } /// /// Initializes an instance of Wgs84ConversionInfo /// /// Bursa Wolf shift in meters. /// Bursa Wolf shift in meters. /// Bursa Wolf shift in meters. /// Bursa Wolf rotation in arc seconds. /// Bursa Wolf rotation in arc seconds. /// Bursa Wolf rotation in arc seconds. /// Bursa Wolf scaling in parts per million. public Wgs84ConversionInfo(double dx, double dy, double dz, double ex, double ey, double ez, double ppm) : this(dx, dy, dz, ex, ey, ez, ppm, String.Empty) { } /// /// Initializes an instance of Wgs84ConversionInfo /// /// Bursa Wolf shift in meters. /// Bursa Wolf shift in meters. /// Bursa Wolf shift in meters. /// Bursa Wolf rotation in arc seconds. /// Bursa Wolf rotation in arc seconds. /// Bursa Wolf rotation in arc seconds. /// Bursa Wolf scaling in parts per million. /// Area of use for this transformation public Wgs84ConversionInfo(double dx, double dy, double dz, double ex, double ey, double ez, double ppm, string areaOfUse) { Dx = dx; Dy = dy; Dz = dz; Ex = ex; Ey = ey; Ez = ez; Ppm = ppm; AreaOfUse = areaOfUse; } /// /// Bursa Wolf shift in meters. /// public double Dx; /// /// Bursa Wolf shift in meters. /// public double Dy; /// /// Bursa Wolf shift in meters. /// public double Dz; /// /// Bursa Wolf rotation in arc seconds. /// public double Ex; /// /// Bursa Wolf rotation in arc seconds. /// public double Ey; /// /// Bursa Wolf rotation in arc seconds. /// public double Ez; /// /// Bursa Wolf scaling in parts per million. /// public double Ppm; /// /// Human readable text describing intended region of transformation. /// public string AreaOfUse; /// /// Affine Bursa-Wolf matrix transformation /// /// /// Transformation of coordinates from one geographic coordinate system into another /// (also colloquially known as a "datum transformation") is usually carried out as an /// implicit concatenation of three transformations: /// [geographical to geocentric >> geocentric to geocentric >> geocentric to geographic /// /// The middle part of the concatenated transformation, from geocentric to geocentric, is usually /// described as a simplified 7-parameter Helmert transformation, expressed in matrix form with 7 /// parameters, in what is known as the "Bursa-Wolf" formula:
/// /// S = 1 + Ppm/1000000 /// [ Xt ] [ S -Ez*S +Ey*S Dx ] [ Xs ] /// [ Yt ] = [ +Ez*S S -Ex*S Dy ] [ Ys ] /// [ Zt ] [ -Ey*S +Ex*S S Dz ] [ Zs ] /// [ 1 ] [ 0 0 0 1 ] [ 1 ] ///
/// The parameters are commonly referred to defining the transformation "from source coordinate system /// to target coordinate system", whereby (XS, YS, ZS) are the coordinates of the point in the source /// geocentric coordinate system and (XT, YT, ZT) are the coordinates of the point in the target /// geocentric coordinate system. But that does not define the parameters uniquely; neither is the /// definition of the parameters implied in the formula, as is often believed. However, the /// following definition, which is consistent with the "Position Vector Transformation" convention, /// is common E&P survey practice: ///
/// (dX, dY, dZ): Translation vector, to be added to the point's position vector in the source /// coordinate system in order to transform from source system to target system; also: the coordinates /// of the origin of source coordinate system in the target coordinate system /// (RX, RY, RZ): Rotations to be applied to the point's vector. The sign convention is such that /// a positive rotation about an axis is defined as a clockwise rotation of the position vector when /// viewed from the origin of the Cartesian coordinate system in the positive direction of that axis; /// e.g. a positive rotation about the Z-axis only from source system to target system will result in a /// larger longitude value for the point in the target system. Although rotation angles may be quoted in /// any angular unit of measure, the formula as given here requires the angles to be provided in radians. /// : The scale correction to be made to the position vector in the source coordinate system in order /// to obtain the correct scale in the target coordinate system. M = (1 + dS*10-6), whereby dS is the scale /// correction expressed in parts per million. /// for an explanation of the Bursa-Wolf transformation ///
/// public double[] GetAffineTransform() { double RS = 1 + Ppm * 0.000001; return new double[7] { RS, Ex * SEC_TO_RAD * RS, Ey * SEC_TO_RAD * RS, Ez * SEC_TO_RAD * RS, Dx, Dy, Dz }; /*return new double[3,4] { { RS, -Ez*SEC_TO_RAD*RS, +Ey*SEC_TO_RAD*RS, Dx} , { Ez*SEC_TO_RAD*RS, RS, -Ex*SEC_TO_RAD*RS, Dy} , { -Ey*SEC_TO_RAD*RS,Ex*SEC_TO_RAD*RS, RS, Dz} };*/ } /// /// Returns the Well Known Text (WKT) for this object. /// /// The WKT format of this object is: TOWGS84[dx, dy, dz, ex, ey, ez, ppm] /// WKT representaion public string WKT { get { return String.Format(CultureInfo.InvariantCulture.NumberFormat, "TOWGS84[{0}, {1}, {2}, {3}, {4}, {5}, {6}]", Dx, Dy, Dz, Ex, Ey, Ez, Ppm); } } /// /// Gets an XML representation of this object /// public string XML { get { return String.Format(CultureInfo.InvariantCulture.NumberFormat, "", Dx, Dy, Dz, Ex, Ey, Ez, Ppm); } } /// /// Returns the Well Known Text (WKT) for this object. /// /// The WKT format of this object is: TOWGS84[dx, dy, dz, ex, ey, ez, ppm] /// WKT representaion public override string ToString() { return WKT; } /// /// Returns true of all 7 parameter values are 0.0 /// /// public bool HasZeroValuesOnly { get { return !(Dx != 0 || Dy != 0 || Dz != 0 || Ex != 0 || Ey != 0 || Ez != 0 || Ppm != 0); } } #region IEquatable Members /// /// Indicates whether the current object is equal to another object of the same type. /// /// /// public override bool Equals(object obj) { return Equals(obj as Wgs84ConversionInfo); } /// /// Returns a hash code for the specified object /// /// A hash code for the specified object public override int GetHashCode() { return Dx.GetHashCode() ^ Dy.GetHashCode() ^ Dz.GetHashCode() ^ Ex.GetHashCode() ^ Ey.GetHashCode() ^ Ez.GetHashCode() ^ Ppm.GetHashCode(); } /// /// Checks whether the values of this instance is equal to the values of another instance. /// Only parameters used for coordinate system are used for comparison. /// Name, abbreviation, authority, alias and remarks are ignored in the comparison. /// /// /// True if equal public bool Equals(Wgs84ConversionInfo obj) { if (obj == null) return false; return obj.Dx == this.Dx && obj.Dy == this.Dy && obj.Dz == this.Dz && obj.Ex == this.Ex && obj.Ey == this.Ey && obj.Ez == this.Ez && obj.Ppm == this.Ppm; } #endregion } }