コード例 #1
0
 public MstLineSweeper(List<Tuple<int, int, double, double, double>> proximityEdges, Size[] nodeSizes, Point[] nodePositions, bool forLayers) {
     _proximityEdges = proximityEdges;
     _nodeSizes = nodeSizes;
     _nodePositions = nodePositions;
     _forLayers = forLayers;
     Debug.Assert(nodePositions.Length==nodeSizes.Length);
     _q = new BinaryHeapPriorityQueue(nodeSizes.Length*2); 
 }
コード例 #2
0
 OverlapRemoval(OverlapRemovalSettings settings, Node[] nodes, Size[] sizes) {
     _overlapForLayers = true;
     _settings = settings;
     _sizes = sizes;
     _nodes = nodes;
 }
コード例 #3
0
/*
        /// <summary>
        /// Add additional proximity edges which where not found by the triangulation.
        /// </summary>
        /// <param name="proximityEdges">tuple representing an edge with more information: nodeId1, nodeId2,expandingFactor t, ideal distance, weight</param>
        /// <param name="nodeSizes"></param>
        /// <param name="nodePositions"></param>
        /// <returns></returns>
        int CreateProximityEdgesWithRTree(List<Tuple<int, int, double, double, double>> proximityEdges,
            Size[] nodeSizes, Point[] nodePositions) {
            HashSet<Tuple<int, int>> edgeSet = new HashSet<Tuple<int, int>>();

            foreach (var proximityEdge in proximityEdges) {
                edgeSet.Add(Tuple.Create(proximityEdge.Item1, proximityEdge.Item2));
            }
            RectangleNode<int> rootNode =
                RectangleNode<int>.CreateRectangleNodeOnEnumeration(
                    nodeSizes.Select(
                        (size, index) => new RectangleNode<int>(index, new Rectangle(size, nodePositions[index]))));
            int numCrossings = 0;
            RectangleNodeUtils.CrossRectangleNodes<int, int>(rootNode, rootNode,
                (a, b) => {
                    if (a == b) return;

                    var tuple = GetIdealEdgeLength
                        (
                            a, b,
                            nodePositions[a
                                ],
                            nodePositions[b
                                ],
                            nodeSizes);

                    Tuple<int, int> setTuple;
                    if (!(tuple.Item3 > 1) ||
                        edgeSet.Contains(setTuple = new Tuple<int, int>(tuple.Item1, tuple.Item2)))
                        return;
                    proximityEdges.Add(tuple);
                    edgeSet.Add(setTuple);
                    numCrossings++;
                });

            return numCrossings;
        }
*/


        /// <summary>
        /// Returns a tuple representing an edge with: nodeId1, nodeId2, t(overlapFactor), ideal distance, edge weight.
        /// </summary>
        /// <param name="nodeId1"></param>
        /// <param name="nodeId2"></param>
        /// <param name="point1"></param>
        /// <param name="point2"></param>
        /// <param name="nodeSizes"></param>
        /// <param name="forLayers"></param>
        /// <returns></returns>
        internal static Tuple<int, int, double, double, double> GetIdealEdgeLength(int nodeId1, int nodeId2,
            Point point1,
            Point point2,
            Size[] nodeSizes, bool forLayers) {
            double t;

            double idealDist = GetIdealEdgeLength(nodeId1, nodeId2, point1, point2, nodeSizes, out t);
            double length = (point1 - point2).Length;

            Rectangle box1, box2;
            if (forLayers) {
                int maxId = Math.Max(nodeId1, nodeId2);
                box1 = new Rectangle(nodeSizes[maxId], point1);
                box2 = new Rectangle(nodeSizes[maxId], point2);
            }
            else {
                box1 = new Rectangle(nodeSizes[nodeId1], point1);
                box2 = new Rectangle(nodeSizes[nodeId2], point2);
            }
            var distBox = GetDistanceRects(box1, box2);

            double weight;
            if (t > 1) //overlap
                weight = -(idealDist - length);
            else
                weight = distBox;
            int smallId = nodeId1;
            int bigId = nodeId2;
            if (nodeId1 > nodeId2) {
                smallId = nodeId2;
                bigId = nodeId1;
            }
            return Tuple.Create(smallId, bigId, t, idealDist, weight);

        }
