Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,631

Функции изменения режима отображения

04.11.2022, 06:00. Показов 1908. Ответов 11

Студворк — интернет-сервис помощи студентам
Здравствуйте! Думал, что понял, но, как оказалось нет, связано это непонимание с функциями изменения режима отображения. Если я хочу изменить режим отображения на MM_ISOTROPIC например,

Я пишу следующее:
C++
1
2
3
4
SetMapMode(hdc, MM_ISOTROPIC);
        SetWindowExtEx(hdc, cxClient, -cyClient, NULL);
        SetViewportExtEx(hdc, radius, radius, NULL);
        SetViewportOrgEx(hdc, cxOrig, cyOrig, NULL);
Устанавливаю координаты (0, 0) на середину окна cxOrig, cyOrig, хочу нарисовать группу эллипсов radius - радиус, cxClient, cyClient - рабочая область окна.
1)Если вместо SetViewportOrgEx(hdc, cxOrig, cyOrig, NULL); вызвать функцию SetWindowOrgEx(hdc, cxOrig, cyOrig, NULL); то в окне вообще ничего не рисуется, почему?

2)Если я хочу рисовать в цикле, скажем, 10 кругов, то установив режим отображения как указано выше у меня рисуется один круг, почем так
вот код:

Кликните здесь для просмотра всего текста
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
case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
 
        int cxOrig = (cxClient >> 1);
        int cyOrig = (cyClient >> 1);
 
        SetMapMode(hdc, MM_ISOTROPIC);
        SetWindowExtEx(hdc, cxClient, -cyClient, NULL);
        SetViewportExtEx(hdc, radius, radius, NULL);
        SetViewportOrgEx(hdc, cxOrig, cyOrig, NULL);
 
        int scaling = radius;
        for (int i = 0; i < 10; ++i)
        {
            /*hBrush = CreateSolidBrush(RGB((BYTE)rand() % 255,
                                          (BYTE)rand() % 255, 
                                          (BYTE)rand() % 255));*/
 
            //hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
 
            hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
            hOldPen = (HPEN)SelectObject(hdc, hPen);
                
            Ellipse(hdc, -radius, -radius,
                          radius, radius);
            //приращение радиуса, рассчитывал, что таким образом
            //удастся получить координаты для следующего круга.
            radius += scaling;
 
            SelectObject(hdc, hOldPen);
            DeleteObject(hPen);
            //SelectObject(hdc, hOldBrush);
            //DeleteObject(hBrush);
            hPen = hOldPen = NULL;
            hBrush = hOldBrush = NULL;
        }
        EndPaint(hwnd, &ps);


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

Если я вызываю функцию SetWindowExtEx(hdc, cxClient, -cyClient, NULL);, то таким образом я задаю некий прямоугольник/квадрат, с которым, в дальнейшем будет вестись работа или нет?

А если, соответственно, вызвать функцию SetViewportExtEx(hdc, radius, radius, NULL);, то это значит, что я задаю некий масштаб отображения, единицы вроде тех, что используются в MM_LOENGLISH... или нет?

----------------------------
Читаю книжку по работе с API и пытаюсь понять смысл функций SetViewport/SetWindowOrgEx.
SetViewportOrgEx смещает начало физической системы координат (ФКС),
SetWindowOrgEx смещает начало логической системы координат (ЛКС). А теперь небольшой код:

C++
1
2
3
4
SetMapMode(hdc, MM_LOENGLISH);
SetViewportOrgEx(hdc, 0, 100,NULL);
Rectangle(hdc, 0,0,500, 300);
Ellipse(hdc, 0,0,500, 300);
Первая путаница, которая возникает у меня – это направление осей этих систем координат. Раз функция SetViewportOrgEx работает с ФКС, значит единицы измерения этой системы координат – пиксели и направление осей слева-направо, СВЕРХУ-вниз. То есть положительное смещение начала координат на 100 пикселей фактически сместит область вывода на 100 пикселей вниз – соответственно будет видна (на величину этого смещения) часть нарисованного круга и эллипса. По аналогии с объяснением выше исследуем вот такой код:

