Example #1
0
        private SolidColorBrush GetBrush(IHierarchicalData data)
        {
            if (Highlighting != null && Highlighting.IsHighlighted(data))
            {
                return(DefaultDrawingPrimitives.HighlightBrush);
            }

            SolidColorBrush brush;

            if (data.ColorKey != null)
            {
                brush = _brushFactory.GetBrush(data.ColorKey);
            }
            else
            {
                // For non leaf nodes the weight is 0. We only can merge area metrics.
                // See HierarchyBuilder.InsertLeaf.

                var color = DefaultDrawingPrimitives.WhiteToRedGradient.GradientStops.GetRelativeColor(data.NormalizedWeightMetric);
                brush = new SolidColorBrush(color);
                brush.Freeze();
            }

            return(brush);
        }
        private CircularLayoutInfo CalculateEnclosingCircle(IHierarchicalData root, FrontChain frontChain)
        {
            // Get extreme points by extending the vector from origin to center by the radius
            var layouts = frontChain.ToList();
            var points  = layouts.Select(x => Geometry.MovePointAlongLine(new Point(), x.Center, x.Radius)).ToList();

            var layout = GetLayout(root);

            Debug.Assert(layout.Center == new Point()); // Since we process bottom up this node was not considered yet.

            double radius;
            Point  center;

            if (frontChain.Head.Next == frontChain.Head) // Single element
            {
                center = frontChain.Head.Value.Center;
                radius = frontChain.Head.Value.Radius;
            }
            else
            {
                // 2 and 3 points seem to be handled correctly.
                Geometry.FindMinimalBoundingCircle(points, out center, out radius);
            }

            layout.Center = center;
            Debug.Assert(Math.Abs(radius) > 0.00001);
            layout.Radius = radius * 1.03; // Just a little larger 3%.
            return(layout);

            // Note that this is not exact. It is a difficult problem.
            // We may have a little overlap. The larger the increment in radius
            // the smaller this problem gets.
        }
Example #3
0
        private CircularLayoutInfo GetLayout(IHierarchicalData item)
        {
            var layout = item.Layout as CircularLayoutInfo;

            Debug.Assert(layout != null);
            return(layout);
        }
Example #4
0
        private void Squarify(Rect availableSpace, IHierarchicalData data)
        {
            if (DebugEnabled)
            {
                // Print the item and the available space.
                _level++;
                Debug.WriteLine(GetLevelIndent() + "Squarify - " + data.Name + " Available=" + Format(availableSpace));
            }

            if (data.Children.Count == 0)
            {
                // Draw leaf node at its location
                //DrawRectangle(availableSpace, data); No, just calculate the layout!

                if (DebugEnabled)
                {
                    var layout = GetLayout(data);
                    Debug.WriteLine(GetLevelIndent() + "Printing " + data.Name + ", " + "Rect=" + Format(layout.Rect));
                }

                _level--;
                return;
            }

            var itemsToArrange = new List <IHierarchicalData>(data.Children);

            Squarify(availableSpace, itemsToArrange);
            _level--;
        }
Example #5
0
        public bool IsHighlighted(IHierarchicalData data)
        {
            var isNameMatchingActive = !string.IsNullOrEmpty(_pattern);
            var isNameMatching       = false;

            if (isNameMatchingActive)
            {
                isNameMatching = data.Name.ToLowerInvariant().Contains(_pattern);
            }

            // Matching area and weight criteria is optional.
            var areRangesMatching = _toolViewModel.NoFilterJustHighlight &&
                                    _toolViewModel.IsAreaValid(data.AreaMetric) &&
                                    _toolViewModel.IsWeightValid(data.WeightMetric);

            if (!isNameMatchingActive && _toolViewModel.NoFilterJustHighlight)
            {
                // If no name is entered ignore the name filtering
                return(areRangesMatching);
            }

            if (isNameMatchingActive && !_toolViewModel.NoFilterJustHighlight)
            {
                return(isNameMatching);
            }

            if (isNameMatchingActive && _toolViewModel.NoFilterJustHighlight)
            {
                return(isNameMatching && areRangesMatching);
            }

            return(false);
        }
