- •ЗаДание к курсовой работе:
- •Содержание
- •Этапы выполнения курсовой работы
- •Этапы разработки программы
- •Блок-схема программы
- •2.3 Создание меню
- •2.4 Создание диалога для входных значений
- •Заключение
- •Приложение Листинг программы
- •Void vxod_dialog::DoDataExchange(cDataExchange* pDx)
- •Void vxod_dialog::OnOk()
- •Void vxod_dialog::OnDefaultd()
- •Void vxod_dialog::OnSaved()
- •Void vxod_dialog::OnLoadd()
- •Implement_dyncreate(cZasyadkoView, cView)
- •Void cZasyadkoView::Draw()
- •Void cZasyadkoView::Clear()
- •Void cZasyadkoView::OnVxod()
- •Vxod_dialog dlg;
- •Void cZasyadkoView::OnTimer(uint nIdEvent)
- •Void cZasyadkoView::OnStop()
- •Void cZasyadkoView::OnTraektor()
2.3 Создание меню
Для создания меню необходимо произвести следующую последовательность действий:
Откроем редактор меню. (Вкладка ResourseVeiw->Menu->IDR_MAINFRAME)
рис. 2.3.1. Создание пунктов меню, вкладка Ресурсы
Добавим в строку меню кнопки «Входные данные», «Траектории», «Старт/Стоп».
Для каждой из них выключим параметр Pop-up.
рис. 2.3.2. Изменение параметров пункта меню
2.4 Создание диалога для входных значений
Для создания нового диалога перейдем на вкладку ResourseVeiw->Dialog(правый клик мышью)->Insert…->Dialog->New.
рис. 2.4.1. Создание нового диалога, вкладка Ресурсы
Аналогичным образом добавим к ресурсам изображение нашего варианта задания, предварительно скопировав изображение в папку /res
рис. 2.4.2. Добавление нового изображения в Ресурсы
Придадим нашему новому диалогу следующий вид.
рис. 2.4.3. Окно редактора диалога
При помощи MFC ClassWizard(пункт меню View) свяжем поля нашего диалога с соответствующими переменными
рис. 2.4.4. Окно MFC ClassWizard, вкладка Member Variables,
связь элементов управления и переменных
Расшифровка переменных:
M_com – значение масштаба;
M_ab – длина звена AB и A’C, в % от длины звена AB ;
M_aa – длина звена AA’, в % от длины звена AB;
M_bc – длина звена BC, в % от длины звена AB;
M_mk – длина звена MK, в % от длины звена AB;
M_dab – длина звена AB, в мм;
M_gs – скорость движения звена AB, в град/с;
M_kp – количество положений механизма для отрисовки;
M_bx – координата X стойки A, относительно левого края экрана;
M_by – координата Y стойки A, относительно верхнего края экрана;
2.5 Описание использованных в прогрмамме функций
С помощью MFC ClassWizard создаем функции нажатий на кнопки окна диалога, пункты меню и событие инициализации диалога.
рис. 2.5.1. Окно MFC ClassWizard, создание функций по событию
Нажатие на кнопку «Стандартные данные» описано в файле vxod_dialog.cpp и имеет вид:
void vxod_dialog::OnDefaultd()
{
m_ab=1;
m_aa=0.198;
m_bc=1.105;
m_mk=0.211;
m_com="1:1";
m_dab=100;
m_gs=5;
m_kp=0;
m_bx=50;
m_by=500;
UpdateData(0);
}
Данная функция заполняет поля ввода стандартными данными при желании пользователя.
Нажатие на кнопку «Сохранить данные» описано в файле vxod_dialog.cpp и имеет вид:
void vxod_dialog::OnSaved()
{
UpdateData(1);
FILE *file=fopen("saved.txt","w");
fprintf(file,"%f\n",m_ab);
fprintf(file,"%f\n",m_aa);
fprintf(file,"%f\n",m_bc);
fprintf(file,"%f\n",m_mk);
if(m_com=="1:1") fputs("1\n",file);
if(m_com=="1:4") fputs("4\n",file);
if(m_com=="1:5") fputs("5\n",file);
if(m_com=="1:20") fputs("20\n",file);
if(m_com=="1:25") fputs("25\n",file);
fprintf(file,"%f\n",m_dab);
fprintf(file,"%i\n",m_gs);
fprintf(file,"%f\n",m_kp);
fprintf(file,"%f\n",m_bx);
fprintf(file,"%f",m_by);
fclose(file);
}
Данная функция сохраняет введенные данные в отдельный файл «saved.txt» при желании пользователя.
Нажатие на кнопку «Загрузить данные» описано в файле vxod_dialog.cpp и имеет вид:
void vxod_dialog::OnLoadd()
{
FILE *file=fopen("saved.txt","rw");
char s[15];
fgets(s,15,file);
m_ab=atof(s);
fgets(s,15,file);
m_aa=atof(s);
fgets(s,15,file);
m_bc=atof(s);
fgets(s,15,file);
m_mk=atof(s);
fgets(s,15,file);
if(atoi(s)==1)m_com="1:1";
if(atoi(s)==4)m_com="1:4";
if(atoi(s)==5)m_com="1:5";
if(atoi(s)==20)m_com="1:20";
if(atoi(s)==25)m_com="1:25";
fgets(s,15,file);
m_dab=atof(s);
fgets(s,15,file);
m_gs=atof(s);
fgets(s,15,file);
m_kp=atof(s);
fgets(s,15,file);
m_bx=atof(s);
fgets(s,15,file);
m_by=atof(s);
fclose(file);
UpdateData(0);
}
Данная функция загружает данные в поля ввода из отдельного файла «saved.txt» при желании пользователя.
Функция при инициализации диалога описана в файле vxod_dialog.cpp и имеет вид:
BOOL vxod_dialog::OnInitDialog()
{
CDialog::OnInitDialog();
FILE *file=fopen("in.txt","rw");
char s[15];
fgets(s,15,file);
m_ab=atof(s);
fgets(s,15,file);
m_aa=atof(s);
fgets(s,15,file);
m_bc=atof(s);
fgets(s,15,file);
m_mk=atof(s);
fgets(s,15,file);
if(atoi(s)==1)m_com="1:1";
if(atoi(s)==4)m_com="1:4";
if(atoi(s)==5)m_com="1:5";
if(atoi(s)==20)m_com="1:20";
if(atoi(s)==25)m_com="1:25";
fgets(s,15,file);
m_dab=atof(s);
fgets(s,15,file);
m_gs=atof(s);
fgets(s,15,file);
m_kp=atof(s);
fgets(s,15,file);
m_bx=atof(s);
fgets(s,15,file);
m_by=atof(s);
fclose(file);
UpdateData(0);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
Данная функция подгружает введенные в прошлый раз данные из файла «in.txt», таким образом программа помнит последние изменения.
Нажатие на кнопку «ОК» описано в файле vxod_dialog.cpp и имеет вид:
void vxod_dialog::OnOK()
{
UpdateData(1);
FILE *file=fopen("in.txt","w");
fprintf(file,"%f\n",m_ab);
fprintf(file,"%f\n",m_aa);
fprintf(file,"%f\n",m_bc);
fprintf(file,"%f\n",m_mk);
if(m_com=="1:1") fputs("1\n",file);
if(m_com=="1:4") fputs("4\n",file);
if(m_com=="1:5") fputs("5\n",file);
if(m_com=="1:20") fputs("20\n",file);
if(m_com=="1:25") fputs("25\n",file);
fprintf(file,"%f\n",m_dab);
fprintf(file,"%i\n",m_gs);
fprintf(file,"%f\n",m_kp);
fprintf(file,"%f\n",m_bx);
fprintf(file,"%f",m_by);
fclose(file);
CDialog::OnOK();
}
В хедер-файле ZasyadkoView.h объявим необходимые для расчёта и отрисовки механизма функции и переменные:
…
// Attributes
public:
CZasyadkoDoc* GetDocument();
void Draw();
void Clear();
void Raschet();
// Operations
public:
float bx,by,ax,ay,a1x,a1y,cx,cy,mx,my,kx,ky,kl,a, b, ab, aa1, a1c, km, dab, kp, ox,oy;
int gs, nTimer, n, nn;
bool flag, flag2,flag3,flag4;
…
Расшифровка:
void Draw() – функция содержащая операции для отрисвки механизма после каждого тика счетчика;
void Clear() – функция для очистки экрана после каждого тика счетчика;
void Raschet() – функция для расчета координат точек механизма;
bx, by, ax, ay, a1x, a1y, cx, cy, mx, my, kx, ky– координаты точек механизма;
ox, oy – центр координат;
kp – количество положений механизма;
kl – масштабный коэффициент;
a, b – углы наклона звеньев AB и A’C;
ab, aa1, a1c, km, dab – длины звеньев;
gs – время одного тика счетчика;
n, nn, flag, flag2, flag3, falg4 – вспомогательные счетчики и условия.
Нажатие на пункт меню «Входные данные» описано в файле zasyadkoView.cpp и имеет вид:
void CZasyadkoView::OnVxod()
{
vxod_dialog dlg;
if(dlg.DoModal()==IDOK)
{
if(dlg.m_com =="1:1"){kl=1;}
if(dlg.m_com =="1:4"){kl=4;}
if(dlg.m_com =="1:5"){kl=5;}
if(dlg.m_com =="1:10"){kl=10;}
if(dlg.m_com =="1:20"){kl=20;}
if(dlg.m_com =="1:25"){kl=25;}
ox=dlg.m_bx;
oy=dlg.m_by;
bx=0;
by=0;
cy=by;
cx=bx+dlg.m_bc*dlg.m_dab*10/kl;
ab=dlg.m_ab*dlg.m_dab*10/kl;
a1c=dlg.m_ab*dlg.m_dab*10/kl;
aa1=dlg.m_dab*10*dlg.m_aa/kl*1.06;
km=dlg.m_dab*10*dlg.m_mk/kl;
kx=(bx+cx)/2;
dab=dlg.m_dab;
flag=1;
flag2=1;
flag3=0;
flag4=1;
a=65;
gs=dlg.m_gs;
kp=dlg.m_kp;
if(kp!=0){ n=0; nn=0;}
CClientDC dc(this);
CPen Pen1; Pen1.CreatePen(PS_DOT, 10, RGB(255,255,255));
dc.SelectObject(Pen1);
dc.Rectangle(0,0,2000,2000);
int s=250;
s=s/gs;
nTimer=SetTimer(1,s,NULL);
ASSERT(nTimer != 0);
}
}
Данная функция по окончанию ввода данных в вызванном диалоговом окне присваивает переменным значения, учитывая размеры звеньев, масштаб и сдвиг по координатам. Очищает экран. Запускает счетчик. И мы видим на экране результат – наш механизм.
рис. 2.5.2. Окно программы, отрисовка механизма
Функция описывающая срабатывание счетчика описана в файле zasyadkoView.cpp и имеет вид:
void CZasyadkoView::OnTimer(UINT nIDEvent)
{
if(kp!=0){
Raschet();
nn=nn+1;
if(kp>2 && nn>=(186/kp)) { Draw(); nn=0;}
if(n>=186) nTimer=KillTimer(1);
n=n+1;
}
if(kp==0){
Clear();
Raschet();
Draw();
CView::OnTimer(1);
}
}
Данная функция в зависимости от введенного параметра «Количество положений механизма» выполняет различные действия:
если введено 0, значит механизм движется непрерывно. А последовательность действий на каждый тик счетчика выглядит так:
очистка экрана
перерасчет значений
отрисовка
если параметр больше 0 то на экране мы увидим статическое изображение нескольких наложенных друг на друга положений нашего механизма.
Нажатие на пункт меню «Старт/Стоп» описано в файле zasyadkoView.cpp и имеет вид:
void CZasyadkoView::OnStop()
{
if(flag4==1)
{
nTimer=KillTimer(1);
flag4=0;
}
else
{
int s=250;
s=s/gs;
nTimer=SetTimer(1,s,NULL);
ASSERT(nTimer != 0);
flag4=1;
}
}
Данная функция имеет двойное значение, если механизм двигался во время нажатия, то он остановится(будет уничтожен счетчик, отвечающий за пересчет и отрисовку следующих положений), если же механизм остановлен, то он снова заработает(мы создадим в этом случае счетчик заново).
Нажатие на пункт меню «Траектории» описано в файле zasyadkoView.cpp и имеет вид:
void CZasyadkoView::OnTRAEKTOR()
{
if(flag3==0)flag3=1;
else
{
flag3=0;
CClientDC dc(this);
CPen Pen1; Pen1.CreatePen(PS_DOT, 10, RGB(255,255,255));
dc.SelectObject(Pen1);
dc.Rectangle(0,0,2000,2000);
}
}
Данная функция включает отрисовку траекторий на движущемся механизме, и при повторном нажатии отключает их отрисовку.
рис. 2.5.3. Окно программы, отрисовка механизма, траектории
Функция Raschet() описана в файле zasyadkoView.cpp и имеет вид:
void CZasyadkoView::Raschet()
{
ax=bx+cos(a*3.14/180)*ab;
ay=by+sin(a*3.14/180)*ab;
double z, z1, z2;
z=sqrt((cy-ay)*(cy-ay)+(cx-ax)*(cx-ax));
if(a>=70 && flag2==1)flag2=0;
else
if(flag2==0 && a>=70)flag2=1;
z1=(z*z+a1c*a1c-aa1*aa1)/(2*z*a1c);
z2=((cx-ax)*(cx-ax)+z*z-(by-ay)*(by-ay)) / (2*z*(cx-ax));
z1=fabs(z1);
z2=fabs(z2);
if(z1<1.000)z1=acos(z1);
else z1=acos(1);
if(z2<1.000)z2=acos(z2);
else z2=acos(1);
if(flag2==1)
b=(z1+z2)*180/3.14;
else
b=(z2-z1)*180/3.14;
a1x=cx-cos(b*3.14/180)*a1c;
a1y=cy+sin(b*3.14/180)*a1c;
mx=(ax+a1x)/2;
my=(a1y+ay)/2;
ky=+my+sqrt( km*km - (mx-kx)*(mx-kx) );
if(flag==1)a+=0.15;
else a-=0.15;
if(a>=70)flag=0;
if(a<=61 && a1x<=kx)flag=1;
if(a<=65 && a1x>=kx)flag=1;
}
Данная функция реализует рассчет координат узлов механизма. Для удобства рассчетов в качестве входного звена взято звено AB и угол между этим звеном и положительным направлением оси X. На каждый тик счетчика вызывается функция рассчета, увеличивается(уменьшается) угол на шаг 0.15 градуса. Крайние положения механизма были получены исходя из конструктивных особенностей данного механизма, а именно максимальной амплитуды хода штока.
Функция Draw() описана в файле zasyadkoView.cpp и имеет вид:
void CZasyadkoView::Draw()
{
CClientDC dc(this);
SetMapMode(dc,MM_LOMETRIC);
SetViewportOrgEx(dc, ox, oy, NULL);
//Траектории
if(flag3==1)
{
int x,y;
x=bx+cos(65*3.14/180)*ab;
y=by+sin(65*3.14/180)*ab;
CPen newpen3(PS_SOLID,20,RGB(100,255,100));
dc.SelectObject(newpen3);
dc.MoveTo(x-(209-340)/kl*(dab/100),y+(200)/kl*(dab/100));
dc.LineTo(x-(209-340)/kl*(dab/100),y+(50)/kl*(dab/100));
CPen newpen4(PS_SOLID,20,RGB(255,150,150));
dc.SelectObject(newpen4);
kl=kl/2.6;
dc.Arc(x-(209-197)/kl*(dab/100), y+(157-162)/kl*(dab/100),
x-(209-320)/kl*(dab/100), y+(157-210)/kl*(dab/100),
x-(209-272)/kl*(dab/100), y+(157-150)/kl*(dab/100),
x-(209-213)/kl*(dab/100), y+(157-200)/kl*(dab/100));
CPen newpen5(PS_SOLID,20,RGB(150,150,255));
dc.SelectObject(newpen5);
dc.Arc(x-(209-37)/kl*(dab/100), y+(157-100)/kl*(dab/100),
x-(209-1037)/kl*(dab/100), y+(157-1100)/kl*(dab/100),
x-(209-37)/kl*(dab/100), y+(157+390)/kl*(dab/100),
x-(209-37)/kl*(dab/100), y+(157-75)/kl*(dab/100));
CPen newpen6(PS_SOLID,20,RGB(100,100,100));
dc.SelectObject(newpen6);
dc.Arc(x-(209+479)/kl*(dab/100), y+(157-120)/kl*(dab/100),
x-(209-521)/kl*(dab/100), y+(157-1120)/kl*(dab/100),
x-(209-266)/kl*(dab/100), y+(157-120)/kl*(dab/100),
x-(209-191)/kl*(dab/100), y+(157-120)/kl*(dab/100));
kl=kl*2.6;
}
//Звенья
CPen newpen1;
newpen1.CreatePen(PS_SOLID,1,RGB(0,0,0));
dc.SelectObject(newpen1);
dc.MoveTo(bx, by);
dc.LineTo(ax, ay);
dc.MoveTo(cx, cy);
dc.LineTo(a1x, a1y);
dc.MoveTo(a1x, a1y);
dc.LineTo(ax, ay);
dc.MoveTo(ax-(a1x-ax), (ay-(a1y-ay)));
dc.LineTo(a1x, a1y);
dc.MoveTo(mx, my);
dc.LineTo(kx, ky);
dc.MoveTo(kx,ky);
dc.LineTo(kx,ky-ab);
CBrush brush;
brush.CreateHatchBrush(HS_BDIAGONAL,RGB(0,0,0));
dc.SelectObject(brush);
CPen newpen2;
newpen2.CreatePen(PS_SOLID,1,RGB(255,255,255));
//Стойки
dc.MoveTo(bx,by);
dc.LineTo(bx-30,by-30);
dc.MoveTo(bx,by);
dc.LineTo(bx+30,by-30);
dc.SelectObject(newpen2);
dc.Rectangle(bx-30, by-30, bx+30, by-60);
dc.SelectObject(newpen1);
dc.MoveTo(bx-30,by-30);
dc.LineTo(bx+30,by-30);
dc.MoveTo(cx,cy);
dc.LineTo(cx-30,cy-30);
dc.MoveTo(cx,cy);
dc.LineTo(cx+30,cy-30);
dc.SelectObject(newpen2);
dc.Rectangle(cx-30, cy-30, cx+30, cy-60);
dc.SelectObject(newpen1);
dc.MoveTo(cx-30,cy-30);
dc.LineTo(cx+30,cy-30);
dc.MoveTo(kx-ab/60,by+ab/5*2);
dc.LineTo(kx-ab/60,by+ab/5);
dc.SelectObject(newpen2);
dc.Rectangle(kx-ab/60-30, by+ab/5*2, kx-ab/60, by+ab/5);
dc.SelectObject(newpen1);
dc.MoveTo(kx+ab/60-1, by+ab/5*2);
dc.LineTo(kx+ab/60-1, by+ab/5);
dc.SelectObject(newpen2);
dc.Rectangle(kx+ab/60+30, by+ab/5*2, kx+ab/60+1, by+ab/5);
dc.SelectObject(newpen1);
//Шарниры
CPen newpen6;
newpen6.CreatePen(PS_SOLID,1,RGB(100,100,255));
dc.SelectObject(newpen6);
dc.Ellipse(bx-10/kl*dab/100,by-10/kl*dab/100,bx+10/kl*dab/100,by+10/kl*dab/100);
dc.Ellipse(cx-10/kl*dab/100,cy-10/kl*dab/100,cx+10/kl*dab/100,cy+10/kl*dab/100);
dc.Ellipse(a1x-10/kl*dab/100,a1y-10/kl*dab/100,a1x+10/kl*dab/100,a1y+10/kl*dab/100);
dc.Ellipse(ax-10/kl*dab/100,ay-10/kl*dab/100,ax+10/kl*dab/100,ay+10/kl*dab/100);
dc.Ellipse(mx-10/kl*dab/100,my-10/kl*dab/100,mx+10/kl*dab/100,my+10/kl*dab/100);
dc.Ellipse(kx-10/kl*dab/100,ky-10/kl*dab/100,kx+10/kl*dab/100,ky+10/kl*dab/100);
//Буквы
dc.SetTextColor(RGB(255,100,100));
dc.SetBkMode(TRANSPARENT);
dc.TextOut(bx+10,by+4,"B");
dc.TextOut(cx+10,cy+4,"C");
dc.TextOut(kx+10,ky-10,"K");
dc.TextOut(ax-15,ay-10,"A");
dc.TextOut(a1x+10,a1y-10,"A'");
dc.TextOut(mx,my+10,"M'");
}
Данная функция осуществляет построение на экране данного механизма, на основании рассчитанных данных. Используем для рисования режим MM_LOMETRIC, это означает что для измерения длины линий используются единицы измерения мм, а не пиксели.
Функция Clear() описана в файле zasyadkoView.cpp и имеет вид:
void CZasyadkoView::Clear()
{
CClientDC dc(this);
SetMapMode(dc,MM_LOMETRIC);
SetViewportOrgEx(dc, ox, oy, NULL);
CPen newpen1;
newpen1.CreatePen(PS_SOLID,1,RGB(255,255,255));
dc.SelectObject(newpen1);
dc.MoveTo(bx, by);
dc.LineTo(ax, ay);
dc.MoveTo(cx, cy);
dc.LineTo(a1x, a1y);
dc.MoveTo(a1x, a1y);
dc.LineTo(ax, ay);
dc.MoveTo(ax-(a1x-ax), ay-(a1y-ay));
dc.LineTo(a1x, a1y);
dc.MoveTo(mx, my);
dc.LineTo(kx, ky);
dc.MoveTo(kx,ky);
dc.LineTo(kx,ky-ab);
CPen newpen6;
newpen6.CreatePen(PS_SOLID,1,RGB(255,255,255));
dc.SelectObject(newpen6);
dc.Ellipse(bx-10/kl*dab/100,by-10/kl*dab/100,bx+10/kl*dab/100,by+10/kl*dab/100);
dc.Ellipse(cx-10/kl*dab/100,cy-10/kl*dab/100,cx+10/kl*dab/100,cy+10/kl*dab/100);
dc.Ellipse(a1x-10/kl*dab/100,a1y-10/kl*dab/100,a1x+10/kl*dab/100,a1y+10/kl*dab/100);
dc.Ellipse(ax-10/kl*dab/100,ay-10/kl*dab/100,ax+10/kl*dab/100,ay+10/kl*dab/100);
dc.Ellipse(mx-10/kl*dab/100,my-10/kl*dab/100,mx+10/kl*dab/100,my+10/kl*dab/100);
dc.Ellipse(kx-10/kl*dab/100,ky-10/kl*dab/100,kx+10/kl*dab/100,ky+10/kl*dab/100);
dc.SetTextColor(RGB(255,255,255));
dc.SetBkMode(TRANSPARENT);
dc.TextOut(bx+10,by+4,"B");
dc.TextOut(cx+10,cy+4,"C");
dc.TextOut(kx+10,ky-10,"K");
dc.TextOut(ax-15,ay-10,"A");
dc.TextOut(a1x+10,a1y-10,"A'");
dc.TextOut(mx,my+10,"M'");
dc.Rectangle(cx*1.4,0,cx*1.5,25);
}
Данная функция осуществляет очистку области отображения механизма по тику счетчика.
