Retains information about how one vertex was drawn.
This is an abstract base class. There is one concrete derived class for each type of vertex that can be drawn. The derived classes must implement the GetEdgeEndpoint, GetSelfLoopEndpoint, and GetLabelLocation methods.
Inheritance: DrawingHistory
示例#1
0
        DrawLabel
        (
            DrawingContext drawingContext,
            GraphDrawingContext graphDrawingContext,
            VertexDrawingHistory vertexDrawingHistory,
            FormattedText formattedText,
            Color formattedTextColor
        )
        {
            Debug.Assert(drawingContext != null);
            Debug.Assert(graphDrawingContext != null);
            Debug.Assert(vertexDrawingHistory != null);
            Debug.Assert(formattedText != null);
            AssertValid();

            DrawLabel(drawingContext, graphDrawingContext, vertexDrawingHistory,
                      GetLabelPosition(vertexDrawingHistory.Vertex), formattedText,
                      formattedTextColor, true);
        }
示例#2
0
        TryGetVertexDrawingHistory
        (
            IVertex oVertex,
            out VertexDrawingHistory oVertexDrawingHistory
        )
        {
            Debug.Assert(oVertex != null);

            oVertexDrawingHistory = null;
            Object oVertexDrawingHistoryAsObject;

            if (!oVertex.TryGetValue(ReservedMetadataKeys.VertexDrawingHistory,
                                     typeof(VertexDrawingHistory), out oVertexDrawingHistoryAsObject))
            {
                return(false);
            }

            oVertexDrawingHistory =
                (VertexDrawingHistory)oVertexDrawingHistoryAsObject;

            return(true);
        }
示例#3
0
    TryGetVertexInformation
    (
        IVertex oVertex1,
        IVertex oVertex2,
        out VertexDrawingHistory oVertex1DrawingHistory,
        out VertexDrawingHistory oVertex2DrawingHistory,
        out Point oEdgeEndpoint1,
        out Point oEdgeEndpoint2
    )
    {
        Debug.Assert(oVertex1 != null);
        Debug.Assert(oVertex2 != null);
        AssertValid();

        oVertex1DrawingHistory = oVertex2DrawingHistory = null;
        oEdgeEndpoint1 = oEdgeEndpoint2 = new Point();

        // Retrieve the information about how the vertices were drawn.

        if (
            !TryGetVertexDrawingHistory(oVertex1, out oVertex1DrawingHistory)
            ||
            !TryGetVertexDrawingHistory(oVertex2, out oVertex2DrawingHistory)
            )
        {
            // One of the edge's vertices is hidden.

            return (false);
        }

        // The drawing histories determine the edge endpoints.  For example, if
        // oVertex1 was drawn as a circle, then oVertex1DrawingHistory is a
        // CircleVertexDrawingHistory that knows to put its endpoint on the
        // circle itself and not at the circle's center.

        oVertex1DrawingHistory.GetEdgeEndpoint(
            oVertex2DrawingHistory.VertexLocation, out oEdgeEndpoint1);

        oVertex2DrawingHistory.GetEdgeEndpoint(
            oVertex1DrawingHistory.VertexLocation, out oEdgeEndpoint2);

        return (true);
    }
示例#4
0
    FilterIntermediatePoints
    (
        IEdge oEdge,
        VertexDrawingHistory oVertex1DrawingHistory,
        VertexDrawingHistory oVertex2DrawingHistory
    )
    {
        Debug.Assert(oEdge != null);
        Debug.Assert(oVertex1DrawingHistory != null);
        Debug.Assert(oVertex2DrawingHistory != null);
        AssertValid();

        List<Point> oFilteredIntermediatePoints = new List<Point>();
        System.Drawing.PointF [] aoIntermediateCurvePoints;

        DrawingVisual oVertex1DrawingVisual =
            oVertex1DrawingHistory.DrawingVisual;

        DrawingVisual oVertex2DrawingVisual =
            oVertex2DrawingHistory.DrawingVisual;

        if ( EdgeUtil.TryGetIntermediateCurvePoints(oEdge,
            out aoIntermediateCurvePoints) )
        {
            foreach (System.Drawing.PointF oIntermediateCurvePoint in 
                aoIntermediateCurvePoints)
            {
                Point oIntermediateCurveWpfPoint =
                    WpfGraphicsUtil.PointFToWpfPoint(oIntermediateCurvePoint);

                // Check whether the point falls within the bounds of either
                // vertex.
                //
                // This could be done more quickly but with more code by
                // selectively hit-testing only vertex 1 or vertex 2 as we move
                // along the curve.  However, the hit-testing is so fast that
                // it's probably not worth the extra complexity.  On one test
                // machine, for example, 200,000 hit tests took about 24 ms,
                // and that didn't vary much with vertex shape or size.

                if (
                    oVertex1DrawingVisual.HitTest(
                        oIntermediateCurveWpfPoint) == null
                    &&
                    oVertex2DrawingVisual.HitTest(
                        oIntermediateCurveWpfPoint) == null
                    )
                {
                    oFilteredIntermediatePoints.Add(
                        oIntermediateCurveWpfPoint);
                }
            }
        }

        return (oFilteredIntermediatePoints);
    }
