• 基于C++的微流控生物芯片模拟程序设计


    目录
    微流控生物芯片模拟程序设计文档 1
    程序介绍 1
    现实背景 1
    设计目的 1
    程序使用方法 3
    testcaseerror.txt测例自行测试,效果为 9
    程序设计 11
    技术基础 11
    类的职责 11
    类的交互 14
    关键部分处理 14
    类的交互
    类的组合关系十分明显, Lattice 是 MainWindow 的组件,大部分逻辑处理均在 MainWindow 中完成。
    下面从用户操作的正常流程(这里说到正常是立足于用户检验软件模拟效果而并非检验逻辑bug的角 度,如用户并不会在加载文件后重新初始化。实际上本程序在逻辑的自恰性上同样下了不少功夫,除非 用户使用强行修改内存等方法破坏逻辑的流畅性,许多细节的处理是严谨的!笔者也在这方面花了很多 时间和精力)来解析类之间的交互和配合过程。
    首先用户点击初始化,触发信号调用槽 void Initiate(); 。这个槽内部新建 InitiateDialog 并阻塞,得到其返回的 Setting 。若用户直接关闭了 InitiateDialog 则维持原来状态,否则根据得到的合法配置构建 Lattice 、调整各个 QAction 的disabled状态、调整窗口大小以适应 Lattice 的大小
    (可对照窗口初始大小和初始化后的大小)、改变status和标签显示。
    之后用户点击加载文件,弹出 QFileDialog 标准文件选择框。若用户关闭对话框则什么也不做(这样的处理之后不再叙述),若用户选择了文件则尝试以ReadOnly模式打开,若打开失败则弹出
    QMessageBox::critical 标准框报错(这样的细节也不再叙述),否则使用
    transferOrdertoMovements(QString) 解析每一行,全部解析后使用 processSimulation() 解析出每一时刻的状态,保留尽可能多的时刻(validetime)。这时已构建了 QVector scenes 和QMap drops ,利用Qt的随机数生成指定每个液滴及其污迹的颜色。之后调用
    Lattice::load 装备lattice,lattice装备过程改变自身的私有变量,且生成每个液滴污迹在格子内的位置(同样使用随机数生成)。本文转载自http://www.biyezuopin.vip/onews.asp?id=16728使用 jumpto(0) 调到0时刻,以及 setStatus(2) 改变 MainWindow 状
    态,这时装载完美结束。
    装载完毕后重置、上一步、下一步、播放按钮处于可点击状态。在不开启清洗时,重置、上一步、下一 步是改变 MainWindow 内置记录当前时刻的私有变量 time 并简单的调用 jumpto(time) ,播放则是使用while循环(没有到达最后时刻且没有停止),不断调用下一步并在代码块内部阻塞延时;播放状态 下停止按钮处于可点击的状态,而其余按钮均变灰。
    在开启清洗功能时,在上文已经提到本程序采用的策略是每步均尽最大可能清洗。开启清洗功能且不处 于Washing状态时,lattice接收鼠标的右键点击事件并在私有变量 QSet 中进行增减操作(清洗液滴移动的路径规划时会有考虑,同时 paintEvent 会对锁定的格子涂红)。此时改变的是
    MainWindow::jumpto(int) 的内在逻辑:从简单的 lattice->getContaminations() —— lattice-

    setScene 到 lattice->getContaminations() —— lattice->setScene ——延时300毫秒—— lattice->wash() —— lattice->refresh() ,途中同时改变 MainWindow 自身的状态及标签显示。这里的一个独特的亮点是,在开启清洗过程的状态下可以点击上一步和重置,细节的设定在下一部分详 述。

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        action_startup=new QAction(this);
        action_import=new QAction(this);
        action_about=new QAction(this);
        action_reset=new QAction(this);
        action_play=new QAction(this);
        action_stop=new QAction(this);
        action_last=new QAction(this);
        action_next=new QAction(this);
        action_startup->setText("Initiate");
        action_startup->setIcon(QIcon(":/image/settings.png"));
        action_startup->setToolTip("Initiate the settings");
        action_import->setText("Import file");
        action_import->setIcon(QIcon(":/image/file.png"));
        action_import->setToolTip("Import file as simulation orders");
        action_about->setText("About");
        action_about->setToolTip("Original info and intention about this program");
        action_reset->setText("Reset");
        action_reset->setIcon(QIcon(":/image/reset.png"));
        action_reset->setToolTip("Return to the initial status");
        action_play->setText("Play");
        action_play->setIcon(QIcon(":/image/play.png"));
        action_play->setToolTip("Display the simulation process step by step");
        action_stop->setText("Stop");
        action_stop->setIcon(QIcon(":/image/cancal.png"));
        action_stop->setToolTip("Terminate the simulation process");
        action_last->setText("Last step");
        action_last->setIcon(QIcon(":/image/left.png"));
        action_last->setToolTip("Return to the last step");
        action_next->setText("Next step");
        action_next->setIcon(QIcon(":/image/right.png"));
        action_next->setToolTip("Proceed to the next step");
    
        ui->menu->addAction(action_startup);
        ui->menu->addAction(action_import);
        ui->mainToolBar->addAction(action_startup);
        ui->mainToolBar->addAction(action_import);
        ui->menu_2->addAction(action_about);
        ui->menuAction->addAction(action_reset);
        ui->menuAction->addAction(action_play);
        ui->menuAction->addAction(action_stop);
        ui->menuAction->addAction(action_last);
        ui->menuAction->addAction(action_next);
        ui->mainToolBar->addAction(action_reset);
        ui->mainToolBar->addAction(action_play);
        ui->mainToolBar->addAction(action_stop);
        ui->mainToolBar->addAction(action_last);
        ui->mainToolBar->addAction(action_next);
        QObject::connect(action_about, &QAction::triggered,this,[=](){
            QMessageBox::about(this,"About DMBS","A rough QT product for course design.");
        });
        this->setFixedSize(400,150);
        this->ui->label->setGeometry(20,0,222,32);
        this->ui->label_2->setGeometry(260,0,182,32);
    
        this->sound_move=new QSound(":/sound/move.wav",this);
        this->sound_merge=new QSound(":/sound/merge.wav",this);
        this->sound_split1=new QSound(":/sound/split1.wav",this);
        this->sound_split2=new QSound(":/sound/split2.wav",this);
    
        QObject::connect(action_startup,SIGNAL(triggered()),this,SLOT(Initiate()));
        QObject::connect(action_import,SIGNAL(triggered()),this,SLOT(Load()));
        QObject::connect(action_next,SIGNAL(triggered()),this,SLOT(nextstep()));
        QObject::connect(action_last,SIGNAL(triggered()),this,SLOT(laststep()));
        QObject::connect(action_reset,SIGNAL(triggered()),this,SLOT(reset()));
        QObject::connect(action_play,SIGNAL(triggered()),this,SLOT(play()));
        QObject::connect(action_stop,SIGNAL(triggered()),this,SLOT(stop()));
    
        label_output=new QLabel(this);
        label_washinput=new QLabel(this);
        label_waste=new QLabel(this);
    
        label_output->setText("Output");
        label_washinput->setText("Wash\nInput");
        label_waste->setText("Waste");
        label_output->setFrameShape (QFrame::Box);
        label_output->setStyleSheet("border-width: 1px;border-style: solid;border-color:black;background-color:violet;");
        label_output->setAlignment(Qt::AlignCenter);
        label_washinput->setFrameShape (QFrame::Box);
        label_washinput->setStyleSheet("border-width: 1px;border-style: solid;border-color:black;background-color:lightblue;");
        label_washinput->setAlignment(Qt::AlignCenter);
        label_waste->setFrameShape (QFrame::Box);
        label_waste->setStyleSheet("border-width: 1px;border-style: solid;border-color:black;background-color:sienna;");
        label_waste->setAlignment(Qt::AlignCenter);
        this->setStatus(0);
    }
    void MainWindow::setStatus(int id){
        if(id==0){
            ui->label->setText("Present time: Not Valid");
            ui->label_2->setText("Status: Vacant");
            this->action_startup->setEnabled(true);
            this->action_import->setEnabled(false);
            this->action_reset->setEnabled(false);
            this->action_stop->setEnabled(false);
            this->action_play->setEnabled(false);
            this->action_next->setEnabled(false);
            this->action_last->setEnabled(false);
            label_output->setVisible(false);
            label_washinput->setVisible(false);
            label_waste->setVisible(false);
        }else if(id==1){
            ui->label->setText("Present time: Not Valid");
            ui->label_2->setText("Status: Setted");
            this->action_startup->setEnabled(true);
            this->action_import->setEnabled(true);
            this->action_reset->setEnabled(false);
            this->action_stop->setEnabled(false);
            this->action_play->setEnabled(false);
            this->action_next->setEnabled(false);
            this->action_last->setEnabled(false);
        }else if(id==2){
            ui->label->setText("Present time: "+QString::number(time)+"/"+QString::number(validtime));
            ui->label_2->setText("Status: Loaded");
            this->action_startup->setEnabled(true);
            this->action_import->setEnabled(true);
            this->action_reset->setEnabled(true);
            this->action_stop->setEnabled(false);
            this->action_play->setEnabled(true);
            this->action_next->setEnabled(true);
            this->action_last->setEnabled(true);
        }else if(id==3){
            ui->label_2->setText("Status: Playing");
            this->action_startup->setEnabled(false);
            this->action_import->setEnabled(false);
            this->action_reset->setEnabled(false);
            this->action_stop->setEnabled(true);
            this->action_play->setEnabled(false);
            this->action_next->setEnabled(false);
            this->action_last->setEnabled(false);
        }else if(id==4){
            ui->label_2->setText("Status: Washing");
            this->action_startup->setEnabled(false);
            this->action_import->setEnabled(false);
            this->action_reset->setEnabled(false);
            this->action_stop->setEnabled(false);
            this->action_play->setEnabled(false);
            this->action_next->setEnabled(false);
            this->action_last->setEnabled(false);
        }
    }
    void MainWindow::Initiate(){
        InitiateDialog *dlg=new InitiateDialog(this);
        dlg->setAttribute(Qt::WA_DeleteOnClose);//设置对话框关闭后,自动销毁
        dlg->setWindowModality(Qt::WindowModal);
        Setting set = dlg->getSetting();
        if(set.w>0&&set.h>0){
            setting=set;
            status=1;
            setStatus(1);
            scenes.clear();
            drops.clear();
            totaltime=0;
            validtime=0;
            for(int i=0;i<200;i++){
                movements[i].clear();
            }
            counter=0;
            time=-1;
            Pos newpos2,newpos3,newpos4;
            QVector<Pos> newpos1;
            for(int i=0;i<label_inputs.size();i++){
                delete label_inputs[i];
            }
            label_inputs.clear();
            for(int i=0;i<setting.in.size();i++){
                newpos1.push_back(getWidgePos(transferPos(setting.in[i])));
                QLabel* qlabel=new QLabel(this);
                qlabel->setText("Input");
                qlabel->setFrameShape (QFrame::Box);
                qlabel->setStyleSheet("border-width: 1px;border-style: solid;border-color:black;background-color:green;");
                qlabel->setAlignment(Qt::AlignCenter);
                label_inputs.push_back(qlabel);
                qlabel->setVisible(false);
                qlabel->setGeometry(newpos1[i].x,newpos1[i].y,60,60);
            }
            newpos2=getWidgePos(transferPos(setting.out));
            newpos3=getWidgePos(transferPos(setting.w_in));
            w_inpos=temppos;
            newpos4=getWidgePos(transferPos(setting.w_out));
            w_outpos=temppos;
            if(lattice!=nullptr)delete lattice;
            lattice=new Lattice(this,set,w_inpos,w_outpos);
            lattice->setVisible(false);
            lattice->setGeometry(80,190,60*setting.w,60*setting.h);
            label_output->setVisible(false);
            label_washinput->setVisible(false);
            label_waste->setVisible(false);
    
            label_output->setGeometry(newpos2.x,newpos2.y,60,60);
            label_washinput->setGeometry(newpos3.x,newpos3.y,60,60);
            label_waste->setGeometry(newpos4.x,newpos4.y,60,60);
            lattice->show();
            for(int i=0;i<label_inputs.size();i++){
                label_inputs[i]->setVisible(true);
            }
            label_output->setVisible(true);
            if(setting.washable){
                label_washinput->setVisible(true);
                label_waste->setVisible(true);
            }
            this->setFixedSize(utils::max<int>(400,100+60*(setting.w+2)),150+60*(setting.h+2));
        }
    
    }
    void MainWindow::Load(){
        QString strFile = QFileDialog::getOpenFileName(this,"Choose a txt file containing orders","C:","text files(*txt)");
        if(strFile.isEmpty()||strFile.isNull())return;
        QFile f(strFile);
        if (!f.open(QIODevice::ReadOnly)){
            QMessageBox::critical(this, "Loading Failed", "Could not open file.");
            return;
        }
        status=2;
        scenes.clear();
        drops.clear();
        totaltime=0;
        validtime=0;
        for(int i=0;i<200;i++){
            movements[i].clear();
        }
        counter=0;
        time=-1;
        QTextStream in(&f);
    
        while(!in.atEnd()){
            transferOrdertoMovements(in.readLine());
        }
        totaltime++;
        if(processSimulation()){
            QMessageBox::information(this, "Simulating Success", "Total time: "+QString::number(validtime));
        }else{
            QMessageBox::critical(this, "Simulating Terminated", "Valid time: "+QString::number(validtime));
        }
        qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()));
        foreach(Drop *drop,drops){
            drop->color=QColor::fromHsl(qrand()%360,qrand()%256,qrand()%200);
        }
        lattice->load(validtime,scenes,drops);
        time=0;
        jumpto(0);
        setStatus(2);
    }
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    Pos MainWindow::getWidgePos(Pos pos){
        Pos newpos;
        newpos.x=20+60*pos.x;
        newpos.y=130+60*pos.y;
        return newpos;
    }
    
    Pos MainWindow::transferPos(Pos pos){
        Pos newpos;
        if(pos.x==1){
            //L
            newpos.x=pos.x-1;
            newpos.y=pos.y;
            temppos=0;
        }else if(pos.x==setting.w){
            //R
            newpos.x=pos.x+1;
            newpos.y=pos.y;
            temppos=1;
        }else if(pos.y==1){
            //U
            newpos.x=pos.x;
            newpos.y=pos.y-1;
            temppos=2;
        }else{
            //D
            newpos.x=pos.x;
            newpos.y=pos.y+1;
            temppos=3;
        }
        return newpos;
    }
    
    void MainWindow::transferOrdertoMovements(QString order){
        order=order.left(order.size()-1);
        QStringList list1=order.split(" ");
        QString keyword=list1.at(0);
        QStringList list2=list1.at(1).split(",");
        int time=list2.at(0).toInt();
        if(keyword=="Input"){
            Movement m;
            m.type=0;
            m.pos={list2.at(1).toInt(),list2.at(2).toInt()};
            movements[time].push_back(m);
            totaltime=utils::max(totaltime,time);
        }else if(keyword=="Output"){
            Movement m;
            m.type=1;
            m.pos={list2.at(1).toInt(),list2.at(2).toInt()};
            movements[time].push_back(m);
            totaltime=utils::max(totaltime,time);
        }else if(keyword=="Move"){
            Movement m;
            m.type=2;
            m.pos={list2.at(1).toInt(),list2.at(2).toInt()};
            m.destination={list2.at(3).toInt(),list2.at(4).toInt()};
            movements[time].push_back(m);
            totaltime=utils::max(totaltime,time);
        }else if(keyword=="Mix"){
            for(int i=1;i<list2.size()/2;i++){
                Movement m;
                m.type=2;
                m.pos={list2.at(2*i-1).toInt(),list2.at(2*i).toInt()};
                m.destination={list2.at(2*i+1).toInt(),list2.at(2*i+2).toInt()};
                movements[time+i-1].push_back(m);
                totaltime=utils::max(totaltime,time+i-1);
            }
        }else if(keyword=="Split"){
            Movement m1,m2;
            m1.type=3;
            m2.type=4;
            Pos pos={list2.at(1).toInt(),list2.at(2).toInt()};
            m1.pos=pos;
            m2.pos=pos;
            m1.upward=(list2.at(1).toInt()==list2.at(3).toInt());
            movements[time].push_back(m1);
            movements[time+1].push_back(m2);
            totaltime=utils::max(totaltime,time+1);
        }else if(keyword=="Merge"){
            Movement m1,m2;
            m1.type=5;
            m2.type=6;
            Pos pos={(list2.at(1).toInt()+list2.at(3).toInt())/2,(list2.at(2).toInt()+list2.at(4).toInt())/2};
            m1.pos=pos;
            m2.pos=pos;
            m1.upward=(list2.at(1).toInt()==list2.at(3).toInt());
            m2.upward=m1.upward;
            movements[time].push_back(m1);
            movements[time+1].push_back(m2);
            totaltime=utils::max(totaltime,time+1);
        }
    }
    
    bool MainWindow::processSimulation(){
        //return the validity of the scenes
        Scene empty;
        scenes.push_back(empty);
        for(int i=1;i<=totaltime;i++){
            //generate scene[i] on the fundaion of scene[i-1] and movements[i-1]
            QMap<Pos,Drop*> lastmap;
            foreach(Drop* drop,scenes[i-1].dropstatus.keys()){
                lastmap.insert(scenes[i-1].dropstatus.value(drop).pos,drop);
            }
            Scene newscene=scenes[i-1];
            newscene.newcontaminations.clear();
            //process movements of drops and contaminations
            foreach(Movement move,movements[i-1]){
                if(move.type==0){
                    //Input
                    bool inputvalid=false;
                    foreach(Pos pos,setting.in){
                        if(pos==move.pos){
                            inputvalid=true;
                            break;
                        }
                    }
                    if(inputvalid){
                        Drop *newdrop=new Drop(this,counter,Qt::black);
                        drops.insert(counter,newdrop);
                        counter++;
                        newscene.dropstatus.insert(newdrop,{move.pos,false,false});
                        newscene.newcontaminations[move.pos].insert(newdrop->id);
                    }else{
                        QMessageBox::critical(this, "Simulating Failed", "Input error.");
                        return false;
                    }
                }else if(move.type==1){
                    //Output
                    if(lastmap.contains(move.pos)&&move.pos==setting.out){
                        for(auto it=newscene.dropstatus.begin();it!=newscene.dropstatus.end();it++){
                            if(it.value().pos==move.pos){
                                newscene.dropstatus.erase(it);
                                break;
                            }
                        }
                    }else{
                        QMessageBox::critical(this, "Simulating Failed", "Output error.");
                        return false;
                    }
                }else if(move.type==2){
                    //Move
                    if(lastmap.contains(move.pos)&&isadjacent(move.pos,move.destination)){
                        newscene.dropstatus[lastmap.value(move.pos)].pos=move.destination;
                        newscene.newcontaminations[move.destination].insert(lastmap.value(move.pos)->id);
                    }else{
                        QMessageBox::critical(this, "Simulating Failed", "Move or mix error.");
                        return false;
                    }
                }else if(move.type==3){
                    //Split1
                    if(lastmap.contains(move.pos)){
                        newscene.dropstatus[lastmap.value(move.pos)].elliptical=true;
                        newscene.dropstatus[lastmap.value(move.pos)].vertical=move.upward;
                    }else{
                        QMessageBox::critical(this, "Simulating Failed", "Split error.");
                        return false;
                    }
                }else if(move.type==4){
                    //Split2
                    if(lastmap.contains(move.pos)&&newscene.dropstatus.value(lastmap.value(move.pos)).elliptical){
                        Pos pos1(move.pos),pos2(move.pos);
                        if(newscene.dropstatus.value(lastmap.value(move.pos)).vertical){
                            pos1.y--;
                            pos2.y++;
                        }else{
                            pos1.x--;
                            pos2.x++;
                        }
                        Drop *newdrop1=new Drop(this,counter,Qt::black);
                        drops.insert(counter,newdrop1);
                        counter++;
                        newscene.dropstatus.insert(newdrop1,{pos1,false,false});
                        newscene.newcontaminations[pos1].insert(newdrop1->id);
                        Drop *newdrop2=new Drop(this,counter,Qt::black);
                        drops.insert(counter,newdrop2);
                        counter++;
                        newscene.dropstatus.insert(newdrop2,{pos2,false,false});
                        newscene.newcontaminations[pos2].insert(newdrop2->id);
    
                        for(auto it=newscene.dropstatus.begin();it!=newscene.dropstatus.end();it++){
                            if(it.value().pos==move.pos){
                                newscene.dropstatus.erase(it);
                                break;
                            }
                        }
                    }else{
                        QMessageBox::critical(this, "Simulating Failed", "Split error.");
                        return false;
                    }
                }else if(move.type==5){
                    //Merge1
                    Pos pos1(move.pos),pos2(move.pos);
                    if(move.upward){
                        pos1.y--;
                        pos2.y++;
                    }else{
                        pos1.x--;
                        pos2.x++;
                    }
                    if(lastmap.contains(pos1)&&lastmap.contains(pos2)){
                        Drop *newdrop=new Drop(this,counter,Qt::black);
                        drops.insert(counter,newdrop);
                        counter++;
                        newscene.dropstatus.insert(newdrop,{move.pos,true,move.upward});
                        newscene.newcontaminations[move.pos].insert(newdrop->id);
                        for(auto it=newscene.dropstatus.begin();it!=newscene.dropstatus.end();it++){
                            if(it.value().pos==pos1){
                                newscene.dropstatus.erase(it);
                                break;
                            }
                        }
                        for(auto it=newscene.dropstatus.begin();it!=newscene.dropstatus.end();it++){
                            if(it.value().pos==pos2){
                                newscene.dropstatus.erase(it);
                                break;
                            }
                        }
                    }else{
                        QMessageBox::critical(this, "Simulating Failed", "Merge error.");
                        return false;
                    }
                }else if(move.type==6){
                    //Merge2
                    if(lastmap.contains(move.pos)&&newscene.dropstatus.value(lastmap.value(move.pos)).elliptical&&newscene.dropstatus.value(lastmap.value(move.pos)).vertical==move.upward){
                        newscene.dropstatus[lastmap.value(move.pos)].elliptical=false;
                    }else{
                        QMessageBox::critical(this, "Simulating Failed", "Merge error.");
                        return false;
                    }
                }
            }
            //test the validity of this scene
            //in the border
            foreach(Drop* drop,newscene.dropstatus.keys()){
                if(!intheborder(newscene.dropstatus.value(drop).pos)){
                    QMessageBox::critical(this, "Simulating Failed", "Border exceeded.");
                    return false;
                }
            }
            //static and dynamic constraint
            foreach(Drop* drop,newscene.dropstatus.keys()){
                foreach(Drop* drop1,newscene.dropstatus.keys()){
                    if(drop!=drop1){
                        if(newscene.dropstatus.value(drop).elliptical){
                            Pos pos1(newscene.dropstatus.value(drop).pos),pos2(newscene.dropstatus.value(drop).pos);
                            if(newscene.dropstatus.value(drop).vertical){
                                pos1.y--;
                                pos2.y++;
                            }else{
                                pos1.x--;
                                pos2.x++;
                            }
                            if(!farenough(pos1,newscene.dropstatus.value(drop1).pos)){
                                QMessageBox::critical(this, "Simulating Failed", "Static constraint violation.");
                                return false;
                            }
                            if(!farenough(pos2,newscene.dropstatus.value(drop1).pos)){
                                QMessageBox::critical(this, "Simulating Failed", "Static constraint violation.");
                                return false;
                            }
                        }else{
                            if(!farenough(newscene.dropstatus.value(drop).pos,newscene.dropstatus.value(drop1).pos)){
                                QMessageBox::critical(this, "Simulating Failed", "Static constraint violation.");
                                return false;
                            }
                        }
                    }
    
                }
                foreach(Drop* drop2,scenes[i-1].dropstatus.keys()){
                    if(drop!=drop2){
                        if(!newscene.dropstatus.value(drop).elliptical){
                            Pos pos=newscene.dropstatus.value(drop).pos;
                            if(!scenes[i-1].dropstatus.value(drop2).elliptical){
                                Pos pos20(newscene.dropstatus.value(drop2).pos);
                                if(!farenough(pos,pos20)){
                                    QMessageBox::critical(this, "Simulating Failed", "Static constraint violation.");
                                    return false;
                                }
                            }
                        }
                    }
                }
            }
    
            //if valid, add newscene and modify validtime
            scenes.push_back(newscene);
            validtime=i;
        }
        return true;
    }
    
    bool MainWindow::isadjacent(Pos pos1,Pos pos2){
        int dx,dy;
        dx=utils::abs(pos1.x,pos2.x);
        dy=utils::abs(pos1.y,pos2.y);
        return (dx==1&&dy==0)||(dx==0&&dy==1);
    }
    bool MainWindow::farenough(Pos pos1,Pos pos2){
        int dx,dy;
        dx=utils::abs(pos1.x,pos2.x);
        dy=utils::abs(pos1.y,pos2.y);
        return dx>1||dy>1;
    }
    bool MainWindow::intheborder(Pos pos){
        return pos.x>0&&pos.x<=setting.w&&pos.y>0&&pos.y<=setting.h;
    }
    void MainWindow::jumpto(int i){
        if(i<0)i=0;
        if(i>validtime)i=validtime;
        if(i==0)action_last->setEnabled(false);
        if(i==validtime){
            action_next->setEnabled(false);
            action_play->setEnabled(false);
        }
        if(status==2){
            if(i!=0)action_last->setEnabled(true);
            if(i!=validtime){
                action_next->setEnabled(true);
                action_play->setEnabled(true);
            }
        }
        ui->label->setText("Present time: "+QString::number(time)+"/"+QString::number(validtime));
        if(setting.washable&&i!=validtime){
            int restore=status;
            if(i!=0)lattice->getContaminations(i);
            lattice->setScene(i);
            QTime t;
            t.start();
            while(t.elapsed()<300)
                QCoreApplication::processEvents();
            status=4;
            setStatus(4);
            lattice->wash();
            lattice->refresh();
            status=restore;
            setStatus(status);
        }else{
            if(i!=0)lattice->getContaminations(i);
            lattice->setScene(i);
        }
        if(i==0)action_last->setEnabled(false);
        if(i==validtime){
            action_next->setEnabled(false);
            action_play->setEnabled(false);
        }
        if(status==2){
            if(i!=0)action_last->setEnabled(true);
            if(i!=validtime){
                action_next->setEnabled(true);
                action_play->setEnabled(true);
            }
        }
    }
    void MainWindow::nextstep(){
        time++;
        foreach(Movement move,movements[time-1]){
            if(move.type==2){
                sound_move->play();
            }else if(move.type==3){
                sound_split1->play();
            }else if(move.type==4){
                sound_split2->play();
            }else if(move.type==6){
                sound_merge->play();
            }
        }
        jumpto(time);
    }
    void MainWindow::laststep(){
        time--;
        jumpto(time);
    }
    void MainWindow::reset(){
        time=0;
        jumpto(0);
    }
    void MainWindow::play(){
        setStatus(3);
        status=3;
        while(time<validtime&&status==3){
            QTime t;
            t.start();
            while(t.elapsed()<300)
                QCoreApplication::processEvents();
            nextstep();
        }
        stop();
    }
    void MainWindow::stop(){
        setStatus(2);
        status=2;
        jumpto(time);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    通过阿里云创建accessKeyId和accessKeySecret
    redis
    智慧水利整体解决方案
    初级java 面试时经常会问到的问题!
    Spring Boot 简介与入门
    安防监控系统视频融合平台EasyCVR页面地图功能细节详解
    photoshop常用快捷键
    Java Gradle
    Unity如何生成随机数(设置种子)
    onnxruntime C++推理
  • 原文地址:https://blog.csdn.net/newlw/article/details/126827267