Как перемещать маркер вдоль полилинии с помощью карты google

Я пытаюсь переместить маркер в соответствии с полилинией и с анимацией. Как показано на рисунке ниже:

Взято из Mapbox

Mapbox уже дает такую ​​демонстрацию. Но я хочу достичь того же, используя карты Google. Однако сейчас мой маркер не вращается по пути. Вот что я пробовал:

private void onReady(List polyz) { for (int i = 0; i < polyz.size() - 1; i++) { LatLng src = polyz.get(i); LatLng dest = polyz.get(i + 1); Polyline line = map.addPolyline(new PolylineOptions() .add(new LatLng(src.latitude, src.longitude), new LatLng(dest.latitude, dest.longitude)) .width(2).color(Color.RED).geodesic(true)); } LatLngBounds.Builder builder = new LatLngBounds.Builder(); builder.include(polyz.get(0)); builder.include(polyz.get(polyz.size()-1)); map.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 48)); map.animateCamera(CameraUpdateFactory.zoomTo(7), 1000, null); BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.car); marker = map.addMarker(new MarkerOptions() .position(polyz.get(0)) .title("Curr") .snippet("Move")); marker.setIcon(icon); } 

И анимация:

  private void animateMarker(GoogleMap myMap, final Marker marker, final List directionPoint, final boolean hideMarker) { final Handler handler = new Handler(); final long start = SystemClock.uptimeMillis(); Projection proj = myMap.getProjection(); final long duration = 600000; final Interpolator interpolator = new LinearInterpolator(); handler.post(new Runnable() { int i = 0; @Override public void run() { long elapsed = SystemClock.uptimeMillis() - start; float t = interpolator.getInterpolation((float) elapsed / duration); Location location=new Location(String.valueOf(directionPoint.get(i))); Location newlocation=new Location(String.valueOf(directionPoint.get(i+1))); marker.setAnchor(0.5f, 0.5f); marker.setRotation(location.bearingTo(newlocation) - 45); if (i < directionPoint.size()) { marker.setPosition(directionPoint.get(i)); } i++; if (t < 1.0) { // Post again 16ms later. handler.postDelayed(this, 16); } else { if (hideMarker) { marker.setVisible(false); } else { marker.setVisible(true); } } } }); } 

Вы можете использовать для своей задачи свой подход, основанный на пользовательской анимации маркера: анимировать отдельно движение автомобиля и поворот автомобиля по всем направлениям. Для этого вам нужны 2 вида анимации:

1) анимация движения автомобиля;

2) анимация для поворота автомобиля;

который вызывает друг друга на своем конце (анимация движения автомобиля на конце вызывает анимацию поворота автомобиля и наоборот: анимация поворота автомобиля на своем конце вызывает анимацию движения автомобиля и, следовательно, для всех точек пути автомобиля).

Например, на рис.

введите описание изображения здесь

1) анимация движения автомобиля от P0 до P1 ;

2) анимация для включения автомобиля P1 ;

3) анимация движения автомобиля от P1 до P2

и так далее.

