円を描画する次のコードがある(Google Play Servicesの「マップ」サンプルから取得):
_ PolylineOptions options = new PolylineOptions();
int radius = 5; //What is that?
int numPoints = 100;
double phase = 2 * Math.PI / numPoints;
for (int i = 0; i <= numPoints; i++) {
options.add(new LatLng(SYDNEY.latitude + radius * Math.sin(i * phase),
SYDNEY.longitude + radius * Math.cos(i * phase)));
}
int color = Color.RED;
mMap.addPolyline(options
.color(color)
.width(2));
_
これは、世界のさまざまな部分に描かれているものです。
ご覧のとおり、円は実際には円ではなく、2番目の円でも基本的には楕円です。
_int numPoints
_変数のポイント数に応じて、円の「アンチエイリアス」が発生すると思います。
int radius = 5
_変数とは何ですか?どういう意味なの?canvas.drawCircle()
を使用してAPI v1にあったものに似たもの更新--------------------
数学を改善した後、「右」の円を描くことができました。
_private void addCircle(LatLng latLng, double radius)
{
double R = 6371d; // earth's mean radius in km
double d = radius/R; //radius given in km
double lat1 = Math.toRadians(latLng.latitude);
double lon1 = Math.toRadians(latLng.longitude);
PolylineOptions options = new PolylineOptions();
for (int x = 0; x <= 360; x++)
{
double brng = Math.toRadians(x);
double latitudeRad = Math.asin(Math.sin(lat1)*Math.cos(d) + Math.cos(lat1)*Math.sin(d)*Math.cos(brng));
double longitudeRad = (lon1 + Math.atan2(Math.sin(brng)*Math.sin(d)*Math.cos(lat1), Math.cos(d)-Math.sin(lat1)*Math.sin(latitudeRad)));
options.add(new LatLng(Math.toDegrees(latitudeRad), Math.toDegrees(longitudeRad)));
}
mMap.addPolyline(options.color(Color.BLACK).width(2));
}
_
しかし、私が推測する円のアンチエイリアスはやや制御を超えており、someズームレベルでは円が醜くなる可能性があります。
Googleマップv2(ビットマップ)で円を描く方法
// 1. some variables:
private static final double EARTH_RADIUS = 6378100.0;
private int offset;
// 2. convert meters to pixels between 2 points in current zoom:
private int convertMetersToPixels(double lat, double lng, double radiusInMeters) {
double lat1 = radiusInMeters / EARTH_RADIUS;
double lng1 = radiusInMeters / (EARTH_RADIUS * Math.cos((Math.PI * lat / 180)));
double lat2 = lat + lat1 * 180 / Math.PI;
double lng2 = lng + lng1 * 180 / Math.PI;
Point p1 = YourActivity.getMap().getProjection().toScreenLocation(new LatLng(lat, lng));
Point p2 = YourActivity.getMap().getProjection().toScreenLocation(new LatLng(lat2, lng2));
return Math.abs(p1.x - p2.x);
}
// 3. bitmap creation:
private Bitmap getBitmap() {
// fill color
Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
Paint1.setColor(0x110000FF);
Paint1.setStyle(Style.FILL);
// stroke color
Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
Paint2.setColor(0xFF0000FF);
Paint2.setStyle(Style.STROKE);
// icon
Bitmap icon = BitmapFactory.decodeResource(YourActivity.getResources(), R.drawable.blue);
// circle radius - 200 meters
int radius = offset = convertMetersToPixels(lat, lng, 200);
// if zoom too small
if (radius < icon.getWidth() / 2) {
radius = icon.getWidth() / 2;
}
// create empty bitmap
Bitmap b = Bitmap.createBitmap(radius * 2, radius * 2, Config.ARGB_8888);
Canvas c = new Canvas(b);
// draw blue area if area > icon size
if (radius != icon.getWidth() / 2) {
c.drawCircle(radius, radius, radius, Paint1);
c.drawCircle(radius, radius, radius, Paint2);
}
// draw icon
c.drawBitmap(icon, radius - icon.getWidth() / 2, radius - icon.getHeight() / 2, new Paint());
return b;
}
// 4. calculate image offset:
private LatLng getCoords(double lat, double lng) {
LatLng latLng = new LatLng(lat, lng);
Projection proj = YourActivity.getMap().getProjection();
Point p = proj.toScreenLocation(latLng);
p.set(p.x, p.y + offset);
return proj.fromScreenLocation(p);
}
// 5. draw:
MarkerOptions options = new MarkerOptions();
options.position(getCoords(lat, lng));
options.icon(BitmapDescriptorFactory.fromBitmap(getBitmap()));
marker = YourActivity.getMap().addMarker(options);
そして結果:
Google v2で作成されたGoogleはシンプルです。以下のスニペットは、マーカーと円の両方を描画し、それらの位置を一緒に更新する方法を示しています。
private Circle mCircle;
private Marker mMarker;
private GoogleMap mGoogleMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGoogleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.mapFragment)).getMap();
mGoogleMap.setMyLocationEnabled(true);
mGoogleMap.setOnMyLocationChangeListener(new GoogleMap.OnMyLocationChangeListener() {
@Override
public void onMyLocationChange(Location location) {
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
if(mCircle == null || mMarker == null){
drawMarkerWithCircle(latLng);
}else{
updateMarkerWithCircle(latLng);
}
}
});
}
private void updateMarkerWithCircle(LatLng position) {
mCircle.setCenter(position);
mMarker.setPosition(position);
}
private void drawMarkerWithCircle(LatLng position){
double radiusInMeters = 100.0;
int strokeColor = 0xffff0000; //red outline
int shadeColor = 0x44ff0000; //opaque red fill
CircleOptions circleOptions = new CircleOptions().center(position).radius(radiusInMeters).fillColor(shadeColor).strokeColor(strokeColor).strokeWidth(8);
mCircle = mGoogleMap.addCircle(circleOptions);
MarkerOptions markerOptions = new MarkerOptions().position(position);
mMarker = mGoogleMap.addMarker(markerOptions);
}
Android 2.0 APIでは、CircleOptionを使用して円を描くことができ、非常にうまく機能します。ピクセルからメートルへの面倒な変換はありません。
public CircleOptions getCircleOptions() {
CircleOptions co = new CircleOptions();
co.center(latlng);
co.radius(getCircleSize());
co.fillColor(getCircleColor());
co.strokeColor(getStrokeColor());
co.strokeWidth(2.0f);
return co;
}
Circle circle = mapView.getMap().addCircle(munzeeMarker.getCircleOptions());
これが私のコードです。追加されたバリエーションです。アンチエイリアスや形状の単純化に関する問題を解決する方法が見つかりませんでした。
// Make a circle of latitude and longitude points.
// Radius is in metres.
// Probably won't work if the circle is large or near the poles.
private ArrayList<LatLng> makeCircle(LatLng centre, double radius)
{
ArrayList<LatLng> points = new ArrayList<LatLng>();
double EARTH_RADIUS = 6378100.0;
// Convert to radians.
double lat = centre.latitude * Math.PI / 180.0;
double lon = centre.longitude * Math.PI / 180.0;
for (double t = 0; t <= Math.PI * 2; t += 0.1)
{
// y
double latPoint = lat + (radius / EARTH_RADIUS) * Math.sin(t);
// x
double lonPoint = lon + (radius / EARTH_RADIUS) * Math.cos(t) / Math.cos(lat);
points.add(new LatLng(latPoint * 180.0 / Math.PI, lonPoint * 180.0 / Math.PI));
}
return points;
}
Google Earthは メルカトル図法 を使用します。これは、物理的な円が地図上に円として表示されず、代わりに質問に示されているように歪んでいることを意味します。ポールに近づくほど、歪みが大きくなります。地図に円を描くには、緯度/経度で座標を指定し、歪みを反転させる必要があります。
最初に、円の中心をラジアンで見つけます。これは非常に単純で、lat
とlon
に格納されています。
次に、そのエッジ上のポイントを見つけるサークルを回ります。物理的な円を作成している場合、各ポイントの緯度と経度は次のとおりです。
double latPoint = lat + (radius / EARTH_RADIUS) * Math.sin(t);
double lonPoint = lon + (radius / EARTH_RADIUS) * Math.cos(t);
これは非常に単純な三角法です。 (半径/ EARTH_RADIUS)は、ラジアンで表した円のangular半径です(たとえば、半径100 mの円はangular半径0.000015 rad)。
この単純なコードを使用すると、マップに表示された円がcos(lat)
で水平方向に押し潰されていることがわかります。そのため、cos(lat)
で割って円を描くだけです。
同様にこれを行うことができます:
double latPoint = lat + (radius / EARTH_RADIUS) * Math.sin(t) * Math.cos(lat);
double lonPoint = lon + (radius / EARTH_RADIUS) * Math.cos(t);
結果として大きな円になります-radius
関数パラメーターが緯度と経度のどちらを参照しているかによって異なります。
この説明では、いくつかの図を使用できますが、私は気になりません。
Googleは本日2月26日、オーバーレイタイプとしてCircleをリリースしました。
昨日Android開発者チームがGoogle Playサービスv3を導入しました。悪用してください;) https://developers.google.com/maps/documentation/Android/shapes#circles