2012-02-18 49 views
0

我在嘗試驗證使用Google地圖API的可點擊路線功能。手柄點擊路線

我使用地圖API在兩個座標之間建立了路線顯示。

爲了實現這一點,我使用了基本解析KML文件(谷歌地圖方向請求的響應)的以下教程http://csie-tw.blogspot.com/2009/06/android-driving-direction-route-path.html, ,並使用自定義地圖疊加繪製路線。

自定義背景畫面:

package com.test.route; 

import android.graphics.Bitmap; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Point; 
import android.graphics.RectF; 
import android.util.Log; 
import android.view.MotionEvent; 

import com.google.android.maps.GeoPoint; 
import com.google.android.maps.MapView; 
import com.google.android.maps.Overlay; 
import com.google.android.maps.Projection; 

public class MyOverLay extends Overlay 
{ 
    private GeoPoint gp1; 
    private GeoPoint gp2; 
    private int mRadius=6; 
    private int mode=0; 
    private int defaultColor; 
    private String text=""; 
    private Bitmap img = null; 


    public MyOverLay(GeoPoint gp1,GeoPoint gp2,int mode) // GeoPoint is a int. (6E) 
    { 

    this.gp1 = gp1; 
    this.gp2 = gp2; 
    this.mode = mode; 
    defaultColor = 999; // no defaultColor 

    } 


    public MyOverLay(GeoPoint gp1,GeoPoint gp2,int mode, int defaultColor) 
    { 
    this.gp1 = gp1; 
    this.gp2 = gp2; 
    this.mode = mode; 
    this.defaultColor = defaultColor; 
    } 

    public void setText(String t) 
    { 
     this.text = t; 
    } 

    public void setBitmap(Bitmap bitmap) 
    { 
     this.img = bitmap; 
    } 

    public int getMode() 
    { 
     return mode; 
    } 

    @Override 
    public boolean draw 
    (Canvas canvas, MapView mapView, boolean shadow, long when) 
    { 

    Projection projection = mapView.getProjection(); 
    if (shadow == false) 
    {  

     Paint paint = new Paint(); 
     paint.setAntiAlias(true); 


     Point point = new Point(); 
     projection.toPixels(gp1, point); 
     // mode=1¡Gstart 
     if(mode==1) 
     { 
     if(defaultColor==999) 
      paint.setColor(Color.BLUE); 
     else 
      paint.setColor(defaultColor); 


     RectF oval=new RectF(point.x - mRadius, point.y - mRadius, 
          point.x + mRadius, point.y + mRadius); 
     // start point 
     canvas.drawOval(oval, paint); 
     } 
     // mode=2¡Gpath 
     else if(mode==2) 
     { 
     if(defaultColor==999) 
      paint.setColor(Color.RED); 
     else 
      paint.setColor(defaultColor); 

     Point point2 = new Point(); 
     projection.toPixels(gp2, point2); 
     paint.setStrokeWidth(5); 
     paint.setAlpha(120);  
     canvas.drawLine(point.x, point.y, point2.x,point2.y, paint);  
     } 
     /* mode=3¡Gend */ 
     else if(mode==3) 
     { 
     /* the last path */ 

     if(defaultColor==999) 
      paint.setColor(Color.GREEN); 
     else 
      paint.setColor(defaultColor); 

     Point point2 = new Point(); 
     projection.toPixels(gp2, point2); 
     paint.setStrokeWidth(5); 
     paint.setAlpha(120); 
     canvas.drawLine(point.x, point.y, point2.x,point2.y, paint); 


     RectF oval=new RectF(point2.x - mRadius,point2.y - mRadius, 
          point2.x + mRadius,point2.y + mRadius); 
     /* end point */ 
     paint.setAlpha(255); 
     canvas.drawOval(oval, paint); 
     } 
     /* mode=4¡Gcar */ 
     else if(mode==4) 
     { 

     if(defaultColor==999) 
      paint.setColor(Color.GREEN); 
     else 
      paint.setColor(defaultColor); 

     Point point2 = new Point(); 
     projection.toPixels(gp2, point2); 
     paint.setTextSize(20); 
     paint.setAntiAlias(true); 
     canvas.drawBitmap(img, point2.x, point2.y,paint);  
     canvas.drawText(this.text, point2.x, point2.y, paint); 
     } 

     else if(mode==5) 
     { 

     if(defaultColor==999) 
      paint.setColor(Color.GREEN); 
     else 
      paint.setColor(defaultColor); 

     Point point2 = new Point(); 
     projection.toPixels(gp2, point2); 
     paint.setTextSize(20); 
     paint.setAntiAlias(true); 
     canvas.drawBitmap(img, point2.x, point2.y,paint); 

     } 



    } 
    return super.draw(canvas, mapView, shadow, when); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event, MapView mapView) 
    { 
     Log.i("Map", "Clicked"); 
     return false; 
    } 
} 

