/// <summary> /// テトラメッシュを構築して返す /// </summary> /// <param name="posList"></param> /// <param name="tetraCount">作成されたテトラ数</param> /// <param name="tetraIndexList">テトラ数x4のインデックスリスト</param> /// <param name="tetraSizeList">テトラの重心からの最大距離リスト</param> public static void CalcTetraMesh(List <Vector3> posList, out int tetraCount, out List <int> tetraIndexList, out List <float> tetraSizeList) { tetraCount = 0; tetraIndexList = new List <int>(); tetraSizeList = new List <float>(); // 作業用バッファ List <TetraVertex> vertexList = new List <TetraVertex>(); for (int i = 0; i < posList.Count; i++) { vertexList.Add(new TetraVertex(posList[i], i)); } // 入力頂点のバウンディングボックス Bounds b = new Bounds(posList[0], Vector3.one * 0.01f); foreach (var pos in posList) { b.Encapsulate(pos); } // ポイントをすべて内包するテトラポイントを追加する float areaRadius = Mathf.Max(Mathf.Max(b.extents.x, b.extents.y), b.extents.z); float dist = areaRadius * 100.0f; var tempSV0 = new TetraVertex(); var tempSV1 = new TetraVertex(); var tempSV2 = new TetraVertex(); var tempSV3 = new TetraVertex(); tempSV0.pos = b.center + new Vector3(0.0f, -dist, 0.0f); tempSV1.pos = b.center + new Vector3(-dist, dist, dist); tempSV2.pos = b.center + new Vector3(dist, dist, dist); tempSV3.pos = b.center + new Vector3(0.0f, dist, -dist); int svcnt = vertexList.Count; tempSV0.index = svcnt++; tempSV1.index = svcnt++; tempSV2.index = svcnt++; tempSV3.index = svcnt++; vertexList.Add(tempSV0); vertexList.Add(tempSV1); vertexList.Add(tempSV2); vertexList.Add(tempSV3); // 最初のテトラを分割テトラとして登録 List <Tetra> divideTetras = new List <Tetra>(); var tetra0 = new Tetra(tempSV0, tempSV1, tempSV2, tempSV3); tetra0.CalcCircumcircle(); divideTetras.Add(tetra0); // 重複チェック用 Dictionary <ulong, Tetra> useTetraHash = new Dictionary <ulong, Tetra>(); useTetraHash.Add(tetra0.GetTetraHash(), tetra0); // テトラ構築 for (int k = 0; k < (vertexList.Count - 4); k++) { var point = vertexList[k]; List <Tetra> tempDivTetras = new List <Tetra>(); for (int i = 0; i < divideTetras.Count;) { var tetra = divideTetras[i]; if (tetra.ContainsPoint(point) == false) { if (tetra.IntersectCircumcircle(point.pos)) { // 再分割 var tetra1 = new Tetra(tetra.vertexList[0], tetra.vertexList[1], tetra.vertexList[2], point); var tetra2 = new Tetra(tetra.vertexList[0], tetra.vertexList[2], tetra.vertexList[3], point); var tetra3 = new Tetra(tetra.vertexList[0], tetra.vertexList[3], tetra.vertexList[1], point); var tetra4 = new Tetra(tetra.vertexList[1], tetra.vertexList[2], tetra.vertexList[3], point); tempDivTetras.Add(tetra1); tempDivTetras.Add(tetra2); tempDivTetras.Add(tetra3); tempDivTetras.Add(tetra4); useTetraHash.Remove(tetra.GetTetraHash()); divideTetras.RemoveAt(i); continue; } } i++; } // 次の候補として追加 foreach (var tetra in tempDivTetras) { ulong thash = tetra.GetTetraHash(); if (useTetraHash.ContainsKey(thash) == false) { tetra.CalcCircumcircle(); useTetraHash.Add(thash, tetra); divideTetras.Add(tetra); } else { // 衝突 // 衝突もとも削除する var deltetra = useTetraHash[thash]; useTetraHash.Remove(thash); divideTetras.Remove(deltetra); } } } // 最初に追加したテトラを削除 for (int i = 0; i < divideTetras.Count;) { var tetra = divideTetras[i]; if (tetra.ContainsPoint(tempSV0, tempSV1, tempSV2, tempSV3)) { // このテトラは削除する useTetraHash.Remove(tetra.GetTetraHash()); divideTetras.RemoveAt(i); continue; } i++; } vertexList.Remove(tempSV0); vertexList.Remove(tempSV1); vertexList.Remove(tempSV2); vertexList.Remove(tempSV3); // テトラの検証 for (int i = 0; i < divideTetras.Count;) { var tetra = divideTetras[i]; if (tetra.Verification() == false) { divideTetras.RemoveAt(i); continue; } i++; } // 最終結果を格納 tetraCount = divideTetras.Count; foreach (var tetra in divideTetras) { for (int i = 0; i < 4; i++) { tetraIndexList.Add(tetra.vertexList[i].index); } tetraSizeList.Add(tetra.tetraSize); } }