П р и л о ж е н и е 4

ПРИМЕР ВЫВОДА НА ЭКРАН ГРАФИКА ФУНКЦИИ С ИСПОЛЬЗОВАНИЕМ БИБЛИОТЕКИ SDL

В качестве примера рассмотрим два фрагмента программы с использованием библиотеки SDL_draw, отображающей в окне 640 на 480 пикселей график функции y=ln(|x|), причем xmin = –32, xmax = 32, (MX = MY = 10 пикселей), а экранное положение начала координат – в центре экрана. В первом фрагменте – отображение производится по точкам с шагом Δx = 0,001, во втором – отрезками с Δx = 0,1. Инициализация, отображение осей координат, асимптот и т.п. не приводятся.

/* Отображение графика функции по точкам */
/* screen – инициализированная поверхность для рисования 640 на 480 пикселей, */
const Sint16 width=640, heght=480;
double xmin=-32.0, xmax=32.0, ymin, ymax;
double mx=10.0, my=10.0, dx=0.001, x, y;
Sint16 x0scr, y0scr, xscr, yscr;
x0scr=floor(-1*xmin*mx);
/* ymin – неизвестно, так нельзя: y0scr=floor(height+ymin*my);
Используем соглашение о середине экрана: */
y0scr=height/2; /*целочисленное деление */
for(x=xmin;x<=xmax;x+=dx)
{
  if((fabs(x)-1e-4)>0)
  { /*исключение нуля */
    y=log(fabs(x));
    xscr=x0scr+floor(x*mx);
    yscr=y0scr-floor(y*my);
    /*Точка синим цветом: */
    Draw_Pixel(screen, xscr, yscr, 0x0000FF); 
  }
}

/* Отображение графика функции отрезками */
/* screen – инициализированная поверхность для рисования 640 на 480 пикселей, */
const Sint16 width=640, heght=480;
double xmin=-32.0, xmax=32.0, ymin, ymax;
double mx=10.0, my=10.0, dx=0.1, x1, y1, x2, y2;
Sint16 x0scr, y0scr, xscr1, yscr1, xscr2, yscr2;
x0scr=floor(-1*xmin*mx);
/* ymin – неизвестно, так нельзя:
y0scr=floor(height+ymin*my);
Используем соглашение о середине экрана: */
y0scr=height/2; /*целочисленное деление */
for(x1=xmin, x2=xmin+dx;x1<xmax;x1=x2, x2+=dx)
{
  if((fabs(x1)-1e-4)>0 && (fabs(x2)-1e-4)>0)
  { 
    /*исключение нуля */
    y1=log(fabs(x1)); /* можно исключить 
                        повтор вычислений*/
    y2=log(fabs(x2));
    xscr1=x0scr+floor(x1*mx);
    yscr1=y0scr-floor(y1*my);
    xscr2=x0scr+floor(x2*mx);
    yscr2=y0scr-floor(y2*my);
    /*Отрезок синим цветом: */
    Draw_Line(screen,xscr1,yscr1,
      xscr2,yscr2,0x0000FF);
  }
}

