// Input N rectangles and points (top-left corner of rectangle)
        // Output all R(r, p) where point p is within rectangle r

        private void BatchedRangeSearch(DisplayList dl)
        {
            // 1) Sort all points and left/right rectangle sides w.r.t. x-coordinate
            // 2) Sweep left-to-right while storing y-intervals of rectangles intersecting
            //    the sweepline in a segment tree T
            //    2.1) Left side => insert interval into T
            //    2.2) Right side => delete interval from T
            //    2.3) Point (x, y) stabbing query report all [y1,y2] where y is in [y1..y2]

            Coordinate[] uniqueY = RemoveDuplication(_yCoord);

            SegmentTree st = new SegmentTree(uniqueY, 0, uniqueY.Length);

            // Sweep through sorted x coordiates from left to right, skipping MinValue/MaxValue
            for (int i = 1; i < _xCount - 1; i++)
            {
                Coordinate c = _xCoord[i];

                double y0 = c.top.value;
                double y1 = c.bottom.value;

                if (Double.Equals(c.value, dl[c.index].Left))
                {
                    st.Insert(c.index, y0, y1);

                    st.ReportIntersection(dl, c.index, y0);
                }
                else
                {
                    st.Remove(c.index, y0, y1);
                }
            }
        }
        private void SortEndPoints(DisplayList dl, int count)
        {
            _xCoord = new Coordinate[2 * count + 2];
            _yCoord = new Coordinate[2 * count + 2];

            AddPoint(0, -1, Double.MinValue, Double.MinValue);

            int p = 1;

            for (int i = 0; i < count; i++)
            {
                Rect r = dl[i];

                AddPoint(p, i, r.Left, r.Top);
                AddPoint(p + 1, i, r.Right, r.Bottom);

                _xCoord[p].top    = _yCoord[p];
                _xCoord[p].bottom = _yCoord[p + 1];

                _xCoord[p + 1].top    = _yCoord[p];
                _xCoord[p + 1].bottom = _yCoord[p + 1];

                p += 2;
            }

            AddPoint(p, count + 1, Double.MaxValue, Double.MaxValue);

            Array.Sort(_xCoord, new CoordinateComparer());
            _xCount = _xCoord.Length;

            Array.Sort(_yCoord, new CoordinateComparer());
            _yCount = _yCoord.Length;
        }
        // Input N rectangles -> 2N vertical line segment, 2N horizontal line segments
        // Output all true intersections rectangles
        private void OrthogonalLineSegmentIntersection(DisplayList dl)
        {
            // Sweep through sorted x coordiates from left to right, skipping MinValue/MaxValue
            for (int i = 1; i < _xCount - 1; i++)
            {
                Coordinate c = _xCoord[i];

                bool left = Double.Equals(c.value, dl[c.index].Left);

                // Left endpoint  => insertion into range tree
                // Right endpoint => delection from range tree
                c.top.active    = left;
                c.bottom.active = left;

                // Vertical segment [y0..y1] => report [y0..y1] AND range tree
                double y0 = c.top.value;
                double y1 = c.bottom.value;

                int p = Array.BinarySearch(_yCoord, y0, new CoordinateSearcher());

                if (p >= 0)
                {
                    do
                    {
                        if ((_yCoord[p].active) && (c.index != _yCoord[p].index))
                        {
                            dl.ReportOverlapping(c.index, _yCoord[p].index);
                            // Console.WriteLine("{0} {1} intersects ({2},{3})", c.index, _yCoord[p].index, c.value, _yCoord[p].value);
                        }

                        p++;
                    }while (_yCoord[p].value <= y1);
                }
            }
        }
        public void CalculateIntersections(DisplayList dl, int count)
        {
            SortEndPoints(dl, count);

            OrthogonalLineSegmentIntersection(dl);

            BatchedRangeSearch(dl);
        }
