Exemplo n.º 1
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));
        }