コード例 #4
0
 int FindProximityEdgesWithSweepLine(List<Tuple<int, int, double, double, double>> proximityEdges,
     Size[] nodeSizes, Point[] nodePositions) {
     MstLineSweeper mstLineSweeper = new MstLineSweeper(proximityEdges, nodeSizes, nodePositions, _overlapForLayers);
     return mstLineSweeper.Run();
 }
コード例 #5
0
        /// <summary>
        /// Does one iterations in which a miniminum spanning tree is 
        /// determined on the delaunay triangulation and finally the tree is exanded to resolve the overlaps.
        /// </summary>
        /// <param name="nodePositions"></param>
        /// <param name="nodeSizes"></param>
        /// <param name="scanlinePhase"></param>
        /// <returns></returns>
        bool OneIteration(Point[] nodePositions, Size[] nodeSizes, bool scanlinePhase) {
            var cdt = new Cdt(nodePositions.Select((p, index) => Tuple.Create(p, (object) index)));
            cdt.Run();
            var siteIndex = new Dictionary<CdtSite, int>();
            for (int i = 0; i < nodePositions.Length; i++)
                siteIndex[cdt.PointsToSites[nodePositions[i]]] = i;

            int numCrossings = 0;
            List<Tuple<int, int, double, double, double>> proximityEdges =
                new List<Tuple<int, int, double, double, double>>();
            foreach (var site in cdt.PointsToSites.Values)
                foreach (var edge in site.Edges) {

                    Point point1 = edge.upperSite.Point;
                    Point point2 = edge.lowerSite.Point;
                    var nodeId1 = siteIndex[edge.upperSite];
                    var nodeId2 = siteIndex[edge.lowerSite];
                    Debug.Assert(ApproximateComparer.Close(point1, nodePositions[nodeId1]));
                    Debug.Assert(ApproximateComparer.Close(point2, nodePositions[nodeId2]));
                    var tuple = GetIdealEdgeLength(nodeId1, nodeId2, point1, point2, nodeSizes, _overlapForLayers);
                    proximityEdges.Add(tuple);
                    if (tuple.Item3 > 1) numCrossings++;
                }


            if (numCrossings == 0 || scanlinePhase) {
                int additionalCrossings = FindProximityEdgesWithSweepLine(proximityEdges, nodeSizes, nodePositions);
                if (numCrossings == 0 && additionalCrossings == 0) {
//                    if(nodeSizes.Length>100)
//                    ShowAndMoveBoxesRemoveLater(null, proximityEdges, nodeSizes, nodePositions, -1);
                    return false;
                }

                if (numCrossings == 0 && !scanlinePhase) return false;
            }
            var treeEdges = MstOnDelaunayTriangulation.GetMstOnTuple(proximityEdges, nodePositions.Length);

            int rootId = treeEdges.First().Item1;

//            if (nodeSizes.Length > 100)
//                ShowAndMoveBoxesRemoveLater(treeEdges, proximityEdges, nodeSizes, nodePositions, rootId);

            MoveNodePositions(treeEdges, nodePositions, rootId);

            return true;
        }
