Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.80/15: Рейтинг темы: голосов - 15, средняя оценка - 4.80
 Аватар для xamelione25
-4 / 5 / 2
Регистрация: 04.02.2013
Сообщений: 1,860

Рисование кривой совместно с использованием алгоритма отсечения Коэна-Сазерленда

01.02.2021, 13:49. Показов 2890. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Помогите подкорректировать код под задание (помимо всего-прочего у меня выскакивают ошибки по 83 и 84 строке):
в оконном приложении должно рисовать кривые согласно функциям (см. ниже), и использовать метода отсечения Коэна-Сазерленда (по нему уже сделан код, но он мне выбивает ошибку - не пойму как исправить).

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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
static float Wxlef = 0.0,   /* Координаты левого нижнего и */
Wybot = 0.0,   /* правого верхнего углов окна */
Wxrig = 7.0,   /* отсечения                   */
Wytop = 5.0;
 
/* Глобальные скаляры для алгоритма Кируса-Бека
 * отсечения по многоугольному окну
 */
 
 /* Координаты прямоугольного окна */
static float Wxrect[4] = { 0.0, 0.0, 7.0, 7.0 };
static float Wyrect[4] = { 0.0, 5.0, 5.0, 0.0 };
 
/* Перпендикуляры к сторонам прямоугольного окна */
static float WxNrec[4] = { 1.0,  0.0, -1.0, 0.0 };
static float WyNrec[4] = { 0.0, -1.0,  0.0, 1.0 };
 
/* Данные для многоугольного окна */
static int   Windn = 4;          /* Кол-во вершин у окна   */
static float* Windx = Wxrect,  /* Координаты вершин окна */
* Windy = Wyrect;
static float* Wnormx = WxNrec,  /* Координаты нормалей    */
* Wnormy = WyNrec;
 
 
/*--------------------------------------------------- V_CSclip
 * Реализует алгоритм отсечения Коэна-Сазерленда с
 * кодированием концов отсекаемого отрезка
 *
 * int  V_CSclip (float *x0, float *y0, float *x1, float *y1)
 *
 * Отсекает отрезок, заданный значениями координат его
 * точек (x0,y0), (x1,y1), по окну отсечения, заданному
 * глобальными скалярами Wxlef, Wybot, Wxrig, Wytop
 *
 * Конечным точкам отрезка приписываются коды,
 * характеризующие его положение относительно окна отсечения
 * по правилу:
 *
 *  1001 | 1000 | 1010
 *  -----|------|-----
 *       | Окно |
 *  0001 | 0000 | 0010
 *  -----|------|-----
 *  0101 | 0100 | 0110
 *
 *  Отрезок целиком видим если оба его конца имеют коды 0000
 *  Если логическое И кодов концов не равно 0, то отрезок
 *  целиком вне окна и он просто отбрасывается.
 *  Если же результат этой операции = 0, то отрезок
 *  подозрительный. Он может быть и вне и пересекать окно.
 *  Для подозрительных отрезков определяются координаты их
 *  пересечений с теми сторонами, с которыми они могли бы
 *  пересечься в соответствии с кодами концов.
 *  При этом используется горизонтальность и вертикальность
 *  сторон окна, что позволяет определить одну из координат
 *  без вычислений.
 *  Часть отрезка, оставшаяся за окном отбрасывается.
 *  Оставшаяся часть отрезка проверяется на возможность его
 *  принятия или отбрасывания целиком. Если это невозможно,
 *  то процесс повторяется для другой стороны окна.
 *  На каждом цикле вычислений конечная точка отрезка,
 *  выходившая за окно, заменяется на точку, лежащую или на
 *  стороне окна или его продолжении.
 *
 *  Вспомогательная процедура Code вычисляет код положения
 *  для конца отрезка.
 *
 */
 
static float  CSxn, CSyn;   /* Координаты начала отрезка */
static int  CScode(void)  /* Определяет код точки xn, yn */
{
    register int  i;
    i = 0;
    if (CSxn < Wxlef) ++i; else
        if (CSxn > Wxrig) i += 2;
    if (CSyn < Wybot) i += 4; else
        if (CSyn > Wytop) i += 8;
    return (i);
}  /* CScode */
 
int   V_CSclip(x0, y0, x1, y1) 
float * x0, * y0, * x1, * y1;
{
    float  CSxk, CSyk;   /* Координаты конца отрезка  */
    int    cn, ck,       /* Коды концов отрезка */
        visible,      /* 0/1 - не видим/видим*/
        ii, s;        /* Рабочие переменные  */
    float  dx, dy,      /* Приращения координат*/
        dxdy, dydx,    /* Наклоны отрезка к сторонам */
        r;            /* Рабочая переменная  */
 
    CSxk = *x1; CSyk = *y1;
    CSxn = *x1; CSyn = *y1; ck = CScode();
    CSxn = *x0; CSyn = *y0; cn = CScode();
 
    /* Определение приращений координат и наклонов отрезка
     * к осям. Заодно сразу на построение передается отрезок,
     * состоящий из единственной точки, попавшей в окно
     */
    dx = CSxk - CSxn;
    dy = CSyk - CSyn;
    if (dx != 0) dydx = dy / dx; else {
        if (dy == 0) {
            if (cn == 0 && ck == 0) goto out; else goto all;
        }
    }
    if (dy != 0) dxdy = dx / dy;
 
    /* Основной цикл отсечения */
    visible = 0;  ii = 4;
    do {
        if (cn & ck) break;       /* Целиком вне окна    */
        if (cn == 0 && ck == 0) { /* Целиком внутри окна */
            ++visible;  
            break;
        }
        if (!cn) {                /* Если Pn внутри окна, то */
            s = cn; cn = ck; ck = s;  /* перестить точки Pn,Pk и */
            r = CSxn; CSxn = CSxk; CSxk = r;  /* их коды, чтобы Pn  */
            r = CSyn; CSyn = CSyk; CSyk = r;  /* оказалась вне окна */
        }
        /* Теперь отрезок разделяется. Pn помещается в точку
         * пересечения отрезка со стороной окна.
         */
        if (cn & 1) {         /* Пересечение с левой стороной */
            CSyn = CSyn + dydx * (Wxlef - CSxn);
            CSxn = Wxlef;
        }
        else if (cn & 2) {  /* Пересечение с правой стороной*/
            CSyn = CSyn + dydx * (Wxrig - CSxn);
            CSxn = Wxrig;
        }
        else if (cn & 4) {  /* Пересечение в нижней стороной*/
            CSxn = CSxn + dxdy * (Wybot - CSyn);
            CSyn = Wybot;
        }
        else if (cn & 8) {  /*Пересечение с верхней стороной*/
            CSxn = CSxn + dxdy * (Wytop - CSyn);
            CSyn = Wytop;
        }
        cn = CScode();        /* Перевычисление кода точки Pn */
    } while (--ii >= 0);
    if (visible) {
    out:  *x0 = CSxn;  *y0 = CSyn;
        *x1 = CSxk;  *y1 = CSyk;
    }
all:
    return (visible);
}  /* V_CSclip */
https://www.cyberforum.ru/cgi-bin/latex.cgi?\begin{cases} & \ x=31*cos(t) + 5*cos(31*t/5)  \\  & \ y=31*sin(t) - 5*sin(31*t/5)  \end{cases}
https://www.cyberforum.ru/cgi-bin/latex.cgi?0\leq t\leq 10*\pi
Миниатюры
Рисование кривой совместно с использованием алгоритма отсечения Коэна-Сазерленда  
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
01.02.2021, 13:49
Ответы с готовыми решениями:

Реализация двумерного алгоритма отсечения отрезка Сазерленда-Коэна
Помогите, пожалуйста, с лабораторной работой. Описание алгоритма: Дано: прямоугольное окно с координатами (xl,ya),(xr,yb) верхнего...

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

Алгоритм отсечения Коэна-Сазерленда
Собственно как реализовать его? Например есть пикчер бокс на нём нарисовал квадрат. А вот как отсечь его... На паре да же сам...

12
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
01.02.2021, 13:56
Цитата Сообщение от xamelione25 Посмотреть сообщение
C++
1
2
int   V_CSclip(x0, y0, x1, y1) 
float * x0, * y0, * x1, * y1;
И как это понимать? Копипастить тоже уметь нужно.
0
 Аватар для xamelione25
-4 / 5 / 2
Регистрация: 04.02.2013
Сообщений: 1,860
01.02.2021, 13:57  [ТС]
zayats80888, я взял аналогично как здесь:
https://algolist.manual.ru/graphics/clip_seg.php
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
01.02.2021, 14:05
Цитата Сообщение от xamelione25 Посмотреть сообщение
я взял аналогично как здесь
С точки зрения синтаксиса языка C++, что означает процитированный мной фрагмент кода?
0
 Аватар для xamelione25
-4 / 5 / 2
Регистрация: 04.02.2013
Сообщений: 1,860
01.02.2021, 14:14  [ТС]
zayats80888, уж простите( я его не настолько хорошо знаю... C++

Я чаще всего с C# сталкивался .... Но я понимаю что там в них разницы особой нет...

Насколько я понимаю это объявление переменных с присваиванием им типа float

Но я такой конструкции как в первой строке не встречал...
Обычно только вторую....
Поэтому корректно объяснить не могу

C++
1
2
int V_CSclip(x0, y0, x1, y1) 
float x0, y0, x1, y1;
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
01.02.2021, 14:20
Цитата Сообщение от xamelione25 Посмотреть сообщение
Но я такой конструкции как в первой строке не встречал...
C++
1
2
3
4
5
6
7
8
// int V_CSclip(x0, y0, x1, y1) - это должно быть либо объявление функции, либо определение.
 // это объявление
int V_CSclip(x0, y0, x1, y1);
// это определение
int V_CSclip(x0, y0, x1, y1)
{
    // это тело функции, где находится выполняемый ей код
}
В С# как-то иначе?
0
 Аватар для xamelione25
-4 / 5 / 2
Регистрация: 04.02.2013
Сообщений: 1,860
01.02.2021, 14:26  [ТС]
zayats80888,
В С# как-то иначе?
Я ж и говорю что особой разницы то и нет....

Просто я уже и объявление и определением пытался методом тыка сделать... Ничего не помогло...

Да и сложность возникла с тем что везде показывается использование этого метода отсечением прямыми .... А у меня по заданию - кривые... Вот я и сел в лужу
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
01.02.2021, 14:32
Цитата Сообщение от xamelione25 Посмотреть сообщение
методом тыка
Это тупиковый метод...

Нашел у себя в заначке, делал когда-то давно, сейчас не проверял. Отсечение по нормализованным координатам(в диапазоне [-1, 1]). Нормализация делается условно так: normalized_coord = coord / resolution * 2.0f - 1.0f.
Кликните здесь для просмотра всего текста
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
    struct vec2f{ float x, y;};
 
    vec2f operator-(const vec2f& lh, const vec2f& rh)
    {
        return {lh.x - rh.x, lh.y - rh.y};
    }
//...
    struct clipper
    {
        enum region : uint32_t
        {
            INSIDE = 0,
            LEFT = 1,
            RIGHT = 1 << 1,
            BOTTOM = 1 << 2,
            TOP = 1 << 3
        };
 
        static constexpr float border = 1;
 
        static uint32_t clip_point(const vec2f& point)
        {
            uint32_t result = INSIDE;
            if (point.x < -border)
                result |= LEFT;
            else if (border < point.x)
                result |= RIGHT;
            if (point.y < -border)
                result |= BOTTOM;
            else if (border < point.y)
                result |= TOP;
            return result;
        }
        
        // основная функция, если вернёт flase, отрезок полностью отсекается
        static bool clip_line(vec2f& first, vec2f& second)
        {
            uint32_t first_pos = clip_point(first);
            uint32_t second_pos = clip_point(second);
 
            while(true)
            {
                if ((first_pos | second_pos) == INSIDE)
                    return true;
                else if ((first_pos & second_pos))
                    return false;
                else
                {
                    const vec2f delta = second - first;
                    uint32_t* pos = &first_pos;
                    vec2f* point = &first;
                    if (*pos == INSIDE)
                    {
                        pos = &second_pos;
                        point = &second;
                    }
 
                    if (*pos & TOP)
                    {
                        point->x = first.x + delta.x * (border - first.y) / delta.y;
                        point->y = border;
                    }
                    else if (*pos & BOTTOM)
                    {
                        point->x = first.x + delta.x * (-border - first.y) / delta.y;
                        point->y = -border;
                    }
                    else if (*pos & RIGHT)
                    {
                        point->y = first.y + delta.y * (border - first.x) / delta.x;
                        point->x = border;
                    }
                    else // if (*pos & LEFT)
                    {
                        point->y = first.y + delta.y * (-border - first.x) / delta.x;
                        point->x = -border;
                    }
 
                    *pos = clip_point(*point);
                }
            }
        }
    };
 
// использование:
if (clipper::clip_line(a, b))
    draw_line(a, b);

Цитата Сообщение от xamelione25 Посмотреть сообщение
А у меня по заданию - кривые
Кривая - это цепочка прямых отрезков.
1
 Аватар для xamelione25
-4 / 5 / 2
Регистрация: 04.02.2013
Сообщений: 1,860
01.02.2021, 15:00  [ТС]
zayats80888,
Кривая - это цепочка прямых отрезков
Да я это прекрасно понимаю ...

Но я с нуля код, скажу прямо, не умею писать...
Я все время по аналогии делаю... Беру за основу другой код и переделываю под себя...

Просто с кривыми код будет немного по-другому строиться ... а похожий код я найти-то вот и не смог ... Поэтому и зашёл в ступор
Аналогию просто не нашел...просто везде ж код под прямые сделан... А чтоб конкретно под кривые - я не нашел

Вот и написал...

Добавлено через 26 секунд
zayats80888,
Нашел у себя в заначке
спс

Добавлено через 17 минут
zayats80888,
Цитата Сообщение от zayats80888 Посмотреть сообщение
делал когда-то давно, сейчас не проверял
А это консольное или оконное приложение windows???

LNK2019 ссылка на неразрешенный внешний символ _main в функции "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ).

Просто у меня это любимая ошибка)))) обычно всплывает когда код сделан под консольное приложение, а задано оконное. Но я щас по пробовал, - безуспешно, все-равно выбило эту же ошибку.
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
01.02.2021, 15:14
Цитата Сообщение от xamelione25 Посмотреть сообщение
А это консольное или оконное приложение windows???
Это не приложение. Это фрагмент кода с упрощённой реализацией алгоритма Коэна-Сазерленда. Он и не должен компилироваться. В общем вам нужно понять, для чего этот алгоритм и как он работает. Вам нужно изучить основы С++. Только после этого писать приложение. Копипаста вам не поможет.

Не по теме:

Я за вас писать не хочу, может у кого другого будет настроение...



Кстати, реализация есть на википедии.
0
 Аватар для xamelione25
-4 / 5 / 2
Регистрация: 04.02.2013
Сообщений: 1,860
02.02.2021, 01:24  [ТС]
zayats80888, я нашел алгоритм, можете помочь мне его в код рабочий превратить?
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
Окно - массив 1 x 4, содержащий координаты(xл, xп, yн, yв) сторон окна.
 
P1, P2 - концевые точки отрезка с координатами(P1x, P1y) и(P2x, P2y) соответственно.
 
T1код, T2код - массивы 1 x 4, содержащие коды точек P1 и P2 .
 
Flag - индикатор координатной ориентации отрезка, равный : -1 - при вертикальности, 0 - при горизонтальности.
 
инициализация Flag
 
Flag = 1
 
проверка вертикальности и горизонтальности отрезка
 
if P2x - P1x = 0 then
 
Flag = -1
 
else
 
вычисление наклона N1
 
N1 = (P2y - P1y) / (P2x - P1x)
 
if N1 = 0 then Flag = 0
 
end if
 
для каждой стороны окна
 
for i = 1 to 4
 
call Коэн(P1, P2, Окно; Видимость)
 
if Видимость = да then 2
 
if Видимость = нет then 3
 
проверка пересечения отрезка и стороны окна
 
if T1код(5 - i) = T2код(5 - i) then 1
 
проверка нахождения P1 вне окна; если P1 внутри окна, то поменять P1 и P2 местами
 
if T1код(5 - i) = 0 then
 
Pаб = Pi
 
P1 = P2
 
P2 = Pаб
 
end if
 
поиск пересечений отрезка со сторонами окна
 
выбор соответствующей подпрограммы вычисления пересечения
 
контроль вертикальности отрезка
 
if Flag <> -1 and i <= 2 then
 
P1y = N1 * (Окноi - P1x) + P1y
 
P1x = Окноi
 
else
 
if Flag < > 0 then
 
if Flag <> -1 then
 
P1x = (1 / N1) * (Окноi - P1y) + P1x
 
end if
 
P1y = Окноi
 
end if
 
end if
 
next i{ 1 шаг }
 
начертить видимый отрезок
 
Draw P1 P2{ 2 шаг }
 
finish{ 3 шаг }
 
 
 
 
 
 
подпрограмма определения видимости отрезка
 
subroutine Коэн(P1, P2, Окно; Видимость)
 
P1, P2 - концевые точки отрезка с координатами(P1x, P1y) и(P2x, P2y) соответственно.
 
Окно - массив 1 x 4, содержащий координаты(xл, xп, yн, yв) сторон окна.
 
Видимость - признак видимости отрезка равный :
 
"нет", "частично", "да" - если отрезок соответственно :
 
полностью невидим, видим частично или полностью видим
 
вычисление кодов концевых точек отрезка
 
call Конец(P1, Окно; T1код, Сумма1)
 
call Конец(P2, Окно; T2код, Сумма2)
 
предположим, что отрезок частично видим
 
Видимость = частично
 
проверка полной видимости отрезка
 
if Сумма1 = 0 and Сумма2 = 0 then
 
Видимость = да
 
else
 
проверка тривиальной невидимости отрезка
 
call Логическое(T1код, T2код, Произвед)
 
if Произвед < > 0 then Видимость = нет
 
end if
 
отрезок может оказаться частично видимым
 
return
 
 
 
 
 
подпрограмма вычисления кодов концевой точки отрезка
 
subroutine Конец(P, Окно; Tкод, Сумма)
 
Px, Py - координаты точки P
 
Окно - массив 1 x 4, содержащий координаты(xл, xп, yн, yв) сторон окна.
 
Tкод - массив 1 x 4, содержащий коды концевой точки .
 
Сумма - сумма всех элементов массива Tкод
 
вычисление кодов концевой точки
 
if Px < xл then Ткод(4) = 1 else Ткод(4) = 0
 
    if Px > xп then Ткод(3) = 1 else Ткод(3) = 0
 
        if Py < yн then Ткод(2) = 1 else Ткод(2) = 0
 
            if Py > yв then Ткод(1) = 1 else Ткод(1) = 0
 
                вычисление суммы
 
                Сумма = 0
 
                for i = 1 to 4
 
                    Сумма = Сумма + Ткод(i)
 
                    next i
 
                    return
 
 
 
 
 
 
 
                    подпрограмма вычисления логического произведения
 
                    subroutine Логическое(Т1код, Т2код; Произвед)
 
                    T1код, T2код - массивы 1 x 4, содержащие коды первой и второй концевых точек соответственно.
 
                    Произвед - сумма побитовых логических произведений.
 
                    Произвед = 0
 
                    for i = 1 to 4
 
                        Произвед = Произвед + Целая часть((Т1код(i) + Т2код(i)) / 2)
 
                        next i
 
                        return
0
 Аватар для xamelione25
-4 / 5 / 2
Регистрация: 04.02.2013
Сообщений: 1,860
02.02.2021, 17:26  [ТС]
zayats80888, в блок LineClip вставлял использование метода отсечения Лианга-Барски - все работало нормально, а по Коэну-Сазерланду - не работает - выбивает ошибку:

Ошибка LNK2019 ссылка на неразрешенный внешний символ "int __cdecl CScode(void)" (?CScode@@YAHXZ) в функции "bool __cdecl LineClip(class WorldWindow const &,class Gdiplus::PointF &,class Gdiplus::PointF &)" (?LineClip@@YA_NABVWorldWindow@@AAVPoint F@Gdiplus@@1@Z).

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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include<windows.h>
#include<Windowsx.h>
#include<gdiplus.h>
#include<gdiplustypes.h>
#include <string> 
#include <tchar.h>
#include<Strsafe.h>
#include<AtlConv.h>
#include "Math.h"
#include "Vectors.h"
#include"WorldWindowAndViewport.h"
#include<vector>
#define PI 3.14159265
#pragma comment(lib,"Gdiplus.lib")
using namespace Gdiplus;
using namespace std;
 
VOID OnPaint(HDC hdc);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
    HWND                hWnd;
    MSG                 msg;
    WNDCLASS            wndClass;
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR           gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = WndProc;
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hInstance = hInstance;
    wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.lpszMenuName = NULL;
    wndClass.lpszClassName = TEXT("Лианга-Барски ");
    RegisterClass(&wndClass);
    hWnd = CreateWindow(
        TEXT("Лианга-Барски "), TEXT("Лианга-Барски "), WS_SYSMENU,
        CW_USEDEFAULT, CW_USEDEFAULT, 700, 700,
        NULL, NULL, hInstance, NULL);
    ShowWindow(hWnd, iCmdShow);
    UpdateWindow(hWnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    GdiplusShutdown(gdiplusToken);
    return msg.wParam;
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
    WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    switch (message)
    {
    case WM_INITDIALOG:
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        OnPaint(hdc);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}
 
 
template <class Func>
inline std::vector<Gdiplus::PointF> Curve(float tMin, float tMax, size_t n, Func f) {
    std::vector<Gdiplus::PointF> result;
    if (n > 1)
    {
        result.reserve(n); // зарезервируем место для n точек
                           // определяем шаг изменения t
        float dt = (tMax - tMin) / (float)(n - 1);
        for (size_t i = 0; i < n; ++i)
        {
            // добавим точку в массив
            result.push_back(f(tMin + i * dt));
        } // for
    } // if
    return result;
} // Curve
 
 
bool LineClip(const WorldWindow& w, PointF& pt1, PointF& pt2)
{
    static float  CSxn, CSyn;   /* Координаты начала отрезка */
 
    int  CScode();  /* Определяет код точки xn, yn */
    {
        register int  i;
        i = 0;
        if (CSxn < w.Left) ++i; else
            if (CSxn > w.Right) i += 2;
        if (CSyn < w.Bottom) i += 4; else
            if (CSyn > w.Top) i += 8;
        return (i);
    }  /* CScode */
 
    int V_CSclip();
    float x0, y0, x1, y1;
    {
        float  CSxk, CSyk;   /* Координаты конца отрезка  */
        int    cn, ck,       /* Коды концов отрезка */
            visible,      /* 0/1 - не видим/видим*/
            ii, s;        /* Рабочие переменные  */
        float  dx, dy,       /* Приращения координат*/
            dxdy, dydx,    /* Наклоны отрезка к сторонам */
            r;            /* Рабочая переменная  */
 
        CSxk = x1; CSyk = y1;
        CSxn = x1; CSyn = y1; ck = CScode();
        CSxn = x0; CSyn = y0; cn = CScode();
 
        /* Определение приращений координат и наклонов отрезка
         * к осям. Заодно сразу на построение передается отрезок,
         * состоящий из единственной точки, попавшей в окно
         */
        dx = CSxk - CSxn;
        dy = CSyk - CSyn;
        if (dx != 0) dydx = dy / dx; else {
            if (dy == 0) {
                if (cn == 0 && ck == 0) goto out; else goto all;
            }
        }
        if (dy != 0) dxdy = dx / dy;
 
        /* Основной цикл отсечения */
        visible = 0;  ii = 4;
        do {
            if (cn & ck) break;       /* Целиком вне окна    */
            if (cn == 0 && ck == 0) { /* Целиком внутри окна */
                ++visible;  break;
            }
            if (!cn) {                /* Если Pn внутри окна, то */
                s = cn; cn = ck; ck = s;  /* перестить точки Pn,Pk и */
                r = CSxn; CSxn = CSxk; CSxk = r;  /* их коды, чтобы Pn  */
                r = CSyn; CSyn = CSyk; CSyk = r;  /* оказалась вне окна */
            }
            /* Теперь отрезок разделяется. Pn помещается в точку
             * пересечения отрезка со стороной окна.
             */
            if (cn & 1) {         /* Пересечение с левой стороной */
                CSyn = CSyn + dydx * (w.Left - CSxn);
                CSxn = w.Left;
            }
            else if (cn & 2) {  /* Пересечение с правой стороной*/
                CSyn = CSyn + dydx * (w.Right - CSxn);
                CSxn = w.Right;
            }
            else if (cn & 4) {  /* Пересечение в нижней стороной*/
                CSxn = CSxn + dxdy * (w.Bottom - CSyn);
                CSyn = w.Bottom;
            }
            else if (cn & 8) {  /*Пересечение с верхней стороной*/
                CSxn = CSxn + dxdy * (w.Top - CSyn);
                CSyn = w.Top;
            }
            cn = CScode();        /* Перевычисление кода точки Pn */
        } while (--ii >= 0);
        if (visible) {
        out: x0 = CSxn; y0 = CSyn; x1 = CSxk; y1 = CSyk;
        }
    all:
        return (visible);
    }
}
 
void DrawPolyline(Gdiplus::Graphics& g, const Gdiplus::Pen* pen, const std::vector<Gdiplus::PointF>& polyline,
    const WorldWindow& w, const Viewport& vp)
{
    for (size_t i = 1; i < polyline.size(); ++i)
    {
        PointF points[2] = { polyline[i - 1], polyline[i] };
        // производим отсечение
        bool fIsDraw = LineClip(w, points[0], points[1]);
        if (fIsDraw) // если ребро выжило
        //if (true) // если ребро выжило
        {
            // выполняем преобразование координат точек
            WorldToViewport(w, vp, points, 2);
            // рисуем ребро
            g.DrawLines(pen, points, 2);
        } // if
    } // for
} // DrawPolyline
Gdiplus::PointF f(float t)
{
    PointF res;
    res.X = 31 * Cos(t) + 5 * Cos(31 * t / 5);
    res.Y = 31 * Sin(t) - 5 * Sin(31 * t / 5);
    return res;
}
 
 
VOID OnPaint(HDC hdc)
{
    Graphics drawingBoard(hdc);
    drawingBoard.Clear(Color::DodgerBlue);
    Pen curvePen(Color(0, 0, 0), 2.0f);
    Pen borderPen(Color(255, 210, 140), 5.0f);
    WorldWindow w(-36, 36, 36, -36);            // кординаты мирового окна
    Viewport vp(100, 100, 600, 600);        // координаты порта просмотра
 
    drawingBoard.DrawRectangle(&borderPen, 100, 100, 500, 500);
    std::vector<Gdiplus::PointF> parabola = Curve(0, 10 * PI, 500, f);
    DrawPolyline(drawingBoard, &curvePen, parabola, w, vp);
}
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
02.02.2021, 20:57
Лучший ответ Сообщение было отмечено xamelione25 как решение

Решение

Цитата Сообщение от xamelione25 Посмотреть сообщение
не работает
Как я и сказал,
Цитата Сообщение от zayats80888 Посмотреть сообщение
Копипаста вам не поможет.
Воткнул свою "заначку", остальное не трогал, вроде работает
Кликните здесь для просмотра всего текста
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
#include<windows.h>
#include<Windowsx.h>
#include<gdiplus.h>
#include<gdiplustypes.h>
#include <string> 
#include <tchar.h>
#include<Strsafe.h>
//#include<AtlConv.h>
//#include "Math.h"
//#include "Vectors.h"
//#include"WorldWindowAndViewport.h"
#include<vector>
#include <cmath>
#define PI 3.14159265
#pragma comment(lib,"Gdiplus.lib")
using namespace Gdiplus;
using namespace std;
 
VOID OnPaint(HDC hdc);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
    HWND                hWnd;
    MSG                 msg;
    WNDCLASS            wndClass;
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR           gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = WndProc;
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hInstance = hInstance;
    wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.lpszMenuName = NULL;
    wndClass.lpszClassName = TEXT("Лианга-Барски ");
    RegisterClass(&wndClass);
    hWnd = CreateWindow(
        TEXT("Лианга-Барски "), TEXT("Лианга-Барски "), WS_SYSMENU,
        CW_USEDEFAULT, CW_USEDEFAULT, 700, 700,
        NULL, NULL, hInstance, NULL);
    ShowWindow(hWnd, iCmdShow);
    UpdateWindow(hWnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    GdiplusShutdown(gdiplusToken);
    return msg.wParam;
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
    WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    switch (message)
    {
    case WM_INITDIALOG:
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        OnPaint(hdc);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}
 
 
template <class Func>
inline std::vector<Gdiplus::GpPointF> Curve(float tMin, float tMax, size_t n, Func f) {
    std::vector<Gdiplus::GpPointF> result;
    if (n > 1)
    {
        result.reserve(n); // зарезервируем место для n точек
                           // определяем шаг изменения t
        float dt = (tMax - tMin) / (float)(n - 1);
        for (size_t i = 0; i < n; ++i)
        {
            // добавим точку в массив
            result.push_back(f(tMin + i * dt));
        } // for
    } // if
    return result;
} // Curve
 
struct WorldWindow
{
    REAL m00, m11, m02, m12;
 
    template<class T>
    WorldWindow(T l, T r, T b, T t)
        : m00(static_cast<REAL>(2) / (r - l))
        , m11(static_cast<REAL>(2) / (t - b))
        , m02(static_cast<REAL>(-(r + l)) / (r - l))
        , m12(static_cast<REAL>(-(t + b)) / (t - b))
    {}
 
    GpPointF map(GpPointF p) const
    {
        return {p.X * m00 + m02, p.Y * m11 + m12};
    }
};
 
struct Viewport
{
    GpRectF r;
 
    template<class T>
    Viewport(T l, T t, T r, T b)
        : r(static_cast<REAL>(l),
            static_cast<REAL>(t),
            static_cast<REAL>(r - l) * static_cast<REAL>(0.5),
            static_cast<REAL>(b - t) * static_cast<REAL>(0.5))
    {}
 
    GpPointF map(GpPointF p) const
    {
        return
        {
            r.X + (p.X + static_cast<REAL>(1)) * r.Width,
            r.Y + (static_cast<REAL>(1) - p.Y) * r.Height
        };
    }
};
 
using vec2f = GpPointF;
 
struct clipper
{
    enum region : uint32_t
    {
        INSIDE = 0,
        LEFT = 1,
        RIGHT = 1 << 1,
        BOTTOM = 1 << 2,
        TOP = 1 << 3
    };
 
    static constexpr float border = 1;
 
    static uint32_t clip_point(const vec2f &point)
    {
        uint32_t result = INSIDE;
        if (point.X < -border)
            result |= LEFT;
        else if (border < point.X)
            result |= RIGHT;
        if (point.Y < -border)
            result |= BOTTOM;
        else if (border < point.Y)
            result |= TOP;
        return result;
    }
 
    static bool clip_line(vec2f &first, vec2f &second)
    {
        uint32_t first_pos = clip_point(first);
        uint32_t second_pos = clip_point(second);
 
        while (true)
        {
            if ((first_pos | second_pos) == INSIDE)
                return true;
            else if ((first_pos & second_pos))
                return false;
            else
            {
                const vec2f delta = second - first;
                uint32_t *pos = &first_pos;
                vec2f *point = &first;
                if (*pos == INSIDE)
                {
                    pos = &second_pos;
                    point = &second;
                }
 
                if (*pos & TOP)
                {
                    point->X = first.X + delta.X * (border - first.Y) / delta.Y;
                    point->Y = border;
                }
                else if (*pos & BOTTOM)
                {
                    point->X = first.X + delta.X * (-border - first.Y) / delta.Y;
                    point->Y = -border;
                }
                else if (*pos & RIGHT)
                {
                    point->Y = first.Y + delta.Y * (border - first.X) / delta.X;
                    point->X = border;
                }
                else // if (*pos & LEFT)
                {
                    point->Y = first.Y + delta.Y * (-border - first.X) / delta.X;
                    point->X = -border;
                }
 
                *pos = clip_point(*point);
            }
        }
    }
};
 
void DrawPolyline(Gdiplus::Graphics& g, const Gdiplus::Pen* pen, const std::vector<Gdiplus::GpPointF>& polyline,
    const WorldWindow& w, const Viewport& vp)
{
    for (size_t i = 1; i < polyline.size(); ++i)
    {
        GpPointF points[2] = { w.map(polyline[i - 1]), w.map(polyline[i]) };
 
        if(clipper::clip_line(points[0], points[1]))
        {
            points[0] = vp.map(points[0]);
            points[1] = vp.map(points[1]);
            // рисуем ребро
            g.DrawLines(pen, points, 2);
        } // if
    } // for
} // DrawPolyline
Gdiplus::GpPointF f(REAL t)
{
    GpPointF res;
    res.X = 31 * std::cos(t) + 5 * std::cos(31 * t / 5);
    res.Y = 31 * std::sin(t) - 5 * std::sin(31 * t / 5);
    return res;
}
 
VOID OnPaint(HDC hdc)
{
    Graphics drawingBoard(hdc);
    drawingBoard.Clear(Color::DodgerBlue);
    Pen curvePen(Color(0, 0, 0), 2.0f);
    Pen borderPen(Color(255, 210, 140), 5.0f);
    WorldWindow w(-36, 36, 36, -36);            // кординаты мирового окна
    Viewport vp(100, 100, 600, 600);        // координаты порта просмотра
 
    drawingBoard.DrawRectangle(&borderPen, 100, 100, 500, 500);
    std::vector<Gdiplus::GpPointF> parabola = Curve(0, 10 * PI, 500, f);
    DrawPolyline(drawingBoard, &curvePen, parabola, w, vp);
}
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
02.02.2021, 20:57
Помогаю со студенческими работами здесь

Алгоритм отсечения Коэна-Сазерленда
здравствуйте, нужна помощь в разъяснении кода по алгоритму Коэна-Сазерленда, вот есть код: function ClipSegmentByRect(seg: OneLine;...

Алгоритм двумерного отсечения Сазерленда-Коэна
Здравствуйте, помогите реализовать алгоритм двумерного отсечения Сазерленда-Коэна, пожалуйста.

Как доработать алгоритм отсечения Коэна Сазерленда?
Подскажите как доработать алгоритм отсечения Коэна Сазерленда. Совсем ничего не понимаю в Паскале, а завтра уже сдавать.Помогите...

Реализация алгоритма Сазерленда-Коэна
Если у кого-то есть опыт &quot;творения&quot; этого алгоритма (object pascal) - помогите. не представляю с чего подступить. ...

Нужно на завтра переписать код с С на PascalABC алгоритма Коэна — Сазерленда по отсечению отрезка
Здраствуйте, Господа. Помогите переписать код с С на PascalABC( алгоритм по отсечению отрезка Коэна — Сазерленда) Первый исходник на...


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

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11680&amp;d=1772460536 Одним из. . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru