Как визуально соединить 2 круга? - PullRequest
0 голосов
/ 20 октября 2018

Мы знаем 2 круга 'x и y центральную позицию, а радиус такой же.Я хочу визуально соединить круги, не зацикливая эллипс рисования для каждой точки на линии, которая соединяет центр 2 круга.

Отсюда:

Кэто:

Код:

int radius = 75;

int x1 = 100;
int y1 = 200;

int x2 = 300;
int y2 = 100;

g.FillEllipse(Brushes.Blue, new Rectangle(x1 - radius / 2, y1 - radius / 2, radius, radius));
g.FillEllipse(Brushes.Blue, new Rectangle(x2 - radius / 2, y2 - radius / 2, radius, radius));

Ответы [ 3 ]

0 голосов
/ 21 октября 2018

Поскольку другие ответы пока что немного пропускают правильное решение, вот то, которое соединяет два круга одинакового размера :

using (Pen pen = new Pen(Color.Blue, radius)
 { EndCap = LineCap.Round, StartCap = LineCap.Round }  )
     g.DrawLine(pen, x1, y1, x2, y2);

enter image description here

Примечания:

  • Обычно рекомендуется установить режим сглаживания графического объекта на сглаживание.

  • Чтобы соединить два круга разных размеров, потребуется некоторая математика для вычисления четырех внешних точек касания .Из них можно получить многоугольник для заполнения или, при необходимости, создать GraphicsPath для заполнения, если цвет имеет альфа <1. </p>

  • Комментарии Джими указывают надругое решение, использующее возможности преобразования GDI +.

  • В некоторых ответах или комментариях желаемая форма обозначается как овал .Хотя это нормально в обычной речи, здесь, особенно когда упоминаются книги по геометрии, это неправильно, поскольку овал не будет иметь никаких прямых линий.

  • Как заметил Джими, то, что вы называете радиус - это действительно диаметр кругов.Я оставил неправильный термин в коде, но вы не должны !

0 голосов
/ 22 октября 2018

Решение для случаев, когда Круги не имеют одинаковый диаметр.

Первая необходимая информация - это расстояние между центрами двух кругов.
Для вычисления мы используем Евклидово расстояние , применяемое к декартовой плоскости:

Euclidean Distance

Где (x1, y1) и (x2, y2) - координатыЦентры двух Кругов.
Нам также нужно знать Направление (выраженное как положительное или отрицательное значение): вычисленное [Distance] всегда будет положительным.

в C# it, это может быть закодировано как:

float Direction = (Circle1Center.X > Circle2Center.X) ? -1 : 1;
float Distance = (float)Math.Sqrt(Math.Pow(Circle1Center.X - Circle2Center.X, 2) + 
                                  Math.Pow(Circle1Center.Y - Circle2Center.Y, 2));
Distance *= Direction;

Теперь у нас есть расстояние между центрами двух кругов, которое также выражает направление.
Нам также нужно знать, как эта виртуальная линия- Соединение двух Центров - вращается относительно нашей плоскости чертежа.На рисунке ниже расстояние можно рассматривать как гипотенузу прямоугольного h = (A, B).Угол C определяется пересечением прямых, параллельных оси, которые пересекают центры кругов.

Нам нужно вычислить угол Theta (θ).
Используя теорему Пифагора , мы можем получить, что синус угла тета равен Sinθ = b/h (как на рисунке)

Right TriangleSine Cosinus

Используя координаты центров окружностей, это можно кодировать в C# как:
(Distance - гипотенуза треугольника)

float SinTheta = (Math.Max(Circle1Center.Y, Circle2Center.Y) - 
                  Math.Min(Circle1Center.Y, Circle2Center.Y)) / Distance;

SinTheta выражает угол в Radians.Нам нужен угол, выраженный в Degrees: объект Graphics использует эту меру для своих функций преобразования мира.

float RotationAngle = (float)(Math.Asin(SinTheta) * (180 / Math.PI));

Теперь нам нужно построить Connector , форма, которая связывает 2 круга.Нам нужен полигон;a Прямоугольник не может иметь разные пары сторон (мы рассматриваем круги с разными диаметрами).
Этот многоугольник будет иметь более длинные стороны = до расстояния между центрами кругов, более короткие стороны = до диаметров кругов.

Для построения многоугольника мы можем использовать как Graphics.DrawPolygon , так и GraphicsPath.AddPolygon .Я выбираю метод GraphicsPath, потому что GraphicsPath может содержать более одной фигуры, и эти фигуры могут взаимодействовать , в некотором роде.

To соедините 2 рассматриваемых Круга с Полигоном, нам нужно повернуть Полигон, используя ранее вычисленный RotationAngle.
Простой способ выполнить вращение, это переместить мировые координаты в Центр одного изКруги, используя метод Graphics.TranslateTransform , затем вращайте новые координаты, используя Graphics.RotateTransform .

. Нам нужно нарисовать наш полигон, позиционируя одно изкороткие стороны - соответствующие диаметру окружности, которая является центром преобразования координат - в центре окружности.Следовательно, когда будет применено вращение, его короткая сторона будет находиться в середине этого преобразования, привязанного к центру.

Здесь figure 3 показывает расположение многоугольника (желтая форма) (хорошо, это похоже на прямоугольник, не говоря уже о);
в figure 4 тот же самый многоугольник после вращения.

Centering and Rotating a Polygon

Примечания:
Как указывало TaW , этот рисунок должен быть выполнен с использованием SolidBrush с непрозрачным цветом, что несколько разочаровывает.
Хорошополупрозрачная кисть не запрещена, но перекрывающиеся фигуры будут иметь другой цвет, сумма прозрачных цветов пересечений.

Однако возможноНарисуйте фигуры, используя полупрозрачную кисть без изменения цвета, используя способность GraphicsPath для заливки фигур, используя цвет, который применяется ко всем перекрывающимся частям.Нам просто нужно изменить значение по умолчанию FillMode (см. Пример в Документах), установив его на FillMode.Winding.

Пример кода:
В этом примере две пары кругов нарисованы в графическом контексте.Затем они соединяются с многоугольной формой, созданной с использованием GraphicsPath.AddPolygon().
(Конечно, нам нужно использовать событие Paint отрисовываемого элемента управления, здесь форму)

перегруженная вспомогательная функция принимает как положение центров окружностей, выраженное в виде PointF, так и RectangleF структуры, представляющей границы окружностей.

Это визуальный результат с полными цветами и использованиемполупрозрачная кисть:

Drawn Shapes Visual result

using System.Drawing;
using System.Drawing.Drawing2D;

private float Radius1 = 30f;
private float Radius2 = 50f;

private PointF Circle1Center = new PointF(220, 47);
private PointF Circle2Center = new PointF(72, 254);
private PointF Circle3Center = new PointF(52, 58);
private PointF Circle4Center = new PointF(217, 232);


private void form1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.CompositingQuality =  CompositingQuality.GammaCorrected;
    e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

    DrawLinkedCircles(Circle1Center, Circle2Center, Radius1, Radius2, Color.FromArgb(200, Color.YellowGreen), e.Graphics);
    DrawLinkedCircles(Circle3Center, Circle4Center, Radius1, Radius2, Color.FromArgb(200, Color.SteelBlue), e.Graphics);

    //OR, passing a RectangleF structure
    //RectangleF Circle1 = new RectangleF(Circle1Center.X - Radius1, Circle1Center.Y - Radius1, Radius1 * 2, Radius1 * 2);
    //RectangleF Circle2 = new RectangleF(Circle2Center.X - Radius2, Circle2Center.Y - Radius2, Radius2 * 2, Radius2 * 2);

    //DrawLinkedCircles(Circle1, Circle2, Color.FromArgb(200, Color.YellowGreen), e.Graphics);
}

Вспомогательная функция:

public void DrawLinkedCircles(RectangleF Circle1, RectangleF Circle2, Color FillColor, Graphics g)
{
    PointF Circle1Center = new PointF(Circle1.X + (Circle1.Width / 2), Circle1.Y + (Circle1.Height / 2));
    PointF Circle2Center = new PointF(Circle2.X + (Circle2.Width / 2), Circle2.Y + (Circle2.Height / 2));
    DrawLinkedCircles(Circle1Center, Circle2Center, Circle1.Width / 2, Circle2.Width / 2, FillColor, g);
}

public void DrawLinkedCircles(PointF Circle1Center, PointF Circle2Center, float Circle1Radius, float Circle2Radius, Color FillColor, Graphics g)
{
    float Direction = (Circle1Center.X > Circle2Center.X) ? -1 : 1;
    float Distance = (float)Math.Sqrt(Math.Pow(Circle1Center.X - Circle2Center.X, 2) +
                                      Math.Pow(Circle1Center.Y - Circle2Center.Y, 2));
    Distance *= Direction;

    float SinTheta = (Math.Max(Circle1Center.Y, Circle2Center.Y) -
                      Math.Min(Circle1Center.Y, Circle2Center.Y)) / Distance;

    float RotationDirection = (Circle1Center.Y > Circle2Center.Y) ? -1 : 1;
    float RotationAngle = (float)(Math.Asin(SinTheta) * (180 / Math.PI)) * RotationDirection;

    using (GraphicsPath path = new GraphicsPath(FillMode.Winding))
    {
        path.AddEllipse(new RectangleF(-Circle1Radius, -Circle1Radius, 2 * Circle1Radius, 2 * Circle1Radius));
        path.AddEllipse(new RectangleF(-Circle2Radius + (Math.Abs(Distance) * Direction),
                                       -Circle2Radius, 2 * Circle2Radius, 2 * Circle2Radius));
        path.AddPolygon(new[] {
            new PointF(0, -Circle1Radius),
            new PointF(0, Circle1Radius),
            new PointF(Distance, Circle2Radius),
            new PointF(Distance, -Circle2Radius),
        });
        path.AddEllipse(new RectangleF(-Circle1Radius, -Circle1Radius, 2 * Circle1Radius, 2 * Circle1Radius));
        path.AddEllipse(new RectangleF(-Circle2Radius + (Math.Abs(Distance) * Direction),
                                       -Circle2Radius, 2 * Circle2Radius, 2 * Circle2Radius));

        path.CloseAllFigures();

        g.TranslateTransform(Circle1Center.X, Circle1Center.Y);
        g.RotateTransform(RotationAngle);

        using (SolidBrush FillBrush = new SolidBrush(FillColor)) {
            g.FillPath(FillBrush, path);
        }
        g.ResetTransform();
    }
}
0 голосов
/ 20 октября 2018

Псевдо стиль:

  circle1x;
    circle1y;

circle2x;
circle2y;


midx=circle1x-circle2x;
midy=circle2x-circle2x;

draw circle at midx midy;

Повторите для Midy Midy, в обоих направлениях.добавить еще один круг.Честно говоря, это не стоит того, чтобы сделать это гладко, вам понадобится несколько кругов.вам нужно нарисовать овал, используя центр обоих кругов как два центра вашего овала

...