unity 简单的四边形位置矫正
此功能将右边的四边行内的坐标点转换成左侧的矩形坐标点
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Calibration : MonoBehaviour { [Header("四边形内要校准的点")] public Vector2 PointsToBeCalibratedInQuadrilateral; [Header("四边形左上边点")] public Vector2 UpperLeftPointOfQuadrilateral; [Header("四边形左下边点")] public Vector2 LowerLeftPointOfQuadrilateral; [Header("四边形右上边点")] public Vector2 UpperRightPointOfQuadrilateral; [Header("四边形右下边点")] public Vector2 LowerIightPointOfQuadrilateral; [Header("要缩放的大小")] public Vector2 ZoomSize; [Header("矫正后位置")] public Vector2 CorrectedPosition; [Header("四边形焦点")] public Vector2 QuadrilateralFocus; void Start() { QuadrilateralFocus = CrossPoint(UpperLeftPointOfQuadrilateral, LowerIightPointOfQuadrilateral, LowerLeftPointOfQuadrilateral, UpperRightPointOfQuadrilateral); } public Vector2 UPdateVector(Vector2 vector ) { PointsToBeCalibratedInQuadrilateral = vector; StartCalibration(); return CorrectedPosition; } //开始校准 void StartCalibration() { if (IsThePointWithinTheQuadrilateral(PointsToBeCalibratedInQuadrilateral)) { // Debug.Log("在四边行内"); if (PointsToBeCalibratedInQuadrilateral == QuadrilateralFocus) { // Debug.Log("点在中点"); CorrectedPosition = QuadrilateralFocus; } else { if (IsThePointOnTheDiagonal(PointsToBeCalibratedInQuadrilateral, UpperLeftPointOfQuadrilateral, LowerIightPointOfQuadrilateral)) { // Debug.Log("在左上到右下的对角线上"); float Di1 = Vector2.Distance(UpperLeftPointOfQuadrilateral, QuadrilateralFocus); float Di2 = Vector2.Distance(PointsToBeCalibratedInQuadrilateral, UpperLeftPointOfQuadrilateral); if (Di1 > Di2) { // Debug.Log("点在左上半段线上"); float BiLi = Di1 / Di2; Vector2 FdZ = ZoomSize / 2; Vector2 fanhui = new Vector2(FdZ.x / BiLi, ZoomSize.y - (FdZ.y / BiLi)); CorrectedPosition = fanhui; } else { // Debug.Log("点在右下半段线上"); float Di3 = Vector2.Distance(LowerIightPointOfQuadrilateral, QuadrilateralFocus); float Di4 = Vector2.Distance(PointsToBeCalibratedInQuadrilateral, LowerIightPointOfQuadrilateral); float BiLi = Di3 / Di4; Vector2 FdZ = ZoomSize / 2; Vector2 fanhui = new Vector2(ZoomSize.x - (FdZ.x / BiLi), FdZ.y / BiLi); CorrectedPosition = fanhui; } } else { if (IsThePointOnTheDiagonal(PointsToBeCalibratedInQuadrilateral, UpperRightPointOfQuadrilateral, LowerLeftPointOfQuadrilateral)) { // Debug.Log(" 在左下到右上的对角线上"); float Di1 = Vector2.Distance(LowerLeftPointOfQuadrilateral, QuadrilateralFocus); float Di2 = Vector2.Distance(PointsToBeCalibratedInQuadrilateral, LowerLeftPointOfQuadrilateral); if (Di1 > Di2) { // Debug.Log("点在左下半段线上"); float BiLi = Di1 / Di2; Vector2 FdZ = ZoomSize / 2; Vector2 fanhui = new Vector2(FdZ.x / BiLi, FdZ.y / BiLi); CorrectedPosition = fanhui; } else { // Debug.Log("点在右上半段线上"); float Di3 = Vector2.Distance(UpperRightPointOfQuadrilateral, QuadrilateralFocus); float Di4 = Vector2.Distance(PointsToBeCalibratedInQuadrilateral, UpperRightPointOfQuadrilateral); float BiLi = Di3 / Di4; Vector2 FdZ = ZoomSize / 2; Vector2 fanhui = new Vector2(ZoomSize.x - (FdZ.x / BiLi), ZoomSize.y - (FdZ.y / BiLi)); CorrectedPosition = fanhui; } } else { if (InTriangleOrNot(PointsToBeCalibratedInQuadrilateral, QuadrilateralFocus, LowerLeftPointOfQuadrilateral, UpperLeftPointOfQuadrilateral)) { // Debug.Log("在左侧三角形内"); InsideLeftTriangle(); } else { // Debug.Log("没有在对角线上"); if (InTriangleOrNot(PointsToBeCalibratedInQuadrilateral, QuadrilateralFocus, UpperLeftPointOfQuadrilateral, UpperRightPointOfQuadrilateral)) { // Debug.Log("在上侧三角形内"); InsideTheUpperTriangle(); } else { if (InTriangleOrNot(PointsToBeCalibratedInQuadrilateral, QuadrilateralFocus, UpperRightPointOfQuadrilateral, LowerIightPointOfQuadrilateral)) { // Debug.Log("在右侧三角形内"); InsideRightTriangle(); } else { if (InTriangleOrNot(PointsToBeCalibratedInQuadrilateral, QuadrilateralFocus, LowerIightPointOfQuadrilateral, LowerLeftPointOfQuadrilateral)) { // Debug.Log("在下测三角形内"); InsideTheLowerTriangle(); } } } } } } } } else { // Debug.Log("没有在四边形内"); } } //四边形中心点 void Zhong() { //已知直线上的两点P1(X1,Y1) P2(X2,Y2), P1 P2两点不重合。 故直线方程为(y2-y1)x+(x1-x2)y+x2y1-x1y2=0 // 左上到右下 方程 float a= LowerIightPointOfQuadrilateral.y - UpperLeftPointOfQuadrilateral.y; float b= UpperLeftPointOfQuadrilateral.x - LowerIightPointOfQuadrilateral.x; float c = (LowerIightPointOfQuadrilateral.x * UpperLeftPointOfQuadrilateral.y) - (UpperLeftPointOfQuadrilateral.x * LowerIightPointOfQuadrilateral.y); // 所以直线AX+BY+C=0 //右上到左下方程 float d = UpperRightPointOfQuadrilateral.y - LowerLeftPointOfQuadrilateral.y; float e = LowerLeftPointOfQuadrilateral.x - UpperRightPointOfQuadrilateral.x; float f = (UpperRightPointOfQuadrilateral.x * LowerLeftPointOfQuadrilateral.y) - (LowerLeftPointOfQuadrilateral.x * UpperRightPointOfQuadrilateral.y); float y = ((-(c*d/a/e)-(-f/e))) / ((b * d / a / e) - 1); float x = (-c / a) - (b / a * y); QuadrilateralFocus.x = x; QuadrilateralFocus.y = y; } // 点是否在三角形内 bool InTriangleOrNot(Vector3 p, Vector3 a, Vector3 b, Vector3 c) { Vector3 pa = a - p; Vector3 pb = b - p; Vector3 pc = c - p; Vector3 pab = Vector3.Cross(pa, pb); Vector3 pbc = Vector3.Cross(pb, pc); Vector3 pca = Vector3.Cross(pc, pa); float d1 = Vector3.Dot(pab, pbc); float d2 = Vector3.Dot(pab, pca); float d3 = Vector3.Dot(pbc, pca); if (d1 > 0 && d2 > 0 && d3 > 0) return true; return false; } //点是否在对角线上 bool IsThePointOnTheDiagonal(Vector2 p ,Vector2 a, Vector2 b) { float A = a.y - b.y; float B = b.x - a.x; float C = (a.x * b.y) - (b.x * a.y); if ((A * p.x) + (B * p.y) + C == 0) { return true; } return false; } // 点是否在四边形内 bool IsThePointWithinTheQuadrilateral(Vector2 p ) { Vector3 pa = LowerLeftPointOfQuadrilateral - p; Vector3 pb = UpperLeftPointOfQuadrilateral - p; Vector3 pc = UpperRightPointOfQuadrilateral - p; Vector3 pd = LowerIightPointOfQuadrilateral - p; Vector3 pab = Vector3.Cross(pa, pb); Vector3 pbc = Vector3.Cross(pb, pc); Vector3 pcd = Vector3.Cross(pc, pd); Vector3 pca = Vector3.Cross(pd, pa); float d1 = Vector3.Dot(pab, pbc); float d2 = Vector3.Dot(pab, pcd); float d3 = Vector3.Dot(pab, pca); float d4 = Vector3.Dot(pbc, pcd); float d5 = Vector3.Dot(pbc, pca); float d6 = Vector3.Dot(pcd, pca); // float d4 = Vector3.Dot(pbc, pca); if (d1 > 0 && d2 > 0 && d3 > 0 && d4 > 0 && d5 > 0 && d6 > 0) { return true; } return false; } //计算三角形面积 float CalculateTriangleArea(Vector2 a, Vector2 b, Vector2 c) { //海伦公式:p=(a+b+c)/2; S = √[p(p-a)(p-b)(p-c)] float dab = Vector2.Distance(a, b); float dac = Vector2.Distance(a, c); float dbc = Vector2.Distance(b, c); float half = (dab + dac + dbc) / 2; return Mathf.Sqrt(half * (half - dab) * (half - dac) * (half - dbc)); } //左侧三角形内 void InsideLeftTriangle() { Vector2 Jiaodian = CrossPoint(LowerLeftPointOfQuadrilateral, UpperLeftPointOfQuadrilateral, QuadrilateralFocus, PointsToBeCalibratedInQuadrilateral); float Di1 = Vector2.Distance(Jiaodian, LowerLeftPointOfQuadrilateral); float Di2 = Vector2.Distance(LowerLeftPointOfQuadrilateral, UpperLeftPointOfQuadrilateral); float BiLi = Di2 / Di1; Vector2 Fdjiaodian = new Vector2(0, ZoomSize.y / BiLi); Vector2 FdZ = ZoomSize / 2; float Di3 = Vector2.Distance(QuadrilateralFocus, Jiaodian); float Di4 = Vector2.Distance(PointsToBeCalibratedInQuadrilateral, Jiaodian); float BiLi1 = Di3 / Di4; float fx = (FdZ.x - Fdjiaodian.x) / BiLi1; float fy = (FdZ.y - Fdjiaodian.y) / BiLi1+Fdjiaodian.y; Vector2 fanhui = new Vector2(fx, fy); CorrectedPosition = fanhui; } //右侧三角形内 void InsideRightTriangle() { Vector2 Jiaodian = CrossPoint(LowerIightPointOfQuadrilateral, UpperRightPointOfQuadrilateral, QuadrilateralFocus, PointsToBeCalibratedInQuadrilateral); float Di1 = Vector2.Distance(Jiaodian, LowerIightPointOfQuadrilateral); float Di2 = Vector2.Distance(LowerIightPointOfQuadrilateral, UpperRightPointOfQuadrilateral); float BiLi = Di2 / Di1; Vector2 Fdjiaodian = new Vector2(ZoomSize.x, ZoomSize.y / BiLi); Vector2 FdZ = ZoomSize / 2; float Di3 = Vector2.Distance(QuadrilateralFocus, Jiaodian); float Di4 = Vector2.Distance(PointsToBeCalibratedInQuadrilateral, Jiaodian); float BiLi1 = Di3 / Di4; float fx = (FdZ.x - Fdjiaodian.x) / BiLi1 + ZoomSize.x; float fy = (FdZ.y - Fdjiaodian.y) / BiLi1 + Fdjiaodian.y; Vector2 fanhui = new Vector2(fx, fy); CorrectedPosition = fanhui; } //上侧三角形内 void InsideTheUpperTriangle() { Vector2 Jiaodian = CrossPoint(UpperLeftPointOfQuadrilateral,UpperRightPointOfQuadrilateral,QuadrilateralFocus,PointsToBeCalibratedInQuadrilateral); float Di1 = Vector2.Distance(Jiaodian, UpperLeftPointOfQuadrilateral); float Di2 = Vector2.Distance(UpperRightPointOfQuadrilateral, UpperLeftPointOfQuadrilateral); float BiLi = Di2 / Di1; Vector2 Fdjiaodian = new Vector2(ZoomSize.x/BiLi, ZoomSize.y); Vector2 FdZ = ZoomSize / 2; float Di3 = Vector2.Distance(QuadrilateralFocus, Jiaodian); float Di4 = Vector2.Distance(PointsToBeCalibratedInQuadrilateral, Jiaodian); float BiLi1 = Di3 / Di4; float fx = ( FdZ.x -Fdjiaodian.x ) / BiLi1+Fdjiaodian.x; float fy = ZoomSize.y-( (FdZ.y) / BiLi1) ; Vector2 fanhui = new Vector2(fx, fy); CorrectedPosition = fanhui; } //下侧三角形内 void InsideTheLowerTriangle() { Vector2 Jiaodian = CrossPoint(LowerLeftPointOfQuadrilateral, LowerIightPointOfQuadrilateral, QuadrilateralFocus, PointsToBeCalibratedInQuadrilateral); float Di1 = Vector2.Distance(Jiaodian, LowerLeftPointOfQuadrilateral); float Di2 = Vector2.Distance(LowerIightPointOfQuadrilateral, LowerLeftPointOfQuadrilateral); float BiLi = Di2 / Di1; Vector2 Fdjiaodian = new Vector2(ZoomSize.x / BiLi, 0); Vector2 FdZ = ZoomSize / 2; float Di3 = Vector2.Distance(QuadrilateralFocus, Jiaodian); float Di4 = Vector2.Distance(PointsToBeCalibratedInQuadrilateral, Jiaodian); float BiLi1 = Di3 / Di4; float fx = (FdZ.x -Fdjiaodian.x) / BiLi1+Fdjiaodian.x ; float fy = (FdZ.y) / BiLi1; Vector2 fanhui = new Vector2(fx, fy); CorrectedPosition = fanhui; } // 两条直线焦点 Vector2 CrossPoint(Vector2 line1, Vector2 line2, Vector2 line3, Vector2 line4) //交点 { float x_member, x_denominator, y_member, y_denominator; Vector2 cross_point; x_denominator = line4.x* line2.y - line4.x* line1.y - line3.x* line2.y + line3.x* line1.y - line2.x* line4.y + line2.x* line3.y + line1.x* line4.y - line1.x* line3.y; x_member = line3.y* line4.x*line2.x - line4.y* line3.x* line2.x - line3.y* line4.x* line1.x + line4.y* line3.x* line1.x - line1.y* line2.x* line4.x + line2.y* line1.x* line4.x + line1.y* line2.x* line3.x - line2.y* line1.x* line3.x; if (x_denominator == 0) cross_point.x = 0; else cross_point.x = x_member / x_denominator; y_denominator = line4.y* line2.x - line4.y* line1.x - line3.y* line2.x + line1.x* line3.y - line2.y* line4.x + line2.y* line3.x + line1.y* line4.x - line1.y* line3.x; y_member = -line3.y* line4.x*line2.y + line4.y* line3.x* line2.y + line3.y* line4.x* line1.y - line4.y* line3.x* line1.y + line1.y* line2.x* line4.y - line1.y* line2.x* line3.y - line2.y* line1.x* line4.y + line2.y* line1.x* line3.y; if (y_denominator == 0) cross_point.y = 0; else cross_point.y = y_member / y_denominator; return cross_point; //平行返回(0,0) } }
使用方法, 先要设置号四边形的四个顶点坐标, 和要缩放的大小, 之后调用 Vector2 UPdateVector(Vector2 vector ) 传入四边形内点的位置。