using CommonLang.Geometry; using System; using System.Collections.Generic; using System.Text; namespace CommonLang { /** * util math function none float * * @author yifeizhang * @since 2006-12-1 * @version 1.0 */ public class CMath { public static int sqrt(int i) { int l = 0; for (int k = 0x100000; k != 0; k >>= 2) { int j = l + k; l >>= 1; if (j <= i) { i -= j; l += k; } } return l; } // -------------------------------------------------------------------------------------------------------- /// <summary> /// compute cyc number: (value+d) within 0~max scope /// </summary> /// <param name="value"></param> /// <param name="d"></param> /// <param name="max"></param> /// <returns></returns> static public int cycNum(int value, int d, int max) { value += d; return (value >= 0) ? (value % max) : ((max + value % max) % max); } /// <summary> /// compute cyc number: (value+d) within 0~max scope /// </summary> /// <param name="value"></param> /// <param name="max"></param> /// <returns></returns> static public int cycNum(int value, int max) { return (value >= 0) ? (value % max) : ((max + value % max) % max); } /// <summary> /// compute cyc mod: -1 mod 10 = -1 /// </summary> /// <param name="value"></param> /// <param name="div"></param> /// <returns></returns> static public int cycMod(int value, int div) { return (value / div) + (value < 0 ? -1 : 0); } /// <summary> /// 获得符号 /// </summary> /// <param name="value"></param> /// <returns>1 or 0 or -1</returns> static public int getDirect(int value) { return value == 0 ? 0 : (value > 0 ? 1 : -1); } /// <summary> /// 获得符号 /// </summary> /// <param name="value"></param> /// <returns></returns> static public float getDirect(float value) { return value == 0 ? 0 : (value > 0 ? 1 : -1); } /// <summary> /// comput round mod roundMode(33,8) = 5 => 33/8 + (33%8==0?:0:1) /// </summary> /// <param name="value"></param> /// <param name="div"></param> /// <returns></returns> static public int roundMod(int value, int div) { return (value / div) + (value % div == 0 ? 0 : (1 * getDirect(value))); } /// <summary> /// comput round mod roundMode(33,8) = 5 => 33/8 + (33%8==0?:0:1) /// </summary> /// <param name="value"></param> /// <param name="div"></param> /// <returns></returns> static public int roundMod(float value, float div) { return (int)(value / div) + (value % div == 0 ? 0 : (1 * getDirect((int)value))); } /// <summary> /// 根据速度和时间段得到距离 /// </summary> /// <param name="speed">速度 (距离/秒)</param> /// <param name="interval_ms">毫秒</param> /// <returns></returns> static public float getDistanceSpeedInTime(float speed, float interval_ms) { float rate = interval_ms / 1000.0f; return speed * rate; } /// <summary> /// /// </summary> /// <param name="x1"></param> /// <param name="y1"></param> /// <param name="x2"></param> /// <param name="y2"></param> /// <returns></returns> 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); } /// <summary> /// /// </summary> /// <param name="x1"></param> /// <param name="y1"></param> /// <param name="x2"></param> /// <param name="y2"></param> /// <returns></returns> 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; } // ------------------------------------------------------------------------------------------------------------------- #region _Geometry_Collision_Include_ /// <summary> /// 扇形和圆相交 /// </summary> /// <param name="sx">扇形圆心</param> /// <param name="sy">扇形圆心</param> /// <param name="sr">扇形半径</param> /// <param name="dx">点</param> /// <param name="dy">点</param> /// <param name="startAngle">扇形起始角度</param> /// <param name="endAngle">扇形结束角度</param> /// <returns></returns> static public bool includeFanPoint(float sx, float sy, float sr, float dx, float dy, float startAngle, float endAngle) { float ddx = dx - sx; float ddy = dy - sy; float r = sr; if (ddx * ddx + ddy * ddy <= r * r) { float direction = OpitimizeRadians((float)Math.Atan2(ddy, ddx)); startAngle = OpitimizeRadians(startAngle); endAngle = OpitimizeRadians(endAngle); if (endAngle < startAngle) { if (direction < endAngle) { direction += PI_MUL_2; } endAngle += PI_MUL_2; } if (direction >= startAngle && direction <= endAngle) { return true; } } return false; } // -------------------------------------------------------------------------------------------------- /// <summary> /// /// </summary> /// <param name="sx">圆x</param> /// <param name="sy">圆y</param> /// <param name="sr">圆r</param> /// <param name="px">点</param> /// <param name="py">点</param> /// <returns></returns> static public bool includeRoundPoint(float sx, float sy, float sr, float px, float py) { float w = sx - px; float h = sy - py; return (w * w + h * h) <= (sr * sr); } /// <summary> /// /// </summary> /// <param name="sx">圆1x</param> /// <param name="sy">圆1y</param> /// <param name="sr">圆1r</param> /// <param name="dx">圆2x</param> /// <param name="dy">圆2y</param> /// <param name="dr">圆2r</param> /// <returns></returns> static public bool includeRound2(float sx, float sy, float sr, float dx, float dy, float dr) { float w = sx - dx; float h = sy - dy; float r = sr - dr; return (w * w + h * h) <= (r * r); } // -------------------------------------------------------------------------------------------------- /// <summary> /// /// </summary> /// <param name="sx1">矩形x1</param> /// <param name="sy1">矩形y1</param> /// <param name="sx2">矩形x2</param> /// <param name="sy2">矩形y2</param> /// <param name="dx">点</param> /// <param name="dy">点</param> /// <returns></returns> static public bool includeRectPoint(float sx1, float sy1, float sx2, float sy2, float dx, float dy) { if (sx2 < dx) return false; if (sx1 > dx) return false; if (sy2 < dy) return false; if (sy1 > dy) return false; return true; } /// <summary> /// /// </summary> /// <param name="sx1">矩形x</param> /// <param name="sy1">矩形y</param> /// <param name="sw">矩形w</param> /// <param name="sh">矩形h</param> /// <param name="dx">点</param> /// <param name="dy">点</param> /// <returns></returns> static public bool includeRectPoint2(float sx1, float sy1, float sw, float sh, float dx, float dy) { float sx2 = sx1 + sw; if (sx2 < dx) return false; if (sx1 > dx) return false; float sy2 = sy1 + sh; if (sy2 < dy) return false; if (sy1 > dy) return false; return true; } /// <summary> /// 点在椭圆内 /// </summary> /// <param name="x0">椭圆X</param> /// <param name="y0">椭圆Y</param> /// <param name="rx">椭圆宽</param> /// <param name="ry">椭圆高</param> /// <param name="dx">点</param> /// <param name="dy">点</param> /// <returns></returns> public static bool includeEllipsePoint(float x0, float y0, float rx, float ry, float dx, float dy) { return intersectRectEllipse(dx, dy, dx, dy, x0, y0, rx, ry); } /// <summary> /// 点在粗线条内 /// </summary> /// <param name="lx1">线段X1</param> /// <param name="ly1">线段Y1</param> /// <param name="lx2">线段X2</param> /// <param name="ly2">线段Y2</param> /// <param name="line_r">线段半径(粗度的一半)</param> /// <param name="dx">点</param> /// <param name="dy">点</param> /// <returns></returns> public static bool includeStripWidthPoint( float lx1, float ly1, float lx2, float ly2, float line_r, float dx, float dy) { CommonLang.Geometry.Vector2[] list = toStripWidthPolygon(lx1, ly1, lx2, ly2, line_r); return includePolygonPoint(list, dx, dy); } /// <summary> /// 点在多边形内 /// </summary> /// <param name="list">多边形</param> /// <param name="dx">点</param> /// <param name="dy">点</param> /// <returns></returns> public static bool includePolygonPoint(Vector2[] list, float dx, float dy) { return CommonLang.Geometry.CollisionMath.PointInPolygon(new Vector2(dx, dy), list); } #endregion // -------------------------------------------------------------------------------------------------- #region _Geometry_Collision_Intersect_ /// <summary> /// 两圆相交 /// </summary> /// <param name="sx">圆1x</param> /// <param name="sy">圆1y</param> /// <param name="sr">圆1r</param> /// <param name="dx">圆2x</param> /// <param name="dy">圆2y</param> /// <param name="dr">圆2r</param> /// <returns></returns> static public bool intersectRound( float sx, float sy, float sr, float dx, float dy, float dr) { float w = sx - dx; float h = sy - dy; float r = sr + dr; return (w * w + h * h) <= (r * r); } /// <summary> /// 扇形和圆相交 /// </summary> /// <param name="sx">扇形圆心</param> /// <param name="sy">扇形圆心</param> /// <param name="sr">扇形半径</param> /// <param name="dx">圆形中心</param> /// <param name="dy">圆形中心</param> /// <param name="dr">圆形半径</param> /// <param name="startAngle">扇形起始角(弧度)</param> /// <param name="endAngle">扇形结束角(弧度)</param> /// <returns></returns> static public bool intersectFanRound( float sx, float sy, float sr, float dx, float dy, float dr, float startAngle, float endAngle) { float ddx = dx - sx; float ddy = dy - sy; float r = sr + dr; if (ddx * ddx + ddy * ddy <= r * r) { float direction = OpitimizeRadians((float)Math.Atan2(ddy, ddx)); startAngle = OpitimizeRadians(startAngle); endAngle = OpitimizeRadians(endAngle); if (endAngle < startAngle) { if (direction < endAngle) { direction += PI_MUL_2; } endAngle += PI_MUL_2; } if (direction >= startAngle && direction <= endAngle) { return true; } if (intersectLineRound(sx, sy, sx + (float)Math.Cos(startAngle) * sr, sy + (float)Math.Sin(startAngle) * sr, dx, dy, dr)) { return true; } if (intersectLineRound(sx, sy, sx + (float)Math.Cos(endAngle) * sr, sy + (float)Math.Sin(endAngle) * sr, dx, dy, dr)) { return true; } } return false; } // -------------------------------------------------------------------------------------------------- /// <summary> /// 两矩形相交 /// </summary> /// <param name="sx1">矩形1</param> /// <param name="sy1">矩形1</param> /// <param name="sx2">矩形1</param> /// <param name="sy2">矩形1</param> /// <param name="dx1">矩形2</param> /// <param name="dy1">矩形2</param> /// <param name="dx2">矩形2</param> /// <param name="dy2">矩形2</param> /// <returns></returns> static public bool intersectRect( float sx1, float sy1, float sx2, float sy2, float dx1, float dy1, float dx2, float dy2) { if (sx2 < dx1) return false; if (sx1 > dx2) return false; if (sy2 < dy1) return false; if (sy1 > dy2) return false; return true; } /// <summary> /// 两矩形相交(宽高) /// </summary> /// <param name="sx1">矩形1</param> /// <param name="sy1">矩形1</param> /// <param name="sw"> 矩形1</param> /// <param name="sh"> 矩形1</param> /// <param name="dx1">矩形2</param> /// <param name="dy1">矩形2</param> /// <param name="dw"> 矩形2</param> /// <param name="dh"> 矩形2</param> /// <returns></returns> static public bool intersectRect2( float sx1, float sy1, float sw, float sh, float dx1, float dy1, float dw, float dh) { float sx2 = sx1 + sw; float dx2 = dx1 + dw; if (sx2 < dx1) return false; if (sx1 > dx2) return false; float sy2 = sy1 + sh; float dy2 = dy1 + dh; if (sy2 < dy1) return false; if (sy1 > dy2) return false; return true; } // -------------------------------------------------------------------------------------------------- /// <summary> /// 矩形和线段相交 /// </summary> /// <param name="sx1">矩形</param> /// <param name="sy1">矩形</param> /// <param name="sx2">矩形</param> /// <param name="sy2">矩形</param> /// <param name="lx1">线段</param> /// <param name="ly1">线段</param> /// <param name="lx2">线段</param> /// <param name="ly2">线段</param> /// <returns></returns> static public bool intersectRectLine( float sx1, float sy1, float sx2, float sy2, float lx1, float ly1, float lx2, float ly2) { float dx1 = lx1; float dy1 = ly1; float dx2 = lx2; float dy2 = ly2; if (dx1 > dx2) CUtils.Swap(ref dx1, ref dx2); if (dy1 > dy2) CUtils.Swap(ref dy1, ref dy2); if (!intersectRect(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2)) { return false; } if (intersectLine(lx1, ly1, lx2, ly2, sx1, sy1, sx2, sy1)) { return true; } if (intersectLine(lx1, ly1, lx2, ly2, sx2, sy1, sx2, sy2)) { return true; } if (intersectLine(lx1, ly1, lx2, ly2, sx2, sy2, sx1, sy2)) { return true; } if (intersectLine(lx1, ly1, lx2, ly2, sx1, sy2, sx1, sy1)) { return true; } return false; } /// <summary> /// 矩形和圆相交 /// </summary> /// <param name="sx">矩形</param> /// <param name="sy">矩形</param> /// <param name="dx">矩形</param> /// <param name="dy">矩形</param> /// <param name="cx">圆形</param> /// <param name="cy">圆形</param> /// <param name="r">圆形</param> /// <returns></returns> static public bool intersectRectRound(float sx, float sy, float dx, float dy, float cx, float cy, float r) { return intersectRectEllipse(sx, sy, dx, dy, cx, cy, r, r); } /// <summary> /// 计算椭圆和矩形是否相交 /// (x/rx)^2 + (y/ry)^2 = 1; /// left is: (x* ry)^2 + (y* rx)^2 /// right is: (rx* ry)^2 /// if(left > right) out /// else in /// </summary> /// <param name="xmin">矩形左上角x</param> /// <param name="ymin">矩形左上角y</param> /// <param name="xmax">矩形右下角x</param> /// <param name="ymax">矩形右下角y</param> /// <param name="x0">椭圆圆心x </param> /// <param name="y0">椭圆圆心y </param> /// <param name="rx">椭圆x轴半径</param> /// <param name="ry">椭圆y轴半径</param> /// <returns></returns> public static bool intersectRectEllipse(float xmin, float ymin, float xmax, float ymax, float x0, float y0, float rx, float ry) { //如果圆心点就在矩形内部, 那么就直接返回true // if ((x0, y0, x0, y0, xmin, ymin, xmax, ymax)) // { // return true; // } if (includeRectPoint(xmin, ymin, xmax, ymax, x0, y0)) return true; //首先找到矩形距离圆心的最近点 float x = x0, y = y0; if (x < xmin) { x = xmin; } else if (x > xmax) { x = xmax; } if (y < ymin) { y = ymin; } else if (y > ymax) { y = ymax; } float dx = x - x0; float dy = y - y0; dx *= dx; dy *= dy; rx *= rx; ry *= ry; dx *= ry; dy *= rx; if (dx + dy <= rx * ry) { return true; } return false; } /// <summary> /// 两个线段相交 /// ((Q2-Q1)X(P1-Q1))*((P2-Q1)X(Q2-Q1)) >= 0 /// ((P2-P1)X(Q1-P1))*((Q2-P1)X(P2-P1)) >= 0 /// </summary> /// <param name="p1_x">line 1</param> /// <param name="p1_y">line 1</param> /// <param name="p2_x">line 1</param> /// <param name="p2_y">line 1</param> /// <param name="q1_x">line 2</param> /// <param name="q1_y">line 2</param> /// <param name="q2_x">line 2</param> /// <param name="q2_y">line 2</param> /// <returns></returns> static public bool intersectLine( float p1_x, float p1_y, float p2_x, float p2_y, float q1_x, float q1_y, float q2_x, float q2_y) { /* croe */ float v1_x = q2_x - q1_x; float v1_y = q2_y - q1_y; float v2_x = p1_x - q1_x; float v2_y = p1_y - q1_y; float v3_x = p2_x - q1_x; float v3_y = p2_y - q1_y; if ((v1_x * v2_y - v1_y * v2_x) * (v3_x * v1_y - v3_y * v1_x) < 0) { return false; } float v5_x = p2_x - p1_x; float v5_y = p2_y - p1_y; float v6_x = q1_x - p1_x; float v6_y = q1_y - p1_y; float v7_x = q2_x - p1_x; float v7_y = q2_y - p1_y; if ((v5_x * v6_y - v5_y * v6_x) * (v7_x * v5_y - v7_y * v5_x) < 0) { return false; } return true; } /// <summary> /// 两个线段相交 /// ((Q2-Q1)X(P1-Q1))*((P2-Q1)X(Q2-Q1)) >= 0 /// ((P2-P1)X(Q1-P1))*((Q2-P1)X(P2-P1)) >= 0 /// </summary> /// <param name="p1_x">line 1</param> /// <param name="p1_y">line 1</param> /// <param name="p2_x">line 1</param> /// <param name="p2_y">line 1</param> /// <param name="q1_x">line 2</param> /// <param name="q1_y">line 2</param> /// <param name="q2_x">line 2</param> /// <param name="q2_y">line 2</param> /// <param name="ignore_touch">忽略焦点在线段内</param> /// <returns></returns> static public bool intersectLine( float p1_x, float p1_y, float p2_x, float p2_y, float q1_x, float q1_y, float q2_x, float q2_y, bool ignore_touch = true) { /* croe */ float v1_x = q2_x - q1_x; float v1_y = q2_y - q1_y; float v2_x = p1_x - q1_x; float v2_y = p1_y - q1_y; float v3_x = p2_x - q1_x; float v3_y = p2_y - q1_y; float f = (v1_x * v2_y - v1_y * v2_x) * (v3_x * v1_y - v3_y * v1_x); if (ignore_touch ? f <= 0 : f < 0) { return false; } float v5_x = p2_x - p1_x; float v5_y = p2_y - p1_y; float v6_x = q1_x - p1_x; float v6_y = q1_y - p1_y; float v7_x = q2_x - p1_x; float v7_y = q2_y - p1_y; float s = (v5_x * v6_y - v5_y * v6_x) * (v7_x * v5_y - v7_y * v5_x); if (ignore_touch ? s <= 0 : s < 0) { return false; } return true; } /// <summary> /// 求线段与圆碰撞 /// </summary> /// <param name="lx1">线段起点</param> /// <param name="ly1">线段起点</param> /// <param name="lx2">线段终点</param> /// <param name="ly2">线段终点</param> /// <param name="cx">圆心坐标</param> /// <param name="cy">圆心坐标</param> /// <param name="Radius">半径</param> /// <returns>如果有交点返回true,否则返回false</returns> public static bool intersectLineRound( float lx1, float ly1, float lx2, float ly2, float cx, float cy, float Radius) { return CommonLang.Geometry.CollisionMath.CircleLineCollide(new Vector2(cx, cy), Radius, new Vector2(lx1, ly1), new Vector2(lx2, ly2)); } /// <summary> /// 圆与胶囊线段碰撞检测 /// 性能远好于 intersetctRoundStripWidth /// </summary> /// <param name="lx1">线段</param> /// <param name="ly1">线段</param> /// <param name="lx2">线段</param> /// <param name="ly2">线段</param> /// <param name="line_r">线段半径(粗度的一半)</param> /// <param name="cx">圆形</param> /// <param name="cy">圆形</param> /// <param name="r">圆形</param> /// <returns></returns> public static bool intersectRoundStripCapsule( float cx, float cy, float r, float lx1, float ly1, float lx2, float ly2, float line_r) { return CommonLang.Geometry.CollisionMath.CircleLineCollide(new Vector2(cx, cy), line_r + r, new Vector2(lx1, ly1), new Vector2(lx2, ly2)); } /// <summary> /// 圆与线段碰撞检测 /// 性能较差 /// </summary> /// <param name="lx1">线段</param> /// <param name="ly1">线段</param> /// <param name="lx2">线段</param> /// <param name="ly2">线段</param> /// <param name="line_r">线段半径(粗度的一半)</param> /// <param name="cx">圆形</param> /// <param name="cy">圆形</param> /// <param name="r">圆形</param> /// <returns></returns> public static bool intersectRoundStripWidth( float cx, float cy, float r, float lx1, float ly1, float lx2, float ly2, float line_r) { CommonLang.Geometry.Vector2 sp = new CommonLang.Geometry.Vector2(lx1, ly1); CommonLang.Geometry.Vector2 dp = new CommonLang.Geometry.Vector2(lx2, ly2); if (CommonLang.Geometry.CollisionMath.CircleLineCollide(new Vector2(cx, cy), line_r + r, sp, dp)) { float angle = (float)Math.Atan2(ly1 - ly2, lx1 - lx2); CommonLang.Geometry.Vector2 sl = CommonLang.Geometry.CollisionMath.MoveToByRadians(sp, angle + CMath.PI_DIV_2, line_r); CommonLang.Geometry.Vector2 sr = CommonLang.Geometry.CollisionMath.MoveToByRadians(sp, angle - CMath.PI_DIV_2, line_r); CommonLang.Geometry.Vector2 dl = CommonLang.Geometry.CollisionMath.MoveToByRadians(dp, angle + CMath.PI_DIV_2, line_r); CommonLang.Geometry.Vector2 dr = CommonLang.Geometry.CollisionMath.MoveToByRadians(dp, angle - CMath.PI_DIV_2, line_r); return CMath.intersectRoundPolygon(cx, cy, r, new CommonLang.Geometry.Vector2[] { sl, sr, dr, dl, }); } return false; } /// <summary> /// 矩形与粗线段相交 /// </summary> /// <param name="sx1">矩形</param> /// <param name="sy1">矩形</param> /// <param name="sx2">矩形</param> /// <param name="sy2">矩形</param> /// <param name="lx1">线段</param> /// <param name="ly1">线段</param> /// <param name="lx2">线段</param> /// <param name="ly2">线段</param> /// <param name="line_r">线段半径(粗度的一半)</param> /// <returns></returns> public static bool intersectRectStripWidth( float sx1, float sy1, float sx2, float sy2, float lx1, float ly1, float lx2, float ly2, float line_r) { if (CMath.intersectRect(sx1, sy1, sx2, sy2, Math.Min(lx1, lx2), Math.Min(ly1, ly2), Math.Max(lx1, lx2), Math.Max(ly1, ly2))) { CommonLang.Geometry.Vector2 sp = new CommonLang.Geometry.Vector2(lx1, ly1); CommonLang.Geometry.Vector2 dp = new CommonLang.Geometry.Vector2(lx2, ly2); float angle = (float)Math.Atan2(ly1 - ly2, lx1 - lx2); CommonLang.Geometry.Vector2 p0 = CommonLang.Geometry.CollisionMath.MoveToByRadians(sp, angle + CMath.PI_DIV_2, line_r); CommonLang.Geometry.Vector2 p1 = CommonLang.Geometry.CollisionMath.MoveToByRadians(sp, angle - CMath.PI_DIV_2, line_r); CommonLang.Geometry.Vector2 p2 = CommonLang.Geometry.CollisionMath.MoveToByRadians(dp, angle - CMath.PI_DIV_2, line_r); CommonLang.Geometry.Vector2 p3 = CommonLang.Geometry.CollisionMath.MoveToByRadians(dp, angle + CMath.PI_DIV_2, line_r); if (CMath.intersectRectLine(sx1, sy1, sx2, sy2, p0.X, p0.Y, p1.X, p1.Y)) return true; if (CMath.intersectRectLine(sx1, sy1, sx2, sy2, p1.X, p1.Y, p2.X, p2.Y)) return true; if (CMath.intersectRectLine(sx1, sy1, sx2, sy2, p2.X, p2.Y, p3.X, p3.Y)) return true; if (CMath.intersectRectLine(sx1, sy1, sx2, sy2, p3.X, p3.Y, p0.X, p0.Y)) return true; } return false; } /// <summary> /// 圆形与多边形碰撞 /// </summary> /// <param name="cx">圆形</param> /// <param name="cy">圆形</param> /// <param name="r">圆形</param> /// <param name="list">多边形</param> /// <returns></returns> public static bool intersectRoundPolygon(float cx, float cy, float r, Vector2[] list) { if (list.Length == 1) { return CMath.includeRoundPoint(cx, cy, r, list[0].X, list[0].Y); } Vector2 center = new Vector2(cx, cy); if (CollisionMath.PointInPolygon(center, list)) { return true; } for (int i = 0; i < list.Length - 1; ++i) { if (CollisionMath.CircleLineCollide(center, r, list[i], list[i + 1])) return true; } if (CollisionMath.CircleLineCollide(center, r, list[list.Length - 1], list[0])) { return true; } return false; } /// <summary> /// 矩形与多边形碰撞 /// </summary> /// <param name="sx1">矩形</param> /// <param name="sy1">矩形</param> /// <param name="sx2">矩形</param> /// <param name="sy2">矩形</param> /// <param name="list">多边形</param> /// <returns></returns> public static bool intersectRectPolygon(float sx1, float sy1, float sx2, float sy2, Vector2[] list) { if (list.Length == 1) return CMath.includeRectPoint(sx1, sy1, sx2, sy2, list[0].X, list[0].Y); if (CollisionMath.PointInPolygon(new Vector2( CMath.getMiddleValue(0.5f, sx1, sx2), CMath.getMiddleValue(0.5f, sy1, sy2)), list)) return true; Vector2 p = list[0]; Vector2 q = list[list.Length - 1]; if (CMath.intersectRectLine(sx1, sy1, sx2, sy2, p.X, p.Y, q.X, q.Y)) return true; for (int i = list.Length - 2; i >= 0; --i) { p = list[i]; q = list[i + 1]; if (CMath.intersectRectLine(sx1, sy1, sx2, sy2, p.X, p.Y, q.X, q.Y)) return true; } return false; } /// <summary> /// 获得粗线段多边形表达式 /// </summary> /// <param name="lx1">线段</param> /// <param name="ly1">线段</param> /// <param name="lx2">线段</param> /// <param name="ly2">线段</param> /// <param name="line_r">线段半径(粗度的一半)</param> /// <returns>多边形</returns> public static Vector2[] toStripWidthPolygon(float lx1, float ly1, float lx2, float ly2, float line_r) { Vector2[] ret = new Vector2[4]; CommonLang.Geometry.Vector2 sp = new CommonLang.Geometry.Vector2(lx1, ly1); CommonLang.Geometry.Vector2 dp = new CommonLang.Geometry.Vector2(lx2, ly2); float angle = (float)Math.Atan2(ly1 - ly2, lx1 - lx2); ret[0] = CommonLang.Geometry.CollisionMath.MoveToByRadians(sp, angle + CMath.PI_DIV_2, line_r); ret[1] = CommonLang.Geometry.CollisionMath.MoveToByRadians(sp, angle - CMath.PI_DIV_2, line_r); ret[3] = CommonLang.Geometry.CollisionMath.MoveToByRadians(dp, angle + CMath.PI_DIV_2, line_r); ret[2] = CommonLang.Geometry.CollisionMath.MoveToByRadians(dp, angle - CMath.PI_DIV_2, line_r); return ret; } /// <summary> /// 获取多边形外包框 /// </summary> /// <param name="list"></param> /// <param name="min"></param> /// <param name="max"></param> public static void toBoundingBox(Vector2[] list, out Vector2 min, out Vector2 max) { min = new Vector2(float.MaxValue, float.MaxValue); max = new Vector2(float.MinValue, float.MinValue); for (int i = list.Length - 1; i >= 0; --i) { if (list[i].X < min.X) { min.X = list[i].X; } if (list[i].Y < min.Y) { min.Y = list[i].Y; } if (list[i].X > max.X) { max.X = list[i].X; } if (list[i].Y > max.Y) { max.Y = list[i].Y; } } } #endregion // -------------------------------------------------------------------------------------------------- /// <summary> /// max 大于等于 value 并且 min 小于等于 value /// </summary> /// <param name="value"></param> /// <param name="min"></param> /// <param name="max"></param> /// <returns></returns> public static bool isIncludeEqual(int value, int min, int max) { return max >= value && min <= value; } /// <summary> /// max 大于 value 并且 min 小于 value /// </summary> /// <param name="value"></param> /// <param name="min"></param> /// <param name="max"></param> /// <returns></returns> public static bool isInclude(int value, int min, int max) { return max > value && min < value; } /// <summary> /// value 大于等于 0 并且& value 小于 max /// </summary> /// <param name="value"></param> /// <param name="max"></param> /// <returns></returns> public static bool isInRange(int value, int max) { return value >= 0 && value < max; } static public bool IsIntersect(float sx1, float sx2, float dx1, float dx2) { if (sx2 < dx1) return false; if (sx1 > dx2) return false; return true; } static public bool IsIntersect2(float sx1, float sw, float dx1, float dw) { float sx2 = sx1 + sw; if (sx2 < dx1) return false; float dx2 = dx1 + dw; if (sx1 > dx2) return false; return true; } /// <summary> /// 将值定位于min和max之间 /// </summary> /// <param name="value"></param> /// <param name="min"></param> /// <param name="max">包含</param> /// <returns></returns> public static float getInRange( float value, float min, float max) { value = Math.Min(max, value); value = Math.Max(min, value); return value; } /// <summary> /// 获得值在最大与最小之间的比率 /// </summary> /// <param name="value"></param> /// <param name="min_v"></param> /// <param name="max_v"></param> /// <returns></returns> public static float getRate( float value, float min_v, float max_v) { float sw = max_v - min_v; float sx = value - min_v; return (sx / sw); } /// <summary> /// 将比率换算为实际值 /// </summary> /// <param name="rate"></param> /// <param name="min"></param> /// <param name="max"></param> /// <returns></returns> public static float getMiddleValue( float rate, float min, float max) { float v = max - min; return min + v * rate; } // -------------------------------------------------------------------------------------------------- public static long ccNextPOT(long x) { x = x - 1; x = x | (x >> 1); x = x | (x >> 2); x = x | (x >> 4); x = x | (x >> 8); x = x | (x >> 16); return x + 1; } public const float PI_F = (float)(Math.PI); public const float PI_FLOAT = (float)(Math.PI); /// <summary> /// Math.PI / 180 /// </summary> public const float PI_DIV_180 = (float)(Math.PI / 180); /// <summary> /// Math.PI / 2 /// </summary> public const float PI_DIV_2 = (float)(Math.PI / 2); /// <summary> /// Math.PI * 2 /// </summary> public const float PI_MUL_2 = (float)(Math.PI * 2); /// <summary> /// 角度转弧度 /// </summary> /// <param name="degrees"></param> /// <returns></returns> public static float DegreesToRadians(float degrees) { return (PI_DIV_180 * degrees); } /// <summary> /// 弧度转角度 /// </summary> /// <param name="radians"></param> /// <returns></returns> public static float RadiansToDegrees(float radians) { return (radians / PI_DIV_180); } public static float ToPI(float angle) { return (angle * PI_DIV_180); } public static float To360(float angle) { return (angle / PI_DIV_180); } /// <summary> /// 将角度控制在360度范围内 /// </summary> /// <param name="degrees"></param> /// <returns></returns> public static float OpitimizeDegrees(float degrees) { while (degrees > 360) { degrees -= 360; } while (degrees < 0) { degrees += 360; } return degrees; } /// <summary> /// 将弧度控制在2PI度范围内 /// </summary> /// <param name="degrees"></param> /// <returns></returns> public static float OpitimizeRadians(float radians) { while (radians > PI_MUL_2) { radians -= PI_MUL_2; } while (radians < 0) { radians += PI_MUL_2; } return radians; } /// <summary> /// 判断弧度是否在范围内 /// </summary> /// <param name="angle"></param> /// <param name="startAngle"></param> /// <param name="endAngle"></param> /// <returns></returns> public static bool RadiansInRange(float angle, float startAngle, float endAngle) { startAngle = OpitimizeRadians(startAngle); endAngle = OpitimizeRadians(endAngle); if (endAngle < startAngle) { if (angle < endAngle) { angle += PI_MUL_2; } endAngle += PI_MUL_2; } if (angle >= startAngle && angle <= endAngle) { return true; } return false; } /// <summary> /// 获取两个角度间的最小距离 /// </summary> /// <param name="src_angle"></param> /// <param name="dst_angle"></param> /// <returns></returns> public static float GetMinRadians(float src_angle, float dst_angle) { float dd = CMath.OpitimizeRadians(src_angle); float cd = CMath.OpitimizeRadians(dst_angle); float d1 = Math.Abs(dd - cd); if (d1 > PI_F) { return PI_MUL_2 - d1; } return d1; } //-------------------------------------------------------------------------------------------------- public static void RandomPosInRound(Random rand, float x, float y, float r, ref Vector.Vector2 pos) { float angle = (float)rand.NextDouble() * CMath.PI_MUL_2; float distance = (float)rand.NextDouble() * r; pos.SetX(x + (float)Math.Cos(angle) * distance); pos.SetY(y + (float)Math.Sin(angle) * distance); } public static void RandomPosInRound(Random rand, float x, float y, float r, out float out_x, out float out_y) { float angle = (float)rand.NextDouble() * CMath.PI_MUL_2; float distance = (float)rand.NextDouble() * r; out_x = x + (float)Math.Cos(angle) * distance; out_y = y + (float)Math.Sin(angle) * distance; } public static void RandomPosInCycle(Random rand, float x, float y, float r, out float out_x, out float out_y) { float angle = (float)rand.NextDouble() * CMath.PI_MUL_2; out_x = x + (float)Math.Cos(angle) * r; out_y = y + (float)Math.Sin(angle) * r; } public static float RandomAngle(Random rand) { return (float)rand.NextDouble() * CMath.PI_MUL_2; } //-------------------------------------------------------------------------------------------------- public enum PointOnLineResult : byte { Left, Right, Touch, } /// <summary> /// 输入三个点,并且判断第三个点在前两个点连成的直线的左边还是右边或者是在线上 /// </summary> /// <param name="x0"></param> /// <param name="y0"></param> /// <param name="x1"></param> /// <param name="y1"></param> /// <param name="x2"></param> /// <param name="y2"></param> /// <returns></returns> public static PointOnLineResult PointOnLine(float x0, float y0, float x1, float y1, float x2, float y2) { float f = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0); if (f > 0) return PointOnLineResult.Right; if (f < 0) return PointOnLineResult.Left; return PointOnLineResult.Touch; } } }