С для профессиональных программистов

       

Программа вычерчивания диаграмм.


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

Главная программа.

Здесь приводится основная функция 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);

 


Содержание раздела