GetEdgeEndpointOnCircle ( Point oVertexALocation, Double dVertexARadius, Point oVertexBLocation, out Point oEdgeEndpoint ) { Debug.Assert(dVertexARadius >= 0); AssertValid(); Double dEdgeAngle = WpfGraphicsUtil.GetAngleBetweenPoints( oVertexALocation, oVertexBLocation); oEdgeEndpoint = new Point( oVertexALocation.X + (dVertexARadius * Math.Cos(dEdgeAngle)), oVertexALocation.Y - (dVertexARadius * Math.Sin(dEdgeAngle)) ); }
GetEdgeEndpointOnRectangle ( Point oVertexALocation, Rect oVertexARectangle, Point oVertexBLocation, out Point oEdgeEndpoint ) { AssertValid(); if (oVertexALocation == oVertexBLocation) { oEdgeEndpoint = oVertexALocation; return; } Double dVertexAX = oVertexALocation.X; Double dVertexAY = oVertexALocation.Y; Double dVertexBX = oVertexBLocation.X; Double dVertexBY = oVertexBLocation.Y; Double dHalfVertexARectangleWidth = oVertexARectangle.Width / 2.0; Double dHalfVertexARectangleHeight = oVertexARectangle.Height / 2.0; // Get the angle between vertex A and vertex B. Double dEdgeAngle = WpfGraphicsUtil.GetAngleBetweenPoints( oVertexALocation, oVertexBLocation); // Get the angle that defines the aspect ratio of vertex A's rectangle. Double dAspectAngle = Math.Atan2( dHalfVertexARectangleHeight, dHalfVertexARectangleWidth); if (dEdgeAngle >= -dAspectAngle && dEdgeAngle < dAspectAngle) { // For a square, this is -45 degrees to 45 degrees. Debug.Assert(dVertexBX != dVertexAX); oEdgeEndpoint = new Point( dVertexAX + dHalfVertexARectangleWidth, dVertexAY + dHalfVertexARectangleWidth * ((dVertexBY - dVertexAY) / (dVertexBX - dVertexAX)) ); return; } if (dEdgeAngle >= dAspectAngle && dEdgeAngle < Math.PI - dAspectAngle) { // For a square, this is 45 degrees to 135 degrees. Debug.Assert(dVertexBY != dVertexAY); oEdgeEndpoint = new Point( dVertexAX + dHalfVertexARectangleHeight * ((dVertexBX - dVertexAX) / (dVertexAY - dVertexBY)), dVertexAY - dHalfVertexARectangleHeight ); return; } if (dEdgeAngle < -dAspectAngle && dEdgeAngle >= -Math.PI + dAspectAngle) { // For a square, this is -45 degrees to -135 degrees. Debug.Assert(dVertexBY != dVertexAY); oEdgeEndpoint = new Point( dVertexAX + dHalfVertexARectangleHeight * ((dVertexBX - dVertexAX) / (dVertexBY - dVertexAY)), dVertexAY + dHalfVertexARectangleHeight ); return; } // For a square, this is 135 degrees to 180 degrees and -135 degrees to // -180 degrees. Debug.Assert(dVertexAX != dVertexBX); oEdgeEndpoint = new Point( dVertexAX - dHalfVertexARectangleWidth, dVertexAY + dHalfVertexARectangleWidth * ((dVertexBY - dVertexAY) / (dVertexAX - dVertexBX)) ); }
TryDrawEdge ( IEdge edge, GraphDrawingContext graphDrawingContext, out EdgeDrawingHistory edgeDrawingHistory ) { Debug.Assert(edge != null); Debug.Assert(graphDrawingContext != null); AssertValid(); edgeDrawingHistory = null; // If the edge is hidden, do nothing. VisibilityKeyValue eVisibility = GetVisibility(edge); if (eVisibility == VisibilityKeyValue.Hidden) { return(false); } Boolean bDrawAsSelected = GetDrawAsSelected(edge); Color oColor = GetColor(edge, eVisibility, bDrawAsSelected); Double dWidth = GetWidth(edge, bDrawAsSelected); DashStyle oDashStyle = GetDashStyle(edge, dWidth, bDrawAsSelected); Boolean bDrawArrow = (m_bDrawArrowOnDirectedEdge && edge.IsDirected); IVertex [] aoVertices = edge.Vertices; DrawingVisual oDrawingVisual = new DrawingVisual(); using (DrawingContext oDrawingContext = oDrawingVisual.RenderOpen()) { if (edge.IsSelfLoop) { if (!TryDrawSelfLoop(aoVertices[0], oDrawingContext, graphDrawingContext, oColor, dWidth, bDrawArrow)) { // The edge's vertex is hidden, so the edge should be // hidden also. return(false); } } else { Point oEdgeEndpoint1, oEdgeEndpoint2; if (!TryGetEdgeEndpoints(aoVertices[0], aoVertices[1], graphDrawingContext, out oEdgeEndpoint1, out oEdgeEndpoint2)) { // One of the edge's vertices is hidden, so the edge should // be hidden also. return(false); } if (bDrawArrow) { // Draw the arrow and set the second endpoint to the center // of the flat end of the arrow. Double dArrowAngle = WpfGraphicsUtil.GetAngleBetweenPoints( oEdgeEndpoint1, oEdgeEndpoint2); oEdgeEndpoint2 = DrawArrow(oDrawingContext, oEdgeEndpoint2, dArrowAngle, oColor, dWidth); } // Draw the edge. oDrawingContext.DrawLine(GetPen(oColor, dWidth, oDashStyle), oEdgeEndpoint1, oEdgeEndpoint2); // Draw the edge's label, if there is one. Object oLabelAsObject; if (edge.TryGetValue(ReservedMetadataKeys.PerEdgeLabel, typeof(String), out oLabelAsObject) && oLabelAsObject != null) { DrawLabel(oDrawingContext, graphDrawingContext, oEdgeEndpoint1, oEdgeEndpoint2, (String)oLabelAsObject, oColor); } } // Retain information about the edge that was drawn. edgeDrawingHistory = new EdgeDrawingHistory( edge, oDrawingVisual, bDrawAsSelected); return(true); } }
GetEdgeEndpoint ( VertexDrawingHistory otherVertexDrawingHistory, out Point edgeEndpoint ) { AssertValid(); Point oVertexLocation = this.VertexLocation; Point oOtherVertexLocation = otherVertexDrawingHistory.VertexLocation; // Instead of doing geometry calculations similar to what is done in // VertexDrawingHistory.GetEdgePointOnRectangle(), make use of that // method by making the triangle look like a rectangle. First, figure // out how to rotate the triangle about the vertex location so that the // side containing the endpoint is vertical and to the right of the // vertex location. Double dEdgeAngle = WpfGraphicsUtil.GetAngleBetweenPoints( oVertexLocation, oOtherVertexLocation); Double dEdgeAngleDegrees = MathUtil.RadiansToDegrees(dEdgeAngle); Double dAngleToRotateDegrees; if (dEdgeAngleDegrees >= -30.0 && dEdgeAngleDegrees < 90.0) { dAngleToRotateDegrees = 30.0; } else if (dEdgeAngleDegrees >= -150.0 && dEdgeAngleDegrees < -30.0) { dAngleToRotateDegrees = 270.0; } else { dAngleToRotateDegrees = 150.0; } // Now create a rotated rectangle that is centered on the vertex // location and that has the vertical, endpoint-containing triangle // side as the rectangle's right edge. Double dWidth = 2.0 * m_dHalfWidth; Rect oRotatedRectangle = new Rect( oVertexLocation.X, oVertexLocation.Y - m_dHalfWidth, dWidth * WpfGraphicsUtil.Tangent30Degrees, dWidth ); Matrix oMatrix = WpfGraphicsUtil.GetRotatedMatrix(oVertexLocation, dAngleToRotateDegrees); // Rotate the other vertex location. Point oRotatedOtherVertexLocation = oMatrix.Transform(oOtherVertexLocation); // GetEdgeEndpointOnRectangle will compute an endpoint on the // rectangle's right edge. Point oRotatedEdgeEndpoint; GetEdgeEndpointOnRectangle(oVertexLocation, oRotatedRectangle, oRotatedOtherVertexLocation, out oRotatedEdgeEndpoint); // Now rotate the edge endpoint in the other direction. oMatrix = WpfGraphicsUtil.GetRotatedMatrix(oVertexLocation, -dAngleToRotateDegrees); edgeEndpoint = oMatrix.Transform(oRotatedEdgeEndpoint); }
DrawLabel ( DrawingContext oDrawingContext, GraphDrawingContext oGraphDrawingContext, Point oEdgeEndpoint1, Point oEdgeEndpoint2, String sLabel, Color oColor ) { Debug.Assert(oDrawingContext != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(sLabel != null); AssertValid(); if (sLabel.Length == 0) { return; } sLabel = TruncateLabel(sLabel); if (oEdgeEndpoint2.X < oEdgeEndpoint1.X) { // Don't let text be drawn upside-down. Point oTemp = oEdgeEndpoint2; oEdgeEndpoint2 = oEdgeEndpoint1; oEdgeEndpoint1 = oTemp; } Double dEdgeAngleDegrees = MathUtil.RadiansToDegrees( WpfGraphicsUtil.GetAngleBetweenPoints( oEdgeEndpoint1, oEdgeEndpoint2)); Double dEdgeLength = WpfGraphicsUtil.GetDistanceBetweenPoints( oEdgeEndpoint1, oEdgeEndpoint2); // To avoid trigonometric calculations, use a RotateTransform to make // the edge look as if it is horizontal, with oEdgeEndpoint2 to the // right of oEdgeEndpoint1. RotateTransform oRotateTransform = new RotateTransform( dEdgeAngleDegrees, oEdgeEndpoint1.X, oEdgeEndpoint1.Y); oEdgeEndpoint2 = oRotateTransform.Transform(oEdgeEndpoint2); oRotateTransform.Angle = -dEdgeAngleDegrees; oDrawingContext.PushTransform(oRotateTransform); FormattedText oFormattedText = CreateFormattedText(sLabel, oColor); oFormattedText.Trimming = TextTrimming.CharacterEllipsis; if (sLabel.IndexOf('\n') == -1) { // Unless the label includes line breaks, don't allow the // FormattedText class to break the text into multiple lines. oFormattedText.MaxLineCount = 1; } Double dTextWidth = oFormattedText.Width; // The ends of the label text are between one and two "buffer units" // from the ends of the edge. The buffer unit is the width of an // arbitrary character. Double dBufferUnit = CreateFormattedText("i", oColor).Width; Double dEdgeLengthMinusBuffers = dEdgeLength - 2 * dBufferUnit; if (dEdgeLengthMinusBuffers <= 0) { return; } // Determine where to draw the label text, and where to draw a // translucent rectangle behind the text. The translucent rectangle // serves to obscure, but not completely hide, the underlying edge. Point oLabelOrigin = oEdgeEndpoint1; Rect oTranslucentRectangle; if (dTextWidth > dEdgeLengthMinusBuffers) { // The label text should start one buffer unit from the first // endpoint, and terminate with ellipses approximately one buffer // length from the second endpoint. oLabelOrigin.Offset(dBufferUnit, 0); oFormattedText.MaxTextWidth = dEdgeLengthMinusBuffers; // The translucent rectangle should be the same width as the text. oTranslucentRectangle = new Rect(oLabelOrigin, new Size(dEdgeLengthMinusBuffers, oFormattedText.Height)); } else { // The label should be centered along the edge's length. oLabelOrigin.Offset(dEdgeLength / 2.0, 0); oFormattedText.TextAlignment = TextAlignment.Center; // The translucent rectangle should extend between zero and one // buffer units beyond the ends of the text. This provides a // margin between the text and the unobscured edge, if there is // enough space. oTranslucentRectangle = new Rect(oLabelOrigin, new Size( Math.Min(dTextWidth + 2 * dBufferUnit, dEdgeLengthMinusBuffers), oFormattedText.Height) ); oTranslucentRectangle.Offset( -oTranslucentRectangle.Width / 2.0, 0); } // The text and rectangle should be vertically centered on the edge. oDrawingContext.PushTransform( new TranslateTransform(0, -oFormattedText.Height / 2.0)); // Draw the translucent rectangle, then the text. // // Note: Don't make the rectangle any more opaque than the edge, which // might be translucent itself. oDrawingContext.DrawRectangle(GetBrush( WpfGraphicsUtil.SetWpfColorAlpha(oGraphDrawingContext.BackColor, Math.Min(LabelBackgroundAlpha, oColor.A)) ), null, oTranslucentRectangle); oDrawingContext.DrawText(oFormattedText, oLabelOrigin); oDrawingContext.Pop(); oDrawingContext.Pop(); }