測試地圖的活動:

package com.test.route; 

import java.io.IOException; 
import java.net.HttpURLConnection; 
import java.net.MalformedURLException; 
import java.net.URL; 

import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.ParserConfigurationException; 

import org.w3c.dom.Document; 
import org.xml.sax.SAXException; 

import android.content.Intent; 
import android.graphics.Color; 
import android.net.Uri; 
import android.os.Bundle; 
import android.util.Log; 

import com.dailymates.carmate.utils.MyOverLay; 
import com.google.android.maps.GeoPoint; 
import com.google.android.maps.MapActivity; 
import com.google.android.maps.MapView; 

public class TestMap extends MapActivity { 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.map); 
     MapView mapView = (MapView) findViewById(R.id.mapview); 
     /* 
     * Defining the starting and end point of the route (latitude/longitude) 
     * Oh Paris 
     * 
     */ 
     final double src_lat = 48.847378; 
     final double src_long = 2.340417; 
     final double dest_lat = 48.931466; 
     final double dest_long = 2.504525; 

     GeoPoint srcGeoPoint = new GeoPoint((int) (src_lat * 1E6), 
       (int) (src_long * 1E6)); 
     GeoPoint destGeoPoint = new GeoPoint((int) (dest_lat * 1E6), 
       (int) (dest_long * 1E6)); 

     DrawPath(srcGeoPoint, destGeoPoint, Color.GREEN, mapView); 

     mapView.getController().animateTo(srcGeoPoint); 
     mapView.getController().setZoom(12); 

    } 

    protected boolean isRouteDisplayed() { 
     return false; 
    } 

    private void DrawPath(GeoPoint src, GeoPoint dest, int color, MapView mMapView01) { 

     StringBuilder urlString = new StringBuilder(); 
     urlString.append("http://maps.google.com/maps?f=d&hl=en"); 
     urlString.append("&saddr="); 
     urlString.append(Double.toString((double) src.getLatitudeE6()/1.0E6)); 
     urlString.append(","); 
     urlString.append(Double.toString((double) src.getLongitudeE6()/1.0E6)); 
     urlString.append("&daddr=");// to 
     urlString.append(Double.toString((double) dest.getLatitudeE6()/1.0E6)); 
     urlString.append(","); 
     urlString.append(Double.toString((double) dest.getLongitudeE6()/1.0E6)); 
     urlString.append("&ie=UTF8&0&om=0&output=kml"); 

     Log.d("xxx", "URL=" + urlString.toString()); 

     Document doc = null; 
     HttpURLConnection urlConnection = null; 
     URL url = null; 
     try { 
      url = new URL(urlString.toString()); 
      urlConnection = (HttpURLConnection) url.openConnection(); 
      urlConnection.setRequestMethod("GET"); 
      urlConnection.setDoOutput(true); 
      urlConnection.setDoInput(true); 
      urlConnection.connect(); 

      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
      DocumentBuilder db = dbf.newDocumentBuilder(); 
      doc = db.parse(urlConnection.getInputStream()); 

      if (doc.getElementsByTagName("GeometryCollection").getLength() > 0) { 

       String path = doc.getElementsByTagName("GeometryCollection") 
         .item(0).getFirstChild().getFirstChild() 
         .getFirstChild().getNodeValue(); 

       Log.d("xxx", "path=" + path); 

       String[] pairs = path.split(" "); 
       String[] lngLat = pairs[0].split(","); 

       // lngLat[0]=longitude 
       // lngLat[1]=latitude 
       // lngLat[2]=height 

       GeoPoint startGP = new GeoPoint((int) (Double.parseDouble(lngLat[1]) * 1E6), 
         (int) (Double.parseDouble(lngLat[0]) * 1E6)); 
       mMapView01.getOverlays().add(new MyOverLay(startGP, startGP, 1)); 

       GeoPoint gp1; 
       GeoPoint gp2 = startGP; 
       for (int i = 1; i < pairs.length; i++) 
       { 
        lngLat = pairs[i].split(","); 
        gp1 = gp2; 
        gp2 = new GeoPoint(
          (int) (Double.parseDouble(lngLat[1]) * 1E6), 
          (int) (Double.parseDouble(lngLat[0]) * 1E6)); 
        mMapView01.getOverlays().add(
          new MyOverLay(gp1, gp2, 2, color)); 

        Log.d("xxx", "pair:" + pairs[i]); 

       } 
       mMapView01.getOverlays().add(new MyOverLay(dest, dest, 3)); 
      } 
     } catch (MalformedURLException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (ParserConfigurationException e) { 
      e.printStackTrace(); 

     } catch (SAXException e) { 

      e.printStackTrace(); 
     } 

    } 
} 

