/// <summary> /// 平面上に分布する点集合が与えられたとき、その点集合が作る多角形の情報を返す /// 1. 頂点index (originから見て反時計回り) /// 2. 法線ベクトル /// 3. 中心座標 /// </summary> /// <param name="points"></param> /// <returns></returns> public static (int[] Indices, V3d Center, V3d Norm) PolygonInfo(IEnumerable <V3d> points, V3d origin) { var center = new V3d(points.Average(p => p.X), points.Average(p => p.Y), points.Average(p => p.Z)); var prm = Geometriy.GetPlaneEquationFromPoints(points.Select(p => p.ToVector3DBase())); var norm = new V3d(prm[0], prm[1], prm[2]); if (V3d.Dot(norm, (center - origin)) < 0) { norm = -norm; } //座標変換 (XY平面に投影) var rot = CreateRotationToZ(norm); var vXY = points.Select(p => p - center).Select(p => new V2d(rot.M11 * p.X + rot.M12 * p.Y + rot.M13 * p.Z, rot.M21 * p.X + rot.M22 * p.Y + rot.M23 * p.Z)).ToList(); int i = vXY.FindIndex(p => p.LengthSquared == vXY.Max(q => q.LengthSquared));//原点から最も距離の遠い点を選ぶ //もう一つ点を選び、直線の方程式を産出 List <int> iList = new List <int>(new[] { i }); do { for (int j = 0; j < vXY.Count; j++) { if (j != i) { var V = new V2d(vXY[j].Y - vXY[i].Y, vXY[i].X - vXY[j].X); var c = vXY[j].X * vXY[i].Y - vXY[i].X * vXY[j].Y; if (vXY.All(p => V2d.Dot(p, V) + c <= Th)) { iList.Add(j); i = j; break; } } } } while (i != iList[0]); return(iList.ToArray(), center, norm); }