GIS地圖學習筆記六之按圖層縮放地圖

ArcGis中設置地圖縮放比例的方法

 mMapView.setViewpointScaleAsync(scale);

需求

點擊地圖上的縮放按鈕“+”“-” ,讓地圖按照地圖的圖層進行縮放,比如一個地圖包含以下圖層,每一個圖層都有一個縮放比例scale,就是我們在點擊縮放按鈕“+”“-” 的時候需要按照下面的不同層級(level)的縮放比(scale)來設置地圖的縮放比。

"lods": [
   {
    "level": 0,
    "resolution": 0.009746272279880825,
    "scale": 4096000
   },
   {
    "level": 1,
    "resolution": 0.004873136139940413,
    "scale": 2048000
   },
   {
    "level": 2,
    "resolution": 0.0024365680699702063,
    "scale": 1024000
   },
   {
    "level": 3,
    "resolution": 0.0012182840349851032,
    "scale": 512000
   },
   {
    "level": 4,
    "resolution": 6.091420174925516E-4,
    "scale": 256000
   },
   {
    "level": 5,
    "resolution": 3.045710087462758E-4,
    "scale": 128000
   },
   {
    "level": 6,
    "resolution": 1.522855043731379E-4,
    "scale": 64000
   },
   {
    "level": 7,
    "resolution": 7.614275218656895E-5,
    "scale": 32000
   },
   {
    "level": 8,
    "resolution": 3.8071376093284474E-5,
    "scale": 16000
   },
   {
    "level": 9,
    "resolution": 1.9035688046642237E-5,
    "scale": 8000
   },
   {
    "level": 10,
    "resolution": 9.517844023321119E-6,
    "scale": 4000
   },
   {
    "level": 11,
    "resolution": 4.758922011660559E-6,
    "scale": 2000
   },
   {
    "level": 12,
    "resolution": 2.3794610058302796E-6,
    "scale": 1000
   },
   {
    "level": 13,
    "resolution": 1.1897305029151398E-6,
    "scale": 500
   }
  ]

代碼實現

1、圖層信息獲取工具類

要實現按圖層縮放,我們需要先來獲取對應地圖服務的圖層信息,使用的工具類ReturnJson.java,使用handler 返回地圖服務地址、地圖最大縮放比和最小縮放比,注意有聯網請求,需要在子線程中執行。使用url格式是“your map server url ”+”?f=pjson” , 例如:

http://119.97.224.2:8399/PBS/rest/services/MapsRoad/MapServer?f=pjson

注意你的地圖服務地址不要用 “/” 結尾,要和示例相同的格式 ,直接在MapServer後面接?f=pjson 。

public class ReturnJson {
   private Handler mHandler;
   private String mURL;

    public ReturnJson(String strURL, Handler handler) {
        this.mHandler = handler;
        this.mURL = strURL;
        //判斷strURL
        String end = "";
        if (!TextUtils.isEmpty(strURL)) {
            end = strURL.substring(strURL.length() - 1, strURL.length());
        }else {
            return;
        }
        HttpURLConnection httpConnection = null;
        try {
            if (!MyUtils.isUrl(strURL))return;
            if ("/".equals(end)) {
                strURL = strURL.substring(0,strURL.length() - 1);
            }
            URL url = new URL(strURL+"?f=pjson");
            byte[] buf = new byte[1024];
            httpConnection = (HttpURLConnection) url.openConnection();
            httpConnection.connect();
            InputStream in = httpConnection.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuffer response = new StringBuffer();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            String string = response.toString();
            httpConnection.disconnect();
            ExplainJson(string);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (httpConnection != null){
                httpConnection.disconnect();
            }
        }
    }

    // 解析json中縮放比率保存起來
    private void ExplainJson(String retStr) {
        try {
            TileInfoBean infoBean = new TileInfoBean();
            ArrayList<TileInfoBean.LodsBean> list = new ArrayList<>();
            JSONObject tileInfo = new JSONObject(retStr).getJSONObject("tileInfo");
            JSONArray jsonArray_lods = tileInfo.getJSONArray("lods");
            if (jsonArray_lods!=null&&jsonArray_lods.length()>0){
                //最大值的縮放比
                JSONObject jsonObjectMax = (JSONObject) jsonArray_lods.opt(0);
                double fastScale = jsonObjectMax.getDouble("scale");
                //最小值的縮放比
                JSONObject jsonObjectMin = (JSONObject) jsonArray_lods.opt(jsonArray_lods.length()-1);
                double lastScale = jsonObjectMin.getDouble("scale");
                Message message = new Message();
                message.what = 13;
                Bundle bundle = new Bundle();
                bundle.putString("url",mURL);
                bundle.putDouble("fastScale",fastScale);
                bundle.putDouble("lastScale",lastScale);
                message.setData(bundle);
                mHandler.sendMessage(message);
            }
            for (int i = 0; i < jsonArray_lods.length(); i++) {
                TileInfoBean.LodsBean lodsBean = new TileInfoBean.LodsBean();
                JSONObject jsonObject3 = (JSONObject) jsonArray_lods.opt(i);
                int level = jsonObject3.getInt("level");
                double scale = jsonObject3.getDouble("scale");
                double resolution = jsonObject3.getDouble("resolution");
                lodsBean.setLevel(level);
                lodsBean.setResolution(resolution);
                lodsBean.setScale(scale);
                list.add(lodsBean);
            }
            infoBean.setLods(list);
            MyApplication.getInstance().setTileInfoBean(infoBean);
        } catch (Exception e) {
            // TODO: handle exception
        }

    }
}

