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)); }