Рисование графиков в С++

Если использовать Code::Blocks и mingw, то нужно подключить библиотеку freeglut или freeglut_static (во втором случае нужно также установить макрос FREEGLUT_STATIC), а также opengl32, winmm, gdi32. Подключить в проекте заголовочный файл include/easy_plot.hpp, указать С++11 или выше.
Пример того, что может рисовать эта библиотека:

Пример кода
Рисование тепловой карты
Особенности библиотеки:
- Функция plot может принимать такие параметры, как имя окна, стиль окна (различные настройки цвета и пр., см. WindowSpec), данные графиков и стиль линий.
- Функция draw_heatmap может принимать такие параметры, как имя окна, стиль окна (различные настройки цвета и пр., см. WindowSpec), данные массива тепловой карты типа float и размер тепловой карты.
- Если графиков несколько, изначально они будут расположены по всему экрану равномерно.
- Если навести курсор мыши на график, можно узнать номер линии и данные по осям X и Y.
- Рисование графиков и тепловой карты происходит в отдельном потоке.
- При повторном вызове функции с уже существующим именем окна график будет перерисован.
- Можно сохранить график
- Ключевые слова: , , , , , , , , , ,
- хорошо
- 27
- 06 декабря 2019, 13:30

И зачем такие сложности. Встроенных возможностей вполне хватает и без OpenGL.

- 06 декабря 2019, 13:34

- 06 декабря 2019, 13:54

- 06 декабря 2019, 16:17

- 06 декабря 2019, 16:19

- 06 декабря 2019, 18:06

- 06 декабря 2019, 18:19

- 06 декабря 2019, 14:00

- 06 декабря 2019, 14:12

- 06 декабря 2019, 16:59

- 06 декабря 2019, 14:14

- 06 декабря 2019, 14:14

- 06 декабря 2019, 14:43

- 06 декабря 2019, 17:00

- 06 декабря 2019, 22:33

- 06 декабря 2019, 15:21

- 06 декабря 2019, 16:00

Как всё сложно у С++’ников. серьёзный подход. даже сказал бы профессиональный. На пайтон такие вещи попроще делаются.
последний раз графику использовал на c++ когда учился и писал в borland C. там это было примерно также просто как и на turbo pascal/qbasic. цикл по X, вычисление координат из функции (y) с масштабированием, постановка точки через point (ну или можно и lineto, если точек недостаточно).
- 06 декабря 2019, 18:48

Gregori, C++ только для профессионалов.
- 07 декабря 2019, 03:56

- 07 декабря 2019, 12:53

