找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 163|回复: 0

C++ UE4 将凹多边形拆分为多个凸多边

[复制链接]

0

主题

0

回帖

26

积分

管理员

积分
26
发表于 2024-3-2 20:50:27 | 显示全部楼层 |阅读模式
  1. /*从多边形的有序的点数组获取顶点和三角面数据信息(凹凸多边形)
  2.         参数1: 顶点数组
  3.         参数2: 是否是逆时针
  4.         */
  5. TArray<TArray<FVector>> GetPolygonDataFromOrderVertexs(TArray<FVector> 采用points, bool 采用antiClockwise)
  6. {
  7.         int t采用pointsNum = 采用points.Num();
  8.         if (t采用pointsNum > 3)
  9.         {
  10.                 TArray<TArray<FVector>> polygonDividedArr = DividePolygonIfConcave(采用points, 采用antiClockwise);  //递归
  11.                 if (polygonDividedArr.Num() > 0)
  12.                 {
  13.                         UE采用LOG(LogTemp, Warning, TEXT("多边形分割成了%d  个多边形"), polygonDividedArr.Num());
  14.                 }
  15.                 return polygonDividedArr;
  16.         }
  17.         else
  18.                 UE采用LOG(LogTemp, Error, TEXT("多边形分割失败"));
  19.         return TArray<TArray<FVector>>();
  20. }
  21. //分割
  22. /*检查多边形是否是凹多边形,如果是就切割
  23.         参数1:点集
  24.         参数2:需要返回的被切割多边形1
  25.         参数2:需要返回的被切割多边形2
  26.         */
  27. TArray<TArray<FVector>> DividePolygonIfConcave(TArray<FVector> 采用points, bool 采用antiClockwise)
  28. {
  29.         TArray<TArray<FVector>> polygonDividedArr;
  30.         int t采用pointsNum = 采用points.Num();
  31.         if (采用points.Num() < 3)
  32.         {
  33.                 return polygonDividedArr;
  34.         }
  35.         else if (t采用pointsNum == 3)
  36.         {
  37.                 polygonDividedArr.Add(采用points);
  38.                 return polygonDividedArr;
  39.         }
  40.         else if (t采用pointsNum > 3)
  41.         {
  42.                 TArray<FVector> 采用dividePolygonA;
  43.                 TArray<FVector> 采用dividePolygonB;
  44.                 float t采用hei = 采用points[0].Z;
  45.                 SetPointsZvalueBySpecify(采用points, 0);
  46.                 FVector t采用p1;
  47.                 FVector t采用p2;
  48.                 TArray<FVector> t采用dirs = GetVectorArrByPointsArr(采用points);
  49.                 bool t采用divideResult = false;
  50.                 int t采用indexNew = 0;
  51.                 for (int i = 0; i < t采用dirs.Num(); i++)
  52.                 {
  53.                         t采用p1 = t采用dirs[i];
  54.                         if (i == t采用dirs.Num() - 1)
  55.                         {
  56.                                 t采用p2 = t采用dirs[0];
  57.                                 t采用indexNew = 0;
  58.                         }
  59.                         else
  60.                         {
  61.                                 t采用p2 = t采用dirs[i + 1];
  62.                                 t采用indexNew = i + 1;
  63.                         }
  64.                         float t采用rotateDir = FVector::CrossProduct(t采用p1, t采用p2).Z;
  65.                         //检查出是凹多边形
  66.                         if (t采用rotateDir < -0.01f && 采用antiClockwise == true || t采用rotateDir > 0.01f && 采用antiClockwise == false)
  67.                         {
  68.                                 //UE采用LOG(LogTemp, Warning, TEXT("t采用rotateDir:   %f"), t采用rotateDir);
  69.                                 UE采用LOG(LogTemp, Warning, TEXT("是凹多边形~~~~~~~~~~~"));
  70.                                 //求分割点
  71.                                 t采用divideResult = GetRayIntersectionOfVecInVecArr(t采用dirs, 采用points, i, i, t采用pointsNum - 1, 采用dividePolygonA, 采用dividePolygonB);
  72.                                 if (t采用divideResult == false)
  73.                                 {
  74.                                         t采用divideResult = GetRayIntersectionOfVecInVecArr(t采用dirs, 采用points, i, 0, i - 1, 采用dividePolygonA, 采用dividePolygonB);
  75.                                 }
  76.                                 if (t采用divideResult == false)
  77.                                 {
  78.                                         UE采用LOG(LogTemp, Error, TEXT("线段%d  没有得到分割点"), i);
  79.                                 }
  80.                                 break;
  81.                         }
  82.                 }
  83.                 if (t采用divideResult == false)
  84.                 {
  85.                         SetPointsZvalueBySpecify(采用points, t采用hei);
  86.                         polygonDividedArr.Add(采用points);
  87.                 }
  88.                 else
  89.                 {
  90.                         if (采用dividePolygonA.Num() > 2)
  91.                         {
  92.                                 SetPointsZvalueBySpecify(采用dividePolygonA, t采用hei);
  93.                                 DividePolygonIfConcave(采用dividePolygonA, 采用antiClockwise);
  94.                         }
  95.                         if (采用dividePolygonB.Num() > 2)
  96.                         {
  97.                                 SetPointsZvalueBySpecify(采用dividePolygonB, t采用hei);
  98.                                 DividePolygonIfConcave(采用dividePolygonB, 采用antiClockwise);
  99.                         }
  100.                 }
  101.         }
  102.         return polygonDividedArr;
  103. }
  104. /*给定点数组的Z值统一化
  105.         */
  106. bool SetPointsZvalueBySpecify(TArray<FVector>& 采用points, float 采用zValue)
  107. {
  108.         if (采用points.Num() > 0)
  109.         {
  110.                 for (int i = 0; i < 采用points.Num(); i++)
  111.                 {
  112.                         采用points[i].Z = 采用zValue;
  113.                 }
  114.                 return true;
  115.         }
  116.         return false;
  117. }
  118. /*根据点数组获取向量数组
  119.         */
  120. TArray<FVector> GetVectorArrByPointsArr(const TArray<FVector> 采用points)
  121. {
  122.         TArray<FVector> t采用res;
  123.         int t采用pointsNum = 采用points.Num();
  124.         if (t采用pointsNum > 1)
  125.         {
  126.                 FVector t采用p1;
  127.                 FVector t采用p2;
  128.                 for (int i = 0; i < 采用points.Num(); i++)
  129.                 {
  130.                         t采用p1 = 采用points[i];
  131.                         if (i == t采用pointsNum - 1)
  132.                         {
  133.                                 t采用p2 = 采用points[0];
  134.                         }
  135.                         else
  136.                         {
  137.                                 t采用p2 = 采用points[i + 1];
  138.                         }
  139.                         t采用res.Add(t采用p2 - t采用p1);
  140.                 }
  141.         }
  142.         return t采用res;
  143. }
  144. bool IsRectCross(const FVector& p1, const FVector& p2, const FVector& q1, const FVector& q2)
  145. {
  146.         bool ret = FMath::Min(p1.X, p2.X) <= FMath::Max(q1.X, q2.X) &&
  147.                 FMath::Min(q1.X, q2.X) <= FMath::Max(p1.X, p2.X) &&
  148.                 FMath::Min(p1.Y, p2.Y) <= FMath::Max(q1.Y, q2.Y) &&
  149.                 FMath::Min(q1.Y, q2.Y) <= FMath::Max(p1.Y, p2.Y);
  150.         return ret;
  151. }
  152. //跨立判断
  153. bool IsLineSegmentCross(const FVector& P1, const FVector& P2, const FVector& Q1, const FVector& Q2)
  154. {
  155.         if (
  156.                 ((Q1.X - P1.X) * (Q1.Y - Q2.Y) - (Q1.Y - P1.Y) * (Q1.X - Q2.X)) * ((Q1.X - P2.X) * (Q1.Y - Q2.Y) - (Q1.Y - P2.Y) * (Q1.X - Q2.X)) < 0 ||
  157.                 ((P1.X - Q1.X) * (P1.Y - P2.Y) - (P1.Y - Q1.Y) * (P1.X - P2.X)) * ((P1.X - Q2.X) * (P1.Y - P2.Y) - (P1.Y - Q2.Y) * (P1.X - P2.X)) < 0
  158.                 )
  159.                 return true;
  160.         else
  161.                 return false;
  162. }
  163. /**
  164. 求线段P1P2与Q1Q2的交点。
  165. 先进行快速排斥实验和跨立实验确定有交点再进行计算。
  166. 交点(X,Y)使用引用返回。
  167. 没有验证过
  168. **/
  169. int CheckTwoLineIntersectionResult(const FVector& p1, const FVector& p2, const FVector& q1, const FVector& q2, FVector& t采用intersectionFVector)
  170. {
  171.         if (IsRectCross(p1, p2, q1, q2))
  172.         {
  173.                 if (IsLineSegmentCross(p1, p2, q1, q2))
  174.                 {
  175.                         //求交点
  176.                         float tmpLeft, tmpRight;
  177.                         tmpLeft = (q2.X - q1.X) * (p1.Y - p2.Y) - (p2.X - p1.X) * (q1.Y - q2.Y);
  178.                         tmpRight = (p1.Y - q1.Y) * (p2.X - p1.X) * (q2.X - q1.X) + q1.X * (q2.Y - q1.Y) * (p2.X - p1.X) - p1.X * (p2.Y - p1.Y) * (q2.X - q1.X);
  179.                         float X = ((float)tmpRight / (float)tmpLeft);
  180.                         tmpLeft = (p1.X - p2.X) * (q2.Y - q1.Y) - (p2.Y - p1.Y) * (q1.X - q2.X);
  181.                         tmpRight = p2.Y * (p1.X - p2.X) * (q2.Y - q1.Y) + (q2.X - p2.X) * (q2.Y - q1.Y) * (p1.Y - p2.Y) - q2.Y * (q1.X - q2.X) * (p2.Y - p1.Y);
  182.                         float Y = ((float)tmpRight / (float)tmpLeft);
  183.                         t采用intersectionFVector = FVector(X, Y, p1.Z);
  184.                         return true;
  185.                 }
  186.         }
  187.         return false;
  188. }
  189. //       
  190. TArray<FVector> GetPointsByIndexRange(const TArray<FVector> 采用points, int startIndex, int endIndex)
  191. {
  192.         TArray<FVector> pts;
  193.         int idx = startIndex;
  194.         while ( idx <= endIndex && idx < 采用points.Num() )
  195.         {
  196.                 pts.Add(采用points[idx]);
  197.                 idx++;
  198.                 if (idx >= 采用points.Num())
  199.                         idx = 0;
  200.         }
  201.         return pts;
  202. }
  203. /*从向量数组中获取一个向量在这个数组中的延长线与其他向量的交点
  204.         注意:顺序必须先从这个向量的下标开始,不能是0;交点不包括向量端点
  205.         参数1:方向向量数组
  206.         参数2:对应的点数组(长度需保持一致)
  207.         参数3:这个向量的下标
  208.         参数4,5:开始和结束下标
  209.         参数6,7: 根据交点被切分的两组点数组
  210.         返回值:true 为成功,反之无
  211.         */
  212. bool GetRayIntersectionOfVecInVecArr(const TArray<FVector> 采用dirs, const TArray<FVector> 采用points, const int 采用vecIndex, const int 采用beginIndex, const int 采用endIndex,
  213.         TArray<FVector>& 采用dividePolygonA, TArray<FVector>& 采用dividePolygonB)
  214. {
  215.         int t采用dirsNum = 采用dirs.Num();
  216.         int t采用pointsNum = 采用points.Num();
  217.         if (t采用dirsNum > 3 && t采用pointsNum > 3)
  218.         {
  219.                 if (t采用dirsNum == t采用pointsNum)
  220.                 {
  221.                         if (采用beginIndex >= 0 && 采用beginIndex < t采用dirsNum)
  222.                         {
  223.                                 if (采用endIndex >= 0 && 采用endIndex < t采用dirsNum)
  224.                                 {
  225.                                         int t采用indexNew = 采用vecIndex == (t采用dirsNum - 1) ? 0 : 采用vecIndex + 1;
  226.                                         FVector t采用beginA = 采用points[采用vecIndex];
  227.                                         FVector t采用endA = t采用beginA + 采用dirs[采用vecIndex];
  228.                                         FVector t采用intersectionPoint;
  229.                                         for (int j = 采用beginIndex; j <= 采用endIndex; j++)
  230.                                         {
  231.                                                 if (j != 采用vecIndex && j != t采用indexNew)
  232.                                                 {
  233.                                                         FVector t采用beginB = 采用points[j];
  234.                                                         if (CheckTwoLineIntersectionResult(t采用beginA, t采用endA, t采用beginB, t采用beginB + 采用dirs[j], t采用intersectionPoint) == 2)
  235.                                                         {
  236.                                                                 //给分割的多边形点组加点
  237.                                                                 采用dividePolygonA = GetPointsByIndexRange(采用points, t采用indexNew, j);
  238.                                                                 采用dividePolygonA.Add(t采用intersectionPoint);
  239.                                                                 UE采用LOG(LogTemp, Warning, TEXT("采用dividePolygonA向量数组个数: %d"), 采用dividePolygonA.Num());
  240.                                                                 采用dividePolygonB = GetPointsByIndexRange(采用points, j, t采用indexNew);
  241.                                                                 if (采用dividePolygonB.Num() > 0)
  242.                                                                 {
  243.                                                                         采用dividePolygonB[0] = t采用intersectionPoint;
  244.                                                                 }
  245.                                                                 UE采用LOG(LogTemp, Warning, TEXT("采用dividePolygonB向量数组个数: %d"), 采用dividePolygonB.Num());
  246.                                                                 return true;
  247.                                                         }
  248.                                                 }
  249.                                         }
  250.                                 }
  251.                         }
  252.                 }
  253.         }
  254.         return false;
  255. }
复制代码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|膜结构网

GMT+8, 2024-12-28 15:03 , Processed in 0.111172 second(s), 22 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表