packages/core/projections/csharp/Projection.cs (163 lines of code) (raw):

using System; namespace Ali.Polaris.Projections { // 投影类型 public enum ProjectionType { MercatorProjection, GeocentricProjection, GallStereoGraphicProjection, AzimuthalEquidistantProjection, EquirectangularProjection } // 长度单位 public enum ProjectionUnits { kilometers, meters } // 投影描述 public struct ProjectionDesc { public string type; public string orientation; public string units; public double[] center; } // 初始化参数 public struct ProjectionProps { public string orientation; public string units; public double[] center; } // Exceptions public class WrongDescException : Exception { public WrongDescException(string msg) { } } public class WrongPropsException : Exception { public WrongPropsException(string msg) { } } // 基类 public abstract class Projection { // constants protected const double MAX_LATITUDE = 85.05112877980659; protected const double DEG2RAD = Math.PI / 180d; protected const double R = 6378137d; // units scale protected double scale = 1d; // desc public string Type { get; protected set; } = "Projection"; // 兼容JS,其实没啥用 public string Orientation { get; protected set; } public string Units { get; protected set; } public virtual bool IsPlaneProjection { get; protected set; } = false; public virtual bool IsSphereProjection { get; protected set; } = false; public virtual bool IsGeocentricProjection { get; protected set; } = false; protected bool _useRightHand = false; public virtual double[] Center { get; set; } = { 0d, 0d, 0d }; protected Projection(ProjectionProps props) { // default values if (props.orientation == null) { props.orientation = "right"; } if (props.units == null) { props.units = "meters"; } if (props.center == null) { props.center = new double[] { 0d, 0d, 0d }; } Center = props.center; Units = props.units; Orientation = props.orientation; _useRightHand = Orientation == "right"; // 单位转换 if (Units == "kilometers") { scale = 0.001d; } else if (Units == "meters") { scale = 1d; } } // lnglatalt to xyz public abstract double[] Project(double lng, double lat, double alt = 0d); // xyz to lnglatalt public abstract double[] Unproject(double x, double y, double z = 0d); // 输入输出调节,计算过程中全部使用 右手系,以米为单位 protected double[] TransformOut(double x, double y, double z = 0d) { if (this._useRightHand) { return new double[] { x * scale, y * scale, z * scale }; } else { return new double[] { x * scale, z * scale, y * scale }; } } protected void TransformIn(ref double x, ref double y, ref double z) { if (!this._useRightHand) { var tmp = z; z = y; y = tmp; } x /= scale; y /= scale; z /= scale; } // 生成描述 public string ToDesc() { // 0 version | 1 Type | 2 Orientation | 3 Units | 4 Center return $"desc0|{Type}|{Orientation}|{Units}|{Center[0]},{Center[1]},{(Center.Length > 2 ? Center[2] : 0d)}"; } // 从描述创建实例 static public Projection FromDesc(string str) { try { string[] desc = str.Split('|'); var version = desc[0]; var type = desc[1]; var orientation = desc[2]; var units = desc[3]; var centerStr = desc[4]; string[] centerLLA = centerStr.Split(','); double[] center = { Double.Parse(centerLLA[0]), Double.Parse(centerLLA[1]), Double.Parse(centerLLA[2]), }; return Create(type, center, units, orientation); } catch (Exception) { throw new WrongDescException("Failed to parse the desc: " + str); } } // 工厂函数 public static Projection Create(ProjectionType type, double[] center, ProjectionUnits units = ProjectionUnits.meters, string orientation = "right") { return Create(type.ToString(), center, units.ToString(), orientation); } public static Projection Create(string type, double[] center, string units = "meters", string orientation = "right") { ProjectionProps projectionProps = new ProjectionProps { orientation = orientation, units = units, center = center }; try { switch (type) { case "GeocentricProjection": return new GeocentricProjection(projectionProps); case "EquirectangularProjection": return new EquirectangularProjection(projectionProps); case "AzimuthalEquidistantProjection": return new AzimuthalEquidistantProjection(projectionProps); case "GallStereoGraphicProjection": return new GallStereoGraphicProjection(projectionProps); case "SphereProjection": return new SphereProjection(projectionProps); case "MercatorProjection": return new MercatorProjection(projectionProps); default: throw new Exception(); } } catch (Exception) { throw new WrongPropsException("Failed to create projection from props."); } } } }