subject-two/entry/src/main/cpp/toolkit/replay/ReplayWrapper.cpp
2024-07-16 11:12:45 +08:00

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, "");
}