Amap【高德】/Google-开发,无人机航迹规划演示

   
ps:又到了周五,才有时间来写点博客记录下,这篇文章的所描述的内容是我2017年后 做的一个功能,也是我们的产品经理结合 航迹规划 以及我们所提供的 能做到的一些地图开发结合,做的一个自创性的 开发吧。其实开始做的时候挺不自信的,因为第一,地图sdk 并不是非常了解,再说,里面有好多效果和功能  ,主要是一个动态修改航点和航线这个效果,在评估的时候,着实让我觉得头疼。而且领导还说项目很急,让我一周把航迹规划和电子围栏的开发 做完,我和ios 当初可是评估后给了 3个星期的工作日的。他要我们一周搞完,心里挺虚的。 本身博主就是个菜鸡,毕业才半年,虽说在公司实习到现在有一年了,但是毕竟改变不了菜的现实。没办法,顶头干吧。在开发中,越搞越happay  ,常常加班到11点,觉得蛮有意思的,显然不是纯粹的使用地图的简单功能来完成开发的,而是有点难度的。听意外的,4个工作日,就把航迹规划和电子围栏 搞完了。满有成就感的。

 博主以前是学文科的,废话有点多,不要见怪。整个效果展示的比较长,但是呢,gif 又只能上传2M 的图,无奈只能一个一个截取了。fps 设置的也有点低,没办法,gif 2M 实在太小。将就看吧。


1.

2.

3.


一:这次只展示 航迹规划这一个项目,电子围栏,我已经在之前文章中写过了。

二:本次功能要点我做个简单的阐述。

①.要分清楚 你需要建立几个集合 分别是:lList<Latlng>,List<Marker>,List<PolyLine>,代表的分别是,坐标点,标记点,航线。

②.在UI 给的图片上 绘制 标号,技术好的应该都会,我下面会把代码贴出来

③.就是吧Marker的.draggable(true),前提 先吧拖拽功能打开。才可以操作

④重点是这个 线拖拽的问题,分别位2种情况

1)例如图一  在没有2 出现的情况下只有一种情况,拖拽 marker 1 将 线一拖动,

2)例如2 在拖拽2的时候会牵扯到 2根线,2根线要同步刷新。

3)额外说的一个,我的电子围栏中 更复杂一点,比如第一个点生成。 逻辑都和这个一样,但是在最后一根线的时候,他要围城一个围栏,在没围成之前,拖拽marker 1的时候 只有一根线,拖拽2 会有2根,拖拽最后一个Marker 也只有一根,但是一旦确认 围栏 形成,最后一个Marker会和第一个Marker 产生一条线,这时候在拖拽 1和最后一个marker 就需要联动,所有的点都是 2根线 在动。这个 就从代码上没什么技术含量,但是逻辑上 需要思考好多。这次就不说这个,我下面会把代码贴出来。



开始贴代码了。