示例#5
0
        internal void LogInterestingPrimitives(List <PrimitiveInfo> commands, int count, List <Cluster> transparentCluster)
        {
            if (Configuration.Verbose >= 1)
            {
                // Display only interesting primitives

                DisplayList.PrintPrimitive(null, -1, false);

                Rect target = Rect.Empty;

                int vip = 0;

                for (int i = 0; i < count; i++)
                {
                    PrimitiveInfo pi = commands[i];

                    if ((pi != null) && ((pi.overlapHasTransparency != 0) || !pi.primitive.IsOpaque))
                    {
                        if (!pi.primitive.IsOpaque)
                        {
                            target.Union(pi.bounds);
                        }

                        DisplayList.PrintPrimitive(commands[i], i, false);
                        vip++;
                    }
                }

                Console.WriteLine();
                Console.WriteLine("Interesting primitives: {0}", vip);
                Console.WriteLine("Area with transparency: {0}", DisplayList.LeftPad(target, 0));
                Console.WriteLine();

                for (int i = 0; i < transparentCluster.Count; i++)
                {
                    Console.WriteLine(
                        "Cluster {0}: {1} {2} {3}",
                        i + 1,
                        DisplayList.LeftPad(transparentCluster[i].DebugBounds, 0),
                        DisplayList.LeftPad(transparentCluster[i].DebugPrimitives, 0),
                        transparentCluster[i].DebugRasterize);
                }

                Console.WriteLine();
            }
        }
        internal static void UnitTest()
        {
            Console.WriteLine("RectangleIntersection unit test");

            DisplayList dl = new DisplayList(8.5 * 96, 11 * 96);

            dl.Add(3, 8, 6, 36);
            dl.Add(25, 34, 34, 38);
            dl.Add(33, 37, 21, 36);
            dl.Add(21, 38, 23, 27);
            dl.Add(6, 26, 3, 8);
            dl.Add(31, 35, 15, 19);
            dl.Add(23, 38, 11, 14);

            dl.Add(16, 22, 3.5, 7.5);

            RectangleIntersection ri = new RectangleIntersection();

            ri.CalculateIntersections(dl);
        }
        public void ReportIntersection(DisplayList dl, int index, double x)
        {
            if (_sList != null)
            {
                foreach (int i in _sList)
                {
                    if (index != i)
                    {
                        dl.ReportOverlapping(index, i);
                    }
                }
            }

            if ((_left != null) && (x >= _left._min) && (x <= _left._max))
            {
                _left.ReportIntersection(dl, index, x);
            }

            if ((_right != null) && (x >= _right._min) && (x <= _right._max))
            {
                _right.ReportIntersection(dl, index, x);
            }
        }
示例#8
0
        /// <summary>
        /// Optimization phase
        /// </summary>
        /// <param name="commands"></param>
        /// <param name="count"></param>
        /// <param name="disjoint"></param>
        private void DisplayListOptimization(List <PrimitiveInfo> commands, int count, bool disjoint)
        {
#if DEBUG
            Console.WriteLine();
            Console.WriteLine("Start 3: Display list optimization");
            Console.WriteLine();
#endif
            List <int> [] oldUnderlay = null;

            if (!disjoint) // If not in a subtree which needs full flattening
            {
                // The following optimization may change PrimitiveInfo.underlay, but this is needed
                // for cluster calcuation. So we make a copy of it for use within this routine only
                oldUnderlay = CopyUnderlay(count, commands);

                // These optimizations need to run in a seperate pass, because they may affect other primitives
                for (int i = 0; i < count; i++)
                {
repeat:
                    PrimitiveInfo pi = commands[i];

                    if (pi == null)
                    {
                        continue;
                    }

                    // Optimization: If a primitive is covered by an opaque primtive, delete it
                    if (pi.overlap != null)
                    {
                        bool deleted = false;

                        for (int j = 0; j < pi.overlap.Count; j++)
                        {
                            PrimitiveInfo qi = commands[pi.overlap[j]];

                            if (qi.primitive.IsOpaque && qi.FullyCovers(pi))
                            {
                                DeleteCommand(i);
                                deleted = true;
                                break;
                            }
                        }

                        if (deleted)
                        {
                            continue;
                        }
                    }

                    // Optimization: If a primitive is covered by overlap[0], blend brush and switch order
                    // This results in smaller area being rendered as blending of two brushes.
                    if ((pi.overlap != null) && (pi.overlap.Count != 0))
                    {
                        int j = pi.overlap[0]; // first overlapping primitive

                        PrimitiveInfo pj = commands[j];

                        // Do not attempt to blend if both primitives cover exactly same area, since blending
                        // one into the other provides no benefits.
                        if ((pj.underlay[pj.underlay.Count - 1] == i) && pj.FullyCovers(pi) && !pi.FullyCovers(pj))
                        {
                            if (BlendCommands(pi, pj))
                            {
                                SwitchCommands(commands, i, pi, j, pj, true);
                                goto repeat; // pj at position i needs to be processed
                            }
                        }
                    }

                    // Optimization: Delete white primitives with nothing underneath
                    if ((pi.underlay == null) && DisplayList.IsWhitePrimitive(pi.primitive))
                    {
                        DeleteCommand(i);

                        continue;
                    }

                    // Optimization: If a transparent primitive is covered underneath by an opaque primitive, cut its ties with all primitives before it
                    ReduceTie(pi, commands, i);

                    // Transparent primitive
                    if (!pi.primitive.IsOpaque)
                    {
                        // Optimization: If a transparent primitive is covered underneath immediately by an opaque primitive,
                        // or has nothing underneath, convert it to opaque primitive
                        if (!ConvertTransparentOnOpaque(commands, i))
                        {
                            PushTransparencyDown(commands, i);
                        }
                    }
                }

                for (int i = 0; i < count; i++)
                {
                    PrimitiveInfo pi = commands[i];

                    if (pi == null)
                    {
                        continue;
                    }

                    // Optimization: If a primitive is covered by all opaque primitives, cut its ties with primitive on top of it.

                    // This check is also implemented in PrimitiveRender.FindIntersection,
                    // in which it is on a remaing items in overlapping list.
                    // With overlapHasTransparency flag, it can be moved forward.

                    if ((pi.overlap != null) && (pi.overlapHasTransparency == 0))
                    {
                        foreach (int j in pi.overlap)
                        {
                            commands[j].underlay.Remove(i);
                        }

                        pi.overlap = null;
                    }

                    // Optimization: If an opaque primitive is covered by all opaque primitives, cut its ties with primitives under it.
                    if ((pi.underlay != null) && (pi.overlapHasTransparency == 0) && pi.primitive.IsOpaque)
                    {
                        foreach (int j in pi.underlay)
                        {
                            commands[j].overlap.Remove(i);
                        }

                        pi.underlay = null;
                    }
                }
            }

            List <Cluster> transparentCluster = Cluster.CalculateCluster(commands, count, disjoint, oldUnderlay);

            Cluster.CheckForRasterization(transparentCluster, commands);

#if DEBUG
            if (HasUnmanagedCodePermission())
            {
                LogInterestingPrimitives(commands, count, transparentCluster);
                SaveInterestingPrimitives(commands, count, transparentCluster);
            }
#endif
        }
