703 lines
20 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "IExamCar.h"
#include "ExamCarSub2.h"
#include "ExamCarSub3.h"
#include "HFactory.h"
IExamCar::IExamCar()
{
m_graphic = __NEW__(GraphicImage);
m_sensor = __NEW__(ExamSensor);
m_history = __NEW__(ExamHistoryChuan);
m_handle = __NEW__(ExamDatagram, [&, this](Package* data)->void{ doExamDatagram(data); });
}
IExamCar::~IExamCar()
{
__DELETE__(m_handle);
__DELETE__(m_graphic);
__DELETE__(m_sensor);
__DELETE__(m_history);
m_carInfo = nullptr;
}
IExamCar* IExamCar::create(ExamSubject subject)
{
IExamCar* car = NULL;
switch(subject)
{
case ExamSubject2: car = __NEW__(ExamCarSub2); break;
case ExamSubject3: car = __NEW__(ExamCarSub3); break;
default: TASSERT(false, ""); break;
}
return car;
}
void IExamCar::destroy(IExamCar* & p)
{
__DELETE__(p);
}
int IExamCar::examJudgeBeginExam(const char* data, int len)
{
HELP_COST_TIME("");
IAutoLock(m_mtx);
logtrace("begin-exam version=%s", JUDGE_VERSION_INFO);
if(m_examState != examStateEnd)
{
logerror("error begin exam not end.");
return QE(errorBeginNotEnd);
}
if(!XParser::fromAny(std::string(data, len), m_stuInfo))
{
logerror("error begin exam parser.");
return QE(errorBeginParser);
}
if(m_stuInfo.kkcs <= 0) //可考次数判断
{
logerror("error begin exam times=%d.", m_stuInfo.kkcs);
return QE(errorBeginTimes);
}
if(m_stuInfo.xm.empty() || m_stuInfo.sfzmhm.empty() || m_stuInfo.kslsh.empty()) //考生信息判断
{
logerror("error begin exam student info error.");
return QE(errorBeginInfo);
}
{
char tag[256] = {0};
//SafeSprintf(tag, sizeof(tag), "target sfzmhm=%s, kscx=%s, kskm=%d, kchm=%d, kchp=%s",
// m_stuInfo.sfzmhm.c_str(), m_carInfo->kscx.c_str(), m_carInfo->kskm, m_carInfo->kchm, m_carInfo->kchp.c_str());
SafeSprintf(tag, sizeof(tag), "target sfzmhm=%s", m_stuInfo.sfzmhm.c_str());
m_target = tag;
}
__DELETE__(m_track);
m_track = __NEW__(TrackWriter, m_stuInfo.track);
const std::string& initData = FactoryExamService->getInitData();
m_track->write(TTrackTypeInitExam, initData);
m_track->write(TTrackTypeBeginExam, data, len);
ExamCarType cartype = carType();
ExamSubject subject = examSubject();
m_grade = GRADE_TOTAL_FULL;
if(m_stuInfo.passing <= 0) { m_stuInfo.passing = examCarType2Pass(subject, cartype); } //及格分数
m_timeBegin = isReplay() ? 0 : Tools::nowTime();
m_timeEnd = 0;
m_disOffset = 0;
m_disForward = 0;
m_disBackward = 0;
memset(m_disGears, 0, sizeof(m_disGears));
m_message = "";
m_codes.clear();
m_marks.clear();
//如果这里不清那APP外壳如果在非考试状态不调用examJudgeRealExam
//在上一个学员考试结束并且车辆还在行驶,下一个学员开始考试瞬间就会行驶几百米距离的误计算
m_history->clear();
m_nonflag = 0;
m_nontime = 0;
m_nongps = TGpsInfo();
//(*********************不同科目开始考试处理*********************)
ErrorCode errCode = examBeginExam();
if(errCode != codeSuccess)
{
return QE((ErrorCode)errCode);
}
m_examState = examStateIng;
logtrace("begin-exam success %s", target().c_str());
return QE(codeSuccess);
}
int IExamCar::examJudgeEndExam()
{
logtrace("end-exam-judge begin %s", target().c_str());
//IAutoLock(m_mtx);
m_handle->addRealtime(Package::id_end, INVALID_INDEX, "", GetCurrentTime2());
return QE(codeSuccess);
}
int IExamCar::examJudgeEndExamFinish()
{
logtrace("end-exam begin %s", target().c_str());
//IAutoLock(m_mtx);
createEventExamFinish(ExamFinishArti);
m_handle->clearRealtime();
if(m_examState == examStateEnd)
{
logerror("error end exam already");
return QE(errorEndAlready);
}
m_examState = examStateEnd;
__DELETE__(m_track);
m_message = "";
m_codes.clear();
m_marks.clear();
m_timeEnd = GetCurrentTime2(); //必须在这句前面 m_cg = nullptr;
m_cg = nullptr;
//if(isReplay()) //只有回放模式下才清空 2024-04-09 yhy
//{
// m_history->clear();
//}
//如果这里不清那APP外壳如果在非考试状态不调用examJudgeRealExam
//在上一个学员考试结束并且车辆还在行驶,下一个学员开始考试瞬间就会行驶几百米距离的误计算
m_history->clear();
ErrorCode errCode = examEndExam();
if(errCode != codeSuccess)
{
return QE((ErrorCode)errCode);
}
logtrace("end-exam success %s", target().c_str());
return QE(codeSuccess);
}
int IExamCar::examJudgeRealExam(const char* data, int len)
{
//IAutoLock(m_mtx);
m_handle->addRealtime(Package::id_real_exam, INVALID_INDEX, data, len, GetCurrentTime2());
return QE(codeSuccess);
}
int IExamCar::examJudgeRealVision(int type, const char* data, int len)
{
#if !JUDGE_USE_NSUB3
return QE(errorNS3NotSupport);
#else
//IAutoLock(m_mtx);
const std::vector<std::string>& s531 = TableSysSet->asArray531();
bool isUseBeha = (s531.size() > 1 && s531[1] == "1");
const std::vector<std::string>& s407 = TableSysSet->asArray407();
bool isUsePose = (s407.size() > 0 && s407[0] == "1");
bool isUseNight = (s407.size() > 1 && s407[1] == "1");
if(type == VisionTypePose)
{
if(!isUsePose)
{
return QE(errorNS3VisPoseNot);
}
if(isSfyk() && !isUseNight)
{
return QE(errorNS3VisPoseNot);
}
}
else if(type == VisionTypeBeha)
{
if(!isUseBeha)
{
return QE(errorNS3VisBehaNot);
}
}
else if(type == VisionTypeTarg)
{
}
else
{
return QE(errorNS3VisParam);
}
m_handle->addRealtime(Package::id_N3_vision, type, data, len, GetCurrentTime2());
return QE(codeSuccess);
#endif
}
int IExamCar::examJudgeRealRadar(int type, const char* data, int len)
{
#if !JUDGE_USE_NSUB3
return QE(errorNS3NotSupport);
#else
//IAutoLock(m_mtx);
const std::vector<std::string>& s531 = TableSysSet->asArray531();
bool isUseRadar = (s531.size() > 0 && s531[0] == "1");
if(type == RadarTypeNormal)
{
if(!isUseRadar)
{
return QE(errorNS3RadarNot);
}
}
else
{
return QE(errorNS3RadarParam);
}
m_handle->addRealtime(Package::id_N3_radar, type, data, len, GetCurrentTime2());
return QE(codeSuccess);
#endif
}
int IExamCar::examJudgeRealExam2(const char* data, int len)
{
//IAutoLock(m_mtx);
m_handle->addRealtime(Package::id_hardware, INVALID_INDEX, data, len, GetCurrentTime2());
return QE(codeSuccess);
}
int IExamCar::examJudgeArtificialMark(int itemno, const char* serial, int type)
{
HELP_COST_TIME("");
logtrace("artificial-mark itemNo=%d, serial=%s", itemno, serial);
IAutoLock(m_mtx);
ErrorCode code = examArtifMark(ExamItemCode(itemno), serial, MarkType(type));
examPerformSummary();
return code;
}
int IExamCar::examJudgeArtificialItem(int itemno, int type)
{
HELP_COST_TIME("");
logtrace("artificial-item itemNo=%d, type=%d", itemno, type);
IAutoLock(m_mtx);
ErrorCode code = examArtifItem(ExamItemCode(itemno), ArtifItemType(type));
return code;
}
int IExamCar::examJudgeSoundEnd(int itemno, const char* code, int type)
{
logtrace("sound-end itemNo=%d, code=%s, type=%d", itemno, code, type);
IAutoLock(m_mtx);
ErrorCode errCode = examSoundEnd(ExamItemCode(itemno), code, PlaySoundType(type));
return errCode;
}
int IExamCar::examJudgeMapSetParam(int width, int height)
{
IAutoLock(m_mtx);
if(width <= 0 || height <= 0)
{
return QE(errorMapSetParam);
}
if(nullptr == m_graphic)
{
return QE(errorMapSetParam);
}
m_graphic->resize(width, height);
return QE(codeSuccess);
}
int IExamCar::examJudgeMapSetScaling(int scaling)
{
IAutoLock(m_mtx);
if(scaling <= 0)
{
return QE(errorMapSetScaling);
}
if(nullptr == m_graphic)
{
return QE(errorMapSetScaling);
}
m_graphic->setScaling(scaling);
return QE(codeSuccess);
}
int IExamCar::examJudgeMapSetDrawing(bool drawing)
{
IAutoLock(m_mtx);
m_drawing = drawing;
return QE(codeSuccess);
}
const char* IExamCar::examJudgeMapImage()
{
IAutoLock(m_mtx);
examDrawMap();
return m_graphic ? m_graphic->image() : nullptr;
}
int IExamCar::examJudgeMapWidth()
{
IAutoLock(m_mtx);
return m_graphic ? m_graphic->width() : 0;
}
int IExamCar::examJudgeMapHeight()
{
IAutoLock(m_mtx);
return m_graphic ? m_graphic->height() : 0;
}
int IExamCar::examJudgeMapSize()
{
IAutoLock(m_mtx);
return m_graphic ? m_graphic->size() : 0;
}
void IExamCar::createEventEnterItem(const TEventEnterItem& event)
{
TJudgeEvent exam;
exam.event = ExamEventTypeItemEnter;
exam.sj = GetCurrentTime2();
exam.xmks = event;
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
logtrace("item-enter-event %s itemno=%d, xmxh=%s", target().c_str(), event.xmdm, event.xmxh.c_str());
}
void IExamCar::createEventFinishItem(const TEventFinishItem& event)
{
TJudgeEvent exam;
exam.event = ExamEventTypeItemFinish;
exam.sj = GetCurrentTime2();
exam.xmjs = event;
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
logtrace("item-finish-event %s itemno=%d, xmxh=%s, xmhg=%d", target().c_str(), event.xmdm, event.xmxh.c_str(), event.xmhg);
}
void IExamCar::createEventMarkItem(const TEventItemMark& event)
{
TJudgeEvent exam;
exam.event = ExamEventTypeMark;
exam.sj = GetCurrentTime2();
exam.kf = event;
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
logtrace("mark-item %s itemno=%d,markserial=%s", target().c_str(), event.xmdm, event.kfdm.c_str());
}
void IExamCar::createEventMoveState(const TEventCarMove& event)
{
TJudgeEvent exam;
exam.event = ExamEventTypeMoveState;
exam.sj = GetCurrentTime2();
exam.carzt = event;
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
}
void IExamCar::createEventExamFinish(ExamFinishType type)
{
examPerformSummary();
m_examState = examStateFinish;
TJudgeEvent exam;
exam.event = ExamEventTypeExamFinish;
exam.sj = GetCurrentTime2();
exam.ksjs.type = type;
exam.ksjs.qjjl = disKsLjLc();
exam.ksjs.dcjl = m_disBackward;
exam.ksjs.d1 = m_disGears[1];
exam.ksjs.d2 = m_disGears[2];
exam.ksjs.d3 = m_disGears[3];
exam.ksjs.d4 = m_disGears[4];
exam.ksjs.d5 = m_disGears[5];
exam.ksjs.d6 = m_disGears[6];
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
logtrace("exam-finish-event %s", target().c_str());
}
void IExamCar::createEventCancelItem(const TEventCancelItem& event)
{
TJudgeEvent exam;
exam.event = ExamEventTypeItemCancel;
exam.sj = GetCurrentTime2();
exam.xmqx = event;
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
logtrace("item-cancel-event %s itemno=%d, subIdx=%s", target().c_str(), event.xmdm, event.xmxh.c_str());
}
void IExamCar::createEventSound(const TEventSound& event)
{
TJudgeEvent exam;
exam.event = ExamEventTypeSound;
exam.sj = GetCurrentTime2();
exam.sound = event;
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
std::string code = event.codeData();
logtrace("sound-event %s itemno=%d, code=%s, type=%d", target().c_str(), event.xmdm, code.c_str(), event.type);
}
void IExamCar::createEventLight(const TEventLight& event)
{
TJudgeEvent exam;
exam.event = ExamEventTypeLight;
exam.sj = GetCurrentTime2();
exam.mndg = event;
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
logtrace("event-light %s item=%s", target().c_str(), exam.mndg.c_str());
}
void IExamCar::createEventLane(const TEventLane& event)
{
TJudgeEvent exam;
exam.event = ExamEventTypeLane;
exam.sj = GetCurrentTime2();
exam.lane = event;
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
logtrace("event-lane %s road=%s,num=%d,count=%d", target().c_str(), event.road.c_str(), event.num, event.count);
}
void IExamCar::createEventPrecastItem(const TEventPrecastItem& event)
{
TJudgeEvent exam;
exam.event = ExamEventTypeItemPrecast;
exam.sj = GetCurrentTime2();
exam.precast = event;
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
logtrace("item-precast-event %s itemno=%d, xmxh=%s", target().c_str(), event.xmdm, event.xmxh.c_str());
}
void IExamCar::createEventNonGps(const TEventNonGps& event)
{
TJudgeEvent exam;
exam.event = ExamEventTypeNonGps;
exam.sj = GetCurrentTime2();
exam.nongps = event;
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackRealExamToCaller(data.c_str(), data.size());
logtrace("item-nongps-event %s type=%d, sj=%lld, dwzt=%d, jdzt=%d, jd=%0.10f, wd=%0.10f", target().c_str(),
event.type, event.gps.sj, event.gps.dwzt, event.gps.jdzt, event.gps.jd, event.gps.wd);
}
void IExamCar::examPerformSummary()
{
if(historyCount() == 0)
{
return;
}
const Pointi& dis = historyAiGps();
TPerformData exam;
exam.time = timeElapsed();
exam.carzt = historyMoveState();
exam.grade = m_grade;
exam.qjjl = disKsLjLc();
exam.dcjl = m_disBackward;
exam.dxjl = dis.x*10; //单位毫米 所以要乘10
exam.bxjl = dis.y*10; //单位毫米 所以要乘10
exam.hint = m_message;
exam.lane = historyChuanGan()->RTKKM3;
ExamCarType cartype = carType();
if(IS_A2C6(cartype))
{
//对于牵引车,车身距离都是指的挂车(车厢),如果车轮,车前轮指的是车头的轮子,车后轮指的挂车最后面轮子,和军华确认过的 2025-05-13
const TRTKResult& rtkTail = historyChuanGan()->RTKKM3_Tail;
TRTKResult& lane = exam.lane;
lane.Body_LF_ToLeftEdge = rtkTail.Body_LF_ToLeftEdge;
lane.Body_LB_ToLeftEdge = rtkTail.Body_LB_ToLeftEdge;
lane.Body_RF_ToRightEdge = rtkTail.Body_RF_ToRightEdge;
lane.Body_RB_ToRightEdge = rtkTail.Body_RB_ToRightEdge;
lane.Body_RF_ToBaseLine = rtkTail.Body_RF_ToBaseLine;
lane.Body_RB_ToBaseLine = rtkTail.Body_RB_ToBaseLine;
lane.Wheel_RB_ToRightEdge = rtkTail.Wheel_RB_ToRightEdge;
lane.Wheel_RB_ToBaseLine = rtkTail.Wheel_RB_ToBaseLine;
lane.Wheel_LB_ToRightEdge = rtkTail.Wheel_LB_ToRightEdge;
lane.Wheel_LB_ToBaseLine = rtkTail.Wheel_LB_ToBaseLine;
}
std::string data = XParser::toAny(exam);
FactoryExamService->examJudgeCallbackPerformToCaller(data.c_str(), data.size());
//logdebug("perform-summary %s data=%s", target().c_str(), data.c_str());
}
void IExamCar::doExamDatagram(Package* pkg)
{
HELP_COST_TIME("");
IAutoLock(m_mtx);
switch(pkg->id)
{
case Package::id_real_exam : doExamRealExam(pkg); break;
case Package::id_hardware : break;
case Package::id_end : examJudgeEndExamFinish(); break;
default: doExamNS3(pkg); break;
}
}
void IExamCar::doExamRealExam(Package* pkg)
{
//记录轨迹文件
if(m_track)
{
m_track->write(TTrackTypeRealExam, pkg->data);
}
TChuanGan* cg = m_history->create();
if(!XParser::fromAny(pkg->data, cg->real))
{
logerror("protocol error, %s ", pkg->data.c_str());
m_history->recover(cg);
return;
}
if(!m_sensor->pretreatment(cg))
{
logerror("pretreatment failed, %s ", pkg->data.c_str());
m_history->recover(cg);
return;
}
if(m_cg != nullptr)
{
//cg->move = m_cg->move;
cg->MapPoint_Road_Code = m_cg->MapPoint_Road_Code;
}
//examNonGps(cg);
m_cg = cg;
m_history->push(cg, pkg->tm);
//如果和上一次状态不一样,要触发移动状态改变事件
TChuanGan* his = historyChuanGan(1);
if(his == nullptr || cg->move != his->move)
{
createEventMoveState(cg->move);
}
if(isReplay() && m_timeBegin == 0)
{
//为什么开始考试时间放这里呢因为回放有可能是这里才能获取到第1帧数据
//必须在这句后面 m_cg = cg;
m_timeBegin = GetCurrentTime2();
}
if(m_drawing)
{
if(examDrawMap())
{
FactoryExamService->examJudgeCallbackMapImageToCaller(m_graphic->image(), m_graphic->size());
}
}
if(isExamMode() && !isQualified())
{
//如果考试模式,扣分到不合格了,就不调用评判了
}
else
{
if(historyCount() > 1*FRAMES_PER_SECOND) //必须收满1秒数据才开始评判
{
ErrorCode errCode = examJudgeExam();
if(errCode != codeSuccess)
{
logerror("judge item error, %s", pkg->data.c_str());
}
}
examPerformSummary();
}
//... ...
}
int IExamCar::calcDistance(bool mc, int X_McH)
{
int a = 0;
if(mc && X_McH > 0)
{
if(m_history->size() <= 1)
{
return 0;
}
//(当前脉冲-前一帧脉冲) / 百米脉冲 * 10000 单位cm
double ljmc = historySensor().ljmc; //要用浮点计算,否则计算出来都是0
double ljmc1 = historySensor(1).ljmc;
a = (ljmc-ljmc1) / X_McH * 10000;
switch(m_cg->move)
{
case moveForward: m_disForward += a; break;
case moveBackward: m_disBackward += a; break;
default: break;
}
}
else
{
if(m_history->size() <= 1)
{
return 0;
}
const Pointi& h = historyGps(1).ai_gps;
const Pointi& c = historyGps().ai_gps;
if( (c.x == 0 && c.y == 0) || (h.x == 0 && h.y == 0) )
{
return 0;
}
double x = h.x - c.x;
double y = h.y - c.y;
a = std::round(std::sqrt(x*x + y*y));
switch(m_cg->move)
{
case moveForward: m_disForward += a; break;
case moveBackward: m_disBackward += a; break;
default: break;
}
}
m_cg->ai_ljjl_cm = m_disForward;
m_cg->ai_dcjl_cm = m_disBackward;
m_cg->ai_ljjl = m_disForward/100.0;
m_cg->ai_dcjl = m_disBackward/100.0;
if(m_cg->move == moveForward)
{
int gear = m_cg->real.sensor.dw; //只有科三用到
int range = ARRAY_SIZE(m_disGears);
if(gear < range)
{
m_disGears[gear] += a;
}
//else
//{
// logerror("gear=%d is out range=%d", gear, range);
//}
}
//logdebug("move=%d,dis=%dCM", state, a);
return a;
}
int64 IExamCar::GetCurrentTime2() const
{
//0多伦Net数据(CarEx3传过来的) 1:鸿蒙的日志数据 2正常的考试模式(杨海洋考试的场景这个赋值为2)
int64 result = 0;
if(!isReplay()) //if(Data_Replay.Kind = 2) //isExamMode()
{
result = Tools::nowTime();
}
else
{
//TASSERT_INT(nullptr != m_cg, "");
result = (nullptr != m_cg ? m_cg->real.gps.sj : 0);
}
return result;
}
int64 IExamCar::GetCurrentTick2() const
{
int64 result = 0;
if(!isReplay()) //if(Data_Replay.Kind = 2) //isExamMode()
{
result = Tools::nowClock();
}
else
{
//TASSERT_INT(nullptr != m_cg, "");
//if(m_timeBegin == 0) //Tds.StartTime
//{
// m_timeBegin = m_cg->real.gps.sj;
//}
result = (nullptr != m_cg ? m_cg->real.gps.sj - m_timeBegin : 0);
}
return result;
}