You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
4.4 KiB

using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Media3D;
namespace SparkClient.Views.UserControl.ViewportData.Helper
{
internal class LineCalculationHelper
{
private readonly float Y = -0.01F;
private Vector3 point1;
private Vector3 center;
/// <summary>
/// 常数a(y=ax+b)
/// </summary>
private float a;
/// <summary>
/// 常数b(y=ax+b)
/// </summary>
private float b;
public LineCalculationHelper(Vector3 point1, Vector3 center) {
this.point1 = point1;
this.center = center;
this.a = calA(point1, center);
this.b = calB(point1, a);
}
/// <summary>
/// 常数a的计算
/// </summary>
/// <param name="point1"></param>
/// <param name="center"></param>
/// <returns></returns>
private float calA(Vector3 point1, Vector3 center)
{
return (point1.Z - center.Z) / (point1.X - center.X);
}
/// <summary>
/// 常数b的计算
/// </summary>
/// <param name="point1"></param>
/// <param name="a"></param>
/// <returns></returns>
private float calB(Vector3 point1, float a)
{
return -(a * point1.X)+point1.Z;
}
public Tuple<Vector3, Vector3> calXline(float length)
{
var twoPoint = CalculatePointsOnLine(this.a,length);
var x1 = twoPoint.p1.X;
var z1 = twoPoint.p1.Y;
var x2 = twoPoint.p2.X;
var z2 = twoPoint.p2.X;
return new Tuple<Vector3, Vector3>(new Vector3(x1, Y, z1), new Vector3(x2, Y, z2));
}
public Tuple<Vector3, Vector3> calYline(float length)
{
var twoPoint = CalculatePointsOnLine(-(1/a), length);
var x1 = twoPoint.p1.X;
var z1 = twoPoint.p1.Y;
var x2 = twoPoint.p2.X;
var z2 = twoPoint.p2.X;
return new Tuple<Vector3, Vector3>(new Vector3(x1, Y, z1), new Vector3(x2, Y, z2));
}
public Tuple<Vector3, Vector3> calLineOfOffset(Tuple<Vector3, Vector3> tuple, float d)
{
var point1 = tuple.Item1;
var point2 = tuple.Item2;
var x1 = point1.X - d * (point2.Z - point1.Z)/
(float)Math.Sqrt(Square(point2.X - point1.X) + Square(point2.Z - point1.Z));
var z1 = point1.Z + d * (point2.X - point1.X) /
(float)Math.Sqrt(Square(point2.X - point1.X) + Square(point2.Z - point1.Z));
var x2 = point2.X - d * (point2.Z - point1.Z) /
(float)Math.Sqrt(Square(point2.X - point1.X) + Square(point2.Z - point1.Z));
var z2 = point2.Z + d * (point2.X - point1.X) /
(float)Math.Sqrt(Square(point2.X - point1.X) + Square(point2.Z - point1.Z));
return new Tuple<Vector3, Vector3>(new Vector3(x1, Y, z1), new Vector3(x2, Y, z2));
}
float Square(float number)
{
return number * number;
}
public float calZ(float x, float offset = 0)
{
return a * x + b + offset;
}
public float calZVertical(float x, float offset = 0)
{
return (-x / a) + b + offset;
}
private ((float X, float Y) p1, (float X, float Y) p2) CalculatePointsOnLine(float k ,float L)
{
float x0 = center.X;
float y0 = center.Z;
// 将距离公式展开并整理为关于 t 的二次方程
float A = 1 + k * k;
float B = -2 * x0 + 2 * k * (b - y0);
float C = x0 * x0 + (b - y0) * (b - y0) - L * L;
// 计算判别式
float discriminant = B * B - 4 * A * C;
if (discriminant < 0)
{
throw new InvalidOperationException("无解:距离 L 太小,无法找到满足条件的点。");
}
// 计算 t 的两个解
float t1 = (float)(-B + Math.Sqrt(discriminant)) / (2 * A);
float t2 = (float)(-B - Math.Sqrt(discriminant)) / (2 * A);
// 计算两点坐标
var p1 = (X: t1, Y: k * t1 + b);
var p2 = (X: t2, Y: k * t2 + b);
return (p1, p2);
}
}
}