重点的几个说完 就直接把所有的贴出来。

 private ArrayList<LatLng> mPfLatLngList = new ArrayList<>(); // latlng的数量比marker的数量多一,因为当前位置坐标也记录下来了
    private ArrayList<PathPlanBean> uploadList = new ArrayList<>(); //上传航迹规划列表的集合
    private ArrayList<Marker> mPfMarkerList = new ArrayList<>();
    private ArrayList<Polyline> mPfPolylineList = new ArrayList<>();
    
 /**
     * Marker地图点击监听事件
     *
     * @param latLng
     */
    @Override
    public void onMapClick(LatLng latLng) {
        LatLng curLatlng = latLng;
        // 航迹规划
        if (isOpenFlightRoutePlan && mPfMarkerList.size() < 50 && isWayPointMode_state == GduConfig.FpClose) {
            LatLng lastLatlng;
            if (!mPfLatLngList.isEmpty()) { // 这里判断不为空,是保证已经 有飞机的坐标点 已经添加
                if (AMapUtils.calculateLineDistance(currentphoneLatlng, curLatlng) > fp_validityRange) {
                    txhToast.show(getString(R.string.Label_Map_FlightRoute_flightpoit_invalidation));
                } else {
                    int tagNum = mPfLatLngList.size();//Marker 数_标
                    mPfMarkerList.add(mapMarkerTool.addPfMarker(curLatlng, tagNum));
                    mPfLatLngList.add(curLatlng);
                    mIv_Fp_state.setImageResource(R.drawable.bg_map_fp_go);
                    if (tagNum == 1) {
                        LatLng droneLat = mPfLatLngList.get(0);
                        mPfPolylineList.add(mapMarkerTool.addPolyDottedLine(droneLat, curLatlng));
                        mPfFlightDisList.add(calculateFlightDist(droneLat, curLatlng));
                    } else if (tagNum > 1) {
                        lastLatlng = mPfLatLngList.get(mPfLatLngList.size() - 2);
                        mPfPolylineList.add(mapMarkerTool.addPolyDottedLine(lastLatlng, curLatlng));
                        mPfFlightDisList.add(calculateFlightDist(lastLatlng, curLatlng));
                    }
                    setEraserState(true);//有Marker增加时候
                }
            }
        } else if (isOpenFlightRoutePlan && mPfMarkerList.size() == 50 && isWayPointMode_state == GduConfig.FpClose) {
            txhToast.show(getString(R.string.Label_Map_FlightRoute_flightpoit_overflow));
        } else if (isOpenFlightRoutePlan && mPfMarkerList.size() < 50 && isWayPointMode_state == GduConfig.FpGo) {
            // 即当开始航迹规划,在点击地图,无响应,不增加点
        }

在地图上增加点 必须在onMapClick 中操作,在onMapClick 获取最基本的Latlng 数据,并绘制 航线。

add  Marker 

 /**
     * <p>根据经纬度往地图上添加marker</p>
     * <p>[航迹规划]</p>
     *
     * @param lagLng    当前点击的 下的坐标
     * @param markerNum 计数
     * @return
     */
    public Marker addPfMarker(LatLng lagLng, int markerNum) {
     MarkerOptions options= options = new MarkerOptions().draggable(true);
        options.anchor(0.5f, 1f)
                .position(lagLng)
                .icon(BitmapDescriptorFactory.fromBitmap(getBitMap(markerNum)));

        return aMap.addMarker(options);
    }

add  PolyLine

 /**
     * <p>绘制两点之间线段</p>
     * <p>虚线</p>
     *
     * @param beginlatLng 起点
     * @param endLatLng   终点
     * @return
     */
    public Polyline addPolyDottedLine(LatLng beginlatLng, LatLng endLatLng) {

        PolylineOptions options = new PolylineOptions();
        options.add(beginlatLng, endLatLng)
                .width(10)
                .color(Color.rgb(255, 121, 24))
                .setDottedLine(true);// 虚线

        return aMap.addPolyline(options);
    }

计算距离:

    /**
     * <p>计算总的飞行距离</p>
     *
     * @param beginlatLng
     * @param endLatLng
     */
    private float calculateFlightDist(LatLng beginlatLng, LatLng endLatLng) {
        float onceDist = AMapUtils.calculateLineDistance(beginlatLng, endLatLng);
        AllFlightDist += onceDist;
        DecimalFormat df = new DecimalFormat("##.#");
        mTv_flightdis.setText(df.format(AllFlightDist) + StringUtils.getUnit());
        return Float.parseFloat(df.format(AllFlightDist));
    }

这是基本的 添加数据 在地图上显示,下面就让他来动起来吧。

设置监听。

    private void initGuideMap(AMap aMap) {
        // 设置marker可拖拽事件监听器
        aMap.setOnMarkerDragListener(this);
        // 设置显示marker信息监听,要想显示信息必须注册
//        aMap.setInfoWindowAdapter(this);
        aMap.setOnMarkerClickListener(this);
//        aMap.setOnInfoWindowClickListener(this);
        // 初始化Marker配置
        options = new MarkerOptions().draggable(true);
    }
 
监听回调:

/**
     * <p>Marker 拖拽开始监听</p>
     * <li>增加振荡器</li>
     * <li>获取当前Marker 的起始坐标并保存</li>
     * <li>作用:当不满足条件的时候,就可以使用起点坐标</li>
     *
     * @param marker
     */
    private LatLng curMarkerPosition;

    @Override
    public void onMarkerDragStart(Marker marker) {
        Vibrator vibrator = (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);
        vibrator.vibrate(150);
        if (isPfMode == GduConfig.FpMode) {
            for (int i = 0; i < mPfMarkerList.size(); i++) {
                if (marker.equals(mPfMarkerList.get(i))) {
                    curMarkerPosition = mPfLatLngList.get(i + 1);
                }
            }
        } else if (isPfMode == GduConfig.ErMode) {
            for (int i = 0; i < mErMarkerList.size(); i++) {
                if (marker.equals(mErMarkerList.get(i))) {
                    curMarkerPosition = mErLatLngList.get(i);
                }
            }
        }
    }

    /**
     * <p>拖拽过程中的监听</p>
     *
     * @param marker
     */
    @Override
    public void onMarkerDrag(Marker marker) {
        drawTrackLine(marker);// 正常的Marker监听中
    }

    /**
     * <p>拖拽完成后的监听</p>
     * <li>当状态为:航迹规划进行中/电子围栏已启动 ,拖动点回归原点</li>
     * <li>拖拽完成后检查是否超过2000的判定</li>
     *
     * @param marker
     */
    @Override
    public void onMarkerDragEnd(Marker marker) {
        // 模式开启,飞机在执行 指令操作,所有的点都不能生效

        if (isWayPointMode_state == GduConfig.FpGo || isWayPointMode_state == GduConfig.FpGoOn || isElectronicRail_state == GduConfig.ErStart) {
            BackDraggablePoint(marker);// 当前是:航迹规划状态/电子围栏状态
            return;
        }
        if (isPfMode == GduConfig.FpMode && AMapUtils.calculateLineDistance(mPfLatLngList.get(0), marker.getPosition()) > fp_validityRange) {
            txhToast.show(context.getString(R.string.Label_Map_FlightRoute_flightpoit_invalidation));
            BackDraggablePoint(marker);// 就是超过2000米 的判断
        }
    }

继续 上一个 代码中的方法

 /**
     * <p>画航线</p>
     * <li>第一:分航迹规划模式和围栏模式</li>
     * <li>第二:围栏模式分:围栏模式已经启动 -实线情况,围栏模式未启动 -虚线情况</li>
     * <li>第三:围栏模式拖拽:分几个特殊点 ① 起点 ②中间点 ③ 终点 </li>
     * <li>第四:围栏模式拖拽:没启动围栏模式前,是没有最后一根线的,也就是说 5个点四根线 可拖拽的效果也是要分情况的 </li>
     * <li>不仅在拖拽的时候要实况改变预设航线,</li>
     * <li>还要在拖拽结束的时候判断是否满足航线规划的要求</li>
     * <li>满足就按照用户的定义的来,不满足就要回到起始点</li>
     */
    private void drawTrackLine(Marker marker) {
        if (isPfMode == GduConfig.FpMode) { // 航迹规划
            boolean isExceed = AMapUtils.calculateLineDistance(mPfLatLngList.get(0), marker.getPosition()) > fp_validityRange;
            outofrangeCircle(isExceed);
            for (int i = 0; i < mPfMarkerList.size(); i++) {
                if (marker.equals(mPfMarkerList.get(i))) {
                    mPfLatLngList.set(i + 1, marker.getPosition()); // 第一个点是无人机的点,所以要  +1 ;
                    mPfPolylineList.get(i).remove();
                    mPfPolylineList.set(i,
                            addPolyDottedLine(mPfLatLngList.get(i),        //虚线
                                    mPfLatLngList.get(i + 1)));

                    if (i < mPfMarkerList.size() - 1) {
                        mPfPolylineList.get(i + 1).remove();
                        mPfPolylineList.set(i + 1,
                                addPolyDottedLine(mPfLatLngList.get(i + 1),//虚线
                                        mPfLatLngList.get(i + 2)));
                    }
                    updateFlightDisEvent(i, marker);//实况更新飞行距离的事件
                    return;
                }
            }
        } else if (isPfMode == GduConfig.ErMode) { // 电子围栏
            for (int i = 0; i < mErMarkerList.size(); i++) {
                if (marker.equals(mErMarkerList.get(i))) {
                    if (mErMarkerList.size() > 1) {
                        mErLatLngList.set(i, marker.getPosition());// 没有无人机的点,所以就按照第0点来
                        // 一根线  (点的后面那根)
                        if (isElectronicRail_state == GduConfig.ErStart) {   // 已经开启电子围栏模式
                            if (i == mErMarkerList.size() - 1) {  // 【特殊点】移动的是最后一个点就是【起点】,手动添加的 Polyline
                                mErPolylineList.get(i).remove();
                                mErPolylineList.set(i,
                                        addPolySolidLine(mErLatLngList.get(i),//实线
                                                mErLatLngList.get(0)));
                            } else {          // 移动的不是最后一个点
                                mErPolylineList.get(i).remove();
                                mErPolylineList.set(i,
                                        addPolySolidLine(mErLatLngList.get(i),//实线
                                                mErLatLngList.get(i + 1)));
                            }
                        } else {                       // 没有开启电子围栏
                            if (i < mErPolylineList.size()) {
                                mErPolylineList.get(i).remove();
                                mErPolylineList.set(i,
                                        addPolyDottedLine(mErLatLngList.get(i),//虚线
                                                mErLatLngList.get(i + 1)));
                            }
                        }
                        // 二根线  (点的后前面那根)
                        if (isElectronicRail_state == GduConfig.ErStart) {  // 已经开启电子围栏模式
                            if (i == 0) {     //【特殊点】 移动终点
                                mErPolylineList.get(mErPolylineList.size() - 1).remove();
                                mErPolylineList.set(mErPolylineList.size() - 1,
                                        addPolySolidLine(mErLatLngList.get(i), //实线
                                                mErLatLngList.get(mErLatLngList.size() - 1)));
                            } else {
                                mErPolylineList.get(i - 1).remove();
                                mErPolylineList.set(i - 1,
                                        addPolySolidLine(mErLatLngList.get(i),//实线
                                                mErLatLngList.get(i - 1)));
                            }
                        } else {
                            if (i > 0) {
                                mErPolylineList.get(i - 1).remove();
                                mErPolylineList.set(i - 1,
                                        addPolyDottedLine(mErLatLngList.get(i),//虚线
                                                mErLatLngList.get(i - 1)));
                            }
                        }
                        return;
                    }
                }
            }
        }
    }

继续上一个代码的方法

 /**
     * <p>回到拖拽的起点</p>
     * <li>当不满足要求的时候,就会回到起始点</li>
     *
     * @param marker
     */
    private void BackDraggablePoint(Marker marker) {
        marker.setPosition(curMarkerPosition);
        drawTrackLine(marker);// 不满足要求
    }
然后就是 有效域的判定
 我其实是事先做了2个 有效域  的圆形,根据 地图的 距离计算,当大于2000 就隐藏第一个圆形 显示下一个圆形,如果第二个没有
就新建,如果存在就 显示,
 boolean isExceed = AMapUtils.calculateLineDistance(mPfLatLngList.get(0), marker.getPosition()) > 2000;
有效域
 circle = aMap.addCircle(new CircleOptions()
                        .center(latLng)
                        .radius(fp_validityRange)
                        .fillColor(Color.argb(26, 0, 120, 255))  // 填充域颜色
                        .strokeColor(Color.argb(102, 0, 160, 233))// 边框颜色
                        .strokeWidth(2));
警告域
 /**
     * <p>是否超出有效域,超出2000 有效域变色</p>
     * <p>是超出范围的圈/p>
     */
    public void outofrangeCircle(boolean isExceed) {
        if (warning_circle == null) {
            warning_circle = aMap.addCircle(new CircleOptions()
                    .center(currentphoneLatlng)
                    .radius(fp_validityRange)
                    .fillColor(Color.argb(26, 255, 199, 65))  // 填充域颜色
                    .strokeColor(Color.argb(102, 255, 199, 65))// 边框颜色
                    .strokeWidth(2));
        }
        if (isExceed) {
            warning_circle.setVisible(true);
            normal_circle.setVisible(false);
        } else {
            normal_circle.setVisible(true);
            warning_circle.setVisible(false);
        }
    }

基本 的重点都讲完了,下面是我完整的 java 文件

GuideMapFragment.java
package com.gdu.mvp_view.flightRouteplan;

import android.app.Fragment;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMap;
import com.amap.api.maps.AMapOptions;
import com.amap.api.maps.AMapUtils;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.LocationSource;
import com.amap.api.maps.TextureMapView;
import com.amap.api.maps.UiSettings;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.Circle;
import com.amap.api.maps.model.CircleOptions;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MyLocationStyle;
import com.amap.api.maps.model.Polyline;
import com.gdu._enum.ConnStateEnum;
import com.gdu.beans.PathPlanBean;
import com.gdu.config.GduConfig;
import com.gdu.config.GlobalVariable;
import com.gdu.config.UavStaticVar;
import com.gdu.event.PfMostDisEvent;
import com.gdu.mvp_view.application.GduApplication;
import com.gdu.mvp_view.flightRouteplan.helper.GPSTranslateGuide;
import com.gdu.mvp_view.flightRouteplan.helper.UpDroneCurLocation;
import com.gdu.phonedrone.R;
import com.gdu.socket.GduFrame;
import com.gdu.socket.GduMapComm;
import com.gdu.socket.GduSocketConfig;
import com.gdu.socket.SocketCallBack;
import com.gdu.util.AnimationUtils;
import com.gdu.util.BBLog;
import com.gdu.util.DialogUtils;
import com.gdu.util.SPUtils;
import com.gdu.util.StringUtils;
import com.gdu.util.ToastFactory;
import com.gdu.util.YhLog;
import com.gdu.util.dialog.BlackGeneralDialog;
import com.gdu.util.dialog.GeneralDialog;
import com.gdu.views.AngelaTXHToast;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import de.greenrobot.event.EventBus;

/**
 * Created by shangbeibei on 2017/4/20.
 * <p>航迹规划--高德地图</p>
 */
public class GuideMapFragment extends Fragment implements
        AMap.OnMapLoadedListener
        , View.OnClickListener
        , LocationSource     // 回调监听
        , AMapLocationListener //定外监听
        , AMap.OnMapClickListener {

    // init GuideMapFragment  mapview
    private AMap aMap;
    // init MapUtils
    private GuideMapMarkerTool mapMarkerTool;
    // init 定位样式,定位蓝点
    private MyLocationStyle myLocationStyle;
    //声明AMapLocationClient类对象
    public AMapLocationClient mLocationClient = null;
    //声明mLocationOption对象
    public AMapLocationClientOption mLocationOption = null;
    //重要的地图工具,有 比例尺,有logo位置  有 缩放按钮, 指南针。滑动手势,缩放手势
    private UiSettings mUiSettings;
    private OnLocationChangedListener mListener;//定位成功回调
    // 定位当前手机的位置
    private LatLng currentphoneLatlng;
    // 有效域 圆
    private Circle circle;
    // 无效域 圆
    private Circle warning_circle;
    // 航迹规划 【有效域范围】半径
    public static int fp_validityRange = 2000;

    //  init GuideMapFragment view
    private static GuideMapFragment guideMapFragment;
    private View view;
    // 高德地图
    private TextureMapView mMapView;
    // 地图控制台
    private RelativeLayout mRl_MapControlPanel;
    // 清除航线规划
    private ImageView mIv_fp_cleanroutePlan;
    // 电子围栏
    private ImageView mIv_electronicRail_on2off;
    // 航迹规划的开关
    private ImageView mIv_flightPlan_on2off;
    // 隐藏控制台 iocn
    private ImageView mIv_hide_controlpanel;
    // 显示控制台 icon
    private ImageView mIv_show_controlpanel;
    // 地图定位回调
    private ImageView mIv_fp_maplocation;
    // 航迹规划的状态
    private ImageView mIv_Fp_state;
    // 电子围栏的状态
    private ImageView mIv_Er_state;
    // 地图样式切换 button
    private ImageView mIv_switch_mapstyle;
    // 地图切换 样式 的layout 选项框
    private LinearLayout mll_switch_maplayout;
    // (热区域)点击地图样式,普通地图
    private LinearLayout mll_click_mapstyle_normal;
    //  (热区域)点击地图样式,卫星地图
    private LinearLayout mll_click_mapstyle_satellite;
    // 点击后,普通地图样式被选择的background 变化
    private LinearLayout mll_bg_maptype_normal;
    // 点击后,卫星地图样式被选择的background 变化
    private LinearLayout mll_bg_maptype_satellite;
    // 点击后,普通地图 Text 文字 颜色变化
    private TextView mTv_mapstyle_normal;
    //点击后,卫星地图 Text 文字 颜色变化
    private TextView mTv_mapstyle_satellite;
    // 飞行距离 layout (显示/隐藏)
    private LinearLayout mll_flight_distance;
    // 飞行距离 Values 的显示
    private TextView mTv_flightdis;
    //init  Tools
    //更新无人机当前位置
    private UpDroneCurLocation updronelocation;
    //实时控制页面下滑提示
    private AngelaTXHToast txhToast;
    // init  list (航迹规划)
    private ArrayList<LatLng> mPfLatLngList = new ArrayList<>(); // latlng的数量比marker的数量多一,因为当前位置坐标也记录下来了
    private ArrayList<PathPlanBean> uploadList = new ArrayList<>(); //上传航迹规划列表的集合
    private ArrayList<Marker> mPfMarkerList = new ArrayList<>();
    private ArrayList<Polyline> mPfPolylineList = new ArrayList<>();
    private ArrayList<Float> mPfFlightDisList = new ArrayList<>();
    private ArrayList<Polyline> mReceivePolylineList = new ArrayList<>();
    //    private ArrayList<TSMWayPoint> tswayPoints = new ArrayList<>();
//    private ArrayList<TSMFlightFencePoint> fencePoints = new ArrayList<>();
    // init  list (电子围栏)
    private ArrayList<LatLng> mErLatLngList = new ArrayList<>();
    private ArrayList<Marker> mErMarkerList = new ArrayList<>();
    private ArrayList<Polyline> mErPolylineList = new ArrayList<>();
    // init data
    // 是否可以收到飞机的下发航点,表示飞机gps 没有问题。
    private boolean ishasReceiveLatlng;
    // 是否开启航迹规划
    private boolean isOpenFlightRoutePlan = false;
    // 是否处于航迹规划进行的状态中(正在按照规划飞行)
    public static int isWayPointMode_state;
    // 是否开启电子围栏
    private boolean isOpenElectronicRail = false;
    // 是否处于电子围栏 状态中(已经上传点,开始飞行)
    public static int isElectronicRail_state;
    //飞行距离的总规划长度
    private double AllFlightDist;
    private double preLat;
    private double prelon;
    private GduMapComm gduMapComm;
    private final int UPLOAD_PATH_OK = 2;
    private final int UPLOAD_PATH_FAILE = 3;
    private final int ROUTE_PLANE_DOING = 4;
    private final int ROUTE_PLANE_PAUSE = 5;
    private final int ROUTE_PLANE_COMPLETE = 6;
    private final int ROUTE_PLANE_FAILE = 7;
    private final int START_ROUTE = 8;
    private final int NO_ROUTE = 9;
    private final int IN_WALL = 10;
    private final int OUT_WALL = 11;
    private final int CLEAR_WALL = 12;
    private final int EXIT_WALL = 13;
    private final int INVADITE_WALL = 14;
    private boolean isRoutePlane;
    private Timer timer;
    private boolean timeUP;
    private DialogUtils dialogUtils;

    public static synchronized GuideMapFragment getInstance() {
        if (guideMapFragment == null) {
            guideMapFragment = new GuideMapFragment();
        }
        return guideMapFragment;
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_guide_map_layout, null);
        initFindView();
        initAmap(savedInstanceState);
        initAmapListener();
        initTools();
        initListener();
        gduMapComm = new GduMapComm(GduApplication.getSingleApp().gduCommunication.getGduSocket());
        return view;
    }


    /**
     * @author yuhao
     * <p/>
     * 初始化飞机的位置
     */
    private void initPlanePosotion() {
        GlobalVariable.GPS_Lat = 40.043519f;
        GlobalVariable.GPS_Lon = 116.291275f;  //TODO测试无人机坐标为定值

        YhLog.LogE("GlobalVariable.latitude=" + GlobalVariable.GPS_Lat);
        YhLog.LogE("GlobalVariable.longitude=" + GlobalVariable.GPS_Lon);
        LatLng latLng1 = GPSTranslateGuide.transform2Mars(GlobalVariable.GPS_Lat, GlobalVariable.GPS_Lon);  //大地坐标转火星坐标
        currentphoneLatlng = new LatLng(GlobalVariable.GPS_Lat, GlobalVariable.GPS_Lon);
        aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng1, 20));
        updronelocation.refreshDroneLocation(latLng1);// 更新无人机 Marker 位置
        // 保存当前 手机定位 并增加到 mPfLatLngList
        addDroneLocation();
    }


    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.iv_switch_map_icon://地图样式切换
                //TODO测试需要把切换按钮改成确认航迹起飞的按钮
                sureFly();
