using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Media; namespace AIStudio.Wpf.DiagramDesigner { public class SegmentHelper { /// /// 获得贝塞尔曲线 /// /// 当前点 /// 上一个点 /// 下一个点1 /// 下一个点2 /// public static BezierSegment GetBezierSegment(Point currentPt, Point lastPt, Point nextPt1, Point nextPt2) { //计算中点 var lastC = GetCenterPoint(lastPt, currentPt); var nextC1 = GetCenterPoint(currentPt, nextPt1); //贝塞尔控制点 var nextC2 = GetCenterPoint(nextPt1, nextPt2); //计算相邻中点连线跟目的点的垂足 //效果并不算太好,因为可能点在两个线上或者线的延长线上,计算会有误差 //所以就直接使用中点平移方法。 //var C1 = GetFootPoint(lastC, nextC1, currentPt); //var C2 = GetFootPoint(nextC1, nextC2, nextPt1); //计算“相邻中点”的中点 var c1 = GetCenterPoint(lastC, nextC1); var c2 = GetCenterPoint(nextC1, nextC2); //计算【"中点"的中点】需要的点位移 var controlPtOffset1 = currentPt - c1; var controlPtOffset2 = nextPt1 - c2; //移动控制点 var controlPt1 = nextC1 + controlPtOffset1; var controlPt2 = nextC1 + controlPtOffset2; //如果觉得曲线幅度太大,可以将控制点向当前点靠近一定的系数。 controlPt1 = controlPt1 + 0 * (currentPt - controlPt1); controlPt2 = controlPt2 + 0 * (nextPt1 - controlPt2); var bzs = new BezierSegment(controlPt1, controlPt2, nextPt1, true); return bzs; } /// /// 过c点做A和B连线的垂足 /// /// /// /// /// private static Point GetFootPoint(Point aPoint, Point bPoint, Point cPoint) { //设三点坐标是A,B,C,AB构成直线,C是线外的点 //三点对边距离是a,b,c,垂足为D, //根据距离推导公式得:AD距离是(b平方-a平方+c平方)/2c //本人数学不好,可能没考虑点c在线ab上的情况 var offsetADist = (Math.Pow(cPoint.X - aPoint.X, 2) + Math.Pow(cPoint.Y - aPoint.Y, 2) - Math.Pow(bPoint.X - cPoint.X, 2) - Math.Pow(bPoint.Y - cPoint.Y, 2) + Math.Pow(aPoint.X - bPoint.X, 2) + Math.Pow(aPoint.Y - bPoint.Y, 2)) / (2 * GetDistance(aPoint, bPoint)); var v = bPoint - aPoint; var distab = GetDistance(aPoint, bPoint); var offsetVector = v * offsetADist / distab; return aPoint + offsetVector; } private static Point GetCenterPoint(Point pt1, Point pt2) { return new Point((pt1.X + pt2.X) / 2, (pt1.Y + pt2.Y) / 2); } private static double GetDistance(Point pt1, Point pt2) { return Math.Sqrt(Math.Pow(pt1.X - pt2.X, 2) + Math.Pow(pt1.Y - pt2.Y, 2)); } } }