Esempio n. 1
0
        /// <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);
            }
        }