//                showMapTypeWindow();
                break;
            case R.id.ll_mapstyle_normal_layout://normal 点击
                switchMapStyle(view);
                break;
            case R.id.ll_mapstyle_satellite_layout://satellite 点击
                switchMapStyle(view);
                break;
            case R.id.iv_flightplan_on2off://航迹规划开启/关闭
                initFlightPlanEvent();
                break;
            case R.id.iv_electronic_rail://电子围栏 开启/关闭
                initElectronicRail();
                break;
            case R.id.iv_flightplan_clean_route://清除航迹规划
                CleanflightplanRoute();
                break;
            case R.id.iv_mapview_location://定位
                if (currentphoneLatlng != null) {
                    aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentphoneLatlng, 16));//V2.0
                } else {
                    txhToast.show(getString(R.string.Label_Map_FlightRoute_unrecive_plan));
                }
                break;
            case R.id.iv_map_right_menu_hide://隐藏地图控制台
                initControlPanelAnimation(false);
                break;
            case R.id.iv_map_right_menu_show://显示地图控制台
                initControlPanelAnimation(true);
                break;
            case R.id.iv_flightplan_state://航迹规划状态
                initFpState_on2off();
                break;
            case R.id.iv_ElectronicRail_state://电子围栏状态
                initErState_on2off();
                break;
        }
    }

    /**
     * <p>开始,电子围栏事件</p>
     */
    private void initElectronicRail() {
//        if (WifiConnConfig.IS_LINK_DRONE == WifiConnConfig.ConnType.Conn_Sucess && ishasReceiveLatlng) {// 测试关闭
        if (true && currentphoneLatlng != null) {
            if (!isOpenElectronicRail) {
                isOpenElectronicRail = true;
                //开启电子围栏
                mapMarkerTool.isPfMode(GduConfig.ErMode);
                mIv_Er_state.setVisibility(View.VISIBLE);
                mIv_Er_state.setImageResource(R.drawable.icon_map_er_start_gray);
                mIv_electronicRail_on2off.setImageResource(R.drawable.bg_map_electronic_on);
                txhToast.show(getString(R.string.Label_Map_ElectronicRail_Event_on));
                //航迹规划需要禁掉
                mIv_flightPlan_on2off.setImageResource(R.drawable.icon_path_planning_no);
                mIv_flightPlan_on2off.setEnabled(false);
            } else if (isOpenElectronicRail) {
                isOpenElectronicRail = false;
                mapMarkerTool.isPfMode(GduConfig.NoMode);
                mapMarkerTool.cleanPolygonCover();// 清除围栏Cover
                mIv_Er_state.setVisibility(View.GONE);
                mIv_electronicRail_on2off.setImageResource(R.drawable.bg_map_electronic_off);
                txhToast.show(getString(R.string.Label_Map_ElectronicRail_Event_off));
                //航迹规划需要开启
                mIv_flightPlan_on2off.setImageResource(R.drawable.bg_map_fp_off);
                mIv_flightPlan_on2off.setEnabled(true);
                // 地图可以再次添加Marker
                isElectronicRail_state = GduConfig.ErClose;
                ClearMap();//再次点击电子围栏 -清除
            }
        } else if (currentphoneLatlng != null) {
            if (GlobalVariable.connStateEnum == ConnStateEnum.Conn_None)
                txhToast.show(getString(R.string.DeviceNoConn));
            else if (GlobalVariable.connStateEnum == ConnStateEnum.Conn_MoreOne)
                txhToast.show(getString(R.string.Label_ConnMore));
        } else if (currentphoneLatlng == null) {
            txhToast.show(getString(R.string.Label_Map_FlightRoute_unrecive_plan));
        }
    }

    /**
     * <p>连接最后一根线,扩展出来一个不规则矩形</p>
     */
    private void connLastLine() {
        //先清除 虚线 换成 实体线
        for (int i = mErPolylineList.size() - 1; i > -1; i--) {
            mErPolylineList.get(i).remove();
            mErPolylineList.remove(i);
        }
        //在增加实体线
        for (int i = 1; i <= mErLatLngList.size(); i++) {
            if (i == mErLatLngList.size()) {
                mErPolylineList.add(mapMarkerTool.addPolySolidLine(mErLatLngList.get(mErLatLngList.size() - 1), mErLatLngList.get(0)));
            } else {
                mErPolylineList.add(mapMarkerTool.addPolySolidLine(mErLatLngList.get(i - 1), mErLatLngList.get(i)));
            }
        }
    }

    /**
     * <p>开始,航迹规划事件</p>
     */
    private void initFlightPlanEvent() {
//        boolean isflyhint = SPUtils.getBoolean(getActivity(), SPUtils.ISFlyHint);
//        if (WifiConnConfig.IS_LINK_DRONE == WifiConnConfig.ConnType.Conn_Sucess && ishasReceiveLatlng) {// 测试关闭
        if (true && currentphoneLatlng != null) {
            if (!isOpenFlightRoutePlan) {
//                if (!isflyhint) openRoutePlanDialog();
                isOpenFlightRoutePlan = true;
                //开启航迹规划
                mapMarkerTool.isPfMode(GduConfig.FpMode);
                mIv_Fp_state.setVisibility(View.VISIBLE);
                mIv_Fp_state.setImageResource(R.drawable.icon_map_fp_go_gray);
                mIv_flightPlan_on2off.setImageResource(R.drawable.bg_map_fp_on);
                txhToast.show(getString(R.string.Label_Map_FlightRoute_Event_on));
                // 电子围栏需要禁掉
                mIv_electronicRail_on2off.setImageResource(R.drawable.icon_fence_no);
                mIv_electronicRail_on2off.setEnabled(false);

                // 开启航迹规划,绘制航迹规划的范围
                initDrawCircle(true);
                //向MapTool 传递参数
                mapMarkerTool.setParameter(currentphoneLatlng, warning_circle, circle);
                //开启航迹规划,显示距离Layout
                mll_flight_distance.setVisibility(View.VISIBLE);
            } else if (isOpenFlightRoutePlan) {
                isOpenFlightRoutePlan = false;
                // 关闭航迹规划
                mapMarkerTool.isPfMode(GduConfig.NoMode);
                mIv_Fp_state.setVisibility(View.GONE);
                mIv_flightPlan_on2off.setImageResource(R.drawable.bg_map_fp_off);
                txhToast.show(getString(R.string.Label_Map_FlightRoute_Event_off));
                // 电子围栏需要开启
                mIv_electronicRail_on2off.setImageResource(R.drawable.bg_map_electronic_off);
                mIv_electronicRail_on2off.setEnabled(true);

                // 隐藏航迹规划 有效域
                initDrawCircle(false);
                //开启航迹规划,显示距离Layout
                mll_flight_distance.setVisibility(View.GONE);
                // 地图可以再次添加Marker
                isWayPointMode_state = GduConfig.FpClose;
                ClearMap();   //再次点击航迹规划 -清除
                gduMapComm.controlPathPlan((byte) 0x00, goOnRoute);  //停止航迹规划
                gduMapComm.controlPathPlan((byte) 0x04, goOnRoute);
                uploadList.clear();
            }
        } else if (currentphoneLatlng != null) {
            if (GlobalVariable.connStateEnum == ConnStateEnum.Conn_None)
                txhToast.show(getString(R.string.DeviceNoConn));
            else if (GlobalVariable.connStateEnum == ConnStateEnum.Conn_MoreOne)
                txhToast.show(getString(R.string.Label_ConnMore));
        } else if (currentphoneLatlng == null) {
            txhToast.show(getString(R.string.Label_Map_FlightRoute_unrecive_plan));
        }
    }

    /**
     * Marker地图点击监听事件
     *
     * @param latLng
     */
    @Override
    public void onMapClick(LatLng latLng) {
        LatLng curLatlng = latLng;
        // 航迹规划
        if (isOpenFlightRoutePlan && mPfMarkerList.size() < 50 && isWayPointMode_state == GduConfig.FpClose) {
            LatLng lastLatlng;
            if (!mPfLatLngList.isEmpty()) { // 这里判断不为空,是保证已经 有飞机的坐标点 已经添加
                if (AMapUtils.calculateLineDistance(currentphoneLatlng, curLatlng) > fp_validityRange) {
                    txhToast.show(getString(R.string.Label_Map_FlightRoute_flightpoit_invalidation));
                } else {
                    int tagNum = mPfLatLngList.size();//Marker 数_标
                    mPfMarkerList.add(mapMarkerTool.addPfMarker(curLatlng, tagNum));
                    mPfLatLngList.add(curLatlng);
                    mIv_Fp_state.setImageResource(R.drawable.bg_map_fp_go);
                    if (tagNum == 1) {
                        LatLng droneLat = mPfLatLngList.get(0);
                        mPfPolylineList.add(mapMarkerTool.addPolyDottedLine(droneLat, curLatlng));
                        mPfFlightDisList.add(calculateFlightDist(droneLat, curLatlng));
                    } else if (tagNum > 1) {
                        lastLatlng = mPfLatLngList.get(mPfLatLngList.size() - 2);
                        mPfPolylineList.add(mapMarkerTool.addPolyDottedLine(lastLatlng, curLatlng));
                        mPfFlightDisList.add(calculateFlightDist(lastLatlng, curLatlng));
                    }
                    setEraserState(true);//有Marker增加时候
                }
            }
        } else if (isOpenFlightRoutePlan && mPfMarkerList.size() == 50 && isWayPointMode_state == GduConfig.FpClose) {
            txhToast.show(getString(R.string.Label_Map_FlightRoute_flightpoit_overflow));
        } else if (isOpenFlightRoutePlan && mPfMarkerList.size() < 50 && isWayPointMode_state == GduConfig.FpGo) {
            // 即当开始航迹规划,在点击地图,无响应,不增加点
        }
        // 电子围栏
        if (isOpenElectronicRail && mErMarkerList.size() < 6 && isElectronicRail_state == GduConfig.ErClose) {
            LatLng lastLatlng;
            mErMarkerList.add(mapMarkerTool.addErMarker(curLatlng));
            mErLatLngList.add(curLatlng);
            int tagNum = mErLatLngList.size();//Marker 数_标
            if (tagNum > 2) {
                mIv_Er_state.setImageResource(R.drawable.bg_map_er_start);
            }

            if (tagNum > 1) {
                lastLatlng = mErLatLngList.get(mErLatLngList.size() - 2);
                BBLog.LogE("Point_画线", "-------[" + tagNum + "]点");
                mErPolylineList.add(mapMarkerTool.addPolyDottedLine(lastLatlng, curLatlng));
            }
            setEraserState(true);//有Marker增加时候

        } else if (isOpenElectronicRail && mErMarkerList.size() == 6 && isElectronicRail_state == GduConfig.ErClose) {
            txhToast.show(getString(R.string.Label_Map_FlightRoute_flightpoit_overflow));
        } else if (isOpenElectronicRail && mErMarkerList.size() < 6 && isElectronicRail_state == GduConfig.ErStart) {
            // 即当开始电子围栏,在点击地图,无响应,不增加点
        }
    }

    /**
     * <p>电子围栏状态—开/关</p>
     */
    private void initErState_on2off() {
        if (isElectronicRail_state == GduConfig.ErClose) {
            boolean isContainsPoint = mapMarkerTool.isPolygonContainsPoint(mErLatLngList, mPfLatLngList.get(0));
            if (mErMarkerList.size() > 2 && isContainsPoint) {
                connLastLine();
                setEraserState(false);
                upElectronicFencePoint();
                isElectronicRail_state = GduConfig.ErStart;
                mIv_Er_state.setImageResource(R.drawable.bg_map_er_cancel);
                mapMarkerTool.drawpolygonCover();
            } else if (!isContainsPoint) {
                txhToast.show(getString(R.string.Label_Map_FlightRoute_electronicRail_invalidation));
            }
        } else if (isElectronicRail_state == GduConfig.ErStart) {
            initElectronicRail();
        }
    }

    /**
     * <p>航迹规划状态—开/关</p>
     */
    private void initFpState_on2off() {
        if (isWayPointMode_state == GduConfig.FpClose) {
            if (mPfMarkerList.size() != 0) {
                setFlightHei();
            }
        } else if (isWayPointMode_state == GduConfig.FpGo) {
            mIv_Fp_state.setImageResource(R.drawable.bg_map_fp_go_on);
            isWayPointMode_state = GduConfig.FpGoOn;
            gduMapComm.controlPathPlan((byte) 0x02, goOnRoute);
        } else if (isWayPointMode_state == GduConfig.FpGoOn) {
            mIv_Fp_state.setImageResource(R.drawable.bg_map_fp_pause);
            isWayPointMode_state = GduConfig.FpGo;
            gduMapComm.controlPathPlan((byte) 0x03, goOnRoute);
        }
    }

    /**
     * <p>获取 </p>
     * <p>上传飞行航迹点 </p>
     */
    private void upFlightPathPoint() {
        //TODO
        for (int i = 1; i < mPfLatLngList.size(); i++) {
            PathPlanBean pathPlanBean = new PathPlanBean();
            LatLng latLng = GPSTranslateGuide.gcj2wgs(mPfLatLngList.get(i).longitude, mPfLatLngList.get(i).latitude);//火星坐标转大地坐标
            pathPlanBean.longitude = (int) (latLng.longitude * 10000000);
            pathPlanBean.latitude = (int) (latLng.latitude * 10000000);
            uploadList.add(pathPlanBean);
        }
        isRoutePlane = true;
        GduApplication.getSingleApp().gduCommunication.addCycleACKCB(GduSocketConfig.CycleACK_pathPlan, sateRoutePlane);
//        if (GlobalVariableTest.updatePlanPoints==0||GlobalVariableTest.updatePlanPoints==99){ //航点数量为0或99才能上传航点
        //TODO  必须GPS有星时才能上传航迹
//        if (GlobalVariable.satellite_drone>0&&GlobalVariable.satellite_drone!=98){  //必须GPS有星时才能上传航迹
//
//        }
        uploadPath();
//        }else{
//            gduMapComm.controlPathPlan((byte) 0x04, new SocketCallBack() {   //否则先清除航点再上传
//                @Override
//                public void callBack(byte code, GduFrame bean) {
//                    if (code==0){
//                        uploadPath();
//                    }
//                }
//            });
//        }
//        uploadList.clear();
    }


    /**
     * @author yuhao
     * 上传航迹规划
     */
    private void uploadPath() {
        gduMapComm.updatePlanPath(uploadList, new SocketCallBack() {   //上传航迹规划
            @Override
            public void callBack(byte code, GduFrame bean) {
                if (code == 0) {
                    YhLog.LogE("航迹上传成功");
                    handler.sendEmptyMessage(UPLOAD_PATH_OK);
//                    handler.postDelayed(new Runnable() {  //上传后等待3.5s判断飞机收到的航点是否与发送的一致
//                        @Override
//                        public void run() {
//                            if (GlobalVariableTest.updatePlanPoints == mPfLatLngList.size()) {
//                                handler.sendEmptyMessage(UPLOAD_PATH_OK);
//                            } else {
//                                handler.sendEmptyMessage(UPLOAD_PATH_FAILE);
//                            }
//                        }
//                    }, 3500);
                } else {
                    YhLog.LogE("航迹上传失败");
                    handler.sendEmptyMessage(UPLOAD_PATH_FAILE);
                }
            }
        });
    }


    int index = 0;
    private boolean isShowPlane;
    private TimerTask markPointRunner = new TimerTask() {
        @Override
        public void run() {
//            if (isShowPlane){
            YhLog.LogE("GlobalVariable.GPS_Lat=" + GlobalVariable.GPS_Lat + "     " + "GlobalVariable.GPS_Lon" + GlobalVariable.GPS_Lon);
            if (GlobalVariable.GPS_Lat < 90 && GlobalVariable.GPS_Lon < 180) {
                LatLng latLng = new LatLng(GlobalVariable.GPS_Lat, GlobalVariable.GPS_Lon);
                handler.obtainMessage(0, latLng).sendToTarget();
//                }
            }
        }
    };

    /**
     * <p>获取 </p>
     * <p>上传电子围栏 </p>
     */
    private void upElectronicFencePoint() {
        //TODO
        for (int i = 0; i < mErLatLngList.size(); i++) {
            PathPlanBean pathPlanBean = new PathPlanBean();
            LatLng latLng = GPSTranslateGuide.gcj2wgs(mErLatLngList.get(i).longitude, mErLatLngList.get(i).latitude);//火星坐标转大地坐标
            pathPlanBean.longitude = (int) (latLng.longitude * 10000000);
            pathPlanBean.latitude = (int) (latLng.latitude * 10000000);
//            pathPlanBean.longitude = (int) (mErLatLngList.get(i).longitude * 10000000);
//            pathPlanBean.latitude = (int) (mErLatLngList.get(i).latitude * 10000000);
//            pathPlanBean.longitude = (int) (latLng.longitude * 10000000);
//            pathPlanBean.latitude = (int) (latLng.latitude * 10000000);
//            YhLog.LogE("pathPlanBean.longitude="+pathPlanBean.longitude);
//            YhLog.LogE("pathPlanBean.latitude="+pathPlanBean.latitude);
            uploadList.add(pathPlanBean);
        }
//        PathPlanBean pathPlanBean = new PathPlanBean();
//        pathPlanBean.longitude = 1162969390;
//        pathPlanBean.latitude = 400431079;
//        uploadList.add(pathPlanBean);
//
//        PathPlanBean pathPlanBean1 = new PathPlanBean();
//        pathPlanBean1.longitude = 1162987400;
//        pathPlanBean1.latitude = 400437560;
//        uploadList.add(pathPlanBean1);
//
//        PathPlanBean pathPlanBean2 = new PathPlanBean();
//        pathPlanBean2.longitude = 1162969610;
//        pathPlanBean2.latitude = 400442200;
//        uploadList.add(pathPlanBean2);

        isRoutePlane = false;
//        GduApplication.getSingleApp().gduCommunication.addCycleACKCB(GduSocketConfig.CycleAck_wall,stateWall);  //监听围栏状态
//        gduMapComm.clearWallPoint(new SocketCallBack() {
//            @Override
//            public void callBack(byte code, GduFrame bean) {
//                if (code==0){
        gduMapComm.updateWallPoints(uploadList, new SocketCallBack() {  //清理电子围蓝成功后再上传电子围栏
            @Override
            public void callBack(byte code, GduFrame bean) {
                YhLog.LogE("code==" + code);
                if (code == 0) {
                    handler.sendEmptyMessage(UPLOAD_PATH_OK);   //上传电子围栏成功  余浩
//                                uploadList.clear();
                } else {
                    handler.sendEmptyMessage(UPLOAD_PATH_FAILE);
                }
            }
        });
//                }
//            }
//        });
//        uploadList.clear();
    }

    /**
     * <p>上传航点前的飞行高度</p>
     * <p>设置飞行高度</p>
     */
    private void setFlightHei() {
        final BlackGeneralDialog dialog = new BlackGeneralDialog(getActivity(), R.style.NormalDialog) {
            @Override
            public void positiveOnClick() {
                isWayPointMode_state = GduConfig.FpGo;
                setLastMarkerIcon();
                setEraserState(false);
                upFlightPathPoint();
                mIv_Fp_state.setImageResource(R.drawable.bg_map_fp_pause);
                mll_flight_distance.setVisibility(View.GONE);
            }

            @Override
            public void negativeOnClick() {

            }
        };
        dialog.setTitleText(R.string.Label_Map_FlightRoute_setting_flightheight);
        dialog.setContentText(R.string.Label_Map_FlightRoute_plan_keepCurrentHeight_fly);
        dialog.setShowSeekBar(true);
        dialog.show();
    }

    /**
     * <p>绘制航迹规划有效区域</p>
     * currentphoneLatlng (当前手机定位点)作为有效域的 中心
     * PS: 换算方法 argb
     * int alpha = (color & 0xff000000) >>> 24;
     * int red   = (color & 0x00ff0000) >> 16;
     * int green = (color & 0x0000ff00) >> 8;
     * int blue  = (color & 0x000000ff);
     *
     * @param isopen(开启,关闭)
     */
    private void initDrawCircle(boolean isopen) {
        if (isopen) {
            LatLng latLng = GPSTranslateGuide.transform2Mars(currentphoneLatlng.latitude, currentphoneLatlng.longitude);  //大地坐标转火星坐标
            aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 18));
            if (circle != null) {
                circle.setVisible(true);
            } else {
                circle = aMap.addCircle(new CircleOptions()
                        .center(latLng)
                        .radius(fp_validityRange)
                        .fillColor(Color.argb(26, 0, 120, 255))  // 填充域颜色
                        .strokeColor(Color.argb(102, 0, 160, 233))// 边框颜色
                        .strokeWidth(2));
            }
        } else {
            circle.setVisible(false);
        }
    }
    /**
     * <p>初始化(隐藏/显示) 控制台动画</p>
     */
    private void initControlPanelAnimation(boolean isShow) {
        AnimationUtils.mapRightDisappearAnima(isShow, mRl_MapControlPanel, mIv_hide_controlpanel, mIv_show_controlpanel);
    }

    /**
     * <p>清除航迹规划航点和航线</p>
     * <p>或者清除预设电子围栏</p>
     */
    private void CleanflightplanRoute() {
        if (isWayPointMode_state == GduConfig.FpClose) {
            GeneralDialog dialog = new GeneralDialog(getActivity(), R.style.NormalDialog) {
                @Override
                public void positiveOnClick() {
                    ClearMap();// 清楚航迹规划
                }

                @Override
                public void negativeOnClick() {

                }
            };
            dialog.setOnlycontent();
            dialog.setContentText(isOpenFlightRoutePlan ? R.string.Label_Map_FlightRoute_delete_wayPlan : R.string.Label_Map_FlightRoute_delete_electronicRail);
            dialog.show();
        } else if (isWayPointMode_state == GduConfig.FpGo || isWayPointMode_state == GduConfig.FpGoOn) {
            txhToast.show(getString(R.string.Label_Map_FlightRoute_noClean_WayPoint));
        }
    }

    /**
     * <p>清除地图Marker 点</p>
     */
    private void ClearMap() {
        // 清除航迹规划 LatLng 和 Marker 和 PolyLine
        if (mPfFlightDisList != null && !mPfLatLngList.isEmpty() && mPfLatLngList.size() != 1) {
            for (int i = mPfMarkerList.size() - 1; i > -1; i--) {
                mPfMarkerList.get(i).remove();
                mPfMarkerList.remove(i);
            }

            for (int i = mPfLatLngList.size() - 1; i > 0; i--) {
                mPfLatLngList.remove(i);
            }

            for (int i = mPfPolylineList.size() - 1; i > -1; i--) {
                mPfPolylineList.get(i).remove();
                mPfPolylineList.remove(i);
            }

            if (UavStaticVar.isDisplayFlightTrack && mReceivePolylineList != null) {
                for (int i = mReceivePolylineList.size() - 1; i > -1; i--) {
                    mReceivePolylineList.get(i).remove();
                    mReceivePolylineList.remove(i);
                }
            }

            mIv_Fp_state.setImageResource(R.drawable.icon_map_fp_go_gray);
            // 飞行距离
            AllFlightDist = 0;
            if (mPfFlightDisList != null)
                mPfFlightDisList = null;
            mTv_flightdis.setText(0 + StringUtils.getUnit());
        }

        // 清除电子围栏 LatLng 和 Marker 和 PolyLine
        if (!mErLatLngList.isEmpty() && mErLatLngList.size() != 1) {

            for (int i = mErLatLngList.size() - 1; i > -1; i--) {
                mErLatLngList.remove(i);
            }
            for (int i = mErMarkerList.size() - 1; i > -1; i--) {
                mErMarkerList.get(i).remove();
                mErMarkerList.remove(i);
            }
            for (int i = mErPolylineList.size() - 1; i > -1; i--) {
                mErPolylineList.get(i).remove();
                mErPolylineList.remove(i);
            }
            mIv_Er_state.setImageResource(R.drawable.icon_map_er_start_gray);

            gduMapComm.clearWallPoint(new SocketCallBack() {
                @Override
                public void callBack(byte code, GduFrame bean) {
                    if (code == 0) {
                        YhLog.LogE("清除电子围栏==" + bean.frame_content[0]);
                    }
                }
            });
            uploadList.clear();
        }
        setEraserState(false);// 清除航迹后
    }

    /**
     * <p>设置当前的飞机 状态</p>
     * <p>设置橡皮擦状态</p>
     *
     * @param isopen
     */
    private void setEraserState(boolean isopen) {
        mIv_fp_cleanroutePlan.setEnabled(isopen ? true : false);
        mIv_fp_cleanroutePlan.setImageResource(isopen ? R.drawable.bg_map_fp_clean : R.drawable.icon_cleanmap_no);
    }

    /**
     * <p>设置最后一个Marker 的Icon 图</p>
     * <p>将带数字的Icon 替换 终点标志</p>
     */
    private void setLastMarkerIcon() {
        mPfMarkerList.get(mPfMarkerList.size() - 1).remove();
//        mPfMarkerList.add(mapMarkerTool.updateFlagMarker(mPfLatLngList.get(mPfLatLngList.size() - 1)));
        mPfMarkerList.add(mapMarkerTool.addEndMarker(mPfLatLngList.get(mPfLatLngList.size() - 1)));
    }

    /**
     * <p>开启航迹规划后的一个提示信息</p>
     */
    private void openRoutePlanDialog() {

    }

    /**
     * <p>切换地图样式</p>
     *
     * @param view
     */
    private void switchMapStyle(View view) {
        if (view.getId() == R.id.ll_mapstyle_normal_layout) {
            aMap.setMapType(AMap.MAP_TYPE_NORMAL);
            SPUtils.put(getActivity(), SPUtils.MAPTYPE, 1);
            mMapView.invalidate();
        } else {
            aMap.setMapType(AMap.MAP_TYPE_SATELLITE);
            SPUtils.put(getActivity(), SPUtils.MAPTYPE, 2);
            mMapView.invalidate();
        }
        mll_switch_maplayout.setVisibility(View.GONE);
    }

    /**
     * <p>显示地图类型的Layout</p>
     */
    private void showMapTypeWindow() {
        if (mll_switch_maplayout.getVisibility() == View.GONE) {
            mll_switch_maplayout.setVisibility(View.VISIBLE);
        } else {
            mll_switch_maplayout.setVisibility(View.GONE);
        }
        //预设地图背景
        if (AMap.MAP_TYPE_NORMAL == aMap.getMapType()) {
            mll_bg_maptype_normal.setBackgroundResource(R.color.pf_color_ffa030);
            mll_bg_maptype_satellite.setBackgroundResource(R.color.Transparent);
            mTv_mapstyle_normal.setTextColor(getResources().getColor(R.color.pf_color_ffa030));
            mTv_mapstyle_satellite.setTextColor(getResources().getColor(R.color.pf_color_ffffff));
        } else {
            mll_bg_maptype_normal.setBackgroundResource(R.color.Transparent);
            mll_bg_maptype_satellite.setBackgroundResource(R.color.pf_color_ffa030);
            mTv_mapstyle_normal.setTextColor(getResources().getColor(R.color.pf_color_ffffff));
            mTv_mapstyle_satellite.setTextColor(getResources().getColor(R.color.pf_color_ffa030));
        }
    }

    /**
     * <p>计算总的飞行距离</p>
     *
     * @param beginlatLng
     * @param endLatLng
     */
    private float calculateFlightDist(LatLng beginlatLng, LatLng endLatLng) {
        float onceDist = AMapUtils.calculateLineDistance(beginlatLng, endLatLng);
        AllFlightDist += onceDist;
        DecimalFormat df = new DecimalFormat("##.#");
        mTv_flightdis.setText(df.format(AllFlightDist) + StringUtils.getUnit());
        return Float.parseFloat(df.format(AllFlightDist));
    }

    // 加载地图必要数据
    private void initAmap(Bundle savedInstanceState) {
        mMapView.onCreate(savedInstanceState);
        if (aMap == null) aMap = mMapView.getMap();
        myLocationStyle = new MyLocationStyle();// 初始化定位蓝点样式类
        initMyLocationStyle();
        initUiSettings();
        aMap.setMapType(AMap.MAP_TYPE_NORMAL);
    }

    /**
     * <p>初始化定位蓝点样式类</p>
     */
    private void initMyLocationStyle() {
        myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_SHOW);// 定位一次,且将视角移动到地图中心点
