Exemple #1
0
        GetColor
        (
            IMetadataProvider oVertexOrEdge,
            VisibilityKeyValue eVisibility,
            Boolean bDrawAsSelected
        )
        {
            Debug.Assert(oVertexOrEdge != null);
            AssertValid();

            if (bDrawAsSelected)
            {
                Color oColor = m_oSelectedColor;

                if (eVisibility == VisibilityKeyValue.Filtered)
                {
                    oColor.A = m_btFilteredAlpha;
                }

                return(oColor);
            }

            return(GetColor(oVertexOrEdge, eVisibility,
                            ReservedMetadataKeys.PerColor, m_oColor, true));
        }
Exemple #2
0
        GetAlpha
        (
            IMetadataProvider oVertexOrEdge,
            VisibilityKeyValue eVisibility,
            Byte btDefaultAlpha
        )
        {
            Debug.Assert(oVertexOrEdge != null);
            AssertValid();

            if (eVisibility == VisibilityKeyValue.Filtered)
            {
                // The vertex or edge is filtered.

                return(m_btFilteredAlpha);
            }

            // Check for a per-vertex or per-edge alpha.

            Object oPerAlphaAsObject;

            if (oVertexOrEdge.TryGetValue(ReservedMetadataKeys.PerAlpha,
                                          typeof(Single), out oPerAlphaAsObject))
            {
                Single fPerAlpha = (Single)oPerAlphaAsObject;

                if (fPerAlpha < 0F || fPerAlpha > 255F)
                {
                    Debug.Assert(oVertexOrEdge is IIdentityProvider);

                    throw new FormatException(String.Format(

                                                  "{0}: The {1} with the ID {2} has an out-of-range"
                                                  + " {3} value.  Valid values are between 0 and 255."
                                                  ,
                                                  this.ClassName,
                                                  (oVertexOrEdge is IVertex) ? "vertex" : "edge",
                                                  ((IIdentityProvider)oVertexOrEdge).ID,
                                                  "ReservedMetadataKeys.PerAlpha"
                                                  ));
                }

                return((Byte)fPerAlpha);
            }

            return(btDefaultAlpha);
        }
Exemple #3
0
        GetColor
        (
            IMetadataProvider oVertexOrEdge,
            VisibilityKeyValue eVisibility,
            Boolean bDrawAsSelected
        )
        {
            Debug.Assert(oVertexOrEdge != null);
            AssertValid();

            if (bDrawAsSelected)
            {
                return(m_oSelectedColor);
            }

            return(GetColor(oVertexOrEdge, eVisibility,
                            ReservedMetadataKeys.PerColor, m_oColor, true));
        }
Exemple #4
0
        GetColor
        (
            IMetadataProvider oVertexOrEdge,
            VisibilityKeyValue eVisibility,
            String sKey,
            Color oDefaultColor,
            Boolean bApplyAlpha
        )
        {
            Debug.Assert(oVertexOrEdge != null);
            Debug.Assert(!String.IsNullOrEmpty(sKey));
            AssertValid();

            Byte btDefaultAlpha = oDefaultColor.A;

            // Start with the default color.

            Color oColor = oDefaultColor;

            // Check for a per-vertex or per-edge color.

            Color oPerColor;

            if (TryGetColorValue(oVertexOrEdge, sKey, out oPerColor))
            {
                oColor   = oPerColor;
                oColor.A = btDefaultAlpha;
            }

            if (bApplyAlpha)
            {
                // Apply the vertex or edge's alpha.

                oColor.A = GetAlpha(oVertexOrEdge, eVisibility, oColor.A);
            }

            return(oColor);
        }
Exemple #5
0
        TryGetEdgeVisibility
        (
            IEdge oEdge,
            String sKey,
            out VisibilityKeyValue eVisibility
        )
        {
            Debug.Assert(oEdge != null);
            Debug.Assert(!String.IsNullOrEmpty(sKey));

            eVisibility = VisibilityKeyValue.Visible;

            Object oVisibilityAsObject;

            if (oEdge.TryGetValue(sKey, typeof(VisibilityKeyValue),
                                  out oVisibilityAsObject))
            {
                eVisibility = (VisibilityKeyValue)oVisibilityAsObject;
                return(true);
            }

            return(false);
        }
    TryGetEdgeVisibility
    (
        IEdge oEdge,
        String sKey,
        out VisibilityKeyValue eVisibility
    )
    {
        Debug.Assert(oEdge != null);
        Debug.Assert( !String.IsNullOrEmpty(sKey) );

        eVisibility = VisibilityKeyValue.Visible;

        Object oVisibilityAsObject;

        if ( oEdge.TryGetValue(sKey, typeof(VisibilityKeyValue),
            out oVisibilityAsObject) )
        {
            eVisibility = (VisibilityKeyValue)oVisibilityAsObject;
            return (true);
        }

        return (false);
    }