C++
1
2
3
4
SetMapMode(hdc, MM_LOENGLISH);
SetWindowOrgEx(hdc, 0, 100,NULL);
Rectangle(hdc, 0,0,500, 300);
Ellipse(hdc, 0,0,500, 300);
Функция SetWindowOrgEx работает с ЛКС, значит единицы измерения этой системы координат задаются режимом наложения. В нашем случае это MM_LOENGLISH, поэтому единицы измерения – 0,1 мм и направление осей слева-направо, СНИЗУ-вверх. То есть положительное смещение начала координат на 100 единиц поднимет окно на 1 см вверх – соответственно мы должны будет увидеть ту часть области, которая раньше закрывалась верхней границей окна, и опять же увидим часть нарисованного круга и эллипса. Однако моя логика здесь не срабатывает, и я не могу понять почему - вроде все правильно
-------------------------------------------------------------

Хотелось бы разобраться в этой теме.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
04.11.2022, 06:00
Ответы с готовыми решениями:

Синхронизация отображения изменения данных
Доброго времени суток! Такая проблема. Есть QML окно. На нем висит Endless список (реализован через PathView) с ScrollBar и пару клавиш....

Изменение режима отображения значений в форме
Здравствуйте. Ситуация такая. Есть вкладка в форме, где надо указать адрес проживания сотрудника. Адресов два - фактический и по месту...

Какое событие возникает при смене режима отображения формы
Прошу прощения за дурацкий вопрос, меня что-то пермкнуло. Не могу в списке событий найти, какое событие возникает при смене CurrentView...

11
COM‐пропагандист
 Аватар для Замабувараев
936 / 785 / 149
Регистрация: 18.12.2014
Сообщений: 2,256
Записей в блоге: 4
06.11.2022, 11:13
Цитата Сообщение от Liss29 Посмотреть сообщение
у меня рисуется один круг
Все десять рисуются, просто следующий круг затмевает собой уже нарисованный. Если вам нужен круг с прозрачным содержимым, то в контекст устройства следует выбрать бесцветную кисть GetStockObject(NULL_BRUSH);.

Рекомендую ознакомиться «Выбор режима отображения» Александр Фролов, Григорий Фролов
https://frolov-lib.ru/books/bs... w559536907
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,631
06.11.2022, 13:12  [ТС]
Цитата Сообщение от Замабувараев Посмотреть сообщение
Все десять рисуются
У меня не рисуются, если начать отрисовку не с центра, а от левого верхнего угла, тогда рисуются все.

Цитата Сообщение от Замабувараев Посмотреть сообщение
просто следующий круг затмевает собой уже нарисованный.
Т.е. это как если бы на меньший круг вырезанный из бумаги наложить больший, меньший круг будет скрыт кругом, с большим радиусом? Если так, то такие мысли были, уверенности в этом не было.

Цитата Сообщение от Замабувараев Посмотреть сообщение
Если вам нужен круг с прозрачным содержимым
Нет, мне нужно нарисовать мишень, соответственно, каждый круг должен быть закрашен своим цветом, ну и цифры нужно выставить.

Цитата Сообщение от Замабувараев Посмотреть сообщение
Рекомендую ознакомиться «Выбор режима отображения» Александр Фролов, Григорий Фролов
Уже читал, но не всё ясно с этими режимами отображения, а что не ясно я спросил выше в вопросе.
0
COM‐пропагандист
 Аватар для Замабувараев
936 / 785 / 149
Регистрация: 18.12.2014
Сообщений: 2,256
Записей в блоге: 4
06.11.2022, 16:26
Цитата Сообщение от Liss29 Посмотреть сообщение
Нет, мне нужно нарисовать мишень, соответственно, каждый круг должен быть закрашен своим цветом, ну и цифры нужно выставить.
Рисуйте от большего к меньшему.

Цитата Сообщение от Liss29 Посмотреть сообщение
Т.е. это как если бы на меньший круг вырезанный из бумаги наложить больший, меньший круг будет скрыт кругом, с большим радиусом?
А вы что думали, нарисованное будет просвечивать, что ли? Будет, но только для пустой кисти.
Вообще любая GDI фигура рисуется текущей выбранной кистью и пером, обнуляя всё, что было раньше нарисовано.