//        myLocationStyle.interval(2000);//设置连续定位模式下的定位间隔,只在连续定位模式下生效,单次定位模式下不会生效。单位为毫秒。
        myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.drawable.bluepoint));// 设置小蓝点的图标
        myLocationStyle.strokeColor(Color.argb(0, 0, 0, 0)); //设置定位蓝点精度圆圈的边框颜色的方法。
        myLocationStyle.radiusFillColor(Color.argb(0, 0, 0, 0));//设置定位蓝点精度圆圈的填充颜色的方法。
        myLocationStyle.strokeWidth(0);                      //设置定位蓝点精度圈的边框宽度的方法。
        aMap.setMyLocationStyle(myLocationStyle);
    }

    private void initUiSettings() {
        mUiSettings = aMap.getUiSettings(); // 地图工具
        mUiSettings.setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT);// logo 位置
        mUiSettings.setScaleControlsEnabled(true);// 默认比例尺
        mUiSettings.setZoomControlsEnabled(false);// 默认缩放按钮
        mUiSettings.setCompassEnabled(false);// 默认指南针
        mUiSettings.setScrollGesturesEnabled(true);// 默认滑动手势
        mUiSettings.setZoomGesturesEnabled(true);//  默认缩放手势
        mUiSettings.setMyLocationButtonEnabled(false);// 设置默认定位按钮是否显示
    }

    /**
     * 地图的监听事件 集合  都采用匿名内部类
     */
    private void initAmapListener() {
        aMap.setOnMapLoadedListener(this);// 地图加载监听
        aMap.setLocationSource(this);// 设置定位监听 //  先设置定位监听 ,在设置其他属性, 卫星,模式
        aMap.setOnMapClickListener(this);   // 设置点击地图事件监听
        aMap.setMyLocationEnabled(true); // 设置为true表示启动显示定位蓝点,false表示隐藏定位蓝点并不进行定位,默认是false。
        aMap.setMyLocationType(AMap.LOCATION_TYPE_LOCATE);
        // 初始化加载地图类型
        int i = SPUtils.getInt(getActivity(), SPUtils.MAPTYPE);
        if (!UavStaticVar.SetMapStyle && i == 0) {
            aMap.setMapType(AMap.MAP_TYPE_NORMAL); // 设置默认地图为卫星
            UavStaticVar.SetMapStyle = false;
        } else {
            if (i == 1) {
                aMap.setMapType(AMap.MAP_TYPE_NORMAL); // 设置默认地图为普通地图
            } else if (i == 2) {
                aMap.setMapType(AMap.MAP_TYPE_SATELLITE); // 设置默认地图为卫星
            }
        }
    }

    public void initListener() {
        mIv_switch_mapstyle.setOnClickListener(this);
        mIv_fp_maplocation.setOnClickListener(this);
        mIv_switch_mapstyle.setOnClickListener(this);
        mll_click_mapstyle_normal.setOnClickListener(this);
        mll_click_mapstyle_satellite.setOnClickListener(this);

        mIv_hide_controlpanel.setOnClickListener(this);
        mIv_show_controlpanel.setOnClickListener(this);
        mIv_fp_cleanroutePlan.setOnClickListener(this);
        mIv_electronicRail_on2off.setOnClickListener(this);
        mIv_flightPlan_on2off.setOnClickListener(this);
        mIv_fp_maplocation.setOnClickListener(this);
        mIv_Fp_state.setOnClickListener(this);
        mIv_Er_state.setOnClickListener(this);
    }

    /**
     * <p>初始化非地图API 的工具类</p>
     */
    private void initTools() {
        // 控制栏提示Toast
        txhToast = AngelaTXHToast.getInstance(getActivity());
        mapMarkerTool = new GuideMapMarkerTool(getActivity(), txhToast, aMap, mPfMarkerList, mPfLatLngList, mPfPolylineList, mPfFlightDisList, mTv_flightdis, mErMarkerList, mErLatLngList, mErPolylineList);
        updronelocation = new UpDroneCurLocation(handler, aMap, mMapView, mapMarkerTool, mReceivePolylineList);
        // 初始化 ,航迹清除功能 为不可点击
        setEraserState(false);//初始化
        // 初始化 ,无人机Marker 位置
        if (GlobalVariable.GPS_Lat != -1 && GlobalVariable.GPS_Lon != -1) {
            LatLng gpslatLng = GPSTranslateGuide.AmapTransform(GlobalVariable.GPS_Lat, GlobalVariable.GPS_Lon);
            mapMarkerTool.addPlaneMarker(gpslatLng, null);//初始化
//            mapMarkerTool.addPlaneMarker(new LatLng(GlobalVariable.latitude,GlobalVariable.longitude), null);//初始化
        }
    }

    public void initFindView() {
        //init map
        mMapView = ((TextureMapView) view.findViewById(R.id.Ttmv_guide_mapview));
        // init layout
        mRl_MapControlPanel = ((RelativeLayout) view.findViewById(R.id.rl_map_Control_panel));
        // init ControlPanel view
        mIv_hide_controlpanel = ((ImageView) view.findViewById(R.id.iv_map_right_menu_hide));
        mIv_show_controlpanel = ((ImageView) view.findViewById(R.id.iv_map_right_menu_show));
        mIv_fp_cleanroutePlan = ((ImageView) view.findViewById(R.id.iv_flightplan_clean_route));
        mIv_electronicRail_on2off = ((ImageView) view.findViewById(R.id.iv_electronic_rail));
        mIv_flightPlan_on2off = ((ImageView) view.findViewById(R.id.iv_flightplan_on2off));
        mIv_fp_maplocation = ((ImageView) view.findViewById(R.id.iv_mapview_location));
        mIv_Fp_state = ((ImageView) view.findViewById(R.id.iv_flightplan_state));
        mIv_Er_state = ((ImageView) view.findViewById(R.id.iv_ElectronicRail_state));
        // init switch mapstyle
        mIv_switch_mapstyle = ((ImageView) view.findViewById(R.id.iv_switch_map_icon));
        mll_switch_maplayout = ((LinearLayout) view.findViewById(R.id.ll_switch_map_layout));
        mll_click_mapstyle_normal = ((LinearLayout) view.findViewById(R.id.ll_mapstyle_normal_layout));
        mll_click_mapstyle_satellite = ((LinearLayout) view.findViewById(R.id.ll_mapstyle_satellite_layout));
        mll_bg_maptype_normal = ((LinearLayout) view.findViewById(R.id.ll_mapstyle_normal));
        mll_bg_maptype_satellite = ((LinearLayout) view.findViewById(R.id.ll_mapstyle_satellite));
        mTv_mapstyle_normal = ((TextView) view.findViewById(R.id.tv_mapstyle_normal_text));
        mTv_mapstyle_satellite = ((TextView) view.findViewById(R.id.tv_mapstyle_satellite_text));
        //init flight distance
        mll_flight_distance = ((LinearLayout) view.findViewById(R.id.ll_map_flight_dis));
        mTv_flightdis = ((TextView) view.findViewById(R.id.tv_map_flight_distance));

        dialogUtils = new DialogUtils(getActivity());
        showFlyPosition();
    }

    /**
     * @author 余浩
     * 实时刷新飞机的位置
     */
    private void showFlyPosition() {
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
//                YhLog.LogE("GlobalVariable.GPS_Lat=" + GlobalVariable.GPS_Lat + "     " + "GlobalVariable.GPS_Lon" + GlobalVariable.GPS_Lon);
                if (GlobalVariable.GPS_Lat < 90 && GlobalVariable.GPS_Lon < 180) {
                    LatLng latLng = new LatLng(GlobalVariable.GPS_Lat, GlobalVariable.GPS_Lon);
                    handler.obtainMessage(0, latLng).sendToTarget();
                    preLat = GlobalVariable.GPS_Lat;
                    prelon = GlobalVariable.GPS_Lon;
                }
            }
        }, 500, 500);
    }

    /**
     * 激活定位
     */
    @Override
    public void activate(OnLocationChangedListener onLocationChangedListener) {
        mListener = onLocationChangedListener;
        if (mLocationClient == null) {
//            初始化定位
            mLocationClient = new AMapLocationClient(getActivity());
            //初始化定位参数
            mLocationOption = new AMapLocationClientOption();
            //设置定位回调监听
            mLocationClient.setLocationListener(this); // 有成功回调
            //设置为高精度定位模式
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
            mLocationOption.setNeedAddress(true);
            mLocationOption.setOnceLocation(false);
            //设置定位参数
            mLocationClient.setLocationOption(mLocationOption);
            //启动定位
            mLocationClient.startLocation();
        }
    }

    /**
     * <p>定位成功后的回调</p>
     *
     * @param aMapLocation
     */
    @Override
    public void onLocationChanged(AMapLocation aMapLocation) {
//        Toast.makeText(getActivity(), "ErrorCode:" + aMapLocation.getErrorCode() + "-lat:" + aMapLocation.getLatitude() + "-lon:" + aMapLocation.getLongitude(), Toast.LENGTH_SHORT).show();
        if (mListener != null && aMapLocation != null) {
            if (aMapLocation.getErrorCode() == 0) {
                //保存当前定位坐标
                SPUtils.put(getActivity(), SPUtils.AMAP_PHONE_LAST_LAT, aMapLocation.getLatitude() + "");
                SPUtils.put(getActivity(), SPUtils.AMAP_PHONE_LAST_LON, aMapLocation.getLongitude() + "");
                // 显示系统小蓝点
                mListener.onLocationChanged(aMapLocation);
                // set 当前人的位置
                LatLng currentphoneLatlng = new LatLng(aMapLocation.getLatitude(), aMapLocation.getLongitude());
                aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentphoneLatlng, 20));
                // 保存当前 手机定位 并增加到 mPfLatLngList
//                addDroneLocation();     //第一个坐标点改为飞机的坐标  余浩
                deactivate();
            } else {
                BBLog.LogE("onLocationChanged", "定位失败," + aMapLocation.getErrorCode() + ": " + aMapLocation.getErrorInfo());
            }
        }
    }

    /**
     * <p>地图加载回调</p>
     * <p>如果只想定位一次,那就将相机放在地图加载回调中</p>
     */
    @Override
    public void onMapLoaded() {
        String phone_lat = SPUtils.getString(getActivity(), SPUtils.AMAP_PHONE_LAST_LAT);
        String phone_lon = SPUtils.getString(getActivity(), SPUtils.AMAP_PHONE_LAST_LON);
        if (!phone_lat.equals("") && !phone_lon.equals("")) {
            Double lastPostionLat = Double.valueOf(phone_lat);
            Double lastPostionLng = Double.valueOf(phone_lon);
            LatLng latLng = new LatLng(lastPostionLat, lastPostionLng);
            aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16));
        }
        initPlanePosotion();
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    refreshLatLng((LatLng) msg.obj);      //刷新飞机的位置
                    break;

                case 1:
                    mapMarkerTool.setPlaneAngle(msg.arg1);
                    break;

                case UPLOAD_PATH_OK:   //航迹规划上传成功  余浩
                    if (isRoutePlane) {
                        ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.route_upload_success));
                    } else {
                        ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.wall_upload_success));
