/// <summary> /// Находит точку, лежащую с противоположной стороны линии, отностильно заданной точки. /// </summary> /// <param name="p"> Заданная точка. </param> /// <param name="vec"> Линия. </param> /// <param name="points"> Набор всех точек. </param> /// <returns> Индекс найденной точки. </returns> public static int FindPointAcrossLine(Point3d p, VecLine vec, List<Point3d> points) { MoveCenter(ref p, ref vec, ref points); // Смещает центр координат. int indexMaxPoint = -1; float maxAngle = 0; // Проверка всех точек. for (int i = 0; i < points.Count; i++ ) { if (points[i].Y * p.Y < 0) // Если произведение меньше 0, то значит что точки лежат // с разных сторон оси Х. { var tempAngle = (float) SolveAngle(vec, points[i]); // Вычисляет угол. if (maxAngle < tempAngle && tempAngle > 0.001) // Если угол больше 0 и больше уже найденнго, то { maxAngle = tempAngle; // Запоминает найденный угол. indexMaxPoint = i; // Запоминает индекс точки. } else if (indexMaxPoint >= 0) // Если точка совпадает с началом или концом отрезка то берем ее. if (maxAngle == tempAngle && (points[i].Z == vec.Start.Z || points[i].Z == vec.End.Z)) { indexMaxPoint = i; } } } return indexMaxPoint; // Возвращает индекс найденной точки. }
public static void RotatePoint(ref Point3d p, float angle) { var x = (float)(p.X * Math.Cos(angle) - p.Y * Math.Sin(angle)); // новая координата по х. var y = (float)(p.X * Math.Sin(angle) + p.Y * Math.Cos(angle)); // новая координата по у. p.X = x; p.Y = y; }
public static Point3d Normal(Point3d a, Point3d b) { return new Point3d { X = (a.Y*b.Z - b.Y*a.Z), Y = (-(a.Z*b.Z - b.Z*a.Z)), Z = (a.X*b.Y - b.X*a.Y) }; }
public static void MoveCenter(ref Point3d p, ref VecLine vec, ref List<Point3d> points) { float dx = vec.Start.X; float dy = vec.Start.Y; float angle = vec.Angle(); Transform(ref p, dx, dy); Transform(ref vec, dx, dy); Transform(ref points, dx, dy); RotatePoint(ref p, -angle); RotatePoint(ref vec, -angle); RotatePoint(ref points, -angle); }
public static double Length(Point3d p1, Point3d p2) { return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2)); }
public static void Transform(ref Point3d p, float dx, float dy) { p.X -= dx; p.Y -= dy; }
public static double SolveAngle(VecLine vec, Point3d p) { double a = Length(p, vec.Start); double b = Length(p, vec.End); return Math.Acos((Math.Pow(a, 2) + Math.Pow(b, 2) - Math.Pow(vec.Length(), 2))/(2*a*b)); }
public VecLine(Point3d start, Point3d end) { Start = start; End = end; }
/// <summary> /// Строит триангуляцию заданного набора точек. /// </summary> /// <param name="points"> Заданный набор точек. </param> /// <returns> Результат триангуляции. </returns> public Triangles Triangulation(List<Point3d> points) { var triangles = new Triangles(); // Первоначальное задание точек P1, P2, P3. var p1 = new Point3d(points[0].X, points[0].Y, points[0].Z, 0); var p2 = new Point3d(points[1].X, points[1].Y, points[1].Z, 1); var p3 = new Point3d(points[0].X - 2, points[0].Y, 0, -1); // Создание стека. var stack = new Stack<Point3d>(); // Помещаем точки в стек. stack.Push(p3); stack.Push(p2); stack.Push(p1); while (stack.Count > 0) // Пока стек не пуст. { // Снимаем точки со стека. p1 = stack.Pop(); p2 = stack.Pop(); p3 = stack.Pop(); int index; // Получаем массив точек. var tempPoints = new List<Point3d>(); for (int i = 0; i < points.Count; i++ ) tempPoints.Add(new Point3d(points[i])); // Начальная и конечная точки линии P1 P2 Point3d tempPS; Point3d tempPE; if (p2 > p1) // Конец должен быть дальше начала. { tempPS = new Point3d(p1); tempPE = new Point3d(p2); } else { tempPS = new Point3d(p2); tempPE = new Point3d(p1); } // Если точка с другой стороны прямой найдена, то про возваращается ее индекс > -1 if ((index = MyMath.FindPointAcrossLine(new Point3d(p3), new VecLine(new Point3d(tempPS), new Point3d(tempPE)), tempPoints)) > -1) { // Создаем триугольник с найднной точкой. var tempTriangle = new Triangle(tempPE, tempPS, points[index]); if (!triangles.ifHas(tempTriangle)) // Если в списке триугольников еще нет этого { // то добавляем его в списко триугольников triangles.Add(new Triangle(tempPE, tempPS, points[index])); // Добавляем вершины в стек. stack.Push(p1); stack.Push(points[index]); stack.Push(p2); stack.Push(p2); stack.Push(points[index]); stack.Push(p1); } } } triangles.SolveMaxMin(); // Рассчитывает максимальное и минимальное значение вершины Z. return triangles; // Возвращает список треугольников. }