#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& s531 = TableSysSet->asArray531(); bool isUseBeha = (s531.size() > 1 && s531[1] == "1"); const std::vector& 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& 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; }