예제 #1
0
        /// <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
            };
        }
예제 #5
0
 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));
 }