//                        handler.postDelayed(new Runnable() {  //上传成功后计时2s判断围栏点上传成功与否
//                            @Override
//                            public void run() {
//                                timeUP=true;
//                            }
//                        },2000);
                    }
                    isShowPlane = true;
                    break;

                case UPLOAD_PATH_FAILE:  //航迹规划上传失败  余浩
                    ToastFactory.toastShort(getActivity(),getActivity().getString(R.string.route_upload_faile));

//                    gduMapComm.controlPathPlan((byte) 0x04, new SocketCallBack() {  //清除航迹规划
//                        @Override
//                        public void callBack(byte code, GduFrame bean) {
//
//                        }
//                    });
                    YhLog.LogE("航迹规划上传失败");
                    break;

                case ROUTE_PLANE_DOING:  //航迹规划中   余浩
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.routing));
                    YhLog.LogE("航迹规划中");
                    break;

                case ROUTE_PLANE_PAUSE:   //暂停航迹规划  余浩
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.pause_route));
                    YhLog.LogE("暂停航迹规划");
                    break;

                case ROUTE_PLANE_FAILE:   //航迹规划失败  余浩
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.route_faile));
                    YhLog.LogE("航迹规划失败");
                    break;

                case START_ROUTE:   //开始航迹规划   余浩
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.start_route));
                    YhLog.LogE("开始航迹规划");
                    break;

                case ROUTE_PLANE_COMPLETE:  //航迹规划完成  余浩
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.route_complete));
                    YhLog.LogE("航迹规划完成");
                    break;

                case NO_ROUTE:    //未进行航迹规划   余浩
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.no_route));
                    YhLog.LogE("未进行航迹规划");
                    break;

                case IN_WALL:  //在围栏中
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.in_wall));
                    break;

                case OUT_WALL:   //在围栏外
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.out_wall));
                    break;

                case CLEAR_WALL:  //清除电子围栏
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.clear_wall));
                    break;

                case EXIT_WALL:   //退出电子围栏模式
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.exit_wall));
                    break;

                case INVADITE_WALL:  //无效电子围栏点
                    ToastFactory.toastShort(getActivity(), getActivity().getString(R.string.invalid_wall));
                    break;
            }
        }
    };


    /**
     * 确认开始航迹飞行的提示
     */
    private void sureFly() {
        dialogUtils.createDialogWith2Btn("确定要启动航迹飞行吗"
                , "启动航迹飞行飞机将按照航迹自动飞行"
                , getString(R.string.Label_cancel)
                , getString(R.string.Label_Sure), new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        switch (v.getId()) {

                            case R.id.dialog_btn_cancel:
                                dialogUtils.cancelDailog();
                                break;

                            case R.id.dialog_btn_sure:
                                gduMapComm.controlPathPlan((byte)0x01,goOnRoute);  //开始航迹飞行
                                dialogUtils.cancelDailog();
                                break;

                        }
                    }
                }
        );
    }

    private byte preState = -1;
    /**
     * @author 余浩
     * 航迹规划的状态
     */
    private SocketCallBack sateRoutePlane = new SocketCallBack() {
        @Override
        public void callBack(byte code, GduFrame bean) {
            switch (bean.frame_content[0]) {
                case 0:
                    if (preState != 0) {
                        handler.sendEmptyMessage(NO_ROUTE);
                    }
                    break;

                case 1:
                    if (preState != 1) {

                        handler.sendEmptyMessage(ROUTE_PLANE_DOING);
                    }
                    break;

                case 2:
                    if (preState != 2) {
                        handler.sendEmptyMessage(ROUTE_PLANE_PAUSE);
                    }
                    break;

                case 3:
                    if (preState != 3) {
                        handler.sendEmptyMessage(ROUTE_PLANE_COMPLETE);
                    }
                    break;

                case 4:
                    if (preState != 4) {
                        handler.sendEmptyMessage(ROUTE_PLANE_FAILE);
                    }
                    break;
            }
            preState = bean.frame_content[0];
        }
    };

    private byte preStateWall = -1;
    /**
     * @author 余浩
     * 电子围栏状态反馈
     */
    private SocketCallBack stateWall = new SocketCallBack() {
        @Override
        public void callBack(byte code, GduFrame bean) {
            switch (bean.frame_content[0]) {
                case 0:   //围栏中
                    if (preStateWall != 0) {
                        handler.sendEmptyMessage(IN_WALL);
                    }
                    break;

                case 1:  //围栏外
                    if (preStateWall != 1) {
                        handler.sendEmptyMessage(OUT_WALL);
                    }
                    break;

                case 2:  //围栏被清除(手机发送清楚指令)
                    if (preStateWall != 2) {
                        handler.sendEmptyMessage(CLEAR_WALL);
                    }
                    break;

                case 3:   //退出电子围栏模式
                    if (preStateWall != 3) {
                        handler.sendEmptyMessage(EXIT_WALL);
                    }
                    break;

                case 4:  //无效电子围栏
                    if (timeUP && bean.frame_content[1] != mErLatLngList.size()) {
                        handler.sendEmptyMessage(INVADITE_WALL);
                        gduMapComm.clearWallPoint(new SocketCallBack() {   //发送清除指令取消围栏状态的周期反馈
                            @Override
                            public void callBack(byte code, GduFrame bean) {

                            }
                        });
                        timeUP = false;
                    }
                    break;
            }
            preStateWall = bean.frame_content[0];
        }
    };

    /**
     * 航迹规划操作
     */
    private SocketCallBack goOnRoute = new SocketCallBack() {
        @Override
        public void callBack(byte code, GduFrame bean) {

        }
    };

    /**
     * <p>获取无人机的位置,实况刷新</p>
     */
    public void refreshLatLng(LatLng latLng) {
        if (latLng != null) {
            LatLng gpslatLng = GPSTranslateGuide.AmapTransform(latLng.latitude, latLng.longitude);
            LatLng latLng1 = GPSTranslateGuide.transform2Mars(latLng.latitude, latLng.longitude);  //将坐标转换为火星坐标进行显示纠正偏移
            receiveDroneLatlng(latLng1);// 绘制已经飞过的路径
            updronelocation.refreshDroneLocation(latLng1);// 更新无人机 Marker 位置
            UavStaticVar.droneCurLatLng = new LatLng(gpslatLng.latitude, gpslatLng.longitude);
            UavStaticVar.isGetuavCurLatLng = true;
        }
    }

    /**
     * <p>接受无人机端传递过来的经纬度绘制轨迹。</p>
     */
    boolean isFirstReturn = true;

    public void receiveDroneLatlng(LatLng backLatLng) {
//        MainActivity mMainActivity = (MainActivity) getActivity();
//        if (mMainActivity.sateliteNum > 6) {
        if (isFirstReturn) {
            if (!UavStaticVar.isGetuavCurLatLng) {
                UavStaticVar.droneCurLatLng = backLatLng;
                isFirstReturn = false;
            }
        }

        if (UavStaticVar.droneCurLatLng != null) {
            //  836 的意思是  原来1000 的显示是 *1.2 倍,显示时候需要显示正确的 米 反向除以 1.2后的位置是正确超过1000米的
            if (AMapUtils.calculateLineDistance(UavStaticVar.droneCurLatLng, backLatLng) > 836) {
                txhToast.show(getString(R.string.Label_Map_FlightRoute_flight_dis_over_1000));
            }
        }
        // 无人机第一个点位置替换
        if (mPfLatLngList.isEmpty()) {
            mPfLatLngList.add(backLatLng);
        } else {
            mPfLatLngList.set(0, backLatLng);
        }
        //绘制飞机传回来的坐标并在飞的时候绘制飞过的线
        updronelocation.drawRecievePolyLine(backLatLng);
        // 计算当前无人机最远飞了多远(人和无人机)
        if (UavStaticVar.droneCurLatLng != null) {
            EventBus.getDefault().post(new PfMostDisEvent((int) AMapUtils.calculateLineDistance(UavStaticVar.droneCurLatLng, backLatLng)));
        }
    }

    /**
     * <p>添加无人机 当前位置</p>
     */
    private void addDroneLocation() {
        if (mPfLatLngList.isEmpty()) {
//            mPfLatLngList.add(UavStaticVar.droneCurLatLng);
            mPfLatLngList.add(currentphoneLatlng);
        } else {
//            mPfLatLngList.set(0, UavStaticVar.droneCurLatLng);
            mPfLatLngList.set(0, currentphoneLatlng);
        }
    }

    /**
     * 停止定位
     */
    @Override
    public void deactivate() {
        mListener = null;
        if (mLocationClient != null) {
            mLocationClient.stopLocation();
            mLocationClient.onDestroy();
        }
        mLocationClient = null;
    }

    /**
     * 以下是必须要重写的
     */
    @Override
    public void onResume() {
        mMapView.onResume();
        super.onResume();
    }

    @Override
    public void onPause() {
        mMapView.onPause();
        super.onPause();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        mMapView.onSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        timer.cancel();
        timer.purge();
        updronelocation.stopThread();
        isElectronicRail_state = GduConfig.ErClose;
        isWayPointMode_state = GduConfig.FpClose;
        //预算的飞行距离
        AllFlightDist = 0;
        if (mPfFlightDisList != null && mPfFlightDisList.size() > 0) {
            mPfFlightDisList = null;
        }
        //默认初始值
        isOpenFlightRoutePlan = false;
        isOpenElectronicRail = false;
        // 电子围栏,矩形覆盖面
        mapMarkerTool.cleanPolygonCover();
        mapMarkerTool.isPfMode(GduConfig.NoMode);
        // 航迹规划 清除圆面
        if (circle != null) {
            circle.remove();
            circle = null;
        }
        if (warning_circle != null) {
            warning_circle.remove();
            warning_circle = null;
        }
        if (mPfMarkerList != null && mPfMarkerList.size() > 0) {
            mPfMarkerList = null;
        }
        if (mPfPolylineList != null && mPfPolylineList.size() > 0) {
            mPfPolylineList = null;
        }
        // 电子围栏
        if (mErLatLngList != null && mErLatLngList.size() > 0) {
            mErLatLngList = null;
        }
        if (mErMarkerList != null && mErMarkerList.size() > 0) {
            mErMarkerList = null;
        }
        if (mErPolylineList != null && mErPolylineList.size() > 0) {
            mErPolylineList = null;
        }
        mMapView.onDestroy();
        aMap = null;
//        if (null != mLocationClient) {
//            mLocationClient.onDestroy();
//        }
    }
}
GuideMapMarkerTool.java
package com.gdu.mvp_view.flightRouteplan;

