gpt4 book ai didi

android - Google Maps API v2 在 MapFragment 上绘制部分圆圈

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:22:49 25 4
gpt4 key购买 nike

我需要画这样的东西,它会被涂上颜色,透明度很低

它还需要可点击(onTouch 事件等)

enter image description here

我知道在 API v1 中您必须使用 Overlay 并使用 Canvas 和一些数学来扩展它。在 Google Map API v2 中最简单的方法是什么?

PS:半径是可变的。

(进一步引用)编辑 1:

我实现了 CanvasTileProvider 子类并覆盖了它的 onDraw() 方法:

@Override
void onDraw(Canvas canvas, TileProjection projection) {
// TODO Auto-generated method stub

LatLng tempLocation = moveByDistance(mSegmentLocation, mSegmentRadius, mSegmentAngle);

DoublePoint segmentLocationPoint = new DoublePoint(0, 0);
DoublePoint tempLocationPoint = new DoublePoint(0, 0);

projection.latLngToPoint(mSegmentLocation, segmentLocationPoint);
projection.latLngToPoint(tempLocationPoint, tempLocationPoint);

float radiusInPoints = FloatMath.sqrt((float) (Math.pow(
(segmentLocationPoint.x - tempLocationPoint.x), 2) + Math.pow(
(segmentLocationPoint.y - tempLocationPoint.y), 2)));

RectF segmentArea = new RectF();
segmentArea.set((float)segmentLocationPoint.x - radiusInPoints, (float)segmentLocationPoint.y - radiusInPoints,
(float)segmentLocationPoint.x + radiusInPoints, (float)segmentLocationPoint.y + radiusInPoints);

canvas.drawArc(segmentArea, getAdjustedAngle(mSegmentAngle),
getAdjustedAngle(mSegmentAngle + 60), true, getOuterCirclePaint());


}

另外,我从 MapActivity 添加了这个:

private void loadSegmentTiles() {

TileProvider tileProvider;
TileOverlay tileOverlay = mMap.addTileOverlay(
new TileOverlayOptions().tileProvider(new SegmentTileProvider(new LatLng(45.00000,15.000000), 250, 30)));

}

现在我想知道为什么我的弧线不在 map 上?

最佳答案

为了绘制圆段,如果圆段主要是静态的,我会注册一个 TileProvider。 (图 block 通常只加载一次,然后缓存。)为了检查点击事件,您可以注册一个 onMapClickListener 并遍历您的段以检查单击的 LatLng 是否在您的段之一内。 (有关更多详细信息,请参见下文。)

这是一个 TileProvider 示例,您可以将其子类化并仅实现 onDraw 方法。
一个重要提示:子类必须是线程安全的! onDraw 方法会被多个线程同时调用。因此,请避免在 onDraw 中更改任何全局变量!

/* imports should be obvious */ 
public abstract class CanvasTileProvider implements TileProvider {
private static int TILE_SIZE = 256;

private BitMapThreadLocal tlBitmap;

@SuppressWarnings("unused")
private static final String TAG = CanvasTileProvider.class.getSimpleName();

public CanvasTileProvider() {
super();
tlBitmap = new BitMapThreadLocal();
}

@Override
// Warning: Must be threadsafe. To still avoid creation of lot of bitmaps,
// I use a subclass of ThreadLocal !!!
public Tile getTile(int x, int y, int zoom) {
TileProjection projection = new TileProjection(TILE_SIZE,
x, y, zoom);

byte[] data;
Bitmap image = getNewBitmap();
Canvas canvas = new Canvas(image);
onDraw(canvas, projection);
data = bitmapToByteArray(image);
Tile tile = new Tile(TILE_SIZE, TILE_SIZE, data);
return tile;
}

/** Must be implemented by a concrete TileProvider */
abstract void onDraw(Canvas canvas, TileProjection projection);

/**
* Get an empty bitmap, which may however be reused from a previous call in
* the same thread.
*
* @return
*/
private Bitmap getNewBitmap() {
Bitmap bitmap = tlBitmap.get();
// Clear the previous bitmap
bitmap.eraseColor(Color.TRANSPARENT);
return bitmap;
}

private static byte[] bitmapToByteArray(Bitmap bm) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, bos);
byte[] data = bos.toByteArray();
return data;
}

class BitMapThreadLocal extends ThreadLocal<Bitmap> {
@Override
protected Bitmap initialValue() {
Bitmap image = Bitmap.createBitmap(TILE_SIZE, TILE_SIZE,
Config.ARGB_8888);
return image;
}
}
}

使用传递给 onDraw 方法的投影首先获取图 block 的边界。如果没有段在边界内,则返回。否则将您的 fragment 绘制到 Canvas 中。 projection.latLngToPoint 方法可帮助您将 LatLng 转换为 Canvas 的像素。

