Как правило, ваша задача Конструкция выпуклой оболочки и может быть решена одним из алгоритмов выпуклой оболочки , например, как Алгоритм упаковки подарков (он же Джарвис) в это реализация .
Обратите внимание, что большинство реализаций алгоритмов выпуклой оболочки предназначены для плоских (x,y)
координат точек, а не для LatLng
координат местоположения, поэтому проще всего преобразовать LatLng
в плоские (x,y)
точки с Projection.toScreenLocation()
и затем, после применения алгоритма выпуклой оболочки, преобразовать его обратно в LatLng
с помощью Projection.fromScreenLocation()
метода.
Также помните, что 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;
}
}
Также вы можете найти более простой алгоритм, если вам нужно «сортировать» точки только по прямоугольникам (например, вам нужно проверить, какие 3 точки образуют прямой угол и добавить их от первого к третьему, а затем добавить четвертую точку и т. д.).