mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	源代码改用vs默认格式化
This commit is contained in:
		@@ -7,57 +7,66 @@ using System.Data.Common;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.MySql {
 | 
			
		||||
	class MySqlAdo : FreeSql.Internal.CommonProvider.AdoProvider {
 | 
			
		||||
namespace FreeSql.MySql
 | 
			
		||||
{
 | 
			
		||||
    class MySqlAdo : FreeSql.Internal.CommonProvider.AdoProvider
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
		public MySqlAdo() : base(DataType.MySql) { }
 | 
			
		||||
		public MySqlAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings) : base(DataType.MySql) {
 | 
			
		||||
			base._util = util;
 | 
			
		||||
			if (!string.IsNullOrEmpty(masterConnectionString))
 | 
			
		||||
				MasterPool = new MySqlConnectionPool("主库", masterConnectionString, null, null);
 | 
			
		||||
			if (slaveConnectionStrings != null) {
 | 
			
		||||
				foreach (var slaveConnectionString in slaveConnectionStrings) {
 | 
			
		||||
					var slavePool = new MySqlConnectionPool($"从库{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables));
 | 
			
		||||
					SlavePools.Add(slavePool);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		static DateTime dt1970 = new DateTime(1970, 1, 1);
 | 
			
		||||
		public override object AddslashesProcessParam(object param, Type mapType) {
 | 
			
		||||
			if (param == null) return "NULL";
 | 
			
		||||
			if (mapType != null && mapType != param.GetType())
 | 
			
		||||
				param = Utils.GetDataReaderValue(mapType, param);
 | 
			
		||||
			if (param is bool || param is bool?)
 | 
			
		||||
				return (bool)param ? 1 : 0;
 | 
			
		||||
			else if (param is string || param is char)
 | 
			
		||||
				return string.Concat("'", param.ToString().Replace("'", "''"), "'");
 | 
			
		||||
			else if (param is Enum)
 | 
			
		||||
				return string.Concat("'", param.ToString().Replace("'", "''"), "'"); //((Enum)val).ToInt64();
 | 
			
		||||
			else if (decimal.TryParse(string.Concat(param), out var trydec))
 | 
			
		||||
				return param;
 | 
			
		||||
			else if (param is DateTime || param is DateTime?)
 | 
			
		||||
				return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.fff"), "'");
 | 
			
		||||
			else if (param is TimeSpan || param is TimeSpan?)
 | 
			
		||||
				return ((TimeSpan)param).Ticks / 10;
 | 
			
		||||
			else if (param is MygisGeometry)
 | 
			
		||||
				return string.Concat("ST_GeomFromText('", (param as MygisGeometry).AsText().Replace("'", "''"), "')");
 | 
			
		||||
			else if (param is IEnumerable) {
 | 
			
		||||
				var sb = new StringBuilder();
 | 
			
		||||
				var ie = param as IEnumerable;
 | 
			
		||||
				foreach (var z in ie) sb.Append(",").Append(AddslashesProcessParam(z, mapType));
 | 
			
		||||
				return sb.Length == 0 ? "(NULL)" : sb.Remove(0, 1).Insert(0, "(").Append(")").ToString();
 | 
			
		||||
			}
 | 
			
		||||
			return string.Concat("'", param.ToString().Replace("'", "''"), "'");
 | 
			
		||||
		}
 | 
			
		||||
        public MySqlAdo() : base(DataType.MySql) { }
 | 
			
		||||
        public MySqlAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings) : base(DataType.MySql)
 | 
			
		||||
        {
 | 
			
		||||
            base._util = util;
 | 
			
		||||
            if (!string.IsNullOrEmpty(masterConnectionString))
 | 
			
		||||
                MasterPool = new MySqlConnectionPool("主库", masterConnectionString, null, null);
 | 
			
		||||
            if (slaveConnectionStrings != null)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (var slaveConnectionString in slaveConnectionStrings)
 | 
			
		||||
                {
 | 
			
		||||
                    var slavePool = new MySqlConnectionPool($"从库{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables));
 | 
			
		||||
                    SlavePools.Add(slavePool);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        static DateTime dt1970 = new DateTime(1970, 1, 1);
 | 
			
		||||
        public override object AddslashesProcessParam(object param, Type mapType)
 | 
			
		||||
        {
 | 
			
		||||
            if (param == null) return "NULL";
 | 
			
		||||
            if (mapType != null && mapType != param.GetType())
 | 
			
		||||
                param = Utils.GetDataReaderValue(mapType, param);
 | 
			
		||||
            if (param is bool || param is bool?)
 | 
			
		||||
                return (bool)param ? 1 : 0;
 | 
			
		||||
            else if (param is string || param is char)
 | 
			
		||||
                return string.Concat("'", param.ToString().Replace("'", "''"), "'");
 | 
			
		||||
            else if (param is Enum)
 | 
			
		||||
                return string.Concat("'", param.ToString().Replace("'", "''"), "'"); //((Enum)val).ToInt64();
 | 
			
		||||
            else if (decimal.TryParse(string.Concat(param), out var trydec))
 | 
			
		||||
                return param;
 | 
			
		||||
            else if (param is DateTime || param is DateTime?)
 | 
			
		||||
                return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.fff"), "'");
 | 
			
		||||
            else if (param is TimeSpan || param is TimeSpan?)
 | 
			
		||||
                return ((TimeSpan)param).Ticks / 10;
 | 
			
		||||
            else if (param is MygisGeometry)
 | 
			
		||||
                return string.Concat("ST_GeomFromText('", (param as MygisGeometry).AsText().Replace("'", "''"), "')");
 | 
			
		||||
            else if (param is IEnumerable)
 | 
			
		||||
            {
 | 
			
		||||
                var sb = new StringBuilder();
 | 
			
		||||
                var ie = param as IEnumerable;
 | 
			
		||||
                foreach (var z in ie) sb.Append(",").Append(AddslashesProcessParam(z, mapType));
 | 
			
		||||
                return sb.Length == 0 ? "(NULL)" : sb.Remove(0, 1).Insert(0, "(").Append(")").ToString();
 | 
			
		||||
            }
 | 
			
		||||
            return string.Concat("'", param.ToString().Replace("'", "''"), "'");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		protected override DbCommand CreateCommand() {
 | 
			
		||||
			return new MySqlCommand();
 | 
			
		||||
		}
 | 
			
		||||
        protected override DbCommand CreateCommand()
 | 
			
		||||
        {
 | 
			
		||||
            return new MySqlCommand();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		protected override void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex) {
 | 
			
		||||
			(pool as MySqlConnectionPool).Return(conn, ex);
 | 
			
		||||
		}
 | 
			
		||||
        protected override void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            (pool as MySqlConnectionPool).Return(conn, ex);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		protected override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
 | 
			
		||||
	}
 | 
			
		||||
        protected override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,170 +8,210 @@ using System.Data.Common;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.MySql {
 | 
			
		||||
namespace FreeSql.MySql
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	class MySqlConnectionPool : ObjectPool<DbConnection> {
 | 
			
		||||
    class MySqlConnectionPool : ObjectPool<DbConnection>
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
		internal Action availableHandler;
 | 
			
		||||
		internal Action unavailableHandler;
 | 
			
		||||
        internal Action availableHandler;
 | 
			
		||||
        internal Action unavailableHandler;
 | 
			
		||||
 | 
			
		||||
		public MySqlConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null) {
 | 
			
		||||
			var policy = new MySqlConnectionPoolPolicy {
 | 
			
		||||
				_pool = this,
 | 
			
		||||
				Name = name
 | 
			
		||||
			};
 | 
			
		||||
			this.Policy = policy;
 | 
			
		||||
			policy.ConnectionString = connectionString;
 | 
			
		||||
        public MySqlConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null)
 | 
			
		||||
        {
 | 
			
		||||
            var policy = new MySqlConnectionPoolPolicy
 | 
			
		||||
            {
 | 
			
		||||
                _pool = this,
 | 
			
		||||
                Name = name
 | 
			
		||||
            };
 | 
			
		||||
            this.Policy = policy;
 | 
			
		||||
            policy.ConnectionString = connectionString;
 | 
			
		||||
 | 
			
		||||
			this.availableHandler = availableHandler;
 | 
			
		||||
			this.unavailableHandler = unavailableHandler;
 | 
			
		||||
		}
 | 
			
		||||
            this.availableHandler = availableHandler;
 | 
			
		||||
            this.unavailableHandler = unavailableHandler;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false) {
 | 
			
		||||
			if (exception != null && exception is MySqlException) {
 | 
			
		||||
				try { if (obj.Value.Ping() == false) obj.Value.Open(); } catch { base.SetUnavailable(exception); }
 | 
			
		||||
			}
 | 
			
		||||
			base.Return(obj, isRecreate);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
        public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false)
 | 
			
		||||
        {
 | 
			
		||||
            if (exception != null && exception is MySqlException)
 | 
			
		||||
            {
 | 
			
		||||
                try { if (obj.Value.Ping() == false) obj.Value.Open(); } catch { base.SetUnavailable(exception); }
 | 
			
		||||
            }
 | 
			
		||||
            base.Return(obj, isRecreate);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	class MySqlConnectionPoolPolicy : IPolicy<DbConnection> {
 | 
			
		||||
    class MySqlConnectionPoolPolicy : IPolicy<DbConnection>
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
		internal MySqlConnectionPool _pool;
 | 
			
		||||
		public string Name { get; set; } = "MySql MySqlConnection 对象池";
 | 
			
		||||
		public int PoolSize { get; set; } = 100;
 | 
			
		||||
		public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
 | 
			
		||||
		public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero;
 | 
			
		||||
		public int AsyncGetCapacity { get; set; } = 10000;
 | 
			
		||||
		public bool IsThrowGetTimeoutException { get; set; } = true;
 | 
			
		||||
		public int CheckAvailableInterval { get; set; } = 5;
 | 
			
		||||
        internal MySqlConnectionPool _pool;
 | 
			
		||||
        public string Name { get; set; } = "MySql MySqlConnection 对象池";
 | 
			
		||||
        public int PoolSize { get; set; } = 100;
 | 
			
		||||
        public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
 | 
			
		||||
        public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero;
 | 
			
		||||
        public int AsyncGetCapacity { get; set; } = 10000;
 | 
			
		||||
        public bool IsThrowGetTimeoutException { get; set; } = true;
 | 
			
		||||
        public int CheckAvailableInterval { get; set; } = 5;
 | 
			
		||||
 | 
			
		||||
		static ConcurrentDictionary<string, int> dicConnStrIncr = new ConcurrentDictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
 | 
			
		||||
		private string _connectionString;
 | 
			
		||||
		public string ConnectionString {
 | 
			
		||||
			get => _connectionString;
 | 
			
		||||
			set {
 | 
			
		||||
				_connectionString = value ?? "";
 | 
			
		||||
        static ConcurrentDictionary<string, int> dicConnStrIncr = new ConcurrentDictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
 | 
			
		||||
        private string _connectionString;
 | 
			
		||||
        public string ConnectionString
 | 
			
		||||
        {
 | 
			
		||||
            get => _connectionString;
 | 
			
		||||
            set
 | 
			
		||||
            {
 | 
			
		||||
                _connectionString = value ?? "";
 | 
			
		||||
 | 
			
		||||
				var pattern = @"Max\s*pool\s*size\s*=\s*(\d+)";
 | 
			
		||||
				var m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
			
		||||
				if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100;
 | 
			
		||||
				var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => oldval + 1);
 | 
			
		||||
				PoolSize = poolsize + connStrIncr;
 | 
			
		||||
				_connectionString = m.Success ? 
 | 
			
		||||
					Regex.Replace(_connectionString, pattern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) :
 | 
			
		||||
					$"{_connectionString};Max pool size={PoolSize}";
 | 
			
		||||
                var pattern = @"Max\s*pool\s*size\s*=\s*(\d+)";
 | 
			
		||||
                var m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
			
		||||
                if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100;
 | 
			
		||||
                var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => oldval + 1);
 | 
			
		||||
                PoolSize = poolsize + connStrIncr;
 | 
			
		||||
                _connectionString = m.Success ?
 | 
			
		||||
                    Regex.Replace(_connectionString, pattern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) :
 | 
			
		||||
                    $"{_connectionString};Max pool size={PoolSize}";
 | 
			
		||||
 | 
			
		||||
				pattern = @"Connection\s*LifeTime\s*=\s*(\d+)";
 | 
			
		||||
				m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
			
		||||
				if (m.Success) {
 | 
			
		||||
					IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value));
 | 
			
		||||
					_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
 | 
			
		||||
				}
 | 
			
		||||
                pattern = @"Connection\s*LifeTime\s*=\s*(\d+)";
 | 
			
		||||
                m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
			
		||||
                if (m.Success)
 | 
			
		||||
                {
 | 
			
		||||
                    IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value));
 | 
			
		||||
                    _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
				var minPoolSize = 0;
 | 
			
		||||
				pattern = @"Min\s*pool\s*size\s*=\s*(\d+)";
 | 
			
		||||
				m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
			
		||||
				if (m.Success) {
 | 
			
		||||
					minPoolSize = int.Parse(m.Groups[1].Value);
 | 
			
		||||
					_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
 | 
			
		||||
				}
 | 
			
		||||
                var minPoolSize = 0;
 | 
			
		||||
                pattern = @"Min\s*pool\s*size\s*=\s*(\d+)";
 | 
			
		||||
                m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
			
		||||
                if (m.Success)
 | 
			
		||||
                {
 | 
			
		||||
                    minPoolSize = int.Parse(m.Groups[1].Value);
 | 
			
		||||
                    _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
				FreeSql.Internal.CommonUtils.PrevReheatConnectionPool(_pool, minPoolSize);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
                FreeSql.Internal.CommonUtils.PrevReheatConnectionPool(_pool, minPoolSize);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public bool OnCheckAvailable(Object<DbConnection> obj) {
 | 
			
		||||
			if (obj.Value.State == ConnectionState.Closed) obj.Value.Open();
 | 
			
		||||
			return obj.Value.Ping(true);
 | 
			
		||||
		}
 | 
			
		||||
        public bool OnCheckAvailable(Object<DbConnection> obj)
 | 
			
		||||
        {
 | 
			
		||||
            if (obj.Value.State == ConnectionState.Closed) obj.Value.Open();
 | 
			
		||||
            return obj.Value.Ping(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public DbConnection OnCreate() {
 | 
			
		||||
			var conn = new MySqlConnection(_connectionString);
 | 
			
		||||
			return conn;
 | 
			
		||||
		}
 | 
			
		||||
        public DbConnection OnCreate()
 | 
			
		||||
        {
 | 
			
		||||
            var conn = new MySqlConnection(_connectionString);
 | 
			
		||||
            return conn;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public void OnDestroy(DbConnection obj) {
 | 
			
		||||
			if (obj.State != ConnectionState.Closed) obj.Close();
 | 
			
		||||
			obj.Dispose();
 | 
			
		||||
		}
 | 
			
		||||
        public void OnDestroy(DbConnection obj)
 | 
			
		||||
        {
 | 
			
		||||
            if (obj.State != ConnectionState.Closed) obj.Close();
 | 
			
		||||
            obj.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public void OnGet(Object<DbConnection> obj) {
 | 
			
		||||
        public void OnGet(Object<DbConnection> obj)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
			if (_pool.IsAvailable) {
 | 
			
		||||
            if (_pool.IsAvailable)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
				if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false) {
 | 
			
		||||
                if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false)
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
					try {
 | 
			
		||||
						obj.Value.Open();
 | 
			
		||||
					} catch (Exception ex) {
 | 
			
		||||
						if (_pool.SetUnavailable(ex) == true)
 | 
			
		||||
							throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        obj.Value.Open();
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (_pool.SetUnavailable(ex) == true)
 | 
			
		||||
                            throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		async public Task OnGetAsync(Object<DbConnection> obj) {
 | 
			
		||||
        async public Task OnGetAsync(Object<DbConnection> obj)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
			if (_pool.IsAvailable) {
 | 
			
		||||
            if (_pool.IsAvailable)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
				if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (await obj.Value.PingAsync()) == false) {
 | 
			
		||||
                if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (await obj.Value.PingAsync()) == false)
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
					try {
 | 
			
		||||
						await obj.Value.OpenAsync();
 | 
			
		||||
					} catch (Exception ex) {
 | 
			
		||||
						if (_pool.SetUnavailable(ex) == true)
 | 
			
		||||
							throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await obj.Value.OpenAsync();
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (_pool.SetUnavailable(ex) == true)
 | 
			
		||||
                            throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public void OnGetTimeout() {
 | 
			
		||||
        public void OnGetTimeout()
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public void OnReturn(Object<DbConnection> obj) {
 | 
			
		||||
        public void OnReturn(Object<DbConnection> obj)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public void OnAvailable() {
 | 
			
		||||
			_pool.availableHandler?.Invoke();
 | 
			
		||||
		}
 | 
			
		||||
        public void OnAvailable()
 | 
			
		||||
        {
 | 
			
		||||
            _pool.availableHandler?.Invoke();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public void OnUnavailable() {
 | 
			
		||||
			_pool.unavailableHandler?.Invoke();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
        public void OnUnavailable()
 | 
			
		||||
        {
 | 
			
		||||
            _pool.unavailableHandler?.Invoke();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	static class DbConnectionExtensions {
 | 
			
		||||
    static class DbConnectionExtensions
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
		static DbCommand PingCommand(DbConnection conn) {
 | 
			
		||||
			var cmd = conn.CreateCommand();
 | 
			
		||||
			cmd.CommandTimeout = 5;
 | 
			
		||||
			cmd.CommandText = "select 1";
 | 
			
		||||
			return cmd;
 | 
			
		||||
		}
 | 
			
		||||
		public static bool Ping(this DbConnection that, bool isThrow = false) {
 | 
			
		||||
			try {
 | 
			
		||||
				PingCommand(that).ExecuteNonQuery();
 | 
			
		||||
				return true;
 | 
			
		||||
			} catch {
 | 
			
		||||
				if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
 | 
			
		||||
				if (isThrow) throw;
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		async public static Task<bool> PingAsync(this DbConnection that, bool isThrow = false) {
 | 
			
		||||
			try {
 | 
			
		||||
				await PingCommand(that).ExecuteNonQueryAsync();
 | 
			
		||||
				return true;
 | 
			
		||||
			} catch {
 | 
			
		||||
				if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
 | 
			
		||||
				if (isThrow) throw;
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
        static DbCommand PingCommand(DbConnection conn)
 | 
			
		||||
        {
 | 
			
		||||
            var cmd = conn.CreateCommand();
 | 
			
		||||
            cmd.CommandTimeout = 5;
 | 
			
		||||
            cmd.CommandText = "select 1";
 | 
			
		||||
            return cmd;
 | 
			
		||||
        }
 | 
			
		||||
        public static bool Ping(this DbConnection that, bool isThrow = false)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                PingCommand(that).ExecuteNonQuery();
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
 | 
			
		||||
                if (isThrow) throw;
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        async public static Task<bool> PingAsync(this DbConnection that, bool isThrow = false)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await PingCommand(that).ExecuteNonQueryAsync();
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
 | 
			
		||||
                if (isThrow) throw;
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,289 +4,338 @@ using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
public struct MygisCoordinate2D : IEquatable<MygisCoordinate2D> {
 | 
			
		||||
	public double X { get; }
 | 
			
		||||
	public double Y { get; }
 | 
			
		||||
	public MygisCoordinate2D(double x, double y) { X = x; Y = y; }
 | 
			
		||||
public struct MygisCoordinate2D : IEquatable<MygisCoordinate2D>
 | 
			
		||||
{
 | 
			
		||||
    public double X { get; }
 | 
			
		||||
    public double Y { get; }
 | 
			
		||||
    public MygisCoordinate2D(double x, double y) { X = x; Y = y; }
 | 
			
		||||
 | 
			
		||||
	public bool Equals(MygisCoordinate2D c) => X == c.X && Y == c.Y;
 | 
			
		||||
	public override int GetHashCode() => X.GetHashCode() ^ MygisGeometry.RotateShift(Y.GetHashCode(), sizeof(int) / 2);
 | 
			
		||||
	public override bool Equals(object obj) => obj is MygisCoordinate2D && Equals((MygisCoordinate2D) obj);
 | 
			
		||||
	public static bool operator ==(MygisCoordinate2D left, MygisCoordinate2D right) => Equals(left, right);
 | 
			
		||||
	public static bool operator !=(MygisCoordinate2D left, MygisCoordinate2D right) => !Equals(left, right);
 | 
			
		||||
    public bool Equals(MygisCoordinate2D c) => X == c.X && Y == c.Y;
 | 
			
		||||
    public override int GetHashCode() => X.GetHashCode() ^ MygisGeometry.RotateShift(Y.GetHashCode(), sizeof(int) / 2);
 | 
			
		||||
    public override bool Equals(object obj) => obj is MygisCoordinate2D && Equals((MygisCoordinate2D)obj);
 | 
			
		||||
    public static bool operator ==(MygisCoordinate2D left, MygisCoordinate2D right) => Equals(left, right);
 | 
			
		||||
    public static bool operator !=(MygisCoordinate2D left, MygisCoordinate2D right) => !Equals(left, right);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public abstract class MygisGeometry {
 | 
			
		||||
	protected abstract int GetLenHelper();
 | 
			
		||||
	internal int GetLen(bool includeSRID) => 5 + (SRID == 0 || !includeSRID ? 0 : 4) + GetLenHelper();
 | 
			
		||||
	public uint SRID { get; set; } = 0;
 | 
			
		||||
	internal static int RotateShift(int val, int shift) => (val << shift) | (val >> (sizeof(int) - shift));
 | 
			
		||||
	public override string ToString() => this.AsText();
 | 
			
		||||
	public string AsText() {
 | 
			
		||||
		if (this is MygisPoint) {
 | 
			
		||||
			var obj = this as MygisPoint;
 | 
			
		||||
			return $"POINT({obj.X} {obj.Y})";
 | 
			
		||||
		}
 | 
			
		||||
		if (this is MygisLineString) {
 | 
			
		||||
			var obj = this as MygisLineString;
 | 
			
		||||
			return obj?.PointCount > 0 ? $"LINESTRING({string.Join(",", obj.Select(a => $"{a.X} {a.Y}"))})" : null;
 | 
			
		||||
		}
 | 
			
		||||
		if (this is MygisPolygon) {
 | 
			
		||||
			var obj = (this as MygisPolygon).Where(z => z.Count() > 1 && z.First().Equals(z.Last()));
 | 
			
		||||
			return obj.Any() ? $"POLYGON(({string.Join("),(", obj.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))}))" : null;
 | 
			
		||||
		}
 | 
			
		||||
		if (this is MygisMultiPoint) {
 | 
			
		||||
			var obj = this as MygisMultiPoint;
 | 
			
		||||
			return obj?.PointCount > 0 ? $"MULTIPOINT({string.Join(",", obj.Select(a => $"{a.X} {a.Y}"))})" : null;
 | 
			
		||||
		}
 | 
			
		||||
		if (this is MygisMultiLineString) {
 | 
			
		||||
			var obj = this as MygisMultiLineString;
 | 
			
		||||
			return obj.LineCount > 0 ? $"MULTILINESTRING(({string.Join("),(", obj.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))}))" : null;
 | 
			
		||||
		}
 | 
			
		||||
		if (this is MygisMultiPolygon) {
 | 
			
		||||
			var obj = (this as MygisMultiPolygon)?.Where(z => z.Where(y => y.Count() > 1 && y.First().Equals(y.Last())).Any());
 | 
			
		||||
			return obj.Any() ? $"MULTIPOLYGON((({string.Join(")),((", obj.Select(d => string.Join("),(", d.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))))})))" : null;
 | 
			
		||||
		}
 | 
			
		||||
		return base.ToString();
 | 
			
		||||
	}
 | 
			
		||||
	static readonly Regex regexMygisPoint = new Regex(@"\s*(-?\d+\.?\d*)\s+(-?\d+\.?\d*)\s*");
 | 
			
		||||
	static readonly Regex regexSplit1 = new Regex(@"\)\s*,\s*\(");
 | 
			
		||||
	static readonly Regex regexSplit2 = new Regex(@"\)\s*\)\s*,\s*\(\s*\(");
 | 
			
		||||
	public static MygisGeometry Parse(string wkt) {
 | 
			
		||||
		if (string.IsNullOrEmpty(wkt)) return null;
 | 
			
		||||
		wkt = wkt.Trim();
 | 
			
		||||
		if (wkt.StartsWith("point", StringComparison.CurrentCultureIgnoreCase)) return ParsePoint(wkt.Substring(5).Trim('(', ')'));
 | 
			
		||||
		else if (wkt.StartsWith("linestring", StringComparison.CurrentCultureIgnoreCase)) return new MygisLineString(ParseLineString(wkt.Substring(10).Trim('(', ')')));
 | 
			
		||||
		else if (wkt.StartsWith("polygon", StringComparison.CurrentCultureIgnoreCase)) return new MygisPolygon(ParsePolygon(wkt.Substring(7).Trim('(', ')')));
 | 
			
		||||
		else if (wkt.StartsWith("multipoint", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiPoint(ParseLineString(wkt.Substring(10).Trim('(', ')')));
 | 
			
		||||
		else if (wkt.StartsWith("multilinestring", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiLineString(ParseMultiLineString(wkt.Substring(15).Trim('(', ')')));
 | 
			
		||||
		else if (wkt.StartsWith("multipolygon", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiPolygon(ParseMultiPolygon(wkt.Substring(12).Trim('(', ')')));
 | 
			
		||||
		throw new NotImplementedException($"MygisGeometry.Parse 未实现 \"{wkt}\"");
 | 
			
		||||
	}
 | 
			
		||||
	static MygisPoint ParsePoint(string str) {
 | 
			
		||||
		var m = regexMygisPoint.Match(str);
 | 
			
		||||
		if (m.Success == false) return null;
 | 
			
		||||
		return new MygisPoint(double.TryParse(m.Groups[1].Value, out var tryd) ? tryd : 0, double.TryParse(m.Groups[2].Value, out tryd) ? tryd : 0);
 | 
			
		||||
	}
 | 
			
		||||
	static MygisCoordinate2D[] ParseLineString(string str) {
 | 
			
		||||
		var ms = regexMygisPoint.Matches(str);
 | 
			
		||||
		var points = new MygisCoordinate2D[ms.Count];
 | 
			
		||||
		for (var a = 0; a < ms.Count; a++) points[a] = new MygisCoordinate2D(double.TryParse(ms[a].Groups[1].Value, out var tryd) ? tryd : 0, double.TryParse(ms[a].Groups[2].Value, out tryd) ? tryd : 0);
 | 
			
		||||
		return points;
 | 
			
		||||
	}
 | 
			
		||||
	static MygisCoordinate2D[][] ParsePolygon(string str) {
 | 
			
		||||
		return regexSplit1.Split(str).Select(s => ParseLineString(s)).Where(a => a.Length > 1 && a.First().Equals(a.Last())).ToArray();
 | 
			
		||||
	}
 | 
			
		||||
	static MygisLineString[] ParseMultiLineString(string str) {
 | 
			
		||||
		return regexSplit1.Split(str).Select(s => new MygisLineString(ParseLineString(s))).ToArray();
 | 
			
		||||
	}
 | 
			
		||||
	static MygisPolygon[] ParseMultiPolygon(string str) {
 | 
			
		||||
		return regexSplit2.Split(str).Select(s => new MygisPolygon(ParsePolygon(s))).ToArray();
 | 
			
		||||
	}
 | 
			
		||||
public abstract class MygisGeometry
 | 
			
		||||
{
 | 
			
		||||
    protected abstract int GetLenHelper();
 | 
			
		||||
    internal int GetLen(bool includeSRID) => 5 + (SRID == 0 || !includeSRID ? 0 : 4) + GetLenHelper();
 | 
			
		||||
    public uint SRID { get; set; } = 0;
 | 
			
		||||
    internal static int RotateShift(int val, int shift) => (val << shift) | (val >> (sizeof(int) - shift));
 | 
			
		||||
    public override string ToString() => this.AsText();
 | 
			
		||||
    public string AsText()
 | 
			
		||||
    {
 | 
			
		||||
        if (this is MygisPoint)
 | 
			
		||||
        {
 | 
			
		||||
            var obj = this as MygisPoint;
 | 
			
		||||
            return $"POINT({obj.X} {obj.Y})";
 | 
			
		||||
        }
 | 
			
		||||
        if (this is MygisLineString)
 | 
			
		||||
        {
 | 
			
		||||
            var obj = this as MygisLineString;
 | 
			
		||||
            return obj?.PointCount > 0 ? $"LINESTRING({string.Join(",", obj.Select(a => $"{a.X} {a.Y}"))})" : null;
 | 
			
		||||
        }
 | 
			
		||||
        if (this is MygisPolygon)
 | 
			
		||||
        {
 | 
			
		||||
            var obj = (this as MygisPolygon).Where(z => z.Count() > 1 && z.First().Equals(z.Last()));
 | 
			
		||||
            return obj.Any() ? $"POLYGON(({string.Join("),(", obj.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))}))" : null;
 | 
			
		||||
        }
 | 
			
		||||
        if (this is MygisMultiPoint)
 | 
			
		||||
        {
 | 
			
		||||
            var obj = this as MygisMultiPoint;
 | 
			
		||||
            return obj?.PointCount > 0 ? $"MULTIPOINT({string.Join(",", obj.Select(a => $"{a.X} {a.Y}"))})" : null;
 | 
			
		||||
        }
 | 
			
		||||
        if (this is MygisMultiLineString)
 | 
			
		||||
        {
 | 
			
		||||
            var obj = this as MygisMultiLineString;
 | 
			
		||||
            return obj.LineCount > 0 ? $"MULTILINESTRING(({string.Join("),(", obj.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))}))" : null;
 | 
			
		||||
        }
 | 
			
		||||
        if (this is MygisMultiPolygon)
 | 
			
		||||
        {
 | 
			
		||||
            var obj = (this as MygisMultiPolygon)?.Where(z => z.Where(y => y.Count() > 1 && y.First().Equals(y.Last())).Any());
 | 
			
		||||
            return obj.Any() ? $"MULTIPOLYGON((({string.Join(")),((", obj.Select(d => string.Join("),(", d.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))))})))" : null;
 | 
			
		||||
        }
 | 
			
		||||
        return base.ToString();
 | 
			
		||||
    }
 | 
			
		||||
    static readonly Regex regexMygisPoint = new Regex(@"\s*(-?\d+\.?\d*)\s+(-?\d+\.?\d*)\s*");
 | 
			
		||||
    static readonly Regex regexSplit1 = new Regex(@"\)\s*,\s*\(");
 | 
			
		||||
    static readonly Regex regexSplit2 = new Regex(@"\)\s*\)\s*,\s*\(\s*\(");
 | 
			
		||||
    public static MygisGeometry Parse(string wkt)
 | 
			
		||||
    {
 | 
			
		||||
        if (string.IsNullOrEmpty(wkt)) return null;
 | 
			
		||||
        wkt = wkt.Trim();
 | 
			
		||||
        if (wkt.StartsWith("point", StringComparison.CurrentCultureIgnoreCase)) return ParsePoint(wkt.Substring(5).Trim('(', ')'));
 | 
			
		||||
        else if (wkt.StartsWith("linestring", StringComparison.CurrentCultureIgnoreCase)) return new MygisLineString(ParseLineString(wkt.Substring(10).Trim('(', ')')));
 | 
			
		||||
        else if (wkt.StartsWith("polygon", StringComparison.CurrentCultureIgnoreCase)) return new MygisPolygon(ParsePolygon(wkt.Substring(7).Trim('(', ')')));
 | 
			
		||||
        else if (wkt.StartsWith("multipoint", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiPoint(ParseLineString(wkt.Substring(10).Trim('(', ')')));
 | 
			
		||||
        else if (wkt.StartsWith("multilinestring", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiLineString(ParseMultiLineString(wkt.Substring(15).Trim('(', ')')));
 | 
			
		||||
        else if (wkt.StartsWith("multipolygon", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiPolygon(ParseMultiPolygon(wkt.Substring(12).Trim('(', ')')));
 | 
			
		||||
        throw new NotImplementedException($"MygisGeometry.Parse 未实现 \"{wkt}\"");
 | 
			
		||||
    }
 | 
			
		||||
    static MygisPoint ParsePoint(string str)
 | 
			
		||||
    {
 | 
			
		||||
        var m = regexMygisPoint.Match(str);
 | 
			
		||||
        if (m.Success == false) return null;
 | 
			
		||||
        return new MygisPoint(double.TryParse(m.Groups[1].Value, out var tryd) ? tryd : 0, double.TryParse(m.Groups[2].Value, out tryd) ? tryd : 0);
 | 
			
		||||
    }
 | 
			
		||||
    static MygisCoordinate2D[] ParseLineString(string str)
 | 
			
		||||
    {
 | 
			
		||||
        var ms = regexMygisPoint.Matches(str);
 | 
			
		||||
        var points = new MygisCoordinate2D[ms.Count];
 | 
			
		||||
        for (var a = 0; a < ms.Count; a++) points[a] = new MygisCoordinate2D(double.TryParse(ms[a].Groups[1].Value, out var tryd) ? tryd : 0, double.TryParse(ms[a].Groups[2].Value, out tryd) ? tryd : 0);
 | 
			
		||||
        return points;
 | 
			
		||||
    }
 | 
			
		||||
    static MygisCoordinate2D[][] ParsePolygon(string str)
 | 
			
		||||
    {
 | 
			
		||||
        return regexSplit1.Split(str).Select(s => ParseLineString(s)).Where(a => a.Length > 1 && a.First().Equals(a.Last())).ToArray();
 | 
			
		||||
    }
 | 
			
		||||
    static MygisLineString[] ParseMultiLineString(string str)
 | 
			
		||||
    {
 | 
			
		||||
        return regexSplit1.Split(str).Select(s => new MygisLineString(ParseLineString(s))).ToArray();
 | 
			
		||||
    }
 | 
			
		||||
    static MygisPolygon[] ParseMultiPolygon(string str)
 | 
			
		||||
    {
 | 
			
		||||
        return regexSplit2.Split(str).Select(s => new MygisPolygon(ParsePolygon(s))).ToArray();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class MygisPoint : MygisGeometry, IEquatable<MygisPoint> {
 | 
			
		||||
	MygisCoordinate2D _coord;
 | 
			
		||||
	protected override int GetLenHelper() => 16;
 | 
			
		||||
	public double X => _coord.X;
 | 
			
		||||
	public double Y => _coord.Y;
 | 
			
		||||
public class MygisPoint : MygisGeometry, IEquatable<MygisPoint>
 | 
			
		||||
{
 | 
			
		||||
    MygisCoordinate2D _coord;
 | 
			
		||||
    protected override int GetLenHelper() => 16;
 | 
			
		||||
    public double X => _coord.X;
 | 
			
		||||
    public double Y => _coord.Y;
 | 
			
		||||
 | 
			
		||||
	public MygisPoint(double x, double y) {
 | 
			
		||||
		_coord = new MygisCoordinate2D(x, y);
 | 
			
		||||
	}
 | 
			
		||||
    public MygisPoint(double x, double y)
 | 
			
		||||
    {
 | 
			
		||||
        _coord = new MygisCoordinate2D(x, y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public bool Equals(MygisPoint other) => !ReferenceEquals(other, null) && _coord.Equals(other._coord);
 | 
			
		||||
	public override bool Equals(object obj) => Equals(obj as MygisPoint);
 | 
			
		||||
	public static bool operator ==(MygisPoint x, MygisPoint y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
	public static bool operator !=(MygisPoint x, MygisPoint y) => !(x == y);
 | 
			
		||||
	public override int GetHashCode() => X.GetHashCode() ^ RotateShift(Y.GetHashCode(), sizeof(int) / 2);
 | 
			
		||||
    public bool Equals(MygisPoint other) => !ReferenceEquals(other, null) && _coord.Equals(other._coord);
 | 
			
		||||
    public override bool Equals(object obj) => Equals(obj as MygisPoint);
 | 
			
		||||
    public static bool operator ==(MygisPoint x, MygisPoint y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
    public static bool operator !=(MygisPoint x, MygisPoint y) => !(x == y);
 | 
			
		||||
    public override int GetHashCode() => X.GetHashCode() ^ RotateShift(Y.GetHashCode(), sizeof(int) / 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class MygisLineString : MygisGeometry, IEquatable<MygisLineString>, IEnumerable<MygisCoordinate2D> {
 | 
			
		||||
	readonly MygisCoordinate2D[] _points;
 | 
			
		||||
	protected override int GetLenHelper() => 4 + _points.Length * 16;
 | 
			
		||||
	public IEnumerator<MygisCoordinate2D> GetEnumerator() => ((IEnumerable<MygisCoordinate2D>) _points).GetEnumerator();
 | 
			
		||||
	IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
	public MygisCoordinate2D this[int index] => _points[index];
 | 
			
		||||
	public int PointCount => _points.Length;
 | 
			
		||||
public class MygisLineString : MygisGeometry, IEquatable<MygisLineString>, IEnumerable<MygisCoordinate2D>
 | 
			
		||||
{
 | 
			
		||||
    readonly MygisCoordinate2D[] _points;
 | 
			
		||||
    protected override int GetLenHelper() => 4 + _points.Length * 16;
 | 
			
		||||
    public IEnumerator<MygisCoordinate2D> GetEnumerator() => ((IEnumerable<MygisCoordinate2D>)_points).GetEnumerator();
 | 
			
		||||
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
    public MygisCoordinate2D this[int index] => _points[index];
 | 
			
		||||
    public int PointCount => _points.Length;
 | 
			
		||||
 | 
			
		||||
	public MygisLineString(IEnumerable<MygisCoordinate2D> points) {
 | 
			
		||||
		_points = points.ToArray();
 | 
			
		||||
	}
 | 
			
		||||
	public MygisLineString(MygisCoordinate2D[] points) {
 | 
			
		||||
		_points = points;
 | 
			
		||||
	}
 | 
			
		||||
    public MygisLineString(IEnumerable<MygisCoordinate2D> points)
 | 
			
		||||
    {
 | 
			
		||||
        _points = points.ToArray();
 | 
			
		||||
    }
 | 
			
		||||
    public MygisLineString(MygisCoordinate2D[] points)
 | 
			
		||||
    {
 | 
			
		||||
        _points = points;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public bool Equals(MygisLineString other) {
 | 
			
		||||
		if (ReferenceEquals(other, null)) return false;
 | 
			
		||||
		if (_points.Length != other._points.Length) return false;
 | 
			
		||||
		for (var i = 0; i < _points.Length; i++)
 | 
			
		||||
			if (!_points[i].Equals(other._points[i])) return false;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	public override bool Equals(object obj) => Equals(obj as MygisLineString);
 | 
			
		||||
	public static bool operator ==(MygisLineString x, MygisLineString y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
	public static bool operator !=(MygisLineString x, MygisLineString y) => !(x == y);
 | 
			
		||||
	public override int GetHashCode() {
 | 
			
		||||
		var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
 | 
			
		||||
		foreach (var t in _points) ret ^= RotateShift(t.GetHashCode(), ret % sizeof(int));
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
    public bool Equals(MygisLineString other)
 | 
			
		||||
    {
 | 
			
		||||
        if (ReferenceEquals(other, null)) return false;
 | 
			
		||||
        if (_points.Length != other._points.Length) return false;
 | 
			
		||||
        for (var i = 0; i < _points.Length; i++)
 | 
			
		||||
            if (!_points[i].Equals(other._points[i])) return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    public override bool Equals(object obj) => Equals(obj as MygisLineString);
 | 
			
		||||
    public static bool operator ==(MygisLineString x, MygisLineString y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
    public static bool operator !=(MygisLineString x, MygisLineString y) => !(x == y);
 | 
			
		||||
    public override int GetHashCode()
 | 
			
		||||
    {
 | 
			
		||||
        var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
 | 
			
		||||
        foreach (var t in _points) ret ^= RotateShift(t.GetHashCode(), ret % sizeof(int));
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class MygisPolygon : MygisGeometry, IEquatable<MygisPolygon>, IEnumerable<IEnumerable<MygisCoordinate2D>> {
 | 
			
		||||
	readonly MygisCoordinate2D[][] _rings;
 | 
			
		||||
	protected override int GetLenHelper() => 4 + _rings.Length * 4 + TotalPointCount * 16;
 | 
			
		||||
	public MygisCoordinate2D this[int ringIndex, int pointIndex] => _rings[ringIndex][pointIndex];
 | 
			
		||||
	public MygisCoordinate2D[] this[int ringIndex] => _rings[ringIndex];
 | 
			
		||||
	public IEnumerator<IEnumerable<MygisCoordinate2D>> GetEnumerator() => ((IEnumerable<IEnumerable<MygisCoordinate2D>>) _rings).GetEnumerator();
 | 
			
		||||
	IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
	public int RingCount => _rings.Length;
 | 
			
		||||
	public int TotalPointCount => _rings.Sum(r => r.Length);
 | 
			
		||||
public class MygisPolygon : MygisGeometry, IEquatable<MygisPolygon>, IEnumerable<IEnumerable<MygisCoordinate2D>>
 | 
			
		||||
{
 | 
			
		||||
    readonly MygisCoordinate2D[][] _rings;
 | 
			
		||||
    protected override int GetLenHelper() => 4 + _rings.Length * 4 + TotalPointCount * 16;
 | 
			
		||||
    public MygisCoordinate2D this[int ringIndex, int pointIndex] => _rings[ringIndex][pointIndex];
 | 
			
		||||
    public MygisCoordinate2D[] this[int ringIndex] => _rings[ringIndex];
 | 
			
		||||
    public IEnumerator<IEnumerable<MygisCoordinate2D>> GetEnumerator() => ((IEnumerable<IEnumerable<MygisCoordinate2D>>)_rings).GetEnumerator();
 | 
			
		||||
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
    public int RingCount => _rings.Length;
 | 
			
		||||
    public int TotalPointCount => _rings.Sum(r => r.Length);
 | 
			
		||||
 | 
			
		||||
	public MygisPolygon(MygisCoordinate2D[][] rings) {
 | 
			
		||||
		_rings = rings;
 | 
			
		||||
	}
 | 
			
		||||
	public MygisPolygon(IEnumerable<IEnumerable<MygisCoordinate2D>> rings) {
 | 
			
		||||
		_rings = rings.Select(x => x.ToArray()).ToArray();
 | 
			
		||||
	}
 | 
			
		||||
    public MygisPolygon(MygisCoordinate2D[][] rings)
 | 
			
		||||
    {
 | 
			
		||||
        _rings = rings;
 | 
			
		||||
    }
 | 
			
		||||
    public MygisPolygon(IEnumerable<IEnumerable<MygisCoordinate2D>> rings)
 | 
			
		||||
    {
 | 
			
		||||
        _rings = rings.Select(x => x.ToArray()).ToArray();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public bool Equals(MygisPolygon other) {
 | 
			
		||||
		if (ReferenceEquals(other, null)) return false;
 | 
			
		||||
		if (_rings.Length != other._rings.Length) return false;
 | 
			
		||||
		for (var i = 0; i < _rings.Length; i++) {
 | 
			
		||||
			if (_rings[i].Length != other._rings[i].Length) return false;
 | 
			
		||||
			for (var j = 0; j < _rings[i].Length; j++)
 | 
			
		||||
				if (!_rings[i][j].Equals(other._rings[i][j])) return false;
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	public override bool Equals(object obj) => Equals(obj as MygisPolygon);
 | 
			
		||||
	public static bool operator ==(MygisPolygon x, MygisPolygon y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
	public static bool operator !=(MygisPolygon x, MygisPolygon y) => !(x == y);
 | 
			
		||||
	public override int GetHashCode() {
 | 
			
		||||
		var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
 | 
			
		||||
		for (var i = 0; i < _rings.Length; i++)
 | 
			
		||||
			for (var j = 0; j < _rings[i].Length; j++)
 | 
			
		||||
				ret ^= RotateShift(_rings[i][j].GetHashCode(), ret % sizeof(int));
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
    public bool Equals(MygisPolygon other)
 | 
			
		||||
    {
 | 
			
		||||
        if (ReferenceEquals(other, null)) return false;
 | 
			
		||||
        if (_rings.Length != other._rings.Length) return false;
 | 
			
		||||
        for (var i = 0; i < _rings.Length; i++)
 | 
			
		||||
        {
 | 
			
		||||
            if (_rings[i].Length != other._rings[i].Length) return false;
 | 
			
		||||
            for (var j = 0; j < _rings[i].Length; j++)
 | 
			
		||||
                if (!_rings[i][j].Equals(other._rings[i][j])) return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    public override bool Equals(object obj) => Equals(obj as MygisPolygon);
 | 
			
		||||
    public static bool operator ==(MygisPolygon x, MygisPolygon y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
    public static bool operator !=(MygisPolygon x, MygisPolygon y) => !(x == y);
 | 
			
		||||
    public override int GetHashCode()
 | 
			
		||||
    {
 | 
			
		||||
        var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
 | 
			
		||||
        for (var i = 0; i < _rings.Length; i++)
 | 
			
		||||
            for (var j = 0; j < _rings[i].Length; j++)
 | 
			
		||||
                ret ^= RotateShift(_rings[i][j].GetHashCode(), ret % sizeof(int));
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class MygisMultiPoint : MygisGeometry, IEquatable<MygisMultiPoint>, IEnumerable<MygisCoordinate2D> {
 | 
			
		||||
	readonly MygisCoordinate2D[] _points;
 | 
			
		||||
	protected override int GetLenHelper() => 4 + _points.Length * 21;
 | 
			
		||||
	public IEnumerator<MygisCoordinate2D> GetEnumerator() => ((IEnumerable<MygisCoordinate2D>) _points).GetEnumerator();
 | 
			
		||||
	IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
	public MygisCoordinate2D this[int indexer] => _points[indexer];
 | 
			
		||||
	public int PointCount => _points.Length;
 | 
			
		||||
public class MygisMultiPoint : MygisGeometry, IEquatable<MygisMultiPoint>, IEnumerable<MygisCoordinate2D>
 | 
			
		||||
{
 | 
			
		||||
    readonly MygisCoordinate2D[] _points;
 | 
			
		||||
    protected override int GetLenHelper() => 4 + _points.Length * 21;
 | 
			
		||||
    public IEnumerator<MygisCoordinate2D> GetEnumerator() => ((IEnumerable<MygisCoordinate2D>)_points).GetEnumerator();
 | 
			
		||||
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
    public MygisCoordinate2D this[int indexer] => _points[indexer];
 | 
			
		||||
    public int PointCount => _points.Length;
 | 
			
		||||
 | 
			
		||||
	public MygisMultiPoint(MygisCoordinate2D[] points) {
 | 
			
		||||
		_points = points;
 | 
			
		||||
	}
 | 
			
		||||
	public MygisMultiPoint(IEnumerable<MygisPoint> points) {
 | 
			
		||||
		_points = points.Select(x => new MygisCoordinate2D(x.X, x.Y)).ToArray();
 | 
			
		||||
	}
 | 
			
		||||
	public MygisMultiPoint(IEnumerable<MygisCoordinate2D> points) {
 | 
			
		||||
		_points = points.ToArray();
 | 
			
		||||
	}
 | 
			
		||||
    public MygisMultiPoint(MygisCoordinate2D[] points)
 | 
			
		||||
    {
 | 
			
		||||
        _points = points;
 | 
			
		||||
    }
 | 
			
		||||
    public MygisMultiPoint(IEnumerable<MygisPoint> points)
 | 
			
		||||
    {
 | 
			
		||||
        _points = points.Select(x => new MygisCoordinate2D(x.X, x.Y)).ToArray();
 | 
			
		||||
    }
 | 
			
		||||
    public MygisMultiPoint(IEnumerable<MygisCoordinate2D> points)
 | 
			
		||||
    {
 | 
			
		||||
        _points = points.ToArray();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public bool Equals(MygisMultiPoint other) {
 | 
			
		||||
		if (ReferenceEquals(other, null)) return false;
 | 
			
		||||
		if (_points.Length != other._points.Length) return false;
 | 
			
		||||
		for (var i = 0; i < _points.Length; i++)
 | 
			
		||||
			if (!_points[i].Equals(other._points[i])) return false;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	public override bool Equals(object obj) => Equals(obj as MygisMultiPoint);
 | 
			
		||||
	public static bool operator ==(MygisMultiPoint x, MygisMultiPoint y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
	public static bool operator !=(MygisMultiPoint x, MygisMultiPoint y) => !(x == y);
 | 
			
		||||
	public override int GetHashCode() {
 | 
			
		||||
		var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
 | 
			
		||||
		for (var i = 0; i < _points.Length; i++) ret ^= RotateShift(_points[i].GetHashCode(), ret % sizeof(int));
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
    public bool Equals(MygisMultiPoint other)
 | 
			
		||||
    {
 | 
			
		||||
        if (ReferenceEquals(other, null)) return false;
 | 
			
		||||
        if (_points.Length != other._points.Length) return false;
 | 
			
		||||
        for (var i = 0; i < _points.Length; i++)
 | 
			
		||||
            if (!_points[i].Equals(other._points[i])) return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    public override bool Equals(object obj) => Equals(obj as MygisMultiPoint);
 | 
			
		||||
    public static bool operator ==(MygisMultiPoint x, MygisMultiPoint y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
    public static bool operator !=(MygisMultiPoint x, MygisMultiPoint y) => !(x == y);
 | 
			
		||||
    public override int GetHashCode()
 | 
			
		||||
    {
 | 
			
		||||
        var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
 | 
			
		||||
        for (var i = 0; i < _points.Length; i++) ret ^= RotateShift(_points[i].GetHashCode(), ret % sizeof(int));
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public sealed class MygisMultiLineString : MygisGeometry,
 | 
			
		||||
	IEquatable<MygisMultiLineString>, IEnumerable<MygisLineString> {
 | 
			
		||||
	readonly MygisLineString[] _lineStrings;
 | 
			
		||||
	protected override int GetLenHelper() {
 | 
			
		||||
		var n = 4;
 | 
			
		||||
		for (var i = 0; i < _lineStrings.Length; i++) n += _lineStrings[i].GetLen(false);
 | 
			
		||||
		return n;
 | 
			
		||||
	}
 | 
			
		||||
	public IEnumerator<MygisLineString> GetEnumerator() => ((IEnumerable<MygisLineString>) _lineStrings).GetEnumerator();
 | 
			
		||||
	IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
	public MygisLineString this[int index] => _lineStrings[index];
 | 
			
		||||
	public int LineCount => _lineStrings.Length;
 | 
			
		||||
    IEquatable<MygisMultiLineString>, IEnumerable<MygisLineString>
 | 
			
		||||
{
 | 
			
		||||
    readonly MygisLineString[] _lineStrings;
 | 
			
		||||
    protected override int GetLenHelper()
 | 
			
		||||
    {
 | 
			
		||||
        var n = 4;
 | 
			
		||||
        for (var i = 0; i < _lineStrings.Length; i++) n += _lineStrings[i].GetLen(false);
 | 
			
		||||
        return n;
 | 
			
		||||
    }
 | 
			
		||||
    public IEnumerator<MygisLineString> GetEnumerator() => ((IEnumerable<MygisLineString>)_lineStrings).GetEnumerator();
 | 
			
		||||
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
    public MygisLineString this[int index] => _lineStrings[index];
 | 
			
		||||
    public int LineCount => _lineStrings.Length;
 | 
			
		||||
 | 
			
		||||
	internal MygisMultiLineString(MygisCoordinate2D[][] pointArray) {
 | 
			
		||||
		_lineStrings = new MygisLineString[pointArray.Length];
 | 
			
		||||
		for (var i = 0; i < pointArray.Length; i++)
 | 
			
		||||
			_lineStrings[i] = new MygisLineString(pointArray[i]);
 | 
			
		||||
	}
 | 
			
		||||
	public MygisMultiLineString(MygisLineString[] linestrings) {
 | 
			
		||||
		_lineStrings = linestrings;
 | 
			
		||||
	}
 | 
			
		||||
	public MygisMultiLineString(IEnumerable<MygisLineString> linestrings) {
 | 
			
		||||
		_lineStrings = linestrings.ToArray();
 | 
			
		||||
	}
 | 
			
		||||
	public MygisMultiLineString(IEnumerable<IEnumerable<MygisCoordinate2D>> pointList) {
 | 
			
		||||
		_lineStrings = pointList.Select(x => new MygisLineString(x)).ToArray();
 | 
			
		||||
	}
 | 
			
		||||
    internal MygisMultiLineString(MygisCoordinate2D[][] pointArray)
 | 
			
		||||
    {
 | 
			
		||||
        _lineStrings = new MygisLineString[pointArray.Length];
 | 
			
		||||
        for (var i = 0; i < pointArray.Length; i++)
 | 
			
		||||
            _lineStrings[i] = new MygisLineString(pointArray[i]);
 | 
			
		||||
    }
 | 
			
		||||
    public MygisMultiLineString(MygisLineString[] linestrings)
 | 
			
		||||
    {
 | 
			
		||||
        _lineStrings = linestrings;
 | 
			
		||||
    }
 | 
			
		||||
    public MygisMultiLineString(IEnumerable<MygisLineString> linestrings)
 | 
			
		||||
    {
 | 
			
		||||
        _lineStrings = linestrings.ToArray();
 | 
			
		||||
    }
 | 
			
		||||
    public MygisMultiLineString(IEnumerable<IEnumerable<MygisCoordinate2D>> pointList)
 | 
			
		||||
    {
 | 
			
		||||
        _lineStrings = pointList.Select(x => new MygisLineString(x)).ToArray();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public bool Equals(MygisMultiLineString other) {
 | 
			
		||||
		if (ReferenceEquals(other, null)) return false;
 | 
			
		||||
		if (_lineStrings.Length != other._lineStrings.Length) return false;
 | 
			
		||||
		for (var i = 0; i < _lineStrings.Length; i++)
 | 
			
		||||
			if (_lineStrings[i] != other._lineStrings[i]) return false;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	public override bool Equals(object obj) => Equals(obj as MygisMultiLineString);
 | 
			
		||||
	public static bool operator ==(MygisMultiLineString x, MygisMultiLineString y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
	public static bool operator !=(MygisMultiLineString x, MygisMultiLineString y) => !(x == y);
 | 
			
		||||
	public override int GetHashCode() {
 | 
			
		||||
		var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
 | 
			
		||||
		for (var i = 0; i < _lineStrings.Length; i++) ret ^= RotateShift(_lineStrings[i].GetHashCode(), ret % sizeof(int));
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
    public bool Equals(MygisMultiLineString other)
 | 
			
		||||
    {
 | 
			
		||||
        if (ReferenceEquals(other, null)) return false;
 | 
			
		||||
        if (_lineStrings.Length != other._lineStrings.Length) return false;
 | 
			
		||||
        for (var i = 0; i < _lineStrings.Length; i++)
 | 
			
		||||
            if (_lineStrings[i] != other._lineStrings[i]) return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    public override bool Equals(object obj) => Equals(obj as MygisMultiLineString);
 | 
			
		||||
    public static bool operator ==(MygisMultiLineString x, MygisMultiLineString y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
    public static bool operator !=(MygisMultiLineString x, MygisMultiLineString y) => !(x == y);
 | 
			
		||||
    public override int GetHashCode()
 | 
			
		||||
    {
 | 
			
		||||
        var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
 | 
			
		||||
        for (var i = 0; i < _lineStrings.Length; i++) ret ^= RotateShift(_lineStrings[i].GetHashCode(), ret % sizeof(int));
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class MygisMultiPolygon : MygisGeometry, IEquatable<MygisMultiPolygon>, IEnumerable<MygisPolygon> {
 | 
			
		||||
	readonly MygisPolygon[] _polygons;
 | 
			
		||||
	protected override int GetLenHelper() {
 | 
			
		||||
		var n = 4;
 | 
			
		||||
		for (var i = 0; i < _polygons.Length; i++) n += _polygons[i].GetLen(false);
 | 
			
		||||
		return n;
 | 
			
		||||
	}
 | 
			
		||||
	public IEnumerator<MygisPolygon> GetEnumerator() => ((IEnumerable<MygisPolygon>) _polygons).GetEnumerator();
 | 
			
		||||
	IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
	public MygisPolygon this[int index] => _polygons[index];
 | 
			
		||||
	public int PolygonCount => _polygons.Length;
 | 
			
		||||
public class MygisMultiPolygon : MygisGeometry, IEquatable<MygisMultiPolygon>, IEnumerable<MygisPolygon>
 | 
			
		||||
{
 | 
			
		||||
    readonly MygisPolygon[] _polygons;
 | 
			
		||||
    protected override int GetLenHelper()
 | 
			
		||||
    {
 | 
			
		||||
        var n = 4;
 | 
			
		||||
        for (var i = 0; i < _polygons.Length; i++) n += _polygons[i].GetLen(false);
 | 
			
		||||
        return n;
 | 
			
		||||
    }
 | 
			
		||||
    public IEnumerator<MygisPolygon> GetEnumerator() => ((IEnumerable<MygisPolygon>)_polygons).GetEnumerator();
 | 
			
		||||
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 | 
			
		||||
    public MygisPolygon this[int index] => _polygons[index];
 | 
			
		||||
    public int PolygonCount => _polygons.Length;
 | 
			
		||||
 | 
			
		||||
	public MygisMultiPolygon(MygisPolygon[] polygons) {
 | 
			
		||||
		_polygons = polygons;
 | 
			
		||||
	}
 | 
			
		||||
	public MygisMultiPolygon(IEnumerable<MygisPolygon> polygons) {
 | 
			
		||||
		_polygons = polygons.ToArray();
 | 
			
		||||
	}
 | 
			
		||||
	public MygisMultiPolygon(IEnumerable<IEnumerable<IEnumerable<MygisCoordinate2D>>> ringList) {
 | 
			
		||||
		_polygons = ringList.Select(x => new MygisPolygon(x)).ToArray();
 | 
			
		||||
	}
 | 
			
		||||
    public MygisMultiPolygon(MygisPolygon[] polygons)
 | 
			
		||||
    {
 | 
			
		||||
        _polygons = polygons;
 | 
			
		||||
    }
 | 
			
		||||
    public MygisMultiPolygon(IEnumerable<MygisPolygon> polygons)
 | 
			
		||||
    {
 | 
			
		||||
        _polygons = polygons.ToArray();
 | 
			
		||||
    }
 | 
			
		||||
    public MygisMultiPolygon(IEnumerable<IEnumerable<IEnumerable<MygisCoordinate2D>>> ringList)
 | 
			
		||||
    {
 | 
			
		||||
        _polygons = ringList.Select(x => new MygisPolygon(x)).ToArray();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public bool Equals(MygisMultiPolygon other) {
 | 
			
		||||
		if (ReferenceEquals(other, null)) return false;
 | 
			
		||||
		if (_polygons.Length != other._polygons.Length) return false;
 | 
			
		||||
		for (var i = 0; i < _polygons.Length; i++) if (_polygons[i] != other._polygons[i]) return false;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	public override bool Equals(object obj) => obj is MygisMultiPolygon && Equals((MygisMultiPolygon) obj);
 | 
			
		||||
	public static bool operator ==(MygisMultiPolygon x, MygisMultiPolygon y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
	public static bool operator !=(MygisMultiPolygon x, MygisMultiPolygon y) => !(x == y);
 | 
			
		||||
	public override int GetHashCode() {
 | 
			
		||||
		var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
 | 
			
		||||
		for (var i = 0; i < _polygons.Length; i++) ret ^= RotateShift(_polygons[i].GetHashCode(), ret % sizeof(int));
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
    public bool Equals(MygisMultiPolygon other)
 | 
			
		||||
    {
 | 
			
		||||
        if (ReferenceEquals(other, null)) return false;
 | 
			
		||||
        if (_polygons.Length != other._polygons.Length) return false;
 | 
			
		||||
        for (var i = 0; i < _polygons.Length; i++) if (_polygons[i] != other._polygons[i]) return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    public override bool Equals(object obj) => obj is MygisMultiPolygon && Equals((MygisMultiPolygon)obj);
 | 
			
		||||
    public static bool operator ==(MygisMultiPolygon x, MygisMultiPolygon y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
 | 
			
		||||
    public static bool operator !=(MygisMultiPolygon x, MygisMultiPolygon y) => !(x == y);
 | 
			
		||||
    public override int GetHashCode()
 | 
			
		||||
    {
 | 
			
		||||
        var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
 | 
			
		||||
        for (var i = 0; i < _polygons.Length; i++) ret ^= RotateShift(_polygons[i].GetHashCode(), ret % sizeof(int));
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,18 +6,20 @@ using System.Drawing;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
public static partial class MygisTypesExtensions {
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// 测量两个经纬度的距离,返回单位:米
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	/// <param name="that">经纬坐标1</param>
 | 
			
		||||
	/// <param name="point">经纬坐标2</param>
 | 
			
		||||
	/// <returns>返回距离(单位:米)</returns>
 | 
			
		||||
	public static double Distance(this MygisPoint that, MygisPoint point) {
 | 
			
		||||
		double radLat1 = (double)(that.Y) * Math.PI / 180d;
 | 
			
		||||
		double radLng1 = (double)(that.X) * Math.PI / 180d;
 | 
			
		||||
		double radLat2 = (double)(point.Y) * Math.PI / 180d;
 | 
			
		||||
		double radLng2 = (double)(point.X) * Math.PI / 180d;
 | 
			
		||||
		return 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin((radLat1 - radLat2) / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin((radLng1 - radLng2) / 2), 2))) * 6378137;
 | 
			
		||||
	}
 | 
			
		||||
public static partial class MygisTypesExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测量两个经纬度的距离,返回单位:米
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="that">经纬坐标1</param>
 | 
			
		||||
    /// <param name="point">经纬坐标2</param>
 | 
			
		||||
    /// <returns>返回距离(单位:米)</returns>
 | 
			
		||||
    public static double Distance(this MygisPoint that, MygisPoint point)
 | 
			
		||||
    {
 | 
			
		||||
        double radLat1 = (double)(that.Y) * Math.PI / 180d;
 | 
			
		||||
        double radLng1 = (double)(that.X) * Math.PI / 180d;
 | 
			
		||||
        double radLat2 = (double)(point.Y) * Math.PI / 180d;
 | 
			
		||||
        double radLng2 = (double)(point.X) * Math.PI / 180d;
 | 
			
		||||
        return 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin((radLat1 - radLat2) / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin((radLng1 - radLng2) / 2), 2))) * 6378137;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user