上頭紅色的是繪製的路徑,藍色點則是模擬時,顯示的 GPS 座標位置,將隨著時間變動。這是根據此篇 Android 開發教學筆記 - 透過 Google Maps API 畫出 GPS 路徑 和 Android 開發教學筆記 - 調整 GPS 座標個數,以提昇路徑繪圖效率 的筆記所做的延伸練習。
給定一段 GPS 紀錄的路徑,經過個數的縮減壓縮並在地圖上完成路徑的繪製,接著想要了解原始 GPS 移動與繪製的路徑差異有多大,所以就有了這個練習。依照原始 GPS 座標資訊,畫製一個 marker 隨著時間擺放到指定的 GPS 位置,這樣的效果除了能確認原始 GPS 路線與壓縮後的路徑位置的差異,也可以了解實際收集到的 GPS 座標是否出現在 Google Maps 繪製的地圖道路。
實做上在 class MyGPSPath 裡,新增並且改變一些 member 宣告方式:
Handler jobs;
final double srcLogs[]={ 48.138050017878413, 16.481179967522621 /* , ... */ };
double logs[] = {};
int gps_at;
其中 jobs 用來更新畫面,srcLogs用來紀錄原始的不重複的 GPS 資訊,而 logs 會是壓縮過後的 GPS 個數,而 gps_at 則是等會模擬時,用來紀錄走到那個 GPS 點。
接著在 onCreate 裡,初始化 gps_at, jobs, logs 變數,以及調整 overlay :
gps_at = 0;
jobs = new Handler();
ArrayList<Double> data = new ArrayList<Double>();
for( int i=0; i<srcLogs.length ; ++i )
data.add( new Double( srcLogs[i] ) );
data = rebuildGSPLogsByAngleCheck( data , 0 );
logs = new double[data.size()];
for( int i=0; i<data.size() ; ++i)
logs[i] = data.get(i).floatValue();
List<com.google.android.maps.Overlay> ol = mapView.getOverlays();
ol.clear();
ol.add(new MyPathOverlay());
MapController mapController = mapView.getController();
if( mapController != null )
{
mapController.setCenter(new GeoPoint( (int) (srcLogs[0]* 1000000) , (int)(srcLogs[1]* 1000000) ) );
mapController.setZoom(15);
}
new Thread( new Runnable(){
public void run()
{
gps_at = 2;
while( gps_at < srcLogs.length )
{
try{
jobs.post( new Runnable(){
public void run(){
List<com.google.android.maps.Overlay> ol = mapView.getOverlays();
while( ol.size() > 1 )
ol.remove(1);
ol.add(new MyMarkerOverlay( srcLogs[gps_at] , srcLogs[gps_at+1]));
GeoPoint in = new GeoPoint((int) (srcLogs[gps_at] * 1000000) , (int) (srcLogs[gps_at+1] * 1000000) );
Point out = new Point();
mapView.getProjection().toPixels(in, out);
int diff = 100;
if( out.x < diff || out.y < diff || out.x > mapView.getWidth() - diff || out.y > mapView.getHeight() - diff )
{
MapController mc = mapView.getController();
mc.animateTo(new GeoPoint( (int)(srcLogs[gps_at]*1000000) , (int)(srcLogs[gps_at+1]*1000000 )) );
}
}
});
Thread.sleep(500);
}
catch(Exception e)
{
}
gps_at +=2 ;
}
}
}).start();
上頭的 MyPathOverlay 則是之前例子中的 MyMapOverlay,在此僅改變成較有意義的名稱,而 onCreate 最後面使用到的 Thread,就是用來模擬 GPS 變化的過程,每 0.5 秒更動 gps_at 時,則重新擺放 MyMarkerOverlay 的位置,並且稍微計算一下,當 Marker 太靠近可視地圖的邊框時,自動調整地圖位置。
另外,還需實做 MyMarkerOverlay,用來標記 GPS 移動:
class MyMarkerOverlay extends com.google.android.maps.Overlay
{
double at_lat,at_lng;
MyMarkerOverlay( double _lat, double _lng )
{
super();
at_lat = _lat;
at_lng = _lng;
}
@Override
public boolean draw(Canvas canvas, MapView mapView,boolean shadow, long when)
{
super.draw(canvas, mapView, shadow);
if( !shadow )
{
GeoPoint in = new GeoPoint((int) (at_lat * 1000000) , (int) (at_lng * 1000000) );
Point out = new Point();
mapView.getProjection().toPixels(in, out);
int r = 6;
Paint p = new Paint();
p.setColor(Color.BLUE);
p.setAntiAlias(true);
RectF oval=new RectF( out.x - r, out.y - r, out.x + r, out.y + r);
canvas.drawOval(oval, p);
}
return true;
}
}
也可以實做 ItemizedOverlay<OverlayItem> 的方式,好處是用法接近 Web API 的使用,把你想要新增的點,加到下面的 list 即可:
class MyItemMarkerOverlay extends com.google.android.maps.ItemizedOverlay<OverlayItem>
{
private ArrayList<OverlayItem> myOverlays = new ArrayList<OverlayItem>();
private Context myContext;
public MyItemMarkerOverlay(Drawable defaultMarker, Context context)
{
super(boundCenterBottom(defaultMarker));
myContext = context;
}
@Override
protected OverlayItem createItem(int i)
{
return myOverlays.get(i);
}
@Override
public int size()
{
return myOverlays.size();
}
@Override
protected boolean onTap(int index)
{
OverlayItem item = myOverlays.get(index);
//AlertDialog dialog = new AlertDialog.Builder(MyGPSPath.this).create();
AlertDialog dialog = new AlertDialog.Builder(myContext).create();
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
dialog.setButton("OK", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which)
{
dialog.cancel();
}
} );
dialog.show();
return true;
}
public void addOverlay(OverlayItem overlay)
{
myOverlays.add(overlay);
populate();
}
}
用法:
List<com.google.android.maps.Overlay> olay = mapView.getOverlays();
Drawable drawable = this.getResources().getDrawable(R.drawable.icon);
MyItemMarkerOverlay markersOverlay = new MyItemMarkerOverlay( drawable, this ); // new MyItemMarkerOverlay( drawable, MyPGSPath.this );
markersOverlay.addOverlay(
new OverlayItem(
new GeoPoint((int) (srcLogs[gps_at] * 1000000) , (int) (srcLogs[gps_at+1] * 1000000)),
"Title",
"Snippet"
)
);
olay.add(markersOverlay);
此練習的 GPS 變化,也可以透過 DDMS 來處理,例如定時 send 一些 GPS 座標等,但我還沒嘗試,看來下個練習方向可以用用看 DDMS 囉。
沒有留言:
張貼留言