2011-03-22 72 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