入门Android开发----国家天地图开发= = 哈哈哈哈。。因为需要

http://api.tianditu.com/api-new/home.html

开发完回头修改了这个文章。

(有需求可参看《入门Android开发--ArcGis结合天地图实现地图建筑图层》)

天地图有国家和省的版本,地图显示详细度不一样(省的详细),功能不一样(国家的强)

所以根据需求,用了国家天地图(目前知道省的内部天地图Android客户端功能很强,但是没有sdk)

无需注册(百度地图说防止“balabla”,所以有个key),

在项目Libraries里添加tiandituapi2.2.2.jar,将libMapEngine.so复制到工程目录下的libs\armeabi下,再在android工程中引用jar和so文件

天地图里类参考中,mapview的一些类,在demo中有出现,但是说明里没有找着= =


//天地图常见的小问题就不多说了。可以百度类似的错误进行解决。

//大问题有:

//(路线规划的回调结果经常出错),一看错误类。。。-1为不支持的地图类型。。。呵呵

//  请看问题4


目前的需求和解决思路:

1、获取两个坐标点的“直线”距离,没有自带的方法。

答:网上找的(和百度地图的距离差不多吧):

double s =R*Math.acos(Math.cos(lat1*pi/180) *Math.cos(lat2*pi/180)*Math.cos(lng1*pi/180 -lng2*pi/180)+
Math.sin(lat1*pi/180 )*Math.sin(lat2*pi/180));

2、获取两个坐标点的路程距离。

答:用驾车规划里的回调结果,获取路程长度。或者使用网页服务

http://www.tianditu.cn/query.shtml   ,  POST方式:postStr={'orig':'120.957149,28.112149','dest':'120.957854,28.111113','style':'0','mid':''}&type=search

获取一个xml格式的结果

3、路线规划的结果需要恰好最合适显示在地图视图中间,

答:首先用自带的方法,确定返回结果的中心点,和视图的经纬度范围。

求经纬度范围有个自带的zoomToSpan方法,但是我这边的点位,起码试出了一个不能合理显示(有一个之后就没试其他的了)

然后就是自己写一个,这也是花了最多时间的部分。

思路大概就是先获取地图的缩放比例,经纬度范围(都是可以直接用的方法)

然后创建一个比例数组,和各个比例之间的比例尺的换算比例数组(如下代码块部分)

通过地图视图显示的经纬度乘以换算比例,和路线规划返回的经纬度点的经纬度范围进行比较,得到相应的缩放比例。

//缩放等级对应,如果地图未设置缩放等级,则为4km,即12。
//minLevle为5,如果低于则设为5;maxLevel为18,如果高于则设为18
//5为400km,6为200km,7为92km,8为48km,9为24km,(基本盖住温州了)
//10为16km,11为8km,12为4km,13为2km,14为1km,15为500m,
//16为240m,17为120m,18为60m,
int[] level=		{5,6,7,8,9,10,11,12,13,14,15,16,17,18};
double[] multiple=	{0.5,0.46,0.52,0.5,0.67,0.5,0.5,0.5,0.5,0.5,0.48,0.5,0.5};

4、如果有两个activity都使用了地图,两张地图会互相影响(包括地图图层的显示、比例和长宽)

答:目前没有好的办法,只能把第二张地图设置为第一张地图一样的设置。

5、结合3、4。因为我们先进入一个默认地图(全屏,假设100,map_def),然后点击目标点,

      进入路线规划,因为有其他面板,所以地图高度只用了部分(假设80, map_route)

      然后返回def的时候,def只会显示80的部分,下面20为空。

      如果route部分因为适应缩放改变了比例尺,那么def地图也会变化成相应的比例尺。

其实这个20,是通过动态计算的方法。(网上有计算组件高度的方法,但是我不知道怎么结合进这里,我用的是计算字符高度和空白高度的方法)

    为了说明方便,直接使用了20。

答:还不懂这个地图的原理,所以只好把route的地图也设置成100,不过20部分被面板遮盖。

然后在activity返回的时候设置route的缩放级别和def的一样(route通过intent获取def的缩放级别,在返回键和设置的back按钮点击事件中设置)

这样会有两个新的问题:地图的视图下移20/2(让画出来的线显示在下方的80中),经纬度范围为原纬度范围的4/5

这里下移20/2又需要换算成经纬度范围,(注意这里是比例尺改变之后的偏移,所以需要乘以不同的比例)

总结一下方法:计算比例尺等级的方法同3,然后通过比较旧的比例尺范围,还是3中的两个数组,进行比例换算,即可以算出新的比例尺下,20/2对应的纬度范围值

    通过将中心点的纬度坐标加上这个20/2对应的纬度范围值,即可完成中心点偏移操作。

6、在解决上面的问题的时候出现了地图无法缩放和移动的问题。

答:因为我把更改地图状态的函数写在了,overlay类里的重载draw方法中,

这个地图的机制大致是这样的:在更改地图图层状态的时候,通知所有的图层,调用draw方法,更改对应图层装态

(比如绘制路线的图层,就是在路线规划的回调中,将地图的中心点设置了一下之后,才调用了draw方法,开始绘制)

而产生这个问题的原因是,我把设置中心点放在了draw方法里,那每次拖动地图的时候,都会重新调用这个设置中心点的方法。

所以加了一个isFirstDraw的判断。即可解决。

7、代码怎么写呢。嘿嘿。主要的工具代码如下:(看不懂没事啊。不难,就是写了好久,放一下)

//缩放等级对应,如果地图未设置缩放等级,则为4km,即12。
//minLevle为5,如果低于则设为5;maxLevel为18,如果高于则设为18
//5为400km,6为200km,7为92km,8为48km,9为24km,(基本盖住温州了)
//10为16km,11为8km,12为4km,13为2km,14为1km,15为500m,
//16为240m,17为120m,18为60m,


//在线路导航布局下,
public class ZoomLevelUtil {
	
	
	//每次点击按钮的时候,比例等级都是不一定的。
	//所以需要判断
	int[] level={5,6,7,8,9,10,11,12,13,14,15,16,17,18};
	double[] multiple={0.5,0.46,0.52,0.5,0.67,0.5,0.5,0.5,0.5,0.5,0.48,0.5,0.5};
	
	GeoPoint point;
	Activity _activity;
	MapView mapView;
	int before_zoomLevel;//记录刚获取时视图的比例设置
	int after_zoomLevel;//记录最后确定的比例设置
	
	public ZoomLevelUtil(Activity activity,GeoPoint point,MapView mapView){
		this.point=point;
		_activity=activity;
		this.mapView=mapView;
		before_zoomLevel=mapView.getZoomLevel();//获取地图当前比例等级
		after_zoomLevel=mapView.getZoomLevel();
	}
	//解析进入时,每个地图视图被隐藏的高度(即上部面板高度对应的Lat值)
	public int parseSpan(int SpanE6){
		
			// TODO Auto-generated method stub
		
			//这个例子需要减去一部分,为22dp+4text+20sp
			 DisplayMetrics metric = new DisplayMetrics();  
	         _activity.getWindowManager().getDefaultDisplay().getMetrics(metric);  
	         int height = metric.heightPixels; //屏幕高度
	         float scale=_activity.getResources().getDisplayMetrics().density;//屏幕密度  
	         int title_height=DensityUtil.dip2px(_activity, 48);
	         height-=scale*title_height;
	         
	         //获取默认单个字符高度  
	         TextPaint paint = new TextPaint();  
	         FontMetrics fm = paint.getFontMetrics();  
	         //Math.ceil(fm.descent - fm.top) + 2;
	         int deftext_Height=(int)Math.ceil(fm.descent - fm.ascent)  ;  
	         //获取20sp字符单个高度
	         paint.setTextSize(20);
	         fm = paint.getFontMetrics(); 
	         int text_20_Height=(int)Math.ceil(fm.descent - fm.ascent) ;
	         int margin=DensityUtil.dip2px(_activity, 22);//上下总空余的距离22dp  
	         return (int)(SpanE6*(scale*(double)(3*deftext_Height+text_20_Height+margin)/(double)height));
	         
	} 
	//获取新的中心点坐标
	//需要先执行getAfterZoomLevel()
	public GeoPoint getFreshPoint(){
		
		int after_addLatSpan=0;
		//获取点击时,应该减小的距离
		int before_addLatSpan=parseSpan(mapView.getLatitudeSpan());
		//获取从before_zoomLevel转到after_zoomLevel,所需要的比例
		after_addLatSpan=(int)((double)before_addLatSpan*getScale(before_zoomLevel,after_zoomLevel));
		//要把地图往下移,其实是把中心点上调
		int after_LatSpan=point.getLatitudeE6()+after_addLatSpan/2;
		
		GeoPoint new_P=new GeoPoint(after_LatSpan,point.getLongitudeE6());
//		GeoPoint point = mResult.getCenterPoint();
//		int new_lat=point.getLatitudeE6()+addLngSpan/2;
		return new_P;
	}
	//计算,最终zoomLevel和传入的zoomLevel时,两者距离的比例
	//需要先执行getAfterZoomLevel()
	private double getScale(int before_zoomLevel,int after_zoomLevel) {
		// TODO Auto-generated method stub
		double scale=1;
		//获取处理前等级在列表中的位置
		int i=0;
		for(;i<level.length;i++){
			if(level[i]==before_zoomLevel){
				break;
			}
		}
		//获取处理后等级在列表中的位置
		int j=0;
		for(;j<level.length;j++){
			if(level[j]==after_zoomLevel){
				break;
			}
		}
		
		if(i<j){
			for(;i<j;i++)
				scale*=multiple[i];
		}else if(i>j){
			for(;i>j;){
//				i--;
				scale/=multiple[--i];
			}
		}
		
		
		return scale;
	}
	
	public int getAfterZoomLevel(int latSpanE6,int lngSpanE6){
//		int zoomLevel=15;//默认为15(15的比例比较适中,使用18或者12都有点不合适)
		int before_zoomLevel=mapView.getZoomLevel();
		int maxLevel=mapView.getMaxZoomLevel();
		int minLevel=mapView.getMinZoomLevel();
		
		//获取屏幕经纬度范围,
		int mapLatSpan=mapView.getLatitudeSpan();
		int mapLngSpan=mapView.getLongitudeSpan();
		//根据比例换算实际显示的高度
		mapLatSpan-=parseSpan(mapLatSpan);
		
		if(maxLevel!=18||minLevel!=5){
			Toast.makeText(_activity, "比例等级变化,校准失败", Toast.LENGTH_SHORT).show();
			return before_zoomLevel;
		}
	
		//获取等级在列表中的位置
		int i=0;
		for(;i<level.length;i++){
			if(level[i]==before_zoomLevel){
				break;
			}
		}
		//设置经度比例和纬度比例	
		int latLevel=before_zoomLevel;
		int lngLevel=before_zoomLevel;
		
		int j=i;
		if(mapLatSpan<=latSpanE6){
			for(;mapLatSpan<=latSpanE6;){
				if(j==0)
					break;
				mapLatSpan/=multiple[j--];
			}
		}else{
			for(;mapLatSpan>latSpanE6;j++){
				if(j==(level.length-1))
					break;
				mapLatSpan*=multiple[j];
			}
			j--;
		}
		latLevel=level[j];
		
		j=i;
		if(mapLngSpan<=lngSpanE6){
			for(;mapLngSpan<=lngSpanE6;){
				if(j==0)
					break;
				j--;
				mapLngSpan/=multiple[j];
			}
		}else{
			for(;mapLngSpan>lngSpanE6;j++){
				if(j==(level.length-1))
					break;
				mapLngSpan*=multiple[j];
			}
			j--;
		}
		lngLevel=level[j];
		
		
		after_zoomLevel=latLevel<lngLevel?latLevel:lngLevel;
		return after_zoomLevel;
	}
	
}



        

你可能感兴趣的:(入门Android开发----国家天地图开发= = 哈哈哈哈。。因为需要)