Программа вычерчивания диаграмм.
Вы можете использовать описанные функции для построения программы создания диаграмм. Программа позволяет пользователю вводить количество наборов данных, количество элементов в каждом наборе, наименования и метки соответствующих данных, а также толщину линий и расстояния между диаграммами. После ввода указанных данных программа автоматически вычерчивает диаграмму. Вы также можете написать программу сохранения построенной диаграммы в файле для ее дальнейшего использования.
Главная программа.
Здесь приводится основная функция main(), описывающая алгоритм построения диаграмм и содержащая несколько макросов.
#define MAX_SETS 3
#define MAX_ENTRIES 50
#define MAX_LABELS 20
#define MAX_NAMES 20
main()
double v[MAX_SETS][MAX_ENTRIES]; /* размещение данных */
int num_entries;
int num_sets;
int min,max,i;
int lines,offset;
char save = 0; /* признак сохранения диаграммы */
char names[MAX_NAMES][20];
char lab[MAX_LABELS][20];
/* считывание данных */
enter(v,&num_entries,&num_sets);
/* поиск минимального и максимального значения */
min_max(v,num_entries,num_sets,&min,&max);
/* ввод наименований данных */
get_names(names,num_sets);
/* ввод меток для диаграммы */
get_labels(lab,num_entries);
/* ввод толщины линии */
lines = get_line_size();
/* ввод интервала между диаграммами */
offset = get_offset();
/* сохранить диаграмму в файле ? */
printf(" сохранить диаграмму в файле ? (y/n) ");
if (tolower(getche()) == 'y') save = 1;
mode(4); /* графический режим 320*200 */
palette(0);
grid(min,max); /* вывод линии нулевого уровня */
hashlines(); /* вывод пунктирных линий */
label(lab,num_entries); /* вывод меток диаграммы */
legend(names,num_sets); /* вывод пояснительных надписей */
/* вывод значений в виде диаграммы */
for (i=0;i<num_sets;i++)
bargraph(v[i],num_entries,i*offset,min,max,lines);
if (save) save_pic();
getch();
mode(3);
Как вы видите, функция main() начинается описанием переменных, значения которых устанавливает пользователь. Массив v определен достаточно большим, чтобы содержать до трех наборов данных до 50 элементов каждый. (Эти размеры являются произвольными и при желании вы можете их изменить.) Затем функция считывает выводимые пользователем в виде диаграмм данные и определяет минимальное и максимальное значение данных. После этого на экран выводятся линия нулевого уровня, пунктирные линии уровня, метки диаграммы и наименование наборов. В завершение вычерчивается сама диаграмма. Перед выходом происходит сохранение диаграммы при помощи функции save_pic(). Давайте рассмотрим некоторые используемые в программе main() функции, которые не входят в описанные выше инструментарии построения диаграмм.
Функция enter().
Приведенная здесь функция enter() использует в качестве своих параметров адрес массива, в котором будут размещены данные, и адреса переменных для размещения числа количества элементов в наборе и числа самих наборов. Функция начинает свою работу с запроса у пользователя количества наборов данных и затем количества элементов данных в каждом наборе. После получения этой информации производится считывание данных для каждого набора.
/* Считывание данных */
enter(v,entries,sets)
double v[][MAX_ENTRIES]; /* массив данных */
int *entries; /* количество элементов в каждом наборе данных */
int *sets; /* количество наборов данных */
int i,j,count,num;
char s[80];
printf("Введите число наборов данных (от 1 до %d)",MAX_SETS);
scanf("%d%c",&count,&j);
if (count>MAX_SETS) count = MAX_SETS; /* выход за границы
массива */
*sets = count;
printf("Введите количество элементов (от 1 до %d) ",MAX_ENTRIES);
scanf("%d%c",&num,&j);
if (num>MAX_SETS) num = MAX_ENTRIES; /* выход за границы
массива */
*entries = num;
j = 0;
/* считывание значений данных */
while((j<count))
printf("Набор данных %d\n",j+1);
for (i=0;i<num;i++)
printf("%d:",i+1);
gets(s);
sscanf(s,"%lf",&v[j][i]);
j++;
return count;
Функция min_max().
Так как функция bargraph() использует максимальное и минимальное значения выводимых данных, то нам потребуется специальная функция для определения этих значений. Необходимо также отметить, что эта функция должна не просто определять минимальное и максимальное значения набора данных, а находить наименьшее минимальное и наибольшее максимальное значения для нескольких наборов данных, что обеспечит соответствие при одновременном построении сразу нескольких диаграмм. Функция min_max(), приведенная здесь, вместе с двумя внутренними функциями удовлетворяет этому требованию.
/* Поиск наименьшего минимума и наибольшего максимума
среди всех наборов данных */
void min_max(v,entries,sets,min,max)
double v[][MAX_ENTRIES]; /* значения */
int entries; /* количество входов для каждого набора
данных */
int sets; /* количество наборов данных */
int *min,*max; /* возвращает минимальное и максимальное
значение */
int i,j;
int tmin,tmax;
*min = *max = 0;
for (i=0;i<sets;i++)
tmax = getmax(v[i],entries);
tmin = getmin(v[i],entries);
if (tmax>*max) *max = tmax;
if (tmin <*min) *min = tmin;
/* Возврат максимального значения данных */
getmax(data,num)
double *data;
int num;
int t,max;
max = (int)data[0];
for (t=1;t<num;++t)
if (data[t]>max) max = (int)data[t];
return max;
/* Возврат минимального значения данных */
getmin(data,num)
double *data;
int num;
int t,min;
min = (int)data[0];
for (t=1;t<num;++t)
if (data[t]<min) min = (int)data[t];
return min;
Полный текст программы вычерчивания диаграмм.
Полный текст программы вычерчивания диаграмм представлен ниже.
/* Программа генерации диаграмм */
#include "dos.h"
#include "stdio.h"
#define MAX_SETS 3
#define MAX_ENTRIES 50
#define MAX_LABELS 20
#define MAX_NAMES 20
void bargraph(),mode(),mempoint();
void line(),goto_xy(),grid(),label();
void hashlines(),legend(),read_cursor_xy();
void palette(),color_puts(),fill_box();
void get_labels(),get_names(),min_max();
void save_pic();
main()
double v[MAX_SETS][MAX_ENTRIES]; /* размещение данных */
int num_entries;
int num_sets;
int min,max,i;
int lines,offset;
char save = 0; /* признак записи диаграммы */
char names[MAX_NAMES][20];
char lab[MAX_LABELS][20];
/* считывание данных */
enter(v,&num_entries,&num_sets);
/* поиск минимального и максимального значения */
min_max(v,num_entries,num_sets,&min,&max);
/* ввод наименований данных */
get_names(names,num_sets);
/* ввод меток для диаграммы */
get_labels(lab,num_entries);
/* ввод толщины линии */
lines = get_line_size();
/* ввод интервала между диаграммами */
offset = get_offset();
/* сохранить диаграмму в файле ? */
printf(" сохранить диаграмму в файле ? (y/n) ");
if (tolower(getche()) == 'y') save = 1;
mode(4); /* графический режим 320*200 */
palette(0);
grid(min,max); /* вывод линии нулевого уровня */
hashlines(); /* вывод пунктирных линий */
label(lab,num_entries); /* вывод меток диаграммы */
legend(names,num_sets); /* вывод пояснительных надписей */
/* вывод значений в виде диаграммы */
for (i=0;i<num_sets;i++)
bargraph(v[i],num_entries,i*offset,min,max,lines);
if (save) save_pic();
getch();
mode(3);
/* считывание данных */
enter(v,entries,sets)
double v[][MAX_ENTRIES]; /* массив данных */
int *entries; /* количество элементов данных в каждом наборе
данных */
int *sets; /* количество наборов данных */
int i,j,count,num;
char s[80];
printf("Введите число наборов данных (от 1 до %d)",MAX_SETS);
scanf("%d%c",&count,&j);
if (count>MAX_SETS) count = MAX_SETS; /* выход за границы
массива */
*sets = count;
printf("Ведите число элементов данных (от 1 до %d)",MAX_ENTRIES);
scanf("%d%c",&num,&j);
if (num>MAX_ENTRIES) num = MAX_ENTRIES; /* выход за границы
массива */
*entries = num;
j = 0;
/* считывание значений */
while((j<count))
printf(" Набор данных %d\n",j+1);
for (i = 0;i<num;i++)
printf("%d:",i+1);
gets(s);
sscanf(s,"%lf",&v[j][i]);
j++;
return count;
/* Ввод имен наборов */
void get_names(n,num)
char n[][20]; /* массив для имен */
int num; /* число наборов */
int i;
for (i=0;i<num;i++)
printf(" Введите имя: ");
gets(n[i]);
/* Ввод метки каждого входа */
void get_labels(l,num)
char l[][20]; /* массив для меток */
int num; /* число входов */
int i;
for (i=0;i<num;i++)
printf(" Введите имя метки: ");
gets(l[i]);
/* Ввод интервала между диаграммами в единицах растра */
get_offset()
int i;
printf(" Введите интервал между диаграммами в единицах растра");
scanf("%d%*c",&i);
return i;
/* Ввод толщины диаграмм в единицах растра */
get_line_size()
int i;
printf("Введите толщину диаграммы в единицах растра : ");
scanf("%d",&i);
return i;
/* Вывод линии нулевого уровня диаграммы */
void grid(min,max)
int min,max;
register int t;
goto_xy(22,0); printf("%d",min);
goto_xy(0,0); printf("%d",max);
line(180,10,180,300,1);
/* Вывод меток на экран */
void label(str,num)
char str[][20]; /* массив меток */
int num; /* количество меток */
int i,j,inc;
inc = 38/num;
i = 2; /* определение начальной точки */
for (j=0;j<num;j++)
goto_xy(23,i);
printf(str[j]);
i += inc;
/* Вывод пунктирных линий на экран */
void hashlines()
int i,j;
for (i=10;1<180;i+=10)
for (j=10;j<300;j+=5)
mempoint(i,j,3); /* одна точка на каждые 5 единиц
растра */
/* Вывод надписи */
void legend(names,num)
char names[][20];
int num; /* количество наименований */
int color = 1,i,j;
goto_xy(24,0); /* надпись производится в последней строке */
j = 0;
for (i=0;i<num;i++)
/* Вывод наименования */
printf("%s ",names[i]);
/* определение координаты цветного прямоугольника. В 4
режиме каждому литерному символу отводится 8 единиц
растра ( в ширину ) */
j += strlen(names[i]) * 8 + 4;
fill_box(192,j,198,j+12,color);
j += 28; /* продвижение к следующему полю вывода */
color ++;
if ( color>3 ) color = 1;
void bargraph(data,num,offset,min,max,width)
double *data; /* массив данных */
int num; /* количество элементов в массиве */
int offset; /* расстояние между диаграммами */
int min,max; /* минимальное и максимальное выводимые значения */
int width; /* толщина линий */
int y,t,incr;
double norm_data,norm_ratio,spread;
char s[80];
static int color = 0;
int tempwidth;
/* всегда используйте различные цвета */
color++;
if ( color > 3 ) color = 1;
/* определение нормирующего множителя */
spread = (double)max-min;
norm_ratio = 180/spread;
incr = 280/num; /* определение промежутка между значениями*/
tempwidth = width;
for (t=0;t<num;++t)
norm_data = data[t];
/* подгонка отрицательных значений */
norm_data = norm_data-(double)min;
norm_data *= norm_ratio; /* нормирование */
y = (int)norm_data; /* преобразование типа */
do
Line(179,((t*incr)+20+offset+width),179-y,
((t*incr)+20+offset+width),color);
width--;
while(width);
width = tempwidth;
/* поиск наименьшего минимума и наибольшего максимума
среди всех наборов данных */
void min_max(v,entries,sets,min,max)
double v[][MAX_ENTRIES]; /* значения */
int entries; /* количество входов для каждого набора
данных */
int sets; /* количество наборов данных */
int *min,*max; /* возвращает минимальное и максимальное
значение */
int i,j;
int tmin,tmax;
*min = *max = 0;
for (i=0;i<sets;i++)
tmax = getmax(v[i],entries);
tmin = getmin(v[i],entries);
if (tmax>*max) *max = tmax;
if (tmin <*min) *min = tmin;
/* Возврат максимального значения данных */
getmax(data,num)
double *data;
int num;
int t,max;
max = (int)data[0];
for (t=1;t<num;++t)
if (data[t]>max) max = (int)data[t];
return max;
/* Возврат минимального значения данных */
getmin(data,num)
double *data;
int num;
int t,min;
min = (int)data[0];
for (t=1;t<num;++t)
if (data[t]<min) min = (int)data[t];
return min;
/* Вывод линии заданного цвета, используя базовый алгоритм
Брезенхама */
void line(startx,starty,endx,endy,color)
int startx,starty,endx,endy,color;
register int t,distance;
int x=0,y=0,delta_x,delta_y;
int incx,incy;
/* вычисление расстояний по обоим направлениям */
delta_x = endx - startx;
delta_y = endy - starty;
/* определение направлений увеличения координат, нулевое
увеличение соответствует либо вертикальной, либо
горизонтальной линии */
if ( delta_x > 0 ) incx = 1 ;
else if (delta_x == 0 ) incx = 0;
else incx = -1;
if ( delta_y > 0 ) incy = 1 ;
else if (delta_y == 0 ) incy = 0;
else incy = -1;
/* определение максимума изменения координат */
delta_x = abs(delta_x);
delta_y = abs(delta_y);
if ( delta_x > delta_y ) distance = delta_x;
else distance = delta_y;
/* вычерчивание линии */
for (t=0;t<=distance+1;t++)
mempoint(startx,starty,color);
x+= delta_x;
y+= delta_y;
if (x>distance)
x-=distance;
startx+=incx;
if (y>distance)
y-=distance;
starty+=incy;
/* наполнение прямоугольника заданным цветом */
void fill_box(startx,starty,endx,endy,color_code)
int startx,starty,endx,endy,color_code;
register int i,begin,end;
begin = startx < endx ? startx : endx;
end = startx > endx ? startx : endx;
for (i=begin;i<=end;i++)
line(i,starty,i,endy,color_code);
/* запись точки в CGA/EGA память */
void mempoint(x,y,color_code)
int x,y,color_code;
union mask
char c[2];
int i;
bit_mask;
int i,index,bit_position;
unsigned char t;
char xor; /* xor - цвет или наложение */
char far *ptr = (char far *) 0xB8000000; /* указатель на
CGA */ bit_mask.i = 0xFF3F; /* 11111111 00111111 в двоичном коде */
/* контроль координат для 4 режима */
if (x<0 || x>199 || y<0 || y>319) return;
xor = color_code & 128; /* проверка установки режима xor */
color_code = color_code & 127; /* маска 7 старших бит */
/* установка bit_mask и color_code в правильное положение */
bit_position = y%4;
color_code <<= 2*(3-bit_position);
bit_mask.i >>= 2*bit_position;
/* поиск соответствующего байта в памяти экрана */
index = x*40 + (y>>2);
if (x%2) index+=8152; /* если нечетный, использовать второй
банк */
/* запись цвета */
if (!xor) /* режим наложения */
t = *(ptr + index) & bit_mask.c[0];
*(ptr + index) = t | color_code;
else /* режим xor */
t = *(ptr + index) | (char)0;
*(ptr + index) = t ^ color_code;
/* установка видеорежима */
void mode(mode_code)
int mode_code;
union REGS r;
r.h.al = mode_code;
r.h.ah = 0;
int86(0x10,&r,&r);
/* установка курсора в координаты x,y */
void goto_xy(x,y)
int x,y;
union REGS r;
r.h.ah = 2; /* функция адресации курсора */
r.h.dl = y; /* горизонтальная координата */
r.h.dh = x; /* вертикальная координата */
r.h.bh = 0; /* видеостраница */
int86(0x10,&r,&r);
/* установка цветов диаграмм */
void palette(pnum)
int pnum;
union REGS r;
r.h.bh = 1; /* код 4 режима */
r.h.bl = pnum;
r.h.ah = 11; /* установка функции цвета */
int86(0x10,&r,&r);
/* сохранение выведенного видеографика */
void save_pic()
char fname[80];
FILE *fp; register int i,j;
char far *ptr = (char far *) 0xB8000000; /* указатель на CGA память */
char far *temp;
unsigned char buf[14][80]; /* для размещения содержимого
экрана */
temp = ptr;
/* сохранение верхней части текущего экрана */
for (i=0;i<14;i++)
for (j=0;j<80;j+=2)
buf[i][j] = *temp; /* четный байт */
buf[i][j+1] = *(temp+8152); /* нечетный байт*/
*temp = 0;
*(temp+8152) = 0; /* чистка верхней части
экрана */
temp++;
goto_xy(0,0);
printf(" Имя файла : ");
gets(fname);
if (!(fp=fopen(fname,"wb")))
printf(" Невозможно открыть файл \n");
return;
temp = ptr;
/* восстановление верхней части экрана */
for (i=0;i<14;i++)
for (j=0;j<80;j+=2)
*temp = buf[i][j];
*(temp+8152) = buf[i][j+1];
temp++;
/* сохранение рисунка в файле */
for (i=0;i<8152;i++)
putc(*ptr,fp); /* четный байт */
putc(*(ptr+8152),fp); /* нечетный байт */
ptr++;
fclose(fp);