コード例 #6
0
        /// <summary>
        /// adding a point with a Size
        /// </summary>
        /// <param name="size"></param>
        /// <param name="point"></param>
        public void Add(Size size, Point point) {
            var w = size.Width / 2;
            var h = size.Height / 2;

            Add(new Point(point.X - w, point.Y - h));
            Add(new Point(point.X + w, point.Y - h));
            Add(new Point(point.X - w, point.Y + h));
            Add(new Point(point.X + w, point.Y + h));
        }
        /// <summary>
        /// Determines the edges of the triangulation together with their desired length (distance between nodes).
        /// </summary>
        /// <param name="originalGraph"></param>
        /// <param name="cdt"></param>
        /// <param name="targetSizes"></param>
        /// <param name="desiredEdgeDistances"></param>
        /// <returns></returns>
        public static int GetProximityEdgesWithDistance(Node[] originalGraph, Cdt cdt,
                                                        Size[] targetSizes,
                                                        out List<Tuple<int, int, double, double>> desiredEdgeDistances) {
            desiredEdgeDistances = new List<Tuple<int, int, double, double>>();
            int numberOverlappingPairs = 0;
            var edgeSet = new HashSet<CdtEdge>();
            //add edges
            foreach (CdtTriangle triangle in cdt.GetTriangles()) {
                foreach (CdtEdge triangleEdge in triangle.Edges) {
                    CdtSite site1 = triangleEdge.upperSite;
                    CdtSite site2 = triangleEdge.lowerSite;
                    var nodeId1 = (int) site1.Owner;
                    var nodeId2 = (int) site2.Owner;
                    if (edgeSet.Contains(triangleEdge)) continue; //edge already included 
                    edgeSet.Add(triangleEdge);

                    Point point1 = site1.Point;
                    Point point2 = site2.Point;

                    double t;
                    double distance = GetIdealDistanceBetweenNodes(nodeId1, nodeId2, point1, point2, targetSizes,
                                                                   out t);
                    if (t > 1)
                        numberOverlappingPairs++;
                    int nodeIdSmall = nodeId1;
                    int nodeIdBig = nodeId2;
                    if (nodeId1 > nodeId2) {
                        nodeIdSmall = nodeId2;
                        nodeIdBig = nodeId1;
                    }
                    var tuple = new Tuple<int, int, double, double>(nodeIdSmall, nodeIdBig, distance, t);
                    desiredEdgeDistances.Add(tuple);
                }
            }
            return numberOverlappingPairs;
        }
コード例 #8
0
        /// <summary>
        /// Does the initial scaling of the layout, could also be avoided.
        /// </summary>
        /// <param name="nodes"></param>
        /// <param name="nodePositions"></param>
        /// <param name="nodeSizes"></param>
        /// <param name="scalingMethod"></param>
        static void DoInitialScaling(Node[] nodes, Point[] nodePositions, Size[] nodeSizes,
            InitialScaling scalingMethod) {

            var avgEdgeLength = AvgEdgeLength(nodes);
            double goalLength;
            if (scalingMethod == InitialScaling.Inch72Pixel)
                goalLength = 72;
            else if (scalingMethod == InitialScaling.AvgNodeSize)
                goalLength = nodeSizes.Average(box => (box.Width + box.Height)/2);
            else return;

            double scaling = goalLength/avgEdgeLength;
#if DEBUG
            Console.WriteLine("AvgEdgeLength Scaling Method: {0}, ScaleFactor={1:F2}", scalingMethod, scaling);
#endif
            for (int j = 0; j < nodePositions.Length; j++) {
                nodePositions[j] *= scaling;
            }
        }
         int CountCrossingsWithRTree(Size[] nodeSizes) {
            RectangleNode<int> rootNode =
                RectangleNode<int>.CreateRectangleNodeOnEnumeration(
                    nodeSizes.Select((r, index) => new RectangleNode<int>(index, new Rectangle(r,nodePositions[index]))));
            int numCrossings = 0;
            RectangleNodeUtils.CrossRectangleNodes<int, int>(rootNode, rootNode,
                                                             (a, b) => {
                                                                 if (a == b) return;
                                                                 numCrossings++;
                                                             });

            return numCrossings;
        }