Цитата Сообщение от Liss29 Посмотреть сообщение
Уже читал, но не всё ясно с этими режимами отображения, а что не ясно я спросил выше в вопросе.
Если надо повернуть ось «y» вверх и центрировать кококоординаты как в кабинете математики:
C
1
2
3
4
SetMapMode(hDC, MM_ISOTROPIC);
SetWindowExtEx(hDC, ClientWidth, ClientHeight, NULL);
SetViewportExtEx(hDC, ClientWidth, -1 * ClientHeight, NULL);
SetViewportOrgEx(hDC, ClientWidth / 2, ClientHeight / 2, NULL);
Если надо повернуть ось «y» вверх и поставить ось «x» как на осциллографе, где x только положительные:
C
1
2
3
4
SetMapMode(hDC, MM_ISOTROPIC);
SetWindowExtEx(hDC, ClientWidth, ClientHeight, NULL);
SetViewportExtEx(hDC, ClientWidth, -1 * ClientHeight, NULL);
SetViewportOrgEx(hDC, 0, ClientHeight / 2, NULL);
Если надо повернуть ось «y» вверх и ось «x» сдвинуть вниз как на графике биржевых котировок:
C
1
2
3
4
SetMapMode(hDC, MM_ISOTROPIC);
SetWindowExtEx(hDC, ClientWidth, ClientHeight, NULL);
SetViewportExtEx(hDC, ClientWidth, -1 * ClientHeight, NULL);
SetViewportOrgEx(hDC, 0, ClientHeight, NULL);
Вот три основные вида графиков, которые могут встретиться на практике.

А теперь можете забыть про эти режимы и приступить к преобразованию координатного пространства через матрицы перехода:
https://learn.microsoft.com/en... formations
1
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,631
07.11.2022, 09:23  [ТС]

Не по теме:

Цитата Сообщение от Замабувараев Посмотреть сообщение
Рисуйте от большего к меньшему.
Хм... я написал, что в итоге так и сделал.



Цитата Сообщение от Замабувараев Посмотреть сообщение
А вы что думали, нарисованное будет просвечивать, что ли? Будет, но только для пустой кисти.
Вообще любая GDI фигура рисуется текущей выбранной кистью и пером, обнуляя всё, что было раньше нарисовано.
Было такое, не знаю, почему.))

Цитата Сообщение от Замабувараев Посмотреть сообщение
Если надо повернуть ось «y» вверх и центрировать кококоординаты как в кабинете математики:
Цитата Сообщение от Замабувараев Посмотреть сообщение
Если надо повернуть ось «y» вверх и поставить ось «x» как на осциллографе, где x только положительные:
Цитата Сообщение от Замабувараев Посмотреть сообщение
Если надо повернуть ось «y» вверх и ось «x» сдвинуть вниз как на графике биржевых котировок:
Обязательно в размерах указывать ширину и высоту рабочей области или всё же можно задавать другие значения, ну, например, так, если ширина окна 1400, высота 700 и я хочу выделить область в которой буду работать, скажем такую, ширина - 600, высота - 400.
Я задаю так:
C++
1
2
3
4
5
6
7
8
SetMapMode(hdc, MM_ISOTROPIC);
        SetWindowExtEx(hdc, cxClientArea, cyClientArea, NULL);
        SetViewportExtEx(hdc, 600, -400, NULL); //Изменить направление
                                                //оси Y
        SetViewportOrgEx(hdc, 600, 400, NULL);
        //SetWindowOrgEx(hdc, 600, 400, NULL); //Почему, если пытаюсь
                                        //установить начало вывода
                                        //(0, 0) так, то ничего не происходит, если пытаюсь что-то вывести?
Если выбираю режим MM_LOMETRIC/MM_HIMETRIC, тогда при приращении переменной(сдвиг к следующей позиции) я буду перемещаться не на пиксель, а на 0.1/0.01 мм, я правильно понимаю?
C++
1
2
3
4
5
6
7
8
SetMapMode(hdc, MM_HIMETRIC);
    SetViewportOrgEx(hdc, 10, 40, NULL); //При этом и подобных 
                                         //режимах установка начала //координат окна не //обязательна?
                                         //Так же как и так же как 
                                         //установка протяжённости
                                         //окна и области вывода
                                         //SetWindowExtEx(),
                                         //SetViewportExtEx()?
Если всё что я написал имеет место быть, то, видимо, понимание того, как работают эти функции потихоньку, но приходит.

Не по теме:

Цитата Сообщение от Замабувараев Посмотреть сообщение
А теперь можете забыть про эти режимы и приступить к преобразованию координатного пространства через матрицы перехода:
Не понял юмора=-O.

0
COM‐пропагандист
 Аватар для Замабувараев
936 / 785 / 149
Регистрация: 18.12.2014
Сообщений: 2,256
Записей в блоге: 4
07.11.2022, 12:32
Цитата Сообщение от Liss29 Посмотреть сообщение
//Так же как и так же как
//установка протяжённости
//окна и области вывода
//SetWindowExtEx(),
//SetViewportExtEx()?
Экстенты окна и экрана можно устанавливать только в режимах MM_ISOTROPIC и MM_ANISOTROPIC. В остальных режимах попытку сменить экстенты Windows будет игнорировать. Вы наверное статью по ссылке не читали, потому что там это указано.