Exemple #7
0
        //*************************************************************************
        //  Method: DrawLabelShape()
        //
        /// <summary>
        /// Draws a vertex as a label.
        /// </summary>
        ///
        /// <param name="oVertex">
        /// The vertex to draw.
        /// </param>
        ///
        /// <param name="oGraphDrawingContext">
        /// Provides access to objects needed for graph-drawing operations.
        /// </param>
        ///
        /// <param name="oDrawingContext">
        /// The DrawingContext to use.
        /// </param>
        ///
        /// <param name="oDrawingVisual">
        /// The <see cref="DrawingVisual" /> object from which <paramref
        /// name="oDrawingContext" /> was obtained.
        /// </param>
        ///
        /// <param name="eVisibility">
        /// The visibility of the vertex.
        /// </param>
        ///
        /// <param name="bDrawAsSelected">
        /// true to draw the vertex as selected.
        /// </param>
        ///
        /// <param name="sLabel">
        /// The label to draw.  Can't be null or empty.
        /// </param>
        ///
        /// <returns>
        /// A VertexDrawingHistory object that retains information about how the
        /// vertex was drawn.
        /// </returns>
        //*************************************************************************
        protected VertexDrawingHistory DrawLabelShape(
            IVertex oVertex,
            GraphDrawingContext oGraphDrawingContext,
            DrawingContext oDrawingContext,
            DrawingVisual oDrawingVisual,
            VisibilityKeyValue eVisibility,
            Boolean bDrawAsSelected,
            String sLabel
            )
        {
            Debug.Assert(oVertex != null);
            Debug.Assert(oGraphDrawingContext != null);
            Debug.Assert(oDrawingContext != null);
            Debug.Assert(oDrawingVisual != null);
            Debug.Assert( !String.IsNullOrEmpty(sLabel) );
            AssertValid();

            // Figure out what colors to use.

            Color oOutlineColor;

            Color oTextColor = GetColor(oVertex, eVisibility, false);

            Color oFillColor = GetColor(oVertex, eVisibility,
            ReservedMetadataKeys.PerVertexLabelFillColor, m_oLabelFillColor,
            true);

            if (bDrawAsSelected)
            {
            // The outline color is always the selected color.

            oOutlineColor = m_oSelectedColor;

            // The text color is the default or per-vertex color with no alpha.

            oTextColor.A = 255;

            // The fill color is the default or per-vertex fill color with no
            // alpha.

            oFillColor.A = 255;
            }
            else
            {
            // The outline color is the default or per-vertex color with alpha.

            oOutlineColor = oTextColor;

            // The text color is the default or per-vertex color with alpha.

            // The fill color is the default or per-vertex fill color with
            // alpha.
            }

            Double dLabelFontSize = GetLabelFontSize(oVertex);

            // Format the text, subject to a maximum label size.  If a maximum
            // label size isn't specified, the label would be as wide as necessary
            // to accommodate the text length.  Specifying a maximum size forces
            // the text to wrap at word breaks.
            //
            // Side effect: If the font size is large enough, not a single
            // character of the text will fit within the specified width and no
            // text will be drawn.

            FormattedText oFormattedText = CreateFormattedText(sLabel, oTextColor,
            dLabelFontSize);

            oFormattedText.MaxTextWidth = MaximumLabelWidth * m_dGraphScale;
            oFormattedText.MaxTextHeight = MaximumLabelHeight * m_dGraphScale;

            Rect oVertexRectangle = GetVertexRectangle(
            GetVertexLocation(oVertex), oFormattedText.Width,
            oFormattedText.Height);

            // Pad the text.

            Rect oVertexRectangleWithPadding = oVertexRectangle;
            Double dLabelPadding = GetLabelPadding(dLabelFontSize);

            oVertexRectangleWithPadding.Inflate(dLabelPadding,
            dLabelPadding * 0.7);

            if (m_oTypeface.Style != FontStyles.Normal)
            {
            // This is a hack to move the right edge of the padded rectangle
            // to the right to adjust for wider italic text, which
            // FormattedText.Width does not account for.  What is the correct
            // way to do this?  It might involve the FormattedText.Overhang*
            // properties, but I'll be darned if I can understand how those
            // properties work.

            Double dItalicCompensation = dLabelFontSize / 7.0;
            oVertexRectangleWithPadding.Inflate(dItalicCompensation, 0);
            oVertexRectangleWithPadding.Offset(dItalicCompensation, 0);
            }

            // Move the vertex if it falls outside the graph rectangle.

            Double dOriginalVertexRectangleWithPaddingX =
            oVertexRectangleWithPadding.X;

            Double dOriginalVertexRectangleWithPaddingY =
            oVertexRectangleWithPadding.Y;

            MoveVertexIfNecessary(oVertex, ref oVertexRectangleWithPadding,
            oGraphDrawingContext);

            oVertexRectangle.Offset(

            oVertexRectangleWithPadding.X -
                dOriginalVertexRectangleWithPaddingX,

            oVertexRectangleWithPadding.Y -
                dOriginalVertexRectangleWithPaddingY
            );

            // Draw the padded rectangle, then the text.

            oDrawingContext.DrawRectangle( GetBrush(oFillColor),
            GetPen(oOutlineColor, DefaultPenThickness),
            oVertexRectangleWithPadding);

            oDrawingContext.DrawText(oFormattedText, oVertexRectangle.Location);

            // Return information about how the vertex was drawn.

            return ( new LabelVertexDrawingHistory(oVertex, oDrawingVisual,
            bDrawAsSelected, oVertexRectangleWithPadding) );
        }
    DrawSimpleShape
    (
        IVertex oVertex,
        VertexShape eShape,
        GraphDrawingContext oGraphDrawingContext,
        DrawingContext oDrawingContext,
        DrawingVisualPlus oDrawingVisual,
        VisibilityKeyValue eVisibility,
        Boolean bDrawAsSelected,
        String sAnnotation,
        VertexLabelDrawer oVertexLabelDrawer,
        CollapsedGroupDrawingManager oCollapsedGroupDrawingManager
    )
    {
        Debug.Assert(oVertex != null);
        Debug.Assert(oGraphDrawingContext != null);
        Debug.Assert(oDrawingContext != null);
        Debug.Assert(oDrawingVisual != null);
        Debug.Assert(oVertexLabelDrawer != null);
        Debug.Assert(oCollapsedGroupDrawingManager != null);
        AssertValid();

        Double dRadius = GetRadius(oVertex);
        Color oColor = GetColor(oVertex, eVisibility, bDrawAsSelected);
        Point oVertexLocation = GetVertexLocation(oVertex);

        oDrawingVisual.SetEffect( GetSimpleShapeEffect(
            oGraphDrawingContext, dRadius, oColor) );

        Rect oVertexBounds;

        if (eShape == VertexShape.Triangle ||
            eShape == VertexShape.SolidTriangle)
        {
            oVertexBounds =
                WpfGraphicsUtil.TriangleBoundsFromCenterAndHalfWidth(
                    oVertexLocation, dRadius);
        }
        else if (eShape == VertexShape.SolidTaperedDiamond)
        {
            // Note that the bounds of a tapered diamond can't be calculated
            // using simple equations.  Instead, create the tapered diamond and
            // let WPF compute the bounds.
            //
            // There is some inefficiency here, because the tapered diamond
            // gets created again before it is drawn, in its possibly-moved
            // location.

            oVertexBounds = WpfPathGeometryUtil.GetTaperedDiamond(
                oVertexLocation, dRadius).Bounds;
        }
        else if (eShape == VertexShape.SolidRoundedX)
        {
            // Note that the bounds of a rounded X can't be calculated
            // using simple equations.  Instead, create the rounded X and
            // let WPF compute the bounds.
            //
            // There is some inefficiency here, because the rounded X
            // gets created again before it is drawn, in its possibly-moved
            // location.

            oVertexBounds = WpfPathGeometryUtil.GetRoundedX(
                oVertexLocation, dRadius).Bounds;
        }
        else
        {
            oVertexBounds = WpfGraphicsUtil.SquareFromCenterAndHalfWidth(
                oVertexLocation, dRadius);
        }

        // Move the vertex if it falls outside the graph rectangle.

        MoveVertexIfNecessary(oVertex, oGraphDrawingContext,
            oCollapsedGroupDrawingManager, ref oVertexBounds);

        oVertexLocation = GetVertexLocation(oVertex);
        VertexDrawingHistory oVertexDrawingHistory = null;

        // Note that for the "hollow" shapes -- Circle, Square, Diamond, and
        // Triangle -- Brushes.Transparent is used instead of a null brush.
        // This allows the entire area of these shapes to be hit-tested.  Using
        // a null brush would cause hit-testing to fail if the shapes'
        // interiors were clicked.

        switch (eShape)
        {
            case VertexShape.Circle:
            case VertexShape.Disk:

                Boolean bIsDisk = (eShape == VertexShape.Disk);

                oDrawingContext.DrawEllipse(
                    bIsDisk ? GetBrush(oColor) : Brushes.Transparent,
                    bIsDisk ? null : GetPen(oColor, DefaultPenThickness),
                    oVertexLocation, dRadius, dRadius
                    );

                oVertexDrawingHistory = bIsDisk ?

                    new DiskVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius)
                    :
                    new CircleVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius);

                break;

            case VertexShape.Sphere:

                RadialGradientBrush oRadialGradientBrush =
                    new RadialGradientBrush();

                oRadialGradientBrush.GradientOrigin =
                    oRadialGradientBrush.Center = new Point(0.3, 0.3);

                GradientStopCollection oGradientStops =
                    oRadialGradientBrush.GradientStops;

                oGradientStops.Add( new GradientStop(
                    WpfGraphicsUtil.SetWpfColorAlpha(Colors.White, oColor.A),
                    0.0) );

                oGradientStops.Add( new GradientStop(oColor, 1.0) );

                WpfGraphicsUtil.FreezeIfFreezable(oRadialGradientBrush);

                oDrawingContext.DrawEllipse(oRadialGradientBrush, null,
                    oVertexLocation, dRadius, dRadius);

                oVertexDrawingHistory = new SphereVertexDrawingHistory(
                    oVertex, oDrawingVisual, bDrawAsSelected, dRadius);

                break;

            case VertexShape.Square:

                WpfGraphicsUtil.DrawPixelAlignedRectangle(oDrawingContext,
                    Brushes.Transparent, GetPen(oColor, DefaultPenThickness),
                    oVertexBounds);

                oVertexDrawingHistory = new SquareVertexDrawingHistory(oVertex,
                    oDrawingVisual, bDrawAsSelected, oVertexBounds);

                break;

            case VertexShape.SolidSquare:

                oDrawingContext.DrawRectangle(GetBrush(oColor), null,
                    oVertexBounds);

                oVertexDrawingHistory = new SolidSquareVertexDrawingHistory(
                    oVertex, oDrawingVisual, bDrawAsSelected, oVertexBounds);

                break;

            case VertexShape.Diamond:
            case VertexShape.SolidDiamond:

                Boolean bIsSolidDiamond = (eShape == VertexShape.SolidDiamond);

                PathGeometry oDiamond =
                    WpfPathGeometryUtil.GetDiamond(oVertexLocation, dRadius);

                oDrawingContext.DrawGeometry(

                    bIsSolidDiamond ? GetBrush(oColor) : Brushes.Transparent,

                    bIsSolidDiamond ? null :
                        GetPen(oColor, DefaultPenThickness),

                    oDiamond
                    );

                oVertexDrawingHistory = bIsSolidDiamond ?

                    new SolidDiamondVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius)
                    :
                    new DiamondVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius);

                break;

            case VertexShape.Triangle:
            case VertexShape.SolidTriangle:

                Boolean bIsSolidTriangle =
                    (eShape == VertexShape.SolidTriangle);

                PathGeometry oTriangle =
                    WpfPathGeometryUtil.GetTriangle(oVertexLocation, dRadius);

                oDrawingContext.DrawGeometry(

                    bIsSolidTriangle ? GetBrush(oColor) : Brushes.Transparent,

                    bIsSolidTriangle ? null :
                        GetPen(oColor, DefaultPenThickness),

                    oTriangle
                    );

                oVertexDrawingHistory = bIsSolidTriangle ?

                    new SolidTriangleVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius)
                    :
                    new TriangleVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius);

                break;

            case VertexShape.SolidTaperedDiamond:

                Geometry oTaperedDiamond =
                    WpfPathGeometryUtil.GetTaperedDiamond(
                        oVertexLocation, dRadius);

                // Note that as of August 2012, the tapered diamond shape is
                // used only for collapsed connector motifs.  Collapsed motifs
                // have an outline, so draw an outline here.

                oDrawingContext.DrawGeometry(GetBrush(oColor),

                    GetPen( CollapsedGroupDrawingManager
                        .GetCollapsedMotifOutlineColor(oColor.A),
                        DefaultPenThickness),

                    oTaperedDiamond);

                oVertexDrawingHistory =
                    new SolidTaperedDiamondVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius);

                break;

            case VertexShape.SolidRoundedX:

                Geometry oRoundedX =
                    WpfPathGeometryUtil.GetRoundedX(
                        oVertexLocation, dRadius);

                // Note that as of August 2012, the rounded X shape is
                // used only for collapsed clique motifs.  Collapsed motifs
                // have an outline, so draw an outline here.

                oDrawingContext.DrawGeometry(GetBrush(oColor),

                    GetPen(CollapsedGroupDrawingManager
                        .GetCollapsedMotifOutlineColor(oColor.A),
                        DefaultPenThickness),

                    oRoundedX);

                oVertexDrawingHistory =
                    new SolidRoundedXVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius);

                break;

            default:

                Debug.Assert(false);
                break;
        }

        if (sAnnotation != null)
        {
            oVertexLabelDrawer.DrawLabel(oDrawingContext,
                oGraphDrawingContext, oVertexDrawingHistory,

                CreateFormattedTextWithWrap(sAnnotation, oColor,
                    m_oFormattedTextManager.FontSize),

                oColor);
        }

        Debug.Assert(oVertexDrawingHistory != null);

        return (oVertexDrawingHistory);
    }
    DrawStraightEdge
    (
        IEdge oEdge,
        GraphDrawingContext oGraphDrawingContext,
        DrawingContext oDrawingContext,
        Point oEdgeEndpoint1,
        Point oEdgeEndpoint2,
        Boolean bDrawAsSelected,
        Boolean bDrawArrow,
        Pen oPen,
        Color oColor,
        Double dWidth,
        VisibilityKeyValue eVisibility,
        String sLabel
    )
    {
        Debug.Assert(oEdge != null);
        Debug.Assert(oGraphDrawingContext != null);
        Debug.Assert(oDrawingContext != null);
        Debug.Assert(oPen != null);
        AssertValid();

        if (bDrawArrow)
        {
            // Draw the arrow and set the second endpoint to the center of the
            // flat end of the arrow.

            Double dArrowAngle = WpfGraphicsUtil.GetAngleBetweenPointsRadians(
                oEdgeEndpoint1, oEdgeEndpoint2);

            oEdgeEndpoint2 = DrawArrow(oDrawingContext, oEdgeEndpoint2,
                dArrowAngle, oColor, dWidth);
        }

        oDrawingContext.DrawLine(oPen, oEdgeEndpoint1, oEdgeEndpoint2);

        if ( !String.IsNullOrEmpty(sLabel) )
        {
            DrawLabel(oEdge, oDrawingContext, oGraphDrawingContext,
                bDrawAsSelected, oColor, eVisibility, oEdgeEndpoint1,
                oEdgeEndpoint2, null, new Point(), sLabel);
        }
    }
    GetColor
    (
        IMetadataProvider oVertexOrEdge,
        VisibilityKeyValue eVisibility,
        String sKey,
        Color oDefaultColor,
        Boolean bApplyAlpha
    )
    {
        Debug.Assert(oVertexOrEdge != null);
        Debug.Assert( !String.IsNullOrEmpty(sKey) );
        AssertValid();

        Byte btDefaultAlpha = oDefaultColor.A;

        // Start with the default color.

        Color oColor = oDefaultColor;

        // Check for a per-vertex or per-edge color.

        Color oPerColor;

        if ( TryGetColorValue(oVertexOrEdge, sKey, out oPerColor) )
        {
            oColor = oPerColor;
            oColor.A = btDefaultAlpha;
        }

        if (bApplyAlpha)
        {
            // Apply the vertex or edge's alpha.

            oColor.A = GetAlpha(oVertexOrEdge, eVisibility, oColor.A);
        }

        return (oColor);
    }
    GetAlpha
    (
        IMetadataProvider oVertexOrEdge,
        VisibilityKeyValue eVisibility,
        Byte btDefaultAlpha
    )
    {
        Debug.Assert(oVertexOrEdge != null);
        AssertValid();

        if (eVisibility == VisibilityKeyValue.Filtered)
        {
            // The vertex or edge is filtered.

            return (m_btFilteredAlpha);
        }

        // Check for a per-vertex or per-edge alpha.

        Object oPerAlphaAsObject;

        if ( oVertexOrEdge.TryGetValue(ReservedMetadataKeys.PerAlpha,
            typeof(Single), out oPerAlphaAsObject) )
        {
            Single fPerAlpha = (Single)oPerAlphaAsObject;

            if (fPerAlpha < 0F || fPerAlpha > 255F)
            {
                Debug.Assert(oVertexOrEdge is IIdentityProvider);

                throw new FormatException( String.Format(

                    "{0}: The {1} with the ID {2} has an out-of-range"
                    + " {3} value.  Valid values are between 0 and 255."
                    ,
                    this.ClassName,
                    (oVertexOrEdge is IVertex) ? "vertex" : "edge",
                    ( (IIdentityProvider)oVertexOrEdge ).ID,
                    "ReservedMetadataKeys.PerAlpha"
                    ) );
            }

            return ( (Byte)fPerAlpha );
        }

        return (btDefaultAlpha);
    }
    GetColor
    (
        IMetadataProvider oVertexOrEdge,
        VisibilityKeyValue eVisibility,
        Boolean bDrawAsSelected
    )
    {
        Debug.Assert(oVertexOrEdge != null);
        AssertValid();

        if (bDrawAsSelected)
        {
            Color oColor = m_oSelectedColor;

            if (eVisibility == VisibilityKeyValue.Filtered)
            {
                oColor.A = m_btFilteredAlpha;
            }

            return (oColor);
        }

        return ( GetColor(oVertexOrEdge, eVisibility,
            ReservedMetadataKeys.PerColor, m_oColor, true) );
    }
        //*************************************************************************
        //  Method: GetColor()
        //
        /// <overloads>
        /// Gets the color of a vertex or edge.
        /// </overloads>
        ///
        /// <summary>
        /// Gets the color of a vertex or edge.
        /// </summary>
        ///
        /// <param name="oVertexOrEdge">
        /// The vertex or edge to get the color for.
        /// </param>
        ///
        /// <param name="eVisibility">
        /// The visibility of the vertex or edge.  This can be obtained with <see
        /// cref="GetVisibility" />.
        /// </param>
        ///
        /// <param name="bDrawAsSelected">
        /// true if <paramref name="oVertexOrEdge" /> should be drawn as selected.
        /// </param>
        ///
        /// <returns>
        /// The color of the vertex or edge.  This includes any per-vertex or
        /// per-edge alpha value specified on the vertex or edge, along with the
        /// visibility specified by <paramref name="eVisibility" />.
        /// </returns>
        //*************************************************************************
        protected Color GetColor(
            IMetadataProvider oVertexOrEdge,
            VisibilityKeyValue eVisibility,
            Boolean bDrawAsSelected
            )
        {
            Debug.Assert(oVertexOrEdge != null);
            AssertValid();

            if (bDrawAsSelected)
            {
            return (m_oSelectedColor);
            }

            return ( GetColor(oVertexOrEdge, eVisibility,
            ReservedMetadataKeys.PerColor, m_oColor, true) );
        }