Анимация движения автомобиля может быть реализована следующим способом:

 private void animateCarMove(final Marker marker, final LatLng beginLatLng, final LatLng endLatLng, final long duration) { final Handler handler = new Handler(); final long startTime = SystemClock.uptimeMillis(); final Interpolator interpolator = new LinearInterpolator(); // set car bearing for current part of path float angleDeg = (float)(180 * getAngle(beginLatLng, endLatLng) / Math.PI); Matrix matrix = new Matrix(); matrix.postRotate(angleDeg); marker.setIcon(BitmapDescriptorFactory.fromBitmap(Bitmap.createBitmap(mMarkerIcon, 0, 0, mMarkerIcon.getWidth(), mMarkerIcon.getHeight(), matrix, true))); handler.post(new Runnable() { @Override public void run() { // calculate phase of animation long elapsed = SystemClock.uptimeMillis() - startTime; float t = interpolator.getInterpolation((float) elapsed / duration); // calculate new position for marker double lat = (endLatLng.latitude - beginLatLng.latitude) * t + beginLatLng.latitude; double lngDelta = endLatLng.longitude - beginLatLng.longitude; if (Math.abs(lngDelta) > 180) { lngDelta -= Math.signum(lngDelta) * 360; } double lng = lngDelta * t + beginLatLng.longitude; marker.setPosition(new LatLng(lat, lng)); // if not end of line segment of path if (t < 1.0) { // call next marker position handler.postDelayed(this, 16); } else { // call turn animation nextTurnAnimation(); } } }); } 

где

mMarkerIcon :

 Bitmap mMarkerIcon; ... mMarkerIcon = BitmapFactory.decodeResource(getResources(), R.drawable.the_car); // for your car icon in file the_car.png in drawable folder 

и значок автомобиля должен быть ориентирован на север:

введите описание изображения здесь

для правильного вращения

nextTurnAnimation() - метод, вызываемый в конце анимации движения автомобиля, чтобы начать анимацию поворота автомобиля:

 private void nextTurnAnimation() { mIndexCurrentPoint++; if (mIndexCurrentPoint < mPathPolygonPoints.size() - 1) { LatLng prevLatLng = mPathPolygonPoints.get(mIndexCurrentPoint - 1); LatLng currLatLng = mPathPolygonPoints.get(mIndexCurrentPoint); LatLng nextLatLng = mPathPolygonPoints.get(mIndexCurrentPoint + 1); float beginAngle = (float)(180 * getAngle(prevLatLng, currLatLng) / Math.PI); float endAngle = (float)(180 * getAngle(currLatLng, nextLatLng) / Math.PI); animateCarTurn(mCarMarker, beginAngle, endAngle, TURN_ANIMATION_DURATION); } } 

В свою очередь способ анимации поворота автомобиля может быть следующим:

 private void animateCarTurn(final Marker marker, final float startAngle, final float endAngle, final long duration) { final Handler handler = new Handler(); final long startTime = SystemClock.uptimeMillis(); final Interpolator interpolator = new LinearInterpolator(); final float dAndgle = endAngle - startAngle; Matrix matrix = new Matrix(); matrix.postRotate(startAngle); Bitmap rotatedBitmap = Bitmap.createBitmap(mMarkerIcon, 0, 0, mMarkerIcon.getWidth(), mMarkerIcon.getHeight(), matrix, true); marker.setIcon(BitmapDescriptorFactory.fromBitmap(rotatedBitmap)); handler.post(new Runnable() { @Override public void run() { long elapsed = SystemClock.uptimeMillis() - startTime; float t = interpolator.getInterpolation((float) elapsed / duration); Matrix m = new Matrix(); m.postRotate(startAngle + dAndgle * t); marker.setIcon(BitmapDescriptorFactory.fromBitmap(Bitmap.createBitmap(mMarkerIcon, 0, 0, mMarkerIcon.getWidth(), mMarkerIcon.getHeight(), m, true))); if (t < 1.0) { handler.postDelayed(this, 16); } else { nextMoveAnimation(); } } }); } 

где nextMoveAnimation() :

 private void nextMoveAnimation() { if (mIndexCurrentPoint < mPathPolygonPoints.size() - 1) { animateCarMove(mCarMarker, mPathPolygonPoints.get(mIndexCurrentPoint), mPathPolygonPoints.get(mIndexCurrentPoint+1), MOVE_ANIMATION_DURATION); } } 

mPathPolygonPoints (геотоны автомобильной поездки):

 private List mPathPolygonPoints; 

И переменная mIndexCurrentPoint является индексом текущей точки на пути (она должна быть 0 в начале анимации и увеличиваться на каждом повороте пути в nextTurnAnimation() ).

TURN_ANIMATION_DURATION - TURN_ANIMATION_DURATION продолжительности (в мс) для поворота маршрута автомобиля;

MOVE_ANIMATION_DURATION - MOVE_ANIMATION_DURATION продолжительности (в мс) для движения автомобиля по отрезку пути;

Чтобы получить опору, вы можете использовать такой метод:

 private double getAngle(LatLng beginLatLng, LatLng endLatLng) { double f1 = Math.PI * beginLatLng.latitude / 180; double f2 = Math.PI * endLatLng.latitude / 180; double dl = Math.PI * (endLatLng.longitude - beginLatLng.longitude) / 180; return Math.atan2(Math.sin(dl) * Math.cos(f2) , Math.cos(f1) * Math.sin(f2) - Math.sin(f1) * Math.cos(f2) * Math.cos(dl));; } 

Наконец, вы можете запускать все анимации по вызову animateCarMove() один раз:

 animateCarMove(mCarMarker, mPathPolygonPoints.get(0), mPathPolygonPoints.get(1), MOVE_ANIMATION_DURATION); 

другие этапы анимации будут вызываться автоматически для каждой точки автомобильной дорожки.

И вы должны учитывать некоторые «особые случаи», такие как:

1) изменение знака угла поворота (например, изменение подшипника от -120 до 150 gradleусов);

