yy1717
2024-02-28 27fc91fbe8f88b6885356e68828cfe1ce1db7601
lib/src/main/cpp/test_items/area_exam.cpp
@@ -3,65 +3,158 @@
//
#include <cstdlib>
#include <tuple>
#include <map>
#include "area_exam.h"
#include "../test_common/car_sensor.h"
#include "../driver_test.h"
#include "../jni_log.h"
#include "park_bottom.h"
#include "stop_and_start.h"
#include "uphill.h"
#include "park_edge.h"
#include "driving_curve.h"
#include "turn_a90.h"
#include "right_corner.h"
#include "../utils/xconvert.h"
#include "../common/apptimer.h"
#include "../test_common/odo_graph.h"
#include "../test_common/Geometry.h"
#include "../common/observer.h"
#include "../native-lib.h"
#define DEBUG(fmt, args...)     LOGD("<area_exam> <%s>: " fmt, __func__, ##args)
ilovers::Observer<std::function<void(move_status_t)>> CarMoveEvent;
enum class ProximityStatus {
    Near,
    Bounce,
    Far
};
static bool ProximityArea(Line &base_line, Line &line);
ilovers::Observer<std::function<void(move_status_t, move_status_t, double)>> CarMoveEvent;
ilovers::Observer<std::function<void(int, int, double)>> ShiftEvent;
static void CheckProximity(prime_t  &prime, Line &base_line, Line &line, int this_id);
static bool CrossingStartLine(Line &trace, Line &start_line);
static void ProximityReminders(prime_t &prime);
static void DetectCarMove(prime_t &prime);
static void DetectShift(prime_t &prime);
static void EnterMap(prime_t &prime);
static void ExitMap(prime_t &prime);
void AreaExam(prime_t &prime)
{
    switch (prime.curr_exam_map.type) {
        case MAP_TYPE_PARK_BUTTOM:
            break;
        case MAP_TYPE_PARK_EDGE:
            break;
        case MAP_TYPE_TURN_90:
            break;
        case MAP_TYPE_UPHILL:
            break;
        case MAP_TYPE_CURVE:
            break;
        default:
            if (EnterMap()) {
            }
            break;
    if (prime.prev_modeling_index == -1 || prime.curr_modeling_index == -1) {
        return;
    }
    DEBUG("--------------> %d", __LINE__);
    DetectShift(prime);
    DEBUG("--------------> %d", __LINE__);
    DetectCarMove(prime);
    DEBUG("--------------> %d", __LINE__);
    ProximityReminders(prime);
    DEBUG("--------------> %d", __LINE__);
    EnterMap(prime);
    DEBUG("--------------> %d", __LINE__);
    TestDrivingCurve(prime);
    DEBUG("--------------> %d", __LINE__);
    TestParkBottom(prime);
    DEBUG("--------------> %d", __LINE__);
    TestParkEdge(prime);
    DEBUG("--------------> %d", __LINE__);
    TestUphill(prime);
    DEBUG("--------------> %d", __LINE__);
    TestRightCorner(prime);
    DEBUG("--------------> %d", __LINE__);
    ExitMap(prime);
    DEBUG("--------------> %d", __LINE__);
}
// 检查换挡,如停车入库、倒车开始等动作,需要在挡位变换时检测,同时需考虑驾驶员一次换挡不进,停在原地再次操作的情况
static void DetectShift(prime_t &prime)
{
    static int prevGear = prime.sensor.gear;
    static double odo = prime.odo;          // 记录这个挡位下行驶的距离
    if (prime.sensor.gear != prevGear) {
        if (prime.odo - odo > 1) {
        }
        ShiftEvent.Notify(prime.sensor.gear, prevGear, prime.odo - odo);
        prevGear = prime.sensor.gear;
        odo = prime.odo;
    }
}
static bool stopTimeout = false;
static void StoppedTimeout(apptimer_var_t val) {
    stopTimeout = true;
}
// 处理各个项目的超时停车(停下时和再次启动时,挡位是一致的)
static void DetectCarMove(prime_t &prime)
{
    static move_status_t prevMove = STOP;
    static double odo = prime.odo;
    static int gearWhenStop = GEAR_N;
    static move_status_t prevMove = prime.pMotion->move;
    if (prime.pMotion->move != prevMove) {
        // Notify
        CarMoveEvent.Notify(prime.pMotion->move);
        DEBUG("行驶状态改变 %d", prime.pMotion->move);
        CarMoveEvent.Notify(prime.pMotion->move, prevMove, prime.odo - odo);
        AppTimer_delete(StoppedTimeout);
        if (prime.pMotion->move == STOP) {
            gearWhenStop = prime.sensor.gear;
            switch (prime.examing_area.type) {
                case MAP_TYPE_PARK_BUTTOM:
                    AppTimer_add(StoppedTimeout, prime.examParam.park_bottom_pause_criteria);
                    break;
                case MAP_TYPE_PARK_EDGE:
                    AppTimer_add(StoppedTimeout, prime.examParam.park_edge_pause_criteria);
                    break;
                case MAP_TYPE_RIGHT_CORNER:
                    AppTimer_add(StoppedTimeout, prime.examParam.turn_a90_pause_criteria);
                    break;
                case MAP_TYPE_CURVE:
                    AppTimer_add(StoppedTimeout, prime.examParam.curve_pause_criteria);
                    break;
                case MAP_TYPE_UPHILL:
                    break;
                default:break;
            }
        } else {
            if (stopTimeout && ((prime.sensor.gear == GEAR_R) == (gearWhenStop == GEAR_R))) {
                // 停车超时
                switch (prime.examing_area.type) {
                    case MAP_TYPE_PARK_BUTTOM:
                        // 停车超2秒,每次扣5分
                        AddExamFault(20106);
                        break;
                    case MAP_TYPE_PARK_EDGE:
                        AddExamFault(20406);
                        break;
                    case MAP_TYPE_RIGHT_CORNER:
                        AddExamFault(20703);
                        break;
                    case MAP_TYPE_CURVE:
                        // 停车超2秒,不合格
                        AddExamFault(20602);
                        break;
                    case MAP_TYPE_UPHILL:
                        break;
                    default:break;
                }
            }
        }
        stopTimeout = false;
        prevMove = prime.pMotion->move;
        odo = prime.odo;
    }
}
void RegisterCarMoveObserver(void (*ptr)(move_status_t))
int RegisterCarMoveObserver(std::function<void(move_status_t, move_status_t, double)> ob)
{
    CarMoveEvent.Connect(ptr);
    return CarMoveEvent.Connect(ob);
}
void UnregisterCarMoveObserver(int handle)
@@ -69,163 +162,313 @@
    CarMoveEvent.Disconnect(handle);
}
void EnterMap(prime_t &prime)
int RegisterShiftObserver(std::function<void(int, int, double)> ob)
{
    if (prime.curr_exam_map.type != 0) {
    return ShiftEvent.Connect(ob);
}
void UnregisterShiftObserver(int handle)
{
    ShiftEvent.Disconnect(handle);
}
static void EnterMap(prime_t &prime)
{
    if (prime.examing_area.type != 0) {
        return;
    }
    if (prime.prev_modeling_index == -1 || prime.curr_modeling_index == -1) {
        return;
    }
    DEBUG("--------------> %d", __LINE__);
    PointF &lp1 = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]];
    PointF &lp2 = prime.pModeling[prime.prev_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]];
    PointF &rp1 = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]];
    PointF &rp2 = prime.pModeling[prime.prev_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]];
    DEBUG("1. %d", prime.pModeling[prime.curr_modeling_index].points.size());
    DEBUG("2. %d", prime.pModeling[prime.prev_modeling_index].points.size());
    DEBUG("3. %d", prime.pModel->left_front_tire[TIRE_OUTSIDE]);
    DEBUG("4. %d", prime.pModel->right_front_tire[TIRE_OUTSIDE]);
    PointF lp1 = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]];
    PointF lp2 = prime.pModeling[prime.prev_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]];
    PointF rp1 = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]];
    PointF rp2 = prime.pModeling[prime.prev_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]];
    Line left_trace, right_trace;
    DEBUG("--------------> %d", __LINE__);
    MAKE_LINE(left_trace, lp1, lp2);
    MAKE_LINE(right_trace, rp1, rp2);
    Line start_line;
    for (int i = 0; i < prime.pMap->park_button_map.size(); ++i) {
        MAKE_LINE(start_line, prime.pMap->park_button_map[i].map[1], prime.pMap->park_button_map[i].map[0]);
    DEBUG("倒库> %d", std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps).size());
    for (int i = 0; i < std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps).size(); ++i) {
        MAKE_LINE(start_line, std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[i].points[1], std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[i].points[0]);
        if (CrossingStartLine(left_trace, start_line)) {
            prime.curr_exam_map.type = MAP_TYPE_PARK_BUTTOM;
            prime.curr_exam_map.map_idx = i;
            prime.examing_area.type = MAP_TYPE_PARK_BUTTOM;
            prime.examing_area.idx = i;
            StartParkBottom(prime);
            return;
        }
        MAKE_LINE(start_line, prime.pMap->park_button_map[i].map[7], prime.pMap->park_button_map[i].map[6]);
        MAKE_LINE(start_line, std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[i].points[7], std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[i].points[6]);
        if (CrossingStartLine(left_trace, start_line)) {
            prime.curr_exam_map.type = MAP_TYPE_PARK_BUTTOM;
            prime.curr_exam_map.map_idx = i;
            prime.examing_area.type = MAP_TYPE_PARK_BUTTOM;
            prime.examing_area.idx = i;
            StartParkBottom(prime);
            return;
        }
    }
    for (int i = 0; i < prime.pMap->park_edge_map.size(); ++i) {
        MAKE_LINE(start_line, prime.pMap->park_edge_map[i].map[1], prime.pMap->park_edge_map[i].map[0]);
    DEBUG("侧方> %d", std::get<MAP_TYPE_PARK_EDGE>(prime.maps).size());
    for (int i = 0; i < std::get<MAP_TYPE_PARK_EDGE>(prime.maps).size(); ++i) {
        MAKE_LINE(start_line, std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[i].points[1], std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[i].points[0]);
        if (CrossingStartLine(left_trace, start_line)) {
            prime.curr_exam_map.type = MAP_TYPE_PARK_EDGE;
            prime.curr_exam_map.map_idx = i;
            prime.examing_area.type = MAP_TYPE_PARK_EDGE;
            prime.examing_area.idx = i;
            StartParkEdge(prime);
            return;
        }
    }
    DEBUG("上坡> %d", std::get<MAP_TYPE_UPHILL>(prime.maps).size());
    for (int i = 0; i < std::get<MAP_TYPE_UPHILL>(prime.maps).size(); ++i) {
        MAKE_LINE(start_line, std::get<MAP_TYPE_UPHILL>(prime.maps)[i].points[0], std::get<MAP_TYPE_UPHILL>(prime.maps)[i].points[10]);
        if (CrossingStartLine(left_trace, start_line)) {
            prime.examing_area.type = MAP_TYPE_UPHILL;
            prime.examing_area.idx = i;
            StartUphill(prime);
            return;
        }
    }
    DEBUG("曲线> %d", std::get<MAP_TYPE_CURVE>(prime.maps).size());
    for (int i = 0; i < std::get<MAP_TYPE_CURVE>(prime.maps).size(); ++i) {
        MAKE_LINE(start_line, std::get<MAP_TYPE_CURVE>(prime.maps)[i].right_start_point, std::get<MAP_TYPE_CURVE>(prime.maps)[i].left_start_point);
        if (CrossingStartLine(left_trace, start_line)) {
            prime.examing_area.type = MAP_TYPE_CURVE;
            prime.examing_area.idx = i;
            StartDrivingCurve(prime);
            return;
        }
    }
    DEBUG("直角> %d", std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps).size());
    for (int i = 0; i < std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps).size(); ++i) {
        MAKE_LINE(start_line, std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[i].points[0], std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[i].points[1]);
        if (CrossingStartLine(left_trace, start_line)) {
            prime.examing_area.type = MAP_TYPE_RIGHT_CORNER;
            prime.examing_area.idx = i;
            StartRightCorner(prime);
            return;
        }
    }
}
/****************************************
 * 退出场地:条件是车头和四轮都不在场地中
 * 如果当前测试项目未完成,要报不合格
 * @param prime
 */
