mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-06-19 12:28:15 +08:00
拆分 FreeSql 按需引用
This commit is contained in:
63
Providers/FreeSql.Provider.MySql/MySqlAdo/MySqlAdo.cs
Normal file
63
Providers/FreeSql.Provider.MySql/MySqlAdo/MySqlAdo.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using FreeSql.Internal;
|
||||
using MySql.Data.MySqlClient;
|
||||
using SafeObjectPool;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
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("'", "''"), "'");
|
||||
}
|
||||
|
||||
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 DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
|
||||
}
|
||||
}
|
177
Providers/FreeSql.Provider.MySql/MySqlAdo/MySqlConnectionPool.cs
Normal file
177
Providers/FreeSql.Provider.MySql/MySqlAdo/MySqlConnectionPool.cs
Normal file
@ -0,0 +1,177 @@
|
||||
using MySql.Data.MySqlClient;
|
||||
using SafeObjectPool;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.MySql {
|
||||
|
||||
class MySqlConnectionPool : ObjectPool<DbConnection> {
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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}";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 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 OnGet(Object<DbConnection> obj) {
|
||||
|
||||
if (_pool.IsAvailable) {
|
||||
|
||||
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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async public Task OnGetAsync(Object<DbConnection> obj) {
|
||||
|
||||
if (_pool.IsAvailable) {
|
||||
|
||||
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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGetTimeout() {
|
||||
|
||||
}
|
||||
|
||||
public void OnReturn(Object<DbConnection> obj) {
|
||||
|
||||
}
|
||||
|
||||
public void OnAvailable() {
|
||||
_pool.availableHandler?.Invoke();
|
||||
}
|
||||
|
||||
public void OnUnavailable() {
|
||||
_pool.unavailableHandler?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
292
Providers/FreeSql.Provider.MySql/MySqlAdo/MygisTypes.cs
Normal file
292
Providers/FreeSql.Provider.MySql/MySqlAdo/MygisTypes.cs
Normal file
@ -0,0 +1,292 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
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 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 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 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 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 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 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 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 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;
|
||||
|
||||
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 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 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user