Example #6
0
        /// <summary>
        /// Layout must have been called
        /// </summary>
        public IHierarchicalData Hit(IHierarchicalData item, Point mousePos)
        {
            // We may find a more detailed hit deeper.
            IHierarchicalData best = null;

            if (item.Layout == null)
            {
                return(null);
            }

            if (item.Layout.IsHit(mousePos))
            {
                best = item;
                if (item.IsLeafNode)
                {
                    return(item);
                }
            }

            foreach (var child in item.Children)
            {
                if (child.Layout.IsHit(mousePos))
                {
                    return(Hit(child, mousePos));
                }
            }

            return(best);
        }
Example #7
0
        public void Layout(IHierarchicalData root, double width, double height)
        {
            var rect   = new Rect(new Point(0, 0), new Size(width, height));
            var layout = GetLayout(root);

            layout.Rect = rect;
            Squarify(rect, root);
        }
Example #8
0
        private static RectangularLayoutInfo GetLayout(IHierarchicalData data)
        {
            if (data.Layout == null)
            {
                data.Layout = new RectangularLayoutInfo();
            }

            return(data.Layout as RectangularLayoutInfo);
        }
Example #9
0
        public void LoadData(IHierarchicalData data)
        {
            _data = data;

            // Layout once. Later we scale it appropriately
            var layout = new CirclePackingLayout();

            layout.Layout(_data, double.MaxValue, double.MaxValue);
        }
        protected override void InitPopup(IHierarchicalData hit)
        {
            _popupText.Text = hit.Description;

            _popup.PlacementTarget = GetCanvas();
            _popup.Placement       = PlacementMode.Mouse;
            _popup.Visibility      = Visibility.Visible;
            _popup.IsOpen          = true;
        }
        /// <summary>
        /// At the beginning any leaf node is simply centered at (0,0)
        /// </summary>
        private void InitLayoutForLeafNode(IHierarchicalData data)
        {
            // Not interested in non leaf nodes, so we can ask for area metric.
            Debug.Assert(data.AreaMetric > 0);
            var layout = GetLayout(data);

            layout.Radius = AreaToRadius(data.AreaMetric);
            layout.Center = new Point(0, 0);
            layout.PendingChildrenMovement = new Vector(0, 0);
        }
        private CircularLayoutInfo GetLayout(IHierarchicalData item)
        {
            if (item.Layout == null)
            {
                var layout = new CircularLayoutInfo();
                item.Layout = layout;
            }

            return(item.Layout as CircularLayoutInfo);
        }
        public IHierarchicalData GetMandatorySubnode(string sXPath)
        {
            IHierarchicalData Result = GetSubnode(sXPath);

            if (Result == null)
            {
                throw new TisException("node for path [{0}] not exist", sXPath);
            }

            return(Result);
        }
        /// <summary>
        /// For performance optimization we did not apply movements to children until
        /// all positions are fixed.
        /// </summary>
        private void ApplyPendingMovements(IHierarchicalData data)
        {
            var layout  = GetLayout(data);
            var pending = layout.PendingChildrenMovement;

            foreach (var child in data.Children)
            {
                var childLayout = GetLayout(child);
                childLayout.Move(pending);
                ApplyPendingMovements(child);
            }
        }
Example #15
0
        private void Draw(DrawingContext dc, IHierarchicalData data)
        {
            var brush = GetBrush(data);

            var layout = GetLayout(data);

            dc.DrawEllipse(brush, _pen, layout.Center, layout.Radius, layout.Radius);

            foreach (var child in data.Children)
            {
                Draw(dc, child);
            }
        }
        public IHierarchicalData[] GetSubnodes(string sXPath)
        {
            IHierarchicalData[] Subnodes = null;

            XmlNodeList Nodes = m_BaseNode.SelectNodes(sXPath);

            Subnodes = new IHierarchicalData[Nodes.Count];

            for (int i = 0; i < Subnodes.Length; i++)
            {
                Subnodes[i] = new XmlHierarchicalData(Nodes[i]);
            }

            return(Subnodes);
        }
        public void Layout(IHierarchicalData root, double actualWidth, double actualHeight)
        {
            // actualWidth and actualHeight are not used. We render the circles independent of the sizes and scale them later.

            // Counters over all steps
            DebugHelper.ResetDbgCounter();

            // Cleanup previous layouting
            root.TraverseTopDown(x => x.Layout = null);
            Layout(root);

            // Center root node to screen. Move to (0,0)
            var rootLayout = GetLayout(root);

            MoveCircles(root, -(Vector)rootLayout.Center);

            ApplyPendingMovements(root);
        }
