// // Created by YY on 2020/3/17. // #include "road_exam.h" #include "../driver_test.h" #include "../utils/xconvert.h" #include "../common/apptimer.h" #include "../jni_log.h" #include "../defs.h" #include "../test_common/car_sensor.h" #include "../native-lib.h" #include "through_something.h" #include "../master/comm_if.h" #include "drive_straight.h" #include "stop_car.h" #include "operate_gear.h" #include #include #include #include #include #define DEBUG(fmt, args...) LOGD(" <%s>: " fmt, __func__, ##args) using namespace std; #define TURN_CHECK_CNT 6 enum { START_CAR_NOT_DO, START_CAR_DOING, START_CAR_DONE }; enum { STOP_CAR_NOT_DO, STOP_CAR_DOING, STOP_CAR_DONE }; static const int INVALID_ROAD = -1; static const int TURN_THRESHOLD = 1; static const int TURN_CHECK_INTERVAL = 500; const double SLIDE_DISTANCE_THRESHOLD_RED = 0.3; const double SLIDE_DISTANCE_THRESHOLD_YELLOW = 0.1; const double CHANGE_LANE_RANGE = 100.0; const double OVERTAKE_RANGE = 150.0; const int OVERTAKE_HOLD_TIME = D_SEC(3); // 在超车道行驶的一段时间 const double EXAM_RANGE = 3000.0; // 至少驾驶距离 static const double LASTEST_BREAK_POINT = 30.0; static const double NEXT_ROAD_TIP = 100.0; // 到达路口前提示下一个怎么走 static const double DISTANCE_STOP_CAR_TO_STOP_LINE = 5.0; static const double PASS_SCHOOL_MAX_SPEED = 30.0; // kmh static const int FIND_POSITION = -2; static const int INVALID_POSITION = -1; static bool occurCrashRedLine; static bool occurCrashGreenLine; static bool occurOverSpeed; static bool occurSecondBreak; static int checkCrashGreenTimeout; static char carIntersectionOfGreenLine; static int currTurnSignalStatus; static int turnSignalStatusWhenCrashGreenLine; static bool reportTurnSignalError; static int prevMoveDirect; static uint32_t stopTimepoint = 0; static bool reportStopCarOnRedArea; static PointF stopPoint, startPoint; static bool prevGearError = false; static bool prevGearNSlide = false; static bool slideLongDistance; static bool slideNormalDistance; static bool occurSlide; static bool startCarLeftTurnSignal, checkStartCarSignal; static struct drive_timer crashGreenRunTime, crashGreenCmpTime, crashGreenStartTime, turnSignalChangeTime; static struct drive_timer gearErrorTimePoint; static struct drive_timer gearNSlideTimePoint; static struct drive_timer startCarLeftTurnSignalTime; static struct drive_timer overTakeCmpTime; static int gearErrorTime; static int gearNSlideTime; static int startCar, stopCar; static int currExamMapIndex; static trigger_line_t *currRoadItem; static int nextRoadId; static PointF roadItemStartPoint; static struct drive_timer roadItemStartTime; static bool overtake = false; static bool checkTurn = false; static bool checkDoor = false; static bool handBreakActive = false; static bool reportRPMOver = false; static const uint32_t TURN_ERROR_COLD_TIME = D_SEC(10); static bool turnError13Cold, turnError14Cold; static struct car_on_lane { int road; int separate; int lane; int direct; // 车道方向限制 int type; // 实线,虚线 } CurrentLane; static bool laneChanging; static int changeLaneDirect; static double odoGraph; static struct drive_timer odoTimer; static double odoPrevSpeed; static int odoCnt; typedef struct { int road; int sep; int lane; } lane_t; typedef struct { int edgeIndex; int pointIndex; PointF point; } projection_t; static const int MAX_ENGINE_RPM = 2500; static const double START_CAR_MOVE_DISTANCE = 10.0; static const double START_CAR_CHECK_DOOR_DISTANCE = 1.0; static const uint32_t GEAR_N_SLIDE_TIMEOUT = D_SEC(5); static const uint32_t GEAR_ERROR_TIMEOUT = D_SEC(15); static const uint32_t STOP_CAR_TIME = D_SEC(2); static const uint32_t CHANGE_LANE_MIN_INTERVAL = D_SEC(10); static const uint32_t CRASH_DOTTED_LINE_TIMEOUT = D_SEC(10); static const uint32_t TURN_SIGNAL_LAMP_ADVANCE = D_SEC(3); static const int CRL_NONE = 0; static const int CRL_SEP_DOTTED = 1; static const int CRL_SEP_SOLID = 2; static const int CRL_EDGE_DOTTED = 3; static const int CRL_EDGE_SOLID = 4; static const double MAX_SPEED = 40.0 * 1000.0 / 3600.0; static const int SPEED_GEAR_TABLE[][2] = {{0, 20}, {5, 30}, {15, 40}, {25, 10000}, {35, 10000}}; static int TestRoadStartCar(const car_model *car, double speed, int moveDirect, const struct RtkTime *rtkTime); static char isTurn(int currYaw, int prevYaw, int &ang); static char CheckCarTurn(LIST_CAR_MODEL &CarModelList); static void TurnSignalError13ColdTimer(union sigval sig); static void TurnSignalError14ColdTimer(union sigval sig); static void ReportTurnSignalError(int err, const struct RtkTime *rtkTime); static bool UpdateLane(struct car_on_lane &out, road_t &road, const car_model *car); static int CrashRoadLine(road_t &road, const car_model *car); static bool LaneIsSame(struct car_on_lane lane1, struct car_on_lane lane2); static bool LaneIsValid(struct car_on_lane lane); static void ArrivedRoadEnd(road_t &road, const car_model *car, LIST_CAR_MODEL &CarModelList); static trigger_line_t * EntryItem(int index, road_exam_map &RoadMap, const car_model *car, LIST_CAR_MODEL &CarModelList); static void ClearAll(road_exam_map &map); static bool AllCmp(road_exam_map &map); static void CheckBreakActive(road_exam_map &map, const car_model *car, LIST_CAR_MODEL &CarModelList, double speed, int moveDirect, const struct RtkTime *rtkTime); static PointF CalcProjectionWithRoadEdge(vector &edge, PointF point); static int CalcRoadIndex(int currRoadIndex, road_exam_map &RoadMap, const car_model *car); void InitRoadExam(road_exam_map &RoadMap) { DEBUG("Start road_exam"); crashGreenCmpTime.hour = -1; occurCrashRedLine = false; occurCrashGreenLine = false; occurOverSpeed = false; occurSecondBreak = false; checkCrashGreenTimeout = 0; carIntersectionOfGreenLine = 0; reportTurnSignalError = false; currTurnSignalStatus = OFF_LIGHT; prevMoveDirect = 0; reportStopCarOnRedArea = false; occurSlide = false; slideLongDistance = false; slideNormalDistance = false; prevGearError = false; gearErrorTime = 0; prevGearNSlide = false; gearNSlideTime = 0; currExamMapIndex = FIND_POSITION; startCar = START_CAR_NOT_DO; stopCar = STOP_CAR_NOT_DO; currRoadItem = NULL; checkDoor = false; handBreakActive = false; reportRPMOver = false; checkStartCarSignal = startCarLeftTurnSignal = false; turnError13Cold = turnError14Cold = true; CurrentLane.road = CurrentLane.separate = CurrentLane.lane = -1; laneChanging = false; changeLaneDirect = 0; nextRoadId = -1; checkTurn = false; ClearAll(RoadMap); odoGraph = 0.0; odoCnt = 0; // 初始化考项 } void TerminateRoadExam(void) { TerminateDummyLightExam(); TerminateStopCarExam(); TerminateOperateGearExam(); TerminateDriveStraightExam(); AppTimer_delete(TurnSignalError13ColdTimer); AppTimer_delete(TurnSignalError14ColdTimer); } /********************************************************************* * 计算某点到道路边线的投影点 * @param edge * @param road * @param point * @return */ static PointF CalcProjectionWithRoadEdge(vector &edge, PointF point) { PointF p1, p2; PointF proj; vector projArray; Line line; // 计算垂点 for (int i = 0; i < edge.size(); ++i) { p1 = edge[i].points[0]; for (int j = 1; j < edge[i].points.size(); ++j) { p2 = edge[i].points[j]; MakeLine(&line, &p1, &p2); PointF vp; if (VerticalPointOnLine(point, line, vp)) { projArray.push_back(vp); } p1 = p2; } } if (projArray.size() == 0) { // 没有任何垂点,找到最近的点 proj = edge[0].points[0]; for (int i = 0; i < edge.size(); ++i) { for (int j = 1; j < edge[i].points.size(); ++j) { if (DistanceOf(point, edge[i].points[j]) < DistanceOf(point, proj)) { proj = edge[i].points[j]; } } } } else { // 最近的垂点 proj = projArray[0]; for (int i = 1; i < projArray.size(); ++i) { if (DistanceOf(point, projArray[i]) < DistanceOf(point, proj)) { proj = projArray[i]; } } } return proj; } static projection_t CalcProjectionWithRoadEdgeEx(vector &edge, PointF point) { PointF p1, p2; Line line; projection_t theProj; vector projSet; // 计算垂点 for (int i = 0; i < edge.size(); ++i) { p1 = edge[i].points[0]; for (int j = 1; j < edge[i].points.size(); ++j) { p2 = edge[i].points[j]; MakeLine(&line, &p1, &p2); PointF vp; if (VerticalPointOnLine(point, line, vp)) { projection_t proj; proj.edgeIndex = i; proj.pointIndex = j - 1; proj.point = vp; projSet.push_back(proj); } p1 = p2; } } if (projSet.size() == 0) { // 没有任何垂点,找到最近的点 theProj.edgeIndex = 0; theProj.pointIndex = 0; theProj.point = edge[0].points[0]; for (int i = 0; i < edge.size(); ++i) { for (int j = 1; j < edge[i].points.size(); ++j) { if (DistanceOf(point, edge[i].points[j]) < DistanceOf(point, theProj.point)) { theProj.edgeIndex = i; theProj.pointIndex = j - 1; theProj.point = edge[i].points[j]; } } } } else { // 最近的垂点 theProj = projSet[0]; for (int i = 1; i < projSet.size(); ++i) { if (DistanceOf(point, projSet[i].point) < DistanceOf(point, theProj.point)) { theProj = projSet[i]; } } } return theProj; } static double CalcDistanceReference(PointF point, PointF refPoint, vector &edge) { double distance = 0; projection_t projection, refProjection; projection = CalcProjectionWithRoadEdgeEx(edge, point); refProjection = CalcProjectionWithRoadEdgeEx(edge, refPoint); if (projection.edgeIndex != refProjection.edgeIndex || projection.pointIndex != refProjection.pointIndex) { bool ahead = false; if (projection.edgeIndex != refProjection.edgeIndex) { if (projection.edgeIndex > refProjection.edgeIndex) { projection_t temp; temp = projection; projection = refProjection; refProjection = temp; ahead = true; } int a = projection.edgeIndex; int b = projection.pointIndex + 1; if (b < edge[a].points.size()) { distance += DistanceOf(projection.point, edge[projection.edgeIndex].points[b]); } for (; a < refProjection.edgeIndex; ++a) { for (; b < edge[a].points.size() - 1; ++b) { distance += DistanceOf(edge[a].points[b], edge[a].points[b+1]); } b = 0; } for (int i = 0; i < refProjection.pointIndex; i++) { distance += DistanceOf(edge[a].points[i], edge[a].points[i+1]); } distance += DistanceOf(refProjection.point, edge[refProjection.edgeIndex].points[refProjection.pointIndex]); } else { if (projection.pointIndex > refProjection.pointIndex) { projection_t temp; temp = projection; projection = refProjection; refProjection = temp; ahead = true; } int a = projection.edgeIndex; int b = projection.pointIndex + 1; if (b < edge[a].points.size()) { distance += DistanceOf(projection.point, edge[projection.edgeIndex].points[b]); } for (; b < refProjection.pointIndex; b++) { distance += DistanceOf(edge[a].points[b], edge[a].points[b+1]); } distance += DistanceOf(refProjection.point, edge[refProjection.edgeIndex].points[refProjection.pointIndex]); } if (ahead) { distance *= -1.0; } } else { distance = DistanceOf(projection.point, refProjection.point); if (DistanceOf(projection.point, edge[projection.edgeIndex].points[projection.pointIndex]) > DistanceOf(refProjection.point, edge[refProjection.edgeIndex].points[refProjection.pointIndex])) { distance *= -1.0; } } return distance; } /*************************************************************** * 车辆所在道路,根据车辆的中轴前点 * @param currRoadIndex * @param RoadMap * @param car * @return */ static int CalcRoadIndex(int currRoadIndex, road_exam_map &RoadMap, const car_model *car) { int n = 0; int index = currRoadIndex; if (index < 0) { index = 0; } while (n++ < RoadMap.roads.size()) { bool changeSegment = false; vector roadOutLine; Polygon area; for (int i = 0; i < RoadMap.roads[index].leftEdge.size(); ++i) { for (int j = 0; j < RoadMap.roads[index].leftEdge[i].points.size(); ++j) { if (changeSegment && roadOutLine.size() > 0 && IsSamePoint(roadOutLine.back(), RoadMap.roads[index].leftEdge[i].points[j])) { continue; } changeSegment = false; roadOutLine.push_back(RoadMap.roads[index].leftEdge[i].points[j]); } changeSegment = true; } for (int i = 0; i < RoadMap.roads[index].rightEdge.size(); ++i) { for (int j = RoadMap.roads[index].rightEdge[i].points.size() - 1; j >= 0; --j) { if (changeSegment && roadOutLine.size() > 0 && IsSamePoint(roadOutLine.back(), RoadMap.roads[index].leftEdge[i].points[j])) { continue; } changeSegment = false; roadOutLine.push_back(RoadMap.roads[index].rightEdge[i].points[j]); } changeSegment = true; } area.num = roadOutLine.size(); area.point = (PointF *) malloc(area.num * sizeof(PointF)); for (int i = 0; i < area.num; ++i) { area.point[i] = roadOutLine[i]; } if (IntersectionOf(car->carXY[car->axial[AXIAL_FRONT]], &area) == GM_Containment) { free(area.point); break; } free(area.point); index = (index + 1) % RoadMap.roads.size(); } if (n >= RoadMap.roads.size()) { index = -1; } return index; } /************************************************ * 车轮压实线,前后轴交叉,前后轮迹交叉 * @param mode * @param RoadMap * @param car * @param CarModelList * @return */ static bool CrashRedLine(int mode, int roadIndex, road_exam_map &RoadMap, const car_model *car, LIST_CAR_MODEL &CarModelList) { Line frontTireAxle, rearTireAxle; Line frontLeftTireTrack, frontRightTireTrack; Line rearLeftTireTrack, rearRightTireTrack; bool track = false; MakeLine(&frontTireAxle, &car->carXY[car->left_front_tire[TIRE_OUTSIDE]], &car->carXY[car->right_front_tire[TIRE_OUTSIDE]]); MakeLine(&rearTireAxle, &car->carXY[car->left_rear_tire[TIRE_OUTSIDE]], &car->carXY[car->right_rear_tire[TIRE_OUTSIDE]]); if (CarModelList.size() >= 2) { list::iterator iter = CarModelList.begin(); PointF p11, p12, p21, p22, p31, p32, p41, p42; p11 = ((car_model *)(*iter))->carXY[((car_model *)(*iter))->left_front_tire[TIRE_OUTSIDE]]; p21 = ((car_model *)(*iter))->carXY[((car_model *)(*iter))->right_front_tire[TIRE_OUTSIDE]]; p31 = ((car_model *)(*iter))->carXY[((car_model *)(*iter))->left_rear_tire[TIRE_OUTSIDE]]; p41 = ((car_model *)(*iter))->carXY[((car_model *)(*iter))->right_rear_tire[TIRE_OUTSIDE]]; struct RtkTime time1 = ((car_model *)(*iter))->tm; ++iter; p12 = ((car_model *)(*iter))->carXY[((car_model *)(*iter))->left_front_tire[TIRE_OUTSIDE]]; p22 = ((car_model *)(*iter))->carXY[((car_model *)(*iter))->right_front_tire[TIRE_OUTSIDE]]; p32 = ((car_model *)(*iter))->carXY[((car_model *)(*iter))->left_rear_tire[TIRE_OUTSIDE]]; p42 = ((car_model *)(*iter))->carXY[((car_model *)(*iter))->right_rear_tire[TIRE_OUTSIDE]]; struct RtkTime time2 = ((car_model *)(*iter))->tm; if (TimeGetDiff(time1.hh, time1.mm, time1.ss, time1.mss, time2.hh, time2.mm, time2.ss, time2.mss) <= D_SEC(1)) { MakeLine(&frontLeftTireTrack, &p11, &p12); MakeLine(&frontRightTireTrack, &p21, &p22); MakeLine(&rearLeftTireTrack, &p31, &p32); MakeLine(&rearRightTireTrack, &p41, &p42); track = true; } } PointF p1, p2; Line redLine; for (int n = 0; n < RoadMap.roads.size(); ++n) { for (int m = 0; m < RoadMap.roads[n].leftEdge.size(); ++m) { if (RoadMap.roads[n].leftEdge[m].character == LINE_SOLID && RoadMap.roads[n].leftEdge[m].points.size() >= 2) { p1 = RoadMap.roads[n].leftEdge[m].points[0]; for (int l = 1; l < RoadMap.roads[n].leftEdge[m].points.size(); ++l) { p2 = RoadMap.roads[n].leftEdge[m].points[l]; MakeLine(&redLine, &p1, &p2); if (IntersectionOf(redLine, frontTireAxle) == GM_Intersection || IntersectionOf(redLine, rearTireAxle) == GM_Intersection) { return true; } if (track && (IntersectionOf(redLine, frontLeftTireTrack) == GM_Intersection || IntersectionOf(redLine, frontRightTireTrack) == GM_Intersection || IntersectionOf(redLine, rearLeftTireTrack) == GM_Intersection || IntersectionOf(redLine, rearRightTireTrack) == GM_Intersection)) { return true; } p1 = p2; } } } for (int m = 0; m < RoadMap.roads[n].rightEdge.size(); ++m) { if (RoadMap.roads[n].rightEdge[m].character == LINE_SOLID && RoadMap.roads[n].rightEdge[m].points.size() >= 2) { p1 = RoadMap.roads[n].rightEdge[m].points[0]; for (int l = 1; l < RoadMap.roads[n].rightEdge[m].points.size(); ++l) { p2 = RoadMap.roads[n].rightEdge[m].points[l]; MakeLine(&redLine, &p1, &p2); if (IntersectionOf(redLine, frontTireAxle) == GM_Intersection || IntersectionOf(redLine, rearTireAxle) == GM_Intersection) { return true; } if (track && (IntersectionOf(redLine, frontLeftTireTrack) == GM_Intersection || IntersectionOf(redLine, frontRightTireTrack) == GM_Intersection || IntersectionOf(redLine, rearLeftTireTrack) == GM_Intersection || IntersectionOf(redLine, rearRightTireTrack) == GM_Intersection)) { return true; } p1 = p2; } } } for (int m = 0; m < RoadMap.roads[n].separate.size(); ++m) { // 一组车道 for (int l = 0; l < RoadMap.roads[n].separate[m].lines.size(); ++l) { // 多根分道线 for (int a = 0; a < RoadMap.roads[n].separate[m].lines[l].size(); ++a) { // 一根分道线中线型相同的 int character = RoadMap.roads[n].separate[m].lines[l][a].character; if (character == LINE_SOLID && RoadMap.roads[n].separate[m].lines[l][a].points.size() >= 2) { p1 = RoadMap.roads[n].separate[m].lines[l][a].points[0]; for (int b = 1; b < RoadMap.roads[n].separate[m].lines[l][a].points.size(); ++b) { p2 = RoadMap.roads[n].separate[m].lines[l][a].points[b]; MakeLine(&redLine, &p1, &p2); if (IntersectionOf(redLine, frontTireAxle) == GM_Intersection || IntersectionOf(redLine, rearTireAxle) == GM_Intersection) { return true; } if (track && (IntersectionOf(redLine, frontLeftTireTrack) == GM_Intersection || IntersectionOf(redLine, frontRightTireTrack) == GM_Intersection || IntersectionOf(redLine, rearLeftTireTrack) == GM_Intersection || IntersectionOf(redLine, rearRightTireTrack) == GM_Intersection)) { return true; } p1 = p2; } } // 比较最近的连续的n个左侧点和上一个右侧点 if (character == LINE_HALF_SOLID_LEFT) { // 不能从左移动到右 } } } } } return false; } /******************************************** * 计算某点在哪个车道 * @param point * @param RoadMap * @param roadIndex * @return */ static bool GetLane(lane_t &theLane, PointF point, road_exam_map &RoadMap, int roadIndex) { Line leftProjLine, rightProjLine; Line sep; PointF p1, p2; if (roadIndex < 0 || roadIndex >= RoadMap.roads.size()) return false; p1 = CalcProjectionWithRoadEdge(RoadMap.roads[roadIndex].leftEdge, point); p2 = CalcProjectionWithRoadEdge(RoadMap.roads[roadIndex].rightEdge, point); MakeLine(&leftProjLine, &point, &p1); MakeLine(&rightProjLine, &point, &p2); for (int i = 0; i < RoadMap.roads[roadIndex].separate.size(); ++i) { struct car_lane_pos { int lane_no; char pos; // 点在车道的左右位置 bool operator == (const int &x) { return(this->lane_no == x); } }; vector CLP; bool oneMoreIntersection = false; for (int j = 0; j < RoadMap.roads[roadIndex].separate[i].lines.size(); ++j) { // 每一根线分组 bool intersection = false; for (int k = 0; !intersection && k < RoadMap.roads[roadIndex].separate[i].lines[j].size(); ++k) { // 同一线型的线分组 p1 = RoadMap.roads[roadIndex].separate[i].lines[j][k].points[0]; for (int m = 1; m < RoadMap.roads[roadIndex].separate[i].lines[j][k].points.size(); ++m) { p2 = RoadMap.roads[roadIndex].separate[i].lines[j][k].points[m]; MakeLine(&sep, &p1, &p2); if (IntersectionOf(sep, leftProjLine) == GM_Intersection) { intersection = true; struct car_lane_pos temp; temp.lane_no = j; temp.pos = 'R'; CLP.push_back(temp); break; } if (IntersectionOf(sep, rightProjLine) == GM_Intersection) { intersection = true; struct car_lane_pos temp; temp.lane_no = j; temp.pos = 'L'; CLP.push_back(temp); break; } p1 = p2; } } if (!intersection) { struct car_lane_pos temp; temp.lane_no = j; temp.pos = 0; CLP.push_back(temp); } else { oneMoreIntersection = true; } } if (oneMoreIntersection) { // 考虑到采集偏差可能每一根线无法对齐,只要其中一根相交,其它不相交的也参与 for (vector::iterator it = CLP.begin(); it != CLP.end(); ++it) { if ((*it).pos == 0) { int m = RoadMap.roads[roadIndex].separate[i].lines[(*it).lane_no].size(); int n = RoadMap.roads[roadIndex].separate[i].lines[(*it).lane_no][m-1].points.size(); if (DistanceOf(RoadMap.roads[roadIndex].separate[i].lines[(*it).lane_no][0].points[0], point) > DistanceOf(RoadMap.roads[roadIndex].separate[i].lines[(*it).lane_no][m-1].points[n-1], point)) { // 车辆接近车道尾部 MakeLine(&sep, &RoadMap.roads[roadIndex].separate[i].lines[(*it).lane_no][m-1].points[n-2], &RoadMap.roads[roadIndex].separate[i].lines[(*it).lane_no][m-1].points[n-1]); } else { // 车辆接近车道头部 MakeLine(&sep, &RoadMap.roads[roadIndex].separate[i].lines[(*it).lane_no][0].points[0], &RoadMap.roads[roadIndex].separate[i].lines[(*it).lane_no][0].points[1]); } struct car_lane_pos temp; temp.lane_no = (*it).lane_no; if (IntersectionOfLine(point, sep) == -1) { temp.pos = 'R'; } else { temp.pos = 'L'; } (*it) = temp; } } theLane.road = roadIndex; theLane.sep = i; theLane.lane = CLP.size(); for (int x = 0; x < CLP.size(); ++x) { if (CLP[x].pos == 'L') { theLane.lane = x; break; } } return true; } } return false; } static void TurnSignalError13ColdTimer(union sigval sig) { AppTimer_delete(TurnSignalError13ColdTimer); turnError13Cold = true; } static void TurnSignalError14ColdTimer(union sigval sig) { AppTimer_delete(TurnSignalError14ColdTimer); turnError14Cold = true; } static void ReportTurnSignalError(int err, const struct RtkTime *rtkTime) { if (err == 13 && turnError13Cold) { DEBUG("起步不开转向灯"); AddExamFault(13, rtkTime); turnError13Cold = false; AppTimer_delete(TurnSignalError13ColdTimer); AppTimer_add(TurnSignalError13ColdTimer, TURN_ERROR_COLD_TIME); } else if (err == 14 && turnError14Cold) { DEBUG("起步转向灯不足3秒"); AddExamFault(14, rtkTime); turnError14Cold = false; AppTimer_delete(TurnSignalError14ColdTimer); AppTimer_add(TurnSignalError14ColdTimer, TURN_ERROR_COLD_TIME); } } static int TestRoadStartCar(const car_model *car, double speed, int moveDirect, const struct RtkTime *rtkTime) { double moveDistance; if (startCar == START_CAR_NOT_DO) { startPoint = car->basePoint; reportRPMOver = false; startCar = START_CAR_DOING; PlayTTS("请起步"); } else if (startCar == START_CAR_DOING) { moveDistance = DistanceOf(startPoint, car->basePoint); DEBUG("起步行驶距离 %f", moveDistance); if (!startCarLeftTurnSignal && ReadCarStatus(TURN_SIGNAL_LAMP) == LEFT_TURN_LIGHT) { startCarLeftTurnSignal = true; Rtk2DriveTimer(startCarLeftTurnSignalTime, rtkTime); } if (!checkStartCarSignal && moveDirect == 1) { checkStartCarSignal = true; if (!startCarLeftTurnSignal) { ReportTurnSignalError(13, rtkTime); } else if (TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss*10, startCarLeftTurnSignalTime.hour, startCarLeftTurnSignalTime.min, startCarLeftTurnSignalTime.sec, startCarLeftTurnSignalTime.msec*10) < TURN_SIGNAL_LAMP_ADVANCE) { ReportTurnSignalError(14, rtkTime); } } if (moveDistance > START_CAR_MOVE_DISTANCE) { if (ReadCarStatus(HAND_BREAK) == BREAK_ACTIVE) { DEBUG("Handbreak active move over 10m"); // 手刹拉起状态下,行驶了10米以上,不合格 AddExamFault(25, rtkTime); } else if (handBreakActive) { // 手刹拉起状态下,行驶了1米以上,扣10分 DEBUG("Handbreak active move over 1M"); AddExamFault(26, rtkTime); } PlayTTS("完成起步"); DEBUG("############# 完成起步 ############"); startCar = START_CAR_DONE; } else if (moveDistance >= START_CAR_CHECK_DOOR_DISTANCE) { if (!checkDoor) { checkDoor = true; if (ReadCarStatus(DOOR) == DOOR_OPEN) { // 车门未完全关闭,不合格 DEBUG("车门未关闭"); AddExamFault(23, rtkTime); } if (ReadCarStatus(HAND_BREAK) == BREAK_ACTIVE) { handBreakActive = true; } } } if (ReadCarStatus(ENGINE_RPM) > MAX_ENGINE_RPM && !reportRPMOver) { // 转速超标,不合格 DEBUG("转速超标"); AddExamFault(29, rtkTime); reportRPMOver = true; } } else { } return startCar; } void TestRoadGeneral(road_exam_map &RoadMap, const car_model *car, LIST_CAR_MODEL &CarModelList, double speed, int moveDirect, const struct RtkTime *rtkTime) { uint32_t cts = AppTimer_GetTickCount(); int ri = CalcRoadIndex(-1, RoadMap, car); bool crash = CrashRedLine(0, RoadMap, car, CarModelList); lane_t laneInfo; double redist = -1; laneInfo.road = -1; laneInfo.sep = -1; laneInfo.lane = -1; if (ri >= 0) { GetLane(laneInfo, car->carXY[car->axial[AXIAL_FRONT]], RoadMap, ri); int m = RoadMap.roads[ri].rightEdge.size(); int n = RoadMap.roads[ri].rightEdge[m-1].points.size(); PointF base; base.X = 428922.2985; base.Y = 3292119.5457; redist = CalcDistanceReference(car->carXY[car->axial[AXIAL_FRONT]], base, RoadMap.roads[ri].rightEdge); } DEBUG("当前道路索引 %d, 触发红线 %d lane %d 距离 %f %ld", ri, crash, laneInfo.lane, redist, AppTimer_GetTickCount() - cts); // 行驶距离,不包含倒车 if (odoCnt == 0 && moveDirect == 1) { odoPrevSpeed = speed; odoCnt = 1; Rtk2DriveTimer(odoTimer, rtkTime); } else if (odoCnt == 1) { uint32_t tm = TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss*10, odoTimer.hour, odoTimer.min, odoTimer.sec, odoTimer.msec*10); if (tm >= D_SEC(1)) { odoGraph += ((double)tm)*(odoPrevSpeed + speed)/2.0/1000.0; if (moveDirect == 1) { Rtk2DriveTimer(odoTimer, rtkTime); odoPrevSpeed = speed; } else { odoCnt = 0; } } } // 超速检测 if (moveDirect != 0 && speed > MAX_SPEED) { if (!occurOverSpeed) { occurOverSpeed = true; // 超速,不合格 DEBUG("超速 %f", speed); AddExamFault(10, rtkTime); } } else { occurOverSpeed = false; } // 副刹车检测 if (ReadCarStatus(SECOND_BREAK) == BREAK_ACTIVE) { // 副刹车踩下,不合格 if (!occurSecondBreak) { DEBUG("副刹车动作了"); occurSecondBreak = true; AddExamFault(17, rtkTime); } } else { occurSecondBreak = false; } // 挡位匹配检测 bool currGearError = false; bool currGearNSlide = false; switch (ReadCarStatus(GEAR)) { case GEAR_N: if (moveDirect != 0) { // 空档滑行 currGearNSlide = true; } break; case GEAR_1: if (ConvertMs2KMh(speed) < SPEED_GEAR_TABLE[0][0] || ConvertMs2KMh(speed) > SPEED_GEAR_TABLE[0][1]) { currGearError = true; } break; case GEAR_2: if (ConvertMs2KMh(speed) < SPEED_GEAR_TABLE[1][0] || ConvertMs2KMh(speed) > SPEED_GEAR_TABLE[1][1]) { currGearError = true; } break; case GEAR_3: if (ConvertMs2KMh(speed) < SPEED_GEAR_TABLE[2][0] || ConvertMs2KMh(speed) > SPEED_GEAR_TABLE[2][1]) { currGearError = true; } break; case GEAR_4: if (ConvertMs2KMh(speed) < SPEED_GEAR_TABLE[3][0] || ConvertMs2KMh(speed) > SPEED_GEAR_TABLE[3][1]) { currGearError = true; } break; case GEAR_5: if (ConvertMs2KMh(speed) < SPEED_GEAR_TABLE[4][0] || ConvertMs2KMh(speed) > SPEED_GEAR_TABLE[4][1]) { currGearError = true; } break; default:break; } // 空档滑行超时 if (currGearNSlide && prevGearNSlide) { gearNSlideTime += TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss*10, gearNSlideTimePoint.hour, gearNSlideTimePoint.min, gearNSlideTimePoint.sec, gearNSlideTimePoint.msec*10); } if (gearNSlideTime > GEAR_N_SLIDE_TIMEOUT) { // 空档滑行超5秒,不合格 DEBUG("挡位滑行,超过5秒"); AddExamFault(8, rtkTime); gearNSlideTime = 0; } prevGearNSlide = currGearNSlide; if (prevGearNSlide) { Rtk2DriveTimer(gearNSlideTimePoint, rtkTime); } else { gearNSlideTime = 0; } // 挡位不匹配超时 if (currGearError && prevGearError) { gearErrorTime += TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss*10, gearErrorTimePoint.hour, gearErrorTimePoint.min, gearErrorTimePoint.sec, gearErrorTimePoint.msec*10); } if (gearErrorTime > GEAR_ERROR_TIMEOUT) { // 累计15秒,挡位-车速不匹配,不合格 DEBUG("挡位错误超过15秒"); AddExamFault(6, rtkTime); gearErrorTime = 0; } prevGearError = currGearError; if (prevGearError) { Rtk2DriveTimer(gearErrorTimePoint, rtkTime); } // 起步后滑 if (moveDirect != prevMoveDirect) { if (moveDirect == 0) { stopTimepoint = TimeMakeComposite(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss*10); reportStopCarOnRedArea = false; DEBUG("停车了 %d %d %d %d %d %d %d", rtkTime->YY, rtkTime->MM, rtkTime->DD, rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss); if (slideNormalDistance) { // 后滑,扣10分 AddExamFault(18, rtkTime); DEBUG("后滑超过10厘米, 但不超过30厘米"); } slideNormalDistance = false; slideLongDistance = false; occurSlide = false; } else if (moveDirect == -1 && prevMoveDirect == 0) { DEBUG("开始后滑"); stopPoint = car->basePoint; occurSlide = true; } prevMoveDirect = moveDirect; } else if (moveDirect == 0) { // 持续停车 uint32_t tp = TimeMakeComposite(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss*10); /*if (tp - stopTimepoint >= STOP_CAR_TIME && !reportStopCarOnRedArea && CrashRedArea(RoadMapList, car)) { // 停车超2秒,停在红区,不合格 AddExamFault(16, rtkTime); DEBUG("禁停区停车"); reportStopCarOnRedArea = true; }*/ } else if (moveDirect == -1) { // 持续后滑 if (occurSlide) { double slideDistance = DistanceOf(stopPoint, car->basePoint); if (slideDistance > SLIDE_DISTANCE_THRESHOLD_YELLOW) { slideNormalDistance = true; } if (slideDistance > SLIDE_DISTANCE_THRESHOLD_RED && !slideLongDistance) { // 后滑超过30厘米, 不合格 AddExamFault(5, rtkTime); DEBUG("后滑超过30厘米"); slideLongDistance = true; slideNormalDistance = false; occurSlide = false; } } } else { // 前进 } // 转向灯读取 switch (ReadCarStatus(TURN_SIGNAL_LAMP)) { case LEFT_TURN_LIGHT: if (currTurnSignalStatus != LEFT_TURN_LIGHT) { currTurnSignalStatus = LEFT_TURN_LIGHT; Rtk2DriveTimer(turnSignalChangeTime, rtkTime); } break; case RIGHT_TURN_LIGHT: if (currTurnSignalStatus != RIGHT_TURN_LIGHT) { currTurnSignalStatus = RIGHT_TURN_LIGHT; Rtk2DriveTimer(turnSignalChangeTime, rtkTime); } break; default: currTurnSignalStatus = ReadCarStatus(TURN_SIGNAL_LAMP); break; } // 检测通过路口、人行道等区域时,释放刹车或减速 CheckBreakActive(RoadMap, car, CarModelList, speed, moveDirect, rtkTime); // 检测离开此路段,全车需不在范围内 if (currExamMapIndex >= 0) { Polygon area; int n = 0; area.num = 0; for (int j = 0; j < RoadMap.roads[currExamMapIndex].leftEdge.size(); ++j) { if (j > 0) { area.num += RoadMap.roads[currExamMapIndex].leftEdge[j].points.size() - 1; } else { area.num += RoadMap.roads[currExamMapIndex].leftEdge[j].points.size(); } } for (int j = 0; j < RoadMap.roads[currExamMapIndex].rightEdge.size(); ++j) { if (j > 0) { area.num += RoadMap.roads[currExamMapIndex].rightEdge[j].points.size() - 1; } else { area.num += RoadMap.roads[currExamMapIndex].rightEdge[j].points.size(); } } area.point = (PointF *) malloc(area.num * sizeof(PointF)); for (int j = 0; j < RoadMap.roads[currExamMapIndex].leftEdge.size(); ++j) { for (int k = (j>0?1:0); k < RoadMap.roads[currExamMapIndex].leftEdge[j].points.size(); ++k) { area.point[n++] = RoadMap.roads[currExamMapIndex].leftEdge[j].points[k]; } } for (int j = RoadMap.roads[currExamMapIndex].rightEdge.size() - 1; j >= 0; --j) { if (j == RoadMap.roads[currExamMapIndex].rightEdge.size() - 1) { for (int k = RoadMap.roads[currExamMapIndex].rightEdge[j].points.size() - 1; k >= 0; --k) { area.point[n++] = RoadMap.roads[currExamMapIndex].rightEdge[j].points[k]; } } else { for (int k = RoadMap.roads[currExamMapIndex].rightEdge[j].points.size() - 2; k >= 0; --k) { area.point[n++] = RoadMap.roads[currExamMapIndex].rightEdge[j].points[k]; } } } // 全车都需不在地图中 Polygon carBody; carBody.num = car->bodyNum; carBody.point = (PointF *)malloc(carBody.num * sizeof(PointF)); for (int i = 0; i < carBody.num; ++i) { carBody.point[i] = car->carXY[car->body[i]]; } if (IntersectionOf(&carBody, &area) == GM_None) { DEBUG("离开路段 id = %d", RoadMap.roads[currExamMapIndex].id); RoadMap.roads[currExamMapIndex].arrivedTail = false; currExamMapIndex = FIND_POSITION; } free(carBody.point); free(area.point); } if (currExamMapIndex == FIND_POSITION) { DEBUG("搜索道路"); for (int i = 0; i < RoadMap.roads.size(); ++i) { Polygon area; int n = 0; area.num = 0; for (int j = 0; j < RoadMap.roads[i].leftEdge.size(); ++j) { if (j > 0) { area.num += RoadMap.roads[i].leftEdge[j].points.size() - 1; } else { area.num += RoadMap.roads[i].leftEdge[j].points.size(); } } for (int j = 0; j < RoadMap.roads[i].rightEdge.size(); ++j) { if (j > 0) { area.num += RoadMap.roads[i].rightEdge[j].points.size() - 1; } else { area.num += RoadMap.roads[i].rightEdge[j].points.size(); } } area.point = (PointF *) malloc(area.num * sizeof(PointF)); for (int j = 0; j < RoadMap.roads[i].leftEdge.size(); ++j) { for (int k = (j>0?1:0); k < RoadMap.roads[i].leftEdge[j].points.size(); ++k) { area.point[n++] = RoadMap.roads[i].leftEdge[j].points[k]; } } for (int j = RoadMap.roads[i].rightEdge.size() - 1; j >= 0; --j) { if (j == RoadMap.roads[i].rightEdge.size() - 1) { for (int k = RoadMap.roads[i].rightEdge[j].points.size() - 1; k >= 0; --k) { area.point[n++] = RoadMap.roads[i].rightEdge[j].points[k]; } } else { for (int k = RoadMap.roads[i].rightEdge[j].points.size() - 2; k >= 0; --k) { area.point[n++] = RoadMap.roads[i].rightEdge[j].points[k]; } } } if (IntersectionOf(car->carXY[car->axial[AXIAL_FRONT]], &area) == GM_Containment) { currExamMapIndex = i; DEBUG("进入道路 id = %d", RoadMap.roads[i].id); if (nextRoadId >= 0 && RoadMap.roads[i].id != nextRoadId) { DEBUG("不按规矩行驶,进入错误路段"); AddExamFault(3, rtkTime); } nextRoadId = -1; checkTurn = false; break; } free(area.point); } if (currExamMapIndex < 0) { currExamMapIndex = FIND_POSITION;//INVALID_POSITION; DEBUG("搜寻未果"); } } else if (currExamMapIndex == INVALID_POSITION) { for (int i = 0; i < RoadMap.roads.size(); ++i) { if (CrashTheLine(RoadMap.roads[i].startLine, car, CarModelList)) { currExamMapIndex = i; DEBUG("进入道路 id = %d", RoadMap.roads[i].id); break; } } } // 检测压线状态 bool crashRedLineNow = false; bool crashGreenLineNow = false; if (currExamMapIndex >= 0) { int crl = CrashRoadLine(RoadMap.roads[currExamMapIndex], car); if (crl == CRL_NONE) { // DEBUG("什么都没压"); } else if (crl == CRL_SEP_DOTTED) { DEBUG("压分道虚线"); crashGreenLineNow = true; } else if (crl == CRL_SEP_SOLID) { DEBUG("压分道实线"); crashRedLineNow = true; } else if (crl == CRL_EDGE_DOTTED) { DEBUG("压边沿虚线"); crashGreenLineNow = true; } else if (crl == CRL_EDGE_SOLID) { DEBUG("压边沿实线"); crashRedLineNow = true; } // 检查当前车道 struct car_on_lane lane; if (UpdateLane(lane, RoadMap.roads[currExamMapIndex], car)) { if (lane.road == CurrentLane.road && lane.separate == CurrentLane.separate && lane.lane == CurrentLane.lane) { laneChanging = false; } if (lane.road == CurrentLane.road && lane.separate == CurrentLane.separate && lane.lane != CurrentLane.lane) { if (crl == CRL_SEP_DOTTED) { // 变道进行中 if (!laneChanging) { laneChanging = true; DEBUG("发生变道"); // 比较上次跨线时间 if (crashGreenCmpTime.hour >= 0) { uint32_t diff = TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss * 10, crashGreenCmpTime.hour, crashGreenCmpTime.min, crashGreenCmpTime.sec, crashGreenCmpTime.msec * 10); int laneDirect = 0; if (CurrentLane.lane > lane.lane) { laneDirect = -1; } else { laneDirect = 1; } if (diff < CHANGE_LANE_MIN_INTERVAL && laneDirect == changeLaneDirect) { DEBUG("===================== 连续变道 %d -> %d ============", CurrentLane.lane, lane.lane); // 连续变道,不合格 AddExamFault(15, rtkTime); } } // 检查变道前,是否提前转向灯 if (lane.lane < CurrentLane.lane) { // 向左侧变道 DEBUG("向左侧变道"); if (currTurnSignalStatus != LEFT_TURN_LIGHT) { DEBUG("变调未打灯!!"); // 没打灯,不合格 ReportTurnSignalError(13, rtkTime); } else if (TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss * 10, turnSignalChangeTime.hour, turnSignalChangeTime.min, turnSignalChangeTime.sec, turnSignalChangeTime.msec * 10) < TURN_SIGNAL_LAMP_ADVANCE) { if (!reportTurnSignalError) { DEBUG("转向灯时间不足"); // 不足3秒,不合格 reportTurnSignalError = true; ReportTurnSignalError(14, rtkTime); } } } else { // 向右侧变道 DEBUG("向右侧变道"); if (currTurnSignalStatus != RIGHT_TURN_LIGHT) { DEBUG("变调未打灯!!"); // 没打灯,不合格 ReportTurnSignalError(13, rtkTime); } else if (TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss * 10, turnSignalChangeTime.hour, turnSignalChangeTime.min, turnSignalChangeTime.sec, turnSignalChangeTime.msec * 10) < TURN_SIGNAL_LAMP_ADVANCE) { if (!reportTurnSignalError) { DEBUG("转向灯时间不足"); // 不足3秒,不合格 reportTurnSignalError = true; ReportTurnSignalError(14, rtkTime); } } } } } else { // 变道完成 DEBUG("变道完成 %d -> %d", CurrentLane.lane, lane.lane); if (currRoadItem != NULL && currRoadItem->active == ROAD_ITEM_CHANGE_LANE) { DEBUG("变更车道项目完成"); currRoadItem = NULL; PlayTTS("完成变道"); } else if (currRoadItem != NULL && currRoadItem->active == ROAD_ITEM_OVERTAKE) { if (CurrentLane.lane > lane.lane) { DEBUG("超车变道完成"); overtake = true; Rtk2DriveTimer(overTakeCmpTime, rtkTime); PlayTTS("完成超车"); } else { DEBUG("右道超车,错误"); AddExamFault(3, rtkTime); currRoadItem = NULL; } } if (CurrentLane.lane > lane.lane) { changeLaneDirect = -1; } else { changeLaneDirect = 1; } CurrentLane = lane; laneChanging = false; // 记录本次变道时间点 Rtk2DriveTimer(crashGreenCmpTime, rtkTime); } } if (lane.road != CurrentLane.road || lane.separate != CurrentLane.separate || lane.direct != CurrentLane.direct) { // 路或段变更,撤销变道跟踪 DEBUG("============== 路或段变更 CURR %d, %d dir %d NEW %d, %d, dir %d", CurrentLane.road, CurrentLane.separate, CurrentLane.direct, lane.road, lane.separate, lane.direct); CurrentLane = lane; laneChanging = false; } if (CurrentLane.direct != 0 && !(CurrentLane.direct & RoadMap.roads[currExamMapIndex].active)) { if (!RoadMap.roads[currExamMapIndex].errorLane) { RoadMap.roads[currExamMapIndex].errorLane = true; DEBUG("不按规定车道标线方向行驶 <%d> %d %d", RoadMap.roads[currExamMapIndex].id, CurrentLane.direct, RoadMap.roads[currExamMapIndex].active); AddExamFault(9, rtkTime); } } } ArrivedRoadEnd(RoadMap.roads[currExamMapIndex], car, CarModelList); if (CrashTheLine(RoadMap.roads[currExamMapIndex].stopLine, car, CarModelList)) { DEBUG("下一个目标路 id = %d", RoadMap.roads[currExamMapIndex].targetRoad); nextRoadId = RoadMap.roads[currExamMapIndex].targetRoad; checkTurn = true; } if (checkTurn) { // 检查是否持续转向 char turnDirect = CheckCarTurn(CarModelList); if (turnDirect == 'L') { // PlayTTS("左1"); if (currTurnSignalStatus != LEFT_TURN_LIGHT) { if (!reportTurnSignalError) { DEBUG("没打左转灯"); // 没打左转灯,不合格 reportTurnSignalError = true; ReportTurnSignalError(13, rtkTime); } } else if (TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss*10, turnSignalChangeTime.hour, turnSignalChangeTime.min, turnSignalChangeTime.sec, turnSignalChangeTime.msec*10) < TURN_SIGNAL_LAMP_ADVANCE) { if (!reportTurnSignalError) { DEBUG("转向灯时间不足"); // 不足3秒,不合格 reportTurnSignalError = true; ReportTurnSignalError(14, rtkTime); } } } else if (turnDirect == 'R') { // PlayTTS("右1"); if (currTurnSignalStatus != RIGHT_TURN_LIGHT) { if (!reportTurnSignalError) { DEBUG("没打右转灯"); // 没打右转灯,不合格 reportTurnSignalError = true; ReportTurnSignalError(13, rtkTime); } } else if (TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss*10, turnSignalChangeTime.hour, turnSignalChangeTime.min, turnSignalChangeTime.sec, turnSignalChangeTime.msec*10) < TURN_SIGNAL_LAMP_ADVANCE) { if (!reportTurnSignalError) { DEBUG("转向灯时间不足"); // 不足3秒,不合格 reportTurnSignalError = true; ReportTurnSignalError(14, rtkTime); } } } else { reportTurnSignalError = false; } } } // 撞红线 if (crashRedLineNow) { if (!occurCrashRedLine) { // 车辆行驶中骑轧车道中心实线或者车道边缘实线,不合格 DEBUG("撞道路边缘线"); AddExamFault(11, rtkTime); occurCrashRedLine = true; } } else { occurCrashRedLine = false; } // 压虚线 if (crashGreenLineNow) { // 压虚线 if (moveDirect != 0) { if (checkCrashGreenTimeout == 0) { checkCrashGreenTimeout = 1; Rtk2DriveTimer(crashGreenRunTime, rtkTime); // 运动中压虚线的开始时间点 } else if (checkCrashGreenTimeout == 1) { uint32_t diff = TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss*10, crashGreenRunTime.hour, crashGreenRunTime.min, crashGreenRunTime.sec, crashGreenRunTime.msec*10); if (diff >= CRASH_DOTTED_LINE_TIMEOUT) { DEBUG("长时间压虚线"); checkCrashGreenTimeout = 2; // 长时间骑轧车道分界线行驶,不合格 AddExamFault(12, rtkTime); } } } else { // 停车就不计时了 checkCrashGreenTimeout = 0; } // 检测当前车辆于虚线的位置,做变道检测; // 检测是否3秒前有开启对应之转向灯 if (!occurCrashGreenLine) { occurCrashGreenLine = true; // 记录开始压线的时间,不确定是否有变道意图,待确认变道后再处理之 Rtk2DriveTimer(crashGreenStartTime, rtkTime); turnSignalStatusWhenCrashGreenLine = currTurnSignalStatus; } } else { // 不再压虚线 occurCrashGreenLine = false; checkCrashGreenTimeout = 0; } TestRoadStartCar(car, speed, moveDirect, rtkTime); if (startCar != START_CAR_DONE) return; if (odoGraph > EXAM_RANGE && currRoadItem == NULL && AllCmp(RoadMap) && stopCar == STOP_CAR_NOT_DO) { // 在合适条件下停车结束考试 StartStopCarExam("请靠边停车"); stopCar = STOP_CAR_DOING; } else if (stopCar == STOP_CAR_DOING) { if (ExecuteStopCarExam(RoadMap.roads[currExamMapIndex], car, CarModelList, speed, moveDirect, rtkTime) < 0) stopCar = STOP_CAR_DONE; } // 执行某个项目 if (currRoadItem != NULL) { if (currRoadItem->active == ROAD_ITEM_CHANGE_LANE) { if (DistanceOf(car->basePoint, roadItemStartPoint) > CHANGE_LANE_RANGE) { DEBUG("变道距离超标"); AddExamFault(3, rtkTime); currRoadItem = NULL; } } else if (currRoadItem->active == ROAD_ITEM_OVERTAKE) { if (!overtake && DistanceOf(car->basePoint, roadItemStartPoint) > OVERTAKE_RANGE) { DEBUG("超车距离超标"); AddExamFault(3, rtkTime); currRoadItem = NULL; } else if (overtake && TimeGetDiff(rtkTime->hh, rtkTime->mm, rtkTime->ss, rtkTime->mss * 10, overTakeCmpTime.hour, overTakeCmpTime.min, overTakeCmpTime.sec, overTakeCmpTime.msec * 10) > OVERTAKE_HOLD_TIME) { DEBUG("回原车道"); PlayTTS("请返回原车道"); currRoadItem = NULL; } } else if (currRoadItem->active == ROAD_ITEM_OPERATE_GEAR) { if (ExecuteOperateGearExam(rtkTime) < 0) { currRoadItem = NULL; } } else if (currRoadItem->active == ROAD_ITEM_STRAIGHT) { if (ExecuteDriveStraightExam(RoadMap.roads[currExamMapIndex], car, currRoadItem, rtkTime) < 0) { currRoadItem = NULL; } } } // 检测由触发线控制的项目 else if (currExamMapIndex >= 0) { trigger_line_t *new_item = EntryItem(currExamMapIndex, RoadMap, car, CarModelList); if (new_item != NULL && !new_item->cmp) { currRoadItem = new_item; if (!currRoadItem->tts.empty()) PlayTTS(currRoadItem->tts.c_str()); // 初始时间和距离限制 roadItemStartPoint = car->basePoint; Rtk2DriveTimer(roadItemStartTime, rtkTime); if (currRoadItem->active == ROAD_ITEM_OVERTAKE) { overtake = false; } else if (currRoadItem->active == ROAD_ITEM_OPERATE_GEAR) { StartOperateGearExam(rtkTime); } else if (currRoadItem->active == ROAD_ITEM_STRAIGHT) { StartDriveStraightExam(currRoadItem->tts); } } } } /************************************************************* * 检测当前车道,以车头中点为基准 * @param road * @param car */ static bool UpdateLane(struct car_on_lane &out, road_t &road, const car_model *car) { bool leftExt = false, rightExt = false; Line leftExtLine, rightExtLine; struct car_on_lane lane; for (int i = 0; i < road.leftEdge.size(); ++i) { PointF p1, p2; Line edge; p1 = road.leftEdge[i].points[0]; for (int j = 1; j < road.leftEdge[i].points.size(); ++j) { p2 = road.leftEdge[i].points[j]; MakeLine(&edge, &p1, &p2); PointF vp; if (VerticalPointOnLine(car->carXY[car->axial[AXIAL_FRONT]], edge, vp)) { leftExt = true; MakeLine(&leftExtLine, &car->carXY[car->axial[AXIAL_FRONT]], &vp); goto LEFT_EXT_CMP; } p1 = p2; } } LEFT_EXT_CMP: for (int i = 0; i < road.rightEdge.size(); ++i) { PointF p1, p2; Line edge; p1 = road.rightEdge[i].points[0]; for (int j = 1; j < road.rightEdge[i].points.size(); ++j) { p2 = road.rightEdge[i].points[j]; MakeLine(&edge, &p1, &p2); PointF vp; if (VerticalPointOnLine(car->carXY[car->axial[AXIAL_FRONT]], edge, vp)) { rightExt = true; MakeLine(&rightExtLine, &car->carXY[car->axial[AXIAL_FRONT]], &vp); goto RIGHT_EXT_CMP; } else { // DEBUG("右侧不垂点 %d p1(%f,%f) p2(%f,%f) (%f,%f)", j, p1.X, p1.Y, p2.X, p2.Y, vp.X, vp.Y); } p1 = p2; } } RIGHT_EXT_CMP: if (!leftExt || !rightExt) { DEBUG("左右边界不匹配"); return false; } bool orthogonalInSegment = false; for (int i = 0; i < road.separate.size(); ++i) { // 段 PointF p1, p2; Line sep; map> orthogonal; // 一段分道组内,有一条正交,就必须保证同组的全都正交,否则直接退出 for (int j = 0; j < road.separate[i].lines.size(); ++j) { // 线组 bool intersection = false; for (int k = 0; !intersection && k < road.separate[i].lines[j].size(); ++k) { // 节 p1 = road.separate[i].lines[j][k].points[0]; for (int m = 1; m < road.separate[i].lines[j][k].points.size(); ++m) { p2 = road.separate[i].lines[j][k].points[m]; MakeLine(&sep, &p1, &p2); if (IntersectionOf(leftExtLine, sep) == GM_Intersection) { vector stor(4); stor[0] = 1; stor[1] = road.separate[i].lines[j][k].character; stor[2] = road.separate[i].lines[j][k].left_lane_direct; stor[3] = road.separate[i].lines[j][k].right_lane_direct; orthogonal.insert(pair>(j, stor)); orthogonalInSegment = true; intersection = true; break; } else if (IntersectionOf(rightExtLine, sep) == GM_Intersection) { vector stor(4); stor[0] = 2; stor[1] = road.separate[i].lines[j][k].character; stor[2] = road.separate[i].lines[j][k].left_lane_direct; stor[3] = road.separate[i].lines[j][k].right_lane_direct; orthogonal.insert(pair>(j, stor)); orthogonalInSegment = true; intersection = true; break; } p1 = p2; } } } // DEBUG("目标 %d 当前 %d", road.separate[i].lines.size(), orthogonal.size()); if (orthogonal.size() > 0) { if (orthogonal.size() == road.separate[i].lines.size()) { // 得到当前在第几个车道 int x = 0; int left_char = LINE_SOLID; // 道路左边线 int right_direct = 0; for (x = 0; x < orthogonal.size(); ++x) { auto itx = orthogonal.find(x); if (itx != orthogonal.end()) { if (itx->second[0] != 1) { // 在车辆右侧 lane.road = road.id; lane.separate = i; lane.lane = itx->first; // DEBUG("left_char %d second %d", left_char, itx->second[1]); if ((left_char == LINE_SOLID || left_char == LINE_HALF_SOLID_RIGHT) && (itx->second[1] == LINE_SOLID || itx->second[1] == LINE_HALF_SOLID_LEFT)) // 车道左右均是实线 lane.direct = itx->second[2]; else lane.direct = 0; // DEBUG("路 %d 段 %d 车道 %d 限定 %d", lane.road, lane.separate, lane.lane, lane.direct); break; } else { right_direct = itx->second[3]; left_char = itx->second[2]; } } } if (x >= orthogonal.size()) { lane.road = road.id; lane.separate = i; lane.lane = orthogonal.size(); // DEBUG("left_char %d right_direct %d", left_char, right_direct); // 最后车道的右侧限定 if (left_char == LINE_SOLID || left_char == LINE_HALF_SOLID_RIGHT) lane.direct = right_direct; else lane.direct = 0; // DEBUG("路 %d 段 %d 车道 %d 限定 %d", lane.road, lane.separate, lane.lane, lane.direct); } out = lane; return true; } else { // 不完全正交,直接退出 } DEBUG("分道线长短不同,退出"); return false; } } DEBUG("段匹配失败"); return false; } /************************************************************************* * 碰触车道线型 * @param road * @param car */ static int CrashRoadLine(road_t &road, const car_model *car) { Line frontAxle, rearAxle; MakeLine(&frontAxle, &car->carXY[car->left_front_tire[TIRE_OUTSIDE]], &car->carXY[car->right_front_tire[TIRE_OUTSIDE]]); MakeLine(&rearAxle, &car->carXY[car->left_rear_tire[TIRE_OUTSIDE]], &car->carXY[car->right_rear_tire[TIRE_OUTSIDE]]); // 检查道路边缘 for (int i = 0; i < road.leftEdge.size(); ++i) { PointF p1, p2; Line edge; p1 = road.leftEdge[i].points[0]; for (int j = 1; j < road.leftEdge[i].points.size(); ++j) { p2 = road.leftEdge[i].points[j]; MakeLine(&edge, &p1, &p2); if (IntersectionOf(edge, frontAxle) == GM_Intersection || IntersectionOf(edge, rearAxle) == GM_Intersection) { // 压道路左边线 if (road.leftEdge[i].character != LINE_SOLID) { return CRL_EDGE_DOTTED; } return CRL_EDGE_SOLID; } p1 = p2; } } for (int i = 0; i < road.rightEdge.size(); ++i) { PointF p1, p2; Line edge; p1 = road.rightEdge[i].points[0]; for (int j = 1; j < road.rightEdge[i].points.size(); ++j) { p2 = road.rightEdge[i].points[j]; MakeLine(&edge, &p1, &p2); if (IntersectionOf(edge, frontAxle) == GM_Intersection || IntersectionOf(edge, rearAxle) == GM_Intersection) { // 压道路右边线 if (road.rightEdge[i].character != LINE_SOLID) { return CRL_EDGE_DOTTED; } return CRL_EDGE_SOLID; } p1 = p2; } } // 检查分道线 for (int i = 0; i < road.separate.size(); ++i) { // 段 PointF p1, p2; Line sep; for (int j = 0; j < road.separate[i].lines.size(); ++j) { // 线 for (int k = 0; k < road.separate[i].lines[j].size(); ++k) { // 节 p1 = road.separate[i].lines[j][k].points[0]; for (int m = 1; m < road.separate[i].lines[j][k].points.size(); ++m) { p2 = road.separate[i].lines[j][k].points[m]; MakeLine(&sep, &p1, &p2); if (IntersectionOf(sep, frontAxle) == GM_Intersection || IntersectionOf(sep, rearAxle) == GM_Intersection) { // 检查道路分隔线类型 if (road.separate[i].lines[j][k].character == LINE_DOTTED) { // 压虚线 return CRL_SEP_DOTTED; } else if (road.separate[i].lines[j][k].character == LINE_SOLID) { // 压实线 return CRL_SEP_SOLID; } else if (road.separate[i].lines[j][k].character == LINE_HALF_SOLID_LEFT) { if (LaneIsValid(CurrentLane) && CurrentLane.lane <= j) { return CRL_SEP_SOLID; } return CRL_SEP_DOTTED; } else if (road.separate[i].lines[j][k].character == LINE_HALF_SOLID_RIGHT) { if (LaneIsValid(CurrentLane) && CurrentLane.lane > j) { return CRL_SEP_SOLID; } return CRL_SEP_DOTTED; } } p1 = p2; } } } } return CRL_NONE; } static bool LaneIsSame(struct car_on_lane lane1, struct car_on_lane lane2) { if (lane1.road == lane2.road && lane1.separate == lane2.separate && lane1.lane == lane2.lane) { return true; } return false; } static bool LaneIsValid(struct car_on_lane lane) { if (lane.road >= 0 && lane.separate >= 0 && lane.lane >= 0) { return true; } return false; } void Rtk2DriveTimer(struct drive_timer &tm, const struct RtkTime *rtkTime) { tm.hour = rtkTime->hh; tm.min = rtkTime->mm; tm.sec = rtkTime->ss; tm.msec = rtkTime->mss; } static char isTurn(int currYaw, int prevYaw, int &ang) { // DEBUG("currYaw %d prevYaw %d", currYaw, prevYaw); int deltaAng = 0; if (ABS(currYaw - prevYaw) > 180) { deltaAng = 360 - ABS(currYaw-prevYaw); } else { deltaAng = ABS(currYaw - prevYaw); } ang = deltaAng; // DEBUG("角度差值 %d", deltaAng); if (deltaAng >= TURN_THRESHOLD) { if((( currYaw + 360 - prevYaw) % 360) < 180) { // DEBUG("右转"); return 'R'; } else { // DEBUG("左转"); return 'L'; } } return 'N'; } static char CheckCarTurn(LIST_CAR_MODEL &CarModelList) { // 最近2秒内,每0.5秒的角度差大于5度,且方向相同,连续4次;或突现超30度的转向;认为转向。 if (CarModelList.size() < 1) return false; list::iterator iter = CarModelList.begin(); car_model *c1 = *iter, *c2; ++iter; char turn[TURN_CHECK_CNT] = {0}; int checkCnt = 0; // DEBUG("CheckCarTurn........."); while (iter != CarModelList.end() && checkCnt < TURN_CHECK_CNT) { c2 = *iter; uint32_t tdiff = TimeGetDiff(c1->tm.hh, c1->tm.mm, c1->tm.ss, c1->tm.mss * 10, c2->tm.hh, c2->tm.mm, c2->tm.ss, c2->tm.mss*10); if (tdiff >= TURN_CHECK_INTERVAL) { int ang = 0; turn[checkCnt] = isTurn((int)c1->yaw, (int)c2->yaw, ang); // DEBUG("%c 角度比较 %02d:%02d:%02d.%03d %02d:%02d:%02d.%03d", turn[checkCnt], c1->tm.hh, c1->tm.mm, c1->tm.ss, c1->tm.mss * 10, c2->tm.hh, c2->tm.mm, c2->tm.ss, c2->tm.mss*10); if (turn[checkCnt] == 'N') { break; } else if (ang >= 30) { DEBUG("左右转确认 %c", turn[checkCnt]); return turn[checkCnt]; } c1 = c2; checkCnt++; } ++iter; } int i = 0; for (; checkCnt == TURN_CHECK_CNT && i < TURN_CHECK_CNT-1; ++i) { if (turn[i] != turn[i+1]) break; } if (i == TURN_CHECK_CNT-1) { DEBUG("左右转确认 %c", turn[0]); return turn[0]; } return 0; } /********************************************************** * 按整个车身是否覆盖计算 * @param RoadMapList * @param car * @return */ /*static bool CrashRedArea(LIST_ROAD_MAP &RoadMapList, const car_model *car) { bool ret = false; Polygon carBody; carBody.num = car->bodyNum; carBody.point = (PointF *)malloc(carBody.num * sizeof(PointF)); for (int i = 0; i < carBody.num; ++i) { carBody.point[i] = car->carXY[car->body[i]]; } for (int i = 0; i < RoadMapList.size(); ++i) { if (RoadMapList[i].type == GENERAL_MAP) { // 每条红区都检测 for (int j = 0; j < RoadMapList[i].redAreaNum; ++j) { if (IntersectionOf(&carBody, &RoadMapList[i].redArea[j]) != GM_None) { ret = true; } } break; } } free(carBody.point); return ret; }*/ bool CrashTheLine(Line line, const car_model *car, LIST_CAR_MODEL &CarModelList) { if (CarModelList.size() < 2) return false; list::iterator iter = CarModelList.begin(); Line trace; PointF p1, p2; p1 = ((car_model *)(*iter))->carXY[((car_model *)(*iter))->axial[AXIAL_FRONT]]; ++iter; p2 = ((car_model *)(*iter))->carXY[((car_model *)(*iter))->axial[AXIAL_FRONT]]; MakeLine(&trace, &p1, &p2); if (IntersectionOf(trace, line) == GM_Intersection && IntersectionOfLine(p1, line) == -1) { return true; } return false; } /*************************************************** * 接近路口时,提示下一步怎么走 * @param road * @param car * @param CarModelList */ static void ArrivedRoadEnd(road_t &road, const car_model *car, LIST_CAR_MODEL &CarModelList) { // 计算车前进轨迹延长线 double yaw = YawOf(car->carXY[ car->axial[AXIAL_FRONT] ], car->carXY[ car->axial[AXIAL_REAR] ]); PointF extPoint = PointExtend(car->carXY[ car->axial[AXIAL_FRONT] ], NEXT_ROAD_TIP, yaw); Line extLine; MakeLine(&extLine, &car->carXY[ car->axial[AXIAL_FRONT] ], &extPoint); if (IntersectionOf(extLine, road.stopLine) == GM_Intersection && IntersectionOfLine(extPoint, road.stopLine) == -1) { if (DistanceOf(extPoint, road.stopLine) > 1.0 && !road.arrivedTail) { // 接近路口后,要检查车辆是否进入错误车道 DEBUG("接近路口"); road.arrivedTail = true; if (!road.tts.empty()) PlayTTS(road.tts.c_str()); } } else if (road.arrivedTail) { road.arrivedTail = false; } } static trigger_line_t * EntryItem(int index, road_exam_map &RoadMap, const car_model *car, LIST_CAR_MODEL &CarModelList) { for (int i = 0; i < RoadMap.triggerLines.size(); ++i) { if (RoadMap.triggerLines[i].road == RoadMap.roads[index].id) { Line triggerLine; if (RoadMap.triggerLines[i].leftPoints.size() != RoadMap.triggerLines[i].points.size()) { RoadMap.triggerLines[i].leftPoints.clear(); for (int j = 0; j < RoadMap.triggerLines[i].points.size(); ++j) { RoadMap.triggerLines[i].leftPoints.push_back(CalcProjectionWithRoadEdge(RoadMap.roads[index].leftEdge, RoadMap.triggerLines[i].points[j])); } for (int j = 0; j < RoadMap.triggerLines[i].points.size(); ++j) { DEBUG("触发线补齐 road %d id %d type %d (%0.4f, %0.4f)-(%0.4f, %0.4f)", RoadMap.roads[index].id, RoadMap.triggerLines[i].id, RoadMap.triggerLines[i].active, RoadMap.triggerLines[i].points[0].X, RoadMap.triggerLines[i].points[0].Y, RoadMap.triggerLines[i].leftPoints[0].X, RoadMap.triggerLines[i].leftPoints[0].Y); } } MakeLine(&triggerLine, &RoadMap.triggerLines[i].points[0], &RoadMap.triggerLines[i].leftPoints[0]); if (CrashTheLine(triggerLine, car, CarModelList)) { DEBUG("触发项目 %d %s (%0.4f, %0.4f)-(%0.4f, %0.4f)", RoadMap.triggerLines[i].active, RoadMap.triggerLines[i].tts.c_str(), triggerLine.X1, triggerLine.Y1, triggerLine.X2, triggerLine.Y2); return &RoadMap.triggerLines[i]; } } } return NULL; } static bool AllCmp(road_exam_map &map) { for (int i = 0; i < map.triggerLines.size(); ++i) { if (!map.triggerLines[i].cmp) return false; } return true; } /************************************************************************ * 开始新的考试后,清除地图所有的刹车、停车记录 * @param map */ static void ClearAll(road_exam_map &map) { for (int i = 0; i < map.roads.size(); ++i) { map.roads[i].activeStop = map.roads[i].activeBreak = false; map.roads[i].arrivedTail = false; map.roads[i].errorLane = false; } for (int i = 0; i < map.specialAreas.size(); i++) { map.specialAreas[i].overSpeed = map.specialAreas[i].activeBreak = false; } for (int i = 0; i < map.triggerLines.size(); ++i) { map.triggerLines[i].cmp = false; } } static void CheckBreakActive(road_exam_map &map, const car_model *car, LIST_CAR_MODEL &CarModelList, double speed, int moveDirect, const struct RtkTime *rtkTime) { int BreakDone = ReadCarStatus(BREAK); // 计算车前进轨迹延长线 double yaw = YawOf(car->carXY[ car->axial[AXIAL_FRONT] ], car->carXY[ car->axial[AXIAL_REAR] ]); PointF extPoint = PointExtend(car->carXY[ car->axial[AXIAL_FRONT] ], LASTEST_BREAK_POINT, yaw); Line extLine; MakeLine(&extLine, &car->carXY[ car->axial[AXIAL_FRONT] ], &extPoint); // 路口刹车点 for (int i = 0; i < map.roads.size(); ++i) { // 车头和路口距离不足30米 if (IntersectionOf(extLine, map.roads[i].stopLine) == GM_Intersection && IntersectionOfLine(car->carXY[ car->axial[AXIAL_FRONT] ], map.roads[i].stopLine) == 1 ) { DEBUG("进入减速区"); if (BreakDone == BREAK_ACTIVE) { map.roads[i].activeBreak = true; } if (DistanceOf(car->carXY[car->axial[AXIAL_FRONT]], map.roads[i].stopLine) < DISTANCE_STOP_CAR_TO_STOP_LINE && moveDirect == 0) { map.roads[i].activeStop = true; } } // 跨线后,检查刹车动作 if (CrashTheLine(map.roads[i].stopLine, car, CarModelList)) { if (map.roads[i].stopFlag != 0 && !map.roads[i].activeStop) { // 不停车瞭望,不合格 DEBUG("不停车瞭望"); if (map.roads[i].active == ROAD_ACTIVE_FORWARD) { AddExamFault(42, rtkTime); } else if (map.roads[i].active == ROAD_ACTIVE_TURN_LEFT) { AddExamFault(44, rtkTime); } else if (map.roads[i].active == ROAD_ACTIVE_TURN_RIGHT) { AddExamFault(47, rtkTime); } } if (!map.roads[i].activeBreak) { // 不按规定减速,不合格 DEBUG("不按规定减速"); if (map.roads[i].active == ROAD_ACTIVE_FORWARD) { AddExamFault(41, rtkTime); } else if (map.roads[i].active == ROAD_ACTIVE_TURN_LEFT) { AddExamFault(43, rtkTime); } else if (map.roads[i].active == ROAD_ACTIVE_TURN_RIGHT) { AddExamFault(46, rtkTime); } } } } // 人行道、公交站刹车点;学校限速区 // DEBUG("补全特殊区域 size = %d", map.specialAreas.size()); for (int i = 0; i < map.specialAreas.size(); i++) { if (map.specialAreas[i].type == GRID_AREA) continue; if (map.specialAreas[i].area.size() == 2 && map.specialAreas[i].leftPoints.size() != 2) { // 计算点到左侧路边线的垂点 int road = 0; for (road = 0; road < map.roads.size(); ++road) { if (map.roads[road].id == map.specialAreas[i].road) break; } PointF vPoint = CalcProjectionWithRoadEdge(map.roads[road].leftEdge, map.specialAreas[i].area[0]); // DEBUG("计算垂点1 (%f, %f)", vPoint.X, vPoint.Y); map.specialAreas[i].leftPoints.push_back(vPoint); vPoint = CalcProjectionWithRoadEdge(map.roads[road].leftEdge, map.specialAreas[i].area[1]); // DEBUG("计算垂点2 (%f, %f)", vPoint.X, vPoint.Y); map.specialAreas[i].leftPoints.push_back(vPoint); } if (map.specialAreas[i].type == ZEBRA_CROSSING || map.specialAreas[i].type == BUS_STATION_AREA) { // DEBUG("斑马线"); Line startLine; MakeLine(&startLine, &map.specialAreas[i].area[0], &map.specialAreas[i].leftPoints[0]); // 车头和斑马线距离不足30米 if (IntersectionOf(extLine, startLine) == GM_Intersection && IntersectionOfLine(car->carXY[ car->axial[AXIAL_FRONT] ], startLine) == 1 ) { DEBUG("进入减速区 %d", map.specialAreas[i].type); if (BreakDone == BREAK_ACTIVE) { map.specialAreas[i].activeBreak = true; } } // 跨线后,检查刹车动作 if (CrashTheLine(startLine, car, CarModelList)) { if (!map.specialAreas[i].activeBreak) { // 不按规定减速,不合格 DEBUG("不按规定减速"); if (map.specialAreas[i].type == ZEBRA_CROSSING) { AddExamFault(48, rtkTime); } else { AddExamFault(50, rtkTime); } } else { DEBUG("按规定减速"); } } } else if (map.specialAreas[i].type == SCHOOL_AREA) { Polygon school; // DEBUG("学校"); school.num = 4; school.point = (PointF *) malloc(school.num * sizeof(PointF)); school.point[0] = map.specialAreas[i].area[0]; school.point[1] = map.specialAreas[i].area[1]; school.point[2] = map.specialAreas[i].leftPoints[1]; school.point[3] = map.specialAreas[i].leftPoints[0]; if (IntersectionOf(car->carXY[ car->axial[AXIAL_FRONT] ], &school) == GM_Containment) { if (ConvertMs2KMh(speed) > PASS_SCHOOL_MAX_SPEED) { if (!map.specialAreas[i].overSpeed) { DEBUG("通过学校区域超速"); AddExamFault(49, rtkTime); map.specialAreas[i].overSpeed = true; } } } free(school.point); } } // DEBUG("补全特殊区域 over"); } #if 0 typedef struct { int road; int segment; int lane; } CarOnTrackInfo_t; static CarOnTrackInfo_t CarOnTrackInfo; void TestRoadGeneral(struct road_exam2_map &map, const car_model *car, LIST_CAR_MODEL &CarModelList, double speed, int moveDirect, const struct RtkTime *rtkTime) { // 检测车道变更 CarOnTrackInfo_t newCarOnTrackInfo; if (newCarOnTrackInfo.road == CarOnTrackInfo.road && newCarOnTrackInfo.segment == CarOnTrackInfo.segment && newCarOnTrackInfo.lane != CarOnTrackInfo.lane) { } CarOnTrackInfo = newCarOnTrackInfo; } /************************************************** * 车辆当前所在路段,车头需越过起始线一定距离 * @param currIndex * @param map * @param car */ static void EnterRoad(int &currIndex, struct road_exam2_map &map, const car_model *car) { Polygon carBody; carBody.num = car->bodyNum; carBody.point = (PointF *)malloc(carBody.num * sizeof(PointF)); for (int i = 0; i < carBody.num; ++i) { carBody.point[i] = car->carXY[car->body[i]]; } Polygon roadArea; roadArea.num = 0; roadArea.point = NULL; for (int i = 0; i < map.roads.size(); ++i) { if (roadArea.point != NULL) { free(roadArea.point); } for (int x = 0; x < map.roads[i].leftEdge.size(); ++x) { roadArea.num += map.roads[i].leftEdge[x].points.size(); } for (int x = 0; x < map.roads[i].rightEdge.size(); ++x) { roadArea.num += map.roads[i].rightEdge[x].points.size(); } roadArea.point = (PointF *) malloc(roadArea.num * sizeof(PointF)); int n = 0; for (int j = 0; j < map.roads[i].leftEdge.size(); j++) { for (int x = 0; x < map.roads[i].leftEdge[j].points.size(); ++x) { if (n > 0 && x == 0 && isEqual2(roadArea.point[n-1].X, map.roads[i].leftEdge[j].points[x].X) && isEqual2(roadArea.point[n-1].Y, map.roads[i].leftEdge[j].points[x].Y)) { // 第一个点已经存在于上一条线 } else { roadArea.point[n++] = map.roads[i].leftEdge[j].points[x]; } } } for (int j = map.roads[i].rightEdge.size(); j > 0; j--) { for (int x = map.roads[i].rightEdge[j].points.size(); x > 0; --x) { if (n > 0 && x == map.roads[i].rightEdge[j].points.size() && isEqual2(roadArea.point[n-1].X, map.roads[i].rightEdge[j - 1].points[x-1].X) && isEqual2(roadArea.point[n-1].Y, map.roads[i].rightEdge[j - 1].points[x-1].Y)) { // 第一个点已经存在于上一条线 } else { roadArea.point[n++] = map.roads[i].rightEdge[j - 1].points[x - 1]; } } } roadArea.num = n; if (IntersectionOf(car->carXY[car->axial[AXIAL_FRONT]], &roadArea) == GM_Containment) { currIndex = i; goto CHECK_CAR_ON_ROAD_END; } } currIndex = INVALID_ROAD; CHECK_CAR_ON_ROAD_END: if (roadArea.point != NULL) { free(roadArea.point); } free(carBody.point); } /****************************************************** * 全车都需离开这个区域 * @param currIndex * @param map * @param car * @return */ static bool ExitRoad(int currIndex, struct road_exam2_map &map, const car_model *car) { // 全车都需不在地图中 bool ret = false; if (currIndex == INVALID_ROAD || currIndex >= map.roads.size()) return ret; Polygon carBody; carBody.num = car->bodyNum; carBody.point = (PointF *)malloc(carBody.num * sizeof(PointF)); for (int i = 0; i < carBody.num; ++i) { carBody.point[i] = car->carXY[car->body[i]]; } if (IntersectionOf(&carBody, &map.roads[currIndex].area) == GM_None) { ret = true; } free(carBody.point); return ret; } static bool CrashSeparateLine(int currIndex, struct road_exam2_map &map, const car_model *car) { Line frontAxle, rearAxle; if (currIndex == INVALID_ROAD || currIndex >= map.roads.size()) return false; MakeLine(&frontAxle, &car->carXY[car->left_front_tire[TIRE_OUTSIDE]], &car->carXY[car->right_front_tire[TIRE_OUTSIDE]]); MakeLine(&rearAxle, &car->carXY[car->left_rear_tire[TIRE_OUTSIDE]], &car->carXY[car->right_rear_tire[TIRE_OUTSIDE]]); // 分段 for (int i = 0; i < map.roads[currIndex].separate.size(); i++) { // 分段中的每条线 for (int j = 0; j < map.roads[currIndex].separate[i].line.size(); j++) { Line theLine; int p1 = 0; for (int p2 = 1; p2 < map.roads[currIndex].separate[i].line[j].num; ++p2) { MakeLine(&theLine, &map.roads[currIndex].separate[i].line[j].point[p1], &map.roads[currIndex].separate[i].line[j].point[p2]); if (IntersectionOf(theLine, frontAxle) == GM_Intersection || IntersectionOf(theLine, rearAxle) == GM_Intersection) { return true; } p1 = p2; } } } return false; } static void DetectSeparate(int currIndex, struct road_exam2_map &map, const car_model *car) { int segment; int lane = -1; CarOnTrackInfo_t newInfo; if (currIndex == INVALID_ROAD || currIndex >= map.roads.size()) return; // 遍历每一分段 for (int i = 0; i < map.roads[currIndex].separate.size(); i++) { int separate_line_num = map.roads[currIndex].separate[i].lines.size(); struct vrecord_ { int valid; int p1; int p2; }; vector vrecord; vrecord.clear(); bool match1 = false; // 遍历当前分段的每一条线 for (int j = 0; j < separate_line_num; ++j) { Line theLine; int p1 = 0; struct vrecord_ v; v.valid = 0; // 单独的一条虚线 for (int p2 = 1; p2 < map.roads[currIndex].separate[i].lines[j].num; ++p2) { MakeLine(&theLine, &map.roads[currIndex].separate[i].lines[j].point[p1], &map.roads[currIndex].separate[i].lines[j].point[p2]); if (VerticalPointOnLine(car->basePoint, theLine)) { v.valid = 1; v.p1 = p1; v.p2 = p2; match1 = true; break; } p1 = p2; } vrecord.push_back(v); lane = separate_line_num;// } if (match1) { for (int x = 0; x < vrecord.size(); ++x) { if (vrecord[i].valid == 0) { // 首尾两段线的延申必有一个垂点 if (DistanceOf(car->carXY[ car->axial[AXIAL_FRONT] ], map.roads[currIndex].separate[i].lines[x].point[0]) < DistanceOf(car->carXY[ car->axial[AXIAL_FRONT] ], map.roads[currIndex].separate[i].lines[x].point[1])) { vrecord[x].p1 = 0; vrecord[x].p2 = 1; } else { vrecord[x].p1 = map.roads[currIndex].separate[i].lines[x].num - 2; vrecord[x].p2 = map.roads[currIndex].separate[i].lines[x].num - 1; } } int rel = IntersectionOfLine(map.roads[currIndex].separate[i].lines[x].point[vrecord[x].p1], map.roads[currIndex].separate[i].lines[x].point[vrecord[x].p2], car->basePoint); if (rel != -1) { newInfo.road = currIndex; newInfo.segment = i; newInfo.lane = x; break; } } newInfo.road = currIndex; newInfo.segment = i; newInfo.lane = vrecord.size(); break; } } } #endif