Exemple #14
0
        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);
            }
        }
    GetLabelTextColor
    (
        IEdge oEdge,
        Boolean bDrawAsSelected,
        Color oEdgeColor,
        VisibilityKeyValue eVisibility
    )
    {
        Debug.Assert(oEdge != null);
        AssertValid();

        Color oLabelTextColor;

        if (bDrawAsSelected)
        {
            // The edge color was calculated using the selected state.

            oLabelTextColor = oEdgeColor;
        }
        else
        {
            oLabelTextColor = GetColor(oEdge, eVisibility,
                ReservedMetadataKeys.PerEdgeLabelTextColor, m_oLabelTextColor,
                false);

            oLabelTextColor = WpfGraphicsUtil.SetWpfColorAlpha(oLabelTextColor,
                oEdgeColor.A);
        }

        return (oLabelTextColor);
    }
Exemple #16
0
        //*************************************************************************
        //  Method: DrawSimpleShape()
        //
        /// <summary>
        /// Draws a vertex as a simple shape.
        /// </summary>
        ///
        /// <param name="oVertex">
        /// The vertex to draw.
        /// </param>
        ///
        /// <param name="eShape">
        /// The vertex shape to use.  Can't be <see cref="VertexShape.Image" /> or
        /// <see cref="VertexShape.Label" />.
        /// </param>
        ///
        /// <param name="oGraphDrawingContext">
        /// Provides access to objects needed for graph-drawing operations.
        /// </param>
        ///
        /// <param name="oDrawingContext">
        /// The DrawingContext to use.
        /// </param>
        ///
        /// <param name="oDrawingVisual">
        /// The <see cref="DrawingVisual" /> object from which <paramref
        /// name="oDrawingContext" /> was obtained.
        /// </param>
        ///
        /// <param name="eVisibility">
        /// The visibility of the vertex.
        /// </param>
        ///
        /// <param name="bDrawAsSelected">
        /// true to draw the vertex as selected.
        /// </param>
        ///
        /// <param name="sAnnotation">
        /// The annotation to draw next to the shape, or null if there is no
        /// annotation.
        /// </param>
        ///
        /// <param name="oVertexLabelDrawer">
        /// Object that draws a vertex label as an annotation.
        /// </param>
        ///
        /// <returns>
        /// A VertexDrawingHistory object that retains information about how the
        /// vertex was drawn.
        /// </returns>
        ///
        /// <remarks>
        /// "Simple" means "not <see cref="VertexShape.Image" /> and not <see
        /// cref="VertexShape.Label" />."
        /// </remarks>
        //*************************************************************************
        protected VertexDrawingHistory DrawSimpleShape(
            IVertex oVertex,
            VertexShape eShape,
            GraphDrawingContext oGraphDrawingContext,
            DrawingContext oDrawingContext,
            DrawingVisual oDrawingVisual,
            VisibilityKeyValue eVisibility,
            Boolean bDrawAsSelected,
            String sAnnotation,
            VertexLabelDrawer oVertexLabelDrawer
            )
        {
            Debug.Assert(oVertex != null);
            Debug.Assert(oGraphDrawingContext != null);
            Debug.Assert(oDrawingContext != null);
            Debug.Assert(oDrawingVisual != null);
            Debug.Assert(oVertexLabelDrawer != null);
            AssertValid();

            Double dRadius = GetRadius(oVertex);
            Color oColor = GetColor(oVertex, eVisibility, bDrawAsSelected);
            Point oVertexLocation = GetVertexLocation(oVertex);

            Rect oVertexBounds;

            if (eShape == VertexShape.Triangle ||
            eShape == VertexShape.SolidTriangle)
            {
            oVertexBounds =
                WpfGraphicsUtil.TriangleBoundsFromCenterAndHalfWidth(
                    oVertexLocation, dRadius);
            }
            else
            {
            oVertexBounds = WpfGraphicsUtil.SquareFromCenterAndHalfWidth(
                oVertexLocation, dRadius);
            }

            // Move the vertex if it falls outside the graph rectangle.

            MoveVertexIfNecessary(oVertex, ref oVertexBounds,
            oGraphDrawingContext);

            Point oLocation = GetVertexLocation(oVertex);
            VertexDrawingHistory oVertexDrawingHistory = null;

            // Note that for the "hollow" shapes -- Circle, Square, Diamond, and
            // Triangle -- Brushes.Transparent is used instead of a null brush.
            // This allows the entire area of these shapes to be hit-tested.  Using
            // a null brush would cause hit-testing to fail if the shapes'
            // interiors were clicked.

            switch (eShape)
            {
            case VertexShape.Circle:
            case VertexShape.Disk:

                Boolean bIsDisk = (eShape == VertexShape.Disk);

                oDrawingContext.DrawEllipse(
                    bIsDisk ? GetBrush(oColor) : Brushes.Transparent,
                    bIsDisk ? null : GetPen(oColor, DefaultPenThickness),
                    oLocation, dRadius, dRadius
                    );

                oVertexDrawingHistory = bIsDisk ?

                    new DiskVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius)
                    :
                    new CircleVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius);

                break;

            case VertexShape.Sphere:

                RadialGradientBrush oRadialGradientBrush =
                    new RadialGradientBrush();

                oRadialGradientBrush.GradientOrigin =
                    oRadialGradientBrush.Center = new Point(0.3, 0.3);

                GradientStopCollection oGradientStops =
                    oRadialGradientBrush.GradientStops;

                oGradientStops.Add( new GradientStop(Colors.White, 0.0) );
                oGradientStops.Add( new GradientStop(oColor, 1.0) );

                WpfGraphicsUtil.FreezeIfFreezable(oRadialGradientBrush);

                oDrawingContext.DrawEllipse(oRadialGradientBrush, null,
                    oLocation, dRadius, dRadius);

                oVertexDrawingHistory = new SphereVertexDrawingHistory(
                    oVertex, oDrawingVisual, bDrawAsSelected, dRadius);

                break;

            case VertexShape.Square:
            case VertexShape.SolidSquare:

                Boolean bIsSolidSquare = (eShape == VertexShape.SolidSquare);

                oDrawingContext.DrawRectangle(
                    bIsSolidSquare ? GetBrush(oColor) : Brushes.Transparent,
                    bIsSolidSquare? null : GetPen(oColor, DefaultPenThickness),
                    oVertexBounds
                    );

                oVertexDrawingHistory = bIsSolidSquare ?

                    new SolidSquareVertexDrawingHistory(oVertex,
                        oDrawingVisual, bDrawAsSelected, oVertexBounds)
                    :
                    new SquareVertexDrawingHistory(oVertex,
                        oDrawingVisual, bDrawAsSelected, oVertexBounds);

                break;

            case VertexShape.Diamond:
            case VertexShape.SolidDiamond:

                Boolean bIsSolidDiamond = (eShape == VertexShape.SolidDiamond);

                PathGeometry oDiamond =
                    WpfGraphicsUtil.DiamondFromCenterAndHalfWidth(
                        oLocation, dRadius);

                oDrawingContext.DrawGeometry(

                    bIsSolidDiamond ? GetBrush(oColor) : Brushes.Transparent,

                    bIsSolidDiamond ? null :
                        GetPen(oColor, DefaultPenThickness),

                    oDiamond
                    );

                oVertexDrawingHistory = bIsSolidDiamond ?

                    new SolidDiamondVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius)
                    :
                    new DiamondVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius);

                break;

            case VertexShape.Triangle:
            case VertexShape.SolidTriangle:

                Boolean bIsSolidTriangle =
                    (eShape == VertexShape.SolidTriangle);

                PathGeometry oTriangle =
                    WpfGraphicsUtil.TriangleFromCenterAndHalfWidth(
                        oLocation, dRadius);

                oDrawingContext.DrawGeometry(

                    bIsSolidTriangle ? GetBrush(oColor) : Brushes.Transparent,

                    bIsSolidTriangle ? null :
                        GetPen(oColor, DefaultPenThickness),

                    oTriangle
                    );

                oVertexDrawingHistory = bIsSolidTriangle ?

                    new SolidTriangleVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius)
                    :
                    new TriangleVertexDrawingHistory(
                        oVertex, oDrawingVisual, bDrawAsSelected, dRadius);

                break;

            default:

                Debug.Assert(false);
                break;
            }

            if (sAnnotation != null)
            {
            oVertexLabelDrawer.DrawLabel( oDrawingContext,
                oGraphDrawingContext, oVertexDrawingHistory, oVertexBounds,
                CreateFormattedText(sAnnotation, oColor) );
            }

            if ( oVertex.ContainsKey(ReservedMetadataKeys.PerVertexDrawPlusSign) )
            {
            DrawPlusSign(eShape, oVertexLocation, oVertexBounds, oColor,
                oGraphDrawingContext, oDrawingContext, oVertexLabelDrawer,
                oVertexDrawingHistory);
            }

            Debug.Assert(oVertexDrawingHistory != null);

            return (oVertexDrawingHistory);
        }
    DrawLabel
    (
        IEdge oEdge,
        DrawingContext oDrawingContext,
        GraphDrawingContext oGraphDrawingContext,
        Boolean bDrawAsSelected,
        Color oEdgeColor,
        VisibilityKeyValue eVisibility,
        Point oEdgeEndpoint1,
        Point oEdgeEndpoint2,
        PathGeometry oBezierCurve,
        Point oBezierControlPoint,
        String sLabel
    )
    {
        Debug.Assert(oEdge != null);
        Debug.Assert(oDrawingContext != null);
        Debug.Assert(oGraphDrawingContext != null);
        Debug.Assert(sLabel != null);
        AssertValid();

        if (sLabel.Length == 0)
        {
            return;
        }

        sLabel = TruncateLabel(sLabel);

        Double dFontSize = GetLabelFontSize(oEdge);

        Color oLabelTextColor = GetLabelTextColor(oEdge, bDrawAsSelected,
            oEdgeColor, eVisibility);

        FormattedText oFormattedText =
            m_oFormattedTextManager.CreateFormattedText(sLabel,
                oLabelTextColor, dFontSize, m_dGraphScale);

        oFormattedText.Trimming = TextTrimming.CharacterEllipsis;

        // Don't let the FormattedText class break long lines when drawing
        // Bezier curves.  DrawBezierLabel(), which draws the label
        // character-by-character, is unable to tell where such line breaks
        // occur, because FormattedText doesn't expose this information.
        //
        // For consistency, do the same when drawing straight edges.

        oFormattedText.MaxLineCount = sLabel.Count(c => c == '\n') + 1;

        // 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 dBufferWidth =
            m_oFormattedTextManager.CreateFormattedText("i", oLabelTextColor,
                dFontSize, m_dGraphScale).Width;

        Double dEdgeLength = WpfGraphicsUtil.GetDistanceBetweenPoints(
            oEdgeEndpoint1, oEdgeEndpoint2);

        Double dEdgeLengthMinusBuffers = dEdgeLength - 2 * dBufferWidth;

        if (dEdgeLengthMinusBuffers <= 0)
        {
            return;
        }

        // Determine where to draw the label text.

        Double dTextWidth = oFormattedText.Width;
        Double dLabelOriginAsFractionOfEdgeLength;

        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.

            dLabelOriginAsFractionOfEdgeLength = dBufferWidth / dEdgeLength;

            oFormattedText.MaxTextWidth = dEdgeLengthMinusBuffers;
        }
        else
        {
            // The label should be centered along the edge's length.

            dLabelOriginAsFractionOfEdgeLength = 
                ( (dEdgeLength - dTextWidth) / 2.0 ) / dEdgeLength;
        }

        // Note: Don't make the translucent rectangle any more opaque than the
        // edge, which might be translucent itself.

        Color oTranslucentRectangleColor = WpfGraphicsUtil.SetWpfColorAlpha(
            oGraphDrawingContext.BackColor,
            Math.Min(LabelBackgroundAlpha, oEdgeColor.A)
            );

        if (this.ShouldDrawBezierCurve)
        {
            DrawBezierLabel(oDrawingContext, oGraphDrawingContext,
                oFormattedText, oEdgeEndpoint1, oEdgeEndpoint2, oBezierCurve,
                dLabelOriginAsFractionOfEdgeLength, dEdgeLength,
                dBufferWidth, oLabelTextColor, oTranslucentRectangleColor,
                dFontSize);
        }
        else
        {
            DrawStraightLabel(oDrawingContext, oGraphDrawingContext,
                oFormattedText, oEdgeEndpoint1, oEdgeEndpoint2,
                dLabelOriginAsFractionOfEdgeLength, dEdgeLength, dBufferWidth,
                oTranslucentRectangleColor);
        }
    }
