Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.69/13: Рейтинг темы: голосов - 13, средняя оценка - 4.69
0 / 0 / 0
Регистрация: 29.10.2014
Сообщений: 14

Скруглить улгы многоугольника

27.09.2015, 23:09. Показов 2788. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
На форме я ставлю точки и рисую по ним полигон, затем "обрезаю" углы, чтобы потом туда нарисовать дугу. И вроде бы все рассчитал, но все равно верно скруглять не хочет.

Функция отрисовки дуг

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void Go(PointF ver1, PointF ver2, PointF ver3, float radius, PointF firstPoint, PointF secondPoint, Graphics g)
    {
        PointF center = new PointF(); // точка пересечения прямых, перпендикулярных сторонам угла и проходящих через точки касания
 
        Line firstLine = new Line (ver2, ver1 );
        Line secondLine = new Line (ver2,ver3);
 
        firstLine = Line.GetReverseLine(firstLine, firstPoint);
        secondLine = Line.GetReverseLine(secondLine, secondPoint);
 
        center = Line.Cross(firstLine, secondLine);
 
        PointF vector = new PointF(1, 0);
        PointF startVect = new PointF(firstPoint.X - center.X, firstPoint.Y - center.Y); //вектор начала дуги
        PointF endVect = new PointF(secondPoint.X - center.X, secondPoint.Y - center.Y);
 
        float angleBetweenSEVectors = Vector.AngleBetweenVectors(startVect, endVect) * 180 / (float)Math.PI;
 
        float angleStartVect = Vector.AngleBetweenVectors(vector, startVect) * 180 / (float)Math.PI;
        float angleEndVect = Vector.AngleBetweenVectors(vector, endVect) * 180 / (float)Math.PI;
 
        if (firstPoint.Y <= center.Y)
        {
            angleStartVect = 360 - angleStartVect;
        }
        if (secondPoint.Y <= center.Y)
        {
            angleEndVect = 360 - angleEndVect;
        }
 
        if (angleStartVect >= angleEndVect)
        {
            float tmp = angleStartVect;
            angleStartVect = angleEndVect;
            angleEndVect = tmp;
        }
 
        float angle;
        if (angleEndVect - angleStartVect < 180)
        {
            angle = angleStartVect;
        }
        else
        {
            angle = angleEndVect;
        }
 
        g.DrawArc(Pens.Blue, center.X, center.Y, radius * 2, radius * 2, angle, angleBetweenSEVectors);
    }

Класс Линии

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
class Line
{
        public Line(PointF point1, PointF point2)
        {
            k = (point1.Y - point2.Y)/(point1.X - point2.X);
            if (float.IsInfinity(k))
            {
                IsParallelY = true;
                x = point1.X;
            }
            b = point1.Y - k * point1.X;
        }
        public Line(float k, float b)
        {
            this.k = k;
            this.b = b;
        }
        public Line(float x)
        {
            this.x = x;
            IsParallelY = true;
        }
        float k, b, x;
        public float GetK
        {
            get { return k; }
        }
        public float GetB
        {
            get { return b; }
        }
        public float GetX
        {
            get { return x;}
        }
        public bool IsParallelY
        {
            get; private set;
        }
        public float Solve(float x)
        {
            return k * x + b;
        }
        public static Line GetReverseLine(Line line, PointF point)
        {
            float newK;
            if (line.IsParallelY)
            {
                newK = 0;
            }
            else
            {
                newK = -1 / line.GetK;
            }
            if (float.IsInfinity(newK))
            {
                return new Line(point.X);
            }
 
            float newB = point.Y - newK * point.X;
            return new Line(newK, newB);
 
        }
        public static PointF Cross(Line line1, Line line2)
        {
            if(line1.IsParallelY && line2.IsParallelY)
            {
                throw new Exception();
            }
            if (line1.IsParallelY)
            {
                return new PointF(line1.GetX, line2.Solve(line1.GetX));
            }
            if (line2.IsParallelY)
            {
                return new PointF(line2.GetX, line1.Solve(line2.GetX));
            }
            float x = (line2.GetB - line1.GetB) / (line1.GetK - line2.GetK);
            float y = line1.Solve(x);
            return new PointF(x, y);
        } 
    }