コード例 #10
0
 internal static Point[] InitNodePositionsAndBoxes(OverlapRemovalSettings overlapRemovalSettings,
                                                   Node[] nodes, out Point[] nodePositions,
                                                   out Size[] nodeSizes) {
     nodePositions = nodes.Select(v => v.Center).ToArray();
     //make sure no two points are the same
     RandomizePoints(nodePositions, new Random(overlapRemovalSettings.RandomizationSeed),
                     overlapRemovalSettings.Epsilon,
                     overlapRemovalSettings.RandomizeAllPointsOnStart);
     nodeSizes = GetNodeSizesByPaddingWithHalfSeparation(nodes, overlapRemovalSettings.NodeSeparation);
     return nodePositions;
 }
コード例 #11
0
//         double GetAverageOverlap(List<Tuple<int, int, double, double>> proximityEdgesWithDistance,
//                                         Point[] positions, Rectangle[] rectangles) {
//            double overlap = 0;
//            int counter = 0;
//            foreach (Tuple<int, int, double, double> tuple in proximityEdgesWithDistance) {
//                int nodeId1 = tuple.Item1;
//                int nodeId2 = tuple.Item2;
//                Point point1 = positions[nodeId1];
//                Point point2 = positions[nodeId2];
//
//                if (nodeBoxes == null) throw new ArgumentNullException("nodeBoxes");
//                if (nodeBoxes.Length <= nodeId1) return 0;
//                if (nodeBoxes.Length <= nodeId2) return 0;
//                double box1Width = nodeBoxes[nodeId1].Width;
//                double box1Height = nodeBoxes[nodeId1].Height;
//                double box2Width = nodeBoxes[nodeId2].Width;
//                double box2Height = nodeBoxes[nodeId2].Height;
//
//                //Gansner et. al Scaling factor of distance
//                double tw = (box1Width/2 + box2Width/2)/Math.Abs(point1.X - point2.X);
//                double th = (box1Height/2 + box2Height/2)/Math.Abs(point1.Y - point2.Y);
//                double t = Math.Max(Math.Min(tw, th), 1);
//
//                if (t == 1) continue; // no overlap between the bounding boxes
//
//                double distance = (t - 1)*(point1 - point2).Length;
//                overlap += distance;
//                counter++;
//            }
//
//            overlap /= counter;
//            return overlap;
//        }

        /// <summary>
        /// For debugging only
        /// </summary>
        /// <param name="currentIteration"></param>
        /// <param name="nodeSizes"></param>
        /// <param name="nodePositions"></param>
        /// <param name="newPositions"></param>
        /// <param name="proximityEdgesWithDistance"></param>
        /// <param name="finalGridVectors"></param>
         static void ShowCurrentMovementVectors(int currentIteration, Size[] nodeSizes,
                                                       Point[] nodePositions, List<Point> newPositions,
                                                       List<Tuple<int, int, double, double>> proximityEdgesWithDistance,
                                                       Point[] finalGridVectors) {
#if DEBUG && ! SILVERLIGHT && !SHARPKIT
            if (DebugMode && currentIteration%1 == 0) {
                List<DebugCurve> curveList = new List<DebugCurve>();
                var nodeBoxes = new Rectangle[nodeSizes.Length];
                for(int i=0;i<nodeBoxes.Length;i++)
                    nodeBoxes[i]=new Rectangle(nodeSizes[i], nodePositions[i]);
                var nodeCurves =
                    nodeBoxes.Select(
                        v =>
                        new DebugCurve(220, 1, "black", Curve.PolylineAroundClosedCurve(CurveFactory.CreateRectangle(v))));
                curveList.AddRange(nodeCurves);
                var vectors = nodePositions.Select(
                    (p, i) =>
                    new DebugCurve(220, 2, "red", new Polyline(p, newPositions[i]))).ToList();

                foreach (Tuple<int, int, double, double> tuple in proximityEdgesWithDistance) {
                    if (tuple.Item3 > 0) {
                        curveList.Add(new DebugCurve(220, 1, "gray",
                                                     new Polyline(nodePositions[tuple.Item1],
                                                                  nodePositions[tuple.Item2])));
                    }
                }
                curveList.AddRange(vectors);
                if (finalGridVectors != null) {
                    var gridFlowVectors = nodePositions.Select((p, i) =>
                                                               new DebugCurve(220, 2, "blue",
                                                                              new Polyline(p, p + finalGridVectors[i])))
                                                       .ToList();
                    curveList.AddRange(gridFlowVectors);
                }

                LayoutAlgorithmSettings.ShowDebugCurves(curveList.ToArray());
            }
#endif
        }
