麥卡托投影法程式範例
此程式為把地球從圓形轉換成圓柱再把圓柱攤開成平面,把位置的經緯度轉換成X、Y軸後顯示在畫面上,下圖為執行結果。
圖一:執行結果
以下為麥卡托投影法程式碼:
專案下載:MercatorProjectionDemo.rar
主程式:MercatorProjectionDemo.java
package ccc.MercatorProjectionDemo; import gmap.MercatorProjection; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; public class MercatorProjectionDemo extends Activity { // 畫布 GmapView view; TextView show; // 中心點經緯度 double centerLat = 0; double centerLng = 0; int zoom = 0; // 指標的位置 float pointX=128; float pointY=128; // 地圖影像 Drawable mapImg; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mapImg = getResources().getDrawable(R.drawable.map); view = new GmapView(this); view.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { float eX=event.getX(); float eY=event.getY(); if(eX<256&&eY<256){ pointX=eX; pointY=eY; showXYZoom(); view.invalidate(); } return false; } }); setContentView(view); } // 顯示text private void show(String text) { this.setTitle(text); } // 顯示經緯度與縮放大小 private void showLngLatZoom() { int centerX = MercatorProjection.LngToX(centerLng, zoom); int centerY = MercatorProjection.LatToY(centerLat, zoom); int px = (int) (centerX + pointX - 128); int py = (int) (centerY + pointY - 128); double lng = MercatorProjection.XToLng(px, zoom); double lat = MercatorProjection.YToLat(py, zoom); show("lng=" + String.format("%.8f",lng) + " lat=" + String.format("%.8f",lat)+" zoom="+zoom+"\n"); } // 顯示X,Y,縮放大小 private void showXYZoom() { int centerX = MercatorProjection.LngToX(centerLng, zoom); int centerY = MercatorProjection.LatToY(centerLat, zoom); int px = (int) (centerX + pointX - 128); int py = (int) (centerY + pointY - 128); show("X=" + px + " Y=" + py+" zoom="+zoom+"\n"); } // 鍵盤事件 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { int centerX = MercatorProjection.LngToX(centerLng, zoom); int centerY = MercatorProjection.LatToY(centerLat, zoom); int edgeLength = 256 * (1 << zoom); if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { centerX-=10; if(centerX<0) centerX = 0; } if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { centerX+=10; if(centerX>edgeLength) centerX = edgeLength; } if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { centerY -= 10; if(centerY<0) centerY=0; } if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { centerY += 10; if(centerY>edgeLength) centerY=edgeLength; } centerLng = MercatorProjection.XToLng(centerX, zoom); centerLat = MercatorProjection.YToLat(centerY, zoom); pointX=128; pointY=128; showLngLatZoom(); view.invalidate(); return super.onKeyDown(keyCode, event); } // 選單放大跟縮小索引 protected static final int MENU_ZoomIn = Menu.FIRST; protected static final int MENU_ZoomOut = Menu.FIRST + 1; // 選單初始化 @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, MENU_ZoomIn, 0, "放大"); menu.add(0, MENU_ZoomOut, 0, "縮小"); return super.onCreateOptionsMenu(menu); }; // 選單項目選擇 @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_ZoomIn: if (zoom < 20) ++zoom; break; case MENU_ZoomOut: if (zoom > 0) --zoom; break; } pointX=128; pointY=128; showLngLatZoom(); view.invalidate(); return super.onOptionsItemSelected(item); } // 畫布 class GmapView extends View { public GmapView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { Paint p = new Paint(); p.setARGB(255, 0, 0, 0); p.setStrokeWidth(1); int edgeLength = 256 * (1 << zoom); int centerX = MercatorProjection.LngToX(centerLng, zoom); int centerY = MercatorProjection.LatToY(centerLat, zoom); Rect showRect = new Rect(0, 0, edgeLength, edgeLength); int offsetX=-centerX+128; int offsetY=-centerY+128; showRect.offset(offsetX ,offsetY); mapImg.setBounds(showRect); mapImg.draw(canvas); canvas.drawLine(pointX-10, pointY,pointX+10, pointY, p); canvas.drawLine(pointX, pointY-10,pointX, pointY+10, p); super.onDraw(canvas); } } }
程式:MercatorProjection.java
package gmap; public class MercatorProjection { // 經度轉成點(point) public static int LngToX(double Longitude,int zoom) { int numberOfTiles = 1 << zoom << 8; return (int)((Longitude + 180.0) * numberOfTiles / 360.0); } // 緯度轉成點(point) public static int LatToY(double Latitude,int zoom) { int numberOfTiles = 1 << zoom << 8; double projection = Math.log(Math.tan(Math.PI / 4 + ((Latitude / 180 * Math.PI) / 2))); double y = (projection / Math.PI); y = 1.0 - y; y = y / 2.0 * numberOfTiles; return (int)y; } // 點(X)轉成經度 public static double XToLng(int pointX,int zoom) { int numberOfTiles = 1 << zoom << 8; return (pointX * (360.0 / numberOfTiles)) - 180.0; } // 點(Y)轉成緯度 public static double YToLat(int pointY,int zoom) { int numberOfTiles = 1 << zoom << 8; double Latitude = pointY * (2.0 / numberOfTiles); Latitude = 1 - Latitude; Latitude = Latitude * Math.PI; Latitude = Math.atan(Math.sinh(Latitude)) * 180.0 / Math.PI; return Latitude; } }
AndroidManifest.xml為使用權限:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ccc.MercatorProjectionDemo" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".MercatorProjectionDemo" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="4" /> </manifest>
page revision: 9, last edited: 15 Dec 2010 06:11
Post preview:
Close preview