【发布时间】:2012-07-13 21:08:49
【问题描述】:
我遇到了一个奇怪的问题,即使用谷歌地图包偏移点。
我有一个 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() 返回的 Projection 类将像素坐标转换为 GeoPoint。然后它使用相同的纬度/经度创建第二个 GeoPoint。最后,它将这两个 GeoPoints 转换回屏幕坐标并在此位置绘制两个圆,一个在另一个之上。
除了,当您平移时,第二个圆圈会从第一个圆圈偏移。它们具有相同的纬度/经度坐标(我在绘图后检查),但最终被转换为不同的屏幕坐标。我的调试重点是水平平移,但根据我在原始应用代码中看到的情况,我相信垂直平移可能会遇到类似的问题。
据我所知,由 maps 包创建的任何点都可以正常工作,但任何通过调用 new GeoPoint(lat, lon) 创建的点都会表现出这种行为。
我创建了一个简单的精简应用程序来展示这种行为,粘贴在下面。 (地图图块不会下载,因为我懒得签名,但您不需要它们来查看问题。)只需启动它,一直放大,然后开始向左或向右平移。观察绿色和蓝色点的分歧,并见证 Log.d 打印表明它们仍然具有相同的纬度/经度。
(有没有更好/首选的方式来发布示例项目?抱歉,这是我第一次在这里发帖。)
src/example/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/example/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/layout/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>
【问题讨论】:
-
我也很想知道这个不是否适合任何人。
标签: android