げんめんアルゴリズム

22223 ワード

using System;
using System.Collections.Generic;
using System.Linq;
using GenesisWinForm;
using GenesisWinForm.G3DObject.G3DCore;
//using System.Threading.Tasks;
using GenesisWinForm.MathG3D;
using OpenTK;

public static class CollapseVertexFunction
{
    /// 
    ///       cost
    /// 
    public static double ComputeEdgeCollapseCost(Vertex u, Vertex v)
    {

        // if we collapse edge uv by moving u to v then how

        // much different will the model change, i.e. the “error”.

        double edgelength = (v.position - u.position).Length;

        double curvature = 0;

        // find the “sides” triangles that are on the edge uv

        List sides = new List();

        for (int i = 0; i < u.Face.Count; i++)
        {

            if (u.Face[i].HasVertex(v.id))
            {

                sides.Add(u.Face[i]);

            }

        }

        // use the triangle facing most away from the sides

        // to determine our curvature term

        for (int i = 0; i < u.Face.Count; i++)
        {

            double mincurv = 1;

            for (int j = 0; j < sides.Count; j++)
            {

                // use dot product of face normals.

                double dotprod = Vector3d.Dot(u.Face[i].normal, sides[j].normal);

                mincurv = Math.Min(mincurv, (1 - dotprod) / 2.0f);

            }

            curvature = Math.Max(curvature, mincurv);

        }
        ////Debug.Log("curvature" + curvature);
        return edgelength * curvature;

    }

    /// 
    ///         cost
    /// 
    public static void ComputeEdgeCostAtVertex(Vertex v)
    {

        if (v.neighbor.Count == 0)
        {

            v.collapse = null;

            v.cost = -0.01f;

            return;

        }

        v.cost = 1000000;

        v.collapse = null;

        // search all neighboring edges for “least cost” edge

        for (int i = 0; i < v.neighbor.Count; i++)
        {

            double c;

            c = ComputeEdgeCollapseCost(v, v.neighbor[i]);

            if (c < v.cost)
            {

                v.collapse = v.neighbor[i];

                v.cost = c;

            }

        }

    }

    #region
    /// 
    ///              
    /// 
    //public static int FindTriangleByVertexs(Vertex v1, Vertex v2, Vertex v3)
    //{
    //    TriangleP t = new TriangleP(0);
    //    for (int i = 0; i < v1.Face.Count; i++)
    //    {
    //        for (int j = 0; j < v2.Face.Count; j++)
    //        {
    //            for (int k = 0; k < v3.Face.Count; k++)
    //            {
    //                if (v1.Face[i] == v2.Face[j] && v2.Face[j] == v3.Face[k])
    //                {

    //                    return v1.Face[i].id;
    //                }
    //            }

    //        }

    //    }

    //    return t.id;
    //}


    //public static bool DeleteFace(G3DCore3DObjectOptimize _mesh, TriangleP _triangleP)
    //{

    //    _mesh.DeleteTriangleP(_triangleP.id);

    //    return true;

    //}

    //public static bool DeleteVertexs(G3DCore3DObjectOptimize _mesh, Vertex _v1)
    //{
    //    #region
    //    //Vertex v1 = _v1;
    //    //Vertex v2 = _v1.collapse;

    //    //List v3v4 = FindVertexsHavingSameSide(v1, v2);
    //    //Vertex v3 = v3v4[0];
    //    //Vertex v4 = v3v4[1];
    //    //Vertex v5;//v1v3       ,    v1v3v5  neighbor
    //    //Vertex v6;//v1v4       ,    v1v4v6  neighbor
    //    //Vertex v7;//v2v3       ,    v2v3v7  neighbor
    //    //Vertex v8;//v2v4       ,    v2v4v7  neighbor

    //    //List V2V5 = FindVertexsHavingSameSide(v1, v3);
    //    //List V2V6 = FindVertexsHavingSameSide(v1, v4);
    //    //List V7V1 = FindVertexsHavingSameSide(v2, v3);
    //    //List V8V1 = FindVertexsHavingSameSide(v2, v4);
    //    ////v5
    //    //if (V2V5[0] == v2)
    //    //{
    //    //    v5 = V2V5[1];
    //    //}
    //    //else
    //    //{
    //    //    v5 = V2V5[0];
    //    //}
    //    ////v6
    //    //if (V2V6[0] == v2)
    //    //{
    //    //    v6 = V2V6[1];
    //    //}
    //    //else
    //    //{
    //    //    v6 = V2V6[0];
    //    //}
    //    ////v7
    //    //if (V7V1[0] == v1)
    //    //{
    //    //    v7 = V7V1[1];
    //    //}
    //    //else
    //    //{
    //    //    v7 = V7V1[0];
    //    //}
    //    ////v8
    //    //if (V8V1[0] == v1)
    //    //{
    //    //    v8 = V8V1[1];
    //    //}
    //    //else
    //    //{
    //    //    v8 = V8V1[0];
    //    //}
    //    ////  v135,v146,v237,v248    id
    //    //int v135 = FindTriangleByVertexs(v1, v3, v5);
    //    //int v146 = FindTriangleByVertexs(v1, v4, v6);
    //    //int v237 = FindTriangleByVertexs(v2, v3, v7);
    //    //int v248 = FindTriangleByVertexs(v2, v4, v8);
    //    //int v123 = FindTriangleByVertexs(v1, v2, v3);
    //    //int v124 = FindTriangleByVertexs(v1, v2, v4);
    //    ////  face->neighbor
    //    //for (int i = 0; i < _mesh.AllTrianglesOld[v135].NeighborID.Length; i++)
    //    //{
    //    //    if (_mesh.AllTrianglesOld[v135].NeighborID[i] == v123)
    //    //    {//  v135
    //    //        _mesh.AllTrianglesOld[v135].NeighborID[i] = v237;
    //    //    }

    //    //}
    //    //for (int i = 0; i < _mesh.AllTrianglesOld[v146].NeighborID.Length; i++)
    //    //{
    //    //    if (_mesh.AllTrianglesOld[v146].NeighborID[i] == v124)
    //    //    {//  v146
    //    //        _mesh.AllTrianglesOld[v146].NeighborID[i] = v248;
    //    //    }

    //    //}
    //    //for (int i = 0; i < _mesh.AllTrianglesOld[v237].NeighborID.Length; i++)
    //    //{
    //    //    if (_mesh.AllTrianglesOld[v237].NeighborID[i] == v123)
    //    //    {//  v237
    //    //        _mesh.AllTrianglesOld[v237].NeighborID[i] = v135;
    //    //    }

    //    //}
    //    //for (int i = 0; i < _mesh.AllTrianglesOld[v248].NeighborID.Length; i++)
    //    //{
    //    //    if (_mesh.AllTrianglesOld[v248].NeighborID[i] == v124)
    //    //    {//  v248
    //    //        _mesh.AllTrianglesOld[v248].NeighborID[i] = v146;
    //    //    }

    //    //}




    //    //if (v135 == 0 || v146 == 0 || v237 == 0 || v248 == 0)
    //    //{

    //    //    return false;
    //    //}
    //    #endregion

    //    List v3v4 = FindVertexsHavingSameSide(_v1, _v1.collapse);

    //    int v123 = FindTriangleByVertexs(_v1, _v1.collapse, v3v4[0]);
    //    int v124 = FindTriangleByVertexs(_v1, _v1.collapse, v3v4[1]);

    //    for (int i = 0; i < _v1.Face.Count; i++)
    //    {
    //        for (int j = 0; j < _v1.collapse.Face.Count; j++)
    //        {
    //            if (_v1.Face[i].HasVertex(v3v4[0].id) == _v1.collapse.Face[j].HasVertex(v3v4[0].id))
    //            {
    //                for (int k = 0; k < _v1.Face[i].NeighborID.Length; k++)
    //                {
    //                    if (_v1.Face[i].NeighborID[k] == v123)
    //                    {
    //                        _v1.Face[i].NeighborID[k] = _v1.collapse.Face[j].id;
    //                        break;
    //                    }
    //                }

    //                for (int k = 0; k < _v1.collapse.Face[j].NeighborID.Length; k++)
    //                {
    //                    if (_v1.Face[i].NeighborID[k] == v123)
    //                    {
    //                        _v1.Face[i].NeighborID[k] = _v1.collapse.Face[j].id;
    //                        break;
    //                    }
    //                }

    //            }

    //            if (_v1.Face[i].HasVertex(v3v4[1].id) == _v1.collapse.Face[j].HasVertex(v3v4[1].id))
    //            {
    //                for (int k = 0; k < _v1.Face[i].NeighborID.Length; k++)
    //                {
    //                    if (_v1.Face[i].NeighborID[k] == v124)
    //                    {
    //                        _v1.Face[i].NeighborID[k] = _v1.collapse.Face[j].id;
    //                        break;
    //                    }
    //                }

    //                for (int k = 0; k < _v1.collapse.Face[j].NeighborID.Length; k++)
    //                {
    //                    if (_v1.Face[i].NeighborID[k] == v124)
    //                    {
    //                        _v1.Face[i].NeighborID[k] = _v1.collapse.Face[j].id;
    //                        break;
    //                    }
    //                }

    //            }
    //        }

    //    }




    //    _mesh.DeleteVertex(_v1.id);

    //    return true;

    //}
    #endregion
    /// 
    ///   mesh
    /// 
    public static bool UpdateMesh(ref G3DCore3DObjectOptimize _mesh)
    {
        //  VertexOld  VertexX

        _mesh.AllVertexsX.Clear();
        foreach (KeyValuePair t in _mesh.AllVertexsOld)
        {

            _mesh.AllVertexsX.Add(t.Value);

        }

        foreach (KeyValuePair t in _mesh.AllTrianglesOld)
        {
            t.Value.ComputeNormalByPostion();

        }


        for (int i = 0; i < _mesh.AllVertexsX.Count; i++)
        {

            _mesh.AllVertexsX[i].ComputeNormal();


        }

        return true;

    }

    /// 
    ///               
    /// 
    public static bool IsPointInTriangle(Vertex _v1)
    {
        ////Debug.Log("     IsPointInTriangle ,_v1   " + _v1.id);
        if (_v1.neighbor.Count < 3)
        {

            return false;
        }

        for (int vertexCont = 0; vertexCont < _v1.neighbor.Count; vertexCont++)
        {//  v1    ,   v1    

            List v3v4 = FindVertexsHavingSameSide(_v1, _v1.neighbor[vertexCont]);

            if (v3v4.Count < 2)//       , v1      
            {
                return false;
            }
            else if (vertexCont < _v1.neighbor.Count - 1)
            {//           ,    
             ////Debug.Log("       " + _v1.neighbor.Count+ ",     "+ vertexCont+" ");

            }
            if (vertexCont == _v1.neighbor.Count - 1)
            { //                        2, v1   
                return true;
            }


        }

        return false;
    }
    /// 
    ///               
    /// 
    public static List FindVertexsHavingSameSide(Vertex v1, Vertex v2)
    {
        List list = new List();
        for (int i = 0; i < v1.neighbor.Count; i++)
        {
            for (int j = 0; j < v2.neighbor.Count; j++)
            {

                if (v1.neighbor[i].id == v2.neighbor[j].id)
                {
                    list.Add(v1.neighbor[i]);
                }
                if (list.Count == 2)
                {
                    return list;
                }
            }

        }


        return list;
    }


    /// 
    /// mesh    ,threshold        ,         , d
    public static void Start(ref G3DCore3DObjectOptimize object3D, int targetCount)
    {

        int count = object3D.AllVertexsX.Count;//    

        UpdateMesh(ref object3D);

        //List contractileValueList = new List();
        //SortedList contractileValueList1 = new SortedList();//    ,
        Dictionary VertexIDToCost = new Dictionary();
        VertexIDToCost.Clear();
        foreach (KeyValuePair t in object3D.AllVertexsOld)//        ,     
        {
            ////Debug.Log("      " + (i+1) + "  ,  " + (count - i-1) + "  ");
            ComputeEdgeCostAtVertex(t.Value);
            VertexIDToCost.Add(t.Value.id, t.Value.cost);
            //ContractileValue temp = new ContractileValue(t.Value);
            //idToIndex.Add(t.Key,indx);
            //contractileValueList.Add(temp);
            //contractileValueListOrigin.Add(temp);

        }//    

        Dictionary dic1_SortedByValue = VertexIDToCost.OrderBy(o => o.Value).ToDictionary(p => p.Key, o => o.Value);

        VertexIDToCost = dic1_SortedByValue;

        //SortContractileValueList(ref contractileValueList);//           ,              
        //contractileValueList.OrderBy(p => p.value);                                                 //         
        ////Debug.Log("OrderList.Count = " + contractileValueList.Count);

        int targetNumber = object3D.AllVertexsOld.Count - targetCount;
        ////Debug.Log("targetNumber" + targetNumber + "object3D.AllTrianglesOld.Count - targetCount" + (object3D.AllTrianglesOld.Count - targetCount));


        while (targetNumber != 0)
        {
            if (VertexIDToCost.Count > 0)
            {

                ////Debug.Log("  " + targetNumber + "    ");
                int temp = VertexIDToCost.Keys.First();
                ////Debug.Log("    id" + temp);
                ////Debug.Log("if costToVertexs  " + VertexIDToCost.Count);
                if (IsPointInTriangle(object3D.AllVertexsOld[temp]))
                {
                    ////Debug.Log("   contractileValueList  "+ contractileValueList.Count);
                    targetNumber--;
                    if (targetNumber == 0) {
                        Console.Write("");
                    }
                    //bool b = Collapse(ref object3D, contractileValueList[0].v1, contractileValueList[0].v1.collapse,ref contractileValueList);//     , ,     ,           
                    //if (b)
                    //{
                    //    #region      
                    //    contractileValueList.Clear();
                    //    foreach (KeyValuePair t in object3D.AllVertexsOld)
                    //    {

                    //        ContractileValue temp1 = new ContractileValue(t.Value);
                    //        contractileValueList.Add(temp1);

                    //    }

                    //    SortContractileValueList(ref contractileValueList);
                    //    #endregion


                    //}

                    Collapse(ref object3D, object3D.AllVertexsOld[temp], object3D.AllVertexsOld[temp].collapse, ref VertexIDToCost);



                }
                else
                {
                    // //Debug.Log("    ");
                    VertexIDToCost.Remove(VertexIDToCost.Keys.First());
                    //contractileValueList.RemoveAt(0);

                }
            }
            else
            {
                break;
            }
        }
        UpdateMesh(ref object3D);
        //Debug.Log("    " + (count - object3D.AllVertexsX.Count) * 2);
        //Debug.Log("  ");

    }