示例#5
0
    DrawCurveThroughIntermediatePoints
    (
        IEdge oEdge,
        GraphDrawingContext oGraphDrawingContext,
        DrawingContext oDrawingContext,
        VertexDrawingHistory oVertex1DrawingHistory,
        VertexDrawingHistory oVertex2DrawingHistory,
        Point oEdgeEndpoint1,
        Point oEdgeEndpoint2,
        Pen oPen
    )
    {
        Debug.Assert(oEdge != null);
        Debug.Assert(oGraphDrawingContext != null);
        Debug.Assert(oDrawingContext != null);
        Debug.Assert(oVertex1DrawingHistory != null);
        Debug.Assert(oVertex2DrawingHistory != null);
        Debug.Assert(oPen != null);
        AssertValid();

        // Note: Don't attempt to draw an arrow in this case.

        // Create a list of intermediate points, excluding those that fall
        // within the vertex bounds.  An edge always terminates on the vertex
        // bounds, so we don't want it venturing into the vertex itself.

        List<Point> oCurvePoints = FilterIntermediatePoints(oEdge,
            oVertex1DrawingHistory, oVertex2DrawingHistory);

        Int32 iCurvePoints = oCurvePoints.Count;

        if (iCurvePoints == 0)
        {
            // Just draw a straight line.

            oDrawingContext.DrawLine(oPen, oEdgeEndpoint1, oEdgeEndpoint2);
            return;
        }

        #if false
        // Draw intermediate points for testing.

        foreach (Point oPoint in oCurvePoints)
        {
            oDrawingContext.DrawEllipse(Brushes.Green, null, oPoint, 2, 2);
        }
        #endif

        // The endpoints were originally calculated as if the edge was a
        // straight line between the two vertices.  Recalculate them so they
        // connect more smoothly to the adjacent intermediate curve points.

        oVertex1DrawingHistory.GetEdgeEndpoint(oCurvePoints[0],
            out oEdgeEndpoint1);

        oVertex2DrawingHistory.GetEdgeEndpoint(oCurvePoints[iCurvePoints - 1],
            out oEdgeEndpoint2);

        oCurvePoints.Insert(0, oEdgeEndpoint1);
        oCurvePoints.Add(oEdgeEndpoint2);

        PathGeometry oCurveThroughPoints =
            WpfPathGeometryUtil.GetCurveThroughPoints(oCurvePoints, 0.5,
                CurveThroughIntermediatePointsTolerance);

        oDrawingContext.DrawGeometry(null, oPen, oCurveThroughPoints);

        // Note: Don't attempt to draw a label in this case.
    }
    PostDrawVertex
    (
        VertexShape vertexShape,
        Color vertexColor,
        GraphDrawingContext graphDrawingContext,
        DrawingContext drawingContext,
        Boolean drawAsSelected,
        Double graphScale,
        VertexLabelDrawer vertexLabelDrawer,
        FormattedTextManager formattedTextManager,
        VertexDrawingHistory vertexDrawingHistory
    )
    {
        Debug.Assert(graphDrawingContext != null);
        Debug.Assert(drawingContext != null);
        Debug.Assert(graphScale >= GraphDrawer.MinimumGraphScale);
        Debug.Assert(graphScale <= GraphDrawer.MaximumGraphScale);
        Debug.Assert(vertexLabelDrawer != null);
        Debug.Assert(formattedTextManager != null);
        Debug.Assert(vertexDrawingHistory != null);
        AssertValid();

        if (m_oCollapsedGroupVertex == null)
        {
            // The vertex that was drawn is not a collapsed group vertex.  Do
            // nothing.

            return;
        }

        if (m_oCollapsedGroupAttributes.Count == 0)
        {
            // The vertex that was drawn represents a collapsed group, but no
            // attributes were specified for it.  By default, such a vertex
            // gets a plus sign drawn on top of it.

            DrawPlusSign(vertexShape, vertexColor, graphDrawingContext,
                drawingContext, graphScale, vertexLabelDrawer,
                formattedTextManager, vertexDrawingHistory);
        }
        else
        {
            // Check whether this this is a collapsed motif.

            switch ( m_oCollapsedGroupAttributes.GetGroupType() )
            {
                case CollapsedGroupAttributeValues.FanMotifType:

                    DrawFanMotifFan(vertexColor, drawingContext,
                        drawAsSelected, graphScale, vertexDrawingHistory);

                    break;

                default:

                    // Do nothing.  This includes the D-connector motif case,
                    // which requires no post-drawing action.

                    break;
            }
        }
    }
    DrawFanMotifFan
    (
        Color oHeadColor,
        DrawingContext oDrawingContext,
        Boolean bDrawAsSelected,
        Double dGraphScale,
        VertexDrawingHistory oVertexDrawingHistory
    )
    {
        Debug.Assert(oDrawingContext != null);
        Debug.Assert(dGraphScale >= GraphDrawer.MinimumGraphScale);
        Debug.Assert(dGraphScale <= GraphDrawer.MaximumGraphScale);
        Debug.Assert(oVertexDrawingHistory != null);
        AssertValid();

        // The fill color to use for the fan was set in PreDrawVertex().

        Object oFanColorAsObject;

        if ( !m_oCollapsedGroupVertex.TryGetValue(
            ReservedMetadataKeys.FanMotifFanColor,
            typeof(System.Drawing.Color), out oFanColorAsObject) )
        {
            return;
        }

        // If the collapsed group vertex is selected, the entire vertex,
        // including the fan drawn here, should be drawn using oHeadColor,
        // which the caller has set to the selected color.

        Color oFanColor = bDrawAsSelected ? oHeadColor :
            WpfGraphicsUtil.ColorToWpfColor(
                (System.Drawing.Color)oFanColorAsObject);

        Double dAngleRadians = GetFanMotifAngleRadians();
        Rect oVertexBounds = oVertexDrawingHistory.GetBounds().Bounds;

        Brush oFillBrush = new SolidColorBrush(oFanColor);
        WpfGraphicsUtil.FreezeIfFreezable(oFillBrush);

        Color oPenColor = GetCollapsedMotifOutlineColor(255);
        Brush oPenBrush = new SolidColorBrush(oPenColor);
        WpfGraphicsUtil.FreezeIfFreezable(oPenBrush);

        Pen oPen = new Pen(oPenBrush, 2.0 * dGraphScale);
        WpfGraphicsUtil.FreezeIfFreezable(oPen);

        oDrawingContext.DrawGeometry( oFillBrush, oPen, 
            GetCircleSegment(oVertexBounds, dAngleRadians, dGraphScale) );
    }
    DrawPlusSign
    (
        VertexShape eVertexShape,
        Color oVertexColor,
        GraphDrawingContext oGraphDrawingContext,
        DrawingContext oDrawingContext,
        Double dGraphScale,
        VertexLabelDrawer oVertexLabelDrawer,
        FormattedTextManager oFormattedTextManager,
        VertexDrawingHistory oVertexDrawingHistory
    )
    {
        Debug.Assert(oGraphDrawingContext != null);
        Debug.Assert(oDrawingContext != null);
        Debug.Assert(dGraphScale >= GraphDrawer.MinimumGraphScale);
        Debug.Assert(dGraphScale <= GraphDrawer.MaximumGraphScale);
        Debug.Assert(oVertexLabelDrawer != null);
        Debug.Assert(oFormattedTextManager != null);
        Debug.Assert(oVertexDrawingHistory != null);
        AssertValid();

        Color oFillColor;

        switch (eVertexShape)
        {
            case VertexShape.Circle:
            case VertexShape.Square:
            case VertexShape.Diamond:
            case VertexShape.Triangle:

                // The fill color is the color of the background.  Adjust the
                // fill color for the opacity of the vertex.

                oFillColor = WpfGraphicsUtil.SetWpfColorAlpha(
                    oGraphDrawingContext.BackColor, oVertexColor.A);

                break;

            default:

                oFillColor = oVertexColor;
                break;
        }

        Color oContrastingColor =
            WpfGraphicsUtil.GetContrastingColor(oFillColor);

        // The font size used below was chosen so that it is large enough to be
        // easily readable, but small enough to fit within the smallest
        // collapsed group vertex created by this class.

        oVertexLabelDrawer.DrawLabel(oDrawingContext, oGraphDrawingContext,
            oVertexDrawingHistory, VertexLabelPosition.MiddleCenter,

            oFormattedTextManager.CreateFormattedText("+", oContrastingColor,
                15.0, dGraphScale),

            oContrastingColor, false);
    }