import android.app.Service;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint.Align;
import android.os.Vibrator;
import android.text.TextPaint;
import android.util.TypedValue;
import android.widget.TextView;

import com.amap.api.maps.AMap;
import com.amap.api.maps.AMap.OnMarkerClickListener;
import com.amap.api.maps.AMapUtils;
import com.amap.api.maps.model.BitmapDescriptor;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.Circle;
import com.amap.api.maps.model.CircleOptions;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.LatLngBounds;
import com.amap.api.maps.model.LatLngBounds.Builder;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.Polygon;
import com.amap.api.maps.model.PolygonOptions;
import com.amap.api.maps.model.Polyline;
import com.amap.api.maps.model.PolylineOptions;
import com.gdu.config.GduConfig;
import com.gdu.config.UavStaticVar;
import com.gdu.phonedrone.R;
import com.gdu.util.BBLog;
import com.gdu.util.StringUtils;
import com.gdu.views.AngelaTXHToast;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import static com.gdu.mvp_view.flightRouteplan.GuideMapFragment.fp_validityRange;
import static com.gdu.mvp_view.flightRouteplan.GuideMapFragment.isElectronicRail_state;
import static com.gdu.mvp_view.flightRouteplan.GuideMapFragment.isWayPointMode_state;

public class GuideMapMarkerTool implements AMap.OnMarkerDragListener, OnMarkerClickListener {

    private Context context;
    private AMap aMap;
    private AngelaTXHToast txhToast; //实时控制页面下滑提示
    // init list 【航迹规划】
    private ArrayList<Marker> mPfMarkerList;
    private ArrayList<LatLng> mPfLatLngList;
    private ArrayList<Polyline> mPfPolylineList;
    private ArrayList<Float> mPfFlightDisList;
    private TextView mTv_flightdis;
    // init list 【电子围栏】
    private ArrayList<Marker> mErMarkerList;
    private ArrayList<LatLng> mErLatLngList;
    private ArrayList<Polyline> mErPolylineList;
    // Marker config
    private MarkerOptions options;
    // 围栏不规则 矩形  cover
    private Polygon polygon;
    // 小数点保留一位
    private DecimalFormat df = new DecimalFormat("##.#");
    // 红旗和空白图片资源
    private BitmapDescriptor mFlagesource;
    private BitmapDescriptor mBlanksource;
    private ArrayList<BitmapDescriptor> mBitmapList;
    // 无人机端 Marker
    private Marker mPlaneMarker;
    // 手机端标志 Marker
    private Marker mPeopleMarker;
    // 旗子Marker
    public Marker mFlagMarker;
    // init data
    private boolean mLoopMode;
    private int mLoopCount;
    private int planeAngle = 0;
    private int mapAngle = 0;

    // 构造方法,传入需要用的值
    public GuideMapMarkerTool(Context context, AngelaTXHToast txhToast, AMap aMap,
                              ArrayList<Marker> pf_markersList, ArrayList<LatLng> pf_latLngList, ArrayList<Polyline> pf_polylineList, ArrayList<Float> pf_flightdisList, TextView tv_flightdis,
                              ArrayList<Marker> er_markersList, ArrayList<LatLng> er_latLngList, ArrayList<Polyline> er_polylineList
    ) {
        initGuideMap(aMap);
        this.aMap = aMap;
        this.context = context;
        this.txhToast = txhToast;
        // 航迹规划
        this.mPfMarkerList = pf_markersList;
        this.mPfLatLngList = pf_latLngList;
        this.mPfPolylineList = pf_polylineList;
        this.mPfFlightDisList = pf_flightdisList;
        this.mTv_flightdis = tv_flightdis;
        // 电子围栏
        this.mErMarkerList = er_markersList;
        this.mErLatLngList = er_latLngList;
        this.mErPolylineList = er_polylineList;
    }

    private void initGuideMap(AMap aMap) {
        // 设置marker可拖拽事件监听器
        aMap.setOnMarkerDragListener(this);
        // 设置显示marker信息监听,要想显示信息必须注册
//        aMap.setInfoWindowAdapter(this);
        aMap.setOnMarkerClickListener(this);
//        aMap.setOnInfoWindowClickListener(this);
        // 初始化Marker配置
        options = new MarkerOptions().draggable(true);
    }

    // 设置循环圈数
    public void setLoop(boolean loop, int count) {
        mLoopMode = loop;
        mLoopCount = count;
    }

    // 判断是否是循环状态
    public boolean isLoop() {
        return mLoopMode;
    }

    // 获得循环圈数
    public int getLoopCount() {
        return mLoopCount;
    }


