lizhanwei
2020-03-20 97c46a7978d2be86b45e0c2dd8ba5244a9406b24
c文件添加个头文件
3个文件已修改
1个文件已添加
594 ■■■■■ 已修改文件
app/src/main/java/safeluck/drive/evaluation/fragment/NetWorkTrainFragment.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/fragment/RoadDriveMapFragment.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/fragment/RoadDriveMapFragmentaa.java 580 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
lib/src/main/cpp/test_items2/road_exam.cpp 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/fragment/NetWorkTrainFragment.java
@@ -23,8 +23,6 @@
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;
import com.anyun.exam.lib.AYSdk;
@@ -38,8 +36,6 @@
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import me.yokeyword.fragmentation.SupportFragment;
import safeluck.drive.evaluation.Constant;
@@ -69,9 +65,6 @@
import safeluck.drive.evaluation.platformMessage.JKMessage0204;
import safeluck.drive.evaluation.util.Utils;
import safeluck.drive.evaluation.viewmodels.TimeViewModel;
import safeluck.drive.evaluation.worker.TimeWorker;
import static androidx.work.PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS;
/**
 * 联网训练UI
app/src/main/java/safeluck/drive/evaluation/fragment/RoadDriveMapFragment.java
@@ -1,14 +1,11 @@
package safeluck.drive.evaluation.fragment;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
@@ -34,14 +31,11 @@
import me.yokeyword.fragmentation.SupportFragment;
import safeluck.drive.evaluation.Constant;
import safeluck.drive.evaluation.bean.ExamMap;
import safeluck.drive.evaluation.bean.RealTimeCarPos;
import safeluck.drive.evaluation.bean.RoadExamMap;
import safeluck.drive.evaluation.cEventCenter.CEventCenter;
import safeluck.drive.evaluation.cEventCenter.ICEventListener;
import safeluck.drive.evaluation.util.FileUtil;
import static android.view.View.LAYER_TYPE_SOFTWARE;
public class RoadDriveMapFragment extends SupportFragment implements SurfaceHolder.Callback {
app/src/main/java/safeluck/drive/evaluation/fragment/RoadDriveMapFragmentaa.java
New file
@@ -0,0 +1,580 @@
package safeluck.drive.evaluation.fragment;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import com.anyun.exam.lib.MyLog;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import me.yokeyword.fragmentation.SupportFragment;
import safeluck.drive.evaluation.Constant;
import safeluck.drive.evaluation.R;
import safeluck.drive.evaluation.bean.RealTimeCarPos;
import safeluck.drive.evaluation.bean.RoadExamMap;
import safeluck.drive.evaluation.cEventCenter.CEventCenter;
import safeluck.drive.evaluation.cEventCenter.ICEventListener;
import safeluck.drive.evaluation.util.CThreadPoolExecutor;
import safeluck.drive.evaluation.util.FileUtil;
public class RoadDriveMapFragmentaa extends SupportFragment {
    private static final int ALL_MAP = 100;
    private boolean isDrawing = false;
    private StringBuffer buffer;//存放地图的buffer
    private ICEventListener rtcmicEventListener = new ICEventListener() {
        @Override
        public void onCEvent(String topic, int msgCode, int resultCode, final Object obj) {
            if (msgCode == Constant.DEBUG_RTCM){
                CThreadPoolExecutor.runOnMainThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.i(TAG, "title="+(String)obj);
                        toolbar.setTitle((String)obj);
                    }
                });
            }
        }
    };
    private ICEventListener debugTxticEventListener = new ICEventListener() {
        @Override
        public void onCEvent(String topic, int msgCode, int resultCode, final Object obj) {
            if (msgCode == Constant.DEBUG_TXT){
                CThreadPoolExecutor.runOnMainThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.i(TAG, "subtitle="+(String)obj);
                        toolbar.setSubtitle((String)obj);
                    }
                });
            }
        }
    };
    private ICEventListener speedListener = new ICEventListener() {
        @Override
        public void onCEvent(String topic, int msgCode, int resultCode, Object obj) {
            if (msgCode == Constant.RTK_INFO){
                gpsSpeed = (double)obj;
            }
        }
    };
    public static SupportFragment newInstance() {
        return new RoadDriveMapFragmentaa();
    }
    private SurfaceView mSurfaceView;
    private static final String TAG = "RoadDriveFragment";
    private SurfaceHolder holder;
    Path path = new Path();
    private Canvas canvas;
    private int x = -1;
    private int y = -1;
    private Toolbar toolbar;
    private Bitmap bmp = null;
    private Canvas canvas2 = null;
    private Paint paint = null;
    private int screen_width = 0, screen_height = 0;
    private String osdHeading = null;
    private String osdMoveDirect = null;
    private String osdRtkSpeed = null;
    private String osdQf = null;
    private int map_id;
    private double gpsSpeed = 0;
    double allMap[][][];
    double map[][] = {{-2.4065, 30.7090}, {-3.0759, 30.3599}, { -2.6023, 29.2578}, {-3.3316,28.9383},{-3.8247,30.0293},
            {-3.4503,30.1946}, {-2.9669,29.0981}, { -3.6962, 28.7786}, {-4.1991, 29.8640}};
    double map_other[][] = {{-2.4065, 30.7090}, {-3.0759, 30.3599}, { -2.6023, 29.2578}, {-3.3316,28.9383},{-3.8247,30.0293},
            {-3.4503,30.1946}, {-2.9669,29.0981}};
    //    double map[][] ;
    double car[][] = {{8.278, 1.467}, {7.2780000000000009, 1.467}, {7.2780000000000009, -1.533}, {8.278, -1.533}
            , {9.278, -1.5330000000000004}, {9.277999999999999, 1.467000000000001}};
    Gson gson;
    private LinearLayout linearLayout;//surfaceview的父容器,为了移动surfaceview而使用,因为scrollto不能移动view,
    private LinkedBlockingQueue queue = new LinkedBlockingQueue(100);
    private ExecutorService producer = Executors.newSingleThreadExecutor();
    private ExecutorService consumer = Executors.newSingleThreadExecutor();
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.layout_mapfragment, container, false);
        gson = new Gson();
        initView(view);
        consumer.execute(new CalRunnable());
        return view;
    }
    private int avaliableHeight,avalibleWidth;
    private void initView(View view) {
        toolbar = view.findViewById(R.id.toolbar);
        toolbar.setTitle("简单地图");
        toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                _mActivity.onBackPressed();
            }
        });
        avaliableHeight= getResources().getDisplayMetrics().heightPixels;
        avalibleWidth = getResources().getDisplayMetrics().widthPixels;
        Log.i(TAG, "initView: aliwidht="+avalibleWidth+" height="+avaliableHeight);
        mSurfaceView = view.findViewById(R.id.surfaceview);
        holder = mSurfaceView.getHolder();
        holder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder surfaceHolder) {
                Canvas canvas = surfaceHolder.lockCanvas();
                if (canvas != null) {
                    Log.d(TAG, "W = " + canvas.getWidth() + " H = " + canvas.getHeight());
                    screen_width = canvas.getWidth();
                    screen_height = canvas.getHeight();
                    surfaceHolder.unlockCanvasAndPost(canvas);
                    bmp = Bitmap.createBitmap(screen_width, screen_height, Bitmap.Config.ARGB_8888);
                    canvas2 = new Canvas(bmp);
                    canvas2.drawColor(Color.WHITE);
                    paint = new Paint();
                    paint.setTextSize(30);
                    paint.setColor(Color.BLACK);
                    paint.setStrokeWidth(1.5f);
                    paint.setAntiAlias(true);
                    paint.setStyle(Paint.Style.STROKE);
                    holder.lockCanvas();
                    canvas.drawBitmap(bmp, 0, 0, paint);
                    holder.unlockCanvasAndPost(canvas);
                }
            }
            @Override
            public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
            }
            @Override
            public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            }
        });
    }
    public void DrawMap(List<Double> mainAnt, final double[][] map, final double[][] car,
                        List<Integer>body, List<Integer> tire, List<RoadExamMap.MapsBean> maps) {
        if (canvas2 == null || bmp == null) {
            return;
        }
        double base_x = 300, base_y = 20;
        double max_x = 0, min_x = 0, max_y = 0, min_y = 0;
        Log.d(TAG, "DrawMap map size " + map.length + " car size " + car.length);
        for (int i = 0; i < map.length; i++) {
            if (i == 0) {
                max_x = map[0][0];
                min_x = map[0][0];
                max_y = map[0][1];
                min_y = map[0][1];
            } else {
                if (max_x < map[i][0]) {
                    max_x = map[i][0];
                }
                if (min_x > map[i][0]) {
                    min_x = map[i][0];
                }
                if (max_y < map[i][1]) {
                    max_y = map[i][1];
                }
                if (min_y > map[i][1]) {
                    min_y = map[i][1];
                }
            }
        }
        if (map_other.length>9){
            for (int i = 0; i < map_other.length; i++) {
                if (max_x < map_other[i][0]) {
                    max_x = map_other[i][0];
                }
                if (min_x > map_other[i][0]) {
                    min_x = map_other[i][0];
                }
                if (max_y < map_other[i][1]) {
                    max_y = map_other[i][1];
                }
                if (min_y > map_other[i][1]) {
                    min_y = map_other[i][1];
                }
            }
        }
        Log.d(TAG, "DrawMap max_x " + max_x + " max_y " + max_y + " min_x " + min_x + " min_y " + min_y);
        for (int i = 0; i < car.length; i++) {
            if (max_x < car[i][0]) {
                max_x = car[i][0];
            }
            if (min_x > car[i][0]) {
                min_x = car[i][0];
            }
            if (max_y < car[i][1]) {
                max_y = car[i][1];
            }
            if (min_y > car[i][1]) {
                min_y = car[i][1];
            }
        }
        Log.d(TAG, "DrawMap max_x " + max_x + " max_y " + max_y + " min_x " + min_x + " min_y " + min_y);
        long scale_x = Math.round((screen_width - base_x - 10) / (max_x - min_x));
        long scale_y = Math.round((screen_height - base_y - 10) / (max_y - min_y));
        if (scale_x >= scale_y) {
            scale_x = scale_y;
        } else {
            scale_y = scale_x;
        }
        Log.d(TAG, "DrawMap scale_x " + scale_x + " scale_y " + scale_y);
        canvas2.drawColor(Color.WHITE);
        if (paint == null || canvas2==null){
            return;
        }
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setColor(Color.BLUE);
        canvas2.drawCircle((float) (base_x + (mainAnt.get(0) - min_x) * scale_x), (float) (base_y + (0 - mainAnt.get(1) - min_y) * scale_y), 2, paint);
        paint.setColor(Color.RED);
        canvas2.drawCircle((float) (base_x + (car[tire.get(0)][0] - min_x) * scale_x), (float) (base_y + (car[tire.get(0)][1] - min_y) * scale_y), 2.5f, paint);
        canvas2.drawCircle((float) (base_x + (car[tire.get(1)][0] - min_x) * scale_x), (float) (base_y + (car[tire.get(1)][1] - min_y) * scale_y), 2.5f, paint);
        canvas2.drawCircle((float) (base_x + (car[tire.get(2)][0] - min_x) * scale_x), (float) (base_y + (car[tire.get(2)][1] - min_y) * scale_y), 2.5f, paint);
        canvas2.drawCircle((float) (base_x + (car[tire.get(3)][0] - min_x) * scale_x), (float) (base_y + (car[tire.get(3)][1] - min_y) * scale_y), 2.5f, paint);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.BLACK);
        Path path = new Path();
        Log.i(TAG, "DrawMap: map.length:"+map.length);
        if (maps != null&& maps.size()>0){
            for (int i = 0; i < maps.size(); i++) {
                RoadExamMap.MapsBean mapItem = maps.get(i);
                if (mapItem.getItem() == ALL_MAP){
                    List<List<Integer>> redLines= mapItem.getRed_line();
                    List<List<Integer>> greenLines = mapItem.getGreen_line();
                    paint.reset();
                    paint.setStyle(Paint.Style.STROKE);
                    paint.setStrokeWidth(1.5f);
                    paint.setAntiAlias(true);
                    paint.setColor(Color.RED);
                    Log.i(TAG,"redLinesSize"+redLines.size());
                    for (List<Integer> redline: redLines
                    ) {
                        for (int j = 0; j < redline.size(); j++) {
                            Log.i(TAG,"redLiSize"+redline.size());
                            int pos = redline.get(j);
                            if (j == 0){
                                path.moveTo((float) (base_x + (map[pos][0] - min_x) * scale_x), (float) (base_y + (map[pos][1] - min_y) * scale_y));
                            }
                            path.lineTo((float) (base_x + (map[pos][0] - min_x) * scale_x), (float) (base_y + (map[pos][1] - min_y) * scale_y));
                            Log.i(TAG,String.format("map[%d][0]=%f,map[%d][1]=%f,line to (%f,%f)",pos,map[pos][0],pos,map[pos][1],
                                    (float) (base_x + (map[pos][0] - min_x) * scale_x),(float) (base_y + (map[pos][1] - min_y) * scale_y)));
                        }
                    }
//                    canvas2.drawPath(path,paint);
                    //画虚线(分道线)
                    paint.reset();
                    paint.setStyle(Paint.Style.STROKE);
                    paint.setStrokeWidth(1.5f);
                    paint.setAntiAlias(true);
                    paint.setColor(Color.WHITE);
                    paint.setPathEffect(new DashPathEffect(new float[] {15, 15}, 0));
                    for (List<Integer> greenline:
                            greenLines){
                        for (int j = 0; j < greenline.size(); j++) {
                            int pos = greenline.get(j);
                            if (j == 0){
                                path.moveTo((float) (base_x + (map[pos][0] - min_x) * scale_x), (float) (base_y + (map[pos][1] - min_y) * scale_y));
                            }
                            path.lineTo((float) (base_x + (map[pos][0] - min_x) * scale_x), (float) (base_y + (map[pos][1] - min_y) * scale_y));
                            Log.i(TAG,String.format("map[%d][0]=%f,map[%d][1]=%f,line to (%f,%f)",pos,map[pos][0],pos,map[pos][1],
                                    (float) (base_x + (map[pos][0] - min_x) * scale_x),(float) (base_y + (map[pos][1] - min_y) * scale_y)));
                        }
                    }
                    canvas2.drawPath(path,paint);
                }
            }
        }
        canvas2.drawPath(path, paint);
        path.moveTo((float) (base_x + (car[body.get(0)][0] - min_x) * scale_x), (float) (base_y + (car[body.get(0)][1] - min_y) * scale_y));
        for (int i = 1; i < body.size(); i++){
            Log.d(TAG, "for 循环 DrawMap to X = " + (float) (base_x + (car[body.get(i)][0] - min_x) * scale_x)+ " Y = " + (float) (base_y + (car[body.get(i)][1] - min_y) * scale_y));
            path.lineTo((float) (base_x + (car[body.get(i)][0] - min_x) * scale_x), (float) (base_y + (car[body.get(i)][1] - min_y) * scale_y));
        }
        path.close();
        canvas2.drawPath(path, paint);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        if (osdHeading != null) {
            Path pathText = new Path();
            pathText.moveTo(10, 170);
            pathText.lineTo(700, 170);
            canvas2.drawTextOnPath(osdHeading, pathText, 0, 0, paint);//逆时针生成
        }
        if (osdMoveDirect != null) {
            Path pathText = new Path();
            pathText.moveTo(10, 30);
            pathText.lineTo(700, 30);
            canvas2.drawTextOnPath(osdMoveDirect, pathText, 0, 0, paint);//逆时针生成
        }
        if (osdRtkSpeed != null) {
            Path pathText = new Path();
            pathText.moveTo(10, 240);
            pathText.lineTo(700, 240);
            canvas2.drawTextOnPath(osdRtkSpeed, pathText, 0, 0, paint);//逆时针生成
        }
        if (osdQf != null) {
            Path pathText = new Path();
            pathText.moveTo(10, 120);
            pathText.lineTo(700, 120);
            canvas2.drawTextOnPath(osdQf, pathText, 0, 0, paint);//逆时针生成
        }
        {
            BigDecimal bd = new BigDecimal(gpsSpeed);
            bd = bd.setScale(3, BigDecimal.ROUND_HALF_UP);
            Path pathText = new Path();
            pathText.moveTo(10, 70);
            pathText.lineTo(700, 70);
            canvas2.drawTextOnPath("GPS速度:" + bd, pathText, 0, 0, paint);//逆时针生成
        }
        // 提交画布
        Canvas canvas = holder.lockCanvas();
        if (canvas != null){
            canvas.drawBitmap(bmp, 0, 0, paint);
            holder.unlockCanvasAndPost(canvas);
        }
    }
    int line = 0;
    int map_line = 0;
    class MessageRemoteService{
        public int msgCode;
        public String json;
        public MessageRemoteService(int msgCode, Object obj) {
            this.json = (String) obj;
            this.msgCode = msgCode;
        }
    }
    RoadExamMap examMaps ;
    private ICEventListener icEventListener = new ICEventListener() {
        @Override
        public void onCEvent(String topic, final int msgCode, int resultCode, final Object obj) {
            producer.execute(new Runnable() {
                @Override
                public void run() {
                    queue.offer(new MessageRemoteService(msgCode,obj));
                }
            });
        }
    };
    boolean flag = true;
    class CalRunnable implements Runnable{
        private String json;
        private int cmd;
        @Override
        public void run() {
            while (flag) {
                MessageRemoteService messageRemoteService = (MessageRemoteService) queue.peek();
                if (messageRemoteService == null) {
                    Log.i(TAG, "messageRemoteService ==null");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                messageRemoteService = (MessageRemoteService) queue.poll();
                if (messageRemoteService != null) {
                    MyLog.i(TAG, messageRemoteService.json);
                    RealTimeCarPos timeCarPos = gson.fromJson((String) messageRemoteService.json, RealTimeCarPos.class);
                    List<Double> points = timeCarPos.getPoint();
                    switch (timeCarPos.getMove()) {
                        case 0:
                            osdMoveDirect = "停车";
                            break;
                        case 1:
                            osdMoveDirect = "前进";
                            break;
                        case -1:
                            osdMoveDirect = "后退";
                            break;
                    }
                    osdHeading = "方向角" + String.valueOf(timeCarPos.getHeading());
                    BigDecimal bd = new BigDecimal(timeCarPos.getSpeed());
                    bd = bd.setScale(3, BigDecimal.ROUND_HALF_UP);
                    osdRtkSpeed = "计算速度:" + bd;
                    osdQf = "QF:" + String.valueOf(timeCarPos.getQf());
                    car = new double[points.size() / 2][2];
                    for (int i = 0; i < points.size(); i++) {
                        if ((i % 2) == 0) {
                            car[line][0] = points.get(i);
                        } else {
                            double value = 0 - points.get(i);
                            car[line][1] = value;
                            line++;
                        }
                    }
                    map_id = timeCarPos.getMap_id();
                    List<Double> mainAnt = timeCarPos.getMain_ant();
                    List<Integer> tire1 = timeCarPos.getLeft_front_tire();
                    List<Integer> tire2 = timeCarPos.getRight_front_tire();
                    List<Integer> tire3 = timeCarPos.getLeft_rear_tire();
                    List<Integer> tire4 = timeCarPos.getRight_rear_tire();
                    List<Integer> body = timeCarPos.getBody();
                    List<Integer> tire = new ArrayList<>();
                    tire.add(tire1.get(0));
                    tire.add(tire2.get(0));
                    tire.add(tire3.get(0));
                    tire.add(tire4.get(0));
                    if (buffer == null) {
                        buffer = FileUtil.readAssetTxtFile(_mActivity, Constant.ROAD_MAP);
                        Log.i(TAG, "ditu=" + buffer.toString().trim());
                    }
                    Type type = new TypeToken<RoadExamMap>() {
                    }.getType();
                    if (buffer != null) {
                        examMaps = gson.fromJson(buffer.toString().trim(), type);
                    }
                    if (examMaps != null) {
                        points = examMaps.getPoints();
                        if (points != null) {
                            map = new double[points.size() / 2][2];
                            for (int i = 0; i < points.size(); i++) {
                                if ((i % 2) == 0) {
                                    map[map_line][0] = points.get(i);
                                } else {
                                    double value = 0 - points.get(i);
                                    map[map_line][1] = value;
                                    map_line++;
                                }
                            }
                        }
                    }
                    DrawMap(mainAnt,map, car, body, tire,  examMaps.getMaps());
                }
            }
        }
    }
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        CEventCenter.onBindEvent(true, icEventListener, Constant.REAL_TIME_POS_CAR_TOPIC);
        CEventCenter.onBindEvent(true, rtcmicEventListener, Constant.BIND_RTCM_TOPIC);
        CEventCenter.onBindEvent(true, debugTxticEventListener, Constant.BIND_DEBUG_TXT);
        CEventCenter.onBindEvent(true, speedListener, Constant.BIND_RTK_SPEED_TOPIC);
    }
    @Override
    public void onDetach() {
        super.onDetach();
        flag = false;
        producer.shutdown();
        consumer.shutdown();
        CEventCenter.onBindEvent(false, icEventListener, Constant.REAL_TIME_POS_CAR_TOPIC);
        CEventCenter.onBindEvent(false, icEventListener, Constant.BIND_RTCM_TOPIC);
        CEventCenter.onBindEvent(false, icEventListener, Constant.BIND_DEBUG_TXT);
        CEventCenter.onBindEvent(false, speedListener, Constant.BIND_RTK_SPEED_TOPIC);
    }
}
lib/src/main/cpp/test_items2/road_exam.cpp
@@ -14,6 +14,7 @@
#include <vector>
#include <list>
#include <string>
#include <cstdlib>
#define DEBUG(fmt, args...)     LOGD("<road_exam> <%s>: " fmt, __func__, ##args)