GIS Map Learning Notes VI Scale Maps by Layer

Keywords: Java REST JSON ftp

The Method of Setting Map Scaling Proportion in ArcGis

 mMapView.setViewpointScaleAsync(scale);

demand

Click on the zoom button (+"-) on the map and let the map zoom according to the map layer. For example, a map contains the following layers. Each layer has a zoom scale. When we click on the zoom button (+"-), we need to set the zoom scale of the map according to the different level s below.

"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
   }
  ]

code implementation

1. Layer Information Acquisition Tool Class

In order to zoom by layer, we need to get the layer information of the corresponding map service first. The tool class ReturnJson.java is used. We should pay attention to the networking request and execute it in the sub-thread. Using URL format is "your map server url"+? f=pjson, for example:

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

Note that your map service address does not end with'/'. It should be in the same format as the example, followed directly by MapServer? f=pjson.

public class ReturnJson {
    public ReturnJson(String strURL) {
        //Judge 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();
            }
        }
    }

    // Save the scaling ratio in parsing 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");
            for (int i = 0; i < jsonArray_lods.length(); i++) {
                TileInfoBean.LodsBean lodsBean = new TileInfoBean.LodsBean();
                JSONObject jsonObject3 = (JSONObject) jsonArray_lods.opt(i);
                lodsBean.setLevel(jsonObject3.getInt("level"));
                lodsBean.setResolution(jsonObject3.getDouble("resolution"));
                lodsBean.setScale(jsonObject3.getDouble("scale"));
                list.add(lodsBean);
            }
            infoBean.setLods(list);
            MyApplication.getInstance().setTileInfoBean(infoBean);
        } catch (Exception e) {
            // TODO: handle exception
        }

    }
}

The related tool class in the code, MyUtils.isUrl(strURL)

 /**
     * Match URL address
     */
    public static boolean isUrl(String str) {
        return match(str, "(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]");
    }
    /**
     * Regular Expression Matching
     * @param text   Text to be matched
     * @param reg  regular expression
     * @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();
    }

The related entity class in the code, TileInfoBean.java, because I only need layer information, so the defined entity class only contains layer information, if there are other requirements can be redefined.

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. Use of Layer Information Acquisition Tool Class

Called when loading the map, be careful to execute in the sub-thread

 new Thread(new Runnable() {
                @Override
                public void run() {
                    new ReturnJson(url);    //Scaling Ratio of Stored Maps
                }
            }).start();

3. Click and zoom

  case R.id.scale_max:  // + operation
     changeScale(MAX);
     break;
  case R.id.scale_min: // - operation
     changeScale(MIN);
     break;
private double CurrentScale = 15500;
...
//Changing Map Scaling Ratio by Layer
    private void changeScale(String type) {
        TileInfoBean bean = instance.getTileInfoBean();
        if (bean == null) {
            new CenterHintToast(MainActivity.this, "Failed to obtain scaling ratio");
            return;
        }
        List<TileInfoBean.LodsBean> lods = bean.getLods();
        if (lods == null || lods.size() <= 0) return;
        double mapScale = mMapView.getMapScale();
        for (int i = 0; i < lods.size() - 1; i++) {
            if (MAX.equals(type)) {  // + Operations (enlarging maps, reducing display areas)
                if (mapScale <= lods.get(i).getScale() && mapScale > lods.get(i+1).getScale()) {
                    CurrentScale = lods.get(i+1).getScale();
                }
            } else if (MIN.equals(type)) {  // - Operations (Reducing Maps, Enlarging Display Areas)
                if (mapScale < lods.get(i).getScale() && mapScale >= lods.get(i+1).getScale()) {
                    CurrentScale = lods.get(i).getScale();
                }
            }
        }
        mMapView.setViewpointScaleAsync(CurrentScale);
    }

The above for loop uses I < lods. size () - 1 instead of I < lods. size () to prevent subscripts from crossing the bounds, because the operation uses i+1

4, the end

ok, so that's it. With the above code, when the map is zoomed to the maximum or minimum scale, the map will no longer zoom, and the code will still execute, except that the zoom ratio set for the map will not change the value of CurrentScale.
In addition, it doesn't matter if you zoom the map using gesture recognition before clicking on the zoom button "+"-", because the code above takes the current zoom ratio of the map for calculation.

Posted by maniac1aw on Sat, 18 May 2019 12:24:13 -0700