所以,正如我所說,我得到正確的路線圖。 但是,我怎麼能處理這些繪製的路線上的點擊事件?

的信息,我在想一些東西,很可能是低效的,但我會告訴你,我們永遠不知道:)

由於路線丁祖泉是basicaly一個beetween 2個geopoints(段)圖紙繼承,我們可以預先處理這種點擊路線:

  • 使用地圖疊加的onTouchEvent方法,我們可以獲取與點擊關聯的地址點。
  • 然後我們嘗試確定點擊的地理點是否是路段的一部分。

最後一條信息:在同一時刻將在地圖上繪製多條路線,因此點擊必須關聯到唯一路線,而不是全部。

謝謝。

回答

1

10個月後,我給了我用過的工作(10個月前),誰知道,也許它會幫助別人:)。

爲了處理地圖路線上的點擊/觸摸,一種方法可以是估計點擊的點是否位於顯示的路線附近。

使用OnTouchEvent方法,您應該計算點擊點是否靠近一個線段(路線部分)。

路線可以表示爲段列表。

下面的方法讓你計算點和段(從Java java.awt.geom.Line2D中)之間的距離:

/** 
* Get the closest distance between a point and a segment 
* 
* @param x1 , x coordinate of the 1st segment point 
* @param y1 , y coordinate of the 1st segment point 
* @param x2 , x coordinate of the 2st segment point 
* @param y2 , y coordinate of the 2st segment point 
* @param x , x coordinate of the point from which distance will be calculated 
* @param y , y coordinate of the point from which distance will be calculated 
* 
* @return the distance 
* 
*/ 
public static float ptSegDistSq(float x1, float y1, float x2, float y2, float px, float py){ 
    // Adjust vectors relative to x1,y1 
    // x2,y2 becomes relative vector from x1,y1 to end of segment 
    x2 -= x1; 
    y2 -= y1; 
    // px,py becomes relative vector from x1,y1 to test point 
    px -= x1; 
    py -= y1; 
    float dotprod = px * x2 + py * y2; 
    float projlenSq; 
    if (dotprod <= 0.0) { 
     // px,py is on the side of x1,y1 away from x2,y2 
     // distance to segment is length of px,py vector 
     // "length of its (clipped) projection" is now 0.0 
     projlenSq = (float) 0.0; 
    } else { 
     // switch to backwards vectors relative to x2,y2 
     // x2,y2 are already the negative of x1,y1=>x2,y2 
     // to get px,py to be the negative of px,py=>x2,y2 
     // the dot product of two negated vectors is the same 
     // as the dot product of the two normal vectors 
     px = x2 - px; 
     py = y2 - py; 
     dotprod = px * x2 + py * y2; 
     if (dotprod <= 0.0) { 
      // px,py is on the side of x2,y2 away from x1,y1 
      // distance to segment is length of (backwards) px,py vector 
      // "length of its (clipped) projection" is now 0.0 
      projlenSq = (float) 0.0; 
     } else { 
      // px,py is between x1,y1 and x2,y2 
      // dotprod is the length of the px,py vector 
      // projected on the x2,y2=>x1,y1 vector times the 
      // length of the x2,y2=>x1,y1 vector 
      projlenSq = dotprod * dotprod/(x2 * x2 + y2 * y2); 
     } 
    } 
    // Distance to line is now the length of the relative point 
    // vector minus the length of its projection onto the line 
    // (which is zero if the projection falls outside the range 
    // of the line segment). 
    float lenSq = px * px + py * py - projlenSq; 
    if (lenSq < 0) { 
     lenSq = 0; 
    } 
    return lenSq; 
} 

有了這個距離,你可以建立固定的規則,如果估算點在路線附近,計算地圖縮放級別(在每個縮放級別對應最大距離容差)。