Также там есть формула преобразования координат из логических в физические:
Code
1
2
xViewport = (xWindow — xWinOrg) × (xViewExt/xWinExt) + xViewOrg
yViewport = (yWindow — yWinOrg) × (yViewExt/yWinExt) + yViewOrg,
Можете подставлять в неё значения и вычислять на листочке как логическая точка будет транслироваться в физическую.

Цитата Сообщение от Liss29 Посмотреть сообщение
SetViewportOrgEx(hdc, 600, 400, NULL);
//SetWindowOrgEx(hdc, 600, 400, NULL); //Почему, если пытаюсь
//установить начало вывода
//(0, 0) так, то ничего не происходит, если пытаюсь что-то вывести?
Windows имеет функции SerViewportOrgEx и SetWindowOrgEx для изменения начала координат области вывода и окна. Эти функции обладают эффектом сдвига осей координат таким образом, что логическая точка (0, 0) не будет далее соответствовать левому верхнему углу рабочей области. Чаще всего вы будете использовать SetViewportOrgEx или SetWindowOrgEx, но не обе функции одновременно.

Если вы переносите начало координат области вывода в точку (xViewOrg, yViewOrg), то логическая точка (0, 0) будет соответствовать физической точке с координатами (xViewOrg, yViewOrg). Если вы переносите начало координат окна в точку (xWinOrg, yWinOrg), то логическая точка (xWinOrg, yWinOrg) будет соответствовать физической точке с координатами (0, 0), то есть левому верхнему углу рабочей области.

Например, предположим, что рабочая область вашего окна имеет ширину ClientWidth и высоту ClientHeight пикселей. Если вы хотите установить начало логической системы координат — точку (0, 0) — в центр рабочей зоны окна, вы можете это сделать так:

SetViewportOrgEx(hdc, ClientWidth / 2, ClientHeight / 2, NULL);

Аргументы функции SetViewportOrgEx всегда задаются в координатах устройства. Логическая точка (0, 0) будет теперь отображаться в точку с физическими координатами (ClientWidth/2, ClientHeight/2). Теперь вы используете рабочую область так, как будто бы она имела представленную ниже систему координат:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
┌───────────────────────────────────┐
│                 ↑+y               │
│                 │                 │
│                 │                 │
│                 │                 │
│-x               │0,0            +x│
│─────────────────┼────────────────→│
│                 │                 │
│                 │                 │
│                 │                 │
│                 │                 │
│                 │-y               │
└─────────────────┴─────────────────┘
Значения логической координаты x могут изменяться в диапазоне от —ClientWidth/2 до ClientWidth/2. Значения логической координаты y могут изменяться в диапазоне от —ClientHeight/2 до ClientHeight/2. Правый нижний угол рабочей области — точка с логическими координатами (ClientWidth/2, ClientHeight/2). Если вы хотите вывести текст, начиная от верхнего левого угла рабочей зоны, имеющего физические координаты (0, 0), вам придётся задать отрицательные координаты:
C
1
TextOut(hdc, -ClientWidth / 2, -ClientHeight / 2, "Hello", 5);
Вы можете добиться того же результата, используя функцию SetWindowOrgEx вместо функции SetViewportOrgEx:
C
1
SetWindowOrgEx(hdc, -ClientWidth / 2, -ClientHeight / 2, NULL);
Аргументы функции SetWindowOrgEx всегда задаются в логических координатах. После этого вызова логическая точка (—ClientWidth/2, —ClientHeight/2) соответствует физической точке (0, 0) — левому верхнему углу рабочей области.

То, чего вы не должны делать (до тех пор, пока вы не будете знать, к чему это приведёт) — это использовать обе функции совместно:
C
1
2
SetViewportOrgEx(hdc, ClientWidth / 2, ClientHeight / 2, NULL);
SetWindowOrgEx(hdc, -ClientWidth / 2, -ClientHeight / 2, NULL);
Это означает, что логическая точка (—ClientWidth/2, —ClientHeight/2) соответствует физической точке (ClientWidth/2, ClientHeight/2), представляя вам такую систему координат:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
┌───────────────────────────────────┐
│                                -y↑│
│                                  ││
│                                  ││
│                                  ││
│                                  ││
│                                  ││
│                                  ││
│                                  ││
│                                  ││
│-x                           (0,0)││
│←─────────────────────────────────┘│
└───────────────────────────────────┘
Добавлено через 18 минут
Цитата Сообщение от Liss29 Посмотреть сообщение
Не понял юмора.
Вся 3D графика основана на матричных преобразованиях. То же самое желательно делать и в 2D, чтобы не переучиваться.
Сразу приступайте к изучению матриц поворота, отражения, сдвига, переноса и масштабирования.
Например, нарисовать эллипс под углом.
Или отмасштабированный в соответствии с размерами окна квадрат. Вы что, к координатам каждой фигуры будете добавлять поправочные коэффициенты? Нет, это следует делать установкой матрицы масштабирования.
Или стрелки в аналоговых часах. Вместо пересчёта координат, вычисления синусов и косинусов, следует просто установить матрицу поворота.