Exemple #18
0
        //*************************************************************************
        //  Method: DrawImageShape()
        //
        /// <summary>
        /// Draws a vertex as a specified image.
        /// </summary>
        ///
        /// <param name="oVertex">
        /// The vertex to draw.
        /// </param>
        ///
        /// <param name="oGraphDrawingContext">
        /// Provides access to objects needed for graph-drawing operations.
        /// </param>
        ///
        /// <param name="oDrawingContext">
        /// The DrawingContext to use.
        /// </param>
        ///
        /// <param name="oDrawingVisual">
        /// The <see cref="DrawingVisual" /> object from which <paramref
        /// name="oDrawingContext" /> was obtained.
        /// </param>
        ///
        /// <param name="eVisibility">
        /// The visibility of the vertex.
        /// </param>
        ///
        /// <param name="bDrawAsSelected">
        /// true to draw the vertex as selected.
        /// </param>
        ///
        /// <param name="sAnnotation">
        /// The annotation to draw next to the image, or null if there is no
        /// annotation.
        /// </param>
        ///
        /// <param name="oImageSource">
        /// The image to draw.
        /// </param>
        ///
        /// <param name="oVertexLabelDrawer">
        /// Object that draws a vertex label as an annotation.
        /// </param>
        ///
        /// <returns>
        /// A VertexDrawingHistory object that retains information about how the
        /// vertex was drawn.
        /// </returns>
        //*************************************************************************
        protected VertexDrawingHistory DrawImageShape(
            IVertex oVertex,
            GraphDrawingContext oGraphDrawingContext,
            DrawingContext oDrawingContext,
            DrawingVisual oDrawingVisual,
            VisibilityKeyValue eVisibility,
            Boolean bDrawAsSelected,
            String sAnnotation,
            ImageSource oImageSource,
            VertexLabelDrawer oVertexLabelDrawer
            )
        {
            Debug.Assert(oVertex != null);
            Debug.Assert(oGraphDrawingContext != null);
            Debug.Assert(oDrawingContext != null);
            Debug.Assert(oDrawingVisual != null);
            Debug.Assert(oImageSource != null);
            Debug.Assert(oVertexLabelDrawer != null);
            AssertValid();

            // Move the vertex if it falls outside the graph rectangle.

            Rect oVertexRectangle = GetVertexRectangle(
            GetVertexLocation(oVertex), oImageSource.Width * m_dGraphScale,
            oImageSource.Height * m_dGraphScale);

            MoveVertexIfNecessary(oVertex, ref oVertexRectangle,
            oGraphDrawingContext);

            Byte btAlpha = 255;

            if (!bDrawAsSelected)
            {
            // Check for a non-opaque alpha value.

            btAlpha = GetAlpha(oVertex, eVisibility, btAlpha);
            }

            VertexDrawingHistory oVertexDrawingHistory =
            new ImageVertexDrawingHistory(oVertex, oDrawingVisual,
                bDrawAsSelected, oVertexRectangle);

            if (btAlpha > 0)
            {
            oDrawingContext.DrawImage(oImageSource, oVertexRectangle);

            Color oColor = GetColor(oVertex, eVisibility, bDrawAsSelected);

            // Draw an outline rectangle.

            oDrawingContext.DrawRectangle(null,
                GetPen(oColor, DefaultPenThickness), oVertexRectangle);

            if (btAlpha < 255)
            {
                // Real transparency can't be achieved with arbitrary images,
                // so simulate transparency by drawing on top of the image with
                // a translucent brush the same color as the graph's
                // background.
                //
                // This really isn't a good solution.  Is there are better way
                // to simulate transparency?

                Color oTranslucentColor = oGraphDrawingContext.BackColor;
                oTranslucentColor.A = (Byte)( (Byte)255 - btAlpha );

                oDrawingContext.DrawRectangle(
                    CreateFrozenSolidColorBrush(oTranslucentColor), null,
                        oVertexRectangle);
            }

            if (sAnnotation != null)
            {
                oVertexLabelDrawer.DrawLabel(oDrawingContext,
                    oGraphDrawingContext, oVertexDrawingHistory,
                    oVertexRectangle, CreateFormattedText(sAnnotation, oColor)
                    );
            }
            }

            return (oVertexDrawingHistory);
        }
    DrawBezierCurve
    (
        IEdge oEdge,
        GraphDrawingContext oGraphDrawingContext,
        DrawingContext oDrawingContext,
        Point oEdgeEndpoint1,
        Point oEdgeEndpoint2,
        Boolean bDrawAsSelected,
        Boolean bDrawArrow,
        Pen oPen,
        Color oColor,
        Double dWidth,
        VisibilityKeyValue eVisibility,
        String sLabel
    )
    {
        Debug.Assert(oEdge != null);
        Debug.Assert(oGraphDrawingContext != null);
        Debug.Assert(oDrawingContext != null);
        Debug.Assert(oPen != null);
        AssertValid();

        Point oBezierControlPoint = GetBezierControlPoint(oGraphDrawingContext,
            oEdgeEndpoint1, oEdgeEndpoint2, m_dBezierDisplacementFactor);

        if (bDrawArrow)
        {
            // When the edge is a Bezier curve, the arrow should be aligned
            // along the tangent of the curve at the second endpoint.  The
            // tangent runs from the second endpoint to the Bezier control
            // point.

            Double dArrowAngle = WpfGraphicsUtil.GetAngleBetweenPointsRadians(
                oBezierControlPoint, oEdgeEndpoint2);

            // Draw the arrow and set the second endpoint to the center of the
            // flat end of the arrow.  Note that in the Bezier case, moving the
            // second endpoint causes a small distortion of the Bezier curve.

            oEdgeEndpoint2 = DrawArrow(oDrawingContext, oEdgeEndpoint2,
                dArrowAngle, oColor, dWidth);
        }

        PathGeometry oBezierCurve =
            WpfPathGeometryUtil.GetQuadraticBezierCurve(oEdgeEndpoint1,
                oEdgeEndpoint2, oBezierControlPoint);

        oDrawingContext.DrawGeometry(null, oPen, oBezierCurve);

        if ( !String.IsNullOrEmpty(sLabel) )
        {
            DrawLabel(oEdge, oDrawingContext, oGraphDrawingContext,
                bDrawAsSelected, oColor, eVisibility, oEdgeEndpoint1,
                oEdgeEndpoint2, oBezierCurve, oBezierControlPoint, sLabel);
        }
    }
    DrawLabelShape
    (
        IVertex oVertex,
        GraphDrawingContext oGraphDrawingContext,
        DrawingContext oDrawingContext,
        DrawingVisualPlus oDrawingVisual,
        VisibilityKeyValue eVisibility,
        Boolean bDrawAsSelected,
        String sLabel,
        CollapsedGroupDrawingManager oCollapsedGroupDrawingManager
    )
    {
        Debug.Assert(oVertex != null);
        Debug.Assert(oGraphDrawingContext != null);
        Debug.Assert(oDrawingContext != null);
        Debug.Assert(oDrawingVisual != null);
        Debug.Assert( !String.IsNullOrEmpty(sLabel) );
        Debug.Assert(oCollapsedGroupDrawingManager != null);
        AssertValid();

        // Figure out what colors to use.

        Color oOutlineColor;

        Color oTextColor = GetColor(oVertex, eVisibility, false);

        Color oFillColor = GetColor(oVertex, eVisibility,
            ReservedMetadataKeys.PerVertexLabelFillColor, m_oLabelFillColor,
            true);

        if (bDrawAsSelected)
        {
            // The outline color is always the selected color.

            oOutlineColor = m_oSelectedColor;

            // The text color is the default or per-vertex color with no alpha.

            oTextColor.A = 255;

            // The fill color is the default or per-vertex fill color with no
            // alpha.

            oFillColor.A = 255;
        }
        else
        {
            // The outline color is the default or per-vertex color with alpha.

            oOutlineColor = oTextColor;

            // The text color is the default or per-vertex color with alpha.

            // The fill color is the default or per-vertex fill color with
            // alpha.
        }

        Double dLabelFontSize = GetLabelFontSize(oVertex);

        FormattedText oFormattedText = CreateFormattedTextWithWrap(
            sLabel, oTextColor, dLabelFontSize);

        Rect oVertexRectangle = GetVertexRectangle(
            GetVertexLocation(oVertex), oFormattedText.Width,
            oFormattedText.Height);

        // Pad the text.

        Rect oVertexRectangleWithPadding = oVertexRectangle;
        Double dLabelPadding = GetLabelPadding(dLabelFontSize);

        oVertexRectangleWithPadding.Inflate(dLabelPadding,
            dLabelPadding * 0.7);

        if (m_oFormattedTextManager.Typeface.Style != FontStyles.Normal)
        {
            // This is a hack to move the right edge of the padded rectangle
            // to the right to adjust for wider italic text, which
            // FormattedText.Width does not account for.  What is the correct
            // way to do this?  It might involve the FormattedText.Overhang*
            // properties, but I'll be darned if I can understand how those
            // properties work.

            Double dItalicCompensation = dLabelFontSize / 7.0;
            oVertexRectangleWithPadding.Inflate(dItalicCompensation, 0);
            oVertexRectangleWithPadding.Offset(dItalicCompensation, 0);
        }

        // Move the vertex if it falls outside the graph rectangle.

        Double dOriginalVertexRectangleWithPaddingX =
            oVertexRectangleWithPadding.X;

        Double dOriginalVertexRectangleWithPaddingY =
            oVertexRectangleWithPadding.Y;

        MoveVertexIfNecessary(oVertex, oGraphDrawingContext,
            oCollapsedGroupDrawingManager, ref oVertexRectangleWithPadding);

        oVertexRectangle.Offset(

            oVertexRectangleWithPadding.X -
                dOriginalVertexRectangleWithPaddingX,

            oVertexRectangleWithPadding.Y -
                dOriginalVertexRectangleWithPaddingY
            );

        oDrawingVisual.SetEffect( GetRectangleEffect(
            oGraphDrawingContext, oOutlineColor) );

        // Draw the padded rectangle, then the text.

        WpfGraphicsUtil.DrawPixelAlignedRectangle(oDrawingContext,
            GetBrush(oFillColor), GetPen(oOutlineColor, DefaultPenThickness),
            oVertexRectangleWithPadding);

        oDrawingContext.DrawText(oFormattedText, oVertexRectangle.Location);

        // Return information about how the vertex was drawn.

        return ( new LabelVertexDrawingHistory(oVertex, oDrawingVisual,
            bDrawAsSelected, oVertexRectangleWithPadding) );
    }