double SeparationCost(BundleInfo bundleInfo) { return SeparationCostForBundleBase(bundleInfo.SourceBase) + SeparationCostForBundleBase(bundleInfo.TargetBase); }
void AllocateBundleBases() { externalBases = new Dictionary<ICurve, List<BundleBase>>(); internalBases = new Dictionary<ICurve, List<BundleBase>>(); Bundles = new List<BundleInfo>(); foreach (var station in metroGraphData.Stations) { if (station.BoundaryCurve == null) station.BoundaryCurve = new Ellipse(station.Radius, station.Radius, station.Position); } foreach (var station in metroGraphData.Stations) { foreach (Station neighbor in station.Neighbors) { if (station < neighbor) { var bb = new BundleBase(metroGraphData.RealEdgeCount(station, neighbor), station.BoundaryCurve, station.Position, station.IsRealNode, neighbor.SerialNumber); station.BundleBases[neighbor] = bb; var bb2 = new BundleBase(metroGraphData.RealEdgeCount(station, neighbor), neighbor.BoundaryCurve, neighbor.Position, neighbor.IsRealNode, station.SerialNumber); neighbor.BundleBases[station] = bb2; if (Curve.PointRelativeToCurveLocation(neighbor.Position, station.BoundaryCurve) != PointLocation.Outside) { bb.IsParent = true; CollectionUtilities.AddToMap(internalBases, station.BoundaryCurve, bb); CollectionUtilities.AddToMap(externalBases, neighbor.BoundaryCurve, bb2); } else if (Curve.PointRelativeToCurveLocation(station.Position, neighbor.BoundaryCurve) != PointLocation.Outside) { bb2.IsParent = true; CollectionUtilities.AddToMap(externalBases, station.BoundaryCurve, bb); CollectionUtilities.AddToMap(internalBases, neighbor.BoundaryCurve, bb2); } else { CollectionUtilities.AddToMap(externalBases, station.BoundaryCurve, bb); CollectionUtilities.AddToMap(externalBases, neighbor.BoundaryCurve, bb2); } Set<Polyline> obstaclesToIgnore = metroGraphData.tightIntersections.ObstaclesToIgnoreForBundle(station, neighbor); var bundle = new BundleInfo(bb, bb2, obstaclesToIgnore, bundlingSettings.EdgeSeparation, metroOrdering.GetOrder(station, neighbor).Select(l => l.Width / 2).ToArray()); bb.OutgoingBundleInfo = bb2.IncomingBundleInfo = bundle; Bundles.Add(bundle); } } } //neighbors SetBundleBaseNeighbors(); }
double CenterCost(BundleInfo bundleInfo) { if (!bundleInfo.SourceBase.BelongsToRealNode && !bundleInfo.TargetBase.BelongsToRealNode) return 0; return CenterCost(bundleInfo.SourceBase) + CenterCost(bundleInfo.TargetBase); }
double AssymetryCost(BundleInfo bundleInfo) { return GetAssymetryCostForBase(bundleInfo.SourceBase) + GetAssymetryCostForBase(bundleInfo.TargetBase); }
//this is an accelerated version of the above function (calculate cost partly) double Cost(BundleInfo bundleInfo, double limit) { double cost = 0; cost += CenterCoeff * CenterCost(bundleInfo); if (cost > limit) return cost; cost += SeparationCoeff * SeparationCost(bundleInfo); if (cost > limit) return cost; cost += SqueezeCoeff * SqueezeCost(bundleInfo); if (cost > limit) return cost; cost += AssymetryCoeff * AssymetryCost(bundleInfo); return cost; }
double SqueezeCost(BundleInfo bundleInfo) { var middleLineDir = (bundleInfo.TargetBase.MidPoint - bundleInfo.SourceBase.MidPoint).Normalize(); var perp = middleLineDir.Rotate90Ccw(); var projecton0 = Math.Abs((bundleInfo.SourceBase.RightPoint - bundleInfo.SourceBase.LeftPoint) * perp); var projecton1 = Math.Abs((bundleInfo.TargetBase.RightPoint - bundleInfo.TargetBase.LeftPoint) * perp); double del0 = Math.Abs(bundleInfo.TotalRequiredWidth - projecton0) / bundleInfo.TotalRequiredWidth; double del1 = Math.Abs(bundleInfo.TotalRequiredWidth - projecton1) / bundleInfo.TotalRequiredWidth; double del = Math.Abs(projecton0 - projecton1) / bundleInfo.TotalRequiredWidth; double cost = Math.Exp(del0 * 10) - 1 + Math.Exp(del1 * 10) - 1; cost += del; return cost; }
double Cost(BundleInfo bundleInfo) { return SeparationCoeff * SeparationCost(bundleInfo) + SqueezeCoeff * SqueezeCost(bundleInfo) + AssymetryCoeff * AssymetryCost(bundleInfo) + CenterCoeff * CenterCost(bundleInfo); }
double DeltaWithChangedAngles(int rotationOfSourceRigthPoint, int rotationOfSourceLeftPoint, int rotationOfTargetRigthPoint, int rotationOfTargetLeftPoint, BundleInfo bundleInfo, double bundleCost, double parameterChange) { if (!bundleInfo.RotationIsLegal(rotationOfSourceRigthPoint, rotationOfSourceLeftPoint, rotationOfTargetRigthPoint, rotationOfTargetLeftPoint, parameterChange)) return 0; bundleInfo.RotateBy(rotationOfSourceRigthPoint, rotationOfSourceLeftPoint, rotationOfTargetRigthPoint, rotationOfTargetLeftPoint, parameterChange); var newCost = Cost(bundleInfo, bundleCost); //restoring bundleInfo.RotateBy(-rotationOfSourceRigthPoint, -rotationOfSourceLeftPoint, -rotationOfTargetRigthPoint, -rotationOfTargetLeftPoint, parameterChange); return bundleCost - newCost; }
bool OptimizeBundle(BundleInfo bundleInfo, double parameterChange, ref double cost) { double bundleCost = Cost(bundleInfo); if (bundleCost < CostThreshold) return false; //choose the best step double bestDelta = 0; int bestI = -1, bestJ = -1; for (int i = 0; i < Deltas.Length - 1; i++) { double delta = DeltaWithChangedAngles(Deltas[i][0], Deltas[i][1], 0, 0, bundleInfo, bundleCost, parameterChange); if (delta > CostDeltaThreshold && delta > bestDelta) { bestI = i; bestJ = Deltas.Length - 1; bestDelta = delta; } delta = DeltaWithChangedAngles(0, 0, Deltas[i][0], Deltas[i][1], bundleInfo, bundleCost, parameterChange); if (delta > CostDeltaThreshold && delta > bestDelta) { bestI = Deltas.Length - 1; bestJ = i; bestDelta = delta; } } if (bestDelta < CostDeltaThreshold) return false; //do the change cost -= bestDelta; bundleInfo.RotateBy(Deltas[bestI][0], Deltas[bestI][1], Deltas[bestJ][0], Deltas[bestJ][1], parameterChange); return true; }
double SeparationCost(BundleInfo bundleInfo) { return(SeparationCostForBundleBase(bundleInfo.SourceBase) + SeparationCostForBundleBase(bundleInfo.TargetBase)); }
double AssymetryCost(BundleInfo bundleInfo) { return(GetAssymetryCostForBase(bundleInfo.SourceBase) + GetAssymetryCostForBase(bundleInfo.TargetBase)); }