using System; using System.Collections.Generic; using System.Text; using CommonLang.IO; using CommonLang.ByteOrder; using CommonLang; namespace CommonLang.Vector { public interface IPosBase { float X { get; } float Y { get; } } public interface IVector2 : IPosBase { void SetX(float value); void SetY(float value); void AddX(float value); void AddY(float value); } public interface IRoundObject : IVector2 { //float X { get; set; } //float Y { get; set; } /// /// 半径 /// float RadiusSize { get; } } public interface IPositionObject : IPosBase { /// /// 方向 /// float Direction { get; } /// /// 半径 /// float RadiusSize { get; } } /// /// 2D向量 /// public class Vector2 : IVector2, ICloneable { private float x; private float y; public float X { get { return this.x; } } public float Y { get { return this.y; } } public void SetX(float value) { this.x = value; } public void SetY(float value) { this.y = value; } public void AddX(float value) { this.x += value; } public void AddY(float value) { this.y += value; } public Vector2() { this.x = 0; this.y = 0; } public Vector2(float _x, float _y) { this.x = _x; this.y = _y; } public object Clone() { return new Vector2(x, y); } public override bool Equals(object obj) { if (obj is Vector2) { Vector2 v = (Vector2)obj; return X == v.X && Y == v.Y; } return false; } public bool Equals(Vector2 v) { return v.x == x && v.y == y; } public static bool Equals(Vector2 a, Vector2 b) { if (a != null && b != null) { return a.x == b.x && a.y == b.y; } return a == b; } public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); } public override string ToString() { return X + ", " + Y; } public string ToString(bool rounded) { if (rounded) { return (int)Math.Round(X) + ", " + (int)Math.Round(Y); } else { return ToString(); } } public static Vector2 operator *(Vector2 value1, float value2) { value1.SetX(value1.X * value2); value1.SetY(value1.Y * value2); return value1; } #region IExternalizable 成员 public void WriteExternal(IOutputStream output) { output.PutF32(x); output.PutF32(y); } public void ReadExternal(IInputStream input) { this.x = input.GetF32(); this.y = input.GetF32(); } #endregion } /// /// 2D向量 /// public struct TVector2 : IVector2 { public static readonly TVector2 Zero = new TVector2(0, 0); private float x; private float y; public float X { get { return this.x; } } public float Y { get { return this.y; } } public void SetX(float value) { this.x = value; } public void SetY(float value) { this.y = value; } public void AddX(float value) { this.x += value; } public void AddY(float value) { this.y += value; } public TVector2(float _x, float _y) { this.x = _x; this.y = _y; } public override bool Equals(object obj) { if (obj is Vector2) { Vector2 v = (Vector2)obj; return X == v.X && Y == v.Y; } return false; } public bool Equals(IVector2 v) { return v.X == X && v.Y == Y; } public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); } public override string ToString() { return X + ", " + Y; } public string ToString(bool rounded) { if (rounded) { return (int)Math.Round(X) + ", " + (int)Math.Round(Y); } else { return ToString(); } } #region IExternalizable 成员 public void WriteExternal(IOutputStream output) { output.PutF32(x); output.PutF32(y); } public void ReadExternal(IInputStream input) { this.x = input.GetF32(); this.y = input.GetF32(); } #endregion public float Magnitude { get { return (float)Math.Sqrt(X * X + Y * Y); } } public void Normalize() { float magnitude = Magnitude; this.x = X / magnitude; this.y = Y / magnitude; } public TVector2 GetNormalized() { float magnitude = Magnitude; return new TVector2(X / magnitude, Y / magnitude); } public float DotProduct(TVector2 vector) { return this.X * vector.X + this.Y * vector.Y; } public float DistanceTo(TVector2 vector) { return (float)Math.Sqrt(Math.Pow(vector.X - this.X, 2) + Math.Pow(vector.Y - this.Y, 2)); } public static TVector2 operator +(TVector2 a, TVector2 b) { return new TVector2(a.X + b.X, a.Y + b.Y); } public static TVector2 operator -(TVector2 a) { return new TVector2(-a.X, -a.Y); } public static TVector2 operator -(TVector2 a, TVector2 b) { return new TVector2(a.X - b.X, a.Y - b.Y); } public static TVector2 operator *(TVector2 a, float b) { return new TVector2(a.X * b, a.Y * b); } public static TVector2 operator *(TVector2 a, int b) { return new TVector2(a.X * b, a.Y * b); } public static TVector2 operator *(TVector2 a, double b) { return new TVector2((float)(a.X * b), (float)(a.Y * b)); } } /// /// 2D极坐标向量 /// public class Polar2 : ICloneable { public float direction; public float distance; public Polar2() { } public Polar2(float _direction, float _distance) { this.direction = _direction; this.distance = _distance; } public bool Equals(Polar2 v) { return v.direction == this.direction && v.distance == this.distance; } public object Clone() { return new Polar2(direction, distance); } #region IExternalizable 成员 public void WriteExternal(IOutputStream output) { output.PutF32(direction); output.PutF32(distance); } public void ReadExternal(IInputStream input) { this.direction = input.GetF32(); this.distance = input.GetF32(); } #endregion } public struct TPolar2 { public float direction; public float distance; public TPolar2(float _direction, float _distance) { this.direction = _direction; this.distance = _distance; } public bool Equals(TPolar2 v) { return v.direction == this.direction && v.distance == this.distance; } #region IExternalizable 成员 public void WriteExternal(IOutputStream output) { output.PutF32(direction); output.PutF32(distance); } public void ReadExternal(IInputStream input) { this.direction = input.GetF32(); this.distance = input.GetF32(); } #endregion } public class Line2 : ICloneable { readonly public Vector2 p = new Vector2(); readonly public Vector2 q = new Vector2(); public Line2() { } public Line2(float x0, float y0, float x1, float y1) { p.SetX(x0); p.SetY(y0); q.SetX(x1); q.SetY(y1); } public float getMinX() { return Math.Min(p.X, q.X); } public float getMaxX() { return Math.Max(p.X, q.X); } public float getMinY() { return Math.Min(p.Y, q.Y); } public float getMaxY() { return Math.Max(p.Y, q.Y); } public object Clone() { return new Line2(p.X, p.Y, q.X, q.Y); } #region IExternalizable 成员 public void WriteExternal(IOutputStream output) { output.PutF32(p.X); output.PutF32(p.Y); output.PutF32(q.X); output.PutF32(q.Y); } public void ReadExternal(IInputStream input) { p.SetX(input.GetF32()); p.SetY(input.GetF32()); q.SetX(input.GetF32()); q.SetY(input.GetF32()); } #endregion } public struct TLine2 { public TVector2 p; public TVector2 q; public TLine2(float x0, float y0, float x1, float y1) { p = new TVector2(); q = new TVector2(); p.SetX(x0); p.SetY(y0); q.SetX(x1); q.SetY(y1); } public float getMinX() { return Math.Min(p.X, q.X); } public float getMaxX() { return Math.Max(p.X, q.X); } public float getMinY() { return Math.Min(p.Y, q.Y); } public float getMaxY() { return Math.Max(p.Y, q.Y); } #region IExternalizable 成员 public void WriteExternal(IOutputStream output) { output.PutF32(p.X); output.PutF32(p.Y); output.PutF32(q.X); output.PutF32(q.Y); } public void ReadExternal(IInputStream input) { p.SetX(input.GetF32()); p.SetY(input.GetF32()); q.SetX(input.GetF32()); q.SetY(input.GetF32()); } #endregion } public static class MathVector { /** * 移动指定偏移 * @param v * @param dx x距离 * @param dy y距离 */ public static void move(IVector2 v, float dx, float dy) { v.AddX(dx); v.AddY(dy); } /** * 通过极坐标来移动 * @param v * @param degree 弧度 * @param distance 距离 */ public static void movePolar(IVector2 v, float degree, float distance) { float dx = (float)(Math.Cos(degree) * distance); float dy = (float)(Math.Sin(degree) * distance); move(v, dx, dy); } public static void movePolar(ref float x, ref float y, float degree, float distance) { x += (float)(Math.Cos(degree) * distance); y += (float)(Math.Sin(degree) * distance); } public static void movePolarExt(ref Vector2 pos, float degree, float distance) { pos.AddX((float)(Math.Cos(degree) * distance)); pos.AddY((float)(Math.Sin(degree) * distance)); } public static void movePolarExt(ref TVector2 pos, float degree, float distance) { pos.AddX((float)(Math.Cos(degree) * distance)); pos.AddY((float)(Math.Sin(degree) * distance)); } /** * 通过极坐标来移动 * @param v * @param degree 弧度 * @param speed 速度 (单位距离/秒) * @param interval_ms 毫秒时间 */ public static void movePolar(IVector2 v, float degree, float speed, float interval_ms) { float distance = getDistanceSpeedTime(speed, interval_ms); movePolar(v, degree, distance); } public static void movePolar(ref float x, ref float y, float degree, float speed, float interval_ms) { float distance = getDistanceSpeedTime(speed, interval_ms); movePolar(ref x, ref y, degree, distance); } public static void movePolar(ref Vector2 pos, float degree, float speed, float interval_ms) { float distance = getDistanceSpeedTime(speed, interval_ms); movePolarExt(ref pos, degree, distance); } /** * 向目标移动 * @param v * @param x 目标x * @param y 目标y * @return 是否到达目的地 */ public static bool moveTo(IVector2 v, float dx, float dy, float distance) { float ddx = dx - v.X; float ddy = dy - v.Y; if (Math.Abs(ddx) < distance && Math.Abs(ddy) < distance) { v.SetX(dx); v.SetY(dy); return true; } else { float angle = (float)Math.Atan2(ddy, ddx); movePolar(v, angle, distance); return false; } } public static bool moveTo(ref float x, ref float y, float dx, float dy, float distance) { float ddx = dx - x; float ddy = dy - y; if (Math.Abs(ddx) < distance && Math.Abs(ddy) < distance) { x = (dx); y = (dy); return true; } else { float angle = (float)Math.Atan2(ddy, ddx); movePolar(ref x, ref y, angle, distance); return false; } } public static bool moveToX(IVector2 v, float x, float distance) { float ddx = x - v.X; if (Math.Abs(ddx) < distance) { v.SetX(x); return true; } else { if (ddx > 0) { v.AddX(distance); } else { v.AddX(-distance); } return false; } } public static bool moveToY(IVector2 v, float y, float distance) { float ddy = y - v.Y; if (Math.Abs(ddy) < distance) { v.SetY(y); return true; } else { if (ddy > 0) { v.AddY(distance); } else { v.AddY(-distance); } return false; } } public static void scale(IVector2 v, float scale) { v.SetX(v.X * scale); v.SetY(v.Y * scale); } public static void scale(IVector2 v, float scale_x, float scale_y) { v.SetX(v.X * scale_x); v.SetY(v.Y * scale_y); } public static void scale(ref float x, ref float y, float scale_x, float scale_y) { x = (x * scale_x); y = (y * scale_y); } public static void rotate(IVector2 v, float degree) { float cos_v = (float)Math.Cos(degree); float sin_v = (float)Math.Sin(degree); float x = (v.X) * cos_v - (v.Y) * sin_v; float y = (v.Y) * cos_v + (v.X) * sin_v; v.SetX(x); v.SetY(y); } public static void rotate(IVector2 v, IVector2 p0, float degree) { float dx = v.X - p0.X; float dy = v.Y - p0.Y; float cos_v = (float)Math.Cos(degree); float sin_v = (float)Math.Sin(degree); float x = p0.X + dx * cos_v - dy * sin_v; float y = p0.Y + dy * cos_v + dx * sin_v; v.SetX(x); v.SetY(y); } public static void rotate(IVector2 v, float px, float py, float degree) { float dx = v.X - px; float dy = v.Y - py; float cos_v = (float)Math.Cos(degree); float sin_v = (float)Math.Sin(degree); float x = px + dx * cos_v - dy * sin_v; float y = py + dy * cos_v + dx * sin_v; v.SetX(x); v.SetY(y); } public static void rotate(ref float x, ref float y, float px, float py, float degree) { float dx = x - px; float dy = y - py; float cos_v = (float)Math.Cos(degree); float sin_v = (float)Math.Sin(degree); float rx = px + dx * cos_v - dy * sin_v; float ry = py + dy * cos_v + dx * sin_v; x = (rx); y = (ry); } public static float getDirection(float d) { if (d > 0) { return 1; } if (d < 0) { return -1; } return 0; } /** * 得到速度和时间产生的距离 * @param speed 速度 (单位距离/秒) * @param interval_ms 毫秒时间 * @return */ public static float getDistanceSpeedTime(float speed, float interval_ms) { float rate = interval_ms / 1000f; return speed * rate; } public static float getDistance(float x1, float y1, float x2, float y2) { float r1 = x1 - x2; float r2 = y1 - y2; return (float)Math.Sqrt(r1 * r1 + r2 * r2); } public static float getDistanceSquare(float x1, float y1, float x2, float y2) { float r1 = x1 - x2; float r2 = y1 - y2; return r1 * r1 + r2 * r2; } public static float getDistance(IVector2 v1, IVector2 v2) { float r1 = v1.X - v2.X; float r2 = v1.Y - v2.Y; return (float)Math.Sqrt(r1 * r1 + r2 * r2); } public static float getDistanceSquare(IVector2 v1, IVector2 v2) { float r1 = v1.X - v2.X; float r2 = v1.Y - v2.Y; return (r1 * r1 + r2 * r2); } /// /// 得到弧度 /// /// x向量 /// y向量 /// public static float getDegree(float dx, float dy) { return (float)Math.Atan2(dy, dx); } /// /// /// /// /// /// /// /// public static float getDegree(float x1, float y1, float x2, float y2) { return (float)Math.Atan2(y2 - y1, x2 - x1); } /** * 得到弧度 * @param v 向量 * @return */ public static float getDegree(IVector2 v) { return (float)Math.Atan2(v.Y, v.X); } public static float getDegree(IVector2 a, IVector2 b) { return (float)Math.Atan2(b.Y - a.Y, b.X - a.X); } /** * 将2个向量相加得到一个新的向量 * @param a * @param b * @return */ public static Vector2 vectorAdd(IVector2 a, IVector2 b) { Vector2 v = new Vector2(); v.SetX(a.X + b.X); v.SetY(a.Y + b.Y); return v; } /** * 将2个向量相减得到一个新的向量 * @param a * @param b * @return */ public static Vector2 vectorSub(IVector2 a, IVector2 b) { Vector2 v = new Vector2(); v.SetX(a.X - b.X); v.SetY(a.Y - b.Y); return v; } /** * 将一个向量加上新的向量,得到一个新的向量 * @param a * @param degree * @param distance * @return */ public static Vector2 vectorAdd(IVector2 a, float degree, float distance) { Vector2 v = new Vector2(); v.SetX(a.X); v.SetY(a.Y); movePolar(v, degree, distance); return v; } /** * 把一个向量向自己本身的方向相加,得到一个新的向量 * @param a * @param distance * @return */ public static Vector2 vectorAdd(IVector2 a, float distance) { Vector2 v = new Vector2(); v.SetX(a.X); v.SetY(a.Y); movePolar(v, getDegree(v), distance); return v; } /** * 将一个向量缩放一定比率后,得到一个新的向量 * @param a * @param scale * @return */ public static Vector2 vectorScale(IVector2 a, float scale) { Vector2 v = new Vector2(); v.SetX(a.X * scale); v.SetY(a.Y * scale); return v; } public static float vectorDot(IVector2 v1, IVector2 v2) { return v1.X * v2.X + v1.Y * v2.Y; } public static float vectorDot(float x1, float y1, float x2, float y2) { return x1 * x2 + y1 * y2; } /// /// 挤压移动单位,某个单位在集合中移动,碰撞并挤开其他单位 /// /// /// /// /// /// /// public static void moveImpact(ICollection vectors, IRoundObject obj, float angle, float distance, int depth, int max_depth) { float dx = (float)(Math.Cos(angle) * distance); float dy = (float)(Math.Sin(angle) * distance); obj.AddX(dx); obj.AddY(dy); if (depth < max_depth) { foreach (IRoundObject o in vectors) { if (!o.Equals(obj)) { float dr = MathVector.getDistance(o, obj) - o.RadiusSize - obj.RadiusSize; if (dr < 0) { float ta = MathVector.getDegree(obj.X, obj.Y, o.X, o.Y); moveImpact(vectors, o, ta, -dr, depth + 1, max_depth); } } } } } } public static class VectorGroupHelper { public static void GetCenterOf(ICollection vectors, out float cx, out float cy) where T : IVector2 { if (vectors.Count == 0) { cx = 0; cy = 0; } else { float min_x = float.MaxValue; float max_x = float.MinValue; float min_y = float.MaxValue; float max_y = float.MinValue; foreach (T a in vectors) { min_x = Math.Min(min_x, a.X); max_x = Math.Max(max_x, a.X); min_y = Math.Min(min_y, a.Y); max_y = Math.Max(max_y, a.Y); } cx = min_x + (max_x - min_x) / 2f; cy = min_y + (max_y - min_y) / 2f; } } public static void MoveImpactInner(ICollection vectors, T obj, float spacing_size, float angle, float distance, int depth, int max_depth) where T : IVector2 { float dx = (float)(Math.Cos(angle) * distance); float dy = (float)(Math.Sin(angle) * distance); obj.AddX(dx); obj.AddY(dy); if (depth < max_depth) { float dr2 = spacing_size * 2; foreach (T o in vectors) { if (!o.Equals(obj)) { float dr = MathVector.getDistance(o, obj) - dr2; if (dr < 0) { float ta = MathVector.getDegree(obj.X, obj.Y, o.X, o.Y); MoveImpactInner(vectors, o, spacing_size, ta, -dr, depth + 1, max_depth); } } } } } /// /// 随机调整每个点, /// 使得距离都最小保持在spacing_size /// public static void DistributeSpacingSizeRandom(IVector2 center, ICollection vectors, float spacing_size, Random random) where T : IVector2 { foreach (T o in vectors) { MoveImpactInner(vectors, o, spacing_size, (float)(random.NextDouble() * CMath.PI_MUL_2), 0, 0, 1); } } /// /// 按正方形调整每个点, /// 使得距离都最小保持在spacing_size /// public static void DistributeSpacingSizeSquare(IVector2 center, ICollection vectors, float spacing_size) where T : IVector2 { float cx = center.X; float cy = center.Y; int row_count = (int)Math.Round(Math.Sqrt(vectors.Count)); //GetCenterOf(vectors, out cx, out cy); float sx = cx - (row_count - 1) * spacing_size / 2; float sy = cy - (vectors.Count / row_count - 1) * spacing_size / 2; int i = 0; foreach (T o in vectors) { int x = i % row_count; int y = i / row_count; o.SetX(sx + x * spacing_size); o.SetY(sy + y * spacing_size); i++; } } /// /// 按圆形调整每个点, /// 使得距离都最小保持在spacing_size /// public static void DistributeSpacingSizeRound(IVector2 center, ICollection vectors, float spacing_size) where T : IVector2 { float cx = center.X; float cy = center.Y; int count = vectors.Count; T[] array = new T[count]; vectors.CopyTo(array, 0); int cycle = 0; int i = 0; while (i < count) { if (i == 0) { array[i].SetX(cx); array[i].SetY(cy); i++; } else { float cr = spacing_size * cycle; float clen = cr * 2 * CMath.PI_F; int ccount = (int)(clen / spacing_size); float cangle = CMath.PI_MUL_2 / ccount; for (int j = 0; (j < ccount) && (i < count); j++) { float da = cangle * j; array[i].SetX(cx + (float)Math.Cos(da) * cr); array[i].SetY(cy + (float)Math.Sin(da) * cr); i++; } } cycle++; } } /// /// 按环形调整每个点, /// 使得距离都最小保持在spacing_size /// public static void DistributeSpacingSizeCycle(IVector2 center, ICollection vectors, float spacing_size) where T : IVector2 { float cx = center.X; float cy = center.Y; int count = vectors.Count; float total_len = count * spacing_size; float total_r = total_len / CMath.PI_F / 2f; float sangle = CMath.PI_MUL_2 / count; int i = 0; foreach (T o in vectors) { float da = sangle * i; o.SetX(cx + (float)Math.Cos(da) * total_r); o.SetY(cy + (float)Math.Sin(da) * total_r); i++; } } /// /// 按蜂窝状调整每个点, /// 使得距离都最小保持在spacing_size /// public static void DistributeSpacingSizeBeehive(IVector2 center, ICollection vectors, float spacing_size) where T : IVector2 { float cx = center.X; float cy = center.Y; int count = vectors.Count; T[] array = new T[count]; vectors.CopyTo(array, 0); int cycle = 0; int i = 0; float d_angle = CMath.PI_MUL_2 / 6; while (i < count) { if (i == 0) { array[i].SetX(cx); array[i].SetY(cy); i++; } else { float c_r = spacing_size * cycle; for (int j = 0; (j < 6) && (i < count); j++) { float s_angle = d_angle * j; float s_x = cx + (float)Math.Cos(s_angle) * c_r; float s_y = cy + (float)Math.Sin(s_angle) * c_r; float b_angle = s_angle + d_angle * 2; for (int aj = 0; (aj < cycle) && (i < count); aj++) { float blen = aj * spacing_size; array[i].SetX(s_x + (float)Math.Cos(b_angle) * blen); array[i].SetY(s_y + (float)Math.Sin(b_angle) * blen); i++; } } } cycle++; } } /// /// 直线 /// 使得距离都最小保持在spacing_size /// public static void DistributeSpacingSizeLine(IVector2 center, ICollection vectors, float spacing_size) where T : IVector2 { int count = vectors.Count / 2; float statX = center.X - spacing_size * count; float startY = center.Y - spacing_size * count; if (vectors.Count % 2 != 0) { statX += spacing_size / 2; startY = spacing_size / 2; } int i = 0; foreach (T o in vectors) { o.SetX(statX + i * spacing_size); o.SetY(startY + i * spacing_size); i++; } } } }