/// <summary> /// Считает расстояние от прямой aP - aQ до текущей точки. /// </summary> /// <param name="aP"></param> /// <param name="aQ"></param> /// <returns></returns> public double DistanceToLine(Point3D aP, Point3D aQ) { // A, B, c - коэфициенты прямой. var a = aQ.X - aP.X; var b = aQ.Y - aP.Y; var c = aQ.Z - aP.Z; var x0 = aP.X; var y0 = aP.Y; var z0 = aP.Z; var numerator = Math.Pow(b * (X - x0) - a * (Y - y0), 2) + Math.Pow(c * (Y - y0) - b * (Z - z0), 2) + Math.Pow(c * (X - x0) - a * (Z - z0), 2); var distance = Math.Sqrt(numerator) / Math.Sqrt(a * a + b * b + c * c); return distance; }
/// <summary> /// Накладывает искривление. /// </summary> /// <param name="centers"></param> /// <param name="flexConfiguration"></param> private void MakeFlexs(PointF[] aCenters, FlexConfiguration aFlex) { var centersCount = aCenters.Length; // укажем три точки на слитке. var a = aCenters[0]; var b = aCenters[centersCount - 1]; PointF c = new PointF(); var currentPosition = 0.0; var find = false; for (var i = 0; i < aCenters.Length; ++i) { if (currentPosition >= aFlex.Position) { c = aCenters[i]; find = true; break; } currentPosition += 1.0 * configuration.Length / centersCount; } if (!find) { throw new ArgumentException("MakeFlexs: положение искривления не в пределах размеров слитка."); } // Сдвинем точку C на заданное отклонение. c.Y -= (float)aFlex.Maximum; // Все точик лежат в плоскости YOZ, поэтому учитываем это. // теперь найдем центр и радиус окружности. var pa = new Point3D { X = 0, Y = a.Y, Z = 0 }; var pb = new Point3D { X = configuration.Length, Y = b.Y, Z = 0 }; var pc = new Point3D { X = aFlex.Position, Y = c.Y, Z = 0 }; var center = CalcCircleCenter(pa, pb, pc); var radius = CalcCircleDiameter(pa, pb, pc) / 2.0; // переведем центр обратно в систему координат. center.Z = center.X; center.X = 0; // теперь сдвигаем все точки в направлении радиус-вектора. currentPosition = 0.0; for (var i = 0; i < centersCount; ++i) { // dr: найдем разницу между радиусом и расстоянием от центра до точки. var pt = new Point3D { X = aCenters[i].X, Y = aCenters[i].Y, Z = currentPosition }; var dr = radius - center.DistanceToPoint(pt); // vr: найдем вектор радиуса и нормализуем его. var vr = new Point3D { X = pt.X - center.X, Y = pt.Y - center.Y, Z = pt.Z - center.Z }; var vsize = Math.Sqrt(vr.X * vr.X + vr.Y * vr.Y + vr.Z * vr.Z); vr.X /= vsize; vr.Y /= vsize; // теперь сдвинем исходную точку по направлению вектора на разницу. pt.X += dr * vr.X; pt.Y += dr * vr.Y; aCenters[i].X = (float)pt.X; aCenters[i].Y = (float)pt.Y; currentPosition += 1.0 * configuration.Length / centersCount; } }
/// <summary> /// Вычисляет диаметр описанной окружности. /// </summary> /// <param name="aA"></param> /// <param name="aB"></param> /// <param name="aC"></param> /// <returns>Диаметр.</returns> private double CalcCircleDiameter(Point3D aA, Point3D aB, Point3D aC) { // Формула: // D = a*b*c / 2 * sqrt(p*(p-a)*(p-b)*(p-c)), // где a,b,c - длины сторон треугольника, p - полупериметр треугольника. var a = aA.DistanceToPoint(aB); var b = aB.DistanceToPoint(aC); var c = aC.DistanceToPoint(aA); var p = (a + b + c) / 2.0; return (2 * a * b * c) / (4 * Math.Sqrt(p * (p - a) * (p - b) * (p - c))); }
/// <summary> /// Вычисляет центр описанной окружности. /// </summary> /// <returns></returns> private Point3D CalcCircleCenter(Point3D aA, Point3D aB, Point3D aC) { var epsilon = 0.0001; if (Math.Abs(aA.Z - aB.Z) > epsilon || Math.Abs(aA.Z - aC.Z) > epsilon) { throw new ArgumentException("CalcCircleCenter: точки находятся не в одной плоскости."); } // формула http://www.cyberforum.ru/geometry/thread1190053.html double x1 = aA.X, x2 = aB.X, x3 = aC.X, y1 = aA.Y, y2 = aB.Y, y3 = aC.Y; double x12 = x1 - x2, x23 = x2 - x3, x31 = x3 - x1, y12 = y1 - y2, y23 = y2 - y3, y31 = y3 - y1; double z1 = x1 * x1 + y1 * y1, z2 = x2 * x2 + y2 * y2, z3 = x3 * x3 + y3 * y3; double zx = y12 * z3 + y23 * z1 + y31 * z2, zy = x12 * z3 + x23 * z1 + x31 * z2, z = x12 * y31 - y12 * x31; return new Point3D { X = -zx / (2.0 * z), Y = zy / (2.0 * z), Z = aA.Z }; }
public double DistanceToPoint(Point3D aPoint) { return Math.Sqrt((aPoint.X - X) * (aPoint.X - X) + (aPoint.Y - Y) * (aPoint.Y - Y) + (aPoint.Z - Z) * (aPoint.Z - Z)); }