/** Converts between LatLng coordinates and the pixels inside a tile. */
public class TileProjection {

private int x;
private int y;
private int zoom;
private int TILE_SIZE;

private DoublePoint pixelOrigin_;
private double pixelsPerLonDegree_;
private double pixelsPerLonRadian_;

TileProjection(int tileSize, int x, int y, int zoom) {
this.TILE_SIZE = tileSize;
this.x = x;
this.y = y;
this.zoom = zoom;
pixelOrigin_ = new DoublePoint(TILE_SIZE / 2, TILE_SIZE / 2);
pixelsPerLonDegree_ = TILE_SIZE / 360d;
pixelsPerLonRadian_ = TILE_SIZE / (2 * Math.PI);
}

/** Get the dimensions of the Tile in LatLng coordinates */
public LatLngBounds getTileBounds() {
DoublePoint tileSW = new DoublePoint(x * TILE_SIZE, (y + 1) * TILE_SIZE);
DoublePoint worldSW = pixelToWorldCoordinates(tileSW);
LatLng SW = worldCoordToLatLng(worldSW);
DoublePoint tileNE = new DoublePoint((x + 1) * TILE_SIZE, y * TILE_SIZE);
DoublePoint worldNE = pixelToWorldCoordinates(tileNE);
LatLng NE = worldCoordToLatLng(worldNE);
return new LatLngBounds(SW, NE);
}

/**
* Calculate the pixel coordinates inside a tile, relative to the left upper
* corner (origin) of the tile.
*/
public void latLngToPoint(LatLng latLng, DoublePoint result) {
latLngToWorldCoordinates(latLng, result);
worldToPixelCoordinates(result, result);
result.x -= x * TILE_SIZE;
result.y -= y * TILE_SIZE;
}


private DoublePoint pixelToWorldCoordinates(DoublePoint pixelCoord) {
int numTiles = 1 << zoom;
DoublePoint worldCoordinate = new DoublePoint(pixelCoord.x / numTiles,
pixelCoord.y / numTiles);
return worldCoordinate;
}

/**
* Transform the world coordinates into pixel-coordinates relative to the
* whole tile-area. (i.e. the coordinate system that spans all tiles.)
*
*
* Takes the resulting point as parameter, to avoid creation of new objects.
*/
private void worldToPixelCoordinates(DoublePoint worldCoord, DoublePoint result) {
int numTiles = 1 << zoom;
result.x = worldCoord.x * numTiles;
result.y = worldCoord.y * numTiles;
}

private LatLng worldCoordToLatLng(DoublePoint worldCoordinate) {
DoublePoint origin = pixelOrigin_;
double lng = (worldCoordinate.x - origin.x) / pixelsPerLonDegree_;
double latRadians = (worldCoordinate.y - origin.y)
/ -pixelsPerLonRadian_;
double lat = Math.toDegrees(2 * Math.atan(Math.exp(latRadians))
- Math.PI / 2);
return new LatLng(lat, lng);
}

/**
* Get the coordinates in a system describing the whole globe in a
* coordinate range from 0 to TILE_SIZE (type double).
*
* Takes the resulting point as parameter, to avoid creation of new objects.
*/
private void latLngToWorldCoordinates(LatLng latLng, DoublePoint result) {
DoublePoint origin = pixelOrigin_;

result.x = origin.x + latLng.longitude * pixelsPerLonDegree_;

// Truncating to 0.9999 effectively limits latitude to 89.189. This is
// about a third of a tile past the edge of the world tile.
double siny = bound(Math.sin(Math.toRadians(latLng.latitude)), -0.9999,
0.9999);
result.y = origin.y + 0.5 * Math.log((1 + siny) / (1 - siny))
* -pixelsPerLonRadian_;
};

/** Return value reduced to min and max if outside one of these bounds. */
private double bound(double value, double min, double max) {
value = Math.max(value, min);
value = Math.min(value, max);
return value;
}

/** A Point in an x/y coordinate system with coordinates of type double */
public static class DoublePoint {
double x;
double y;

public DoublePoint(double x, double y) {
this.x = x;
this.y = y;
}
}

}

最后,您需要检查一下 LatLng 坐标上的点击是否在您的段内。因此,我会通过 LatLng 坐标列表来近似该段,在您的情况下,一个简单的三角形可能就足够了。对于每个 LatLng 坐标列表,即对于每个段,您可以调用如下内容:

private static boolean isPointInsidePolygon(List<LatLng> vertices, LatLng point) {
/**
* Test is based on a horizontal ray, starting from point to the right.
* If the ray is crossed by an even number of polygon-sides, the point
* is inside the polygon, otherwise it is outside.
*/
int i, j;
boolean inside = false;
int size = vertices.size();
for (i = 0, j = size - 1; i < size; j = i++) {
LatLng vi = vertices.get(i);
LatLng vj = vertices.get(j);
if ((vi.latitude > point.latitude) != (vj.latitude > point.latitude)) {
/* The polygonside crosses the horizontal level of the ray. */
if (point.longitude <= vi.longitude
&& point.longitude <= vj.longitude) {
/*
* Start and end of the side is right to the point. Side
* crosses the ray.
*/
inside = !inside;
} else if (point.longitude >= vi.longitude
&& point.longitude >= vj.longitude) {
/*
* Start and end of the side is left of the point. No
* crossing of the ray.
*/
} else {
double crossingLongitude = (vj.longitude - vi.longitude)
* (point.latitude - vi.latitude)
/ (vj.latitude - vi.latitude) + vi.longitude;
if (point.longitude < crossingLongitude) {
inside = !inside;
}
}
}
}
return inside;
}

如您所见,我有一个非常相似的任务要解决 :-)

关于android - Google Maps API v2 在 MapFragment 上绘制部分圆圈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20382823/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com