static void ExitMap(prime_t &prime)
{
    if (prime.examing_area.type == MAP_TYPE_NONE) {
        return;
    }
    for (int i = 0; i < prime.pMap->uphill_map.size(); ++i) {
        PointF vPoint = Calc3Point(prime.pMap->uphill_map[i].map[8], prime.pMap->uphill_map[i].map[0], DistanceOf(prime.pMap->uphill_map[i].map[8], prime.pMap->uphill_map[i].map[7]), 'R');
        MAKE_LINE(start_line, prime.pMap->uphill_map[i].map[0], vPoint);
        if (CrossingStartLine(left_trace, start_line)) {
            prime.curr_exam_map.type = MAP_TYPE_UPHILL;
            prime.curr_exam_map.map_idx = i;
            return;
    if (prime.examing_area.type == MAP_TYPE_CURVE) {
        // 车的后轮是否越过结束线或是车辆不在2个大圆范围内
        PointF lp1 = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]];
        PointF lp2 = prime.pModeling[prime.prev_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]];
        PointF rp1 = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]];
        PointF rp2 = prime.pModeling[prime.prev_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]];
        Line left_trace, right_trace;
        MAKE_LINE(left_trace, lp1, lp2);
        MAKE_LINE(right_trace, rp1, rp2);
        Line end_line;
        MAKE_LINE(end_line, std::get<MAP_TYPE_CURVE>(prime.maps)[prime.examing_area.idx].right_end_point, std::get<MAP_TYPE_CURVE>(prime.maps)[prime.examing_area.idx].left_end_point);
        if (CrossingStartLine(left_trace, end_line)) {
            // 离开区域
            StopDrivingCurve(prime);
        }
    }
    for (int i = 0; i < prime.pMap->curve_map.size(); ++i) {
        MAKE_LINE(start_line, prime.pMap->curve_map[i].right_start_point, prime.pMap->curve_map[i].left_start_point);
        if (CrossingStartLine(left_trace, start_line)) {
            prime.curr_exam_map.type = MAP_TYPE_CURVE;
            prime.curr_exam_map.map_idx = i;
            return;
        if (DistanceOf(prime.pModeling[prime.curr_modeling_index].base_point, std::get<MAP_TYPE_CURVE>(prime.maps)[prime.examing_area.idx].front_half_big_circle_centre) > std::get<MAP_TYPE_CURVE>(prime.maps)[prime.examing_area.idx].front_half_big_circle_radius
            && DistanceOf(prime.pModeling[prime.curr_modeling_index].base_point, std::get<MAP_TYPE_CURVE>(prime.maps)[prime.examing_area.idx].back_half_big_circle_centre) > std::get<MAP_TYPE_CURVE>(prime.maps)[prime.examing_area.idx].back_half_big_circle_radius) {
            // 离开区域
            StopDrivingCurve(prime);
        }
    }
    for (int i = 0; i < prime.pMap->turn_a90_map.size(); ++i) {
        MAKE_LINE(start_line, prime.pMap->turn_a90_map[i].map[0], prime.pMap->turn_a90_map[i].map[1]);
        if (CrossingStartLine(left_trace, start_line)) {
            prime.curr_exam_map.type = MAP_TYPE_TURN_90;
            prime.curr_exam_map.map_idx = i;
            return;
    } else {
        MakePolygon area({});
        DEBUG("------------> %d", __LINE__);
        switch (prime.examing_area.type) {
            case MAP_TYPE_PARK_BUTTOM:
                area.AddPoints({std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[prime.examing_area.idx].points[0],
                                std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[prime.examing_area.idx].points[1],
                                std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[prime.examing_area.idx].points[2],
                                std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[prime.examing_area.idx].points[3],
                                std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[prime.examing_area.idx].points[4],
                                std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[prime.examing_area.idx].points[5],
                                std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[prime.examing_area.idx].points[6],
                                std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[prime.examing_area.idx].points[7]});
                break;
            case MAP_TYPE_PARK_EDGE:
                area.AddPoints({std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[prime.examing_area.idx].points[0],
                                std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[prime.examing_area.idx].points[1],
                                std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[prime.examing_area.idx].points[2],
                                std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[prime.examing_area.idx].points[3],
                                std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[prime.examing_area.idx].points[4],
                                std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[prime.examing_area.idx].points[5],
                                std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[prime.examing_area.idx].points[6],
                                std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[prime.examing_area.idx].points[7]});
                break;
            case MAP_TYPE_UPHILL:
                area.AddPoints({std::get<MAP_TYPE_UPHILL>(prime.maps)[prime.examing_area.idx].points[0],
                                std::get<MAP_TYPE_UPHILL>(prime.maps)[prime.examing_area.idx].points[9],
                                std::get<MAP_TYPE_UPHILL>(prime.maps)[prime.examing_area.idx].points[11],
                                std::get<MAP_TYPE_UPHILL>(prime.maps)[prime.examing_area.idx].points[10]});
                break;
            case MAP_TYPE_RIGHT_CORNER:
                area.AddPoints({std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[prime.examing_area.idx].points[0],
                                std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[prime.examing_area.idx].points[1],
                                std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[prime.examing_area.idx].points[2],
                                std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[prime.examing_area.idx].points[3],
                                std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[prime.examing_area.idx].points[4],
                                std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[prime.examing_area.idx].points[5]});
                break;
            default:
                break;
        }
        DEBUG("------------> %d", __LINE__);
        int num = 0;
        if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_front_tire[TIRE_OUTSIDE]],
                           area.GetPolygon()) == GM_None) {
            num++;
        }
        if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_front_tire[TIRE_OUTSIDE]],
                           area.GetPolygon()) == GM_None) {
            num++;
        }
        if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->left_rear_tire[TIRE_OUTSIDE]],
                           area.GetPolygon()) == GM_None) {
            num++;
        }
        if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->right_rear_tire[TIRE_OUTSIDE]],
                           area.GetPolygon()) == GM_None) {
            num++;
        }
        if (IntersectionOf(prime.pModeling[prime.curr_modeling_index].points[prime.pModel->body[prime.pModel->axial[AXIAL_FRONT]]],
                           area.GetPolygon()) == GM_None) {
            num++;
        }
        DEBUG("------------> %d", __LINE__);
        if (num == 5) {
            // 离开区域
            StopDrivingCurve(prime);
            StopParkBottom(prime);
            StopRightCorner(prime);
            StopUphill(prime);
            StopParkEdge(prime);
        }
        DEBUG("------------> %d", __LINE__);
    }
}
// 车轮驶过线,且车头位于右侧
static bool CrossingStartLine(Line &trace, Line &start_line)
{
    PointF head = {.X = trace.X1, .Y = trace.Y1};
    PointF head = trace.p1;
    if (IntersectionOf(trace, start_line) == GM_Intersection
        && IntersectionOfLine(head, start_line) == RELATION_RIGHT) {
        && IntersectionOfLine(head, start_line) == REL_POS_RIGHT) {
        return true;
    }
    return false;
}
void FarawayMap(prime_t &prime)
{
    if (prime.arriving_map.type != 0) {
        PointF &car_head = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->axial[AXIAL_FRONT]];
        PointF car_head_trend = PointExtend(car_head, 7, prime.pModeling->yaw);
        Line car_head_line;
        MAKE_LINE(car_head_line, car_head, car_head_trend);
    }
}
static void ProximityReminders(prime_t &prime)
{
    if (prime.curr_exam_map.type != MAP_TYPE_NONE && prime.arriving_map.type != MAP_TYPE_NONE) {
    if (prime.examing_area.type != MAP_TYPE_NONE)
        return;
    DEBUG("----------------> %d", __LINE__);
    DEBUG("test %d",std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps).size());
    DEBUG("test %d",std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[0].points.size());
    DEBUG("test %f,%f",std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[0].points[1].X, std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[0].points[1].Y);
    {
        Line test;
        MAKE_LINE(test, std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[0].points[1], std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[0].points[0]);
        DEBUG("test %f,%f - %f,%f",test.p1.X, test.p1.Y, test.p2.X, test.p2.Y);
    }
    PointF &car_head = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->axial[AXIAL_FRONT]];
    PointF car_head_trend = PointExtend(car_head, 6, prime.pModeling->yaw);
    DEBUG("----------------> %d", __LINE__);
    PointF car_head = prime.pModeling[prime.curr_modeling_index].points[prime.pModel->axial[AXIAL_FRONT]];
    PointF car_head_trend = PointExtend(car_head, 8, prime.pModeling->yaw);
    DEBUG("----------------> %d", __LINE__);
    Line car_head_line;
    MAKE_LINE(car_head_line, car_head, car_head_trend);
    DEBUG("----------------> %d", __LINE__);
    Line start_line;
    for (int i = 0; i < prime.pMap->park_button_map.size(); ++i) {  // 左右2条控制线都可作为入口
        MAKE_LINE(start_line, prime.pMap->park_button_map[i].map[1], prime.pMap->park_button_map[i].map[0]);
        MAKE_LINE(start_line, prime.pMap->park_button_map[i].map[7], prime.pMap->park_button_map[i].map[6]);
    for (int i = 0; i < std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps).size(); ++i) {  // 左右2条控制线都可作为入口
        MAKE_LINE(start_line, std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[i].points[1], std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[i].points[0]);
        CheckProximity(prime, car_head_line, start_line, std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[i].id);
        MAKE_LINE(start_line, std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[i].points[7], std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[i].points[6]);
        CheckProximity(prime, car_head_line, start_line, std::get<MAP_TYPE_PARK_BUTTOM>(prime.maps)[i].id);
    }
    for (int i = 0; i < prime.pMap->park_edge_map.size(); ++i) {
        MAKE_LINE(start_line, prime.pMap->park_edge_map[i].map[1], prime.pMap->park_edge_map[i].map[0]);
    for (int i = 0; i < std::get<MAP_TYPE_PARK_EDGE>(prime.maps).size(); ++i) {
        MAKE_LINE(start_line, std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[i].points[1], std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[i].points[0]);
        CheckProximity(prime, car_head_line, start_line, std::get<MAP_TYPE_PARK_EDGE>(prime.maps)[i].id);
    }
    for (int i = 0; i < prime.pMap->uphill_map.size(); ++i) {
        PointF vPoint = Calc3Point(prime.pMap->uphill_map[i].map[8], prime.pMap->uphill_map[i].map[0], DistanceOf(prime.pMap->uphill_map[i].map[8], prime.pMap->uphill_map[i].map[7]), 'R');
        MAKE_LINE(start_line, prime.pMap->uphill_map[i].map[0], vPoint);
    for (int i = 0; i < std::get<MAP_TYPE_UPHILL>(prime.maps).size(); ++i) {
        MAKE_LINE(start_line, std::get<MAP_TYPE_UPHILL>(prime.maps)[i].points[0], std::get<MAP_TYPE_UPHILL>(prime.maps)[i].points[10]);
        CheckProximity(prime, car_head_line, start_line, std::get<MAP_TYPE_UPHILL>(prime.maps)[i].id);
    }
    for (int i = 0; i < prime.pMap->curve_map.size(); ++i) {
        MAKE_LINE(start_line, prime.pMap->curve_map[i].right_start_point, prime.pMap->curve_map[i].left_start_point);
    for (int i = 0; i < std::get<MAP_TYPE_CURVE>(prime.maps).size(); ++i) {
        MAKE_LINE(start_line, std::get<MAP_TYPE_CURVE>(prime.maps)[i].right_start_point, std::get<MAP_TYPE_CURVE>(prime.maps)[i].left_start_point);
        CheckProximity(prime, car_head_line, start_line, std::get<MAP_TYPE_CURVE>(prime.maps)[i].id);
    }
    for (int i = 0; i < prime.pMap->turn_a90_map.size(); ++i) {
        MAKE_LINE(start_line, prime.pMap->turn_a90_map[i].map[0], prime.pMap->turn_a90_map[i].map[1]);
    for (int i = 0; i < std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps).size(); ++i) {
        MAKE_LINE(start_line, std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[i].points[0], std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[i].points[1]);
        CheckProximity(prime, car_head_line, start_line, std::get<MAP_TYPE_RIGHT_CORNER>(prime.maps)[i].id);
    }
}
// 判断是否接近场地的起始线
// 车头趋势线是否和入口线相交
// 和入口线的夹角
static bool ProximityArea(Line &base_line, Line &line)
static void CheckProximity(prime_t  &prime, Line &base_line, Line &line, int this_id)
{
    PointF head = {.X = line.X1, .Y = line.Y1};
    ProximityStatus status;
    if (IntersectionOf(base_line, line) == GM_Intersection
        && DistanceOf(head, base_line) > 1) {
        double angle = AngleOfTowLine(base_line, line);
        if (angle >= 240 && angle <= 300) {
            return true;
    if (CrossingStartLine(base_line, line)) {
        PointF p1 = base_line.p1;
        PointF p2 = base_line.p2;
        // 增加距离,用于消除测量误差带来的不稳定
        if (DistanceOf(p1, line) > 0.5 && DistanceOf(p2, line) > 0.5) {
            status = ProximityStatus::Near;
        } else {
            status = ProximityStatus::Bounce;
        }
    } else {
        status = ProximityStatus::Far;
    }
    return false;
    if (status == ProximityStatus::Near && prime.arriving_map != this_id) {
        prime.arriving_map = this_id;
        // 报语音提示
        PlayTTS("即将考试", nullptr);
    } else if (status == ProximityStatus::Far && prime.arriving_map == this_id) {
        prime.arriving_map = -1;
    }
}
void TerminateAreaExam(void)
{
    CurrExamMapIndex = -1;
}
void InitAreaExam(void)
{
    CurrExamMapIndex = -1;
    ResetOdo();
}