コード例 #12
0
 Rectangle GetCommonRectangle(Size[] sizes, Point[] points) {
     var rect = Rectangle.CreateAnEmptyBox();
     Debug.Assert(sizes.Length==points.Length);
     for (int i = 0; i < sizes.Length; i++)
         rect.Add(sizes[i], points[i]);
     return rect;
 }
コード例 #13
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="nodeId1"></param>
        /// <param name="nodeId2"></param>
        /// <param name="point1"></param>
        /// <param name="point2"></param>
        /// <param name="nodeBoxes"></param>
        /// <param name="tRes"></param>
        /// <returns></returns>
        public static double GetIdealDistanceBetweenNodes(int nodeId1, int nodeId2, Point point1, Point point2,
                                                          Size[] nodeBoxes, out double tRes) {
            if (nodeBoxes == null) throw new ArgumentNullException("nodeBoxes");
            tRes = -1;
            if (nodeBoxes.Length <= nodeId1) return 0;
            if (nodeBoxes.Length <= nodeId2) return 0;

            const double expandMax = 1.5;
            const double expandMin = 1;
//            double tmax = 0;
//            double tmin = 1E10;

            const double machineAcc = 1.0e-16;
            double dist = (point1 - point2).Length;
            double dx = Math.Abs(point1.X - point2.X);
            double dy = Math.Abs(point1.Y - point2.Y);

            double wx = (nodeBoxes[nodeId1].Width/2 + nodeBoxes[nodeId2].Width/2);
            double wy = (nodeBoxes[nodeId1].Height/2 + nodeBoxes[nodeId2].Height/2);

            double t;
            if (dx < machineAcc*wx) {
                t = wy/dy;
            }
            else if (dy < machineAcc*wy) {
                t = wx/dx;
            }
            else {
                t = Math.Min(wx/dx, wy/dy);
            }

            if (t > 1) t = Math.Max(t, 1.001); // must be done, otherwise the convergence is very slow
//            tmax = Math.Max(tmax, t);
//            tmin = Math.Min(tmin, t);
            t = Math.Min(expandMax, t);
            t = Math.Max(expandMin, t);
            tRes = t;
            return t*dist;
        }
コード例 #14
0
 /// <summary>
 /// temporary due to merge problems.
 /// </summary>
 /// <param name="nodeId1"></param>
 /// <param name="nodeId2"></param>
 /// <param name="point1"></param>
 /// <param name="point2"></param>
 /// <param name="nodeBoxes"></param>
 /// <param name="tRes"></param>
 /// <returns></returns>
 public static double GetOverlapFactorBetweenNodes(int nodeId1, int nodeId2, Point point1, Point point2,
                                                   Size[] nodeBoxes, out double tRes) {
     return GetIdealDistanceBetweenNodes(nodeId1, nodeId2, point1, point2, nodeBoxes, out tRes);
 }
コード例 #15
0
        /// <summary>
        /// Returns the ideal edge length, such that the overlap is removed.
        /// </summary>
        /// <param name="nodeId1"></param>
        /// <param name="nodeId2"></param>
        /// <param name="point1"></param>
        /// <param name="point2"></param>
        /// <param name="nodeBoxes"></param>
        /// <param name="tRes"></param>
        /// <returns></returns>
        static double GetIdealEdgeLength(int nodeId1, int nodeId2, Point point1, Point point2,
            Size[] nodeBoxes, out double tRes) {
            if (nodeBoxes == null) throw new ArgumentNullException("nodeBoxes");


            //            double expandMax = double.PositiveInfinity; //todo : this expands all the way
            const double expandMax = 1.5;
            const double expandMin = 1;

            //todo: replace machineAcc with global epsilon method in MSAGL
            const double machineAcc = 1.0e-16;
            double dist = (point1 - point2).Length;
            double dx = Math.Abs(point1.X - point2.X);
            double dy = Math.Abs(point1.Y - point2.Y);

            double wx = (nodeBoxes[nodeId1].Width/2 + nodeBoxes[nodeId2].Width/2);
            double wy = (nodeBoxes[nodeId1].Height/2 + nodeBoxes[nodeId2].Height/2);

            double t;
            if (dx < machineAcc*wx) {
                t = wy/dy;
            }
            else if (dy < machineAcc*wy) {
                t = wx/dx;
            }
            else {
                t = Math.Min(wx/dx, wy/dy);
            }

            if (t > 1) t = Math.Max(t, 1.001); // must be done, otherwise the convergence is very slow

            t = Math.Min(expandMax, t);
            t = Math.Max(expandMin, t);
            tRes = t;
            return t*dist;
        }
コード例 #16
0
 /// <summary>
 /// Shows the current state of the algorithm for debug purposes.
 /// </summary>
 /// <param name="treeEdges"></param>
 /// <param name="proximityEdges"></param>
 /// <param name="nodeSizes"></param>
 /// <param name="nodePos"></param>
 /// <param name="rootId"></param>
     void ShowAndMoveBoxesRemoveLater(List<Tuple<int, int, double, double, double>> treeEdges,
         List<Tuple<int, int, double, double, double>> proximityEdges, Size[] nodeSizes, Point[] nodePos, int rootId) {
         var l = new List<DebugCurve>();
         foreach (var tuple in proximityEdges)
             l.Add(new DebugCurve(100, 0.5, "black", new LineSegment(nodePos[tuple.Item1], nodePos[tuple.Item2])));
         //just for debug
         var nodeBoxes = new Rectangle[nodeSizes.Length];
         for (int i = 0; i < nodePos.Length; i++)
             nodeBoxes[i] = new Rectangle(nodeSizes[i], nodePos[i]);
         l.AddRange(nodeBoxes.Select(b => new DebugCurve(100, 0.3, "green", b.Perimeter())));
         if (treeEdges != null)
             l.AddRange(
                 treeEdges.Select(
                     e =>
                         new DebugCurve(200, GetEdgeWidth(e), "red",
                             new LineSegment(nodePos[e.Item1], nodePos[e.Item2]))));
         if (rootId >= 0)
             l.Add(new DebugCurve(100, 10, "blue", CurveFactory.CreateOctagon(30, 30, nodePos[rootId])));
         LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(l);
     }
コード例 #17
0
  static Size[] GetNodeSizesByPaddingWithHalfSeparation(Node[] nodes, double nodeSeparation) {
     if (nodes == null) return null;
     var nodeSizes = new Size[nodes.Length];
      var halfSep = nodeSeparation/2;
      for (int i = 0; i < nodes.Length; i++) {
          nodeSizes[i] = nodes[i].BoundingBox.Size;
          nodeSizes[i].Pad(halfSep);
      }
      return nodeSizes;
 }
コード例 #18
0
 public static void RemoveOverlapsForLayers(Node[] nodes, Size[] sizesOnLayers) {
     var settings = new OverlapRemovalSettings
     {
         RandomizeAllPointsOnStart = true,
     };
     var mst = new OverlapRemoval(settings, nodes, sizesOnLayers);
     mst.RemoveOverlaps();
 }
コード例 #19
0
/// <summary>
/// constructor with Size and center
/// </summary>
/// <param name="size"></param>
/// <param name="center"></param>
        public Rectangle(Size size, Point center) {
            var w = size.Width/2;
            left = center.X - w;
            right = center.X + w;
            var h = size.Height / 2;
            bottom = center.Y - h;
            top = center.Y + h;
        }