Example #18
0
        private void RenderToDrawingContext(DrawingContext dc, IHierarchicalData data)
        {
            _level++;
            if (data.IsLeafNode)
            {
                var brush = GetBrush(data);

                //dc.DrawRectangle(_gradient, _pen, data.Layout.Rect);
                var layout = GetLayout(data);
                dc.DrawRectangle(brush, DefaultDrawingPrimitives.BlackPen, layout.Rect);
            }

            foreach (var child in data.Children)
            {
                RenderToDrawingContext(dc, child);
            }

            _level--;
        }
        public bool Fill(ContextMenu menu, IHierarchicalData data)
        {
            if (!_menuItemToAction.Any())
            {
                return(false);
            }

            foreach (var pair in _menuItemToAction)
            {
                var menuItem = pair.Key;

                // Detach context menu items from previous shown context menu (if any)
                var parent = menuItem.Parent as ContextMenu;
                parent?.Items.Clear();
                menuItem.IsEnabled = data != null && data.IsLeafNode;
                menuItem.Command   = new DelegateCommand(() => OnMenuClick(menuItem, data));
                menu.Items.Add(menuItem);
            }

            return(true);
        }
        private static object[] CreateCtorParams(
            IHierarchicalData InitParams,
            object[] additionalCtorParams)
        {
            int actualParamsSize = 1;

            if (additionalCtorParams != null)
            {
                actualParamsSize += additionalCtorParams.Length;
            }

            object[] actualParams = new object[actualParamsSize];

            if (additionalCtorParams != null)
            {
                additionalCtorParams.CopyTo(actualParams, 0);
            }

            actualParams[actualParamsSize - 1] = InitParams;

            return(actualParams);
        }
        public static object[] CreateInstances(
            IHierarchicalData[] instanceParamsList,
            object[] additionalCtorParams)
        {
            int objectsCount = instanceParamsList.Length;

            object[] objects = new object[objectsCount];

            for (int i = 0; i < objectsCount; i++)
            {
                IHierarchicalData instanceParams = instanceParamsList[i];

                // Get the instance implementation class
                string implClassName = instanceParams.GetMandatoryString("ImplClassName");

                // Create ctor params
                object[] actualCtorParams = CreateCtorParams(instanceParams, additionalCtorParams);

                // Create instance and add to the map
                objects[i] = CreateInstance(implClassName, actualCtorParams);
            }

            return(objects);
        }
 public HierarchicalDataContext(IHierarchicalData data)
 {
     Data         = data;
     BrushFactory = null;
 }
 public HierarchicalDataContext(IHierarchicalData data, IBrushFactory brushFactory)
 {
     Data         = data;
     BrushFactory = brushFactory;
 }
Example #24
0
 public HierarchicalDataContext(IHierarchicalData data)
 {
     Data         = data;
     BrushFactory = new ColorScheme();
 }
Example #25
0
 /// <summary>
 /// Gets description for a branch / folder
 /// </summary>
 private string GetDescription(IHierarchicalData branch)
 {
     return(branch.GetPathToRoot());
 }
 private void OnMenuClick(MenuItem item, IHierarchicalData data)
 {
     // Invoke subscriber with clicked data item.
     _menuItemToAction[item].Invoke(data);
 }
Example #27
0
 private static RectangularLayoutInfo GetLayout(IHierarchicalData data)
 {
     return(data.Layout as RectangularLayoutInfo);
 }
