显示地图和定位
对于一个地图SDK来说,首先要显示地图,然后定位到当前城市。这方面百度地图和高德地图的处理代码差不多,下面是两种地图sdk显示并定位的代码例子:
百度地图
- // 以下主要是定位用到的代码
- private MapView mMapView;
- private BaiduMap mMapLayer;
- private LocationClient mLocClient;
- private boolean isFirstLoc = true;// 是否首次定位
- private void initLocation() {
- mMapView = (MapView) findViewById(R.id.bmapView);
- // 先隐藏地图,待定位到当前城市时再显示
- mMapView.setVisibility(View.INVISIBLE);
- mMapLayer = mMapView.getMap();
- mMapLayer.setOnMapClickListener(this);
- // 开启定位图层
- mMapLayer.setMyLocationEnabled(true);
- mLocClient = new LocationClient(this);
- // 设置定位监听器
- mLocClient.registerLocationListener(new MyLocationListenner());
- LocationClientOption option = new LocationClientOption();
- option.setOpenGps(true);// 打开gps
- option.setCoorType("bd09ll"); // 设置坐标类型
- option.setScanSpan(1000);
- option.setIsNeedAddress(true); // 设置true才能获得详细的地址信息
- // 设置定位参数
- mLocClient.setLocOption(option);
- // 开始定位
- mLocClient.start();
- //获取最近一次的位置
- // mLocClient.getLastKnownLocation();
- }
- public class MyLocationListenner implements BDLocationListener {
- @Override
- public void onReceiveLocation(BDLocation location) {
- // map view 销毁后不在处理新接收的位置
- if (location == null || mMapView == null) {
- Log.d(TAG, "location is null or mMapView is null");
- return;
- }
- m_latitude = location.getLatitude();
- m_longitude = location.getLongitude();
- String position = String.format("当前位置:%s|%s|%s|%s|%s|%s|%s",
- location.getProvince(), location.getCity(),
- location.getDistrict(), location.getStreet(),
- location.getStreetNumber(), location.getAddrStr(),
- location.getTime());
- loc_position.setText(position);
- MyLocationData locData = new MyLocationData.Builder()
- .accuracy(location.getRadius())
- // 此处设置开发者获取到的方向信息,顺时针0-360
- .direction(100).latitude(m_latitude)
- .longitude(m_longitude).build();
- mMapLayer.setMyLocationData(locData);
- if (isFirstLoc) {
- isFirstLoc = false;
- LatLng ll = new LatLng(m_latitude, m_longitude);
- MapStatusUpdate update = MapStatusUpdateFactory.newLatLngZoom(ll, 14);
- mMapLayer.animateMapStatus(update);
- // 定位到当前城市时再显示图层
- mMapView.setVisibility(View.VISIBLE);
- }
- }
- public void onReceivePoi(BDLocation poiLocation) {
- }
- }
POI搜索
POI即地图注点,它是“Point of Interest”的缩写,在地图上标注地点名称、类别、经度、纬度等信息,是一个带位置信息的地图标注。POI搜索是地图sdk的一个重要应用,根据关键字搜索并在地图上显示POI结果,这是智能出行的基础。下面是使用百度地图搜索POI的截图:
下面是两种地图sdk进行POI搜索的代码例子:
百度地图
- // 以下主要是POI搜索用到的代码
- private PoiSearch mPoiSearch = null;
- private SuggestionSearch mSuggestionSearch = null;
- private AutoCompleteTextView mKey = null;
- private EditText mScope = null;
- private Button btn_search, btn_nextpage, btn_cleardata;
- private ArrayAdapter<String> sugAdapter = null;
- private int load_Index = 0;
- private void initMap() {
- mPoiSearch = PoiSearch.newInstance();
- mPoiSearch.setOnGetPoiSearchResultListener(this);
- mSuggestionSearch = SuggestionSearch.newInstance();
- mSuggestionSearch.setOnGetSuggestionResultListener(this);
- mScope = (EditText) findViewById(R.id.poi_city);
- mKey = (AutoCompleteTextView) findViewById(R.id.poi_searchkey);
- btn_search = (Button) findViewById(R.id.search);
- btn_nextpage = (Button) findViewById(R.id.map_next_data);
- btn_cleardata = (Button) findViewById(R.id.map_clear_data);
- btn_search.setOnClickListener(this);
- btn_nextpage.setOnClickListener(this);
- btn_cleardata.setOnClickListener(this);
- sugAdapter = new ArrayAdapter<String>(this, R.layout.spinner_dropdown_item);
- mKey.setAdapter(sugAdapter);
- // 当输入关键字变化时,动态更新建议列表
- mKey.addTextChangedListener(new TextWatcher() {
- @Override
- public void afterTextChanged(Editable arg0) {
- }
- @Override
- public void beforeTextChanged(CharSequence arg0, int arg1,
- int arg2, int arg3) {
- }
- @Override
- public void onTextChanged(CharSequence cs, int arg1, int arg2,
- int arg3) {
- if (cs.length() <= 0) {
- return;
- }
- String city = mScope.getText().toString();
- // 使用建议搜索服务获取建议列表,结果在onGetSuggestionResult中更新
- mSuggestionSearch
- .requestSuggestion((new SuggestionSearchOption())
- .keyword(cs.toString()).city(city));
- }
- });
- }
- @Override
- public void onGetSuggestionResult(SuggestionResult res) {
- if (res == null || res.getAllSuggestions() == null) {
- return;
- } else {
- sugAdapter.clear();
- for (SuggestionResult.SuggestionInfo info : res.getAllSuggestions()) {
- if (info.key != null) {
- sugAdapter.add(info.key);
- }
- }
- sugAdapter.notifyDataSetChanged();
- }
- }
- // 影响搜索按钮点击事件
- public void searchButtonProcess(View v) {
- Log.d(TAG, "editCity=" + mScope.getText().toString()
- + ", editSearchKey=" + mKey.getText().toString()
- + ", load_Index=" + load_Index);
- String keyword = mKey.getText().toString();
- if (search_method == SEARCH_CITY) {
- String city = mScope.getText().toString();
- mPoiSearch.searchInCity((new PoiCitySearchOption()).city(city)
- .keyword(keyword).pageNum(load_Index));
- } else if (search_method == SEARCH_NEARBY) {
- LatLng position = new LatLng(m_latitude, m_longitude);
- int radius = Integer.parseInt(mScope.getText().toString());
- mPoiSearch.searchNearby((new PoiNearbySearchOption())
- .location(position).keyword(keyword).radius(radius)
- .pageNum(load_Index));
- }
- }
- public void goToNextPage(View v) {
- load_Index++;
- searchButtonProcess(null);
- }
- public void onGetPoiResult(PoiResult result) {
- if (result == null
- || result.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {
- Toast.makeText(this, "未找到结果", Toast.LENGTH_LONG).show();
- return;
- } else if (result.error == SearchResult.ERRORNO.NO_ERROR) {
- mMapLayer.clear();
- PoiOverlay overlay = new MyPoiOverlay(mMapLayer);
- mMapLayer.setOnMarkerClickListener(overlay);
- List<PoiInfo> poiList = result.getAllPoi();
- overlay.setData(result);
- overlay.addToMap();
- overlay.zoomToSpan();
- // for (PoiInfo poi : poiList) {
- // String detail = String.format(
- // "uid=%s,city=%s,name=%s,phone=%s, address=%s", poi.uid,
- // poi.city, poi.name, poi.phoneNum, poi.address);
- // Log.d(TAG, detail); // 坐标为poi.location(LatLng结构)
- // }
- } else if (result.error == SearchResult.ERRORNO.AMBIGUOUS_KEYWORD) {
- // 当输入关键字在本市没有找到,但在其他城市找到时,返回包含该关键字信息的城市列表
- String strInfo = "在";
- for (CityInfo cityInfo : result.getSuggestCityList()) {
- strInfo += cityInfo.city + ",";
- }
- strInfo += "找到结果";
- Toast.makeText(this, strInfo, Toast.LENGTH_LONG).show();
- }
- }
- public void onGetPoiDetailResult(PoiDetailResult result) {
- if (result.error != SearchResult.ERRORNO.NO_ERROR) {
- Toast.makeText(this, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
- } else {
- Log.d(TAG,
- "name=" + result.getName() + ",address="
- + result.getAddress() + ",detail_url="
- + result.getDetailUrl() + ",shop_hours="
- + result.getShopHours() + ",telephone="
- + result.getTelephone() + ",price="
- + result.getPrice() + ",type=" + result.getType()
- + ",tag=" + result.getTag());
- Toast.makeText(this, result.getName() + ": " + result.getAddress(),
- Toast.LENGTH_SHORT).show();
- }
- }
- private class MyPoiOverlay extends PoiOverlay {
- public MyPoiOverlay(BaiduMap baiduMap) {
- super(baiduMap);
- }
- @Override
- public boolean onPoiClick(int index) {
- super.onPoiClick(index);
- PoiInfo poi = getPoiResult().getAllPoi().get(index);
- mPoiSearch.searchPoiDetail((new PoiDetailSearchOption()).poiUid(poi.uid));
- return true;
- }
- }
测距、测面积
测量距离和测量面积是地图sdk的又一个应用,除了在地图上添加标注之外,就是要用到数学的两个公式。其中测距用的是勾股定理(又名商高定理):勾股定理是一个基本的几何定理:一个直角三角形,两直角边的平方和等于斜边的平方。如果直角三角形两直角边为a和b,斜边为c,那么a*a+b*b=c*c
测面积用的是海伦公式(又名秦九韶公式):海伦公式是利用三角形的三个边长直接求三角形面积的公式,表达式为:S=√p(p-a)(p-b)(p-c)。基于海伦公式,可以推导出根据多边形各边长求多边形面积的公式,即S = 0.5 * ( (x0*y1-x1*y0) + (x1*y2-x2*y1) + ... + (xn*y0-x0*yn) )
两种地图sdk在测量上的数学原理是一样的,只在添加地图标注上有些小差异,下面是使用高德地图进行测量的截图:
下面是两种地图sdk进行测量的代码例子:
百度地图
- // 下面是在地图上添加绘图操作
- private static int lineColor = 0x55FF0000;
- private static int arcColor = 0xbb00FFFF;
- private static int textColor = 0x990000FF;
- private static int polygonColor = 0x77FFFF00;
- private static int radius = 100;
- private ArrayList<LatLng> posArray = new ArrayList<LatLng>();
- boolean is_polygon = false;
- private void addDot(LatLng pos) {
- if (is_polygon == true && posArray.size() > 1
- && MapUtil.isInsidePolygon(pos, posArray) == true) {
- Log.d(TAG, "isInsidePolygon");
- LatLng centerPos = MapUtil.getCenterPos(posArray);
- OverlayOptions ooText = new TextOptions().bgColor(0x00ffffff)
- .fontSize(26).fontColor(textColor).text("标题")// .rotate(-30)
- .position(centerPos);
- mMapLayer.addOverlay(ooText);
- return;
- }
- if (is_polygon == true) {
- Log.d(TAG, "is_polygon == true");
- posArray.clear();
- is_polygon = false;
- }
- boolean is_first = false;
- LatLng thisPos = pos;
- if (posArray.size() > 0) {
- LatLng firstPos = posArray.get(0);
- int distance = (int) Math.round(MapUtil.getShortDistance(
- thisPos.longitude, thisPos.latitude, firstPos.longitude,
- firstPos.latitude));
- //多次点击起点,要忽略之
- if (posArray.size()==1 && distance<=0) {
- return;
- } else if (posArray.size() > 1) {
- LatLng lastPos = posArray.get(posArray.size()-1);
- int lastDistance = (int) Math.round(MapUtil.getShortDistance(
- thisPos.longitude, thisPos.latitude, lastPos.longitude,
- lastPos.latitude));
- //重复响应当前位置的点击,要忽略之
- if (lastDistance <= 0) {
- return;
- }
- }
- if (distance < radius * 2) {
- thisPos = firstPos;
- is_first = true;
- }
- Log.d(TAG, "distance="+distance+", radius="+radius+", is_first="+is_first);
- // 画直线
- LatLng lastPos = posArray.get(posArray.size() - 1);
- List<LatLng> points = new ArrayList<LatLng>();
- points.add(lastPos);
- points.add(thisPos);
- OverlayOptions ooPolyline = new PolylineOptions().width(2)
- .color(lineColor).points(points);
- mMapLayer.addOverlay(ooPolyline);
- // 下面计算两点之间距离
- distance = (int) Math.round(MapUtil.getShortDistance(
- thisPos.longitude, thisPos.latitude, lastPos.longitude,
- lastPos.latitude));
- String disText = "";
- if (distance > 1000) {
- disText = Math.round(distance * 10 / 1000) / 10d + "公里";
- } else {
- disText = distance + "米";
- }
- LatLng llText = new LatLng(
- (thisPos.latitude + lastPos.latitude) / 2,
- (thisPos.longitude + lastPos.longitude) / 2);
- OverlayOptions ooText = new TextOptions().bgColor(0x00ffffff)
- .fontSize(24).fontColor(textColor).text(disText)// .rotate(-30)
- .position(llText);
- mMapLayer.addOverlay(ooText);
- }
- if (is_first != true) {
- // 画圆圈
- OverlayOptions ooCircle = new CircleOptions().fillColor(lineColor)
- .center(thisPos).stroke(new Stroke(2, 0xAAFF0000)).radius(radius);
- mMapLayer.addOverlay(ooCircle);
- // 画图片标记
- BitmapDescriptor bitmapDesc = BitmapDescriptorFactory
- .fromResource(R.drawable.icon_geo);
- OverlayOptions ooMarker = new MarkerOptions().draggable(false)
- .visible(true).icon(bitmapDesc).position(thisPos);
- mMapLayer.addOverlay(ooMarker);
- mMapLayer.setOnMarkerClickListener(new OnMarkerClickListener() {
- @Override
- public boolean onMarkerClick(Marker marker) {
- LatLng markPos = marker.getPosition();
- addDot(markPos);
- return true;
- }
- });
- } else {
- Log.d(TAG, "posArray.size()="+posArray.size());
- //可能存在地图与标记同时响应点击事件的情况
- if (posArray.size() < 3) {
- posArray.clear();
- is_polygon = false;
- return;
- }
- // 画多边形
- OverlayOptions ooPolygon = new PolygonOptions().points(posArray)
- .stroke(new Stroke(1, 0xFF00FF00))
- .fillColor(polygonColor);
- mMapLayer.addOverlay(ooPolygon);
- is_polygon = true;
- // 下面计算多边形的面积
- LatLng centerPos = MapUtil.getCenterPos(posArray);
- double area = Math.round(MapUtil.getArea(posArray));
- String areaText = "";
- if (area > 1000000) {
- areaText = Math.round(area * 100 / 1000000) / 100d + "平方公里";
- } else {
- areaText = (int) area + "平方米";
- }
- OverlayOptions ooText = new TextOptions().bgColor(0x00ffffff)
- .fontSize(26).fontColor(textColor).text(areaText)// .rotate(-30)
- .position(centerPos);
- mMapLayer.addOverlay(ooText);
- }
- posArray.add(thisPos);
- if (posArray.size() >= 3) {
- // 画弧线
- OverlayOptions ooArc = new ArcOptions()
- .color(arcColor)
- .width(2)
- .points(posArray.get(posArray.size() - 1),
- posArray.get(posArray.size() - 2),
- posArray.get(posArray.size() - 3));
- mMapLayer.addOverlay(ooArc);
- }
- }
- @Override
- public void onMapClick(LatLng arg0) {
- addDot(arg0);
- }
- @Override
- public boolean onMapPoiClick(MapPoi arg0) {
- addDot(arg0.getPosition());
- return false;
- }