    //刷新人的位置
    public void updatePeopleMarker(LatLng lagLng) {
        if (mPeopleMarker != null) {
            mPeopleMarker.remove();
        }
//         手机端添加起点.
        mPeopleMarker = aMap.addMarker(new MarkerOptions()
                .position(lagLng)
                .anchor(0.5f, 1f)
                .draggable(false)
                .icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
                        .decodeResource(context.getResources(),
                                R.drawable.bluepoint))));
    }

    /**
     * <p>设置飞机角度</p>
     *
     * @param angle
     */
    public void setPlaneAngle(int angle) {
        planeAngle = 0 - angle;
        if (mPlaneMarker != null) {
            mPlaneMarker.setRotateAngle(planeAngle + mapAngle);
        }
    }

    public void setPlaneAngle(float angle) {
        mapAngle = (int) angle;
        if (mPlaneMarker != null) {
            mPlaneMarker.setRotateAngle(planeAngle + mapAngle);
        }
    }

    //使得栈里面的点尽可能都在可视区域范围内
    private void updateCamera() {

        Builder builder = new LatLngBounds.Builder();
        for (int i = 0; i < mPfLatLngList.size(); i++) {
            LatLng latLng = mPfLatLngList.get(i);
            builder = builder.include(latLng);
        }

        LatLngBounds bounds = builder.build();
//        aMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 10));

    }

    public void refreshPointNumber() {
        for (int i = 0; i < mPfMarkerList.size(); i++) {
            mPfMarkerList.get(i).setIcon(
                    BitmapDescriptorFactory.fromBitmap(getBitMap(i + 1)));
        }
    }

    // dp转px
    public static int dp2px(Context context, int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
                context.getResources().getDisplayMetrics());
    }

    // -------------------航迹规划开始,更新无人机位置-------------------

    //更新无人机mark在地图上的位置
    public void addPlaneMarker(LatLng latLng, LatLng lastLatLng) {
        if (mPlaneMarker != null) {
            mPlaneMarker.remove();
        }

        MarkerOptions options = new MarkerOptions();
        options.anchor(0.5f, 0.5f);
        options.position(latLng);
        options.icon(BitmapDescriptorFactory
                .fromResource(R.drawable.icon_plane));

        mPlaneMarker = aMap.addMarker(options);
        mPlaneMarker.setRotateAngle(planeAngle + mapAngle);

        // 通过栈顶元素与当前的latLng 得到角度。
//        if (mPfLatLngList.isEmpty()) {
//            return;
//        }
//
//        double currentLatitue = lastLatLng.latitude;
//        double currentLongtitue = lastLatLng.longitude;
//
//        double latitude = latLng.latitude;
//        double longtitue = latLng.longitude;
//
//        double rotate = 0;
//        if (currentLatitue - latitude != 0) {
//            boolean flag1 = (longtitue - currentLongtitue) > 0;
//            double k = (longtitue - currentLongtitue)
//                    / (latitude - currentLatitue);
//            boolean flag2 = k > 0;
//
//			/*
//             * 下面计算的是无人机marker的角度。根据平面坐标系的四个象限知识, 第一象限对应右下角,第二象限对应 左下角,
//			 * 第三象限对应左上角,第四象限对应右上角 。
//			 *
//			 * mPlaneMarker.setRotateAngle 从正北开始,逆时钟计算
//			 */
//            if (flag2) {
//                if (flag1) {// 第一象限
//                    rotate = 360 - Math.toDegrees(Math.atan(k));
//                } else {// 第三象限
//                    rotate = 180 - Math.toDegrees(Math.atan(k));
//                }
//            } else {
//                if (flag1) {// 第二象限
//                    rotate = 180 - Math.toDegrees(Math.atan(k));
//                } else {// 第四象限
//                    rotate = Math.abs(Math.toDegrees(Math.atan(k)));
//                }
//            }
//
//            mPlaneMarker.setRotateAngle((float) rotate);
//        }
    }

    // -----------绘制  Marker,number,Line ---------------------

    /**
     * <p>设置Marker 是否可移动,根据不同情况来 设置</p>
     * <p>默认设置可以移动</p>
     *
     * @param isMove 是否可以移动
     */
    public void MarkerIsMove(boolean isMove) {
        options.draggable(isMove);
    }

    /**
     * <P>给marker上绘制数字</P>
     * <P>限制最多 50个 </P>
     *
     * @param text
     * @return path_planning_point
     */
    public Bitmap getBitMap(int text) {
        BBLog.LogE("getBitMap", text + "");
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
                R.drawable.path_planning_point).copy(Bitmap.Config.ARGB_8888, true);
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight());
        Canvas canvas = new Canvas(bitmap);

        // 设置文字样式,大小,颜色
        TextPaint textPaint = new TextPaint();
        textPaint.setAntiAlias(true);
        textPaint.setColor(Color.rgb(226, 138, 34));
        textPaint.setTextSize(45f);
        textPaint.setFakeBoldText(true);
        textPaint.setTextAlign(Align.CENTER);

        canvas.drawText(String.valueOf(text), canvas.getWidth() / 2,
                canvas.getHeight() / 2, textPaint);
        return bitmap;
    }

    /**
     * <p>根据经纬度往地图上添加marker</p>
     * <p>[航迹规划]</p>
     *
     * @param lagLng    当前点击的 下的坐标
     * @param markerNum 计数
     * @return
     */
    public Marker addPfMarker(LatLng lagLng, int markerNum) {

        options.anchor(0.5f, 1f)
                .position(lagLng)
                .icon(BitmapDescriptorFactory.fromBitmap(getBitMap(markerNum)));

        return aMap.addMarker(options);
    }

    /**
     * <p>根据经纬度往地图上添加marker</p>
     * <p>[终点Marker]</p>
     * <p>[静态Marker]</p>
     *
     * @param lagLng 当前点击的 下的坐标
     * @return
     */
    public Marker addEndMarker(LatLng lagLng) {
        if (mFlagMarker != null) {
            mFlagMarker.remove();
        }
        options.anchor(0.5f, 1f)
                .position(lagLng)
                .draggable(false)
                .icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_map_end_point_activity));
        mFlagMarker = aMap.addMarker(options);
        return mFlagMarker;
    }

    /**
     * <p>根据经纬度往地图上添加marker</p>
     * 刷新红旗的位置
     * <p>小红旗闪烁</p>
     * <p>[终点Marker]</p>
     * <p>[动态Marker]</p>
     *
     * @param lagLng
     * @return
     */
    public Marker updateFlagMarker(LatLng lagLng) {
        if (mFlagMarker != null) {
            mFlagMarker.remove();
        }
        if (mBitmapList != null && !mBitmapList.isEmpty()) {
            mBitmapList.clear();
        }
        System.gc();

        // 设置小红旗闪烁
        mFlagesource = BitmapDescriptorFactory.fromResource(R.drawable.icon_map_end_point_activity);
        mBlanksource = BitmapDescriptorFactory.fromResource(R.drawable.icon_map_end_point_default);
        mBitmapList = new ArrayList<BitmapDescriptor>();
        mBitmapList.add(mFlagesource);
        mBitmapList.add(mBlanksource);

        if (UavStaticVar.screenWidth > 2000) {
            mFlagMarker = aMap.addMarker(new MarkerOptions().position(lagLng)
                    .anchor(0.9f, 1.5f).period(20).icons(mBitmapList));
        } else {
            mFlagMarker = aMap.addMarker(new MarkerOptions().position(lagLng)
                    .anchor(0.5f, 1.0f).period(20).icons(mBitmapList));
        }
        return mFlagMarker;
    }

    /**
     * <p>根据经纬度往地图上添加marker</p>
     * <p>[电子围栏]</p>
     *
     * @param lagLng 当前点击的 下的坐标
     * @return
     */
    public Marker addErMarker(LatLng lagLng) {

        options.anchor(0.5f, 1f)
                .position(lagLng)
                .icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_fence_point));

        return aMap.addMarker(options);
    }

    /**
     * <p>绘制两点之间线段</p>
     * <p>虚线</p>
     *
     * @param beginlatLng 起点
     * @param endLatLng   终点
     * @return
     */
    public Polyline addPolyDottedLine(LatLng beginlatLng, LatLng endLatLng) {

        PolylineOptions options = new PolylineOptions();
        options.add(beginlatLng, endLatLng)
                .width(10)
                .color(Color.rgb(255, 121, 24))
                .setDottedLine(true);// 虚线

        return aMap.addPolyline(options);
    }


    /**
     * <p>绘制两点之间线段</p>
     * <p>实线</p>
     *
     * @param beginlatLng 起点
     * @param endLatLng   终点
     * @return
     */
    public Polyline addPolySolidLine(LatLng beginlatLng, LatLng endLatLng) {

        PolylineOptions options = new PolylineOptions();
        options.add(beginlatLng, endLatLng)
                .width(10)
                .color(Color.rgb(255, 121, 24))
                .setDottedLine(false);// 实线

        return aMap.addPolyline(options);
    }

    /**
     * <p>电子围栏区域</p>
     * <p>绘制多边形覆盖</p>
     */
    public void drawpolygonCover() {
        if (polygon != null) {
            polygon.remove();
        }
        PolygonOptions polygonOptions = new PolygonOptions();
        polygonOptions.strokeWidth(5)
                .strokeColor(Color.argb(102, 255, 121, 24)) // 边框颜色
                .fillColor(Color.argb(22, 226, 138, 34));   // 多边形的填充色
        // 添加 多边形的每个顶点(顺序添加)
        for (int i = 0; i < mErLatLngList.size(); i++) {
            polygonOptions.add(mErLatLngList.get(i));
        }
        polygon = aMap.addPolygon(polygonOptions);
    }

    /**
     * <p>清除电子围栏围成的区域</p>
     */
    public void cleanPolygonCover() {
        if (polygon != null)
            polygon.remove();
    }

    /**
     * <p>返回一个点是否在一个多边形区域内</p>
     *
     * @param mLatlng 多边形坐标点列表
     * @param latLng  待判断点
     * @return true 多边形包含这个点,false 多边形未包含这个点。
     */
    public boolean isPolygonContainsPoint(List<LatLng> mLatlng, LatLng latLng) {
        int i, j;
        boolean c = false;
        for (i = 0, j = mLatlng.size() - 1; i < mLatlng.size(); j = i++) {
            if (((mLatlng.get(i).longitude > latLng.longitude) != ((mLatlng.get(j).longitude > latLng.longitude))
                    && (latLng.latitude < (mLatlng.get(j).latitude - mLatlng.get(i).latitude)
                    * (latLng.longitude - mLatlng.get(i).longitude) / (mLatlng.get(j).longitude - mLatlng.get(i).longitude) + mLatlng.get(i).latitude)))
                c = !c;
        }
        return c;
    }

    /**
     * <p>判断2根线是否相交</p>
     */
    public boolean isPolygonIntersect(List<LatLng> mLatlng) {
        if (mLatlng.size() > 3) {
            for (int i = 0; i < mLatlng.size(); i++) {

            }
        }
        return false;
    }

    //-------------------Marker点击,长按,拖拽事件------------------

    /**
     * <p>点击marker事件</p>
     *
     * @param arg0
     * @return
     */
    @Override
    public boolean onMarkerClick(Marker arg0) {
        // 航点信息此版本不需要,暂时屏蔽
        // Marker marker = arg0;
        // if (null != inforPopupWindow)
        // {
        // inforPopupWindow.dismiss();
        // inforPopupWindow = null;
        // }
        // if (marker != mFlagMarker)
        // {
        // initPointPopuptWindow(mGuideMapView, marker);
        // }
        return true;
    }

    /**
     * <p>是否是航迹规划模式</p>
     */
    private int isPfMode;// 0 关闭 1 航迹规划模式 2 电子围栏模式

    public void isPfMode(int ispfmode) {
        this.isPfMode = ispfmode;
    }

    /**
     * <p>Marker 拖拽开始监听</p>
     * <li>增加振荡器</li>
     * <li>获取当前Marker 的起始坐标并保存</li>
     * <li>作用:当不满足条件的时候,就可以使用起点坐标</li>
     *
     * @param marker
     */
    private LatLng curMarkerPosition;

    @Override
    public void onMarkerDragStart(Marker marker) {
        Vibrator vibrator = (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);
        vibrator.vibrate(150);
        if (isPfMode == GduConfig.FpMode) {
            for (int i = 0; i < mPfMarkerList.size(); i++) {
                if (marker.equals(mPfMarkerList.get(i))) {
                    curMarkerPosition = mPfLatLngList.get(i + 1);
                }
            }
        } else if (isPfMode == GduConfig.ErMode) {
            for (int i = 0; i < mErMarkerList.size(); i++) {
                if (marker.equals(mErMarkerList.get(i))) {
                    curMarkerPosition = mErLatLngList.get(i);
                }
            }
        }
    }

    /**
     * <p>拖拽过程中的监听</p>
     *
     * @param marker
     */
    @Override
    public void onMarkerDrag(Marker marker) {
        drawTrackLine(marker);// 正常的Marker监听中
    }

    /**
     * <p>拖拽完成后的监听</p>
     * <li>当状态为:航迹规划进行中/电子围栏已启动 ,拖动点回归原点</li>
     * <li>拖拽完成后检查是否超过2000的判定</li>
     *
     * @param marker
     */
    @Override
    public void onMarkerDragEnd(Marker marker) {
        // 模式开启,飞机在执行 指令操作,所有的点都不能生效

        if (isWayPointMode_state == GduConfig.FpGo || isWayPointMode_state == GduConfig.FpGoOn || isElectronicRail_state == GduConfig.ErStart) {
            BackDraggablePoint(marker);// 当前是:航迹规划状态/电子围栏状态
            return;
        }
        if (isPfMode == GduConfig.FpMode && AMapUtils.calculateLineDistance(mPfLatLngList.get(0), marker.getPosition()) > fp_validityRange) {
            txhToast.show(context.getString(R.string.Label_Map_FlightRoute_flightpoit_invalidation));
            BackDraggablePoint(marker);// 就是超过2000米 的判断
        }
    }

    /**
     * <p>回到拖拽的起点</p>
     * <li>当不满足要求的时候,就会回到起始点</li>
     *
     * @param marker
     */
    private void BackDraggablePoint(Marker marker) {
        marker.setPosition(curMarkerPosition);
        drawTrackLine(marker);// 不满足要求
    }

    /**
     * <p>画航线</p>
     * <li>第一:分航迹规划模式和围栏模式</li>
     * <li>第二:围栏模式分:围栏模式已经启动 -实线情况,围栏模式未启动 -虚线情况</li>
     * <li>第三:围栏模式拖拽:分几个特殊点 ① 起点 ②中间点 ③ 终点 </li>
     * <li>第四:围栏模式拖拽:没启动围栏模式前,是没有最后一根线的,也就是说 5个点四根线 可拖拽的效果也是要分情况的 </li>
     * <li>不仅在拖拽的时候要实况改变预设航线,</li>
     * <li>还要在拖拽结束的时候判断是否满足航线规划的要求</li>
     * <li>满足就按照用户的定义的来,不满足就要回到起始点</li>
     */
    private void drawTrackLine(Marker marker) {
        if (isPfMode == GduConfig.FpMode) { // 航迹规划
            boolean isExceed = AMapUtils.calculateLineDistance(mPfLatLngList.get(0), marker.getPosition()) > fp_validityRange;
            outofrangeCircle(isExceed);
            for (int i = 0; i < mPfMarkerList.size(); i++) {
                if (marker.equals(mPfMarkerList.get(i))) {
                    mPfLatLngList.set(i + 1, marker.getPosition()); // 第一个点是无人机的点,所以要  +1 ;
                    mPfPolylineList.get(i).remove();
                    mPfPolylineList.set(i,
                            addPolyDottedLine(mPfLatLngList.get(i),        //虚线
                                    mPfLatLngList.get(i + 1)));

                    if (i < mPfMarkerList.size() - 1) {
                        mPfPolylineList.get(i + 1).remove();
                        mPfPolylineList.set(i + 1,
                                addPolyDottedLine(mPfLatLngList.get(i + 1),//虚线
                                        mPfLatLngList.get(i + 2)));
                    }
                    updateFlightDisEvent(i, marker);//实况更新飞行距离的事件
                    return;
                }
            }
        } else if (isPfMode == GduConfig.ErMode) { // 电子围栏
            for (int i = 0; i < mErMarkerList.size(); i++) {
                if (marker.equals(mErMarkerList.get(i))) {
                    if (mErMarkerList.size() > 1) {
                        mErLatLngList.set(i, marker.getPosition());// 没有无人机的点,所以就按照第0点来
                        // 一根线  (点的后面那根)
                        if (isElectronicRail_state == GduConfig.ErStart) {   // 已经开启电子围栏模式
                            if (i == mErMarkerList.size() - 1) {  // 【特殊点】移动的是最后一个点就是【起点】,手动添加的 Polyline
                                mErPolylineList.get(i).remove();
                                mErPolylineList.set(i,
                                        addPolySolidLine(mErLatLngList.get(i),//实线
                                                mErLatLngList.get(0)));
                            } else {          // 移动的不是最后一个点
                                mErPolylineList.get(i).remove();
                                mErPolylineList.set(i,
                                        addPolySolidLine(mErLatLngList.get(i),//实线
                                                mErLatLngList.get(i + 1)));
                            }
                        } else {                       // 没有开启电子围栏
                            if (i < mErPolylineList.size()) {
                                mErPolylineList.get(i).remove();
                                mErPolylineList.set(i,
                                        addPolyDottedLine(mErLatLngList.get(i),//虚线
                                                mErLatLngList.get(i + 1)));
                            }
                        }
                        // 二根线  (点的后前面那根)
                        if (isElectronicRail_state == GduConfig.ErStart) {  // 已经开启电子围栏模式
                            if (i == 0) {     //【特殊点】 移动终点
                                mErPolylineList.get(mErPolylineList.size() - 1).remove();
                                mErPolylineList.set(mErPolylineList.size() - 1,
                                        addPolySolidLine(mErLatLngList.get(i), //实线
                                                mErLatLngList.get(mErLatLngList.size() - 1)));
                            } else {
                                mErPolylineList.get(i - 1).remove();
                                mErPolylineList.set(i - 1,
                                        addPolySolidLine(mErLatLngList.get(i),//实线
                                                mErLatLngList.get(i - 1)));
                            }
                        } else {
                            if (i > 0) {
                                mErPolylineList.get(i - 1).remove();
                                mErPolylineList.set(i - 1,
                                        addPolyDottedLine(mErLatLngList.get(i),//虚线
                                                mErLatLngList.get(i - 1)));
                            }
                        }
                        return;
                    }
                }
            }
        }
    }

    /**
     * <p>实况更新飞行距离的事件</p>
     */
    private float dist;

    private void updateFlightDisEvent(int i, Marker marker) {
        // 航线距离问题
        if (i == 0) {
            mPfFlightDisList.set(i, AMapUtils.calculateLineDistance(mPfLatLngList.get(0), marker.getPosition()));
            BBLog.LogE("updateFlightDisEvent-1", AMapUtils.calculateLineDistance(mPfLatLngList.get(0), marker.getPosition()) + "");
        } else if (i == mPfMarkerList.size() - 1) {
            BBLog.LogE("updateFlightDisEvent-2", AMapUtils.calculateLineDistance(mPfLatLngList.get(0), marker.getPosition()) + "");
            mPfFlightDisList.set(i, AMapUtils.calculateLineDistance(mPfLatLngList.get(i), marker.getPosition()));
        } else {
            BBLog.LogE("updateFlightDisEvent-3", AMapUtils.calculateLineDistance(mPfLatLngList.get(0), marker.getPosition()) + "");
            if (i != mPfMarkerList.size() - 1) {
                mPfFlightDisList.set(i + 1, AMapUtils.calculateLineDistance(marker.getPosition(), mPfLatLngList.get(i + 2)));
            }
            mPfFlightDisList.set(i, AMapUtils.calculateLineDistance(marker.getPosition(), mPfLatLngList.get(i)));
        }
        // 重新计算所有的 飞行距离
        for (int j = 0; j < mPfFlightDisList.size(); j++) {
            dist += mPfFlightDisList.get(j);
        }

        mTv_flightdis.setText(df.format(dist) + StringUtils.getUnit());
        dist = 0;
    }

    // ---------在拖动Marker 时候 Circle 的状态判定 ---------------

    // 有效域 圆
    private Circle normal_circle;
    // 无效域 圆
    private Circle warning_circle;
    // 当前手机位置(圆心)
    private LatLng currentphoneLatlng;

    // 设置参数
    public void setParameter(LatLng currentphoneLatlng, Circle warning_circle, Circle normal_circle) {
        this.currentphoneLatlng = currentphoneLatlng;
        this.warning_circle = warning_circle;
        this.normal_circle = normal_circle;
    }

    /**
     * <p>是否超出有效域,超出2000 有效域变色</p>
     * <p>是超出范围的圈/p>
     */
    public void outofrangeCircle(boolean isExceed) {
        if (warning_circle == null) {
            warning_circle = aMap.addCircle(new CircleOptions()
                    .center(currentphoneLatlng)
                    .radius(fp_validityRange)
                    .fillColor(Color.argb(26, 255, 199, 65))  // 填充域颜色
                    .strokeColor(Color.argb(102, 255, 199, 65))// 边框颜色
                    .strokeWidth(2));
        }
        if (isExceed) {
            warning_circle.setVisible(true);
            normal_circle.setVisible(false);
        } else {
            normal_circle.setVisible(true);
            warning_circle.setVisible(false);
        }
    }

}