В GDI для этого есть функции SetWorldTransform, ModifyWorldTransform и структура XFORM.
В GDI+ вообще всё замечательно, там и функций побольше, и сама библиотека очень дружественна к матрицам.
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,631
08.11.2022, 06:59  [ТС]
Цитата Сообщение от Замабувараев Посмотреть сообщение
В остальных режимах попытку сменить экстенты Windows будет игнорировать. Вы наверное статью по ссылке не читали, потому что там это указано.

Не по теме:

Ну да, если угодно, не читал, может просто мне не всё ясно, нет....


Я спросил про единицы(пикселы или миллиметры), которые используются для приращения, но, видимо, не совсем ясно выразился. И да, если имеется ввиду этот код:
C++
1
2
3
4
5
6
7
8
SetMapMode(hdc, MM_HIMETRIC);
    SetViewportOrgEx(hdc, 10, 40, NULL); //При этом и подобных 
                                         //режимах установка начала //координат окна не //обязательна?
                                         //Так же как и так же как 
                                         //установка протяжённости
                                         //окна и области вывода
                                         //SetWindowExtEx(),
                                         //SetViewportExtEx()?
Разве не могу я выбрав режим MM_HIMETRIC УСТАНОВИТЬ КООРДИНАТЫ В УДОБНОЕ ДЛЯ СЕБЯ МЕСТО, екстенты у меня закомментированы.
Эта часть описания взята из книги Питзольда, если не ошибаюсь, её тоже читал. По формулам я их видел при чтении, но особого смысла не предавал т.к. никто не требует писать собственные функции перевода из логических координат в физические и обратно.
Логические и физические координаты - я так понимаю, к физическим координатам относится весть экран, а к логическим область на экране, например, окно, хотя не факт, что я правильно понял.
xViewport = (xWindow — xWinOrg) × (xViewExt/xWinExt) + xViewOrg
yViewport = (yWindow — yWinOrg) × (yViewExt/yWinExt) + yViewOrg,
Если этот параметр(xWinOrg) отсутствует, то его просто игнорируют, если я вызываю только функцию SetViewportExtEx(), а xWindow - это, как я понимаю, логическая координата окна...

Цитата Сообщение от Замабувараев Посмотреть сообщение
То, чего вы не должны делать (до тех пор, пока вы не будете знать, к чему это приведёт) — это использовать обе функции совместно:
Да, с этим я полностью согласен, вот и пытаюсь узнать.

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

Цитата Сообщение от Замабувараев Посмотреть сообщение
Или стрелки в аналоговых часах. Вместо пересчёта координат, вычисления синусов и косинусов, следует просто установить матрицу поворота.
А внутри матрицы, когда идёт вычисление разве не тоже самое происходит?!

Цитата Сообщение от Замабувараев Посмотреть сообщение
В GDI для этого есть функции SetWorldTransform, ModifyWorldTransform и структура XFORM.
Буду иметь ввиду, спасибо!
0
COM‐пропагандист
 Аватар для Замабувараев
936 / 785 / 149
Регистрация: 18.12.2014
Сообщений: 2,256
Записей в блоге: 4
08.11.2022, 11:07
Цитата Сообщение от Liss29 Посмотреть сообщение
Разве не могу я выбрав режим MM_HIMETRIC УСТАНОВИТЬ КООРДИНАТЫ В УДОБНОЕ ДЛЯ СЕБЯ МЕСТО
Можете.
Цитата Сообщение от Liss29 Посмотреть сообщение
екстенты у меня закомментированы
Код в комментариях? Плохая практика, поэтому удаляйте.
Цитата Сообщение от Liss29 Посмотреть сообщение
я так понимаю, к физическим координатам относится весть экран
Нет.