示例#9
0
        DrawLabel
        (
            DrawingContext drawingContext,
            GraphDrawingContext graphDrawingContext,
            VertexDrawingHistory vertexDrawingHistory,
            VertexLabelPosition labelPosition,
            FormattedText formattedText,
            Color formattedTextColor,
            Boolean drawBackground
        )
        {
            Debug.Assert(drawingContext != null);
            Debug.Assert(graphDrawingContext != null);
            Debug.Assert(vertexDrawingHistory != null);
            Debug.Assert(formattedText != null);
            AssertValid();

            if (labelPosition == VertexLabelPosition.Nowhere)
            {
                return;
            }

            // The alignment needs to be set before the width and height of the
            // FormattedText are obtained.

            SetTextAlignment(formattedText, labelPosition);

            // You can't use FormattedText.Width to get the width of the actual
            // text when text wrapping is enabled (FormattedText.MaxTextWidth > 0).
            // Instead, use a method that takes wrapping into account.

            Double dLabelWidth = WpfGraphicsUtil.GetFormattedTextSize(
                formattedText).Width;

            Double dLabelHeight = formattedText.Height;

            // This is the point where the label will be drawn using
            // DrawingContext.Draw().  It initially assumes a text height of zero,
            // a margin of zero, and no adjustment for alignment (see
            // dAdjustmentForTextAlignmentX below), but this will be modified
            // appropriately within the switch statement below.

            Point  oDraw  = vertexDrawingHistory.GetLabelLocation(labelPosition);
            Double dDrawX = oDraw.X;
            Double dDrawY = oDraw.Y;

            // These are the left and right bounds of the rectangle where the text
            // will actually appear.

            Double dLabelBoundsLeft  = 0;
            Double dLabelBoundsRight = 0;

            AdjustForTextAlignment(dLabelWidth, dLabelHeight, labelPosition,
                                   formattedText, ref dDrawX, ref dDrawY, ref dLabelBoundsLeft,
                                   ref dLabelBoundsRight);

            // Don't let the text exceed the bounds of the graph rectangle.

            dDrawX = StayWithinHorizontalBounds(
                dDrawX, graphDrawingContext, dLabelBoundsLeft, dLabelBoundsRight);

            Double dLabelBoundsTop    = dDrawY;
            Double dLabelBoundsBottom = dDrawY + dLabelHeight;

            dDrawY = StayWithinVerticalBounds(
                dDrawY, graphDrawingContext, dLabelBoundsTop, dLabelBoundsBottom);

            if (drawBackground)
            {
                dLabelBoundsLeft = StayWithinHorizontalBounds(
                    dLabelBoundsLeft, graphDrawingContext,
                    dLabelBoundsLeft, dLabelBoundsRight);

                DrawLabelBackground(drawingContext, graphDrawingContext,
                                    formattedText, formattedTextColor, m_btBackgroundAlpha,
                                    new Point(dLabelBoundsLeft, dDrawY));
            }

            drawingContext.DrawText(formattedText, new Point(dDrawX, dDrawY));
        }
示例#10
0
    TryGetVertexDrawingHistory
    (
        IVertex oVertex,
        out VertexDrawingHistory oVertexDrawingHistory
    )
    {
        Debug.Assert(oVertex != null);

        oVertexDrawingHistory = null;
        Object oVertexDrawingHistoryAsObject;

        if ( !oVertex.TryGetValue(ReservedMetadataKeys.VertexDrawingHistory,
            typeof(VertexDrawingHistory), out oVertexDrawingHistoryAsObject) )
        {
            return (false);
        }

        oVertexDrawingHistory =
            (VertexDrawingHistory)oVertexDrawingHistoryAsObject;

        return (true);
    }
    DrawLabel
    (
        DrawingContext drawingContext,
        GraphDrawingContext graphDrawingContext,
        VertexDrawingHistory vertexDrawingHistory,
        FormattedText formattedText,
        Color formattedTextColor
    )
    {
        Debug.Assert(drawingContext != null);
        Debug.Assert(graphDrawingContext != null);
        Debug.Assert(vertexDrawingHistory != null);
        Debug.Assert(formattedText != null);
        AssertValid();

        DrawLabel(drawingContext, graphDrawingContext, vertexDrawingHistory,
            GetLabelPosition(vertexDrawingHistory.Vertex), formattedText,
            formattedTextColor, true);
    }
    DrawLabel
    (
        DrawingContext drawingContext,
        GraphDrawingContext graphDrawingContext,
        VertexDrawingHistory vertexDrawingHistory,
        VertexLabelPosition labelPosition,
        FormattedText formattedText,
        Color formattedTextColor,
        Boolean drawBackground
    )
    {
        Debug.Assert(drawingContext != null);
        Debug.Assert(graphDrawingContext != null);
        Debug.Assert(vertexDrawingHistory != null);
        Debug.Assert(formattedText != null);
        AssertValid();

        if (labelPosition == VertexLabelPosition.Nowhere)
        {
            return;
        }

        // The alignment needs to be set before the width and height of the
        // FormattedText are obtained.

        SetTextAlignment(formattedText, labelPosition);

        // You can't use FormattedText.Width to get the width of the actual
        // text when text wrapping is enabled (FormattedText.MaxTextWidth > 0).
        // Instead, use a method that takes wrapping into account.

        Double dLabelWidth = WpfGraphicsUtil.GetFormattedTextSize(
            formattedText).Width;

        Double dLabelHeight = formattedText.Height;

        // This is the point where the label will be drawn using
        // DrawingContext.Draw().  It initially assumes a text height of zero,
        // a margin of zero, and no adjustment for alignment (see
        // dAdjustmentForTextAlignmentX below), but this will be modified
        // appropriately within the switch statement below.

        Point oDraw = vertexDrawingHistory.GetLabelLocation(labelPosition);
        Double dDrawX = oDraw.X;
        Double dDrawY = oDraw.Y;

        // These are the left and right bounds of the rectangle where the text
        // will actually appear.

        Double dLabelBoundsLeft = 0;
        Double dLabelBoundsRight = 0;

        AdjustForTextAlignment(dLabelWidth, dLabelHeight, labelPosition,
            formattedText, ref dDrawX, ref dDrawY, ref dLabelBoundsLeft,
            ref dLabelBoundsRight);

        // Don't let the text exceed the bounds of the graph rectangle.

        dDrawX = StayWithinHorizontalBounds(
            dDrawX, graphDrawingContext, dLabelBoundsLeft, dLabelBoundsRight);

        Double dLabelBoundsTop = dDrawY;
        Double dLabelBoundsBottom = dDrawY + dLabelHeight;

        dDrawY = StayWithinVerticalBounds(
            dDrawY, graphDrawingContext, dLabelBoundsTop, dLabelBoundsBottom);

        if (drawBackground)
        {
            dLabelBoundsLeft = StayWithinHorizontalBounds(
                dLabelBoundsLeft, graphDrawingContext,
                dLabelBoundsLeft, dLabelBoundsRight);

            DrawLabelBackground( drawingContext, graphDrawingContext,
                formattedText, formattedTextColor, m_btBackgroundAlpha,
                new Point(dLabelBoundsLeft, dDrawY) );
        }

        drawingContext.DrawText( formattedText, new Point(dDrawX, dDrawY) );
    }
示例#13
0
    TryDrawVertex
    (
        IVertex vertex,
        GraphDrawingContext graphDrawingContext,
        out VertexDrawingHistory vertexDrawingHistory
    )
    {
        AssertValid();

        vertexDrawingHistory = null;

        CheckDrawVertexArguments(vertex, graphDrawingContext);

        if (graphDrawingContext.GraphRectangleMinusMarginIsEmpty)
        {
            return (false);
        }

        // If the vertex is hidden, do nothing.

        VisibilityKeyValue eVisibility = GetVisibility(vertex);

        if (eVisibility == VisibilityKeyValue.Hidden)
        {
            return (false);
        }

        // Check whether the vertex represents a collapsed group and perform
        // collapsed group tasks if necessary.

        CollapsedGroupDrawingManager oCollapsedGroupDrawingManager =
            new CollapsedGroupDrawingManager();

        oCollapsedGroupDrawingManager.PreDrawVertex(vertex);

        // Check for a per-vertex label.

        Object oLabelAsObject;
        String sLabel = null;

        if ( vertex.TryGetValue(ReservedMetadataKeys.PerVertexLabel,
            typeof(String), out oLabelAsObject) )
        {
            sLabel = (String)oLabelAsObject;

            if ( String.IsNullOrEmpty(sLabel) )
            {
                sLabel = null;
            }
            else
            {
                sLabel = TruncateLabel(sLabel);
            }
        }

        Boolean bDrawAsSelected = GetDrawAsSelected(vertex);
        Point oLocation = WpfGraphicsUtil.PointFToWpfPoint(vertex.Location);
        DrawingVisualPlus oDrawingVisual = new DrawingVisualPlus();
        VertexShape eShape = GetShape(vertex);

        VertexLabelDrawer oVertexLabelDrawer =
            new VertexLabelDrawer(m_eLabelPosition, m_btBackgroundAlpha);

        using ( DrawingContext oDrawingContext = oDrawingVisual.RenderOpen() )
        {
            if (eShape == VertexShape.Label)
            {
                if (sLabel != null)
                {
                    // Draw the vertex as a label.

                    vertexDrawingHistory = DrawLabelShape(vertex,
                        graphDrawingContext, oDrawingContext, oDrawingVisual,
                        eVisibility, bDrawAsSelected, sLabel,
                        oCollapsedGroupDrawingManager);
                }
                else
                {
                    // Default to something usable.

                    eShape = VertexShape.Disk;
                }
            }
            else if (eShape == VertexShape.Image)
            {
                Object oImageSourceAsObject;

                if (vertex.TryGetValue(ReservedMetadataKeys.PerVertexImage,
                    typeof(ImageSource), out oImageSourceAsObject)
                    )
                {
                    // Draw the vertex as an image.

                    vertexDrawingHistory = DrawImageShape(vertex,
                        graphDrawingContext, oDrawingContext, oDrawingVisual,
                        eVisibility, bDrawAsSelected, sLabel,
                        (ImageSource)oImageSourceAsObject, oVertexLabelDrawer,
                        oCollapsedGroupDrawingManager);
                }
                else
                {
                    // Default to something usable.

                    eShape = VertexShape.Disk;
                }
            }

            if (vertexDrawingHistory == null)
            {
                // Draw the vertex as a simple shape.

                vertexDrawingHistory = DrawSimpleShape(vertex, eShape,
                    graphDrawingContext, oDrawingContext, oDrawingVisual,
                    eVisibility, bDrawAsSelected, sLabel, oVertexLabelDrawer,
                    oCollapsedGroupDrawingManager);
            }

            // Perform collapsed group tasks if necessary.

            oCollapsedGroupDrawingManager.PostDrawVertex(eShape,
                GetColor(vertex, eVisibility, bDrawAsSelected),
                graphDrawingContext, oDrawingContext, bDrawAsSelected,
                m_dGraphScale, oVertexLabelDrawer, m_oFormattedTextManager,
                vertexDrawingHistory);
        }

        return (true);
    }