Полный исходный текст на языке C++ для библиотеки (DLL) с моделями блоков, участвующих в расчетах траектории полета снаряда и иллюстрирующих программный сброс и перезапуск расчета. Библиотека содержит четыре модели:
- Ballistics – блок расчета траектории полета снаряда;
- ArtSearch – блок поиска угла возвышения для заданной дальности полета;
- ArtWalk – блок перебора углов для построения графика зависимости дальности полета от угла возвышения;
- StopCalc – блок, останавливающий расчет по сигналу (копия модели из §2.14.1, сюда она включена для того, чтобы все модели из рассматриваемых примеров схем находились в одной библиотеке).
// Программный сброс расчета на примере баллистических вычислений #include <windows.h> #include <math.h> #include <RdsDef.h> // Подготовка описаний сервисных функций #define RDS_SERV_FUNC_BODY GetInterfaceFunctions #include <RdsFunc.h> // Глобальная переменная для значения ошибки double DoubleErrorValue; //========== Главная функция DLL ========== int WINAPI DllMain(HINSTANCE /*hinst*/, unsigned long reason, void* /*lpReserved*/) { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL { // Получение доступа к функциям RDS if(!GetInterfaceFunctions()) RDS_SERV_ERROR_MSGW // Сообщение: старая версия RDS else rdsGetHugeDouble(&DoubleErrorValue); } return 1; } //========= Конец главной функции ========= // Проверка наличия связи у входа блока BOOL CheckBlockInputConnection( RDS_BHANDLE Block, // Идентификатор блока int num, // Номер входа RDS_PVARDESCRIPTION pVarDescr) // Указатель на структуру // описания переменной { RDS_CHANDLE c; // Идентификатор связи RDS_POINTDESCRIPTION PtDescr; // Структура описания точки связи // Заполнение служебных полей структур их размерами PtDescr.servSize=sizeof(PtDescr); pVarDescr->servSize=sizeof(RDS_VARDESCRIPTION); // Получение описания переменной блока по номеру if(rdsGetBlockVar(Block,num,pVarDescr)==NULL) return FALSE; // Нет такой переменной // Перебор всех связей, подключенных к этому блоку c=NULL; for(;;) { // Найти связь, следующую за c, и заполнить структуру // описания точки соединения PtDescr c=rdsGetBlockLink(Block,c,TRUE,FALSE,&PtDescr); if(c==NULL) // Больше нет связей break; // Найдена очередная связь – сравнение имени заданной // переменной с именем переменной точки этой связи if(strcmp(PtDescr.VarName,pVarDescr->Name)==0) return TRUE; // Имена совпали – есть связь, соединенная // с переменной блока } // Все подключенные связи перебраны, а связь, подключенная // к заданной переменной так и не была найдена return FALSE; } //=========================================== // Добавление поля для ввода или индикации вещественного параметра BOOL AddWinEditOrDisplayDouble( RDS_HOBJECT window, // Идентификатор объекта-окна RDS_BHANDLE Block, // Блок int varnum, // Номер переменной в блоке int ctrlnum, // Идентификатор поля ввода в окне const char *title) // Заголовок поля или NULL { // Структура описания переменной блока RDS_VARDESCRIPTION VarDescr; // Проверка наличия связи у переменной varnum в блоке Block // и заполнение структуры VarDescr описанием переменной BOOL conn=CheckBlockInputConnection(Block,varnum,&VarDescr); if(conn) // К переменной подключена связь { // Вспомогательные переменные char *caption; // Заголовок поля double *cur; // Указатель на данные переменной // Заголовок поля формируется из имени переменной и // текста "подключена связь" caption=rdsDynStrCat(title?title:VarDescr.Name, " (подключена связь)", FALSE); // Добавление поля для индикации текущего значения rdsFORMAddEdit(window,0,ctrlnum,RDS_FORMCTRL_DISPLAY, caption,80); // Освобождение динамически сформированной строки заголовка поля rdsFree(caption); // Получение указателя на данные переменной cur=(double*)rdsGetBlockVarBase(Block,varnum,NULL); // Проверка – переменная должна существовать и иметь тип double if(cur!=NULL && VarDescr.Type=='D') // Занесение текущего значения переменной в поле rdsSetObjectDouble(window,ctrlnum,RDS_FORMVAL_VALUE, *cur); } else // К переменной не подключена связь { // Вспомогательная переменная для значения по умолчанию char *defval; // Получение строки со значением переменной по умолчанию // (необходимо потом освободить при помощи rdsFree) defval=rdsGetBlockVarDefValueStr(Block,varnum,NULL); // Добавление поля для ввода параметра rdsFORMAddEdit(window,0,ctrlnum,RDS_FORMCTRL_EDIT, title?title:VarDescr.Name,80); // Занесение в поле ввода значения перменной по умолчанию rdsSetObjectStr(window,ctrlnum,RDS_FORMVAL_VALUE,defval); // Освобождение динамически сформированной строки rdsFree(defval); } // Возврат: TRUE – есть связь, FALSE – нет связи return conn; } //=========================================== // Функция настройки вещественных параметров, хранящихся в // статических переменных блока. // Возвращает: 1 – ОК, 0 – отмена. // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" int SetupDoubleVars( RDS_BHANDLE Block, // Настраиваемый блок const char *wintitle, // Заголовок окна настройки const char **vars) // Массив строк-описаний полей ввода { RDS_HOBJECT window; // Идентификатор вспомогательного объекта BOOL ok; // Пользователь нажал "OK" int count=0; BOOL *Connections; int *VarNums; if(vars==NULL) // Ошибка – массив не передан return 0; // Подсчитываем число полей ввода в массиве vars while(vars[count]!=NULL) count++; if(!count) // Ошибка – массив пуст return 0; // Отводим вспомогательный массив логических значений, в котором // будем запоминать наличие связей, присоединенных к переменным, // а также массив целых чисел для номеров переменных, считанных // из строк массива vars Connections=new BOOL[count]; VarNums=new int[count]; // Создаем окно с заголовком wintitle window=rdsFORMCreate(FALSE,-1,-1,wintitle); // Добавляем поля ввода из массива vars, заполняя массивы // Connections и VarNums for(int i=0;i<count;i++) { char *str; // Считываем из строки номер переменной. Указатель на первый // после номера символ запишется в str. VarNums[i]=strtol(vars[i],&str,0); // Если после номера строка кончается, присваиваем str // значение NULL, чтобы в качестве заголовка было // использовано имя переменной if(*str==0) str=NULL; // Добавляем поле ввода, запоминаем наличие связи Connections[i]=AddWinEditOrDisplayDouble(window,Block, VarNums[i],i,str); } // Открываем окно ok=rdsFORMShowModalEx(window,NULL); if(ok) { // Нажата кнопка OK – запись параметров в переменные for(int i=0;i<count;i++) if(!Connections[i]) // У переменной нет связи { char *str=rdsGetObjectStr(window,i,RDS_FORMVAL_VALUE); // Устанавливаем новое значение по умолчанию rdsSetBlockVarDefValueStr(Block,VarNums[i],str); } } // Удаляем вспомогательные массивы delete[] Connections; delete[] VarNums; // Уничтожаем окно rdsDeleteObject(window); // Возвращаем 1 или 0 return ok?1:0; } //=========================================== //=========================================== // Модель блока расчета внешней баллистики //=========================================== // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" extern "C" __declspec(dllexport) int RDSCALL Ballistics(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { RDS_PDYNVARLINK Link; double t,dt,A,n,F,Fx,Fy,xp,yp; // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define D (*((double *)(pStart+2*RDS_VSZ_S))) #define m (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D))) #define v0 (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D))) #define Angle (*((double *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_D))) #define l0 (*((double *)(pStart+2*RDS_VSZ_S+4*RDS_VSZ_D))) #define h0 (*((double *)(pStart+2*RDS_VSZ_S+5*RDS_VSZ_D))) #define ValSet (*((char *)(pStart+2*RDS_VSZ_S+6*RDS_VSZ_D))) #define x (*((double *)(pStart+2*RDS_VSZ_S+6*RDS_VSZ_D+RDS_VSZ_L))) #define y (*((double *)(pStart+2*RDS_VSZ_S+7*RDS_VSZ_D+RDS_VSZ_L))) #define vx (*((double *)(pStart+2*RDS_VSZ_S+8*RDS_VSZ_D+RDS_VSZ_L))) #define vy (*((double *)(pStart+2*RDS_VSZ_S+9*RDS_VSZ_D+RDS_VSZ_L))) #define v (*((double *)(pStart+2*RDS_VSZ_S+10*RDS_VSZ_D+RDS_VSZ_L))) #define Impact (*((char *)(pStart+2*RDS_VSZ_S+11*RDS_VSZ_D+RDS_VSZ_L))) #define t0 (*((double *)(pStart+3*RDS_VSZ_S+11*RDS_VSZ_D+RDS_VSZ_L))) #define InFlight (*((char *)(pStart+3*RDS_VSZ_S+12*RDS_VSZ_D+RDS_VSZ_L))) // Массив описания параметров для универсальной функции настройки static const char *setup[]={ "6Длина ствола, м", "7Высота оси, м", "2Диаметр снаряда, м", "3Масса снаряда, кг", "4Начальная скорость, м/с", "5Угол вылета, град.", NULL}; switch(CallMode) { // Инициализация case RDS_BFM_INIT: // Подписка на динамическую переменную "DynTime" Link=rdsSubscribeToDynamicVar(RDS_DVPARENT,"DynTime", "D",TRUE); BlockData->BlockData=Link; break; // Очистка case RDS_BFM_CLEANUP: // Прекращение подписки на "DynTime" rdsUnsubscribeFromDynamicVar( (RDS_PDYNVARLINK)BlockData->BlockData); break; // Проверка типов переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSDDDDDDLDDDDDSDL}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Вызов функции настройки case RDS_BFM_SETUP: return SetupDoubleVars(BlockData->Block, "Внешняя баллистика",setup); // Изменение динамической переменной case RDS_BFM_DYNVARCHANGE: // Получаем доступ к динамической переменной времени Link=(RDS_PDYNVARLINK)BlockData->BlockData; if(Link==NULL || Link->Data==NULL) // Нет доступа break; t=*((double*)Link->Data); // В t – текущее время if(t==t0) // Время не изменилось - ждем break; dt=t-t0; // В dt – интервал времени с прошлого шага t0=t; // Запоминаем время в t0 чтобы при следующем // изменени DynTime (t) можно было вычислить dt if(!ValSet) // Начальные значения еще не считаны { // Начинаем расчет траектории снаряда double alpha=Angle*M_PI/180.0; // Угол в радианах // Занесение в переменные начальных значений vx=v0*cos(alpha); vy=v0*sin(alpha); v=v0; x=l0*cos(alpha); y=h0+l0*sin(alpha); // Сбрасываем сигнал падения Impact=0; // Разрешаем расчет и взводим ValSet InFlight=ValSet=1; } else if(!InFlight) // Снаряд не в полете – ничего не делаем break; // Вычисление модуля вектора скорости и силы сопротивления // по формуле Забудского v=sqrt(vx*vx+vy*vy); if(v<240.0) { A=0.0140; n=2; } else if(v<295.0) { A=0.0000583; n=3; } else if(v<375.0) { A=0.000000000670; n=5; } else if(v<419.0) { A=0.0000940; n=3; } else if(v<550.0) { A=0.0394; n=2; } else if(v<800.0) { A=0.2616; n=1.7; } else { A=0.713; n=1.55; } F=A*M_PI*D*D*pow(v,n)/4.0; // Сила сопротивления // Горизонтальная и вертикальная компоненты F Fx=F*vx/v; Fy=F*vy/v; // Запоминаем текущие значения координат xp=x; yp=y; // Вычисляем новые значения координат по // разностным уравнениям x+=dt*vx; y+=dt*vy; // Вычисляем новые значения компонент вектора скорости // по разностным уравнениям vx-=dt*Fx/m; vy-=dt*(9.807+Fy/m); if(y<0.0) // Снаряд встретился с поверхностью { Impact=1; // Взводим выходной сигнал падения снаряда InFlight=0; // Прекращаем расчет траектории // Вычисляем координату встречи с поверхностью x=xp-yp*(x-xp)/(y-yp); y=vx=vy=0; } Ready=1; // Для передачи выходов по связям break; } return RDS_BFR_DONE; // Отмера макроопределений переменных #undef InFlight #undef t0 #undef Impact #undef v #undef vy #undef vx #undef y #undef x #undef ValSet #undef h0 #undef l0 #undef Angle #undef v0 #undef m #undef D #undef Ready #undef Start #undef pStart } //=========================================== //=========================================== // Поиск угла возвышения для заданной дальности //=========================================== // Личная область данных блока class TArtSearchData { public: BOOL SelfReset; // Блок сам сбросил подсистему int Mode; // Текущее состояние алгоритма: #define ASMODE_READY 0 // Готов к поиску #define ASMODE_SEARCHING 1 // Идет поиск #define ASMODE_FINALRUN 2 // Последний прогон #define ASMODE_FINISHED 3 // Поиск завершен double AngleStep; // Текущий шаг изменения угла double AngleToSet;// Угол, который нужно установить // после сброса double OptAngle; // Наилучший на данный момент угол double OptMiss; // Наименьший на данный момент промах BOOL FirstStep; // Проведенное моделирование – первое с // новым шагом изменения угла // Ограничение диапазона и точности установки угла double FixAngle(double a,double amin,double amax,double acc) { if(a<amin) return amin; if(a>amax) return amax; return floor((a-amin)/acc)*acc+amin; }; // Вывод сообщения о результатах поиска // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" void ShowResults(void) { char *str, *angle=rdsDtoA(OptAngle,-1,NULL), *miss=rdsDtoA(OptMiss,0,NULL); // Формрование динамической строки с сообщением str=rdsDynStrCat("Угол возвышения: ",angle,FALSE); rdsAddToDynStr(&str," гр.\nПромах: ",FALSE); rdsAddToDynStr(&str,miss,FALSE); rdsAddToDynStr(&str," м",FALSE); // Вывод текста rdsMessageBox(str,"Поиск завершен",MB_OK); // Освобождение всех динамических строк rdsFree(str); rdsFree(angle); rdsFree(miss); }; // Конструктор класса TArtSearchData(void) { SelfReset=FALSE; Mode=ASMODE_READY; }; }; //=========================================== // Модель блока поиска угла для заданной дальности // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" extern "C" __declspec(dllexport) int RDSCALL ArtSearch(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { TArtSearchData *data=(TArtSearchData*)(BlockData->BlockData); double delta; // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define MinAngle (*((double *)(pStart+2*RDS_VSZ_S))) #define MaxAngle (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D))) #define Accuracy (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D))) #define Distance (*((double *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_D))) #define x (*((double *)(pStart+2*RDS_VSZ_S+4*RDS_VSZ_D))) #define Impact (*((char *)(pStart+2*RDS_VSZ_S+5*RDS_VSZ_D))) #define Angle (*((double *)(pStart+3*RDS_VSZ_S+5*RDS_VSZ_D))) // Массив описания параметров для универсальной функции настройки static const char *setup[]={ "2Минимальный угол, град.", "3Максимальный угол, град.", "4Точность по углу, град.", "5Дальность цели, м", NULL}; switch(CallMode) { // Инициализация case RDS_BFM_INIT: BlockData->BlockData=new TArtSearchData(); break; // Очистка case RDS_BFM_CLEANUP: delete data; break; // Проверка типов переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSDDDDDSD}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Вызов функции настройки case RDS_BFM_SETUP: return SetupDoubleVars(BlockData->Block, "Поиск угла",setup); // Запуск расчета case RDS_BFM_STARTCALC: switch(data->Mode) { case ASMODE_READY: // Начать поиск угла Angle=MaxAngle; // Начальное значение data->OptMiss=DoubleErrorValue; // Пока не определено data->AngleStep=-(MaxAngle-MinAngle)/5; data->FirstStep=TRUE; data->Mode=ASMODE_SEARCHING; Ready=1; // Для передачи угла по связи break; case ASMODE_FINISHED: // Поиск уже проведен – показать результаты rdsStopCalc(); data->ShowResults(); break; } break; // Сброс расчета case RDS_BFM_RESETCALC: if(data->SelfReset) { // Блок сам сбросил подсистему data->SelfReset=FALSE; // Очиска признака самосброса // Устанавливаем новый угол Angle=data->AngleToSet; Ready=1; // Для передачи угла по связи } else // Расчет сброшен пользователем data->Mode=ASMODE_READY; break; // Один такт моделирования case RDS_BFM_MODEL: if(!Impact) // Снаряд еще не долетел break; // Снаряд долетел – дальность полета в x Impact=0; // Сбрасываем входной сигнал if(data->Mode==ASMODE_FINALRUN) { // Это был последний (демонстрационный) прогон data->Mode=ASMODE_FINISHED; rdsStopCalc(); data->ShowResults(); break; } // Это – очередной прогон в поиске угла delta=fabs(x-Distance); // Промах при угле Angle if(data->OptMiss==DoubleErrorValue || // Первый прогон delta<data->OptMiss) // При новом угле попали точнее { // Запоминаем новый наилучший угол и промах data->OptAngle=Angle; data->OptMiss=delta; // Двигаемся дальше с тем же шагом data->AngleToSet=Angle+data->AngleStep; // Новый расчет будет уже не первым с этим шагом data->FirstStep=FALSE; } else // Промах увеличился или не изменился { if(data->FirstStep) { // Мы только что провели первый расчет с новым // значением шага. Промах увеличился – попробуем // двигаться в обратном направлении с тем же // шагом data->AngleStep=-data->AngleStep; // Новый расчет будет уже не первым с этим шагом data->FirstStep=FALSE; } else { // Это был не первый расчет с данным значением // шага. Мы либо сделали несколько шагов в этом // направлении, либо уже пробовали двигаться // в обратном. Теперь нужно уменьшить шаг вдвое, // если это возможно. if(fabs(data->AngleStep)<=Accuracy) { // Достигли минимального шага по углу - // выполняем последний расчет data->Mode=ASMODE_FINALRUN; // Устанавливаем найденный угол data->AngleToSet=data->OptAngle; data->SelfReset=TRUE; // Флаг самосброса // Сбрасываем родительскую подсистему rdsResetSystemState(BlockData->Parent); break; } // Минимальный шаг еще не достигнут // Дальше будем двигаться от наилучшего на данный // момент угла с меньшим шагом data->AngleStep=data->AngleStep/2.0; // Не даем шагу стать меньше минимального if(fabs(data->AngleStep)<Accuracy) data->AngleStep=(data->AngleStep<0)? (-Accuracy):Accuracy; // Новый расчет будет первым с этим значением шага data->FirstStep=TRUE; } // Новый угол, который установиться после сброса data->AngleToSet=data->OptAngle+data->AngleStep; } // Ограничиваем угол и привязываем его к точности data->AngleToSet=data->FixAngle( data->AngleToSet,MinAngle,MaxAngle,Accuracy); // Сбрасываекм родительскую подсистему data->SelfReset=TRUE; // Флаг самосброса rdsResetSystemState(BlockData->Parent); break; } return RDS_BFR_DONE; // Отмена макроопределений #undef Angle #undef Impact #undef x #undef Distance #undef Accuracy #undef MaxAngle #undef MinAngle #undef Ready #undef Start #undef pStart } //=========================================== //=========================================== // Блок перебора углов для построения графика // зависимости дальности от угла //=========================================== // Личная область данных блока class TArtWalkData { public: BOOL SelfReset; // Блок сам сбросил подсистему double AngleToSet;// Угол, который нужно установить // после сброса BOOL FirstStart; // Начать построение графика с начала // Конструктор класса TArtWalkData(void) { SelfReset=FALSE; FirstStart=TRUE; }; }; //=========================================== // Функция модели блока // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" extern "C" __declspec(dllexport) int RDSCALL ArtWalk(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { TArtWalkData *data=(TArtWalkData*)(BlockData->BlockData); // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define MinAngle (*((double *)(pStart+2*RDS_VSZ_S))) #define MaxAngle (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D))) #define Accuracy (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D))) #define Impact (*((char *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_D))) #define GraphReady (*((char *)(pStart+3*RDS_VSZ_S+3*RDS_VSZ_D))) #define Angle (*((double *)(pStart+4*RDS_VSZ_S+3*RDS_VSZ_D))) // Массив описания параметров для универсальной функции настройки static const char *setup[]={ "2Минимальный угол, град.", "3Маскимальный угол, град.", "4Шаг по углу, град.", NULL}; switch(CallMode) { // Инициализация case RDS_BFM_INIT: BlockData->BlockData=new TArtWalkData(); break; // Очистка case RDS_BFM_CLEANUP: delete data; break; // Проверка типов переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSDDDSSD}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Вызов функции настройки case RDS_BFM_SETUP: return SetupDoubleVars(BlockData->Block, "Перебор углов",setup); // Запуск расчета case RDS_BFM_STARTCALC: if(data->FirstStart) { // Самый первый запуск – начало графика Angle=MinAngle; // Начинаем с начала диапазона data->FirstStart=FALSE; Impact=GraphReady=0; Ready=1; // Для передачи по связям } break; // Сброс расчета case RDS_BFM_RESETCALC: if(data->SelfReset) { // Блок сам сбросил подсистему data->SelfReset=FALSE; // Устанавливаем новый угол Angle=data->AngleToSet; Ready=1; // Для передачи по связям } else // Расчет сброшен кем=то еще data->FirstStart=TRUE; break; // Один такт расчета case RDS_BFM_MODEL: if(!Impact) // Снаряд не долетел { // Сбрасываем сигнал готовности графика GraphReady=0; break; } // Снаряд долетел – проверяем готовность графика if(!GraphReady) break; // График готов Impact=GraphReady=0; // Сбрасываем оба сигнала if(Angle>=MaxAngle) { // Достигли конца диапазона – прекращаем расчет rdsStopCalc(); break; } // Увеличиваем угол на один шаг data->AngleToSet=Angle+Accuracy; if(data->AngleToSet>MaxAngle) // Не допускаем выход data->AngleToSet=MaxAngle; // за MaxAngle data->SelfReset=TRUE; // Сейчас блок сам сбросит подсистему rdsResetSystemState(BlockData->Parent); break; } return RDS_BFR_DONE; // Отмена макроопределений #undef Angle #undef GraphReady #undef Impact #undef Accuracy #undef MaxAngle #undef MinAngle #undef Ready #undef Start #undef pStart } //=========================================== //=========================================== // Блок, запускающий и останавливающий расчет //=========================================== extern "C" __declspec(dllexport) int RDSCALL StopCalc(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { switch(CallMode) { case RDS_BFM_MODEL: // Один такт расчета rdsStopCalc(); break; case RDS_BFM_MOUSEDOWN: // Нажатие кнопки мыши case RDS_BFM_SETUP: // Вызов функции настройки if(rdsCalcProcessIsRunning()) // Расчет сейчас запущен rdsStopCalc(); else // Расчет сейчас остановлен rdsStartCalc(); break; } return RDS_BFR_DONE; } //=========================================