/// <summary> /// Layouts a connected graph with Multidimensional Scaling, using /// shortest-path distances as Euclidean target distances. /// </summary> /// <param name="geometryGraph">A graph.</param> /// <param name="settings">The settings for the algorithm.</param> /// <param name="x">Coordinate vector.</param> /// <param name="y">Coordinate vector.</param> internal static void LayoutGraphWithMds(GeometryGraph geometryGraph, MdsLayoutSettings settings, out double[] x, out double[] y) { x = new double[geometryGraph.Nodes.Count]; y = new double[geometryGraph.Nodes.Count]; if (geometryGraph.Nodes.Count == 0) { return; } if (geometryGraph.Nodes.Count == 1) { x[0] = y[0] = 0; return; } int k = Math.Min(settings.PivotNumber, geometryGraph.Nodes.Count); int iter = settings.GetNumberOfIterationsWithMajorization(geometryGraph.Nodes.Count); double exponent = settings.Exponent; var pivotArray = new int[k]; PivotDistances pivotDistances = new PivotDistances(geometryGraph, false, pivotArray); pivotDistances.Run(); double[][] c = pivotDistances.Result; MultidimensionalScaling.LandmarkClassicalScaling(c, out x, out y, pivotArray); ScaleToAverageEdgeLength(geometryGraph, x, y); if (iter > 0) { AllPairsDistances apd = new AllPairsDistances(geometryGraph, false); apd.Run(); double[][] d = apd.Result; double[][] w = MultidimensionalScaling.ExponentialWeightMatrix(d, exponent); // MultidimensionalScaling.DistanceScaling(d, x, y, w, iter); MultidimensionalScaling.DistanceScalingSubset(d, x, y, w, iter); } }
/// <summary> /// Default constructor /// </summary> public GViewer(){ mdsLayoutSettings = new MdsLayoutSettings(); sugiyamaSettings = new SugiyamaLayoutSettings(); // This call is required by the Windows.Forms Form Designer. InitializeComponent(); BackwardEnabled = false; ForwardEnabled = false; toolbar.MouseMove += ToolBarMouseMoved; Assembly a = Assembly.GetExecutingAssembly(); foreach (string r in a.GetManifestResourceNames()){ if (r.Contains("hmove.cur")) panGrabCursor = new Cursor(a.GetManifestResourceStream(r)); else if (r.Contains("oph.cur")) panOpenCursor = new Cursor(a.GetManifestResourceStream(r)); } originalCursor = Cursor; panButton.Pushed = false; windowZoomButton.Pushed = false; layoutSettingsButton.ToolTipText = "Configures the layout algorithm settings"; undoButton.ToolTipText = "Undo layout editing"; redoButton.ToolTipText = "Redo layout editing"; forwardButton.ToolTipText = "Forward"; panButton.ToolTipText = panButton.Pushed ? panButtonToolTipText : PanButtonDisabledToolTipText; windowZoomButton.ToolTipText = windowZoomButton.Pushed ? WindowZoomButtonToolTipText : windowZoomButtonDisabledToolTipText; InitDrawingLayoutEditor(); toolbar.Invalidate(); SuspendLayout(); InitPanel(); Controls.Add(toolbar); ResumeLayout(); }
/// <summary> /// Executes the algorithm. /// </summary> /// <summary> /// Executes the actual algorithm. /// </summary> protected override void RunInternal() { var g = new GeometryGraph(); foreach (var v in graph.Nodes) { Debug.Assert(!(v is Cluster)); var u = new Node(v.BoundaryCurve.Clone()) { UserData = v }; v.AlgorithmData = new PivotMDSNodeWrap(u); g.Nodes.Add(u); } double avgLength = 0; foreach (var e in graph.Edges) { avgLength += e.Length; if (e.Source is Cluster || e.Target is Cluster) { continue; } var u = e.Source.AlgorithmData as PivotMDSNodeWrap; var v = e.Target.AlgorithmData as PivotMDSNodeWrap; var ee = new Edge(u.node, v.node) { Length = e.Length }; g.Edges.Add(ee); } if (graph.Edges.Count != 0) { avgLength /= graph.Edges.Count; } else { avgLength = 100; } // create edges from the children of each parent cluster to the parent cluster node foreach (var c in graph.RootCluster.AllClustersDepthFirst()) { if (c == graph.RootCluster) { continue; } var u = new Node(CurveFactory.CreateRectangle(10, 10, new Point())); u.UserData = c; c.AlgorithmData = new PivotMDSNodeWrap(u); g.Nodes.Add(u); foreach (var v in c.Nodes.Concat(from cc in c.Clusters select(Node) cc)) { var vv = v.AlgorithmData as PivotMDSNodeWrap; g.Edges.Add(new Edge(u, vv.node) { Length = avgLength }); } } // create edges between clusters foreach (var e in graph.Edges) { if (e.Source is Cluster || e.Target is Cluster) { var u = e.Source.AlgorithmData as PivotMDSNodeWrap; var v = e.Target.AlgorithmData as PivotMDSNodeWrap; var ee = new Edge(u.node, v.node) { Length = e.Length }; g.Edges.Add(ee); } } // with 0 majorization iterations we just do PivotMDS MdsLayoutSettings settings = new MdsLayoutSettings { ScaleX = this.Scale, ScaleY = this.Scale, IterationsWithMajorization = 0, RemoveOverlaps = false, AdjustScale = false }; MdsGraphLayout mdsLayout = new MdsGraphLayout(settings, g); this.RunChildAlgorithm(mdsLayout, 1.0); g.UpdateBoundingBox(); foreach (var v in graph.Nodes) { var m = v.AlgorithmData as PivotMDSNodeWrap; v.Center = m.node.Center; } }
MdsLayoutSettings GetMdsLayoutSettings() { var settings = new MdsLayoutSettings(); settings.ScaleX *= 3; settings.ScaleY *= 3; settings.EdgeRoutingSettings.KeepOriginalSpline = true; settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Spline; settings.IterationsWithMajorization = _argsParser.OptionIsUsed(NoIterationsWithMajorization) ? 0 : 30; if (_argsParser.OptionIsUsed(AllowOverlapsInMds)) settings.RemoveOverlaps = false; if (_argsParser.OptionIsUsed(SequentialRunOption)) settings.RunInParallel = false; if (_argsParser.OptionIsUsed(StraightLineEdgesOption)) settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.StraightLine; if (_argsParser.OptionIsUsed(NoEdgeRoutingOption)) settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.None; //settings.AdjustScale = true; return settings; }
public static void MDS() { WriteMessage("Starting test..."); WriteMessage("Create GeometryGraph"); GeometryGraph graph = AbcdeGraph(); //graph.Save("c:\\tmp\\saved.msagl"); var settings = new MdsLayoutSettings(); settings.RunInParallel = false; settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Rectilinear; LayoutHelpers.CalculateLayout(graph, settings, null); WriteMessage("Layout progressed"); WriteMessage(""); WriteMessage("Segments A->B"); //OutputCurve(ab.Curve); WriteMessage(""); WriteMessage("Segments B->C"); //OutputCurve(bc.Curve); WriteMessage(""); WriteMessage("Segments C->A"); //OutputCurve(ca.Curve); foreach (var node in graph.Nodes) { WriteMessage(string.Format("{0}: {1} {2}", node.UserData, node.Center.X, node.Center.Y)); } /*var canvas = HtmlContext.document.getElementById("drawing").As<HtmlCanvasElement>(); var ctx = canvas.getContext("2d").As<CanvasRenderingContext2D>(); var canvasHeight = canvas.height; var bounds = calcBounds(graph.Nodes); var xScale = canvas.width / bounds.Width; var yScale = canvas.height / bounds.Height; var xShift = -bounds.Left * xScale; var yShift = -(canvas.height - bounds.Top) * yScale; WriteMessage(string.Format("Scaling : {0} {1}", xScale, yScale)); WriteMessage(string.Format("Shifting : {0} {1}", xShift, yShift)); foreach (var msaglEdge in graph.Edges) { DrawEdge(ctx, msaglEdge, xShift, yShift, xScale, yScale, canvasHeight); } foreach (var msaglNode in graph.Nodes) { DrawNode(ctx, msaglNode, xShift, yShift, xScale, yScale, canvasHeight); }*/ }
void MDSLayout(MdsLayoutSettings settings, GeometryGraph component) { LayoutAlgorithmHelpers.ComputeDesiredEdgeLengths(settings.IdealEdgeLength, component); var layout = new MdsGraphLayout(settings, component); layout.Run(this.CancelToken); InitialLayoutHelpers.RouteEdges(component, settings, this.CancelToken); InitialLayoutHelpers.PlaceLabels(component, this.CancelToken); InitialLayoutHelpers.FixBoundingBox(component, settings); }
/// <summary> /// Constructs the multidimensional scaling algorithm. /// </summary> public MdsGraphLayout(MdsLayoutSettings settings, GeometryGraph geometryGraph) { this.settings = settings; graph = geometryGraph; }
static void Main(string[] args) { #if DEBUG DisplayGeometryGraph.SetShowFunctions(); #endif ArgsParser.ArgsParser argsParser = SetArgsParser(args); if (argsParser.OptionIsUsed(PolygonDistanceTestOption)) TestPolygonDistance(); else if (argsParser.OptionIsUsed(TestCdtThreaderOption)) TestCdtThreader(); else if (argsParser.OptionIsUsed(RandomBundlingTest)) RandomBundlingTests.RsmContent(); bundling = argsParser.OptionIsUsed(BundlingOption); var gviewer = new GViewer(); gviewer.MouseMove += Draw.GviewerMouseMove; if(argsParser.OptionIsUsed(FdOption)) { TestFD(); gviewer.CurrentLayoutMethod = LayoutMethod.IcrementalLayout; } Form form = CreateForm(null, gviewer); if (argsParser.OptionIsUsed(AsyncLayoutOption)) gviewer.AsyncLayout = true; string listOfFilesFile = argsParser.GetValueOfOptionWithAfterString(ListOfFilesOption); if (listOfFilesFile != null) { ProcessListOfFiles(listOfFilesFile, argsParser); return; } string fileName = argsParser.GetValueOfOptionWithAfterString(FileOption); string ext = Path.GetExtension(fileName); if (ext != null) { ext = ext.ToLower(); if (ext == ".dot") { ProcessDotFile(gviewer, argsParser, fileName); } else { if (ext == ".geom") { GeometryGraph geometryGraph = GeometryGraphReader.CreateFromFile(fileName); geometryGraph.Margins = 10; FixHookPorts(geometryGraph); // if (argsParser.OptionIsUsed(BundlingOption)) { for (int i = 0; i < 1; i++) { #if DEBUG /*DisplayGeometryGraph.ShowGraph(geometryGraph); var l = new List<DebugCurve>(); l.AddRange(geometryGraph.Nodes.Select(n=>new DebugCurve(100,1,"black",n.BoundaryCurve))); l.AddRange(geometryGraph.Edges.Select(e=>new DebugCurve(100,1,"black", new LineSegment(e.Source.Center,e.Target.Center)))); foreach (var cl in geometryGraph.RootCluster.AllClustersDepthFirst()) { l.Add(new DebugCurve(100,2,"blue",cl.BoundaryCurve)); foreach (var node in cl.Nodes) l.Add(new DebugCurve(100, 2, "brown", node.BoundaryCurve)); foreach (var e in cl.Edges) l.Add(new DebugCurve(100, 2, "pink", new LineSegment(e.Source.Center, e.Target.Center))); } DisplayGeometryGraph.ShowDebugCurves(l.ToArray());*/ #endif BundlingSettings bs = GetBundlingSettings(argsParser); double loosePadding; double tightPadding = GetPaddings(argsParser, out loosePadding); if (argsParser.OptionIsUsed(MdsOption)) { var mdsLayoutSettings = new MdsLayoutSettings {RemoveOverlaps = true, NodeSeparation = loosePadding*3}; var mdsLayout = new MdsGraphLayout(mdsLayoutSettings, geometryGraph); mdsLayout.Run(); } else { if (argsParser.OptionIsUsed(FdOption)) { var settings = new FastIncrementalLayoutSettings {AvoidOverlaps = true}; (new InitialLayout(geometryGraph, settings)).Run(); } } var splineRouter = new SplineRouter(geometryGraph, geometryGraph.Edges, tightPadding, loosePadding, Math.PI/6, bs); splineRouter.Run(); } #if DEBUG DisplayGeometryGraph.ShowGraph(geometryGraph); #endif return; } else { if (ext == ".msagl") { Graph graph = Graph.Read(fileName); // DisplayGeometryGraph.ShowGraph(graph.GeometryGraph); if (graph != null) { if (argsParser.OptionIsUsed(BundlingOption)) { BundlingSettings bs = GetBundlingSettings(argsParser); double loosePadding; double tightPadding = GetPaddings(argsParser, out loosePadding); var br = new SplineRouter(graph.GeometryGraph, tightPadding, loosePadding, Math.PI/6, bs); br.Run(); // DisplayGeometryGraph.ShowGraph(graph.GeometryGraph); } } gviewer.NeedToCalculateLayout = false; gviewer.Graph = graph; gviewer.NeedToCalculateLayout = true; } } } } else if (argsParser.OptionIsUsed(TestCdtOption)) { Triangulation(argsParser.OptionIsUsed(ReverseXOption)); Environment.Exit(0); } else if (argsParser.OptionIsUsed(TestCdtOption0)) { TestTriangulationOnSmallGraph(argsParser); Environment.Exit(0); } else if (argsParser.OptionIsUsed(TestCdtOption2)) { TestTriangulationOnPolys(); Environment.Exit(0); } else if (argsParser.OptionIsUsed(TestCdtOption1)) { ThreadThroughCdt(); Environment.Exit(0); } else if (argsParser.OptionIsUsed(ConstraintsTestOption)) TestGraphWithConstraints(); Application.Run(form); }
static void LoadGeomFile(string s, EdgeRoutingSettings edgeRoutingSettings, bool show) { LayoutAlgorithmSettings settings; GeometryGraph geomGraph = GeometryGraphReader.CreateFromFile(s, out settings); if (geomGraph == null) { //Opens file "data.xml" and deserializes the object from it. var stream = File.Open(s, FileMode.Open); var formatter = new BinaryFormatter(); geomGraph = (GeometryGraph) formatter.Deserialize(stream); geomGraph.RootCluster = new Cluster(); stream.Close(); } geomGraph.UpdateBoundingBox(); if (FormStuff.initialLayout) { var l = new List<Cluster>(); l.Add(geomGraph.RootCluster); var il = new InitialLayoutByCluster(geomGraph, new FastIncrementalLayoutSettings()); il.Run(); } else if (mds) { var mdsSettings = new MdsLayoutSettings { IterationsWithMajorization = 21,ScaleX = 1, ScaleY=1, RemoveOverlaps = true }; var mdslayout = new MdsGraphLayout(mdsSettings, geomGraph); mdslayout.Run(); var router = new SplineRouter(geomGraph, 1, 20, Math.PI / 6, edgeRoutingSettings.BundlingSettings); router.Run(); } else { var sugiyamaSettings = (SugiyamaLayoutSettings) settings; if (edgeRoutingSettings.EdgeRoutingMode == EdgeRoutingMode.Rectilinear || edgeRoutingSettings.EdgeRoutingMode == EdgeRoutingMode.RectilinearToCenter) { RouteRectEdgesOfGeomGraph(edgeRoutingSettings.EdgeRoutingMode, true, edgeRoutingSettings.UseObstacleRectangles, edgeRoutingSettings.BendPenalty, geomGraph, sugiyamaSettings); } else { const double angle = 30*Math.PI/180; var router = new SplineRouter(geomGraph, 1, 20, angle, edgeRoutingSettings.BundlingSettings); router.Run(); TestPadding(geomGraph); } } #if DEBUG if (show) { geomGraph.UpdateBoundingBox(); var b = geomGraph.BoundingBox; b.Pad(40); geomGraph.BoundingBox = b; DisplayGeometryGraph.ShowGraph(geomGraph); } #endif }
public void TreeGraphMdsLayout() { GeometryGraph treeGraph = GraphGenerator.GenerateTree(20); treeGraph.RootCluster = new Cluster(treeGraph.Nodes); var settings = new MdsLayoutSettings { ScaleX = 1, ScaleY = 1, RemoveOverlaps = true, PackingAspectRatio = 1.4 }; settings.EdgeRoutingSettings = new EdgeRoutingSettings { EdgeRoutingMode = EdgeRoutingMode.Spline, ConeAngle = Math.PI / 6, Padding = settings.NodeSeparation / 2.1 }; foreach (var v in treeGraph.Nodes) { v.BoundingBox = new Rectangle(0, 0, new Point(30, 30)); } var layout = new InitialLayoutByCluster(treeGraph, settings); double progress = 0.0; EventHandler<ProgressChangedEventArgs> handler = (s, e) => progress = e.RatioComplete; try { layout.ProgressChanged += handler; layout.Run(); } finally { layout.ProgressChanged -= handler; } EnableDebugViewer(); ShowGraphInDebugViewer(treeGraph); const double EdgeLengthDelta = 0.5; foreach (var e in treeGraph.Edges) { Assert.IsNotNull(e.Curve, "Edge curves not populated"); if (e.Source != e.Target) { double actualLength = (e.Source.Center - e.Target.Center).Length; double actualDesiredRatio = e.Length / actualLength; Assert.AreEqual(1, actualDesiredRatio, EdgeLengthDelta, "Edge length is not correct"); } } double aspectRatio = treeGraph.BoundingBox.Width / treeGraph.BoundingBox.Height; Assert.AreEqual(settings.PackingAspectRatio, aspectRatio, 1.4, "Aspect ratio too far from desired"); Assert.AreEqual(1.0, progress, "Progress was never reported as 100%. Last update was at " + progress + "%"); }
/// <summary> /// reads the layout algorithm settings /// </summary> LayoutAlgorithmSettings ReadLayoutAlgorithmSettings(XmlReader reader) { LayoutAlgorithmSettings layoutSettings = null; CheckToken(GeometryToken.LayoutAlgorithmSettings); if (reader.IsEmptyElement) { reader.Read(); return null; } //reader.Read(); var edgeRoutingMode = (EdgeRoutingMode) GetIntAttributeOrDefault(GeometryToken.EdgeRoutingMode, (int) EdgeRoutingMode.Spline); var str = GetAttribute(GeometryToken.LayoutAlgorithmType); if (XmlReader.NodeType == XmlNodeType.EndElement) { //todo - support fastincremental settings layoutSettings = new FastIncrementalLayoutSettings(); EdgeRoutingSettings routingSettings = layoutSettings.EdgeRoutingSettings; routingSettings.EdgeRoutingMode = edgeRoutingMode; } else { if (str != null) { var token = (GeometryToken) Enum.Parse(typeof (GeometryToken), str, false); if (token == GeometryToken.SugiyamaLayoutSettings) { layoutSettings = ReadSugiyamaLayoutSettings(edgeRoutingMode); } else if (token == GeometryToken.MdsLayoutSettings) { var mds = new MdsLayoutSettings(); EdgeRoutingSettings routingSettings = mds.EdgeRoutingSettings; routingSettings.EdgeRoutingMode = edgeRoutingMode; layoutSettings = mds; if (XmlReader.IsStartElement(GeometryToken.Reporting.ToString())) { #if REPORTING mds.Reporting = #endif ReadBooleanElement(GeometryToken.Reporting); } mds.Exponent = ReadDoubleElement(reader); mds.IterationsWithMajorization = ReadIntElement(GeometryToken.IterationsWithMajorization); mds.PivotNumber = ReadIntElement(GeometryToken.PivotNumber); mds.RotationAngle = ReadDoubleElement(reader); mds.ScaleX = ReadDoubleElement(reader); mds.ScaleY = ReadDoubleElement(reader); } else //todo - write a reader and a writer for FastIncrementalLayoutSettings throw new NotImplementedException(); } } reader.ReadEndElement(); return layoutSettings; }
static LayoutAlgorithmSettings PickLayoutAlgorithmSettings(int edges, int nodes) { LayoutAlgorithmSettings settings; const int sugiaymaTreshold = 200; const double bundlingTreshold = 3.0; bool bundling = nodes != 0 && ((double)edges / nodes >= bundlingTreshold || edges>100); if (nodes < sugiaymaTreshold && edges<sugiaymaTreshold) { settings = new SugiyamaLayoutSettings(); if (bundling) settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.SplineBundling; } else { MdsLayoutSettings mdsSettings; settings = mdsSettings = new MdsLayoutSettings { EdgeRoutingSettings = { EdgeRoutingMode = bundling ? EdgeRoutingMode.SplineBundling : EdgeRoutingMode.Spline } }; if (bundling) settings.EdgeRoutingSettings.BundlingSettings = new BundlingSettings(); double scale = FigureOutScaleForMdsLayout(nodes); mdsSettings.ScaleX = scale; mdsSettings.ScaleY = scale; } return settings; }
/// <summary> /// Executes the algorithm. /// </summary> /// <summary> /// Executes the actual algorithm. /// </summary> protected override void RunInternal() { var g = new GeometryGraph(); foreach (var v in graph.Nodes) { Debug.Assert(!(v is Cluster)); var u = new Node(v.BoundaryCurve.Clone()) { UserData = v }; v.AlgorithmData = new PivotMDSNodeWrap(u); g.Nodes.Add(u); } double avgLength = 0; foreach (var e in graph.Edges) { avgLength += e.Length; if (e.Source is Cluster || e.Target is Cluster) continue; var u = e.Source.AlgorithmData as PivotMDSNodeWrap; var v = e.Target.AlgorithmData as PivotMDSNodeWrap; var ee = new Edge(u.node, v.node) { Length = e.Length }; g.Edges.Add(ee); } if (graph.Edges.Count != 0) { avgLength /= graph.Edges.Count; } else { avgLength = 100; } // create edges from the children of each parent cluster to the parent cluster node foreach (var c in graph.RootCluster.AllClustersDepthFirst()) { if (c == graph.RootCluster) continue; var u = new Node(CurveFactory.CreateRectangle(10, 10, new Point())); u.UserData = c; c.AlgorithmData = new PivotMDSNodeWrap(u); g.Nodes.Add(u); foreach (var v in c.Nodes.Concat(from cc in c.Clusters select (Node)cc)) { var vv = v.AlgorithmData as PivotMDSNodeWrap; g.Edges.Add(new Edge(u, vv.node) { Length = avgLength }); } } // create edges between clusters foreach (var e in graph.Edges) { if (e.Source is Cluster || e.Target is Cluster) { var u = e.Source.AlgorithmData as PivotMDSNodeWrap; var v = e.Target.AlgorithmData as PivotMDSNodeWrap; var ee = new Edge(u.node, v.node) { Length = e.Length }; g.Edges.Add(ee); } } // with 0 majorization iterations we just do PivotMDS MdsLayoutSettings settings = new MdsLayoutSettings { ScaleX = this.Scale, ScaleY = this.Scale, IterationsWithMajorization = 0, RemoveOverlaps = false, AdjustScale = false }; MdsGraphLayout mdsLayout = new MdsGraphLayout(settings, g); this.RunChildAlgorithm(mdsLayout, 1.0); g.UpdateBoundingBox(); foreach (var v in graph.Nodes) { var m = v.AlgorithmData as PivotMDSNodeWrap; v.Center = m.node.Center; } }
/// <summary> /// Layouts a connected graph with Multidimensional Scaling, using /// shortest-path distances as Euclidean target distances. /// </summary> /// <param name="geometryGraph">A graph.</param> /// <param name="settings">The settings for the algorithm.</param> /// <param name="x">Coordinate vector.</param> /// <param name="y">Coordinate vector.</param> internal static void LayoutGraphWithMds(GeometryGraph geometryGraph, MdsLayoutSettings settings, out double[] x, out double[] y) { x = new double[geometryGraph.Nodes.Count]; y = new double[geometryGraph.Nodes.Count]; if (geometryGraph.Nodes.Count == 0) return; if (geometryGraph.Nodes.Count == 1) { x[0] = y[0] = 0; return; } int k = Math.Min(settings.PivotNumber, geometryGraph.Nodes.Count); int iter = settings.GetNumberOfIterationsWithMajorization(geometryGraph.Nodes.Count); double exponent = settings.Exponent; var pivotArray = new int[k]; PivotDistances pivotDistances = new PivotDistances(geometryGraph, false, pivotArray); pivotDistances.Run(); double[][] c = pivotDistances.Result; MultidimensionalScaling.LandmarkClassicalScaling(c, out x, out y, pivotArray); ScaleToAverageEdgeLength(geometryGraph, x, y); if (iter > 0) { AllPairsDistances apd = new AllPairsDistances(geometryGraph, false); apd.Run(); double[][] d = apd.Result; double[][] w = MultidimensionalScaling.ExponentialWeightMatrix(d, exponent); // MultidimensionalScaling.DistanceScaling(d, x, y, w, iter); MultidimensionalScaling.DistanceScalingSubset(d, x, y, w, iter); } }