public IEnumerable <T> Cull(ImageViewState viewState)
            {
                var elements = new List <T>();

                if (this.QuadTree.RootNode != null)
                {
                    var cullRect    = new Rect(0, 0, viewState.ViewportWidth, viewState.ViewportHeight);
                    var cullContext = new CullContext(cullRect, viewState);
                    CullRecursive(elements, cullContext, this.QuadTree.RootNode);
                }

                return(elements);
            }
            private static void CullRecursive(
                List <T> elements,
                CullContext context,
                PointQuadTree <QuadTreeItem> .Node node)
            {
                var intersection =
                    CheckIntersection(context, ToRect(node.Bounds));

                if (intersection == Intersection.Contain)
                {
#if DEBUG_PRINT_CULLING_PROCESS
                    if (_enablePrintCullingProcess)
                    {
                        Logger.Debug(
                            $"{node.DebugDisplayName} fully contained by view, adding itself and all descendants");

                        if (node.Element != null)
                        {
                            Logger.Debug($"\tADDED {node.DebugDisplayName} {node.Element.Element}");
                        }

                        foreach (var descendant in node.EnumerateDescendantNodes())
                        {
                            if (descendant.Element != null)
                            {
                                Logger.Debug($"\tADDED {descendant.DebugDisplayName} {descendant.Element.Element}");
                            }
                        }
                    }
#endif
                    if (node.Element != null)
                    {
                        elements.Add(node.Element.Element);
                    }

                    elements.AddRange(node.EnumerateDescendants().Where(i => i.Element != null).Select(i => i.Element));
                }
                else if (intersection == Intersection.Intersect)
                {
                    var viewPosition = context.ViewState.WorldToViewMatrix.Transform(ToWpfPoint(node.Point));
                    if (context.CullRect.Contains(viewPosition) && node.Element != null)
                    {
#if DEBUG_PRINT_CULLING_PROCESS
                        if (_enablePrintCullingProcess)
                        {
                            Logger.Debug(
                                $"{node.DebugDisplayName} intersects with view, and its Point is contained by view, adding");
                            Logger.Debug($"\tADDED {node.DebugDisplayName} {node.Element.Element}");
                        }
#endif
                        elements.Add(node.Element.Element);
                    }

                    foreach (var subnode in node.Subnodes)
                    {
                        CullRecursive(elements, context, subnode);
                    }
                }
#if DEBUG_PRINT_CULLING_PROCESS
                else
                {
                    if (_enablePrintCullingProcess)
                    {
                        Logger.Debug($"{node.DebugDisplayName} does not intersect with view, ruled out");
                        if (node.Element != null)
                        {
                            Logger.Debug($"\tRULE-OUT {node.DebugDisplayName} {node.Element.Element}");
                        }

                        foreach (var descendant in node.EnumerateDescendantNodes())
                        {
                            if (descendant.Element != null)
                            {
                                Logger.Debug($"\tRULE-OUT {descendant.DebugDisplayName} {descendant.Element.Element}");
                            }
                        }
                    }
                }
#endif
            }
Example #3
0
        /// <summary>
        ///     Check whether target rect, in world space, intersects with the cull rect
        /// </summary>
        protected static Intersection CheckIntersection(CullContext context, Rect targetRect)
        {
            // This method is a simplified implementation with the knowledge of CullRect being unrotated

            var targetPointsInViewSpace = context.ViewState.WorldToViewMatrix.TransformVertices(targetRect);

            // first check whether any or all vertices of targetRect, transformed to the view space,
            // is contained by the cull rect
            var contained      = false;
            var fullyContained = true;

            foreach (var point in targetPointsInViewSpace)
            {
                if (context.CullRect.Contains(point))
                {
                    contained = true;
                    if (!fullyContained)
                    {
                        return(Intersection.Intersect);
                    }
                }
                else
                {
                    fullyContained = false;
                }
            }

            if (fullyContained)
            {
                return(Intersection.Contain);
            }

            if (contained)
            {
                return(Intersection.Intersect);
            }

            // then we go with the SAT (separating axis theorem) checking
            var targetVertices = targetRect.GetVertices();

            foreach (var vertices in new[] { context.WorldCullRectVertices, targetVertices })
            {
                for (var i1 = 0; i1 < vertices.Length; i1++)
                {
                    var i2 = (i1 + 1) % vertices.Length;
                    var p1 = vertices[i1];
                    var p2 = vertices[i2];

                    var normalY = p1.X - p2.X;
                    var normalX = p2.Y - p1.Y;

                    var minA = double.MaxValue;
                    var maxA = double.MinValue;
                    foreach (var p in context.WorldCullRectVertices)
                    {
                        var projected = normalX * p.X + normalY * p.Y;
                        if (projected < minA)
                        {
                            minA = projected;
                        }

                        if (projected > maxA)
                        {
                            maxA = projected;
                        }
                    }

                    var minB = double.MaxValue;
                    var maxB = double.MinValue;
                    foreach (var p in targetVertices)
                    {
                        var projected = normalX * p.X + normalY * p.Y;
                        if (projected < minB)
                        {
                            minB = projected;
                        }

                        if (projected > maxB)
                        {
                            maxB = projected;
                        }
                    }

                    if (maxA < minB || maxB < minA)
                    {
                        return(Intersection.NotIntersect);
                    }
                }
            }

            return(Intersection.Intersect);
        }