Перед тем, как отобразить точку на мониторе, координаты этой точки проходят несколько этапов преобразований.
1. Логические координаты точки клиентской области (xWindow, yWindow), отправляемые в функции GDI, домножаются на мировую матрицу. По умолчанию в контексте устройства установлена единичная матрица, и координаты проходят дальше без изменений.
2. Логические координаты точки (xWindow, yWindow) преобразуются в координаты области вывода (xViewport, yViewport).
3. Полученные координаты области вывода преобразуются в полные координаты окна относительно левого верхнего угла окна.
4. Полные координаты преобразуют в координаты физического устройства (монитора, принтера).

Чаще всего область вывода (Viewport) — это то же самое, что и клиентская область (GetDC, BeginPaint), хотя область вывода может описываться также и в полных координатах окна или в координатах экрана, если вы получили контекст устройства из функций GetWindowDC или CreateDC.

Цитата Сообщение от Liss29 Посмотреть сообщение
А внутри матрицы, когда идёт вычисление разве не тоже самое происходит?!
Внутри идёт только произведение типов данных float по формуле:
Code
1
2
3
4
5
6
| x' |   | eM11 eM21 eDx |   | x |   
| y' | = | eM12 eM22 eDy | . | y |
| 1  |   | 0    0    1   |   | 1 |
 
x' = x * eM11 + y * eM21 + eDx
y' = x * eM12 + y * eM22 + eDy
Как видно, матрица никакие синусы и косинусы не вычисляет, она только числа умножает и складывает. В GDI произведения чисел с плавающей запятой выполняет процессор, а в движках — графическая карта (очень быстро).
Вы должны заранее подготовить нужную вам матрицу, с синусами и косинусами углов поворота. Так как синусы и косинусы каждого угла уже известны (см. таблицы Брадиса), поэтому в своей программе даже не надо использовать функции sin и cos, вы просто храните готовые значения как константы и формируете матрицу поворота на нужный угол когда надо.
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,631
09.11.2022, 08:20  [ТС]
Цитата Сообщение от Замабувараев Посмотреть сообщение
Перед тем, как отобразить точку на мониторе, координаты этой точки проходят несколько этапов преобразований.
Буду разбираться дальше, видимо, здесь ещё путаница в терминологии. Я всё равно не улавливаю связи между физическми, логическими координатами, мне ясны лишь координаты окна т.е. всего окна, области вывода окна(рабочая область) и экрана. Значения получаемые функциями наподобие GetSystemMetric() получаются в пикселах, а значения GetTextMetrics() могу быть получены в физических единицах, например, миллиметрах, если установлен режим MM_LO/HIMETRIC...

Цитата Сообщение от Замабувараев Посмотреть сообщение
Так как синусы и косинусы каждого угла уже известны (см. таблицы Брадиса)
Не проще ли в таком случае просто вычислить значения для синусов и косинусов и сохранить в файлик, в оттуда, из файла, читать те значения, которые нужны тебе в данный момент. Хотя кому как, тут дело привычки, я уже забыл про эти таблицы) , спасибо, что напомнили....

Цитата Сообщение от Замабувараев Посмотреть сообщение
По умолчанию в контексте устройства установлена единичная матрица
Значит её можно изменять на другие значения?
Цитата Сообщение от Замабувараев Посмотреть сообщение
Вы должны заранее подготовить нужную вам матрицу
Это имеется ввиду подготовить матрицу с помощью функций SetWorldTransform, ModifyWorldTransform и структура XFORM на данный момент не совсем понял, как с ними работать, но кто знает, возможно, в скором времени понадобится.
0
COM‐пропагандист
 Аватар для Замабувараев
936 / 785 / 149
Регистрация: 18.12.2014
Сообщений: 2,256
Записей в блоге: 4
10.11.2022, 07:47
Цитата Сообщение от Liss29 Посмотреть сообщение
Я всё равно не улавливаю связи между физическми, логическими координатами
У вас же есть формула пересчёта из логических координат в координаты области вывода. Не можете понять — просто подставьте данные в формулу на листочке ручкой и вычислите результат на калькуляторе.
Цитата Сообщение от Liss29 Посмотреть сообщение
Не проще ли в таком случае просто вычислить значения для синусов и косинусов и сохранить в файлик
Проще? Можно сделать ещё проще: отказаться от вычислений и скопировать готовые значения синусов и косинусов с сайта в файлик.
Цитата Сообщение от Liss29 Посмотреть сообщение
Значит её можно изменять на другие значения?
Функции для манипуляции матрицами в GDI:
GetWorldTransform — возвращает текущую матрицу из контекста устройства.
SetWorldTransform — сбросит старую и установит новую матрицу в контекст устройства.
ModifyWorldTransform — умножит старую и новую матрицу и установит полученную матрицу в контекст устройства. Эта же функция умеет устанавливать едининую матрицу.
CombineTransform — умножает две матрицы.