    /// 
    ///   
    /// 
    public static bool Collapse(ref G3DCore3DObjectOptimize _mesh, Vertex u, Vertex v, ref Dictionary dic)
    {
        List xxx = FindVertexsHavingSameSide(u, v);//v3v4
        TriangleP t1 = new TriangleP(-1);
        TriangleP t2 = new TriangleP(-1); //      
        int i;
        List tmp = new List();//  u       

        v.RemoveNeighbor(u);//v  u
        u.RemoveNeighbor(v);//u    v


        // Collapse the edge uv by moving vertex u onto v


        if (v == null)
        {

            // u is a vertex all by itself so just delete it

            _mesh.DeleteVertex(u.id);

            return true;

        }

        // List tmpTList = new List();
        // make tmp a list of all the neighbors of u
        for (i = 0; i < u.neighbor.Count; i++)
        {

            tmp.Add(u.neighbor[i]);

        }

        tmp.Remove(v);


        // delete triangles on edge uv:

        int iddd = 0;
        for (i = u.Face.Count - 1; i >= 0; i--)
        {

            if (u.Face[i].HasVertex(v.id))
            {
                // delete(u.face[i]);
                //  u     u.Face[i]

                iddd++;
                if (iddd == 1)
                {
                    t1 = u.Face[i];
                }
                if (iddd == 2)
                {
                    t2 = u.Face[i];
                    break;
                }


                //List trianglePs = new List()                           
            }

        }//      t1 t2         u  v,u  t1t2       v  u,v  t1t2

        v.Face.Remove(t1);
        u.Face.Remove(t1);
        v.Face.Remove(t2);
        u.Face.Remove(t2);

        //  t3t4t5t6 neighborID
        bool bo = false;
        for (int k = 0; k < u.Face.Count; k++)
        {
            for (int m = 0; m < v.Face.Count; m++)
            {
                if (u.Face[k].NeighborID.Contains(t1.id) && v.Face[m].NeighborID.Contains(t1.id))
                {

                    int tem1 = Array.IndexOf(u.Face[k].NeighborID, t1.id);
                    int tem2 = Array.IndexOf(v.Face[m].NeighborID, t1.id);
                    u.Face[k].NeighborID[tem1] = v.Face[m].id;
                    v.Face[m].NeighborID[tem2] = u.Face[k].id;
                    //_mesh.DeleteTriangleP(u.Face[i].id);
                    //iddd++;
                    bo = true;
                    //v.Face.Add(u.Face[k]);

                }
                if (bo)
                {
                    break;
                }

            }
            if (bo)
            {
                break;
            }

        }

        bo = false;
        for (int k = 0; k < u.Face.Count; k++)
        {
            for (int m = 0; m < v.Face.Count; m++)
            {
                if (u.Face[k].NeighborID.Contains(t2.id) && v.Face[m].NeighborID.Contains(t2.id))
                {

                    int tem1 = Array.IndexOf(u.Face[k].NeighborID, t2.id);
                    int tem2 = Array.IndexOf(v.Face[m].NeighborID, t2.id);
                    u.Face[k].NeighborID[tem1] = v.Face[m].id;
                    v.Face[m].NeighborID[tem2] = u.Face[k].id;
                    //_mesh.DeleteTriangleP(u.Face[i].id);
                    //iddd++;
                    bo = true;
                    //v.Face.Add(u.Face[k]);

                }
                if (bo)
                {
                    break;
                }

            }
            if (bo)
            {
                break;
            }

        }



        for (i = u.Face.Count - 1; i >= 0; i--)
        {
            u.Face[i].ReplaceVertex(u, v);
            u.Face[i].ComputeNormalByPostion();
        }//u  t1t2      v  u        

        foreach (TriangleP t in u.Face)
        {
            v.Face.Add(t);

        }//v  t1t2     u     t1t2    v face 
        ////Debug.Log("mesh    " + _mesh.AllTrianglesOld.Count);
        // update remaining triangles to have v instead of u
        int j = u.neighbor.Count;//u v         
        for (i = 0; i < j; i++)
        {
            u.neighbor[i].RemoveNeighbor(u);
            u.neighbor[i].AddNeighbor(v);//u v         v neighbor
            v.AddNeighbor(u.neighbor[i]);//v   u      neighbor
        }
        _mesh.DeleteTriangleP(t1.id);
        _mesh.DeleteTriangleP(t2.id);//mesh   t1t2
        _mesh.DeleteVertex(u.id);//mesh   u
        xxx[0].Face.Remove(t1);
        xxx[1].Face.Remove(t1);
        xxx[0].Face.Remove(t2);
        xxx[1].Face.Remove(t2);//v3v4     t1t2

        v.ComputeNormal();//v           t1t2  u t1t2    ,     
        ComputeEdgeCostAtVertex(v);//    v cost
        if (dic.ContainsKey(v.id))
        {

            dic[v.id] = v.cost;

        }

        //DeleteVertexs(_mesh, u);
        ////Debug.Log("       " + _mesh.AllVertexsOld.Count);
        // recompute the edge collapse costs in neighborhood
        //UpdateMesh(_mesh);

        // //Debug.Log("   contractileValueList  " + _list.Count);
        int jjjj = dic.Keys.First();
        //Debug.Log("        " + jjjj + "   ");

        dic.Remove(jjjj);


        for (i = 0; i < tmp.Count; i++)
        {
            //ContractileValue tt = new ContractileValue(tmp[i]);

            //if (_list.Remove(tt)) {
            //    //Debug.Log("   " + i + " ");

            //}
            ComputeEdgeCostAtVertex(tmp[i]);
            if (dic.ContainsKey(tmp[i].id))
            {
                dic[tmp[i].id] = tmp[i].cost;


            }

            //ContractileValue ttt = new ContractileValue(tmp[i]);
            ////Debug.Log("   " + i + " ");
            //_list.Add(ttt);
            // //Debug.Log("   " + i + " ");                   
        }
        //dic[v.id] = v.cost;
        Dictionary dic1_SortedByValue = dic.OrderBy(o => o.Value).ToDictionary(p => p.Key, o => o.Value);

        dic = dic1_SortedByValue;
        //Debug.Log("          "+ dic.Keys.First());
        //_list.OrderBy(p => p.value);
        // //Debug.Log("   contractileValueList  " + _list.Count);

        return true;

    }



}

namespace GenesisWinForm
{

    /// 
    ///  v1     v2      
    /// 
    public class CollapseVertex
    {
        public CollapseVertex(double _value, Vertex _v1)
        {
            value = _value;
            v1 = _v1;

        }


        public CollapseVertex(Vertex _v1)
        {
            value = _v1.cost;
            v1 = _v1;

        }

        public double value;
        public Vertex v1;

    }
}
, 。 ,