GPSTranslateGuide.java
package com.gdu.mvp_view.flightRouteplan.helper;

import com.amap.api.maps.model.LatLng;

import java.util.HashMap;
import java.util.Map;

/**
 * <P>火星坐标和大地坐标的转换</P>
 */
public class GPSTranslateGuide {

    static double pi = 3.14159265358979324;
    static double a = 6378245.0;
    static double ee = 0.00669342162296594323;

    public static com.amap.api.maps.model.LatLng AmapTransform(double wgLat, double wgLon) {

        double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
        double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
        double radLat = wgLat / 180.0 * pi;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        double mgLat = wgLat + dLat;
        double mgLon = wgLon + dLon;

        com.amap.api.maps.model.LatLng latLng = new com.amap.api.maps.model.LatLng(mgLat, mgLon);

        return latLng;
    }
    public static com.google.android.gms.maps.model.LatLng GoogleTransform(double wgLat, double wgLon) {

        double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
        double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
        double radLat = wgLat / 180.0 * pi;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        double mgLat = wgLat + dLat;
        double mgLon = wgLon + dLon;

        com.google.android.gms.maps.model.LatLng latLng = new com.google.android.gms.maps.model.LatLng(mgLat, mgLon);

        return latLng;
    }

    //转换经纬度地纬度
    static double transformLat(double x, double y) {
        double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    //转换经纬度的纬度
    static double transformLon(double x, double y) {
        double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
        return ret;
    }

    /**
     * <p>GCJ02坐标系:即火星坐标系</p>
     * <p>WGS坐标系:即地球坐标</p>
     * <p>火星坐标转地球坐标</p>
     * @param lon
     * @param lat
     * @return
     */
    public static com.amap.api.maps.model.LatLng gcj2wgs(double lon, double lat) {
        double lontitude = lon
                - (((Double) transformtoWGS(lon, lat).get("lon")).doubleValue() - lon);
        double latitude = (lat - (((Double) (transformtoWGS(lon, lat))
                .get("lat")).doubleValue() - lat));

        com.amap.api.maps.model.LatLng latLng = new com.amap.api.maps.model.LatLng(latitude, lontitude);
        return latLng;
    }

    /**
     * <p>(地球)大地坐标</p>
     *
     * @param lon
     * @param lat
     * @return
     */
    public static Map<String, Double> transformtoWGS(double lon, double lat) {
        HashMap<String, Double> localHashMap = new HashMap<String, Double>();
        double dLat = transformLat(lon - 105.0, lat - 35.0);
        double dLon = transformLon(lon - 105.0, lat - 35.0);
        double radLat = lat / 180.0 * pi;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        double mgLat = lat + dLat;
        double mgLon = lon + dLon;
        localHashMap.put("lon", mgLon);
        localHashMap.put("lat", mgLat);
        return localHashMap;
    }


    /**
     * @anthor yuhao
     * 大地坐标转火星坐标
     * @param wgLat
     * @param wgLon
     * @return
     */
    public static LatLng transform2Mars(double wgLat, double wgLon)
    {
        double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
        double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
        double radLat = wgLat / 180.0 * pi;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        double mgLat = wgLat + dLat;
        double mgLon = wgLon + dLon;
        LatLng latLng = new LatLng(mgLat, mgLon);
        return latLng;
    }
}




感谢各位大佬观看,哪里不对请指出,或者有疑问给我留言,可以交流。

          下一期:展示几个动画和View  就是我们产品 给我定义的几个 自创 动画效果,
            如图一,本来我以为很难,我在一步一步摸索,然后简化后发现只需要2句代码就可以了。真的这个效果只需要2句代码。
                                                                                                                                                                                              下期详细解释。







  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
大疆Onboard开发教程是一套专门针对大疆无人机Onboard SDK进行开发的教程。该教程旨在帮助开发者更好地利用Onboard SDK进行无人机控制和数据交互的应用开发。 首先,在学习Onboard开发教程之前,我们需要先了解一些基础知识。大疆无人机Onboard SDK主要基于C++语言进行开发,所以有一定的C++编程基础会有很大的帮助。另外,了解无人机的基本工作原理、传感器信息以及无人机飞行控制系统的相关知识也是很重要的。 大疆Onboard开发教程主要包括以下几个方面的内容:通信接口、飞行控制、传感器数据获取和控制指令发送。首先是通信接口,通过Onboard SDK提供的通信接口,开发者可以与无人机建立稳定的通信连接,实现数据的传输和指令的交互。 其次是飞行控制,通过Onboard开发教程,开发者可以了解和掌握无人机的基本飞行控制原理,实现对无人机的起飞、降落、悬停等操作。同时,还可以通过编写控制指令,实现对无人机的高级控制,如航点飞行、航迹跟踪等。 然后是传感器数据获取,通过Onboard开发教程,开发者可以了解无人机传感器的类型和工作原理,并学习如何获取和解析传感器数据,如位置信息、姿态信息、相机图像等。这些数据对于开发应用程序非常重要。 最后是控制指令发送,通过Onboard开发教程,开发者可以学习如何编写控制指令,将指令发送给无人机,实现对无人机的控制。开发者可以自定义控制指令,实现更复杂的功能。 总之,大疆Onboard开发教程是一套专门针对无人机Onboard SDK的教程,通过学习该教程,开发者可以了解和掌握无人机的控制原理和数据交互方式,进而进行无人机的应用开发
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值