Матрицу вы создаёте сами. То есть вам надо объявить переменную типа XFORM, заполнить её поля и отправить в функцию SetWorldTransform. Вот пример как с помощью матрицы в два раза сплющить плоскость по оси y и повернуть на 30 градусов (код на языке FreeBASIC, но вам не составит труда перевести его на си, добавив визуального мусора в виде точек с запятой):
PureBasic
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
Sub SetCartesian(ByVal hDC As HDC, ClientWidth As Long, ClientHeight As Long)
    Dim cxOrig As Long = ClientWidth \ 2
    Dim cyOrig As Long = ClientHeight \ 2
    Dim AntiHeight As Long = -1 * ClientHeight
    
    SetMapMode(hDC, MM_ISOTROPIC)
    SetWindowExtEx(hDC, ClientWidth, ClientHeight, NULL)
    SetViewportExtEx(hDC, ClientWidth, AntiHeight, NULL)
    SetViewportOrgEx(hDC, cxOrig, cyOrig, NULL)
End Sub
 
Sub OnPaint(ByVal hWin As HWND, ByVal hDC As HDC, ByVal prcPaint As RECT Ptr)
    
    SetGraphicsMode(hDC, GM_ADVANCED)
    
    Dim rcClient As RECT = Any
    GetClientRect(hWin, @rcClient)
    Dim ClientWidth As Long = rcClient.right
    Dim ClientHeight As Long = rcClient.bottom
    
    SetCartesian(hDC, ClientWidth, ClientHeight)
    
    ' Матрица поворота с масштабированием
    Dim Matrix2D As XFORM = Any
    Matrix2D.eM11 = 0.865999997
    Matrix2D.eM12 = 0.5
    Matrix2D.eM21 = -0.25
    Matrix2D.eM22 = 0.432999998
    Matrix2D.eDx = 0.0
    Matrix2D.eDy = 0.0
    ModifyWorldTransform(hDC, @Matrix2D, MWT_LEFTMULTIPLY)
    
    Dim WidthHeightMin As Long = min(ClientWidth \ 2, ClientHeight \ 2)
    
    ' Нарисовать круги
    For radius As Integer = WidthHeightMin To 20 Step -20
        Dim nLeft As Long = -1 * radius
        Dim nTop As Long = -1 * radius
        Dim nRight As Long = radius
        Dim nBottom As Long = radius
        
        Ellipse(hDC, nLeft, nTop, nRight, nBottom)
    Next
    
    ' Сбросить
    ModifyWorldTransform(hDC, NULL, MWT_IDENTITY)
    
    ' Нарисовать оси координат
    MoveToEx(hDC, 0, -1 * ClientHeight, NULL)
    LineTo(hDC, 0, ClientHeight)
    MoveToEx(hDC, -1 * ClientWidth, 0, NULL)
    LineTo(hDC, ClientWidth, 0)
    
End Sub
 
Function MainFormWndProc(ByVal hWin As HWND, ByVal wMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM) As LRESULT
    
    Select Case wMsg
        
        Case WM_PAINT
            Dim ps As PAINTSTRUCT = Any
            Dim hDC As HDC = BeginPaint(hWin, @ps)
            OnPaint(hWin, hDC, @ps.rcPaint)
            EndPaint(hWin, @ps)
            
        Case WM_DESTROY
            PostQuitMessage(0)
            
        Case Else
            Return DefWindowProc(hWin, wMsg, wParam, lParam)
            
    End Select
    
    Return 0
    
End Function
Должно получиться примено так:


В GDI+ дополнительно есть удобные функции‐обёртки для каждого из пяти видов линейных преобразований, умножения матриц и векторов, но это GDI+, а для GDI вам придётся самостоятельно реализовывать такие функции.
1
COM‐пропагандист
 Аватар для Замабувараев