Класс работы с векторами

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Vector
{
    public static PointF NewVector(PointF p1, PointF p2)
    {
        return new PointF(p2.X - p1.X, p2.Y - p1.Y);
    }
    public static float LengthVector(PointF vector)
    {
        return (float)Math.Sqrt(vector.X * vector.X + vector.Y * vector.Y);
    }
    public static float ScalarMult(PointF vector1, PointF vector2)
    {
        return vector1.X * vector2.X + vector1.Y * vector2.Y;
    }
    public static float AngleBetweenVectors(PointF p1, PointF p2, PointF p3)
    {
        PointF v1 = NewVector(p1,p2);
        PointF v2 = NewVector(p2,p3);
        return (float)Math.Acos(Vector.ScalarMult(v1, v2) / (LengthVector(v1) * LengthVector(v2)));
    }
    public static float AngleBetweenVectors(PointF v1, PointF v2)
    {
        return (float)Math.Acos(ScalarMult(v1, v2) / (LengthVector(v1) * LengthVector(v2)));
    }
}
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
27.09.2015, 23:09
Ответы с готовыми решениями:

Скруглить углы многоугольника (полигона)
В общем есть задание построить многоугольник любой формы и закруглить его углы. Есть часть кода на построение многоугольника любой формы,...

Скруглить некоторые углы полигона
Суть проблемы: Есть массив точек соединив которые друг с другом получим полигон. Углы полигона нужно скруглить по определённому радиусу. На...

Как скруглить вокруг минусика
добрый день ! как скруглить вокруг минуса примерно как на фотографии я пробовал но не получается

3
 Аватар для ViterAlex
8951 / 4863 / 1886
Регистрация: 11.02.2013
Сообщений: 10,246
28.09.2015, 22:25
Свой класс для векторов изобретать не нужно. Он уже есть в WindowsBase.Dll в пространстве имён System.Windows.
Попробуй так. Берём массив вершин и на его основе создаём GraphicsPath, где вместо вершин — дуги сопряжения. Прямые между дугами добавляются автоматически. Созданный GraphicsPath можно рисовать.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/// <summary>
/// Прямоугольники, для центров дуг сопряжения
/// </summary>
static private RectangleF[] rects;
/// <summary>
/// Скругление углов многоугольника
/// </summary>
/// <param name="points">Массив с вершинами многоугольника</param>
/// <param name="radius">Радиус сопряжения</param>
/// <returns></returns>
static public GraphicsPath RoundCorners(PointF[] points, float radius) {
    GraphicsPath retval = new GraphicsPath();
    if (points.Length < 3) {
        throw new ArgumentException();
    }
    rects = new RectangleF[points.Length];
    PointF pt1, pt2;
    //Векторы сторон и нормали к ним. Векторы идут из вершины угла
    Vector v1, v2, n1 = new Vector(), n2 = new Vector();
    //Размер прямоугольника, ограничивающего дугу сопряжения
    SizeF size = new SizeF(2 * radius, 2 * radius);
    //Центр дуги сопряжения
    PointF center = new PointF();
 
    for (int i = 0; i < points.Length; i++) {
        //Выделение векторов, выходящих из вершины
        pt1 = points[i];//Первая вершина
        pt2 = points[i == points.Length - 1 ? 0 : i + 1];//Вторая вершина
        v1 = new Vector(pt2.X, pt2.Y) - new Vector(pt1.X, pt1.Y);//вектор одной стороны
        pt2 = points[i == 0 ? points.Length - 1 : i - 1];//третья вершина
        v2 = new Vector(pt2.X, pt2.Y) - new Vector(pt1.X, pt1.Y);//вектор второй стороны
        /// Направление нормали определяем по углу между векторами. Если переход
        /// от v1 к v2 идёт по часовой стрелке, то нормаль к v1 направлена по часовой, 
        /// а к v2 — против. Если переход от v1 к v2 идёт против часовой, то направления
        /// нормалей меняются.
        float sweepangle = (float)Vector.AngleBetween(v1, v2);
 
        if (sweepangle < 0) {//переход от v1 к v2 по часовой
            n1 = new Vector(v1.Y, -v1.X);
            n2 = new Vector(-v2.Y, v2.X);
        }
        else {
            n1 = new Vector(-v1.Y, v1.X);
            n2 = new Vector(v2.Y, -v2.X);
        }
                
        //Нормирование векторов
        n1.Normalize(); n2.Normalize();
        n1 *= radius; n2 *= radius;
        /// Точки, через которые проходят прямые, параллельные сторонам угла и пересекающиеся
        /// в центре сопряжения
        PointF pt = points[i];//Точка на стороне многоугольника (вершина)
        //Точка на прямой, параллельной v1
        pt1 = new PointF((float)(pt.X + n1.X), (float)(pt.Y + n1.Y));
        //Точка на прямой, параллельной v2
        pt2 = new PointF((float)(pt.X + n2.X), (float)(pt.Y + n2.Y));
        double m1 = v1.Y / v1.X, m2 = v2.Y / v2.X;
        //Координаты центра сопряжения. Выводятся из уравнения прямой по вектору и точке
        if (v1.X == 0) {// первая сторона параллельна оси OY
            center.X = pt1.X;
            center.Y = (float)(m2 * (pt1.X - pt2.X) + pt2.Y);
        }
        else if (v1.Y == 0) {// первая сторона параллельна оси OX
            center.X = (float)((pt1.Y - pt2.Y) / m2 + pt2.X);
            center.Y = pt1.Y;
        }
        else if (v2.X == 0) {// первая сторона параллельна оси OY
            center.X = pt2.X;
            center.Y = (float)(m1 * (pt2.X - pt1.X) + pt1.Y);
        }
        else if (v2.Y == 0) {//вторая сторона параллельна оси OX
            center.X = (float)((pt2.Y - pt1.Y) / m1 + pt1.X);
            center.Y = pt2.Y;
        }
        else {
            center.X = (float)((pt2.Y - pt1.Y + m1 * pt1.X - m2 * pt2.X) / (m1 - m2));
            center.Y = (float)(pt1.Y + m1 * (center.X - pt1.X));
        }
        rects[i] = new RectangleF(center.X - 2, center.Y - 2, 4, 4);
        //Точки касания на сторонах
        n1.Negate(); n2.Negate();//Разворот нормалей
        pt1 = new PointF((float)(center.X + n1.X), (float)(center.Y + n1.Y));
        pt2 = new PointF((float)(center.X + n2.X), (float)(center.Y + n2.Y));
        RectangleF rect = new RectangleF(new PointF(center.X - radius, center.Y - radius), size);
        sweepangle = (float)Vector.AngleBetween(n2, n1);
        retval.AddArc(rect, (float)Vector.AngleBetween(new Vector(1, 0), n2), sweepangle);
    }
    retval.CloseAllFigures();
    return retval;
}
Центр сопрягающей дуги находится как точка пересечения прямых, параллельных сторонам угла и отстоящим от них на радиус сопряжения. Поясняющая картинка:

Результат работы. Вершины вводятся кликами по форме: левый клик — указать вершину, правый — очищает форму
Вложения
Тип файла: zip FilletPolygon.zip (10.9 Кб, 39 просмотров)
3
0 / 0 / 0
Регистрация: 29.10.2014
Сообщений: 14
30.09.2015, 10:27  [ТС]
ViterAlex, а как подключить класс Vector? библиотеку System.Windows то я подключил, но все равно класс вектора не видит.
0
 Аватар для ViterAlex
8951 / 4863 / 1886
Регистрация: 11.02.2013
Сообщений: 10,246
30.09.2015, 11:38
Нужно добавить ссылку на библиотеку WindowsBase.dll. Project→Add Reference...
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
30.09.2015, 11:38
Помогаю со студенческими работами здесь

Как скруглить углы у чекбокса
Подскажите как скруглить углы у чекбокса На каждый вопрос создавайте по одной теме! (Правила п.4.4)

Разделить изображение на части и скруглить углы
Приветсвую всех! Есть картинка, хочу получить каждую карту отдельно в png формате и с закругленными углами. Сделал раскройку картинки...

Как скруглить конус при построении бобышки по сечениям?
Гопода, представьте себе учеченный конус - в одной плоскости круг 100 мм, в другой очень маленький - 1 мм. Создаем по сечениям бобышку,...

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

замкнутость многоугольника
добрый вечер.пишу игру точки.подскажите,плз,как можно реализовать вычисление замкнутости многоугольника?вот как в рисунке:надо...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Программа принимает математическое выражение в виде строки и выдаёт его производную в виде строки и вычисляет значение производной при заданном х Логарифм записывается как: (x-2)log(x^2+2) -. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru