internal void InitializeCostCache()
        {
            foreach (var v in metroGraphData.VirtualNodes())
            {
                v.cachedIdealRadius = HubRadiiCalculator.CalculateIdealHubRadiusWithNeighbors(metroGraphData, bundlingSettings, v);
                v.cachedRadiusCost  = costCalculator.RadiusCost(v, v.Position);
                v.cachedBundleCost  = 0;
            }

            foreach (var edge in metroGraphData.VirtualEdges())
            {
                var             v        = edge.Item1;
                var             u        = edge.Item2;
                StationEdgeInfo edgeInfo = metroGraphData.GetIjInfo(v, u);
                edgeInfo.cachedBundleCost = costCalculator.BundleCost(v, u, v.Position);
                v.cachedBundleCost       += edgeInfo.cachedBundleCost;
                u.cachedBundleCost       += edgeInfo.cachedBundleCost;
            }
        }
        /// <summary>
        /// Cost of the whole graph (hubs and bundles)
        /// </summary>
        static internal double CostOfForces(MetroGraphData metroGraphData, BundlingSettings bundlingSettings)
        {
            double cost = 0;

            //hubs
            foreach (var v in metroGraphData.VirtualNodes())
            {
                cost += v.cachedRadiusCost;
            }

            //bundles
            foreach (var edge in metroGraphData.VirtualEdges())
            {
                var v = edge.Item1;
                var u = edge.Item2;
                cost += metroGraphData.GetIjInfo(v, u).cachedBundleCost;
            }

            return(cost);
        }
        /// <summary>
        /// split each edge that is too much constrained by the obstacles
        /// </summary>
        bool RelaxConstrainedEdges()
        {
            HashSet <Point> affectedPoints = new HashSet <Point>();
            bool            progress       = false;

            foreach (var edge in metroGraphData.VirtualEdges())
            {
                if (RelaxConstrainedEdge(edge.Item1, edge.Item2, affectedPoints))
                {
                    progress = true;
                }
            }

            if (progress)
            {
                //TimeMeasurer.DebugOutput("relaxing constrained edges");
                metroGraphData.Initialize(false);

                SimulatedAnnealing.FixRouting(metroGraphData, bundlingSettings, affectedPoints);
            }

            return(progress);
        }
 IEnumerable <DebugCurve> Bundles()
 {
     return(mgd.VirtualEdges().Select(pr => new DebugCurve(100, 1, "red", new LineSegment(pr.Item1.Position, pr.Item2.Position))));
 }
        /// <summary>
        /// Cost of the whole graph (hubs and bundles)
        /// </summary>
        static internal double CostOfForces(MetroGraphData metroGraphData, BundlingSettings bundlingSettings) {
            double cost = 0;

            //hubs
            foreach (var v in metroGraphData.VirtualNodes()) {
                cost += v.cachedRadiusCost;
            }

            //bundles
            foreach (var edge in metroGraphData.VirtualEdges()) {
                var v = edge.Item1;
                var u = edge.Item2;
                cost += metroGraphData.GetIjInfo(v, u).cachedBundleCost;
            }

            return cost;
        }