936 / 785 / 149
Регистрация: 18.12.2014
Сообщений: 2,256
Записей в блоге: 4
10.11.2022, 11:59
Цитата Сообщение от Liss29 Посмотреть сообщение
1)Если вместо SetViewportOrgEx(hdc, cxOrig, cyOrig, NULL); вызвать функцию SetWindowOrgEx(hdc, cxOrig, cyOrig, NULL); то в окне вообще ничего не рисуется, почему?
Теперь давайте распишем на листочке, почему именно не рисуется когда вы сдвигаете логические координаты (вместо физических).
Обратимся к формуле:
Code
1
2
xViewport = (xWindow - xWinOrg) * (xViewExt / xWinExt) + xViewOrg
yViewport = (yWindow - yWinOrg) * (yViewExt / yWinExt) + yViewOrg
Предположим, что размеры клиентской области окна равны 640 на 480. Тогда ваши cxOrig и cyOrig будет 320 и 240. Предположим также, что мы не изменяли ни екстенты логического окна и области вывода, ни координаты области вывода. Мы меняли только логические координаты. Подставим данные в формулу и получим:
Code
1
2
xViewport = (xWindow - 320) * (640 / 640) + 0
yViewport = (yWindow - 240) * (480 / 480) + 0
Упрощаем:
Code
1
2
xViewport = (xWindow - 320)
yViewport = (yWindow - 240)
Попробуем нарисовать точку в координатах (0, 0). Вычислим её координаты:
Code
1
2
xViewport = (0 - 320) = -320
yViewport = (0 - 240) = -240
Наша область вывода ограничена прямоугольником от 0 до 640 и от 0 до 480. Очевидно, что координаты точки (-320, -240) не попадают в этот прямоугольник, следовательно, она не отобразится на экране.

Чтобы точка отобразилась на экране, её логические коориданты должны быть как минимум 320 и 240. Иначе она не попадает в область вывода.

Вот ответ на ваш вопрос.
1
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,631
16.11.2022, 05:28  [ТС]
Цитата Сообщение от Замабувараев Посмотреть сообщение
Не можете понять — просто подставьте данные в формулу на листочке ручкой и вычислите результат на калькуляторе.
И что, подставлял, отношение протяжённости окна и области вывода по X и Y это коэффициент, который влияет на масштаб, видимо, так. Думаю, что стало всё же яснее, но, всё же, это не совсем то понимание ради которого я эту тему создавал, но всё равно, спасибо, это лучше, чем ничего.(

Цитата Сообщение от Замабувараев Посмотреть сообщение
Предположим, что размеры клиентской области окна равны 640 на 480. Тогда ваши cxOrig и cyOrig будет 320 и 240.
Да, здесь, ясно, если задать екстенты с минусом, то начало области вывода буде в середине рабочей области.


Цитата Сообщение от Замабувараев Посмотреть сообщение
Можно сделать ещё проще: отказаться от вычислений и скопировать готовые значения синусов и косинусов с сайта в файлик.
Ну, вообще, я именно это и предлагал, вычислить в файл т.е. заранее вычислить в файл и пользоваться этими данными тогда, когда они станут нужны. Это конкурс на оригинальное решение...)))
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
16.11.2022, 05:28
Помогаю со студенческими работами здесь

Ассемблерная вставка для изменения режима округления
Здравствуйте, помогите пожалуйста, есть программа для вычисления определенного интеграла методом трапеций,в ней нужно изменить режим...

Изменения отображения Chart
Всем привет. При добавлении легенд, chart в размерах не уменьшается, но уменьшается область, выделенная под график. Такого счастья...

Синхронизация отображения изменения данных
Доброго времени суток! Такая проблема. Есть QML окно. На нем висит Endless список (реализован через PathView) с ScrollBar и пару клавиш....

Редактировать скрипт для изменения отображения товаров
Прошу помощи. Имеется сайт http://xn--80akivdjfp5ac.xn--p1ai/games/ Есть скрипт. var busy = false; var pages_loaded =...

Программа для отображения изменения яркости/громкости на ноутбуке
подскажите программку для отображения изменения яркости/громкости на ноутбуке


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

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
Хочу заставить корпорации вкладываться в здоровье сотрудников: делаю мат модель здравосохранения
anaschu 22.03.2026
e7EYtONaj8Y Z4Tv2zpXVVo https:/ / github. com/ shumilovas/ med2. git
1С: Программный отбор элементов справочника по группе
Maks 22.03.2026
Установка программного отбора элементов справочника "Номенклатура" из модуля формы документа. В качестве фильтра для отбора справочника служит группа номенклатуры. Отбор по наименованию группы. . .
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс. Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
1С: Программный отбор элементов справочника по значению перечисления
Maks 21.03.2026
Установка программного отбора элементов справочника "Сотрудники" из модуля формы документа. В качестве фильтра для отбора служит значение перечислений. / / Событие "НачалоВыбора" реквизита на форме. . .
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru