/// <summary> /// Проверка на непересечение круга с множеством кругов. /// </summary> /// <param name="point">Вектор размещения круга.</param> /// <param name="circle">Круг.</param> /// <param name="circles">Множество кругов.</param> /// <param name="height">Значение допустимой погрешности. Положительное число.</param> /// <returns>Возвращает True, если круг не пересекается ни с одним кругом заданного множества. False - в противном случае.</returns> protected static bool IsCheckedCircles(Circle circle, Circle[] circles, int length, double eps) { for (int i = 0; i < length; i++) if (Circle2dExt.Расширенное_расстояние(circle, circles[i]) < -eps) // !!! Необходимо учитывать погрешность? return false; return true; ; }
public Placing(double height, double length, Circle[] circles, double mu, double beta, double eps) : base(height, length, circles, eps) { index_strip = 2 * circles.Length; X = new double[index_strip + 1]; this.mu = mu; this.beta = beta; }
/// <summary> /// Получить точку пересечения границ круга и круга. /// </summary> /// <param name="circle_prev">Круг.</param> /// <param name="circle_next">Круг.</param> /// <returns>Точка пересечения (одна из двух).</returns> public static Point2d Точка_пересечения_границ(Geometric2dWithPointScalar circle_prev, Geometric2dWithPointScalar circle_next) { Vector2d vector = circle_next.Pole - circle_prev.Pole; Vector2d vector_ = vector._I_(false); double vector_vector = vector * vector; double pr = circle_prev.Scalar * circle_prev.Scalar / vector_vector; double nr = circle_next.Scalar * circle_next.Scalar / vector_vector; double vector_length = -(nr - pr - 1) / 2; double vector_length_ = Math.Sqrt(pr - vector_length * vector_length); return circle_prev.Pole + vector * vector_length + vector_ * vector_length_; }
/// <summary> /// Получить точку пересечения границ круга и полуплоскости. /// </summary> /// <param name="circle_prev">Круг.</param> /// <param name="plane_next">Полуплоскость.</param> /// <returns>Точка пересечения.</returns> public static Point2d Точка_пересечения_границ(Geometric2dWithPointScalar circle_prev, Plane2d plane_next) { Vector2d vector_prev = plane_next.Normal._I_(false); Vector2d vector = plane_next.Pole - circle_prev.Pole; double b = vector_prev * vector; double c = vector * vector - circle_prev.Scalar * circle_prev.Scalar; double d = b * b - c; if (d < 0) return null; else { double t = -b - Math.Sqrt(d); return plane_next.Pole + vector_prev * t; } }
private bool PointInTriple(Circle circle, Vertex<Geometric> vertex) { if (vertex.Somes.CircleDelone == null) return false; double ed = Circle2dExt.Расширенное_расстояние(circle, vertex.Somes.CircleDelone); bool point_in_triple = ed < 0; if (point_in_triple) { Vertex<Geometric> vertex_temp = vertex; do { point_in_triple = point_in_triple && Circle2dExt.Расширенное_расстояние(circle, vertex_temp.Cros.Somes.CircleDelone) > ed; vertex_temp = vertex_temp.Next; } while (vertex_temp != vertex); } return point_in_triple; }
public static void SetCircleDelone(this Vertex<Geometric2d> vertex, Circle circle_delone) { vertex.Prev.Somes.CircleDelone = circle_delone; vertex.Somes.CircleDelone = circle_delone; vertex.Next.Somes.CircleDelone = circle_delone; }
/// <summary> /// Получить точку близости второго рода для круга и множества (круг, круг). /// </summary> /// <param name="circle_this">Круг.</param> /// <param name="circle_prev">Круг.</param> /// <param name="circle_next">Круг.</param> /// <returns>Точка близости (одна из двух).</returns> public static Point2d Точка_близости_второго_рода(this Geometric2dWithPointScalar circle_this, Geometric2dWithPointScalar circle_prev, Geometric2dWithPointScalar circle_next) { return Точка_пересечения_границ(Годограф_функции_плотного_размещения(circle_prev, circle_this), Годограф_функции_плотного_размещения(circle_next, circle_this)); }
public static Polygon2d Отрезок(Circle circle_this, Plane2d plane) { Polygon2d polygon = new Polygon2d(); polygon.Add(circle_this.Pole - plane.Normal * circle_this.Scalar); polygon.Add(circle_this.Pole - plane.Normal * (circle_this.Scalar + Plane2dExt.Расширенное_расстояние(plane, circle_this))); return polygon; }
public static List<System.Drawing.PointF> Отрезок(Vertex<Geometric2d> vertex) { List<System.Drawing.PointF> points = new List<System.Drawing.PointF>(); double ed = Circle2dExt.Расширенное_расстояние(vertex.Somes.CircleDelone, vertex.Cros.Somes.CircleDelone) / 2; double k; int n = 100; Point2d point; Circle circle = new Circle { Pole = vertex.Somes.CircleDelone.Pole.Copy, Scalar = vertex.Somes.CircleDelone.Scalar + ed }; Circle circle_cros = new Circle { Pole = vertex.Cros.Somes.CircleDelone.Pole.Copy, Scalar = vertex.Cros.Somes.CircleDelone.Scalar + ed }; point = Circle2dExt.Точка_пересечения_границ(circle, circle_cros); if (point != null && !double.IsNaN(point.X) && !double.IsNaN(point.Y)) points.Add(new System.Drawing.PointF((float)point.X, (float)point.Y)); double ed_end; if (vertex.Prev.DataInVertex is Circle) ed_end = Geometric2dExt.Расширенное_расстояние(vertex.Somes.CircleDelone, (vertex.Prev.DataInVertex as Circle).Pole); else ed_end = 300; // TODO: Доделать! k = (ed_end - ed) / n; for (int i = 0; i < n; i++) { circle.Scalar += k; circle_cros.Scalar += k; point = Circle2dExt.Точка_пересечения_границ(circle, circle_cros); if (point != null && !double.IsNaN(point.X) && !double.IsNaN(point.Y)) points.Add(new System.Drawing.PointF((float)point.X, (float)point.Y)); } points.Reverse(); circle.Scalar = vertex.Somes.CircleDelone.Scalar + ed; circle_cros.Scalar = vertex.Cros.Somes.CircleDelone.Scalar + ed; if (vertex.Next.DataInVertex is Circle) ed_end = Geometric2dExt.Расширенное_расстояние(vertex.Somes.CircleDelone, (vertex.Next.DataInVertex as Circle).Pole) / 2; else ed_end = 300; k = (ed_end - ed) / n; for (int i = 0; i < n; i++) { circle.Scalar += k; circle_cros.Scalar += k; point = Circle2dExt.Точка_пересечения_границ(circle_cros, circle); if (point != null && !double.IsNaN(point.X) && !double.IsNaN(point.Y)) points.Add(new System.Drawing.PointF((float)point.X, (float)point.Y)); } return points; }
/// <summary> /// Получить серединную полуплоскость круга и круга. /// </summary> /// <param name="circle_prev">Круг.</param> /// <param name="circle_next">Круг.</param> /// <returns>Серединная полуплоскость.</returns> public static Plane2d Серединная_полуплоскость(Geometric2dWithPointScalar circle_prev, Geometric2dWithPointScalar circle_next) { return new Plane2d { Pole = circle_prev.Pole.Copy, Normal = (circle_next.Pole - circle_prev.Pole)._I_(false) }; }
public static void FillAndDraw(this Graphics graphics, Brush brush, Pen pen, Geometric2dWithPointScalar circle) { graphics.FillEllipse(brush, circle.ToRectangleF()); graphics.DrawEllipse(pen, circle.ToRectangleF()); }
public Placing(double height, Circle[] circles, double eps) : base(height, 0, circles, eps) { }
private bool Существует_точка_плотного_размещения_второго_рода(Circle circle, Vertex<Geometric2d> vertex) { if (circle.Scalar > vertex.Somes.CircleDelone.Scalar) return false; else if (circle.Scalar >= vertex.Cros.Somes.CircleDelone.Scalar) return true; else if (Функция_расширенного_расстояния_на_отрезке_монотонна(vertex)) // Придумать что-то другое? return false; else return 2 * circle.Scalar >= Geometric2dExt.Расширенное_расстояние(vertex.Prev.DataInVertex, vertex.Next.DataInVertex); }
public PlacingOpt(double height, double length, Circle[] circles, double mu, double beta, double eps) : base(height, length, circles, mu, beta, eps) { #region Временный код. //for (int i = 0; i < circles.Length; i++) // if (circles[i].Value > 1) // circles[i].Value -= 1; #endregion }
/// <summary> /// Получить серединную полуплоскость круга и полуплоскости. /// </summary> /// <param name="circle_prev">Круг.</param> /// <param name="plane_next">Полуплоскость.</param> /// <returns>Серединная полуплоскость.</returns> public static Plane2d Серединная_полуплоскость(Geometric2dWithPointScalar circle_prev, Plane2d plane_next) { return new Plane2d { Pole = circle_prev.Pole.Copy, Normal = plane_next.Normal._I_(true) }; }
/// <summary> /// Получить расширенное расстояние от круга до точки. /// </summary> /// <param name="circle_this">Круг.</param> /// <param name="point">Точка.</param> /// <returns>Расширенное расстояние.</returns> public static double Расширенное_расстояние(Geometric2dWithPointScalar circle_this, Point2d point) { return Point2dExt.Расширенное_расстояние(circle_this.Pole, point) - circle_this.Scalar; }
/// <summary> /// Получить годограф функции плотного размещения круга возле круга. /// </summary> /// <param name="circle_this">Круг.</param> /// <param name="circle">Круг.</param> /// <returns>Годограф функции плотного размещения.</returns> public static Geometric2dWithPointScalar Годограф_функции_плотного_размещения(Geometric2dWithPointScalar circle_this, Geometric2dWithPointScalar circle) { return new Geometric2dWithPointScalar { Pole = circle_this.Pole.Copy, Scalar = circle_this.Scalar + circle.Scalar }; }
/// <summary> /// Получить расширенное расстояние от круга до круга. /// </summary> /// <param name="circle_this">Круг.</param> /// <param name="circle">Круг.</param> /// <returns>Расширенное расстояние.</returns> public static double Расширенное_расстояние(Geometric2dWithPointScalar circle_this, Geometric2dWithPointScalar circle) { return Расширенное_расстояние(circle_this, circle.Pole) - circle.Scalar; }
public PlacingOptWithCloseModel(double height, double length, Circle[] circles, Vertex<Geometric2d> vertex, double mu, double beta, double eps) : base(height, length, circles, mu, beta, eps) { this.vertex = vertex; this.triples = VertexExtention.GetTriples(vertex); for (int i = 0; i < circles.Length; i++) circles[i].Id = i; }
public static List<System.Drawing.PointF> Отрезок(Vertex<Geometric> vertex) { List<System.Drawing.PointF> points = new List<System.Drawing.PointF>(); double ed = Circle2dExt.Расширенное_расстояние(vertex.Somes.CircleDelone, vertex.Cros.Somes.CircleDelone) / 2; double k = 0.1; Point2d point; Circle circle = new Circle { Pole = vertex.Somes.CircleDelone.Pole.Copy, Scalar = vertex.Somes.CircleDelone.Scalar + ed }; Circle circle_cros = new Circle { Pole = vertex.Cros.Somes.CircleDelone.Pole.Copy, Scalar = vertex.Cros.Somes.CircleDelone.Scalar + ed }; do { circle.Scalar += k; circle_cros.Scalar += k; point = Circle2dExt.Точка_пересечения_границ(circle, circle_cros); if (point != null) points.Add(new System.Drawing.PointF((float)point.X, (float)point.Y)); } while (Geometric2dExt.Расширенное_расстояние(vertex.Prev.DataInVertex as Geometric2d, point) > 0 && points.Count < 10000); circle.Scalar = vertex.Somes.CircleDelone.Scalar + ed; circle_cros.Scalar = vertex.Cros.Somes.CircleDelone.Scalar + ed; do { circle.Scalar += k; circle_cros.Scalar += k; point = Circle2dExt.Точка_пересечения_границ(circle_cros, circle); if (point != null) points.Insert(0, new System.Drawing.PointF((float)point.X, (float)point.Y)); } while (Geometric2dExt.Расширенное_расстояние(vertex.Next.DataInVertex as Geometric2d, point) > 0 && points.Count < 10000); return points; }
public PlacingWithCloseModel(double height, Circle[] circles, double eps) : base(height, 0, circles, eps) { length = 2 * height; #region Шаг 1. Создаём начальную модель, состоящую из сторон прямоугольника. !!!Потом переделать на полосу!!! Geometric2d border_1 = new Plane2d { Id = -1, Pole = new Point2d { X = 0, Y = 2 * height / 2 }, Normal = new Vector2d { X = 0, Y = -1 } }; Geometric2d border_2 = new Plane2d { Id = -2, Pole = new Point2d { X = 0, Y = 1 * height / 2 }, Normal = new Vector2d { X = 1, Y = 0 } }; Geometric2d border_3 = new Plane2d { Id = -3, Pole = new Point2d { X = 0, Y = 0 * height / 2 }, Normal = new Vector2d { X = 0, Y = +1 } }; Geometric2d border_4 = new Plane2d { Id = -4, Pole = new Point2d { X = length, Y = height / 2 }, Normal = new Vector2d { X = -1, Y = 0 } }; vertex = Vertex<Geometric2d>.CreateClosenessModel(border_1, border_2, border_3); vertex.BreakCrosBy(border_4); #endregion #region Шаг 2. Устанавливаем для полученных троек круги Делоне. !Для полосы можно не автоматизировать. Для многоугольника необходимо придумать автоматизацию. vertex.SetCircleDelone(new Circle { Pole = new Point2d { X = height / 2, Y = height / 2 }, Scalar = height / 2 }); vertex.Cros.SetCircleDelone(new Circle { Pole = new Point2d { X = length - height / 2, Y = height / 2 }, Scalar = height / 2 }); vertex.Prev.Cros.SetCircleDelone(new Circle { Pole = new Point2d { X = -height / 2, Y = height / 2 }, Scalar = 0 }); vertex.Cros.Prev.Cros.SetCircleDelone(new Circle { Pole = new Point2d { X = double.PositiveInfinity /*length + height / 2*/, Y = height / 2 }, Scalar = 0 }); #endregion length = 0; vertex = vertex.Cros.Next.Cros.Next; triples = vertex.GetTriples(); }
private void MainForm_MouseDown(object sender, MouseEventArgs e) { for (int index = 0; index < 10; ++index) { Vertex<Geometric> vertex = null; Vertex<Geometric> vertex_temp; #region Заполнение круга. //Circle circle = new Circle() { Pole = new Point2d { X = e.X, Y = e.Y } }; Circle circle = new Circle() { Pole = new Point2d { X = this.rand.Next(10, this.ClientSize.Width - 10), Y = this.rand.Next(10, this.ClientSize.Height - 10) } }; int k = -1; for (int i = 0; i < triples.Count && k == -1; i++) if (PointInTriple(circle, triples[i])) k = i; if (k > -1) { vertex = triples[k]; double radius_max = double.PositiveInfinity; vertex_temp = vertex; do { radius_max = Math.Min(Geometric2dExt.Расширенное_расстояние(circle, vertex_temp.DataInVertex as Geometric2d), radius_max); vertex_temp = vertex_temp.Next; } while (vertex_temp != vertex); circle.Scalar = radius_max * rand.NextDouble(); } #endregion if (vertex != null) { vertex.BreakCrosBy(circle); vertex = vertex.Cros; vertex_temp = vertex; do { while (Circle2dExt.Расширенное_расстояние(vertex_temp.DataInVertex as Circle, vertex_temp.Cros.Somes.CircleDelone) < 0) { vertex_temp.Rebuild(); } vertex_temp.SetCircleDelone(Geometric2dExt.Круг_Делоне(vertex_temp.Prev.DataInVertex as Geometric2d, vertex_temp.DataInVertex as Geometric2d, vertex_temp.Next.DataInVertex as Geometric2d)); vertex_temp = vertex_temp.Next.Cros.Next; } while (vertex_temp != vertex); triples = ClosenessModelExt<Geometric, Circle>.GetTriples(this.vertex); } Invalidate(); this.Refresh(); System.Threading.Thread.Sleep(100); } }
/// <summary> /// Проверка на попадание круга в полосу. /// </summary> /// <param name="point">Вектор размещения круга.</param> /// <param name="circle">Круг.</param> /// <param name="height">Высота полосы.</param> /// <returns>Возвращает True, если круг полностью лежит внутри полосы. False - в противном случае.</returns> protected bool IsCheckedStrip(Point2d point, Circle circle, double height) { return (point.Y + circle.Scalar <= height) && (point.X - circle.Scalar >= 0) && (point.Y - circle.Scalar >= 0); //!!! Необходимо учитывать погрешность. }
public static Polygon2d Отрезок(Circle circle_this, Circle circle) { Polygon2d polygon = new Polygon2d(); Vector2d vector = circle.Pole - circle_this.Pole; double length = Math.Sqrt(vector * vector); vector /= length; polygon.Add(circle_this.Pole + vector * circle_this.Scalar); polygon.Add(circle.Pole - vector * circle.Scalar); return polygon; }
/// <summary> /// Поиск локального минимума с использованием метода последовательного одиночного размещения. /// </summary> protected override void Calculate() { #region Шаг 1. Метод последовательного одиночного размещения. Для каждого круга... for (int i = 0; i < circles.Length; i++) { #region Шаг 1.1. Создание списка точек возможных размещений и добавление двух начальных точек. List<Point2d> points = new List<Point2d>(); points.Add(new Point2d { X = circles[i].Scalar, Y = circles[i].Scalar }); points.Add(new Point2d { X = circles[i].Scalar, Y = height - circles[i].Scalar }); #endregion #region Шаг 1.2. Создание и заполнение списка годографов. Circle[] godographs = new Circle[i]; for (int j = 0; j < i; j++) godographs[j] = Circle2dExt.Годограф_функции_плотного_размещения(circles[j], circles[i]); #endregion #region Шаг 1.3. Поиск точек пересечения круга с полосой. for (int j = 0; j < godographs.Length; j++) { #region Шаг 1.3.1. Поиск точек пересечения круга с левой границей полосы. if (godographs[j].Pole.X - godographs[j].Scalar < circles[i].Scalar) { double x = circles[i].Scalar - godographs[j].Pole.X; double y = Math.Sqrt(godographs[j].Scalar * godographs[j].Scalar - x * x); Point2d point; point = new Point2d { X = circles[i].Scalar, Y = godographs[j].Pole.Y - y }; if (IsCheckedStrip(point, circles[i], height)) points.Add(point); point = new Point2d { X = circles[i].Scalar, Y = godographs[j].Pole.Y + y }; if (IsCheckedStrip(point, circles[i], height)) points.Add(point); } #endregion #region Шаг 1.3.2. Поиск точек пересечения круга с нижней границей полосы. if (godographs[j].Pole.Y - godographs[j].Scalar < circles[i].Scalar) { double y = circles[i].Scalar - godographs[j].Pole.Y; double x = Math.Sqrt(godographs[j].Scalar * godographs[j].Scalar - y * y); Point2d point; point = new Point2d { X = godographs[j].Pole.X - x, Y = circles[i].Scalar }; if (IsCheckedStrip(point, circles[i], height)) points.Add(point); point = new Point2d { X = godographs[j].Pole.X + x, Y = circles[i].Scalar }; if (IsCheckedStrip(point, circles[i], height)) points.Add(point); } #endregion #region Шаг 1.3.3. Поиск точек пересечения круга с верхней границей полосы. if (godographs[j].Pole.Y + godographs[j].Scalar > height - circles[i].Scalar) { double y = height - circles[i].Scalar - godographs[j].Pole.Y; double x = Math.Sqrt(godographs[j].Scalar * godographs[j].Scalar - y * y); Point2d point; point = new Point2d { X = godographs[j].Pole.X - x, Y = height - circles[i].Scalar }; if (IsCheckedStrip(point, circles[i], height)) points.Add(point); point = new Point2d { X = godographs[j].Pole.X + x, Y = height - circles[i].Scalar }; if (IsCheckedStrip(point, circles[i], height)) points.Add(point); } #endregion } #endregion #region Шаг 1.4. Поиск точек пересечения годографов. for (int j = 0; j < godographs.Length - 1; j++) for (int k = j + 1; k < godographs.Length; k++) { Point2d point; point = Circle2dExt.Точка_пересечения_границ(godographs[j], godographs[k]); if (point != null && IsCheckedStrip(point, circles[i], height)) points.Add(point); // Заменить на "Добавить в отсортированный набор данных". Лучше всего использовать бинарное взвешенное дерево. point = Circle2dExt.Точка_пересечения_границ(godographs[k], godographs[j]); if (point != null && IsCheckedStrip(point, circles[i], height)) points.Add(point); // Заменить на "Добавить в отсортированный набор данных". Лучше всего использовать бинарное взвешенное дерево. } #endregion #region Шаг 1.5. Сортировка набора точек возможного размещения.!!! Данная часть не нужна, если использовать сортировку при вставке точек в набор данных. for (int j = 0; j < points.Count - 1; j++) for (int k = j + 1; k < points.Count; k++) if (points[j].X > points[k].X || (points[j].X == points[k].X && points[j].Y > points[k].Y)) { Point2d temp_point = points[j]; points[j] = points[k]; points[k] = temp_point; } #endregion #region Шаг 1.6. Выбор наилучшей точки размещения, при которой не возникает пересечение кругов и размещение круга. int p = -1; do { p++; circles[i].Pole.Copy = points[p]; } while (!IsCheckedCircles(circles[i], circles, i, eps)); #endregion #region Шаг 1.7. Пересчёт ширины занятой части полосы. length = Math.Max(length, circles[i].Pole.X + circles[i].Scalar); #endregion } #endregion }
/// <summary> /// Получить годограф функции плотного размещения круга возле полуплоскости. /// </summary> /// <param name="plane_this">Полуплоскость.</param> /// <param name="circle">Круг.</param> /// <returns>Годограф функции плотного размещения.</returns> public static Plane2d Годограф_функции_плотного_размещения(Plane2d plane_this, Geometric2dWithPointScalar circle) { return new Plane2d() { Pole = plane_this.Pole + plane_this.Normal * circle.Scalar, Normal = plane_this.Normal }; }