예제 #1
0
        void SplitTriangle(Triangle t, int splitEdge, int point, Connectivity connectivity)
        {
            int a    = t.edges[splitEdge].a;
            int b    = t.edges[splitEdge].b;
            int c    = t.edges[(splitEdge + 1) % 3].b;
            var list = t.Node.List;

            t.Pull();
            connectivity.Remove(t);
            Triangle nt1 = new Triangle(mesh, a, point, c);
            Triangle nt2 = new Triangle(mesh, point, b, c);

            nt1.vispoints = t.vispoints;
            nt1.height    = t.height;
            nt1.highest   = t.highest;
            nt2.vispoints = new List <int> (t.vispoints);
            nt2.height    = t.height;
            nt2.highest   = t.highest;

            list.AddFirst(nt1.Node);
            list.AddFirst(nt2.Node);
            connectivity.Add(nt1);
            connectivity.Add(nt2);
        }
예제 #2
0
        public FaceSet GetHull()
        {
            FindExtremePoints();


            FaceSet faces = FindSimplex();

            var connectivity = new Connectivity(faces);

            var dupPoints = new HashSet <int> ();

            for (int i = 0; i < mesh.verts.Length; i++)
            {
                for (var f = faces.First; f != null; f = f.Next)
                {
                    if (f.IsDup(i))
                    {
                        dupPoints.Add(i);
                        break;
                    }
                }
                if (dupPoints.Contains(i))
                {
                    continue;
                }
                for (var f = faces.First; f != null; f = f.Next)
                {
                    f.AddPoint(i);
                }
            }
            //Debug.Log($"[Quickhull] dupPoints: {dupPoints.Count}");
            //for (var f = faces.First; f != null; f = f.Next) {
            //	Debug.Log ($"[Quickhull] GetHull {f.vispoints.Count} {f.highest} {f.height}");
            //}

            FaceSet finalFaces = new FaceSet(mesh);

            int          iter = 0;
            BinaryWriter bw   = null;

            var donePoints = new HashSet <int> ();

            while (faces.Count > 0)
            {
                //Debug.Log ($"[Quickhull] iteration {iter}");
                if (dump_faces)
                {
                    bw = new BinaryWriter(File.Open($"/tmp/quickhull-{iter:D5}.bin", FileMode.Create));
                    mesh.Write(bw);
                    faces.Write(bw);
                    finalFaces.Write(bw);
                }
                iter++;
                //int nvis = 0;
                //for (var nf = faces.First; nf != null; nf = nf.Next) {
                //	nvis += nf.vispoints.Count;
                //}
                var f = faces.Pop();
                //Debug.Log ($"[Quickhull] total vis {nvis} f.vis {f.vispoints.Count} faces {faces.Count}");
                if (f.vispoints.Count < 1)
                {
                    finalFaces.Add(f);
                    continue;
                }
                int point = f.vispoints[f.highest];
                //Debug.Log ($"[Quickhull] height {f.height}");
                var litFaces = connectivity.LightFaces(f, point);
                if (dump_faces)
                {
                    bw.Write(point);
                    litFaces.Write(bw);
                }
                //Debug.Log ($"[Quickhull] final:{finalFaces.Count} faces:{faces.Count} lit:{litFaces.Count}");
                connectivity.Remove(litFaces);
                var horizonEdges = litFaces.FindOuterEdges();
                var newFaces     = new FaceSet(mesh);
                foreach (Edge e in horizonEdges)
                {
                    if (e.TouchesPoint(point))
                    {
                        var t         = connectivity[e.reverse];
                        int splitEdge = t.TouchedEdge(point);
                        //Debug.Log ($"[Quickhull] point on edge {splitEdge} {faces.Contains (t)} {finalFaces.Contains (t)} {litFaces.Contains (t)}");
                        if (splitEdge >= 0)
                        {
                            SplitTriangle(t, splitEdge, point, connectivity);
                        }
                    }
                    else
                    {
                        var tri = new Triangle(mesh, e.a, e.b, point);
                        newFaces.Add(tri);
                        connectivity.Add(tri);
                    }
                }
                donePoints.Clear();
                for (var lf = litFaces.First; lf != null; lf = lf.Next)
                {
                    for (int j = 0; j < lf.vispoints.Count; j++)
                    {
                        int p = lf.vispoints[j];
                        if (donePoints.Contains(p))
                        {
                            continue;
                        }
                        donePoints.Add(p);
                        for (var nf = newFaces.First; nf != null; nf = nf.Next)
                        {
                            if (nf.IsDup(p))
                            {
                                dupPoints.Add(p);
                                p = -1;
                                break;
                            }
                        }
                        if (p < 0)
                        {
                            continue;
                        }
                        for (var nf = newFaces.First; nf != null; nf = nf.Next)
                        {
                            nf.AddPoint(p);
                        }
                    }
                }
                //Debug.Log($"[Quickhull] dupPoints: {dupPoints.Count}");
                if (dump_faces)
                {
                    newFaces.Write(bw);
                }
                Triangle next;
                for (var nf = newFaces.First; nf != null; nf = next)
                {
                    next = nf.Next;
                    if (nf.vispoints.Count > 0)
                    {
                        faces.Add(nf);
                    }
                    else
                    {
                        finalFaces.Add(nf);
                    }
                }
                if (dump_faces)
                {
                    bw.Close();
                }
                if (connectivity.error)
                {
                    var vis = new HashSet <int> ();
                    for (var lf = litFaces.First; lf != null; lf = lf.Next)
                    {
                        for (int i = 0; i < lf.vispoints.Count; i++)
                        {
                            vis.Add(lf.vispoints[i]);
                        }
                    }
                    Debug.Log($"[Quickhull] {litFaces.Count} {vis.Count}");
                    for (var lf = litFaces.First; lf != null; lf = lf.Next)
                    {
                        float dist1 = float.PositiveInfinity;
                        float dist2 = float.PositiveInfinity;
                        for (int i = 0; i < 3; i++)
                        {
                            float d = lf.edges[i].Distance(point);
                            if (d < dist1)
                            {
                                dist1 = d;
                            }
                            d = (mesh.verts[point] - mesh.verts[lf.edges[i].a]).magnitude;
                            if (d < dist2)
                            {
                                dist2 = d;
                            }
                        }
                        Debug.Log($"    h:{lf.Dist(point)} d1:{dist1} d2:{dist2} {lf.edges[0].TouchesPoint(point)} {lf.edges[1].TouchesPoint(point)} {lf.edges[2].TouchesPoint(point)}");
                    }
                    break;
                }
            }
            if (dump_faces && !connectivity.error)
            {
                bw = new BinaryWriter(File.Open($"/tmp/quickhull-{iter++:D5}.bin", FileMode.Create));
                mesh.Write(bw);
                faces.Write(bw);
                finalFaces.Write(bw);
                bw.Write((int)-1);
                bw.Write((int)0);
                bw.Write((int)0);
                bw.Close();
            }
            error = connectivity.error;
            return(finalFaces);
        }