我有4个LatLng
。对于制作矩形多边形,它们应该在顺时针或逆时针方向的列表中,这样当我在谷歌地图的addPolygon(new LatLng)
中添加这些LatLng
时,它将创建一个矩形。但在我的情况下,它们可能是顺时针的,也可能是逆时针的,或者是不同的形式。一个例子是->第一个LatLng
,然后是第三个LatLng
,接着是第二个LatLng
,最后是第四个LatLng
。在这种情况下,它不会在谷歌地图上创建矩形多边形。所以我必须按顺时针或逆时针排列,这样形状必须是矩形,当我把这个LatLng
列表放在谷歌地图的addPolygon()
中时。
假设:
val rectOptions = PolygonOptions()
.add(
LatLng(37.35, -122.0),
LatLng(37.45, -122.0),
LatLng(37.45, -122.2),
LatLng(37.35, -122.2)
)
如果我把rectOptions
放在mMap.addPolygon(rectOptions)
的AddPolygon()
中它将在谷歌地图上创建一个矩形。就我而言:
val rectOptions = PolygonOptions()
.add(
LatLng(37.45, -122.0),
LatLng(37.45, -122.2),
LatLng(37.35, -122.0),
LatLng(37.35, -122.2)
)
这不会创建矩形。所以我必须把这些LatLng
排列成矩形。
通常,您的任务是凸包构建,可以通过一种凸包算法来解决,例如本实现中的Gift wrappeng(又名Jarvis(算法。
注意,大多数凸包算法的实现都是针对平面(x,y)
点坐标,而不是针对LatLng
位置坐标,因此最简单的方法是使用Projection.toScreenLocation()
方法将LatLng
转换为平面(x,y)
点,然后在应用凸包算法后,使用Projection.fromScreenLocation()
方法将其转换回LatLng
。
还要记住,Projection
对象只会在映射通过布局过程后返回有效值(即,它设置了有效的width
和height
(,您可以在OnCameraIdleListener
中获得它,也可以使用andr在本答案中描述的方法。
所以完整的演示源代码可以是这样的:
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
private GoogleMap mGoogleMap;
private SupportMapFragment mMapSupportedFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMapSupportedFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map_fragment);
mMapSupportedFragment.getMapAsync(MainActivity.this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
@Override
public void onCameraIdle() {
ArrayList<LatLng> sourcePoints = new ArrayList<>();
sourcePoints.add(new LatLng(37.35, -122.0));
sourcePoints.add(new LatLng(37.45, -122.2));
sourcePoints.add(new LatLng(37.40, -122.1));
sourcePoints.add(new LatLng(37.35, -122.2));
sourcePoints.add(new LatLng(37.45, -122.0));
Projection projection = mGoogleMap.getProjection();
ArrayList<Point> screenPoints = new ArrayList<>(sourcePoints.size());
for (LatLng location : sourcePoints) {
Point p = projection.toScreenLocation(location);
screenPoints.add(p);
}
ArrayList<Point> convexHullPoints = convexHull(screenPoints);
ArrayList<LatLng> convexHullLocationPoints = new ArrayList(convexHullPoints.size());
for (Point screenPoint : convexHullPoints) {
LatLng location = projection.fromScreenLocation(screenPoint);
convexHullLocationPoints.add(location);
}
PolygonOptions polygonOptions = new PolygonOptions();
for (LatLng latLng : convexHullLocationPoints) {
polygonOptions.add(latLng);
}
mGoogleMap.clear();
Polygon polygon = mGoogleMap.addPolygon(polygonOptions.strokeColor(Color.argb(255, 49, 101, 187)).fillColor(Color.argb(100, 49, 101, 187)));
}
});
}
private boolean CCW(Point p, Point q, Point r) {
return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y) > 0;
}
public ArrayList<Point> convexHull(ArrayList<Point> points)
{
int n = points.size();
if (n <= 3) return points;
ArrayList<Integer> next = new ArrayList<>();
// find the leftmost point
int leftMost = 0;
for (int i = 1; i < n; i++)
if (points.get(i).x < points.get(leftMost).x)
leftMost = i;
int p = leftMost, q;
next.add(p);
// iterate till p becomes leftMost
do {
q = (p + 1) % n;
for (int i = 0; i < n; i++)
if (CCW(points.get(p), points.get(i), points.get(q)))
q = i;
next.add(q);
p = q;
} while (p != leftMost);
ArrayList<Point> convexHullPoints = new ArrayList();
for (int i = 0; i < next.size() - 1; i++) {
int ix = next.get(i);
convexHullPoints.add(points.get(ix));
}
return convexHullPoints;
}
}
此外,如果你只需要对矩形的点进行"排序",你可以找到更简单的算法(例如,你需要测试哪三个点形成直角,然后从第一个点添加到第三个点,然后添加第四个点,以此类推(。