2011-03-22 71 views
4

我遇到了一個奇怪的問題,使用google地圖包得到偏移量。在最大縮放級別平移MapView時GeoPoint和/或android.maps.Projection的怪異行爲

我有一個MapView和顯示在其上的路線。我注意到,如果我放大,然後平移,我的路線就會越過窗口邊緣。我自己的代碼要經過調試,我發現,即使是這樣一個簡單的例子就足以瑞普問題:

  GeoPoint midPoint = projection.fromPixels(mapView.getWidth()/2, mapView.getHeight()/2); 
      GeoPoint nextPoint = new GeoPoint(midPoint.getLatitudeE6(), midPoint.getLongitudeE6()); 
      pathPaint.setColor(0xFF00FF00); 
      projection.toPixels(midPoint, screenPoint); 
      canvas.drawCircle(screenPoint.x, screenPoint.y, 5, pathPaint); 
      pathPaint.setColor(0xFF0000FF); 
      projection.toPixels(nextPoint, screenPoint); 
      canvas.drawCircle(screenPoint.x, screenPoint.y, 5, pathPaint); 

這使用)由MapView.getProjection(返回投影類翻譯像素座標轉換成一個GeoPoint 。然後使用相同的經緯度創建第二個GeoPoint。最後,它將這兩個GeoPoints轉換回屏幕座標,並在該位置繪製兩個圈,一個在另一個的頂部。

除了當您平移時,第二個圓與第一個圓偏移。它們具有相同的緯度/經度座標(我在繪圖後檢查),但最終轉換爲不同的屏幕座標。我的調試側重於水平平移,但我相信垂直平移可能會遇到類似的問題,這是基於我用原始應用代碼看到的。

據我所知,地圖包創建的任何點都可以正常工作,但通過調用新GeoPoint(lat,lon)創建的任何點都會表現出這種行爲。

我已經創建了一個簡單的簡化應用程序,展現了下面粘貼的這種行爲。 (地圖切片不會下載,因爲我不打算簽名,但您不需要它們來查看問題。)只需啓動它,放大一切,然後開始向左或向右平移即可。觀看綠色和藍色點的分歧,並目睹Log.d打印,表明它們仍然具有相等的經度/緯度。

(有沒有發佈樣本項目更好/首選方式對不起,這是我第一次發佈在這裏?)

的src /例子/ MYSAMPLE/MapOverlay.java:

package example.mysample; 

import java.util.ArrayList; 

import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Paint; 
import android.graphics.Point; 
import android.graphics.Color; 
import android.graphics.DashPathEffect; 
import android.graphics.RadialGradient; 
import android.graphics.Shader; 
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; 

import android.util.Log; 

class MapOverlay extends Overlay 
{ 
    public MapOverlay(MapScreen activity) 
    { 
     super(); 

     paint = new Paint(); 
     paint.setStyle(Paint.Style.FILL_AND_STROKE); 
     paint.setAntiAlias(true); 
    } 

    @Override public boolean onTouchEvent(MotionEvent e, MapView mapView) { 
     int motionAction = e.getAction(); 
     if (motionAction == MotionEvent.ACTION_MOVE) { 
      dragging = true; 
     } 
     if (motionAction == MotionEvent.ACTION_UP || motionAction == MotionEvent.ACTION_CANCEL) { 
      dragging = false; 
     } 
     return super.onTouchEvent(e, mapView); 
    } 

    @Override public void draw(Canvas canvas, MapView mapView, boolean shadow) { 
     if (!shadow && !dragging) { 
      Projection projection = mapView.getProjection(); 

      // Draw two circles at the center 
      // One with a virgin point, one that we constructed with the same coordinates 
      GeoPoint midPoint = projection.fromPixels(mapView.getWidth()/2, mapView.getHeight()/2); 
      GeoPoint nextPoint = new GeoPoint(midPoint.getLatitudeE6(), midPoint.getLongitudeE6()); 
      paint.setColor(0xFF00FF00); 
      projection.toPixels(midPoint, screenPoint); 
      canvas.drawCircle(screenPoint.x, screenPoint.y, 5, paint); 
      paint.setColor(0xFF0000FF); 
      projection.toPixels(nextPoint, screenPoint); 
      canvas.drawCircle(screenPoint.x, screenPoint.y, 5, paint); 

      // These print EQUAL. 
      Log.d("BKC DEBUG", "Midpoint and our own midpoint have " + 
       ((midPoint.getLatitudeE6() == nextPoint.getLatitudeE6()) ? "EQUAL" : "UNEQUAL") + 
       " latitudes, and " + 
       ((midPoint.getLongitudeE6() == nextPoint.getLongitudeE6()) ? "EQUAL" : "UNEQUAL") + 
       " longitudes"); 
     } 
    } 

    private Paint paint; 
    private boolean dragging; 
    private Point screenPoint = new Point(); 

} 

的src /例如/ MYSAMPLE/MapScreen.java:

package example.mysample; 

import android.os.Bundle; 
import android.view.View; 
import android.widget.Toast; 
import android.util.Log; 

import com.google.android.maps.MapActivity; 
import com.google.android.maps.MapController; 
import com.google.android.maps.MapView; 
import com.google.android.maps.GeoPoint; 

public class MapScreen extends MapActivity 
{ 

    @Override public void onCreate(Bundle icicle) { 
     super.onCreate(icicle); 
     setContentView(R.layout.map); 

     mapView = (MapView)findViewById(R.id.map_map); 
     mapView.setBuiltInZoomControls(true); 
     mapView.getOverlays().add(new MapOverlay(this)); 

     MapController controller; 
     controller = mapView.getController(); 
     controller.setZoom(17); 
     controller.animateTo(new GeoPoint(36000000, -90000000)); 

    } 

    @Override 
    public boolean isRouteDisplayed() { 
     return true; 
    } 

    private MapView mapView; 

} 

RES /佈局/ map.xml:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:background="#414141" 
    >  

<com.google.android.maps.MapView 
      android:id="@+id/map_map" 
      android:layout_width="fill_parent" 
      android:layout_height="fill_parent" 
      android:layout_marginLeft="3dip" 
      android:layout_marginRight="3dip" 
      android:layout_marginTop="3dip" 
      android:layout_marginBottom="3dip" 
      android:apiKey="0jPQdwUtQGBYfPALki6ghGG_X9Jpf-SllYckR4w" 
      android:layout_centerInParent="true" 
      android:clickable="true" 
      /> 

</RelativeLayout> 

的AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
     package="example.mysample" 
     android:versionCode="1" 
     android:versionName="2.0.1"> 
    <uses-sdk android:minSdkVersion="4" /> 

    <!--uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /--> 
    <!--uses-permission android:name="android.permission.READ_PHONE_STATE" /--> 
    <uses-permission android:name="android.permission.INTERNET" /> 
    <!--uses-permission android:name="android.permission.WAKE_LOCK" /--> 
    <!--uses-permission android:name="android.permission.READ_LOGS" /--> 
    <!--uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /--> 

    <!--application android:name="src.example.mysample.AppMain" 
       android:label="MySample" 
       android:icon="@drawable/icon_android" 
       android:theme="@android:style/Theme.NoTitleBar" 
       --> 

    <application android:name="android.app.Application" 
     android:label="MySample" > 

     <uses-library android:name="com.google.android.maps"/> 

     <!-- Main activity --> 
     <activity android:name="example.mysample.MapScreen" 
        android:clearTaskOnLaunch="true" 
        android:label="MySample" 
        android:screenOrientation="portrait"> 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 
       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 

     <!-- Other activities --> 
     <!--activity android:name="example.mysample.SomethingElse" 
        android:label="Something" 
        android:screenOrientation="portrait"/--> 

    </application> 
</manifest> 

的build.xml(持平模板):

<?xml version="1.0" encoding="UTF-8"?> 
<project name="PROJECT_NAME" default="help"> 

<!-- The local.properties file is created and updated by the 'android' 
    tool. 
    It contains the path to the SDK. It should *NOT* be checked into 
    Version Control Systems. --> 
    <property file="local.properties" /> 

    <!-- The build.properties file can be created by you and is never touched 
     by the 'android' tool. This is the place to change some of the 
     default property values used by the Ant rules. 
     Here are some properties you may want to change/update: 

     source.dir 
      The name of the source directory. Default is 'src'. 
     out.dir 
      The name of the output directory. Default is 'bin'. 

     Properties related to the SDK location or the project target should 
     be updated using the 'android' tool with the 'update' action. 

     This file is an integral part of the build system for your 
     application and should be checked into Version Control Systems. 

     --> 
    <property file="build.properties" /> 

    <!-- The default.properties file is created and updated by the 'android' 
     tool, as well as ADT. 
     This file is an integral part of the build system for your 
     application and should be checked into Version Control Systems. --> 
    <property file="default.properties" /> 

    <!-- Custom Android task to deal with the project target, and import the 
     proper rules. 
     This requires ant 1.6.0 or above. --> 
    <path id="android.antlibs"> 
     <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" /> 
     <pathelement path="${sdk.dir}/tools/lib/sdklib.jar" /> 
     <pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" /> 
    </path> 

    <taskdef name="setup" 
     classname="com.android.ant.SetupTask" 
     classpathref="android.antlibs" /> 

<!-- extension targets. Uncomment the ones where you want to do custom work 
    in between standard targets --> 
<!-- 
    <target name="-pre-build"> 
    </target> 
    <target name="-pre-compile"> 
    </target> 

    [This is typically used for code obfuscation. 
    Compiled code location: ${out.classes.absolute.dir} 
    If this is not done in place, override ${out.dex.input.absolute.dir}] 
    <target name="-post-compile"> 
    </target> 
--> 


    <!-- Execute the Android Setup task that will setup some properties 
     specific to the target, and import the build rules files. 

     The rules file is imported from 
      <SDK>/platforms/<target_platform>/ant/ant_rules_r#.xml 

     To customize existing targets, there are two options: 
     - Customize only one target: 
      - copy/paste the target into this file, *before* the 
       <setup> task. 
      - customize it to your needs. 
     - Customize the whole script. 
      - copy/paste the content of the rules files (minus the top node) 
       into this file, *after* the <setup> task 
      - disable the import of the rules by changing the setup task 
       below to <setup import="false" />. 
      - customize to your needs. 
    --> 
    <setup /> 

</project> 
+0

我也有興趣聽到這個_doesn't_ repro爲任何人。 – benkc 2011-03-23 22:39:44

回答

1

我也面臨這個問題 - 似乎是在Android MapView的API中的錯誤 - 我認爲發佈到明星是這一個: http://code.google.com/p/android/issues/detail?id=17387&can=5&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars 也是一個可能的解決方法,這是醜陋的,但適用於包括在評論 - 基本上你確定錯誤,並相應地調整結果

+0

感謝 - 醜陋,但它看起來像現在最好的解決方案。 – benkc 2012-10-10 20:16:15