Навигация:
<< >> Оглавление Указатель
Текст С++

Полный исходный текст на языке C++ для библиотеки (DLL) с моделью блока-узла графа, способного находить и показывать кратчайший путь между двумя заданными узлами. В примере из §2.13.4 прямые вызовы функций блоков заменены на отложенные для исключения переполнения стека в сложных графах. Изменения выделены цветом.

  // Использование функций блоков для поиска пути в графе
  // (вариант с отложенным вызовом функций)
  #include <windows.h>
  #include <math.h>
  #include <RdsDef.h>
  // Подготовка описаний сервисных функций
  
  #include <RdsFunc.h>

  //==========  ==========
  int WINAPI ( /*hinst*/,
                           unsigned long reason,
                           void* /*lpReserved*/)
  { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL
      { // Получение доступа к функциям RDS
        if(!GetInterfaceFunctions())
           // Сообщение: старая версия RDS
      }
    return 1;
  }
  //========= Конец главной функции =========

  //=========================================
  // Функции общего назначения
  //=========================================

  // Вычисление длины кривой Безье численным интегрированием
  // (метод Гаусса)
  double (double x1,double y1,double dx1,double dy1,
      double x2,double y2,double dx2,double dy2,double delta)
  { double ax,bx,cx,ay,by,cy;
    double a,b,c,d,e,q,n,k,T,l,h,I,w;
    int m;
    double x[3],s[3];

    // Вычисление коэффициентов параметрического вида
    ax=2*(x1-x2)+3*(dx1-dx2);
    bx=3*(x2-x1+dx2-2*dx1);
    cx=3*dx1;
    ay=2*(y1-y2)+3*(dy1-dy2);
    by=3*(y2-y1+dy2-2*dy1);
    cy=3*dy1;

    // Интегрирование
    b=1.0;
    n=delta*60.0; m=1; k=0.0;
    do
      { m*=2; a=0.0; T=sqrt(0.6); I=0.0;
        h=(b-a)/m;
        for(int j=1;j<=m;j++)
          { w=a+h;
            c=(w+a)/2; d=(w-a)/2; e=d*5.0/9.0;
            l=d*8.0/9.0; d*=T;
            x[0]=c-d; x[1]=c; x[2]=c+d;
            s[0]=e;   s[1]=l; s[2]=e;
            for(int i=0;i<3;i++)
              { // Вычисление подынтегральной функции (3 раза)
                double vx=3*ax*x[i]*x[i]+2*bx*x[i]+cx,
                       vy=3*ay*x[i]*x[i]+2*by*x[i]+cy;
                double f=sqrt(vx*vx+vy*vy);
                I+=s[i]*f;
              }
            a=w;
          }
        l=k; k=I;
      }
    while(fabs(I-l)>n);
    return I;
  }
  //=========================================

  // Определение расстояния между точкой связи и геометрическим
  // центром блока по структуре 
  double ( point)
  {  dim; // Структура описания размеров блока
    double dx,dy,xc,yc,xp,yp;

    if(point==NULL) // Указатель не передан - ошибка
      return -1.0;
    // Проверка – точка ли соединения с блоком передана?
    if(point->PointType!=)
      return -1.0;

    // Определение размеров блока point->Block
    dim.servSize=sizeof(dim); // Размер структуры
    if(!(point->Block,&dim,))
      return -1.0; // Не удалось получить размеры блока

    // Геометрический центр изображения блока
    xc=dim.Left+dim.Width/2.0;
    yc=dim.Top+dim.Height/2.0;
    // Абсолютные координаты точки связи
    xp=dim.BlockX+point->x;
    yp=dim.BlockY+point->y;
    // Вычисление расстояния между этими точками
    dx=xp-xc; dy=yp-yc;
    return sqrt(dx*dx+dy*dy);
  }
  //=========================================

  // Проверка связи (должно быть два блока на концах) и вычисление
  // длины дуги графа, соответствующей этой связи
  double ( Conn)
  {  ConnDescr;   // Структура описания связи
     PointDescr; // Структура описания точки
     LineDescr;   // Структура описания линии
    int BlockCnt;
    double len=0.0; // Общая длина дуги
    double x1,y1,x2,y2;

    // Заполнение служебных полей размеров структур
    ConnDescr.servSize=sizeof(ConnDescr);
    PointDescr.servSize=sizeof(PointDescr);
    LineDescr.servSize=sizeof(LineDescr);

    // Получаем описание связи – нам нужно число точек и линий в ней
    if(!(Conn,&ConnDescr))
      return -1.0;

    if(ConnDescr.ConnType!=)
      return -1.0; // Это не связь, а шина – шины нам не годятся

    // Проверяем число блоков на концах связи (должно быть ровно 2)
    BlockCnt=0;
    for(int i=0;i<ConnDescr.NumPoints;i++)
      { // Получаем описание точки связи i
        (Conn,i,&PointDescr);
        // Проверяем тип точки
        switch(PointDescr.PointType)
          { case : // Соединение с шиной – связь не годится
              return -1.0;
            case : // Соединение с блоком
              BlockCnt++;
              if(BlockCnt>2) // Связь разветвлена
                return -1.0;
              // Найдена точка соединения с блоком. Добавляем к len
              // расстояние между точкой и центром блока
              len+=(&PointDescr);
              break;
          } // switch(PointDescr.PointType)
      } // for(int i=0;...)
    if(BlockCnt!=2) // Связь соединяет менее двух блоков
     return -1.0;

    // Связь соединена ровно с двумя блоками – суммируем длину всех
    // ее линий
    for(int i=0;i<ConnDescr.NumLines;i++)
      { // Получаем описание линии связи i
        (Conn,i,&LineDescr,NULL,NULL);
        // Переводим целые координаты концов линии в double
        // для большей точности вычисления
        x1=LineDescr.x1; y1=LineDescr.y1;
        x2=LineDescr.x2; y2=LineDescr.y2;
        // В зависимости от типа линии, вычисляем ее длину и
        // добавляем к len
        switch(LineDescr.LineType)
          { case : // Отрезок прямой
              len+=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
              break;
            case : // Кривая Безье
              len+=(x1,y1,
                     LineDescr.dx1,LineDescr.dy1,
                     x2,y2,
                     LineDescr.dx2,LineDescr.dy2,
                     2);
              break;
          } // switch(LineDescr.LineType)
      } // for(int i=0;...)
    return len;
  }
  //=========================================

  // Визуально выделить связь
  void ( Conn)
  { // Определяем число альтернативных внешних видов
    int StylesCount=(Conn,,0,NULL);

    if(StylesCount<1)
      { // Для связи еще не определено ни одного внешнего вида
        // Создаем внешний вид 0 и делаем его толще текущего
         style; // Структура описания стиля связи
        // Получаем описание текущего внешнего вида связи
        style.servSize=sizeof(style);
        (Conn,&style);
        // Увеличиваем толщину и размер стрелки
        style.LineWidth*=3;
        style.ArrowLength*=2;
        style.ArrowWidth*=3;
        // Запоминаем эти параметры как альтернативный вид 0
        (Conn,,0,&style);
      }
    // Устанавливаем альтернативный вид 0
    (Conn,,0,NULL);
  }
  //=========================================

  // Снять выделение связи
  void ( Conn)
  { // Восстанавливаем исходный внешний вид связи
    (Conn,,0,NULL);
  }
  //=========================================

  //=========================================
  // Имена и параметры функций блоков
  //=========================================

  // Функция сброса параметров в узле графа
  #define PROGGUIDEGRAPHPATHFUNC_RESET \
          "ProgrammersGuide.GraphPath.Reset"
  // Структура парметров функции
  typedef struct
  {  servSize;  // Размер этой структуры
     ResetMark;  // TRUE – сбросить метку узла
     ResetBegin; // TRUE – сбросить флаг начала маршрута
     ResetEnd;   // TRUE – сбросить флаг конца маршрута
  } ;
  //=========================================

  // Функция получения параметров узла графа
  #define PROGGUIDEGRAPHPATHFUNC_GETPARAMS \
          "ProgrammersGuide.GraphPath.GetParams"
  // Среагировавший на функцию блок должен вернуть значение 1
  // Структура парметров функции
  typedef struct
  {  servSize; // Размер этой структуры
     Marked;    // В узле есть метка
    double Mark;    // Значение метки
     Begin;     // Этот узел – начало маршрута
     End;       // Этот узел – конец маршрута
  } ;
  //=========================================

  // Функция поиска начала и конца маршрута
  // (вызывается у всех блоков подсистемы)
  #define PROGGUIDEGRAPHPATHFUNC_FIND \
          "ProgrammersGuide.GraphPath.Find"
  // Структура параметров функции
  typedef struct
  {  servSize;         // Размер этой структуры
     BeginBlock; // Найденный идентификатор начала
     EndBlock;   // Найденный идентификатор конца
  } ;
  //=========================================

  // Пометить узел графа указанным вещественным числом и вызвать
  // эту же функцию у его соседей
  #define PROGGUIDEGRAPHPATHFUNC_MARK \
          "ProgrammersGuide.GraphPath.Mark"
  // Структура параметров функции
  typedef struct
  {  servSize;      // Размер этой структуры
    double Mark;         // Устанавливаемое значение метки
     Previous;// Блок, от которого пришла метка
  } ;
  //=========================================

  // Выделить маршрут от данного блока к началу
  #define PROGGUIDEGRAPHPATHFUNC_BACKTRACE \
          "ProgrammersGuide.GraphPath.BackTrace"
  // Параметров у функции нет
  //=========================================

  // Глобальные переменные для хранения идентификаторов функций блоков
  int =0,      // 
      =0, // 
      =0,     // 
      =0,      // 
      =0; // 
  //=========================================

  //=========================================
  // Функции-оболочки (для лучшей читаемости)
  //=========================================

  // Сбросить у узлов графа в заданной подсистеме заданные маркеры
  void (
     Sys, // Подсистема
     mark,       // Сбросить метки узлов
     begin,      // Сбросить начало маршрута
     end)        // Сбросить конец маршрута
  { // Структура параметров функции 
     params;
    // Заполняем поле размера структуры парааметров
    params.servSize=sizeof(params);
    // Заполняем поля структуры параметров
    params.ResetMark=mark;
    params.ResetBegin=begin;
    params.ResetEnd=end;
    // Вызываем  у всех
    // блоков подсистемы Sys
    (Sys,,&params,0);
  }
  //=========================================

  // Найти блоки начала и конца маршрута в заданной подсистеме
   (
     Sys,     // Подсистема с графом
     *pBegin, // Возвращаемый идентификатор начала
     *pEnd)   // Возвращаемый идентификатор конца
  {  params;
    // Заполняем поле размера структуры паараметров
    params.servSize=sizeof(params);
    // Обнуляем поля идентификаторов начала и конца
    params.BeginBlock=params.EndBlock=NULL;
    // Вызываем  у всех блоков в
    // подсистеме Sys, разрешая блокам остановить вызовы
    (Sys,,&params,
        );
    // Копируем найденные идентификаторы в переданные указатели
    if(pBegin) *pBegin=params.BeginBlock;
    if(pEnd) *pEnd=params.EndBlock;
    // Возвращаем TRUE, если установлены и начало, и конец
    return params.BeginBlock!=NULL && params.EndBlock!=NULL;
  }
  //=========================================

  // Поиск маршрута в графе в заданной подсистеме
  void ( System)
  {  StartBlock,EndBlock;
     markparams;

    // Считаем, что маркировка всего графа сброшена

    // Ищем начальную и конечную точку маршрута
    if(!(System,&StartBlock,&EndBlock))
      return; // Начало или конец не найдены
    // Начало маршрута – StartBlock, конец - EndBlock

    // Маркируем граф от начала маршрута
    markparams.servSize=sizeof(markparams);
    markparams.Mark=0.0; // Начало маркируется значением 0
    markparams.Previous=NULL;// Это значение не пришло от какого-то
                             // соседнего блока
    // Вызываем функцию маркировки для начального блока
    // (StartBlock,,&markparams);  
    (StartBlock,,             
        &markparams,sizeof(markparams),);            

    // Теперь отслеживаем кратчайший путь в обратном направлении
    // (от конечного блока)
    // (EndBlock,,NULL);      
    (EndBlock,,          
        NULL,0,);                                     
  }
  //=========================================

  //=========================================
  // Модель блока и дополнительные функции
  //=========================================

  // 
  #define pStart    ((char *)(BlockData->VarTreeData))
  #define Start (*((char *)(pStart)))
  #define Ready (*((char *)(pStart+RDS_VSZ_S)))
  #define sBegin (*((char *)(pStart+2*RDS_VSZ_S)))
  #define sEnd (*((char *)(pStart+2*RDS_VSZ_S+RDS_VSZ_L)))
  #define sInPath (*((char *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_L)))
  #define sMarked (*((char *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_L)))
  #define sPathMark (*((double *)(pStart+2*RDS_VSZ_S+4*RDS_VSZ_L)))
  //=========================================

  // Сделать этот блок началом маршрута (прототип функции)
  void ( BlockData);
  // Сделать этот блок концом маршрута (прототип функции)
  void ( BlockData);
  // Реакция блока на функцию  (прототип функции)
  void ( BlockData,
           *reset);
  // Реакция блока на функцию  (прототип функции)
  void ( BlockData,
           *params);
  // Реакция блока на функцию  (прототип функции)
  void ( BlockData);
  // Программное рисование внешнего вида блока (прототип функции)
  void ( BlockData, draw);
  //=========================================

  // Модель блока-узла графа
  extern "C" __declspec(dllexport)
    int  GraphNode(int CallMode,
             BlockData,
             ExtParam)
  { // Вспомогательная - указатель на данные функции блока
     func;

    switch(CallMode)
      { // Инициализация
        case :
          // Регистрация функций
          if(==0)
            =(
              PROGGUIDEGRAPHPATHFUNC_GETPARAMS);
          if(==0)
            =(
              PROGGUIDEGRAPHPATHFUNC_RESET);
          if(==0)
            =(
              PROGGUIDEGRAPHPATHFUNC_FIND);
          if(==0)
            =(
              PROGGUIDEGRAPHPATHFUNC_MARK);
          if(==0)
            =(
              PROGGUIDEGRAPHPATHFUNC_BACKTRACE);
          break;

        // Проверка типов переменных
        case :
          return strncmp((char*)ExtParam,"{SSLLLLD",8)?
            :;

        // Вызов контекстного меню блока
        case :
          // 
          // 
          // 
          ("Начало маршрута",
            sBegin?:0,0,0);
          ("Конец маршрута",
            sEnd?:0,1,0);
          ("Сбросить все",0,2,0);
          break;

        // Быбор пункта меню
        case :
          switch((()ExtParam)->Function)
            { case 0: // Начало маршрута
                (BlockData);
                (BlockData->Parent,FALSE);
                break;
              case 1: // Конец маршрута
                (BlockData);
                (BlockData->Parent,FALSE);
                break;
              case 2: // Сбросить все
                (BlockData->Parent,TRUE,TRUE,TRUE);
                (BlockData->Parent,FALSE);
                break;
            }
          break;

        // Вызов функции блока
        case :
          func=()ExtParam;
          if(func->Function==) // Сброс параметров
            (BlockData,
              (*)(func->Data));
          else if(func->Function==GraphFuncGetParams)
            { // Получение параметров узла
               *get=
                (*)(func->Data);
              if(get!=NULL &&
                 get->servSize>=sizeof())
                { // Допустимый размер структуры параметров
                  get->Marked=(sMarked!=0);
                  get->Mark=sPathMark;
                  get->Begin=(sBegin!=0);
                  get->End=(sEnd!=0);
                }
              return 1; // Блок является узлом графа
            }
          else if(func->Function==)
            { // Поиск начала и конца маршрута
               *find=
                (*)(func->Data);
              if(find==NULL) break; // Нет параметров
              if(find->servSize<sizeof())
                break; // Недопустимый размер структуры параметров
              if(sBegin) // Этот блок – начало маршрута
                find->BeginBlock=BlockData->Block;
              if(sEnd) // Этот блок – конец маршрута
                find->EndBlock=BlockData->Block;
              if(find->BeginBlock!=NULL && find->EndBlock!=NULL)
                func->Stop=TRUE; // Оба конца маршрута найдены
            }
          else if(func->Function==) // Пометить граф
            (BlockData,
              (TProgGuideFuncMarkParams*)(func->Data));
          else if(func->Function==)
            (BlockData); // Выделить маршрут
          break;

        // Рисование
        case :
          (BlockData,()ExtParam);
          break;
      }
    return ;
  }
  //=========================================

  // Рисование узла графа
  // 
  // 
  // 
  void ( BlockData, draw)
  { static char beg[]="Н",end[]="К"; // Метки начала и конца
    int w,h;

    // Рисуем прямоугольник, цвет которого зависит от переменной
    // блока sInPath
    (0,,1,0,);
    (0,,sInPath?0xff00:0xffffff);
    (draw->Left,draw->Top,
        draw->Left+draw->Width,draw->Top+draw->Height);

    if(sBegin==0 && sEnd==0) // Нет флагов начала и конца маршрута
      return;
    // Устанавливаем шрифт высотой в весь блок
    (0,,0);
    (0,"Arial Cyr",
      draw->Height,0,,0,FALSE,FALSE,FALSE,FALSE);

    if(sBegin) // Рисуем метку начала
      { (beg,&w,&h);
        (draw->Left+(draw->Width-w)/2,
                     draw->Top+(draw->Height-h)/2,
                     beg);
      }
    if(sEnd) // Рисуем метку конца
      { (end,&w,&h);
        (draw->Left+(draw->Width-w)/2,
                     draw->Top+(draw->Height-h)/2,
                     end);
      }
  }
  //=========================================

  // Реакция блока на функцию 
  void ( BlockData,
           *reset)
  { if(reset==NULL) return; // Нет параметров функции
    if(reset->servSize<sizeof(TProgGuideFuncResetParams))
      return; // Размер переданной структуры меньше ожидаемого

    if(reset->ResetMark)
      { // Сбрасываем выделение всех присоединенных к блоку связей
         c=NULL;
        for(;;) // Перебираем все связи, подключенные к блоку
          { c=(BlockData->Block,c,TRUE,TRUE,NULL);
            if(c==NULL) break; // Все связи перебраны
            // Снимаем выделение связи c
            (c);
          }
        // Сбрасываем флаги наличия метки и принадлежности
        // к выделенному маршруту
        sMarked=sInPath=0;
      }

    if(reset->ResetBegin) // Сбрасываем флаг начала маршрута
      sBegin=0;
    if(reset->ResetEnd) // Сбрасываем флаг конца маршрута
      sEnd=0;
  }
  //=========================================

  // Сделать данный блок началом маршрута
  void ( BlockData)
  { if(sBegin) // Блок уже является началом маршрута
      return;
    // Сбрасываем старый флаг начала маршрута и разметку всего графа
    (BlockData->Parent,TRUE,TRUE,FALSE);
    // Устанавливаем флаг начала маршрута у данного блока
    sBegin=1;
    // Ищем маршрут в графе
    (BlockData->Parent);
  }
  //=========================================

  // Сделать данный блок концом маршрута
  void ( BlockData)
  { if(sEnd) // Блок уже является концом маршрута
      return;
    // Сбрасываем старый флаг конца маршрута и разметку всего графа
    (BlockData->Parent,TRUE,FALSE,TRUE);
    // Устанавливаем флаг конца маршрута у данного блока
    sEnd=1;
    // Ищем маршрут в графе
    (BlockData->Parent);
  }
  //=========================================

  // Прототип функции обратного вызова для перечисления соседей блока
    (
       src,
       dest,
       data);
  //=========================================

  // Пометить данный блок и его соседей
  void ( BlockData,
           *params)
  { if(params==NULL) return; // Нет параметров функции
    if(params->servSize<sizeof())
      return; // Размер переданной структуры меньше ожидаемого

    if(sMarked!=0 && sPathMark<=params->Mark)
      return; // Блок уже помечен меньшим или таким же числом

    // Блок не помечен вообще или помечен большим числом -
    // помечаем его и его соседей новыми числами
    sMarked=1; // У блока есть метка
    sPathMark=params->Mark; // Новая метка блока

    if(sEnd) // Это – конец маршрута, дальше помечать незачем
      return;

    // Помечаем всех соседей блока, кроме params->Previous,
    // суммой метки этого блока и длины дуги к соседу
    (BlockData->Block,
      |,
      ,params);
  }
  //=========================================

  // Функция обратного вызова для GraphNode_OnMarkBlock
    (
       src,
       dest, data)
  {  *src_params=
      (*)data;
     dest_params;
    double ArcLen;

    // Функция вызвана для пары блоков: src->Block – данный блок,
    // dest->Block – его сосед. Их соединяет связь dest->Owner (или
    // src->Owner – поля Owner у структур src и dest равны, поскольку
    // обе точки принадлежат одной и той же связи)

    // Сравниваем найденного соседа с блоком,
    // который не нужно помечать
    if(src_params->Previous==dest->Block)
      return TRUE;

    // Связь должна подходить ко входу блока dest->Block
    // (движение в графе возможно только по стрелкам)
    if(dest->Source) // Точка dest соединена с выходом блока
      return TRUE;

    // Является ли найденный сосед узлом графа?
    if(!(dest->Block,,NULL))
      return TRUE; // Не является

    // Вычисляем длину дуги между блоками
    ArcLen=(dest->Owner);
    if(ArcLen<0.0) // Связь разветвленная или оборванная
      return TRUE; // Такая связь не может быть дугой

    // Помечаем найденный соседний блок суммой маркировки данного
    //  блока (src_params->Mark) и длины дуги к найденному (ArcLen)
    dest_params.servSize=sizeof(dest_params);
    dest_params.Mark=src_params->Mark+ArcLen;
    dest_params.Previous=src->Block; // Блок, от которого
                                        // пришла метка
    // (dest->Block,,&dest_params);  
    (dest->Block,,                  
        &dest_params,sizeof(dest_params),);               
    return TRUE;
  }
  //=========================================

  // Проследить и выделить маршрут от данного блока в
  // обратном направлении
  void ( BlockData)
  {  PrevBlock;
     PrevConn,c;
    double minMark;
     conndescr;
     pointdescr;
     params;

    if(!sMarked) // У блока нет метки
      return;

    sInPath=1; // Помечаем данный блок как принадлежащий маршруту

    if(sBegin) // Это начало маршрута – мы выделили его весь
      return;

    // Заполняем служебные поля размера у всех структур,
    // которые нам потребуются
    conndescr.servSize=sizeof(conndescr);
    pointdescr.servSize=sizeof(pointdescr);
    params.servSize=sizeof(params);

    // Ищем среди соседей данного блока блок с наименьшей меткой
    PrevBlock=NULL;
    // Перебираем все связи блока
    c=NULL;
    for(;;)
      {  connBlock;
        double connMark;
        int numBlocks;
        // Получаем очередную связь блока, соединенную с его входом
        c=(BlockData->Block,c,TRUE,FALSE,NULL);
        if(c==NULL) break; // Связи кончились
        // Получаем параметры этой связи
        (c,&conndescr);
        // Перебираем все точки связи c и ищем среди них соединение
        // с узлом графа на другом ее конце
        connBlock=NULL;
        numBlocks=0;
        for(int i=0;i<conndescr.NumPoints;i++)
          { // Получаем описание точки связи i
            (c,i,&pointdescr);
            // Проверяем тип точки
            if(pointdescr.PointType==)
              { // Связь, соединенная с шиной, нам не годится
                connBlock=NULL;
                break;
              }
            if(pointdescr.PointType!=)
              continue;
            // Найдена точка соединения с блоком
            numBlocks++;
            if(numBlocks>2) // Разветвленная связь – не годится
              { connBlock=NULL;
                break;
              }
            if(pointdescr.Block==BlockData->Block)
              continue; // Это не сосед, а сам данный блок
            // Получаем параметры узла блока-соседа
            if(!(pointdescr.Block,
                 ,&params))
              { // Блок не является узлом графа
                connBlock=NULL;
                break;
              }
            // Нашли соседний блок, являющийся узлом графа
            if(params.Marked) // У соседнего узла есть метка
              { connBlock=pointdescr.Block; // Запоминаем
                connMark=params.Mark;
              }
          } // for(int i=0;...)
        // Цикл перебора точек связи закончен. В cоnnBlock должен
        // находиться идентификатор узла, который эта связь соединяет
        // с данным блоком, а в connMark – его метка.
        if(connBlock) // Есть узел графа на другом конце связи
          { if(PrevBlock==NULL || minMark>connMark)
              { // Найден узел с меньшей маркировкой
                PrevBlock=connBlock;
                minMark=connMark;
                PrevConn=c;
              }
          }
      } // for(;;)

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

    if(PrevBlock)
      { // Визуально выделяем связь
        (PrevConn);
        // Вызываем функцию обратного прослеживания маршрута
        // от найденного блока
        // (PrevBlock,,NULL);  
        (PrevBlock,,      
          NULL,0,);                                    
      }
  }
  //=========================================

  // Отмена макроопределений переменных блока
  #undef sPathMark
  #undef sMarked
  #undef sInPath
  #undef sEnd
  #undef sBegin
  #undef Ready
  #undef Start
  #undef pStart
  //=========================================


<< >> Оглавление Указатель