private void CheckIntegrity()
        {
            int iEnd = faces.Count;
            DualIndexedSet <Tuple <Vertex3, Vertex3> > edgeMap = new DualIndexedSet <Tuple <Vertex3, Vertex3> >(x => new Tuple <Vertex3, Vertex3>(x.Item2, x.Item1));
            Dictionary <int, int> edgeToFace = new Dictionary <int, int>();

            for (int i = 0; i < iEnd; ++i)
            {
                foreach (CH_Polygon.Edge edge in faces[i].Edges)
                {
                    var(edgeMap2, eIndex, isNew) = edgeMap.EnsureAdded(new Tuple <Vertex3, Vertex3>(edge.Start, edge.End));
                    edgeMap = edgeMap2;
                    if (edgeToFace.ContainsKey(eIndex))
                    {
                        throw new ArgumentException("Invalid polyhedron (edge traversed in same direction by more than one face)");
                    }
                    edgeToFace.Add(eIndex, i);
                }
                for (int j = 0; j < iEnd; ++j)
                {
                    if (i == j)
                    {
                        continue;
                    }
                    if (faces[i].Plane.IsCoincidentWith(faces[j].Plane))
                    {
                        throw new ArgumentException("Invalid polyhedron (two faces have the same plane)");
                    }
                    if (faces[j].Vertices.Any(x => faces[i].Plane.Excludes(x)))
                    {
                        throw new ArgumentException("Invalid polyhedron (one face cuts another)");
                    }
                }
            }
            int iEnd2 = edgeMap.Count;

            for (int i = 0; i < iEnd2; ++i)
            {
                if (!(edgeToFace.ContainsKey(i)) || !(edgeToFace.ContainsKey(~i)))
                {
                    throw new ArgumentException("Invalid polyhedron (loose edge)");
                }
            }
        }
        public static CH_Polyhedron Make(ImmutableList <CH_Polygon> facesAway, Vertex3 v)
        {
            ImmutableList <CH_Polygon> facesAway1 = facesAway;

            foreach (CH_Polygon face in facesAway1)
            {
                if (!(face.Plane.Includes(v)))
                {
                    throw new ArgumentException("Polygons must face away from new point");
                }
            }

            DualIndexedSet <Tuple <Vertex3, Vertex3> > edgeMap    = new DualIndexedSet <Tuple <Vertex3, Vertex3> >(x => new Tuple <Vertex3, Vertex3>(x.Item2, x.Item1));
            ImmutableDictionary <int, int>             edgeToFace = ImmutableDictionary <int, int> .Empty;
            int iEnd = facesAway1.Count;

            for (int i = 0; i < iEnd; ++i)
            {
                foreach (CH_Polygon.Edge edge in facesAway1[i].Edges)
                {
                    var(edgeMap2, eIndex, isNew) = edgeMap.EnsureAdded(new Tuple <Vertex3, Vertex3>(edge.Start, edge.End));
                    edgeMap = edgeMap2;
                    if (edgeToFace.ContainsKey(eIndex))
                    {
                        throw new ArgumentException("Invalid polyhedron (edge traversed in same direction by more than one face)");
                    }
                    edgeToFace = edgeToFace.Add(eIndex, i);
                }
            }
            ImmutableDictionary <Vertex3, int> startToEdge = ImmutableDictionary <Vertex3, int> .Empty;
            int iEnd2 = edgeMap.Count;

            for (int i = 0; i < iEnd2; ++i)
            {
                if (!(edgeToFace.ContainsKey(i)))
                {
                    startToEdge = startToEdge.Add(edgeMap[i].Item1, i);
                }
                if (!(edgeToFace.ContainsKey(~i)))
                {
                    startToEdge = startToEdge.Add(edgeMap[~i].Item1, ~i);
                }
            }

            ImmutableList <int> edges = ImmutableList <int> .Empty;

            edges = edges.Add(startToEdge.First().Value);
            int sentinel = startToEdge.Count;

            while (true)
            {
                Vertex3 end = edgeMap[edges[edges.Count - 1]].Item2;
                if (!(startToEdge.ContainsKey(end)))
                {
                    throw new ArgumentException("Unable to walk loose edges");
                }
                int nextEdge = startToEdge[end];
                if (nextEdge == edges[0])
                {
                    break;
                }
                edges = edges.Add(nextEdge);
                --sentinel;
                if (sentinel < 0)
                {
                    throw new InvalidOperationException("Loose edges don't loop properly");
                }
            }
            if (edges.Count != startToEdge.Count)
            {
                throw new InvalidOperationException("Not all loose edges were used");
            }

            sentinel = edges.Count;
            Func <int, int, bool> inSamePlane = delegate(int edge1, int edge2)
            {
                Tuple <Vertex3, Vertex3> e1 = edgeMap[edge1];
                Tuple <Vertex3, Vertex3> e2 = edgeMap[edge2];
                Plane3 p = Plane3.FromThreePoints(e1.Item1, e1.Item2, v);
                return(p.Contains(e2.Item1) && p.Contains(e2.Item2));
            };

            while (true)
            {
                if (!inSamePlane(edges[0], edges[edges.Count - 1]))
                {
                    break;
                }
                int x = edges[0];
                edges = edges.RemoveAt(0).Add(x);
                --sentinel;
                if (sentinel < 0)
                {
                    throw new InvalidOperationException("Loose edges all lie in the same plane as the vertex (?!)");
                }
            }

            ImmutableList <CH_Polygon> newPolys = ImmutableList <CH_Polygon> .Empty;
            ImmutableList <Vertex3>    corners  = ImmutableList <Vertex3> .Empty;
            int?lastEdge = null;

            Action flush = delegate()
            {
                corners  = corners.Add(edgeMap[lastEdge.Value].Item2).Add(v);
                newPolys = newPolys.Add(new CH_Polygon(corners));
            };

            Action <int> addEdge = delegate(int edge)
            {
                if (lastEdge == null || inSamePlane(edge, lastEdge.Value))
                {
                    corners  = corners.Add(edgeMap[edge].Item1);
                    lastEdge = edge;
                }
                else
                {
                    flush();
                    corners = ImmutableList <Vertex3> .Empty
                              .Add(edgeMap[edge].Item1);

                    lastEdge = edge;
                }
            };

            foreach (int edge in edges)
            {
                addEdge(edge);
            }
            flush();

            return(new CH_Polyhedron(newPolys.AddRange(facesAway1)));
        }