2) возможности прерывания анимации пользователем;

3) рассчитать продолжительность анимации по длине сегмента пути (например, 1 сек для 1 км длины сегмента вместо фиксированного MOVE_ANIMATION_DURATION )

4) возможно настроить значение 16 в handler.postDelayed(this, 16); линия для лучшей производительности;

5) и т. Д.

Проблема заключается в том, как вы создаете свои объекты Location . Вы используете конструктор Location (String provider) который создает новое местоположение с указанным поставщиком (документацией) :

По умолчанию время, широта и долгота равны 0, а местоположение не имеет опор, высоты, скорости, точности или дополнительных параметров.

В вашем случае вы не создаете Location с требуемыми координатами, а Location , имя поставщика которого является String.valueOf(directionPoint.get(i)) но объекты Location создаются с широтой и долготой = 0.

Правильный способ создания объектов Location выглядит следующим образом:

 Location location = new Location(LocationManager.GPS_PROVIDER); location.setLatitude(directionPoint.get(i).latitude); location.setLongitude(directionPoint.get(i).longitude); Location newlocation = new Location(LocationManager.GPS_PROVIDER); newlocation.setLatitude(directionPoint.get(i+1).latitude); newlocation.setLongitude(directionPoint.get(i+1).longitude); 

В любом случае учтите, что вы получите ArrayIndexOutOfBoundsException потому что вы не принимаете во внимание, что i+1 будет ==directionPoint.size() в конце.

Я думаю, что вы ищете Marker Animations .

Вы можете анимировать маркеры, чтобы они демонстрировали динамическое движение в самых разных обстоятельствах. Чтобы указать способ анимации маркера, используйте свойство анимации маркера типа google.maps.Animation. Поддерживаются следующие значения анимации:

-DROP указывает, что маркер должен опускаться с верха карты до ее конечного местоположения, когда он сначала помещается на карту. Анимация прекратится, как только маркер остановится, а анимация вернется к нулевому значению. Этот тип анимации обычно указывается во время создания маркера.

-BUNCE указывает, что маркер должен отскочить на место. Подскакивающий маркер будет продолжать подпрыгивать, пока его свойство анимации явно не будет установлено в нуль.

Вот fragment из руководства:

 var marker; function initMap() { var map = new google.maps.Map(document.getElementById('map'), { zoom: 13, center: {lat: 59.325, lng: 18.070} }); marker = new google.maps.Marker({ map: map, draggable: true, animation: google.maps.Animation.DROP, position: {lat: 59.327, lng: 18.067} }); marker.addListener('click', toggleBounce); } function toggleBounce() { if (marker.getAnimation() !== null) { marker.setAnimation(null); } else { marker.setAnimation(google.maps.Animation.BOUNCE); } } 
  • math.random, только генерируя 0?
  • Защищенные поля Java vs public getters
  • Как ускорить время распаковки в Java / Android?
  • как я могу открыть календарь из своего приложения?
  • Фатальный сигнал 11 (SIGSEGV) при 0x00000000 (код = 1) - PhoneGap
  • Получение classа по его названию
  • Использование сертификатов клиент / сервер для двухсторонней аутентификации SSL-сокета на Android
  • Получение SMS-сообщений в Android-приложении
  • FileUriExposedException в Android
  • Объем переменной, объявленной внутри цикла for
  • Таймер Android, обновляющий текстовое представление (UI)
  • Давайте будем гением компьютера.