Beispiel #1
0
        GetBounds()
        {
            AssertValid();

            if (m_oEdge.IsSelfLoop)
            {
                Debug.Assert(false);
                throw new InvalidOperationException("Edge is self-loop.");
            }

            // Start with a rectangle that has the same dimensions as the edge, but
            // that starts at the origin and has an angle of zero.

            Point oVertex1Location = WpfGraphicsUtil.PointFToWpfPoint(
                m_oEdge.Vertex1.Location);

            Point oVertex2Location = WpfGraphicsUtil.PointFToWpfPoint(
                m_oEdge.Vertex2.Location);

            Double dLength = WpfGraphicsUtil.GetDistanceBetweenPoints(
                oVertex1Location, oVertex2Location);

            Double dAngleDegrees = MathUtil.RadiansToDegrees(
                WpfGraphicsUtil.GetAngleBetweenPointsRadians(
                    oVertex1Location, oVertex2Location));

            Double dHalfWidth = m_dWidth / 2.0;

            Point[] ao4BoundingPoints = new Point[4] {
                new Point(0, -dHalfWidth),
                new Point(dLength, -dHalfWidth),
                new Point(dLength, dHalfWidth),
                new Point(0, dHalfWidth),
            };

            // Rotate the rectangle so it is at the same angle as the edge.

            TransformPoints(new RotateTransform(dAngleDegrees), ao4BoundingPoints);

            // Translate the rotated rectangle to the location of the edge's first
            // endpoint.

            TransformPoints(
                new TranslateTransform(oVertex1Location.X, oVertex1Location.Y),
                ao4BoundingPoints);

            // Create a PathGeometry from the bounding points.

            return(WpfPathGeometryUtil.GetPathGeometryFromPoints(
                       ao4BoundingPoints[0],
                       ao4BoundingPoints[1],
                       ao4BoundingPoints[2],
                       ao4BoundingPoints[3]
                       ));
        }
Beispiel #2
0
        GetBezierControlPoint
        (
            GraphDrawingContext oGraphDrawingContext,
            Point oEndpoint1,
            Point oEndpoint2,
            Double dBezierDisplacementFactor
        )
        {
            Debug.Assert(oGraphDrawingContext != null);
            Debug.Assert(dBezierDisplacementFactor >= 0);
            AssertValid();

            // This method finds the midpoint of the straight line between the two
            // endpoints, then calculates a point that is displaced from the
            // midpoint at a right angle.  This is analagous to pulling a taut
            // string at its midpoint.
            //
            // The calculations are based on the anonymous post "How Can I
            // Calculate The Cartesian Coordinates Of A The Third Corner Of A
            // Triangle If I Have The Lengths Of All Three Sides And The
            // Coordinates Of The First Two Corners?" at
            // http://www.blurtit.com/q9044151.html.

            // Point a, the first endpoint, is one vertex of a right triangle.

            Double dPointAX = oEndpoint1.X;
            Double dPointAY = oEndpoint1.Y;

            // Point b, the midpoint of the line between the two endpoints, is
            // another vertex of the right triangle.  The angle at b is 90 degrees.

            Double dPointBX = dPointAX + (oEndpoint2.X - dPointAX) / 2.0;
            Double dPointBY = dPointAY + (oEndpoint2.Y - dPointAY) / 2.0;

            // Side C connects points a and b.

            Double dSideCLength = WpfGraphicsUtil.GetDistanceBetweenPoints(
                new Point(dPointBX, dPointBY), oEndpoint1);

            // Side A connects points b and c, where c is the point we need to
            // calculate.  Make the length of A, which is the displacement
            // mentioned above, proportional to the length of the line between the
            // two endpoints, so that a longer line gets displaced more than a
            // shorter line.

            Double dSideALength = dSideCLength * dBezierDisplacementFactor;

            // Calculate the angle of the line between the two endpoints.

            Double dAbsAtan2 = Math.Abs(Math.Atan2(
                                            Math.Max(oEndpoint2.Y, dPointAY) - Math.Min(oEndpoint2.Y, dPointAY),
                                            Math.Max(oEndpoint2.X, dPointAX) - Math.Min(oEndpoint2.X, dPointAX)
                                            ));

            Rect oGraphRectangle = oGraphDrawingContext.GraphRectangle;

            if (dAbsAtan2 >= Math.PI / 4.0 && dAbsAtan2 <= 3.0 * Math.PI / 4.0)
            {
                // The line between the two endpoints is closer to vertical than
                // horizontal.
                //
                // As explained in the post mentioned above, the length of side A
                // can be negative or positive, depending on which direction point
                // c should be displaced.  The following adjustments to
                // dSideALength were determined experimentally.

                if (oEndpoint2.Y > dPointAY)
                {
                    dSideALength *= -1.0;
                }

                if (dPointBX - oGraphRectangle.Left <
                    oGraphRectangle.Right - dPointBX)
                {
                    dSideALength *= -1.0;
                }
            }
            else
            {
                // The line between the two endpoints is closer to horizontal than
                // vertical.

                if (oEndpoint2.X < dPointAX)
                {
                    dSideALength *= -1.0;
                }

                if (dPointBY - oGraphRectangle.Top <
                    oGraphRectangle.Bottom - dPointBY)
                {
                    dSideALength *= -1.0;
                }
            }

            // Calculate point c.

            Double dPointCX = dPointBX +
                              (dSideALength * (dPointAY - dPointBY)) / dSideCLength;

            Double dPointCY = dPointBY +
                              (dSideALength * (dPointBX - dPointAX)) / dSideCLength;

            // Don't let point c fall outside the graph's margins.

            return(WpfGraphicsUtil.MovePointWithinBounds(
                       new Point(dPointCX, dPointCY),
                       oGraphDrawingContext.GraphRectangleMinusMargin));
        }
Beispiel #3
0
        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();
        }