Beispiel #1
0
        /// <summary>
        /// Create the partitioner. New diagonals will be inserted into the result mesh by calls to
        /// the provided DiagonalInserterDelegate which accepts the mesh and from and to vertices for the
        /// new edge.
        /// </summary>
        /// <param name="mesh">The mesh to be partitioned.</param>
        /// <param name="DiagonalInserterDelegate">An action for inserting edges into the mesh between the specificed vertices</param>
        public MonotoneYPartitioner(Mesh <TVertex, TEdge, TFace> mesh,
                                    Action <Mesh <TVertex, TEdge, TFace>, TVertex, TVertex> DiagonalInserterDelegate)
        {
            // TODO: We should copy the mesh here, but no copy-constructor yet!
            //this.mesh = new Mesh<TVertex, TEdge, TFace>(mesh);
            this.mesh = mesh;

            // The comparer used for ordering vertices in the queue - controlling
            // the order in which the sweep line sweeps over vertices
            HighYLowXComparer yxComparer = new HighYLowXComparer();

            meshUtilities                 = new MonotoneMeshUtilities <TVertex>(yxComparer);
            queueDictionary               = new PriorityQueueDictionary <Point2D, TVertex>(yxComparer);
            xEdgeComparer                 = new LeftToRightEdgeComparer();
            sweeplineUtilities            = new SweeplineUtilities(xEdgeComparer);
            helpers                       = new SplayDictionary <EdgeBase, TVertex>(xEdgeComparer);
            this.DiagonalInserterDelegate = DiagonalInserterDelegate;
        }
        public void Init()
        {
            mesh = new Mesh <Vertex, EdgeBase, FaceBase>(false, true);

            v1 = new Vertex(3, 10);
            v2 = new Vertex(3, 6);
            v3 = new Vertex(6, 8);
            v4 = new Vertex(3, 3);
            v6 = new Vertex(13, 4);
            v7 = new Vertex(13, 11);

            mesh.Add(v1);
            mesh.Add(v2);
            edgeTwoToOne  = mesh.AddEdge(v2, v1);
            edgeTwoToOne2 = mesh.AddEdge(v2, v1);
            edgeOneToTwo  = mesh.AddEdge(v1, v2);

            mesh.Add(v3);
            edgeThreeToTwo = mesh.AddEdge(v3, v2);
            edgeTwoToThree = mesh.AddEdge(v2, v3);

            mesh.Add(v4);
            edgeFourToThree = mesh.AddEdge(v4, v3);

            mesh.Add(v7);
            mesh.Add(v6);
            edgeSevenToSix = mesh.AddEdge(v7, v6);

            v100 = new Vertex(101, 103);
            v101 = new Vertex(103, 103);
            v102 = new Vertex(108, 103);
            v103 = new Vertex(107, 103);
            v104 = new Vertex(109, 103);
            v105 = new Vertex(104, 101);
            v106 = new Vertex(106, 106);

            mesh.Add(v100);
            mesh.Add(v101);
            e100to101 = mesh.AddEdge(v100, v101);

            mesh.Add(v101);
            mesh.Add(v102);
            e101to102 = mesh.AddEdge(v101, v102);

            mesh.Add(v103);
            mesh.Add(v104);
            e103to104 = mesh.AddEdge(v103, v104);

            mesh.Add(v105);
            mesh.Add(v106);
            e105to106 = mesh.AddEdge(v105, v106);

            v200 = new Vertex(210, 180);
            v201 = new Vertex(90, 180);
            v202 = new Vertex(90, 60);

            mesh.Add(v200);
            mesh.Add(v201);
            mesh.Add(v202);
            e200to201 = mesh.AddEdge(v200, v201);
            e202to201 = mesh.AddEdge(v202, v201);

            v300 = new Vertex(210, 180);
            v301 = new Vertex(90, 180);
            v302 = new Vertex(90, 60);
            v303 = new Vertex(90, 170);

            mesh.Add(v300);
            mesh.Add(v301);
            mesh.Add(v302);
            mesh.Add(v303);
            e300to301 = mesh.AddEdge(v300, v301);
            e302to303 = mesh.AddEdge(v302, v303);

            comparer = new LeftToRightEdgeComparer();
        }
        private void Triangulate()
        {
            // From O'Rourke (1994) Computational Geometry in C, section 2.1
            // Monotone Partitioning

            // To identify the chains: The vertices in each chain of a monotone
            // polygon are sorted with respect to the line of monotonicity [y-axis].
            // Then the vertices can be sorted by the y-axis in linear time: Find a
            // Highest vertex, find a lowest, and partition the boundary between the two
            // chains. The vertices in each chain are sorted with respect to y.
            // Two sorted lists of vertices can be merged in linear time into one list
            // sorted by y.
            Debug.Assert(face.EdgeCount > 3);
            var vertices = face.Vertices.Cast <TVertex>();

            IComparer <Point2D> pointComparer = new HighYLowXComparer();
            // TODO: Replace with Transform extension method. Consider removing transform comparer
            IComparer <TVertex>     vertexComparer = new TransformComparer <TVertex, Point2D>(pointComparer, v => v.Position);
            Pair <TVertex, TVertex> minMax         = vertices.MinMax(vertexComparer);

            meshUtilities = new MonotoneMeshUtilities <TVertex>(pointComparer);

            LeftToRightEdgeComparer xEdgeComparer = new LeftToRightEdgeComparer();

            sweeplineUtilities = new SweeplineUtilities(xEdgeComparer);

            // Assign each vertex to the left or right chain
            IEnumerable <ChainVertex> leftChainReversed = TraceLeftAndUp(minMax.First);
            IEnumerable <ChainVertex> leftChain         = leftChainReversed.Reverse();
            IEnumerable <ChainVertex> rightChain        = TraceRightAndDown(minMax.Second);

            // From Berg et al (2000) Computational Geometry Algorithms and Applications

            // 1. Merge the vertices on the right chain with those on the left
            // chain into one sequence sorted on decreasing y-coordinate. If
            // two vertices have the same y-coordinate the left one comes first.
            // Let u1 to un denote the sorted sequence.

            IComparer <ChainVertex>   chainVertexComparer = vertexComparer.Transform <ChainVertex, TVertex>(p => p.Vertex).Invert();
            IEnumerable <ChainVertex> mergedVertices      = rightChain.MergeSorted(leftChain, chainVertexComparer);
            List <ChainVertex>        u = new List <ChainVertex>(mergedVertices);

            // 2. Initialize an empty stack and push u1 and u2 onto it
            // This stack contains all the vertices of the polygon that have
            // already been encountered, but which may require additional diagonals
            Stack <ChainVertex> stack = new Stack <ChainVertex>();

            stack.Push(u[0]);
            stack.Push(u[1]);

            for (int j = 2; j < u.Count - 1; ++j)
            {
                // If u[j] and the vertext on top of the stack are of different chains
                if (u[j].Chain != stack.Peek().Chain)
                {
                    // Insert a diagonal from u[j] to each popped vertex...
                    // We progessively subdivide the new faces created by the splitting
                    // so we must keep track of which face to split
                    FaceBase faceToSplit = face;
                    while (stack.Count > 1)
                    {
                        TEdge edge = splitFace(mesh, faceToSplit, u[j], stack.Pop());
                        faceToSplit = edge.Faces.First; // First is always the new face
                    }
                    // ... except the last one
                    if (stack.Count > 0)
                    {
                        stack.Pop();
                    }
                    // Push u j-1 and uj onto the stack
                    stack.Push(u[j - 1]);
                    stack.Push(u[j]);
                }
                else
                {
                    // Pop one vertex from the stack; this vertex is already connected
                    ChainVertex previous = stack.Pop();
                    // We progressively split triangles from the original face
                    TFace faceToSplit = face;
                    while (stack.Count > 0 && CanInsertDiagonal(u[j], stack.Peek(), previous))
                    {
                        previous = stack.Pop();
                        splitFace(mesh, faceToSplit, u[j], previous);
                    }
                    // Push the last vertex popped back onto the stack
                    stack.Push(previous);
                    // Push uj onto the stack
                    stack.Push(u[j]);
                }
            }
            // Add diagonals from un to all vertices except the first and last one
            stack.Pop();
            // Which chain is the stack of vertices on - affects which face we split
            Chain    stackChain       = stack.Peek().Chain;
            FaceBase finalFaceToSplit = face;

            while (stack.Count > 1)
            {
                TEdge edge = splitFace(mesh, finalFaceToSplit, u[u.Count - 1], stack.Pop());
                finalFaceToSplit = stackChain == Chain.Left ? edge.Faces.First : edge.Faces.Second;
            }
            Debug.Assert(stack.Count == 1);

            triangulated = true;
        }