Example #28
0
 /// <summary>
 /// Ensure that SumAreaMetrics and NormalizeWeightMetric was called and
 /// no node has an area of 0.
 /// </summary>
 public void LoadData(IHierarchicalData data)
 {
     _data = data;
 }
        /// <summary>
        /// m, n, j and i refer to the paper.
        /// </summary>
        private void Layout(IHierarchicalData data)
        {
            if (DebugEnabled)
            {
                DebugHelper.DeleteDebugOutput();
            }

            if (data.IsLeafNode)
            {
                // That's the most simple layout. A leaf node is centered around (0,0)
                InitLayoutForLeafNode(data);
                return;
            }

            foreach (var child in data.Children)
            {
                // First layout all levels below.
                Layout(child);
            }

            // The radii of all children are known here.
            // We start again at origin (0,0) and move the circles around using the front chain.
            // To initialize the front chain we use the first three circles.
            // Note that we have to sort by the radius and not(!) by the AreaMetric because
            // the area metric is used only for the leaf nodes. This was a subtle bug.
            // Non leaf nodes have a radius depending on the circle enclosing all children.
            var children = data.Children.OrderByDescending(x => GetLayout(x).Radius).ToList();

            var frontChain = InitializeFrontChain(children);

            var  adjustingFrontChain = false;
            Node mNode = null;
            Node nNode = null;

            // Arrange the remaining circles
            var childIdx = 3;

            while (childIdx < children.Count)
            {
                DebugHelper.IncDbgCounter();

                var iItem   = children.ElementAt(childIdx);
                var iLayout = GetLayout(iItem);

                if (!adjustingFrontChain)
                {
                    // Find circle with shortest distance to origin
                    mNode = frontChain.FindMinValue(DistanceToOrigin);
                    nNode = mNode.Next;
                }
                else
                {
                    // Use the specified indices  from the last front chain update.
                }

                // Calc solutions

                // Test front chain Both violate-> delete and try to fix whole.

                var solutions = FindTangentCircle(mNode.Value, nNode.Value, iLayout.Radius);

                var tmpCircle = SelectCircle(mNode.Value, nNode.Value, solutions.Item1, solutions.Item2);

                Debug.Assert(tmpCircle != null);

                // Find overlapping with circles in the front chain.Does one intersect with the just calculated circle?
                // Exclude mIndex and nIndex Overlapping with itself is detected due to rounding errors.
                var jNode = FindOverlappingCircleOnFrontChain(frontChain, tmpCircle);
                if (jNode != null && adjustingFrontChain)
                {
                    // This is a valid case:
                    // See Examples\Why_we_end_up_with_a_collision_again.html
                }

                adjustingFrontChain = false;
                if (jNode != null && frontChain.IsAfter(jNode, mNode))
                {
                    // This is also the default case if distance j...m and n...j is the same.
                    // IsAfter is true in both cases then.
                    // This way always the m node is removed. m is the node closest to the origin. This seems to be the
                    // best heuristic if we want to grow outwards. Otherwise it happened that the front
                    // chain is reduced to less than three circles.

                    adjustingFrontChain = true;

                    // j is before m
                    // Remove (j, n) from front chain
                    // i should be placed between j and n in the next loop.

                    // Update front chain
                    frontChain.Delete(jNode, nNode);
                    Debug.Assert(frontChain.Count() >= 3);

                    // Adjust the indices
                    mNode = jNode;

                    // nNode stays the same
                }
                else if (jNode != null && frontChain.IsAfter(nNode, jNode))
                {
                    adjustingFrontChain = true;

                    // j is after n
                    // Remove (m,j) from the front chain
                    // i should be placed between m and j in the next loop.

                    //DebugHelper.BreakOn(13025);

                    // Update front chain
                    frontChain.Delete(mNode, jNode);
                    Debug.Assert(frontChain.Count() >= 3);

                    // mNode stays the same
                    nNode = jNode;
                }

                else
                {
                    Debug.Assert(jNode == null);

                    // No overlap with any other circle
                    var disp = tmpCircle.Center - iLayout.Center;
                    MoveCircles(iItem, disp);
                    frontChain.InsertAfter(mNode, tmpCircle);
                    childIdx++;

                    if (DebugEnabled)
                    {
                        // Template for debug output
                        DebugHelper.WriteDebugOutput(frontChain, $"dbgOut_m_{frontChain.IndexOf(mNode)}_n_${frontChain.IndexOf(nNode)}", solutions.Item1, solutions.Item2);
                        DebugHelper.WriteDebugOutput(frontChain, $"dbgOut_m_{frontChain.IndexOf(mNode)}_n_{frontChain.IndexOf(nNode)}", tmpCircle);
                    }
                }
            }

            var enclosing = CalculateEnclosingCircle(data, frontChain);
        }
        /// <summary>
        /// Moves the circle and records that this movement is pending for the children.
        /// </summary>
        private void MoveCircles(IHierarchicalData data, Vector offset)
        {
            var layout = GetLayout(data);

            layout.Move(offset);
        }