elektroyar, первая жесть — это потенциально «размножающиеся» static-переменные в заголовочном файле, особенно mutex. Если я разобью свою программу на несколько модулей (файлов), каждый из которых включит заголовочный файл библиотеки, то у меня появится несколько mutex’ов, по одному на каждый модуль. Всё, защита от race condition сломана.
Добиться того, чтобы mutex все равно был только один, можно, вот пример с несколькими модулями, где показано, что из разных модулей в вашем коде получается разный адрес mutex’а, то есть, их там много.
А также дана правильная реализация, чтобы адрес был один на программу, то есть, чтобы mutex был единственным.
Вторая жесть — это то, что код не является exception-safe там, где это жизненно необходимо.
Вы защищаете mutex’ом изменения drawings. Перед изменением drawings соответствующий mutex lock’чится, после изменения — раз’lock’чивается назад. Как бы, всё хорошо. Но между этими двумя моментами вызываются функции push_back и make_shared, каждая из которых может выбросить исключение. Я, в коде своей программы, могу отловить исключения и продолжить работу дальше. Но, вот, только библиотечный код при этом не раз’lock’чит mutex, и при попытке повторно его за’lock’чить всё повиснет. Для избегания таких вещей в стандартной библиотеке специально имеется lock_guard, который раз’lock’чит mutex при любом развитии событий.
Третья жесть — вы вообще прогоняли свой же тест?
Он не падает где-то на 33-35 строке?
В функцию с переменным числом аргументов передаёте сами объекты, а в самой функции вычитываете их адреса. Но передали-то объекты, а не их адреса. Естественно, всё падает.
В функцию с переменным числом аргументов можно передавать только POD-типы, а вы аж вектор туда запихиваете. И LineSpec не является POD-типом. Чтобы он им стал, требуется оттуда выкинуть всё, что мешает скомпилировать его в pure C. Вам хочется использовать значения по умолчанию, но это можно сделать и с POD-типом, применив вспомогательную функцию. Вот набросок на эту тему. Значение последнего параметра берётся по умолчанию.
Вот здесь рекомендуют вместо функции с переменным числом аргументов использовать variadic templates или initializer_list. Но для этого, конечно, нужно владеть «шаблонной магией» хотя бы на среднем уровне.
Набросок решения с использованием variadic templates — здесь (общее количество пар заранее неизвестно).
Набросок решения с использованием initializer_list — здесь (общее количество пар в данном случае будет заранее известно).
В целом, остальное, навскидку, жестью не является, но очень много особенностей построения кода говорят о непонимании множества вещей.
Для написания библиотек, кстати, требуется более высокая квалификация, чем для написания обычных программ, потому что требуется учитывать множество вариантов, как пользователи библиотеки могут использовать её.
C++ для начинающих Рисование графика функции
Итак. Я с этим не сталкивался, но наверное в Универах могут давать лабораторные построения графиков по разным формулам. По большому счету неважно как выглядит формула, все сводится к однообразному построению и у начинающих не такие уж сложные задачи.
Я выбрал простой график y=x*x Короткая формула, всем известная кривая (всем кто хоть чуть-чуть учился в школе)
Код C++ Рисование графика
============
#include <graphics.h> // включить описание графических функций С/С++ Borland’a
#include <conio.h> // описание функций ввода-вывода с консоли (для getch())
int main ()
<
float x , y ;
/* Автоматическое определение графических параметров */
int gdriver = DETECT , gmode ;
initgraph (& gdriver , & gmode , “” ); // Инициализация графического режима
x =- 10 ; //Инициализируем x
moveto ( x , x * x ); //Устанавливаем курсор
do
<
y = x * x ; //Наша формула для построения графика
lineto ( x * 50 + getmaxx ()/ 2 , getmaxy ()/ 2 -( y * 20 )); // ..откуда рисуем график
x = x + 0.02 ;
> while( x < 10 );
getch (); // ожидание нажатия пользователем любой клавиши
closegraph (); // выход из графического режима
return 0 ;
>
============
Что ж. Сразу скажу – Я не знаю почему x увеличивается на дробное число. При моих попытках увеличивать его на единицу график получался очень даже не гладким и это было плохо, поэтому оставил так как отыскал в просторах интернета. Чтобы начать рисовать линию из какой-то точки имеет смысл определить первоначальную точку, для чего была использована функция moveto Сам график строится с помощью циклического вычисления, ведь для каждого значения x нужно получить соответствующий ему y, значит, чтобы не писать все эти выражения вручную нужно использовать цикл.
Внутри цикла вызывается функция lineto, внутри которой написаны такие параметры, которые могут сбить с толку бедного новичка, но пугаться не стоит. lineto чертит линию от текущей позиции до, но не включая в нее, указанной точки. Другими словами при вычислении значения y мы будем получать некоторые точки, а чтобы получить график, нужно эти точки соединять линиями.
x * 50 + getmaxx ()/ 2 Обозначает, что первоначальная точка x смещена к центру экрана по оси x. Цифра 50 здесь нужна только для того чтобы расширить рисуемый график. Нетрудно попробовать её изменить или убрать, чтобы увидеть эффект. Когда я пытался убрать эту 50 и прибавлять к x единицу вместо 0.02 график рисовался ужасно, хотя если подумать, то то что написано здесь или то что хотел написать я сводится к тому что x прибавляется на единицу, но что-то вот в этом есть чего я понять пока что увы не могу. Точнее понимаю, но понимаю как-то туманно, не полностью и сложно для разъяснений
Не буду скрывать, надеюсь на помощь кого-нибудь из читателей, благодаря критике, благодарностям, указанию моих ошибок этот материал может стать намного легче и понятнее. Проверку на ошибки я убрал, чтобы не отвлекало глаза от описываемого кода
Программа на си для построения графика функции
В этой статье мы разберем программу на языке программирования си для построения графиков функций. В нашей программе будут отражаться система координат с делениями и подписями на них и будут строиться графики двух функций, который может сам задать пользователь.
В программе на си для построения графика функции вводятся следующие константы
X0 , Y0 — координаты центра координат
k – масштаб одного деления на осях (сколько пикселов в одном делении)
Опишем все функции и процедуры используемые в программе для построения графиков функций
Подробно о задании функций и процедур в си
int osx (float x) переводит реальную координату на оси ox в координату экрана
int osy (float y) переводит реальную координату на оси oy в координату экрана
float F1 ( float x ) и float F2 ( float x ) задают функции , графики которых мы будем строить
void Point ( float x, float y, int color ) рисует точку графика функции на экране
Перед построением графиков функций необходимо построить систему координат. Для построения системы координат используется процедура
void Axes()
В этой процедуре в цикле for рисуются линии меток делений на равном расстоянии друг от друга, который определяется масштабом одного деления k и выводятся значения делений с помощью двух операторов
sprintf ( s, "%d", i ); // записываем в строковую переменную число деления
outtextxy ( xe-10, Y0+4, s ); // вывод числа
Процедура grafik1() и grafik2() строят графики функций f1 и f2
В этих процедурах в цикле for для всех доступных значений x определяется координата y и точка графика строится с помощью процедуры point()
Пример работы программы построения графиков на си, функции пользователь может менять

Программа на си для построения графиков функций
#include <stdio.h>
#include <graphics.h> //графический режим
#include <math.h> // математические функции
//————————————————
const int X0 = 100, Y0 = 400;// координаты центра координат
const float k = 15;// масштаб в точках одного деления на графике
//——————————————
// перевод y в координаты экрана
//——————————————
int osx (float x)
<
return X0+k*x;
>
//——————————————
//перевод y в координаты экрана
//——————————————
int osy (float y)
<
return Y0-k*y;
>
// первая функция
float F1 ( float x )
<
return sqrt(2*x);
>
// вторая функция
float F2 ( float x )
<
return x*x/2;
>
// построение осей
void Axes()
<
int i, xe,ye,y1;
char s[10];
line ( X0, 0, X0, 599 ); // ось ox
line ( 0, Y0, 799, Y0 ); // ось oy
// метки на оси ox
for ( i = 1; i <= (800-X0)/k; i ++ )
<
xe = osx ( i );
line ( xe, Y0-2, xe, Y0+2 ); // рисуем деление разметки
sprintf ( s, "%d", i ); // записываем в строковую переменную число деления
outtextxy ( xe-10, Y0+4, s ); // вывод числа
>
// метки на оси oy
for ( i = 1; i <= (Y0)/k; i ++ )
<
ye = osy( i+1 );
line ( X0-2, ye, X0+2, ye ); // рисуем деление
sprintf ( s, "%d",i ); // записываем в строковую переменную число деления
outtextxy ( X0+10, ye+4, s ); // вывод числа
>
>
// построение точки графика функции
void Point ( float x, float y, int color )
<
int xe, ye;
xe = osx(x);
ye = osy(y);
if ( xe >= 0 && xe < 800 && ye >= 0 && ye < 600 )
putpixel(xe, ye, color);
>
// построение графика первой функции
void grafik1()
<
float x, h, xmin, xmax;
h = 1 / k;
xmin = (-X0)/ k;
xmax=(800-X0)/k;
for ( x = xmin; x <= xmax; x += h )
<
Point(x, F1(x), WHITE);
>
>
// построение графика второй функции
void grafik2()
<
float x, h, xmin, xmax;
h = 1 / k;
xmin = (-X0)/ k;
xmax=(800-X0)/k;
for ( x = xmin; x <= xmax; x += h )
<
Point(x, F2(x), WHITE);
>
>
// главная программа
main ()
<
initwindow ( 800, 600 ); // создать окно для графики
Axes(); // построение и разметка осей координат
grafik1(); // строим график первой функции
grafik2(); // строим график второй функции
getch(); // ждать нажатия на клавишу
closegraph(); // закрыть окно для графики
>
Полезно почитать по теме построение графиков функций в программа си
Графика в си
Процедуры и функции в си
С++ как начертить график в консольном приложении?
У меня есть код, находящий значения конхоиды Никомеда, и я хотел бы реализовать отрисовку графика по точкам(параллельно с вычислением значений). Я пытался сделать отрисовку прямо в консоли, но в моей реализации график отрисовывается моментально и пропадает при первой перерисовке окна. Есть ли какие-то другие варианты отрисовать график? Я думаю о варианте открыть еще одно окно (WinForm) и отрисовать уже в нем, но не могу найти примера чего-то подобного.
![]()
![]()
То, что вы рисуете напрямую в окне консоли, затирается стандартным обработчиком отрисовки conhost при следующем обновлении окна (как при выводе нового текста в консоль, так и при изменении, например, размеров ее окна). Переопределить этот обработчик нельзя, но можно отобразить свое окно поверх консоли, как показано в примере ниже. Кроме того, код рисования графика в вопросе рисует график по отдельным точкам, я переделал его с SetPixel на MoveTo/LineTo, чтобы он выглядел непрерывным.

![]()
Используйте SetConsoleCursorPosition(..) для установки курсора в консоли на необходимые координаты. Затем выводите символ, обозначающий линию, например ‘*’.