Smrf.NodeXL.Visualization.Wpf.DrawerBase.GetBezierControlPoint C# (CSharp) Method

GetBezierControlPoint() protected method

protected GetBezierControlPoint ( GraphDrawingContext oGraphDrawingContext, Point oEndpoint1, Point oEndpoint2, Double dBezierDisplacementFactor ) : Point
oGraphDrawingContext GraphDrawingContext
oEndpoint1 Point
oEndpoint2 Point
dBezierDisplacementFactor Double
return Point
    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) );
    }