Полный текст примера попеременного рисования графика данной функции обоим способами выглядит следующим образом (файл main.c, проект создается согласно приложению 2 как консольное приложение Win32 с динамическим подключением библиотек):

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <SDL.h>
#include <SDL_draw.h>
#include <SDL_ttf.h>
void draw_by_pixels(SDL_Surface *who_draw);
void draw_by_line(SDL_Surface *who_draw);
int main(int argc, char *argv[])
{
  SDL_Surface *screen;
  SDL_Event event;
  int flag = 0;
  if (SDL_Init(SDL_INIT_VIDEO)) /* инициализация SDL */
  { /* При ошибке формируем сообщение и выходим */
    fprintf(stderr,"Ошибка в SDL_Init: %s\n",
            SDL_GetError());
    return 1; 
  }
  atexit(SDL_Quit);
  /* После инициализации собственно SDL 
    и установки atexit(SDL_Quit): */
  screen=SDL_SetVideoMode(640,480,32,SDL_ANYFORMAT);
  if (!screen) 
  {
    fprintf(stderr,"SDL mode failed: %s\n",
            SDL_GetError()); 
    return 1; 
  }
  /* Сначала рисуем по точкам синим цветом*/
  draw_by_pixels(screen);
  /* цикл ожидания событий */
  while(SDL_WaitEvent(&event))
  {
    if(event.type == SDL_QUIT || 
      (event.type == SDL_KEYDOWN &&
       event.key.keysym.sym == SDLK_ESCAPE))
    {
      SDL_Quit();
      return 0; /* пусть 0 - нормальное завершение*/
    }
    if(event.type == SDL_VIDEOEXPOSE)
    { /*чередуем способы перерисовки */
      if(flag)
        draw_by_line(screen);
      else
        draw_by_pixels (screen);  
      flag = !flag;
    }
  }
  fprintf(stderr,"WaitEvent failed: %s\n",
          SDL_GetError());
  SDL_Quit();
  return 2; /* Выход с другим кодом ошибки */
}
void draw_by_pixels(SDL_Surface *who_draw)
{
  /* Отображение графика функции по точкам */
  const Sint16 width=640, height=480;
  double xmin=-32.0, xmax=32.0, ymin, ymax;
  double mx=10.0, my=10.0, dx=0.001, x, y;
  Sint16 x0scr, y0scr, xscr, yscr;
  x0scr=floor(-1*xmin*mx);
  /* ymin - неизвестно, так нельзя: y0scr=floor(height+ymin*my);
    Используем соглашение о середине экрана: */
  y0scr=height/2; /*целочисленное деление */
  for(x=xmin;x<=xmax;x+=dx)
  {
    if((fabs(x)-1e-4)>0)
    { /*исключение нуля */
      y=log(fabs(x));
      xscr=x0scr+floor(x*mx);
      yscr=y0scr-floor(y*my);
      /*Точка синим цветом: */
      Draw_Pixel(who_draw, xscr, yscr, 0x0000FF); 
    }
  }
}
void draw_by_line(SDL_Surface *who_draw)
{/* Отображение графика функции отрезками */
  const Sint16 width=640, height=480;
  double xmin=-32.0, xmax=32.0, ymin, ymax;
  double mx=10.0, my=10.0, dx=0.1, x1, y1, x2, y2;
  Sint16 x0scr, y0scr, xscr1, yscr1, xscr2, yscr2;
  x0scr=floor(-1*xmin*mx);
  /* ymin - неизвестно, так нельзя: y0scr=floor(height+ymin*my);
    Используем соглашение о середине экрана: */
  y0scr=height/2; /*целочисленное деление */
  for(x1=xmin, x2=xmin+dx;x1<xmax;x1=x2, x2+=dx){
    if((fabs(x1)-1e-4)>0 && (fabs(x2)-1e-4)>0){ 
      /*исключение нуля */
      y1=log(fabs(x1)); /* можно исключить 
                          повтор вычислений*/
      y2=log(fabs(x2));
      xscr1=x0scr+floor(x1*mx);
      yscr1=y0scr-floor(y1*my);
      xscr2=x0scr+floor(x2*mx);
      yscr2=y0scr-floor(y2*my);
      /*Отрезок красным цветом: */
      Draw_Line(who_draw,xscr1,yscr1,
                xscr2,yscr2,0xFF0000);
    }
  }
}

Второй пример – рисование графика функции y=a+b/(x*c+d) на отрезке [xmin; xmax] с использованием максимальной площади экрана. При этом все параметры вводятся пользователем с клавиатуры.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "SDL.h"
#include "SDL_draw.h"
#include "SDL_ttf.h"
void draw_by_pixels(SDL_Surface *who_draw);
void draw_by_line(SDL_Surface *who_draw);

/*Вывод рационального числа с экранным редактированием. Параметры:
  где рисовать (поверхность), каким шрифтом, каким цветом,
  в какой прямоугольной области можно отображать вводимые данные, 
  исходное значение (значение по умолчанию) */
double input_double(SDL_Surface *who_draw, TTF_Font *fnt,
  SDL_Color color, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
  double defval);

/* Параметры функции и значения по умолчанию*/
double a=0, b=1, c=1, d=0;
const Sint16 width=640, height=480;
double xmin=-32.0, xmax=32.0, ymin, ymax;
double mx=10.0, my=10.0; 

Sint16 x0scr, y0scr;

