599 lines
15 KiB
C++
599 lines
15 KiB
C++
#include "ReplayWrapper.h"
|
|
|
|
void JUDGE_SDK_CALLBACK __examJudgeCallbackLogImpl__(int level, const char* info, int len)
|
|
{
|
|
ReplayWrapper::GetInstance()->replayXexamJudgeCallbackLogImpl(level, info, len);
|
|
}
|
|
|
|
void JUDGE_SDK_CALLBACK __examJudgeCallbackRealExamImpl__(const char* data, int len)
|
|
{
|
|
ReplayWrapper::GetInstance()->replayXexamJudgeCallbackRealExamImpl(data, len);
|
|
}
|
|
|
|
void JUDGE_SDK_CALLBACK __examJudgeCallbackPerformImpl__(const char* data, int len)
|
|
{
|
|
ReplayWrapper::GetInstance()->replayXexamJudgeCallbackPerformImpl(data, len);
|
|
}
|
|
|
|
void JUDGE_SDK_CALLBACK __examJudgeCallbackMapImageImpl__(const char* data, int len)
|
|
{
|
|
ReplayWrapper::GetInstance()->replayXexamJudgeCallbackMapImageImpl(data, len);
|
|
}
|
|
|
|
SINGLETON_IMEPLEMENT(ReplayWrapper);
|
|
|
|
bool ReplayWrapper::replayInit()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void ReplayWrapper::replayUnInit()
|
|
{
|
|
replayReset();
|
|
examJudgeDestroy();
|
|
}
|
|
|
|
void ReplayWrapper::replayReset()
|
|
{
|
|
m_running = false;
|
|
m_pause = false;
|
|
m_frameNum = 0;
|
|
m_assignNum = 0;
|
|
//m_trackDatas.clear();
|
|
m_kfxm.clear();
|
|
m_cond.notify_all();
|
|
__DELETE__(m_reader);
|
|
if(m_thread)
|
|
{
|
|
if(m_thread->joinable())
|
|
{
|
|
m_thread->join(); //detach线程不能被join
|
|
}
|
|
__DELETE__(m_thread);
|
|
}
|
|
}
|
|
|
|
bool ReplayWrapper::replayRunning(bool running)
|
|
{
|
|
if(running)
|
|
{
|
|
if(m_filename.isEmpty())
|
|
{
|
|
logwarning("m_trackfile is empty");
|
|
return false;
|
|
}
|
|
replayReset();
|
|
|
|
TASSERT_BOOL(nullptr == m_thread, "why not?");
|
|
m_running = true;
|
|
m_thread = __KIT_NEW__(std::thread, [&, this]()->void {return replayTrackReadData();});
|
|
}
|
|
else
|
|
{
|
|
replayReset();
|
|
|
|
IExamCar* car = FactoryExamService->getExamCar();
|
|
if(car != nullptr && car->examState() != examStateEnd)
|
|
{
|
|
int codeValue = examJudgeEndExam();
|
|
TASSERT(codeValue == codeSuccess, "codeValue=%s", errorCode2Name((ErrorCode)codeValue));
|
|
}
|
|
//__LOOK__(""); // 日志输出未释放的内存
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ReplayWrapper::replayIsRunning() const
|
|
{
|
|
return m_running;
|
|
}
|
|
|
|
void ReplayWrapper::replaySetTrackFile(const QString& filename)
|
|
{
|
|
m_reload = true;
|
|
m_filename = filename;
|
|
}
|
|
|
|
void ReplayWrapper::replayPause(bool pause)
|
|
{
|
|
m_pause = pause;
|
|
}
|
|
|
|
void ReplayWrapper::replayTrackReadData()
|
|
{
|
|
logtrace("正在加载轨迹数据,请稍等...");
|
|
if(m_reload)
|
|
{
|
|
m_reload = false;
|
|
std::string filename = m_filename.toLocal8Bit().toStdString();
|
|
TASSERT(nullptr == m_reader, "why not?");
|
|
m_reader = __KIT_NEW__(TrackReader, filename);
|
|
m_trackDatas.clear();
|
|
bool ok = m_reader->read(m_trackDatas);
|
|
TASSERT(ok, "");
|
|
}
|
|
|
|
while(m_running)
|
|
{
|
|
if(m_assignNum != 0 && m_frameNum < m_assignNum)
|
|
{
|
|
int cpuCount = QThread::idealThreadCount();
|
|
int ms = 20.0 / (cpuCount / 8.0); //8核CPU的每20毫秒执行快进一帧也就是每秒50帧
|
|
while(m_frameNum != m_assignNum)
|
|
{
|
|
if(!replayTrackReadStep(ms)) //20
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
m_assignNum = 0;
|
|
continue;
|
|
}
|
|
|
|
if(m_pause)
|
|
{
|
|
sdk_msleep(100);
|
|
continue;
|
|
}
|
|
|
|
if(!replayTrackReadStep(m_playSpeedMs))
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
//int codeValue = examJudgeEndExam();
|
|
//TASSERT(codeValue == codeSuccess, "");
|
|
|
|
loginfo("the track over.");
|
|
|
|
emit updateNextDoing();
|
|
}
|
|
|
|
bool ReplayWrapper::replayTrackReadStep(int playSpeed)
|
|
{
|
|
if(!m_running) return false;
|
|
TTrackData::Ptr data = nullptr;
|
|
//if(!m_reader->read(data))
|
|
if(!replayRead(data))
|
|
{
|
|
//sdk_msleep(100);
|
|
logwarning("read track data over");
|
|
return false;
|
|
}
|
|
|
|
switch(data->type)
|
|
{
|
|
case TTrackTypeInitExam:
|
|
{
|
|
replayTrackTypeInitExam(data);
|
|
}break;
|
|
case TTrackTypeBeginExam:
|
|
{
|
|
replayTrackTypeBeginExam(data);
|
|
}break;
|
|
case TTrackTypeRealExam:
|
|
{
|
|
replayTrackTypeRealExam(data);
|
|
std::unique_lock<decltype(m_mt)> lk(m_mt);
|
|
std::cv_status s = m_cond.wait_for(lk, std::chrono::milliseconds(playSpeed));
|
|
if(std::cv_status::timeout == s)
|
|
{
|
|
|
|
}
|
|
//replayMapTrackImage();
|
|
}break;
|
|
case TTrackTypeArtificialMark:
|
|
{
|
|
replayTrackTypeArtificialMark(data);
|
|
}break;
|
|
case TTrackTypeArtificialItem:
|
|
{
|
|
replayTrackTypeArtificialItem(data);
|
|
}break;
|
|
case TTrackTypeSoundEnd:
|
|
{
|
|
replayTrackTypeSoundEnd(data);
|
|
}break;
|
|
default:
|
|
TASSERT(false, "");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ReplayWrapper::replayTrackTypeInitExam(const TTrackData::Ptr& data)
|
|
{
|
|
{
|
|
std::string strInit(data->data);
|
|
|
|
XParser parser;
|
|
TInitInfo info;
|
|
if(!parser.parseInitExam(strInit, &info))
|
|
{
|
|
logerror("replayTrackTypeInitExam parseInitExam error.");
|
|
return;
|
|
}
|
|
//if(!m_carInfo.kchp.empty())
|
|
//{
|
|
// if(m_carInfo.kchp == info.kchp)
|
|
// {
|
|
// loginfo("replayTrackTypeInitExam same car.");
|
|
// return;
|
|
// }
|
|
// else
|
|
// {
|
|
// //如果不是同一辆车,要重新走初始化流程
|
|
// examJudgeDestroy();
|
|
// }
|
|
//}
|
|
|
|
|
|
int codeValue = codeSuccess;
|
|
|
|
//static bool s_init = false;
|
|
//if(!s_init)
|
|
//{
|
|
// s_init = true;
|
|
//}
|
|
//================================================
|
|
examJudgeDestroy();
|
|
//__LOOK__("");
|
|
m_carInfo = info;
|
|
|
|
codeValue = examJudgeInit(strInit.c_str(), strInit.length());
|
|
if(codeValue == errorInitAlready)
|
|
{
|
|
logwarning("init errorInitAlready codeValue=%d", codeValue);
|
|
return;
|
|
}
|
|
else if(codeValue != codeSuccess)
|
|
{
|
|
logerror("init error codeValue=%d", codeValue);
|
|
return;
|
|
}
|
|
//================================================
|
|
|
|
codeValue = examJudgeSetRealExamCallback(__examJudgeCallbackRealExamImpl__);
|
|
TASSERT_VOID(codeValue == codeSuccess, "");
|
|
|
|
codeValue = examJudgeSetPerformCallback(__examJudgeCallbackPerformImpl__);
|
|
TASSERT_VOID(codeValue == codeSuccess, "");
|
|
|
|
codeValue = examJudgeMapImageSetCallback(__examJudgeCallbackMapImageImpl__);
|
|
TASSERT_VOID(codeValue == codeSuccess, "");
|
|
|
|
codeValue = examJudgeMapSetParam(m_width, m_height);
|
|
TASSERT_VOID(codeValue == codeSuccess, "");
|
|
|
|
codeValue = examJudgeMapSetScaling(m_scaling);
|
|
TASSERT_VOID(codeValue == codeSuccess, "");
|
|
|
|
codeValue = examJudgeMapSetDrawing(true);
|
|
TASSERT_VOID(codeValue == codeSuccess, "");
|
|
}
|
|
|
|
{
|
|
QString org = QString::fromUtf8(data->data.c_str());
|
|
emit updateDataInitExam(org);
|
|
}
|
|
}
|
|
|
|
void ReplayWrapper::replayTrackTypeBeginExam(const TTrackData::Ptr& data)
|
|
{
|
|
std::string strStu(data->data);
|
|
XParser parser;
|
|
TStuInfo info;
|
|
if(!parser.parseBeginExam(strStu, info))
|
|
{
|
|
logerror("replayTrackTypeInitExam parseInitExam error.");
|
|
return;
|
|
}
|
|
|
|
m_stuInfo = info;
|
|
|
|
{
|
|
QString org = QString::fromUtf8(data->data.c_str());
|
|
emit updateDataBeginExam(org);
|
|
}
|
|
|
|
{
|
|
Json::Value root;
|
|
std::string strBegin(data->data);
|
|
Tools::fromJson(strBegin, root);
|
|
root["replay"] = m_replay ? 1 : 0;
|
|
//root["track"] = ""; //要生成的轨迹文件 空字符串("")不生成
|
|
strBegin = Tools::toJson(root);
|
|
|
|
ErrorCode codeValue = (ErrorCode)examJudgeBeginExam(strBegin.c_str(), strBegin.length());
|
|
TASSERT(codeValue == codeSuccess || codeValue == errorBeginNotQual, "");
|
|
}
|
|
}
|
|
|
|
void ReplayWrapper::replayTrackTypeRealExam(const TTrackData::Ptr& data)
|
|
{
|
|
{
|
|
std::string strReal(data->data);
|
|
int codeValue = examJudgeRealExam(strReal.c_str(), strReal.length());
|
|
TASSERT(codeValue == codeSuccess, "");
|
|
}
|
|
|
|
{
|
|
QString org = QString::fromUtf8(data->data.c_str());
|
|
emit updateDataRealExam(org);
|
|
}
|
|
|
|
{
|
|
//m_frameNum++; //前2条数据是初始化和从0开始的
|
|
emit updateDataFrameNum(m_frameNum, m_trackDatas.size());
|
|
}
|
|
|
|
}
|
|
|
|
void ReplayWrapper::replayTrackTypeArtificialMark(const TTrackData::Ptr& data)
|
|
{
|
|
Json::Value root;
|
|
bool ok = Tools::fromJson(data->data, root);
|
|
TASSERT(ok, "");
|
|
|
|
int itemno = root["itemno"].asInt();
|
|
std::string serial = root["serial"].asString();
|
|
int codeValue = examJudgeArtificialMark(itemno, serial.c_str());
|
|
TASSERT(codeValue == codeSuccess, "");
|
|
|
|
{
|
|
QString serialCode = QString::fromUtf8(serial.c_str());
|
|
emit updateDataArtificialMark(itemno, serialCode);
|
|
}
|
|
}
|
|
|
|
void ReplayWrapper::replayTrackTypeArtificialItem(const TTrackData::Ptr& data)
|
|
{
|
|
Json::Value root;
|
|
bool ok = Tools::fromJson(data->data, root);
|
|
TASSERT(ok, "");
|
|
|
|
int itemno = root["itemno"].asInt();
|
|
int type = root["type"].asInt();
|
|
int codeValue = examJudgeArtificialItem(itemno, type);
|
|
//TASSERT(codeValue == codeSuccess, "");
|
|
if(codeValue != codeSuccess)
|
|
{
|
|
logerror("examJudgeArtificialItem error %s", errorCode2Name((ErrorCode)codeValue));
|
|
}
|
|
|
|
{
|
|
emit updateDataArtificialItem(itemno, type);
|
|
}
|
|
}
|
|
|
|
void ReplayWrapper::replayTrackTypeSoundEnd(const TTrackData::Ptr &data)
|
|
{
|
|
//return; //240709
|
|
|
|
Json::Value root;
|
|
bool ok = Tools::fromJson(data->data, root);
|
|
TASSERT(ok, "");
|
|
|
|
int itemno = root["itemno"].asInt();
|
|
std::string code = root["code"].asString();
|
|
int type = root["type"].asInt();
|
|
int codeValue = examJudgeSoundEnd(itemno, code.c_str(), type);
|
|
//TASSERT(codeValue == codeSuccess, "");
|
|
if(codeValue != codeSuccess)
|
|
{
|
|
logerror("examJudgeSoundEnd error %s", errorCode2Name((ErrorCode)codeValue));
|
|
}
|
|
|
|
{
|
|
QString soundCode = QString::fromUtf8(code.c_str());
|
|
emit updateDataSoundEnd(itemno, soundCode, type);
|
|
}
|
|
}
|
|
|
|
void ReplayWrapper::replayXexamJudgeCallbackLogImpl(int level, const char* info, int len)
|
|
{
|
|
//QString unicode = replay::converAnyToString(QByteArray(info, len));
|
|
emit updateDataLog(level, QByteArray(info, len)); //QString::fromLocal8Bit(info, len)
|
|
}
|
|
|
|
void ReplayWrapper::replayXexamJudgeCallbackRealExamImpl(const char* data, int len)
|
|
{
|
|
emit updateDataCallbackRealExam(QString::fromLocal8Bit(data, len));
|
|
}
|
|
|
|
void ReplayWrapper::replayXexamJudgeCallbackPerformImpl(const char* data, int len)
|
|
{
|
|
emit updateDataCallbackPerform(QString::fromLocal8Bit(data, len));
|
|
}
|
|
|
|
void ReplayWrapper::replayXexamJudgeCallbackMapImageImpl(const char* data, int len)
|
|
{
|
|
TASSERT(len == m_width * m_height * 4, "");
|
|
QImage img((const uchar*)data, m_width, m_height, QImage::Format_RGBA8888);
|
|
emit updateDataImage(img);
|
|
}
|
|
|
|
void ReplayWrapper::replayMapTrackImage()
|
|
{
|
|
//QPixmap::fromImage(img);
|
|
QImage img((const uchar*)examJudgeMapImage(), m_width, m_height, QImage::Format_RGBA8888);
|
|
emit updateDataImage(img);
|
|
}
|
|
|
|
int ReplayWrapper::replayTrackDataSize()
|
|
{
|
|
return m_trackDatas.size();
|
|
}
|
|
|
|
ExamSubject ReplayWrapper::replayExamSubject()
|
|
{
|
|
return (ExamSubject)m_carInfo.kskm;
|
|
}
|
|
|
|
ExamCarType ReplayWrapper::replayExamCarType()
|
|
{
|
|
return name2ExamCarType(m_carInfo.kscx.c_str());
|
|
}
|
|
|
|
const TInitInfo& ReplayWrapper::replayCarInitInfo()
|
|
{
|
|
return m_carInfo;
|
|
}
|
|
|
|
const TStuInfo& ReplayWrapper::replayStuInfo()
|
|
{
|
|
return m_stuInfo;
|
|
}
|
|
|
|
void ReplayWrapper::replayRetrogress()
|
|
{
|
|
m_frameNum--;
|
|
m_frameNum--;//replayTrackReadStep()会++所以要两次--才能倒退到上一针
|
|
//前两帧一个是初始化考试,一个是开始考试,要过滤掉
|
|
if(m_frameNum < 2) m_frameNum = 2;
|
|
replayTrackReadStep();
|
|
}
|
|
|
|
void ReplayWrapper::replaySetSlider(int value)
|
|
{
|
|
m_slider = value;
|
|
double percent = m_slider / 100.0;
|
|
m_frameNum = percent * m_trackDatas.size();
|
|
//前两帧一个是初始化考试,一个是开始考试,要过滤掉
|
|
if(m_frameNum < 2) m_frameNum = 2;
|
|
replayTrackReadStep();
|
|
}
|
|
|
|
bool ReplayWrapper::replayRead(TTrackData::Ptr& data)
|
|
{
|
|
if(m_frameNum >= 0 && m_frameNum < (int)m_trackDatas.size())
|
|
{
|
|
data = m_trackDatas[m_frameNum];
|
|
m_frameNum++;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ReplayWrapper::replayIsPause() const
|
|
{
|
|
return m_pause;
|
|
}
|
|
|
|
void ReplayWrapper::replaySetSize(int width, int height)
|
|
{
|
|
m_width = width;
|
|
m_height = height;
|
|
}
|
|
|
|
void ReplayWrapper::replaySetScaling(int scaling)
|
|
{
|
|
m_scaling = scaling;
|
|
if(m_running)
|
|
{
|
|
examJudgeMapSetScaling(m_scaling);
|
|
replayMapTrackImage();
|
|
}
|
|
}
|
|
|
|
void ReplayWrapper::replaySetPlaySpeed(int playSpeed)
|
|
{
|
|
m_playSpeed = playSpeed;
|
|
m_playSpeedMs = double(SECOND) / m_playSpeed;
|
|
m_cond.notify_all();
|
|
}
|
|
|
|
int ReplayWrapper::replayStretchScaling(bool plus)
|
|
{
|
|
m_scaling += (plus ? 10 : -10);
|
|
|
|
if(m_scaling <= 0)
|
|
{
|
|
m_scaling = 1;
|
|
}
|
|
if(m_scaling > 5000)
|
|
{
|
|
m_scaling = 5000;
|
|
}
|
|
if(m_running)
|
|
{
|
|
examJudgeMapSetScaling(m_scaling);
|
|
replayMapTrackImage();
|
|
}
|
|
return m_scaling;
|
|
}
|
|
|
|
int ReplayWrapper::replayStretchPlaySpeed(bool plus)
|
|
{
|
|
if(m_playSpeed < 10)
|
|
{
|
|
m_playSpeed += (plus ? 1 : -1);
|
|
}
|
|
else
|
|
{
|
|
m_playSpeed *= (plus ? 2 : 0.5);
|
|
if(!plus && m_playSpeed < 10)
|
|
{
|
|
m_playSpeed = 9;
|
|
}
|
|
}
|
|
|
|
if(m_playSpeed <= 0)
|
|
{
|
|
m_playSpeed = 1; //最慢每秒1幀
|
|
}
|
|
if(m_playSpeed > 200)
|
|
{
|
|
m_playSpeed = 200; //最快每秒100幀
|
|
}
|
|
m_playSpeedMs = double(SECOND) / m_playSpeed;
|
|
return m_playSpeed;
|
|
}
|
|
|
|
void ReplayWrapper::replaySetAssignNum(int num)
|
|
{
|
|
m_assignNum = num;
|
|
}
|
|
|
|
void ReplayWrapper::replayReplay(bool replay)
|
|
{
|
|
m_replay = replay;
|
|
}
|
|
|
|
void ReplayWrapper::replayItemMarkPush(ExamItemCode itemNo, const TKfXm& kf)
|
|
{
|
|
//m_kfxm.push_back(kf);
|
|
TKfXms& kfxm = m_kfxm[itemNo];
|
|
kfxm.push_back(kf);
|
|
}
|
|
|
|
int ReplayWrapper::replayItemMarkSize() const
|
|
{
|
|
return m_kfxm.size();
|
|
}
|
|
|
|
bool ReplayWrapper::replayItemMarkHas(ExamItemCode itemNo) const
|
|
{
|
|
//for(size_t i = 0; i < m_kfxm.size(); i++)
|
|
//{
|
|
// if(itemNo == m_kfxm[i].xmdm)
|
|
// {
|
|
// return true;
|
|
// }
|
|
//}
|
|
//return false;
|
|
|
|
auto it = m_kfxm.find(itemNo);
|
|
return it != m_kfxm.end() ? it->second.size() > 0 : false;
|
|
}
|
|
|
|
void ReplayWrapper::replaySetLogLevel(LogLvType lv)
|
|
{
|
|
m_logLv = lv;
|
|
int codeValue = examJudgeSetLogCallback(m_logLv, __examJudgeCallbackLogImpl__);
|
|
TASSERT_VOID(codeValue == codeSuccess, "");
|
|
}
|