TransformGroupRectangles ( IGraph graph, LayoutContext originalLayoutContext, LayoutContext newLayoutContext ) { Debug.Assert(graph != null); Debug.Assert(originalLayoutContext != null); Debug.Assert(newLayoutContext != null); GroupLayoutDrawingInfo oGroupLayoutDrawingInfo; if (TryGetGroupLayoutDrawingInfo(graph, out oGroupLayoutDrawingInfo)) { // Replace the metadata value's group rectangles with a transformed // set of group rectangles. Matrix oTransformationMatrix = LayoutUtil.GetRectangleTransformation( originalLayoutContext.GraphRectangle, newLayoutContext.GraphRectangle ); foreach (GroupInfo oGroupInfo in oGroupLayoutDrawingInfo.GroupsToDraw) { oGroupInfo.Rectangle = LayoutUtil.TransformRectangle( oGroupInfo.Rectangle, oTransformationMatrix); } } }
TransformLayoutCore ( IGraph graph, LayoutContext originalLayoutContext, LayoutContext newLayoutContext ) { Debug.Assert(graph != null); Debug.Assert(originalLayoutContext != null); Debug.Assert(newLayoutContext != null); AssertValid(); Matrix oTransformationMatrix = LayoutUtil.GetRectangleTransformation( originalLayoutContext.GraphRectangle, newLayoutContext.GraphRectangle ); LayoutUtil.TransformVertexLocations(graph, oTransformationMatrix); }
SaveGraphCore ( IGraph graph, Stream stream ) { Debug.Assert(graph != null); Debug.Assert(stream != null); AssertValid(); // The Pajek format requires coordinates to be between 0 and 1.0. Get // a Matrix that will transform the vertex locations to this range. RectangleF oCurrentBoundingRectangle = LayoutUtil.GetGraphBoundingRectangle(graph); RectangleF oNewBoundingRectangle = new RectangleF(PointF.Empty, new SizeF(1.0F, 1.0F)); Matrix oRectangleTransformation = LayoutUtil.GetRectangleTransformation( oCurrentBoundingRectangle, oNewBoundingRectangle ); // Create a dictionary to keep track of vertices. The keys are vertex // IDs and the values are the one-based vertex numbers used by the // Pajek format. Dictionary <Int32, Int32> oVertexIDToNumber = new Dictionary <Int32, Int32>(); IVertexCollection oVertices = graph.Vertices; StreamWriter oStreamWriter = new StreamWriter(stream, StreamEncoding); // Add the *vertices section. oStreamWriter.WriteLine( "*vertices {0}" , oVertices.Count ); Int32 iVertexNumber = 1; foreach (IVertex oVertex in oVertices) { // Format: // // 1 "vertex 1 name" x y z // Transform the vertex location. PointF oTransformedLocation = LayoutUtil.TransformPointF( oVertex.Location, oRectangleTransformation); // Limit the range in case of rounding errors. Single fX = Math.Max(0F, oTransformedLocation.X); fX = Math.Min(1F, fX); Single fY = Math.Max(0F, oTransformedLocation.Y); fY = Math.Min(1F, fY); oStreamWriter.WriteLine( "{0} \"{1}\" {2:N6} {3:N6} 0" , iVertexNumber, oVertex.Name, fX, fY ); oVertexIDToNumber.Add(oVertex.ID, iVertexNumber); iVertexNumber++; } IEdgeCollection oEdges = graph.Edges; GraphDirectedness eDirectedness = graph.Directedness; Boolean bSectionNameWritten = false; if (eDirectedness != GraphDirectedness.Directed) { // If appropriate, add the *edges section, which specifies // undirected edges. foreach (IEdge oEdge in oEdges) { // The graph could be mixed. if (oEdge.IsDirected) { continue; } if (!bSectionNameWritten) { oStreamWriter.WriteLine("*edges"); bSectionNameWritten = true; } WriteEdge(oEdge, oVertexIDToNumber, oStreamWriter); } } bSectionNameWritten = false; if (eDirectedness != GraphDirectedness.Undirected) { // If appropriate, add the *arcs section, which specifies // directed edges. foreach (IEdge oEdge in oEdges) { // The graph could be mixed. if (!oEdge.IsDirected) { continue; } if (!bSectionNameWritten) { oStreamWriter.WriteLine("*arcs"); bSectionNameWritten = true; } WriteEdge(oEdge, oVertexIDToNumber, oStreamWriter); } } oStreamWriter.Flush(); }
SetUnboundedLocations ( ICollection <IVertex> verticesToLayOut, LayoutContext layoutContext, Single fTemperature, Boolean bAlsoSetVertexLocations ) { Debug.Assert(verticesToLayOut != null); Debug.Assert(layoutContext != null); Debug.Assert(fTemperature > 0); AssertValid(); // The following variables define the unbounded rectangle. TMathType tMinLocationX = Single.MaxValue; TMathType tMaxLocationX = Single.MinValue; TMathType tMinLocationY = Single.MaxValue; TMathType tMaxLocationY = Single.MinValue; foreach (IVertex oVertex in verticesToLayOut) { // Retrieve the object that stores calculated values for the // vertex. We need the vertex's current unbounded location and // the displacement created by the repulsive and attractive forces // on the vertex. FruchtermanReingoldVertexInfo oVertexInfo = (FruchtermanReingoldVertexInfo)oVertex.Tag; TMathType tUnboundedLocationX = (TMathType)oVertexInfo.UnboundedLocationX; TMathType tUnboundedLocationY = (TMathType)oVertexInfo.UnboundedLocationY; TMathType tDisplacementX = (TMathType)oVertexInfo.DisplacementX; TMathType tDisplacementY = (TMathType)oVertexInfo.DisplacementY; TMathType tDisplacement = (TMathType)Math.Sqrt( (tDisplacementX * tDisplacementX) + (tDisplacementY * tDisplacementY) ); if (tDisplacement != 0) { // Calculate a new unbounded location, limited by the current // temperature. tUnboundedLocationX += (tDisplacementX / tDisplacement) * Math.Min(tDisplacement, (TMathType)fTemperature); tUnboundedLocationY += (tDisplacementY / tDisplacement) * Math.Min(tDisplacement, (TMathType)fTemperature); } // Update the vertex's unbounded location. oVertexInfo.UnboundedLocationX = (Single)tUnboundedLocationX; oVertexInfo.UnboundedLocationY = (Single)tUnboundedLocationY; // Expand the unbounded rectangle if necessary. tMinLocationX = Math.Min(tUnboundedLocationX, tMinLocationX); tMaxLocationX = Math.Max(tUnboundedLocationX, tMaxLocationX); tMinLocationY = Math.Min(tUnboundedLocationY, tMinLocationY); tMaxLocationY = Math.Max(tUnboundedLocationY, tMaxLocationY); } if (!bAlsoSetVertexLocations) { return; } Debug.Assert(verticesToLayOut.Count != 0); Debug.Assert(tMinLocationX != Single.MaxValue); Debug.Assert(tMaxLocationX != Single.MinValue); Debug.Assert(tMinLocationY != Single.MaxValue); Debug.Assert(tMaxLocationY != Single.MinValue); // Get a Matrix that will transform vertex locations from coordinates // in the unbounded rectangle to cooordinates in the bounded graph // rectangle. Matrix oTransformationMatrix = LayoutUtil.GetRectangleTransformation( RectangleF.FromLTRB( (Single)tMinLocationX, (Single)tMinLocationY, (Single)tMaxLocationX, (Single)tMaxLocationY ), layoutContext.GraphRectangle ); // Transform the vertex locations. foreach (IVertex oVertex in verticesToLayOut) { FruchtermanReingoldVertexInfo oVertexInfo = (FruchtermanReingoldVertexInfo)oVertex.Tag; PointF [] aoLocation = new PointF [] { new PointF( oVertexInfo.UnboundedLocationX, oVertexInfo.UnboundedLocationY ) }; oTransformationMatrix.TransformPoints(aoLocation); if (!VertexIsLocked(oVertex)) { oVertex.Location = aoLocation[0]; } } }
TransformLayoutCore ( IGraph graph, LayoutContext originalLayoutContext, LayoutContext newLayoutContext ) { Debug.Assert(graph != null); Debug.Assert(originalLayoutContext != null); Debug.Assert(newLayoutContext != null); AssertValid(); // Transform the graph's vertex locations. Matrix oTransformationMatrix = LayoutUtil.GetRectangleTransformation( originalLayoutContext.GraphRectangle, newLayoutContext.GraphRectangle ); base.TransformLayoutCore(graph, originalLayoutContext, newLayoutContext); // Tranform the geometry metadata added by LayOutGraphCore(). Object oValue; if ( graph.TryGetValue( ReservedMetadataKeys.SugiyamaComputedRadius, typeof(Single), out oValue) ) { // Transforming the radius in the x-direction only isn't ideal, but // doing the transform properly would involve drawing the vertex as // an ellipse. PointF oTransformedRadius = LayoutUtil.TransformPointF( new PointF( (Single)oValue, 0 ), oTransformationMatrix ); graph.SetValue( ReservedMetadataKeys.SugiyamaComputedRadius, oTransformedRadius.X ); } foreach (IEdge oEdge in graph.Edges) { if ( !oEdge.TryGetValue( ReservedMetadataKeys.SugiyamaCurvePoints, typeof( PointF [] ), out oValue ) ) { continue; } PointF [] aoCurvePoints = ( PointF [] )oValue; oTransformationMatrix.TransformPoints(aoCurvePoints); oEdge.SetValue(ReservedMetadataKeys.SugiyamaCurvePoints, aoCurvePoints); PointF oEndpoint = (PointF)oEdge.GetRequiredValue( ReservedMetadataKeys.SugiyamaEndpoint, typeof(PointF) ); oEdge.SetValue( ReservedMetadataKeys.SugiyamaEndpoint, LayoutUtil.TransformPointF(oEndpoint, oTransformationMatrix) ); } }