Android-基于无人机-禁飞区/限飞区【地图】的开发

来源:互联网 发布:mac怎么使用百度云 编辑:程序博客网 时间:2024/05/16 05:59

   前段时间,深圳出现限飞政策,我司深圳分公司市场部被深圳某局约谈,具体内容是针对无人的管制问题。为了积极的响应号召,我们第一时间在APP 上做了一个提示和限制,后期飞机的飞控进行更新会把这一限飞区和禁飞区落实到硬件中去。

【本文中 使用的是  高德地图/Google地图】

需求具体可分为:一 :禁飞区/限飞区 ,意思大家都理解,不多阐述。 二 :区域的形状,圆形/不规则多边形

圆形很好判断,举个栗子:

Circle circle  circle = aMap.addCircle(new CircleOptions()                        .center(currentphoneLatlng)                        .radius(fp_validityRange)                        .fillColor(Color.argb(26, 0, 120, 255))  // 填充域颜色                        .strokeColor(Color.argb(102, 0, 160, 233))// 边框颜色                        .strokeWidth(2));

 随便找一个坐标,生成一个区域,就可以 成为一个 禁飞区 区域或者是限飞区区域,因为区域比较规范和常规,因此 判断起来也是比较好判断的。

Amap(高德)

AMapUtils.calculateLineDistance(planposition, curPeoplePosition)

运用地图自带的API 计算方式,来计算出2个左边直接的距离 是否小于/大于 半径,就可以判断出是否是在禁飞区内外

Google(谷歌)

/**     * <p>获取Google 地图上,2点之间的距离</p>     *     * @param start     * @param end     * @return     */    public double getGoogleDistance(LatLng start, LatLng end) {        double lat1 = (Math.PI / 180) * start.latitude;        double lat2 = (Math.PI / 180) * end.latitude;        double lon1 = (Math.PI / 180) * start.longitude;        double lon2 = (Math.PI / 180) * end.longitude;        double R = 6371;        double d = Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1)                * Math.cos(lat2) * Math.cos(lon2 - lon1))                * R;        return d * 1000;    }
  这是最基本的需求,但一般没有那一块区域就这么 规范,所以 多边形 区域的判定才是重点

先设置

aMap.setOnMapLoadedListener(this);// 地图加载监听
 aMap.setOnMapClickListener(this);   //地图点击监听
在回调中进行 区域的 绘制 
    /**     * Marker地图点击监听事件     *     * @param latLng     */    @Override    public void onMapClick(LatLng latLng) {        LatLng curLatlng = latLng;              // 电子围栏        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) {            // 即当开始电子围栏,在点击地图,无响应,不增加点        }    }

ps:第一次做gif 真麻烦啊,还不清晰

如图在地图上点击生成Marker 点,并进行连线


我这个最多支持 6个点,最后 做一个补全,用的是

 /**     * <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>     * <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);    }


关键部分的判断 语句在是这个!!!!!!!

C语言的!

int pnpoly (int nvert, float *vertx, float *verty, float testx, float testy) {    int i, j, c = 0;    for (i = 0, j = nvert-1; i < nvert; j = i++) {        if ( ( (verty[i]>testy) != (verty[j]>testy) ) &&(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )            c = !c;    }    return c;}
java语言的!

  /**     * <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;    }
这个表达式的意思是说,随便画个多边形,随便定一个点,然后通过这个点水平划一条线,先数数看这条横线和多边形的边相交几次,(或者说先排除那些不相交的边,第一个判断条件),然后再数这条横线穿越多边形的次数是否为奇数,如果是奇数,那么该点在多边形内,如果是偶数,则在多边形外。(根据W. Randolph Franklin 提出的PNPoly算法)

这样只要有了判断就很容易了,然后做自己的逻辑判断。



下一章:附上我整个航迹规划,电子围栏的一个 代码 java文件。你会学到在Marker上打标记,还可以拖动marker连同线一起在动。


                                                                                                                                                                                                各位看官,大佬轻喷。