/// <summary> /// 解析字符串为实例。 /// </summary> /// <param name="toString"></param> /// <returns></returns> public static new GeoCoord Parse(string toString, AngleUnit from = AngleUnit.Degree, AngleUnit to = AngleUnit.Degree, AngleUnit fromDegFormat = AngleUnit.Degree) { toString = toString.Replace("(", "").Replace(")", ""); string[] spliters = new string[] { ",", "\t", " " }; string[] strs = toString.Split(spliters, StringSplitOptions.RemoveEmptyEntries); double lon = double.Parse(strs[0]); double lat = double.Parse(strs[1]); if (from == AngleUnit.Degree)//转换为标准的度小数再说。 { lon = AngularConvert.ConvertDegree(lon, fromDegFormat); lat = AngularConvert.ConvertDegree(lat, fromDegFormat); } lon = AngularConvert.Convert(lon, from, to); lat = AngularConvert.Convert(lat, from, to); double h = 0; if (strs.Length > 2) { h = double.Parse(strs[2]); } return(new GeoCoord(lon, lat, h)); }
/// <summary> /// 旋转方位角 /// </summary> /// <param name="val"></param> /// <param name="unit"></param> /// <returns></returns> public PlanePolar RotateAzimuth(double val, AngleUnit unit = AngleUnit.Degree) { if (this.Unit != unit) { val = AngularConvert.Convert(val, unit, this.Unit); } double azimuth = Azimuth + val; return(new PlanePolar(Range, azimuth)); }
/// <summary> /// 计算日固坐标系下的经纬度 /// </summary> /// <param name="dateTimeUtc"></param> /// <returns></returns> public LonLat GetSeLonLat(DateTime dateTimeUtc) { double lon = AngularConvert.ToRad(Lon, this.Unit); double utRad = Geo.Times.Time.DateTimeToRad(dateTimeUtc); lon = lon + utRad - Math.PI; lon = AngularConvert.RadTo(lon, this.Unit); return(new LonLat(lon, Lat, this.Unit)); }
/// <summary> /// Sphere to XYZ Coordinate /// </summary> /// <param name="lon"></param> /// <param name="lat"></param> /// <param name="r"></param> /// <returns></returns> public static XYZ SphereToXyz(double lon, double lat, double r, AngleUnit unit = AngleUnit.Degree) { lon = AngularConvert.ToRad(lon, unit); lat = AngularConvert.ToRad(lat, unit); double x = r * Cos(lat) * Cos(lon); double y = r * Cos(lat) * Sin(lon); double z = r * Sin(lat); return(new XYZ(x, y, z)); }
/// <summary> /// 由空间直角坐标转换为椭球坐标。默认角度单位为度。 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="z"></param> /// <param name="a"></param> /// <param name="e"></param> /// <returns></returns> public static GeoCoord XyzToGeoCoord(double x, double y, double z, double a, double e, AngleUnit angeUnit = AngleUnit.Degree) { double ee = e * e; double lon = Math.Atan2(y, x); double lat; double height; //iteration double deltaZ = 0; double sqrtXy = Math.Sqrt(x * x + y * y); double tempLat = Math.Atan2(z, sqrtXy);//初始取值 lat = tempLat; //if (Math.Abs(lat) > 80.0 * CoordConverter.DegToRadMultiplier)//lat=+-90,或height特大时,采用此算法更稳定(实际有待实验,保留both代码) //{ int count = 0;//避免死循环 do { var sinLat = Sin(lat); deltaZ = a * ee * sinLat / Math.Sqrt(1 - Math.Pow(e * sinLat, 2)); tempLat = lat; lat = Math.Atan2(z + deltaZ, sqrtXy); count++; } while (Math.Abs(lat - tempLat) > 1E-12 || count < 20); //} //else//经典算法 //{ // do // { // double tanB = Math.Tan(lat); // tempLat = lat; // lat = Math.Atan2(z + a * ee * tanB / Math.Sqrt(1 + tanB * tanB * (1 - ee)), sqrtXy); // } while (Math.Abs(lat - tempLat) > 1E-12); //} double n = a / Math.Sqrt(1 - Math.Pow(e * Sin(tempLat), 2)); //double height = Math.Sqrt(x * x + y * y + Math.Pow((z + deltaZ), 2)) - n; height = sqrtXy / Cos(lat) - n; //地心纬度 //double dixinLat = (1 - ee * n / (n + height)) * Math.Tan(lat); //double dixinLatDeg = dixinLat * CoordConverter.RadToDegdMultiplier; lon = AngularConvert.RadTo(lon, angeUnit); lat = AngularConvert.RadTo(lat, angeUnit); return(new GeoCoord(lon, lat, height)); }
/// <summary> /// XYZ to Sphere Coordinate /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="z"></param> /// <returns></returns> public static SphereCoord XyzToSphere(double x, double y, double z, AngleUnit unit = AngleUnit.Degree) { double radius = Math.Sqrt(x * x + y * y + z * z); double lon = Math.Atan2(y, x); double lat = Math.Atan2(z, Math.Sqrt(x * x + y * y)); lon = AngularConvert.RadTo(lon, unit); lat = AngularConvert.RadTo(lat, unit); SphereCoord sphere = new SphereCoord(lon, lat, radius); return(sphere); }
/// <summary> /// 极坐标系到同心空间直角坐标系。 /// </summary> /// <param name="p">极坐标</param> /// <returns></returns> public static NEU PolarToNeu(Polar p) { double ele = AngularConvert.ToRad(p.Elevation, p.Unit); double azi = AngularConvert.ToRad(p.Azimuth, p.Unit); double n = p.Range * Cos(ele) * Cos(azi); double e = p.Range * Cos(ele) * Sin(azi); double u = p.Range * Sin(ele); return(new NEU() { E = e, N = n, U = u }); }
/// <summary> /// 空间极坐标系到空间直角坐标系 /// </summary> /// <param name="polar"></param> /// <param name="unit">角度单位</param> /// <returns></returns> public static XYZ PolarToXyz(Polar polar, AngleUnit unit = AngleUnit.Degree) { double radius = polar.Range; double elevatAngle = polar.Zenith; double azimuth = polar.Azimuth; elevatAngle = AngularConvert.ToRad(elevatAngle, polar.Unit); azimuth = AngularConvert.ToRad(azimuth, polar.Unit); double x = radius * (Cos(elevatAngle) + Cos(azimuth)); double y = radius * (Cos(elevatAngle) + Sin(azimuth)); double z = radius * Sin(elevatAngle); return(new XYZ(x, y, z)); }
/// <summary> /// 经纬度转换到高斯坐标XY /// </summary> /// <param name="lonlat"></param> /// <param name="beltWidth"></param> /// <param name="Ellipsoid"></param> /// <param name="unit"></param> /// <param name="aveGeoHeight">投影面平均大地高</param> /// <param name="YConst">横轴Y加常数</param> /// <param name="orinalLonDeg">中央子午线,度小数</param> /// <param name="isYWithBeltNum"></param> /// <returns></returns> public static XY LonLatToGaussXy(LonLat lonlat, double aveGeoHeight, int beltWidth, ref double orinalLonDeg, bool IsIndicateOriginLon, Ellipsoid Ellipsoid, double YConst = 500000, AngleUnit unit = AngleUnit.Degree, bool isYWithBeltNum = true) { double B = lonlat.Lat; double L = lonlat.Lon; double x; double y; //单位转换 L = AngularConvert.Convert(L, unit, AngleUnit.Degree); B = AngularConvert.Convert(B, unit, AngleUnit.Degree); Geo.Coordinates.GeodeticUtils.LonLatToGaussXy(L, B, aveGeoHeight, out x, out y, ref orinalLonDeg, IsIndicateOriginLon, beltWidth, YConst, isYWithBeltNum, Ellipsoid.SemiMajorAxis, Ellipsoid.InverseFlattening); return(new XY(x, y)); }
/// <summary> /// 计算卫星的站心极坐标,基于当前测站的大地坐标,即高度角基于椭球表面,当前经度为0时,请直接调用 lon lat /// </summary> /// <param name="satXyz">卫星的地心空间直角坐标</param> /// <param name="stationPosition">测站的地心空间直角坐标</param> /// <param name="unit">角度单位,表示输出的角度单位</param> /// <returns></returns> public static Polar XyzToGeoPolar(XYZ satXyz, XYZ stationPosition, AngleUnit unit = AngleUnit.Degree) { double lat, lon, h; //计算站点坐标的经纬度,此法为度为单位,by Zhao Dongqing GeodeticX.Geodetic.XYZ_BLH(stationPosition.X, stationPosition.Y, stationPosition.Z, out lat, out lon, out h, Geo.Referencing.Ellipsoid.WGS84.SemiMajorAxis, Geo.Referencing.Ellipsoid.WGS84.InverseFlattening); if (unit != AngleUnit.Degree) { lat = AngularConvert.Convert(lat, AngleUnit.Degree, unit); lon = AngularConvert.Convert(lon, AngleUnit.Degree, unit); } return(XyzToPolar(satXyz, stationPosition, lon, lat, unit)); }
/// <summary> /// 空间直角坐标系到,站心坐标系的转换。默认B L 单位 度,可以为球坐标和大地坐标 /// 地心空间直角坐标系(XYZ)转换为地方左手笛卡尔直角坐标系(NEU,XYZ) /// </summary> /// <param name="vector1">测站到卫星的向径</param> /// <param name="lat">站点所在纬度</param> /// <param name="lon">站点所在经度</param> /// <param name="angleUnit">站点所在经度的单位</param> /// <returns></returns> public static NEU XyzToNeu(XYZ vector1, double lat, double lon, AngleUnit angleUnit = AngleUnit.Degree) { if (angleUnit != AngleUnit.Radian) //当前经度为 0 的时候,U 的转换会出现符号错误???!!!2017.10.12. { lat = AngularConvert.ToRad(lat, angleUnit); lon = AngularConvert.ToRad(lon, angleUnit); } XYZ v = vector1; double n = -v.X * Sin(lat) * Cos(lon) - v.Y * Sin(lat) * Sin(lon) + v.Z * Cos(lat); double e = -v.X * Sin(lon) + v.Y * Cos(lon); double u = v.X * Cos(lat) * Cos(lon) + v.Y * Cos(lat) * Sin(lon) + v.Z * Sin(lat); return(new NEU(n, e, u));// { N = n, E = e, U = u }; }
/// <summary> /// 平面坐标(自然坐标或假定坐标)到大地坐标的高斯反算 /// </summary> /// <param name="xy">x为横轴</param> /// <param name="a"></param> /// <param name="YConst">横轴Y加常数</param> /// <param name="InverseFlat ">参考椭球扁率倒数</param> /// <param name="beltWidth">6、3</param> /// <param name="aveGeoHeight">投影面大地高</param> /// <param name="unit">输出角度的单位</param> /// <param name="originLon_deg">中央子午线,度</param> /// <returns></returns> public static LonLat GaussXyToLonLat(XY xy, double aveGeoHeight, int beltWidth, double originLon_deg, double YConst, double a = Ellipsoid.SemiMajorAxisOfCGCS2000, double InverseFlat = Ellipsoid.InverseFlatOfCGCS2000, AngleUnit unit = AngleUnit.Degree) { double B; double L; double x = xy.X; double y = xy.Y; var lonlat = GeodeticUtils.GaussXyToLonLat(xy, aveGeoHeight, originLon_deg, YConst, a, InverseFlat); //GeodeticX.Geodetic.xy_BL(x, y, out B, out L, beltWidth, beltNum, a, InverseFlat ); //单位转换 L = AngularConvert.Convert(lonlat.Lon, AngleUnit.Degree, unit); B = AngularConvert.Convert(lonlat.Lat, AngleUnit.Degree, unit); return(new LonLat(L, B)); }
/// <summary> /// 空间直角坐标到极坐标 /// </summary> /// <param name="xyz"></param> /// <param name="unit">角度单位</param> /// <returns></returns> public static Polar XyzToPolar(XYZ xyz, AngleUnit unit = AngleUnit.Degree) { double x = xyz.X; double y = xyz.Y; double z = xyz.Z; double radius = Math.Sqrt(x * x + y * y + z * z); double azimuth = Math.Atan2(y, x); if (azimuth < 0) { azimuth += 2.0 * CoordConsts.PI; } double elevatAngle = Math.Atan2(z, Math.Sqrt(x * x + y * y)); azimuth = AngularConvert.RadTo(azimuth, unit); elevatAngle = AngularConvert.RadTo(elevatAngle, unit); return(new Polar(radius, azimuth, elevatAngle, unit)); }
/// <summary> /// 椭球坐标转为空间直角坐标。默认单位为度。 /// </summary> /// <param name="lon">经度(度)</param> /// <param name="lat">纬度(度)</param> /// <param name="height">大地高</param> /// <param name="a">椭球半径</param> /// <param name="flatOrInverse">扁率或其倒数</param> /// <param name="unit">单位</param> /// <returns></returns> public static XYZ GeoCoordToXyz(double lon, double lat, double height, double a, double flatOrInverse, AngleUnit unit = AngleUnit.Degree) { lon = AngularConvert.ToRad(lon, unit); lat = AngularConvert.ToRad(lat, unit); //扁率判断 double e = flatOrInverse; if (flatOrInverse > 1) { e = 1.0 / e; } double n = a / Math.Sqrt(1 - Math.Pow(e * Sin(lat), 2)); double x = (n + height) * Cos(lat) * Cos(lon); double y = (n + height) * Cos(lat) * Sin(lon); double z = (n * (1 - e * e) + height) * Sin(lat); return(new XYZ(x, y, z)); }
/// <summary> /// 站心坐标系到站心极坐标系。 /// </summary> /// <param name="neu"></param> /// <param name="unit">默认单位为度</param> /// <returns></returns> public static Polar NeuToPolar(NEU neu, AngleUnit unit = AngleUnit.Degree) { double r = neu.Length; double a = Math.Atan2(neu.E, neu.N); if (a < 0)//以北向为基准,顺时针,无负号 { a += 2.0 * CoordConsts.PI; } double o = Math.Asin(neu.U / r); if (unit != AngleUnit.Radian) { a = AngularConvert.RadTo(a, unit); o = AngularConvert.RadTo(o, unit); } return(new Polar(r, a, o) { Unit = unit }); }
/// <summary> /// 构造函数 /// </summary> /// <param name="dval"></param> /// <param name="degreeFormat"></param> public DMS(double dval, AngleUnit degreeFormat) { switch (degreeFormat) { case AngleUnit.Radian: InitDegree(AngularConvert.RadToDeg(dval)); break; case AngleUnit.Degree: InitDegree(dval); break; case AngleUnit.DMS_S: { this.IsPlus = dval > 0; double d = Math.Abs(dval); var str = d.ToString("0.00000000000"); var indexOfPt = str.IndexOf("."); if (indexOfPt > 4) { var degr = str.Substring(0, indexOfPt - 4); this.Degree = int.Parse(degr); } if (indexOfPt > 2) { var minStr = str.Substring(indexOfPt - 4, 2); this.Minute = int.Parse(minStr); } var secStr = str.Substring(indexOfPt - 2); this.Second = Double.Parse(secStr); } break; case AngleUnit.D_MS: //120.30300 { this.IsPlus = dval > 0; double d = Math.Abs(dval); var str = d.ToString("0.00000000000"); var indexOfPt = str.IndexOf("."); var degr = str.Substring(0, indexOfPt); this.Degree = int.Parse(degr); this.Minute = int.Parse(str.Substring(indexOfPt + 1, 2)); var secStr = str.Substring(indexOfPt + 3, 2) + "." + str.Substring(indexOfPt + 5); this.Second = Double.Parse(secStr); } break; case AngleUnit.HMS_S: { this.IsPlus = dval > 0; double d = Math.Abs(dval); var str = d.ToString("0.00000000000"); var indexOfPt = str.IndexOf("."); if (indexOfPt > 4) { var degr = str.Substring(0, indexOfPt - 4); this.Degree = int.Parse(degr) * 15; } if (indexOfPt > 2) { var minStr = str.Substring(indexOfPt - 4, 2); this.Minute = int.Parse(minStr); } var secStr = str.Substring(indexOfPt - 2); this.Second = Double.Parse(secStr); } //this.IsPlus = dval > 0; //double deg0 = Math.Abs(dval); //var hour = (int)(deg0 / 10000); //var minute = (int)((deg0) / 100.0) - Degree * 100; //var second = deg0 % 100; //var hours = hour + minute / 60.0 + second / 3600.0; //var degs = hours * 15.0; //InitDegree(degs); break; default: throw new ArgumentException("暂不支持这种类型 " + degreeFormat); } }