示例#9
0
 public Flattener(bool disJoint, double width, double height)
 {
     _dl = new DisplayList(disJoint, width, height);
 }
示例#10
0
        /// <summary>
        /// Resolve object overlapping in a primitive tree.
        /// Send broken down drawing primitives to _dc.
        /// </summary>
        /// <param name="dc"></param>
        /// <param name="disjoint">True if all output primitives need to be disjoint</param>
        public void AlphaFlatten(IProxyDrawingContext dc, bool disjoint)
        {
            List <PrimitiveInfo> commands = _dl.Commands;

            if (commands == null)
            {
                return;
            }

            int count = commands.Count;

            _dc = dc;

            bool needFlattening = true;

            if (Configuration.BlendAlphaWithWhite || Configuration.ForceAlphaOpaque)
            {
                needFlattening = false;
            }
            else if (!disjoint)
            {
                needFlattening = false;

                for (int i = 0; i < count; i++)
                {
                    PrimitiveInfo info = commands[i];

                    if (!info.primitive.IsOpaque)
                    {
                        needFlattening = true;
                        break;
                    }
                }
            }

            if (needFlattening)
            {
#if DEBUG
                Console.WriteLine();
                Console.WriteLine("Stage 2: Calculating intersections using bounding boxes");
                Console.WriteLine();
#endif
                // Still need all the primitive, for removal by opaque covering and white primitive removal
                _dl.CalculateIntersections(count);
            }

#if DEBUG
            if (Configuration.Verbose >= 2)
            {
                Console.WriteLine();
                Console.WriteLine("Original display list");
                Console.WriteLine();

                DisplayList.PrintPrimitive(null, -1, true);

                for (int i = 0; i < count; i++)
                {
                    DisplayList.PrintPrimitive(commands[i], i, true);
                }

                Console.WriteLine();

                Console.WriteLine("Primitives in display list: {0}", count);

                Console.WriteLine();
            }
#endif

            if (needFlattening)
            {
                DisplayListOptimization(commands, count, disjoint);
            }

#if DEBUG
            for (int i = 0; i < count; i++)
            {
                if (commands[i] != null)
                {
                    commands[i].SetID(i);
                }
            }

            Console.WriteLine();
            Console.WriteLine("Stage 4: Alpha flattening");
            Console.WriteLine();
#endif
            for (int i = 0; i < count; i++)
            {
                PrimitiveInfo info = commands[i];

                if (info == null)
                {
                    continue;
                }

                String desp = null;
#if DEBUG
                if (Configuration.Verbose >= 2)
                {
                    Console.Write(i);
                    Console.Write(": ");
                }

                desp = info.id;
#endif

                if (info.m_cluster != null)
                {
                    info.m_cluster.Render(commands, dc);
                }
                else
                {
                    AlphaRender(info.primitive, info.overlap, info.overlapHasTransparency, disjoint, desp);
                }

#if DEBUG
                if (Configuration.Verbose >= 2)
                {
                    Console.WriteLine("");
                }
#endif
            }

            _dc = null;
        }