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++;
}
}
}
}