Как визуально соединить 2 круга?

голоса
1

Мы знаем 2 круга»х и у центрального положения, а радиус те же. Я хочу, чтобы визуально соединить круги без зацикливания раздаточного эллипса для каждой точки на линии, что соединит это центр 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));
Задан 20/10/2018 в 13:04
источник пользователем
На других языках...                            


3 ответов

голоса
0

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

  circle1x;
    circle1y;

circle2x;
circle2y;


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

draw circle at midx midy;

Повторяю для midx midy, в обоих направлениях. добавить еще один круг. честно человек, это разве стоит, для того, чтобы сделать ее гладкой, вам потребуется несколько кругов. Вам нужно нарисовать овал с помощью центра обоих кругов в двух центрах овала

Ответил 20/10/2018 в 13:34
источник пользователем

голоса
5

Как и другие ответы до сих пор немного пропустить правильное решение, вот один , который соединяет два круга одинакового размера :

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

введите описание изображения здесь

Заметки:

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

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

  • комментарии Джими указывают на другое решение, которое делает использование GDI + трансформационных возможностей.

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

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

Ответил 21/10/2018 в 13:20
источник пользователем

голоса
6

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

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

Евклидово расстояние

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

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

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Угол определяется пересечением прямых линий, параллельных оси, которые пересекают центры окружностей.

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

Прямоугольный треугольниксинус Косинус

Использование координат центров окружностей, это может быть закодирована в 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));

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

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

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

Мы должны обратить наше Polygon позиционирование одна из коротких сторон - соответствующий диаметру круга, который является центром преобразования координат - в центре Cirle. Поэтому, когда будет применено вращение, это короткая сторона будет в середине этой трансформации, закрепленной в центр.

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

Центрирование и Поворот Polygon

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

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

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

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

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

Нарисованные фигуры Визуальный результат

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();
    }
}
Ответил 22/10/2018 в 00:41
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more