Files
aistudio-wpf-diagram/AIStudio.Wpf.DiagramDesigner/Helpers/SegmentHelper.cs

86 lines
3.4 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Media;
2022-10-28 22:45:39 +08:00
namespace AIStudio.Wpf.DiagramDesigner
{
public class SegmentHelper
{
/// <summary>
/// 获得贝塞尔曲线
/// </summary>
/// <param name="currentPt">当前点</param>
/// <param name="lastPt">上一个点</param>
/// <param name="nextPt1">下一个点1</param>
/// <param name="nextPt2">下一个点2</param>
/// <returns></returns>
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;
}
/// <summary>
/// 过c点做A和B连线的垂足
/// </summary>
/// <param name="aPoint"></param>
/// <param name="bPoint"></param>
/// <param name="cPoint"></param>
/// <returns></returns>
private static Point GetFootPoint(Point aPoint, Point bPoint, Point cPoint)
{
//设三点坐标是ABCAB构成直线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));
}
}
}