int main(int argc, char *argv[])
{
  SDL_Surface *screen;
  SDL_Event event;
  TTF_Font *fnt;
  /* Для вывода текста */
  SDL_Color text_color;
  SDL_Rect dest; 
  SDL_Surface *text_surface = NULL;
  char txtbuf[100];
    
  int flag = 0; /* очередность использования методов 
                  рисования*/
  
  setbuf(stderr, NULL); /* Отмена буферизации stderr 
    для гарантированного сохранения сообщений об ошибках*/
  
  if (SDL_Init(SDL_INIT_VIDEO)) /* инициализация SDL */
  { /* При ошибке формируем сообщение и выходим */
    fprintf(stderr,"Ошибка в SDL_Init: %s\n",
            SDL_GetError());
    return 1; 
  }
  if (TTF_Init()) /* инициализация SDL_ttf */
  { /* При ошибке формируем сообщение и выходим */
    fprintf(stderr,"Ошибка в TTF_Init: %s\n",
            SDL_GetError());
    return 1; 
  }
  atexit(SDL_Quit);
  /* После инициализации собственно SDL 
    и установки atexit(SDL_Quit): */
  screen=SDL_SetVideoMode(640,480,32,SDL_ANYFORMAT);
  if (!screen) 
  {
    fprintf(stderr,"SDL mode failed: %s\n",SDL_GetError()); 
    return 1; 
  }
  /* Первый параметр должен быть полностью
    на одной строке вместе с кавычками! */
  SDL_WM_SetCaption("Построение 
                графика функции с 
                испольЕованием SDL. 
                Пример №2",NULL); 
  
  /* Загружаем шрифт размером sz пунктов*/
  fnt = TTF_OpenFont("ClearSans-Thin.ttf", 30); 
  printf("fnt = %p\n", fnt);
  if(!fnt)
    return 3;
  /* Цвета для ввода параметров  (ярко-зеленый): */
  text_color.r = 0; text_color.g = 255; text_color.b = 0;
  /* Ввод параметров: */
  dest.x = 0; dest.y = 0;
  text_surface = TTF_RenderUTF8_Solid(fnt, "a=", 
                                     text_color);
  if(text_surface)
  {
    SDL_BlitSurface(text_surface, NULL, screen, 
                    &dest);
    SDL_FreeSurface(text_surface); 
    text_surface = NULL;
  }
  SDL_Flip(screen);
  a = input_double(screen, fnt, text_color, 
            dest.x+dest.w, dest.y, 
            dest.x+dest.w + 200, dest.y+dest.h, a);
  dest.x = 0; dest.y = dest.y + dest.h;
  text_surface = TTF_RenderUTF8_Solid(fnt, "b=", 
                                      text_color);
  if(text_surface)
  {
    SDL_BlitSurface(text_surface, NULL, screen, 
                    &dest);
    SDL_FreeSurface(text_surface); 
    text_surface = NULL;
  }
  SDL_Flip(screen);
  b = input_double(screen, fnt, text_color, 
            dest.x+dest.w, dest.y, 
            dest.x+dest.w + 200, dest.y+dest.h, b);
  dest.x = 0; dest.y = dest.y + dest.h;
  text_surface = TTF_RenderUTF8_Solid(fnt, "c=", 
                                      text_color);
  if(text_surface)
  {
    SDL_BlitSurface(text_surface, NULL, screen, 
                    &dest);
    SDL_FreeSurface(text_surface); 
    text_surface = NULL;
  }
  SDL_Flip(screen);
  c = input_double(screen, fnt, text_color, 
            dest.x+dest.w, dest.y, 
            dest.x+dest.w + 200, dest.y+dest.h, c);
  dest.x = 0; dest.y = dest.y + dest.h;
  text_surface = TTF_RenderUTF8_Solid(fnt, "d=", 
                                      text_color);
  if(text_surface)
  {
    SDL_BlitSurface(text_surface, NULL, screen, 
                    &dest);
    SDL_FreeSurface(text_surface); 
    text_surface = NULL;
  }
  printf("before input_double(), d=%lf\n",d);
  SDL_Flip(screen);
  d = input_double(screen, fnt, text_color, 
            dest.x+dest.w, dest.y, 
            dest.x+dest.w + 200, dest.y+dest.h, d);
  dest.x = 0; dest.y = dest.y + dest.h;
  text_surface = TTF_RenderUTF8_Solid(fnt, "xmin=", 
                                      text_color);
  if(text_surface)
  {
    SDL_BlitSurface(text_surface, NULL, screen, 
                    &dest);
    SDL_FreeSurface(text_surface); 
    text_surface = NULL;
  }
  SDL_Flip(screen);
  xmin = input_double(screen, fnt, text_color, 
         dest.x+dest.w, dest.y, 
         dest.x+dest.w + 200, dest.y+dest.h, xmin);
  dest.x = 0; dest.y = dest.y + dest.h;
  text_surface = TTF_RenderUTF8_Solid(fnt, "xmax=", 
                                      text_color);
  if(text_surface)
  {
    SDL_BlitSurface(text_surface, NULL, screen, 
                    &dest);
    SDL_FreeSurface(text_surface); 
    text_surface = NULL;
  }
  SDL_Flip(screen);
  xmax = input_double(screen, fnt, text_color, 
         dest.x+dest.w, dest.y, 
         dest.x+dest.w + 200, dest.y+dest.h, xmax);
  /* Расчет масштабных коэффициентов:*/
  mx = (1.0 * width) / fabs(xmax-xmin);
  dest.x = 0; dest.y = dest.y + dest.h;
  memset(txtbuf,0,100);
  sprintf(txtbuf,"mx = %lf",mx);
  text_surface = TTF_RenderUTF8_Solid(fnt, txtbuf, 
                                      text_color);
  if(text_surface)
  {
    SDL_BlitSurface(text_surface, NULL, screen, 
                    &dest);
    SDL_FreeSurface(text_surface); 
    text_surface = NULL;
  }
  dest.x = 0; dest.y = dest.y + dest.h;
  memset(txtbuf,0,100);
  sprintf(txtbuf,"my = %lf",my);
  text_surface = TTF_RenderUTF8_Solid(fnt, txtbuf, 
                                      text_color);
  if(text_surface)
  {
    SDL_BlitSurface(text_surface, NULL, screen, 
                    &dest);
    SDL_FreeSurface(text_surface); 
    text_surface = NULL;
  }
  /* Сначала рисуем по точкам синим цветом*/
  draw_by_pixels(screen);
  SDL_Flip(screen);
  /* цикл ожидания событий */
  while(SDL_WaitEvent(&event))
  {
    if(event.type == SDL_QUIT || 
      (event.type == SDL_KEYDOWN &&
      event.key.keysym.sym == SDLK_ESCAPE))
    {
      TTF_CloseFont(fnt); /* Закрываем шрифт */
      SDL_Quit();
      return 0; /* пусть 0 - нормальное завершение*/
    }
    if(event.type == SDL_VIDEOEXPOSE)
    { /*чередуем способы перерисовки */
      if(flag)
        draw_by_line(screen);
      else
        draw_by_pixels(screen);  
      flag = !flag;
    }
  }
  fprintf(stderr,"WaitEvent failed: %s\n",
          SDL_GetError());
  SDL_Quit();
  return 2; /* Выход с другим кодом ошибки */
}
/* Отображение графика функции по точкам */
void draw_by_pixels(SDL_Surface *who_draw)
{ 
  double dx=0.001, x, y;
  Sint16 xscr, yscr;
  x0scr=floor(-1*xmin*mx);
  /* ymin - неизвестно, так нельзя:
  y0scr=floor(height+ymin*my);
  Используем соглашение о середине экрана: */
  y0scr=height/2; /*целочисленное деление */
  for(x=xmin; x<=xmax; x+=dx){
    if((fabs(x)-1e-4)>0){ /*исключение нуля */
      y=a+b/(c*x+d);
      xscr=x0scr+floor(x*mx);
      yscr=y0scr-floor(y*my);
      /* рисуем синим цветом только точки, 
помещающиеся на поверхности, иначе будет ошибка*/
      if(0<=xscr && xscr<width && 
         0<=yscr && yscr < height)
        Draw_Pixel(who_draw, xscr, yscr, 0x0000FF);
    }
  }
}
/* Отображение графика функции отрезками */
void draw_by_line(SDL_Surface *who_draw)
{ 
  double dx=0.1, x1, y1, x2, y2;
  Sint16 xscr1, yscr1, xscr2, yscr2;
  x0scr=floor(-1*xmin*mx);
  /* ymin - неизвестно, так нельзя:
y0scr=floor(height+ymin*my);
Используем соглашение о середине экрана: */
  y0scr=height/2; /*целочисленное деление */
  for(x1=xmin, x2=xmin+dx;x1<xmax;x1=x2, x2+=dx)
  {
    if((fabs(x1)-1e-4)>0 && (fabs(x2)-1e-4)>0)
    { /*исключение нуля */
      y1=a+b/(c*x1+d); /* можно исключить повтор 
                         вычислений*/
      y2=a+b/(c*x2+d);
      xscr1=x0scr+floor(x1*mx);
      yscr1=y0scr-floor(y1*my);
      xscr2=x0scr+floor(x2*mx);
      yscr2=y0scr-floor(y2*my);
      /*Отрезок красным цветом (для отрезков больше проверок:*/
      if( 0<=xscr1 && xscr1<width && 
          0<=yscr1 && yscr1 < height &&
          0<=xscr2 && xscr2<width && 
          0<=yscr2 && yscr2 < height)  
        Draw_Line(who_draw,xscr1,yscr1,xscr2,yscr2,
                  0xFF0000);
    }
  }
}
/* Функция вывода на поверхность одиночного символа заданным 
  шрифтом в указанных координатах заданным цветом */
void OutSymbolFntColorXY(SDL_Surface *screen, 
        TTF_Font *fnt, SDL_Color clr, 
        Sint16 x, Sint16 y, int symbolcode) 
{ /* Такая реализация корректно работает только с символами, 
    код которых в utf8 задается 1 байтом. То есть, только 
    символами ASCII, имеющими код от 0 до 127. Этого достаточно 
    для записи вещественных чисел. */
  SDL_Rect dest; dest.x = x; dest.y = y; 
  сhar s[2]; s[0]=symbolcode; s[1]='\0'; 
  SDL_Surface *TextSurface = TTF_RenderUTF8_Solid 
                                    (fnt, s, clr);
  SDL_BlitSurface(TextSurface, NULL, screen, 
                  &dest);
  SDL_FreeSurface(TextSurface); /* Освобождаем 
                                  поверхность */ 
  /* Обновляем только измененный участок целевой поверхности:*/
  SDL_UpdateRect(screen,dest.x,dest.y,
                 dest.w,dest.h);
} 

/* Функция ввода вещественного числа. Параметры см. выше при объявлении.*/
double input_double(SDL_Surface *who_draw, 
             TTF_Font *fnt, SDL_Color color, 
             Sint16 x1, Sint16 y1, 
             Sint16 x2, Sint16 y2, double defval)
{
#define WHOLE 7 /* кол-во знаков под целую часть мантиссы */
#define FRACTIONAL 6 /* кол-во знаков под дробную часть мантиссы */
#define EXP 3 /* кол-во знаков под степень */
#define E 308 /* максимальное значение степени */
  /* Символьный буфер для ввода и редактирования: размер исходя
    из заданного числа знаков, а также места по одному байту
    для возможного знака мантиссы и показателя, десятичной точки
    в мантиссе, разделителя мантиссы и показателя и завершающего
    NULL-терминатора.*/
  char s[WHOLE+FRACTIONAL+EXP+5]; 
  /* Все символы в нем делаем нулевыми */
  memset(s,0,WHOLE+FRACTIONAL+EXP+5);
  /* количество и положение различных символов в буфере */
  int _kol=-1, _whole=0, _fractional=0,   _exp=0,
    _pointf=0,_minusf=0,_ef=0,_minusEf=0; 
  /* Координаты рабочей области */
  Sint16 wrk_x1=x1, x=wrk_x1, wrk_y1=y1, y=wrk_y1;
  SDL_Event event;
  int i;
  while ( SDL_WaitEvent(&event) ){
    if (event.type == SDL_QUIT){ 
      /* По идее, надо вернуть его обратно в очередь 
      и пусть обрабатывает основная программа... 
      В данном примере не реализовано. */
      break; 
    }
    if (event.type == SDL_KEYDOWN)
    { /*Если нажата клавиша...*/
      if((!_pointf && _whole<WHOLE && 
          !_fractional && !_ef)||
         (_pointf && _fractional<FRACTIONAL 
          && !_ef)||(_ef && _exp<EXP))
      {/*При соблюдении условий смотрим, не цифра ли нажата...*/
        if(event.key.keysym.sym >= SDLK_0 && 
          event.key.keysym.sym <=SDLK_9) 
        {/* Цифровую клавиатуру пока игнорируем */
          char digitsym = 
                       (char) event.key.keysym.sym;
          OutSymbolFntColorXY(who_draw, fnt, color,
                              x,y, digitsym); 
          x+=20; s[++_kol]=digitsym; 
          if(!_pointf && _whole<WHOLE 
             && !_fractional && !_ef) 
            _whole=_whole+1; 
          else 
            if(_pointf && _fractional<FRACTIONAL 
               && !_ef) 
              _fractional=_fractional+1; 
            else 
              _exp=_exp+1; 
        }
      }
      if ((event.key.keysym.sym==SDLK_BACKSPACE)
           &&(x!=x1)) 
      {
        if(_whole<=WHOLE && !_pointf && !_ef 
           && _whole>0 && !_fractional) 
          _whole=_whole-1; /* удаление цифры 
                            из целой части */ 
        else 
          if(_pointf && _fractional>0 && 
             _fractional<=FRACTIONAL && 
             !_ef && _whole)
            _fractional=_fractional-1; /*удаление 
                     цифры из дробной части мантиссы */
          else 
            if(!_whole && _minusf) 
              _minusf=0; /* удаление минуса перед 
                           целой частью*/ 
            else 
              if (_pointf && !_fractional && 
                  !_ef && _whole) 
                _pointf=0; /*удаление точки*/ 
              else 
                if (_ef && !_exp && !_minusEf) 
                  _ef=0; /*удаление символа exp*/ 
                else 
                  if (_ef && !_exp && _minusEf) 
                    _minusEf=0; /* удаление минуса 
                                  после exp*/
                  else 
                    if (_ef && _exp<=EXP) 
                      _exp=_exp-1; /*удаление цифры 
                                    в степени*/ 
        /* Смещаемся на 20 пикселей влево (одно "знакоместо")*/
        x-=20;
        /* Затираем знакоместо черным цветом */
        Draw_FillRect(who_draw,x,y,20,42,0); 
        /* Обновляем экран */
        SDL_UpdateRect(who_draw,0,0,width,height); 
        _kol=_kol-1; /* Уменьшаем число символов */
        continue; /*Продолжаем ожидание событий */
      } 
      if(event.key.keysym.sym==SDLK_MINUS && 
        ((!_minusf && !_whole && !_ef) || 
        (!_minusEf && _ef && !_exp))) 
      {
        OutSymbolFntColorXY(who_draw, fnt, color, 
                            x,y,SDLK_MINUS); 
        x+=20; s[++_kol]=45; 
        if (!_minusf && !_whole && !_ef) 
          _minusf=1; 
        else 
          _minusEf=1; 
        continue;
      } 
      if (event.key.keysym.sym==SDLK_PERIOD && 
          !*pointf && !_ef)
      {
        if (!_whole)
        { 
          s[++_kol]=48; _whole=1; 
          OutSymbolFntColorXY(who_draw,fnt,color,
                              x,y,SDLK_0); 
        } 
        s[++_kol]=46; 
        OutSymbolFntColorXY(who_draw, fnt, color,
                            x,y,SDLK_PERIOD); 
        x+=20; 
        _pointf=1; 
        continue;
      } 
      if (event.key.keysym.sym==SDLK_e && !_ef)
      {
        OutSymbolFntColorXY(who_draw, fnt, color,
                            x,y,SDLK_e); 
        x+=20; s[++_kol]=101; _ef=1; 
        continue;
      }
      if (event.key.keysym.sym==SDLK_RETURN && 
          _kol!=-1) 
      { /* Завершение ввода */
        double tmp;
        s[_kol+1]='\0'; 
        sscanf(s,"%lf",&tmp); /*Нет проверки ввода! */
        return tmp;
      } 
      if (event.key.keysym.sym == SDLK_ESCAPE) 
        /* Будет возвращено значение по умолчанию */
        break; 
    } /* Конец обработки события SDL_KEYDOWN */
  } /* Конец цикла обработки событий */ 
  return defval;
} /* конец тела функции input_double */