2几何学的方法
程序员文章站
2022-04-01 16:39:01
...
public static class Geometry
{
#region 点是否在多边形内(含边界)
/// <summary>
/// 判断点是否在多边形内部(含边界)
/// </summary>
/// <remarks>
/// 将测试点的Y坐标与多边形的每一个点进行比较,得到测试点所在的行与多边形边的交点的列表,如果测试点的两边点的个数都是奇数个则该测试点在多边形内,否则在多边形外
/// </remarks>
public static bool IsPointInsidePolygon(IEnumerable<Vector2> polygon, Vector2 point, float torlance = 0.001f)
{
// 多边形顶点数目必须大于2
if (polygon.Count() < 3)
{
Debug.LogError(string.Format("Polygon must have at least 3 vertex, current polygon has {0} vertex!", polygon.Count()));
return false;
}
bool isInside = false;
List<float> polyX = polygon.Select(x => x.x).ToList();
List<float> polyY = polygon.Select(x => x.y).ToList();
for (int i = 0, j = polygon.Count() - 1; i < polygon.Count(); i++)
{
if ((polyY[i] < point.y && polyY[j] >= point.y || polyY[j] < point.y && polyY[i] >= point.y) &&
(polyX[i] <= point.x || polyX[j] <= point.x))
{
isInside ^= (polyX[i] + (point.y - polyY[i]) / (polyY[j] - polyY[i]) * (polyX[j] - polyX[i]) < point.x);
}
j = i;
}
// 做边界判断
if (!isInside)
{
//Debug.Log("做边界判断!");
//float torlance = 0.001f;
foreach (Vector2 vert in polygon)
{
if (Vector2.Distance(vert, point) < torlance)
{
//Debug.Log("有相近点!");
isInside = true;
break;
}
}
if (!isInside)
{
for (int i = 0; i < polyX.Count; i++)
{
Vector2 start = new Vector2(polyX[i], polyY[i]);
Vector2 end = new Vector2(polyX[(i + 1) % polyX.Count], polyY[(i + 1) % polyY.Count]);
//Debug.Log(string.Format("Start:{0} End:{1} Point:{2} Dis:{3}", start, end, point, DisPoint2Line(point, start, end)));
if (DisPoint2Line(point, start, end) < torlance)
{
Vector2 s2p = (point - start).normalized;
Vector2 e2p = (point - end).normalized;
//Debug.Log("是否在边上 " + Mathf.Abs(Vector2.Dot(s2p, e2p) - (-1)));
if (Mathf.Abs(Vector2.Dot(s2p, e2p) - (-1)) < torlance)
{
//Debug.Log("有相近边!");
isInside = true;
break;
}
}
}
}
}
return isInside;
}
#endregion
#region 点是否在线段上(含两端点)
/// <summary>
/// 判断点是否在线段上(含边界)
/// </summary>
/// <remarks>
/// 点到线段两端的距离之和为线段的长度则在线段上,否则在线段外
/// </remarks>
public static bool IsPointInsideSegment(IEnumerable<Vector2> segment, Vector2 point)
{
// 线段顶点数目必须等于2
if (segment.Count() != 2)
{
Debug.LogError(string.Format("Segment must have only 2 vertex, current segment have {0} vertex!", segment.Count()));
return false;
}
if (Mathf.Approximately((point - segment.First()).magnitude + (point - segment.Last()).magnitude, (segment.First() - segment.Last()).magnitude))
return true;
else
return false;
}
/// <summary>
/// 检测某个点是否在线段上
/// </summary>
/// <param name="lineStart"></param>
/// <param name="lineEnd"></param>
/// <param name="point"></param>
/// <returns></returns>
public static bool CheckPointInSegement(Vector2 lineStart, Vector2 lineEnd, Vector2 point)
{
// 误差范围
if (DisPoint2Line(point, lineStart, lineEnd) >= 0.002f)
{
return false;
}
Vector2 p2Start = (lineStart - point).normalized;
Vector2 p2End = (lineEnd - point).normalized;
if (Vector2.Dot(p2End, p2Start) <= 0)
{
return true;
}
else
{
return false;
}
}
#endregion
#region 坐标系偏移
/// <summary>
/// 将Unity世界坐标系按照逆时针方向偏移指定degrees后,origin相对于偏移坐标系的位置
/// </summary>
public static Vector2 CoordinateOffsetByDegrees(Vector2 origin, float degrees)
{
return CoordinateOffsetByRadians(origin, degrees * Mathf.Deg2Rad);
}
/// <summary>
/// 将Unity世界坐标系内,指定点围绕坐标系原点,按照逆时针方向偏移指定radians后,origin相对于偏移坐标系的位置
/// </summary>
public static Vector2 CoordinateOffsetByRadians(Vector2 origin, float radians)
{
float x = origin.x * Mathf.Cos(radians) + origin.y * Mathf.Sin(radians);
float y = origin.y * Mathf.Cos(radians) - origin.x * Mathf.Sin(radians);
return new Vector2(x, y);
}
/// <summary>
/// 计算在Unity世界坐标系内,指定点围绕锚点,按照逆时针方向旋转一定角度后,得到的新的世界坐标
/// </summary>
/// <param name="point">需要操作的点</param>
/// <param name="anchor">锚点,指定点围绕该点进行旋转操作</param>
/// <param name="degrees">角度,以逆时针方向为正值</param>
public static Vector2 RotateArroundAnchorByDegrees(Vector2 point, Vector2 anchor, float degrees)
{
return RotateArroundAnchorByRadians(point, anchor, degrees * Mathf.Deg2Rad);
}
/// <summary>
/// 计算在Unity世界坐标系内,指定点围绕锚点,按照逆时针方向旋转一定弧度后,得到的新的世界坐标
/// </summary>
/// <param name="point">需要操作的点</param>
/// <param name="anchor">锚点,指定点围绕该点进行旋转操作</param>
/// <param name="radians">弧度,以逆时针方向为正值</param>
public static Vector2 RotateArroundAnchorByRadians(Vector2 point, Vector2 anchor, float radians)
{
float x = (point.x - anchor.x) * Mathf.Cos(radians) - (point.y - anchor.y) * Mathf.Sin(radians) + anchor.x;
float y = (point.x - anchor.x) * Mathf.Sin(radians) + (point.y - anchor.y) * Mathf.Cos(radians) + anchor.y;
return new Vector2(x, y);
}
#endregion
#region 判断多边形各顶点是否按照顺时针排序
/// <summary>
/// 判断多边形顶点是否按照顺时针排序
/// </summary>
/// <remarks>
/// 在凸点A处,若CA、AB的叉积的y值小于0时,为逆时针方向,大于0时为顺时针方向,不考虑为0的情况;
/// 由于Unity使用左手坐标系,与数学定义上的叉乘使用的右手坐标系正好相反,因此需要特别注意
/// </remarks>
public static bool IsPolygonClockWise(IEnumerable<Vector2> polygon)
{
// 多边形顶点数目必须大于2
if (polygon.Count() < 3)
{
Debug.LogError(string.Format("Polygon must have at least 3 vertex, current polygon has {0} vertex!", polygon.Count()));
return false;
}
List<Vector2> sortedPolygon = polygon.ToList();
// 选择凸点进行判断(此处选择左下角顶点)
int leftBottomIndex = FindLeftBottomPointIndex(sortedPolygon);
Vector3 ptC = sortedPolygon[(leftBottomIndex - 1 + sortedPolygon.Count) % sortedPolygon.Count].ToVector3XZ();
Vector3 ptA = sortedPolygon[leftBottomIndex].ToVector3XZ();
Vector3 ptB = sortedPolygon[(leftBottomIndex + 1) % sortedPolygon.Count].ToVector3XZ();
if (Vector3.Cross((ptA - ptC), (ptB - ptA)).y < 0)
return false;
else
return true;
}
#endregion
#region 以顺/逆实在排列多边形的顶点
/// <summary>
/// 以顺/逆时针顺序排列多边形的顶点集合
/// </summary>
/// <remarks>
/// 在凸点A处,若CA、AB的叉积的y值小于0时,为逆时针方向,大于0时为顺时针方向,不考虑为0的情况;
/// 由于Unity使用左手坐标系,与数学定义上的叉乘使用的右手坐标系正好相反,因此需要特别注意
/// </remarks>
public static IEnumerable<Vector2> SortPolygonInClockWise(IEnumerable<Vector2> polygon, bool isClockWise = true)
{
// 多边形顶点数目必须大于2
if (polygon.Count() < 3)
{
Debug.LogError(string.Format("Polygon must have at least 3 vertex, current polygon has {0} vertex!", polygon.Count()));
return polygon;
}
List<Vector2> sortedPolygon = polygon.ToList();
// 选择凸点进行判断(此处选择左下角顶点)
int leftBottomIndex = FindLeftBottomPointIndex(sortedPolygon);
Vector3 ptC = sortedPolygon[(leftBottomIndex - 1 + sortedPolygon.Count) % sortedPolygon.Count].ToVector3XZ();
Vector3 ptA = sortedPolygon[leftBottomIndex].ToVector3XZ();
Vector3 ptB = sortedPolygon[(leftBottomIndex + 1) % sortedPolygon.Count].ToVector3XZ();
Vector3 crossProduct = Vector3.Cross((ptA - ptC), (ptB - ptA));
// 实际为逆而要求顺,或实际为顺而要求逆时,翻转列表
if ((crossProduct.y < 0 && isClockWise) || (crossProduct.y > 0 && !isClockWise))
sortedPolygon.Reverse();
return sortedPolygon;
}
#endregion
#region 寻找点集中的特定点
/// <summary>
/// 寻找点集中的左下角顶点
/// </summary>
/// <remarks>
/// 左下角的定义:y值最小的情况下取x值最小的点
/// </remarks>
public static Vector2 FindLeftBottomPoint(IEnumerable<Vector2> vertices)
{
float minY = vertices.Min(x => x.y);
return vertices.Where(x => x.y == minY).OrderBy(x => x.x).First();
}
/// <summary>
/// 寻找点集中的左下角顶点的Index
/// </summary>
/// <remarks>
/// 左下角的定义:y值最小的情况下取x值最小的点
/// </remarks>
public static int FindLeftBottomPointIndex(List<Vector2> vertices)
{
float minY = vertices.Min(x => x.y);
return vertices.IndexOf(vertices.Where(x => x.y == minY).OrderBy(x => x.x).First());
}
#endregion
#region 获取两直线交点
/// <summary>
/// 得到两直线交点的方法
/// </summary>
/// <param name="lineFirstStart"> 第一条线的一个点 </param>
/// <param name="lineFirstEnd"> 第一条线的另外一个点 </param>
/// <param name="lineSecondStart"> 第二条线的一个点 </param>
/// <param name="lineSecondEnd"> 第二条线的另外一个点 </param>
/// <returns></returns>
public static Vector3 GetIntersectionByPoints(Vector3 lineFirstStart, Vector3 lineFirstEnd, Vector3 lineSecondStart,
Vector3 lineSecondEnd)
{
float y = lineFirstStart.y;
double a = 0, b = 0;
int state = 0;
if (lineFirstStart.x != lineFirstEnd.x)
{
a = (lineFirstEnd.z - lineFirstStart.z) / (lineFirstEnd.x - lineFirstStart.x);
state |= 1;
}
if (lineSecondStart.x != lineSecondEnd.x)
{
b = (lineSecondEnd.z - lineSecondStart.z) / (lineSecondEnd.x - lineSecondStart.x);
state |= 2;
}
switch (state)
{
case 0:
{
if (lineFirstStart.x == lineSecondStart.x)
{
return Vector3.zero;
}
else
{
return Vector3.zero;
}
}
case 1:
{
double x = lineSecondStart.x;
double z = (lineFirstStart.x - x) * (-a) + lineFirstStart.z;
return new Vector3((float)x, y, (float)z);
}
case 2:
{
double x = lineFirstStart.x;
double z = (lineSecondStart.x - x) * (-b) + lineSecondStart.z;
return new Vector3((float)x, y, (float)z);
}
case 3:
{
if (Mathf.Abs((float)(a - b)) < 0.0001)
{
return Vector3.zero;
}
double x = (a * lineFirstStart.x - b * lineSecondStart.x - lineFirstStart.z + lineSecondStart.z) / (a - b);
double z = a * x - a * lineFirstStart.x + lineFirstStart.z;
return new Vector3((float)x, y, (float)z);
}
}
return Vector3.zero;
}
#endregion
#region 获取线段与直线的交点
public static Vector3? GetIntersectonBetweenLineAndSegment(Vector3 linePointA, Vector3 linePointB, Vector3 segmentPointA, Vector3 segmentPointB)
{
// 先求两直线交点 再判断交点是否在线段上
Vector3? intersection = GetIntersectionByPoints(linePointA, linePointB, segmentPointA, segmentPointB);
if (intersection != Vector3.zero)
{
//if (CheckPointInSegement(segmentPointA, segmentPointB, intersection.Value))
//{
// Debug.Log(string.Format("segmentStart: {0} segmentEnd: {1} intersection:{2}", segmentPointA.ToString("f4"), segmentPointB.ToString("f4"), intersection.Value.ToString("f4")));
// return intersection;
//}
if (IsPointInsideSegment(new List<Vector2>() { segmentPointA.ToVector2XZ(), segmentPointB.ToVector2XZ() }, intersection.Value.ToVector2XZ()))
{
//Debug.Log(string.Format("segmentStart: {0} segmentEnd: {1} intersection:{2}", segmentPointA.ToString("f4"), segmentPointB.ToString("f4"), intersection.Value.ToString("f4")));
return intersection;
}
}
return null;
}
#endregion
#region 点到直线的距离
/// <summary>
/// 某个点到线段上的距离
/// </summary>
/// <param name="point"></param>
/// <param name="linePointA"></param>
/// <param name="linePointB"></param>
/// <returns></returns>
public static double DisPoint2Line(Vector2 point, Vector2 linePointA, Vector2 linePointB)
{
double dis = 0;
if (linePointA.x == linePointB.x)
{
dis = Math.Abs(point.x - linePointA.x);
return dis;
}
double lineK = (linePointB.y - linePointA.y) / (linePointB.x - linePointA.x);
double lineC = (linePointB.x * linePointA.y - linePointA.x * linePointB.y) / (linePointB.x - linePointA.x);
dis = Math.Abs(lineK * point.x - point.y + lineC) / (Math.Sqrt(lineK * lineK + 1));
return dis;
}
#endregion
#region 获取点在直线上的垂直投影点
/// <summary>
/// 获得某点在一个直线上的投影
/// </summary>
/// <param name="point"></param>
/// <param name="linePoint1"></param>
/// <param name="linePoint2"></param>
/// <returns></returns>
public static Vector3 GetProjectivePoint(Vector3 point, Vector3 linePoint1, Vector3 linePoint2)
{
Vector3 target;
Vector3 lineDir = (linePoint2 - linePoint1).normalized;
Vector3 projectiveDir = Quaternion.Euler(0, 90, 0) * lineDir;
Vector3 point2 = point + projectiveDir;
target = GetIntersectionByPoints(point, point2, linePoint1, linePoint2);
return target;
}
#endregion
#region 判断两多边形是否相交
// 函数存在缺陷,最后一个点到第一个点的线段会被忽略
public static bool IsPolygonIntersectOtherPolygon(IEnumerable<Vector2> polgon, IEnumerable<Vector2> otherPolgon)
{
Vector2 segmentStart = Vector2.zero;
Vector2 segmentEnd = Vector2.zero;
int count = 0;
// 让两个多边形的边依次进行判断
foreach (Vector2 point in polgon)
{
if (count == 0)
{
segmentStart = point;
count++;
continue;
}
else
{
segmentEnd = point;
Vector2 otherStart = Vector2.zero;
Vector2 otherEnd = Vector2.zero;
int otherCount = 0;
foreach (Vector2 otherPoint in otherPolgon)
{
if (otherCount == 0)
{
otherStart = otherPoint;
otherCount++;
continue;
}
else
{
otherEnd = otherPoint;
bool isCrose = CheckTwoSegmentCrose(segmentStart, segmentEnd, otherStart, otherEnd);
if (isCrose)
return true;
otherStart = otherPoint;
}
}
segmentStart = point;
}
}
return false;
}
#endregion
#region 判断两线段是否相交
//firstlineStart, firstlineEnd为一条线段两端点 SecondlineStart, SecondlineEnd为另一条线段的两端点 相交返回true, 不相交返回false
public static bool CheckTwoSegmentCrose(Vector2 firstlineStart, Vector2 firstlineEnd, Vector2 SecondlineStart, Vector2 SecondlineEnd)
{
if (max(firstlineStart.x, firstlineEnd.x) < min(SecondlineStart.x, SecondlineEnd.x))
{
return false;
}
if (max(firstlineStart.y, firstlineEnd.y) < min(SecondlineStart.y, SecondlineEnd.y))
{
return false;
}
if (max(SecondlineStart.x, SecondlineEnd.x) < min(firstlineStart.x, firstlineEnd.x))
{
return false;
}
if (max(SecondlineStart.y, SecondlineEnd.y) < min(firstlineStart.y, firstlineEnd.y))
{
return false;
}
if (mult(SecondlineStart, firstlineEnd, firstlineStart) * mult(firstlineEnd, SecondlineEnd, firstlineStart) < 0)
{
return false;
}
if (mult(firstlineStart, SecondlineEnd, SecondlineStart) * mult(SecondlineEnd, firstlineEnd, SecondlineStart) < 0)
{
return false;
}
return true;
}
#endregion
#region 判断两个线段是否端点相连
// 判断两条线段是否相连
public static bool CheckTwoSegmentSharePoint(Vector2 firstlineStart, Vector2 firstlineEnd, Vector2 SecondlineStart, Vector2 SecondlineEnd)
{
return firstlineStart == SecondlineStart || firstlineStart == SecondlineEnd || firstlineEnd == SecondlineStart || firstlineEnd == SecondlineEnd;
}
#endregion
#region 计算多边形面积
/// <summary>
/// 多边形面积计算(不论凸凹)
/// </summary>
/// <param name="count">坐标点数</param>
/// <param name="X">坐标的横坐标集合</param>
/// <param name="Y">坐标的纵坐标集合</param>
/// <returns></returns>
public static double AoArea(int count, double[] X, double[] Y)
{
double area;
if (count < 3)
return 0;
area = Y[0] * (X[count - 1] - X[1]);
for (int i = 1; i < count; i++)
area += Y[i] * (X[(i - 1)] - X[(i + 1) % count]);
return area / 2;
}
public static double GetAreaOfPolygon(Vector3[] polygon)
{
double[] xDoubles = new double[polygon.Length];
double[] yDoubles = new double[polygon.Length];
int i = 0;
foreach (Vector3 vector3 in polygon)
{
xDoubles[i] = vector3.x;
yDoubles[i] = vector3.z;
i++;
}
return Geometry.AoArea(xDoubles.Length, xDoubles, yDoubles);
}
#endregion
#region 2D平面上某点绕某点旋转一定角度后的位置
/// <summary>
/// 一个点绕另外一个点逆时针旋转一定角度得到的点
/// </summary>
/// <param name="startPos"></param>
/// <param name="origin"></param>
/// <param name="angle"></param>
/// <returns></returns>
public static Vector2 RotateAround(Vector2 startPos, Vector2 origin, float angle)
{
float rad = Mathf.Deg2Rad * angle;
double x = (startPos.x - origin.x) * Math.Cos(rad) - (startPos.y - origin.y) * Math.Sin(rad) + origin.x;
//Debug.Log(string.Format("angle : {0} cos: {1} sin: {2} startPos: {3} origin: {4}", angle, Math.Cos(rad), Math.Sin(rad), startPos.ToString("f4"), origin.ToString("f4")));
double y = (startPos.x - origin.x) * Math.Sin(rad) + (startPos.y - origin.y) * Math.Cos(rad) + origin.y;
return new Vector2((float)x, (float)y);
}
#endregion
#region 删掉多边形*线的顶点
/// <summary>
/// 删掉共线的点
/// </summary>
/// <param name="Polygon"></param>
/// <returns></returns>
public static List<Vector3> RemoveInLinePoint(List<Vector3> polygon)
{
List<Vector3> resultPolygon = new List<Vector3>(polygon);
// 一个点一个点地检验过去 如果在这个点前一个点和这个点后一个点连成的直线上,就删除该点
bool check = true;
do
{
check = true;
for (int i = 0; i < resultPolygon.Count; i++)
{
int frontIndex = i <= 0 ? resultPolygon.Count - 1 : i - 1;
int nextIndex = (i + 1) % resultPolygon.Count;
Vector3 frontToCur = resultPolygon[i] - resultPolygon[frontIndex];
Vector3 nextToCur = resultPolygon[i] - resultPolygon[nextIndex];
bool inLine = (frontToCur.normalized + nextToCur.normalized == Vector3.zero);
if (inLine)
{
resultPolygon.RemoveAt(i);
check = false;
break;
}
}
} while (!check);
return resultPolygon;
}
#endregion
#region 判断两线段是否共线
/// <summary>
/// 判断两个线段是否共线
/// </summary>
/// <param name="firstWall"></param>
/// <param name="secondWall"></param>
/// <returns></returns>
public static bool CheckTwoSegmentShareLine(Vector2 lineAStart, Vector2 lineAEnd, Vector2 lineBStart, Vector2 lineBEnd)
{
Vector2 firstWallDir = (lineAEnd - lineAStart).normalized;
Vector2 secondWallDir = (lineBEnd - lineBStart).normalized;
//Debug.Log(string.Format("aStart:{2] end:{3} bStart:{4} end:{5} firstWallDir:{0} secondWallDir:{1}",
// firstWallDir.ToString("f4"), secondWallDir.ToString("f4"), lineAStart.ToString("f4"), lineAEnd.ToString("f4"), lineBStart.ToString("f4"), lineBEnd.ToString("f4")));
//if (DisPoint2Line(lineAStart, lineBStart, lineBEnd)>0.001f|| DisPoint2Line(lineAEnd, lineBStart, lineBEnd)>0.001f)
// return false;
//// 没有加检测
//return Vector3.Distance(firstWallDir, secondWallDir) < 0.001f || Vector3.Distance(firstWallDir, -secondWallDir) < 0.001f;
return (CheckThreePointShareLine(lineAStart, lineAEnd, lineBStart)) && (CheckThreePointShareLine(lineAStart, lineAEnd, lineBEnd));
}
#endregion
#region 判断三点是否共线
/// <summary>
/// 判断三点是否共线
/// </summary>
/// <param name="lineA"></param>
/// <param name="lineB"></param>
/// <param name="lineC"></param>
/// <returns></returns>
public static bool CheckThreePointShareLine(Vector2 lineA, Vector2 lineB, Vector2 lineC)
{
if (lineA != lineB && lineB != lineC && lineC != lineA)//这里修改了一下
{
Vector2 a2b = (lineB - lineA).normalized;
Vector2 c2b = (lineB - lineC).normalized;
//Debug.Log(a2b.ToString("f6") + " " + c2b.ToString("f6"));
return (a2b == c2b) || (a2b == -c2b);
}
else
{
return true;
}
}
#endregion
#region 判断两条线段是否共线且存在重叠
/// <summary>
/// 判断两条选段是否有重叠
/// </summary>
/// <param name="lineAStart"></param>
/// <param name="lineAEnd"></param>
/// <param name="lineBStart"></param>
/// <param name="lineBEnd"></param>
/// <returns></returns>
public static bool CheckTwoSegmentOverlap(Vector2 lineAStart, Vector2 lineAEnd, Vector2 lineBStart, Vector2 lineBEnd)
{
if (CheckTwoSegmentShareLine(lineAStart, lineAEnd, lineBStart, lineBEnd))
{
//Debug.Log("ShareLine");
Vector2 s2s = (lineBStart - lineAStart).normalized;
Vector2 s2e = (lineBEnd - lineAStart).normalized;
Vector2 e2s = (lineBStart - lineAEnd).normalized;
Vector2 e2e = (lineBEnd - lineAEnd).normalized;
if (s2s == s2e && s2e == e2s && e2s == e2e)
{
return false;
}
return true;
}
return false;
}
#endregion
#region 判断两个向量是否平行
public static bool CheckTwoVectorParallel(Vector3 vectorA, Vector3 vectorB, float tolerance)
{
return Mathf.Abs(Mathf.Abs(Vector3.Dot(vectorA, vectorB)) - 1) < tolerance;
}
#endregion
#region 判断两个向量是否垂直
public static bool CheckTwoVectorPerpendicular(Vector3 vectorA, Vector3 vectorB, float tolerance)
{
return Mathf.Abs(Vector3.Dot(vectorA, vectorB)) < tolerance;
}
#endregion
#region 二次贝塞尔曲线
public static List<Vector3> GetQuadraticBezierCurve(int segmentCount, Vector3 start, Vector3 controlPoint, Vector3 end)
{
List<Vector3> curve = new List<Vector3>();
for (int i = 0; i <= segmentCount; i++)
{
float t = i / (float)segmentCount;
Vector3 pixel = CalculateQuadraticBezierPoint(t, start, controlPoint, end);
curve.Add(pixel);
}
return curve;
}
public static List<Vector3> GetQuadraticBezierCurve(int segmentCount, float fromT, float toT, Vector3 start, Vector3 controlPoint, Vector3 end)
{
List<Vector3> curve = new List<Vector3>();
for (int i = 0; i <= segmentCount; i++)
{
float t = (i / (float)segmentCount) * (toT - fromT) + fromT;
Vector3 pixel = CalculateQuadraticBezierPoint(t, start, controlPoint, end);
curve.Add(pixel);
}
return curve;
}
public static Vector3 CalculateQuadraticBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
{
float u = 1 - t;
float tt = t * t;
float uu = u * u;
Vector3 p = uu * p0;
p += 2 * u * t * p1;
p += tt * p2;
return p;
}
// 获得曲线某点处切线方向(方向向量)
public static Vector3 GetQuadraticBezierDirAtPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
{
return (2 * (p0 + -2 * p1 + p2) * t + 2 * p1 - 2 * p0).normalized;
}
public static double GetQuadraticBezierT(Vector2 point, Vector2 p0, Vector2 p1, Vector2 p2)
{
Vector2 a = p0 - 2 * p1 + p2;
Vector2 b = 2 * (p1 - p0);
Vector2 c = p0 - point;
double t = (-b.x + Math.Pow(b.x * b.x - 4 * a.x * c.x, 0.5f)) / (2 * a.x);
//Debug.Log("t:" + t);
return t;
}
#endregion
#region 一些计算
static double mult(Vector2 a, Vector2 b, Vector2 c)
{
return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y);
}
static float max(float a, float b)
{
return a > b ? a : b;
}
static float min(float a, float b)
{
return a < b ? a : b;
}
/// <summary>
/// 计算两个向量的叉乘。
/// </summary>
/// <param name="pt1"></param>
/// <param name="pt2"></param>
/// <returns></returns>
static float CrossMul(Vector2 pt1, Vector2 pt2)
{
return pt1.x * pt2.y - pt1.y * pt2.x;
}
#endregion
}