代碼中相關的工具類,MyUtils.isUrl(strURL)

 /**
     * 匹配URL地址
     */
    public static boolean isUrl(String str) {
        return match(str, "(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]");
    }
    /**
     * 正則表達式匹配
     * @param text   待匹配的文本
     * @param reg  正則表達式
     * @return
     */
    private static boolean match(String text, String reg) {
        if (TextUtils.isEmpty(text) || TextUtils.isEmpty(reg)) return false;
        return Pattern.compile(reg).matcher(text).matches();
    }

代碼中相關的實體類,TileInfoBean.java,因爲我只需要圖層信息,所以定義的實體類只包含圖層的相關信息,如果有其他需求可以自己重新定義。

public class TileInfoBean implements Parcelable{
    private List<LodsBean> lods;

    public List<LodsBean> getLods() {
        return lods;
    }

    public void setLods(List<LodsBean> lods) {
        this.lods = lods;
    }

    protected TileInfoBean(Parcel in) {
    }

    public TileInfoBean() {
    }

    public static final Creator<TileInfoBean> CREATOR = new Creator<TileInfoBean>() {
        @Override
        public TileInfoBean createFromParcel(Parcel in) {
            return new TileInfoBean(in);
        }

        @Override
        public TileInfoBean[] newArray(int size) {
            return new TileInfoBean[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
    }

    public static class LodsBean {
        private int level;
        private double resolution;
        private double scale;

        public int getLevel() {
            return level;
        }

        public void setLevel(int level) {
            this.level = level;
        }

        public double getResolution() {
            return resolution;
        }

        public void setResolution(double resolution) {
            this.resolution = resolution;
        }

        public double getScale() {
            return scale;
        }

        public void setScale(double scale) {
            this.scale = scale;
        }
    }
}

2、加載地圖,獲取圖層信息

在加載地圖的時候調用,注意要在子線程中執行

 new Thread(new Runnable() {
            @Override
            public void run() {
                new ReturnJson(url,mHandler);    //存地圖縮放比例
            }
        }).start();

3、點擊縮放

  case R.id.scale_max:  // + 運算
     changeScale(MAX);
     break;
  case R.id.scale_min: // - 運算
     changeScale(MIN);
     break;
private double CurrentScale = 15500;
...
//改變地圖縮放比例--按圖層
private void changeScale(String type) {
        TileInfoBean bean = instance.getTileInfoBean();
        if (bean == null) {
            new CenterHintToast(MainActivity.this, "獲取縮放比例失敗");
            return;
        }
        List<TileInfoBean.LodsBean> lods = bean.getLods();
        if (lods == null || lods.size() <= 0) return;
        double mapScale = mMapView.getMapScale();
        double fastScale = lods.get(0).getScale();
        double lastScale = lods.get(lods.size() - 1).getScale();
        if (mapScale>=fastScale&&MIN.equals(type))return;
        if (mapScale<=lastScale&&MAX.equals(type))return;
        for (int i = 0; i < lods.size() - 1; i++) {
            if (MAX.equals(type)) {  // + 運算(放大地圖、顯示區域變小)
                if (mapScale <= lods.get(i).getScale() && mapScale > lods.get(i+1).getScale()) {
                    CurrentScale = lods.get(i+1).getScale();
                }
            } else if (MIN.equals(type)) {  // - 運算(縮小地圖、顯示區域變大)
                if (mapScale < lods.get(i).getScale() && mapScale >= lods.get(i + 1).getScale()) {
                    CurrentScale = lods.get(i).getScale();
                }
            }
        }
        mMapView.setViewpointScaleAsync(CurrentScale);
    }

上面for循環的時候使用i < lods.size() - 1而不是i < lods.size()是爲了防止下標越界,因爲運算使用了i+1


4、利用圖層信息配置地圖最大、最小縮放比

獲取地圖配置信息成功後,利用handler傳遞信息,配置地圖最大和最小縮放比,並設置地圖中心點及當前顯示比例。

 //--獲取地圖配置信息成功
    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 13:
                    Bundle data = msg.getData();
                    String url = data.getString("url");
                    MinScale = data.getDouble("fastScale");
                    MaxScale = data.getDouble("lastScale");
                    ArcGISTiledLayer tiledLayer = new ArcGISTiledLayer(url);
                    tiledLayer.setMinScale(MinScale);  //控制縮小,數值越大,縮小倍數越大,看的範圍越廣
                    tiledLayer.setMaxScale(MaxScale);   //控制放大,數值越小,放大倍數越高
                    Basemap basemap = new Basemap(tiledLayer);
                    mArcGISMap = new ArcGISMap(basemap);
                    mMapView.setMap(mArcGISMap);
                    Point point = CoordinateFormatter.fromLatitudeLongitude(center, SpatialReferences.getWgs84());
                    mMapView.setViewpointCenterAsync(point, CurrentScale);
                    break;
            }
        }
    };

5、結束

ok,到這裏就寫完了,使用上面的代碼,當地圖縮放到最大或最小比例之後,地圖將不再縮放,代碼還是會執行,只是給地圖設置的縮放比CurrentScale的數值不會變化。
另外,如果你在點擊縮放按鈕“+”“-” 之前先使用手勢識別進行了地圖縮放也沒有關係,因爲上面的代碼取的是地圖當前的縮放比進行計算的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章