2013-01-14 20 views
19

Jeśli otworzysz aplikację Mapy Google, w prawym górnym rogu ekranu znajduje się przycisk, który możesz nacisnąć, aby wyśrodkować mapę w bieżącej lokalizacji. Ikona przycisku zmienia się. Jeśli naciśniesz ten sam przycisk ponownie, mapa automatycznie obraca się zgodnie z kierunkiem kompasu. Innymi słowy, mapa staje się egocentryczna (w przeciwieństwie do alokatywnej AKA północ zawsze).Mapy automatyczne automatyczne obracanie

Google niedawno uruchomił mapy API V2 na Androida i zdecydowanie podoba mi się to bardziej niż stare. Domyślnie mapy w systemie Android V2 zawierają przycisk "centrum na miejscu". Jednak naciśnięcie go więcej niż jeden raz nie umożliwia automatycznego obracania; próbuje jedynie ponownie wycentrować mapę w twojej lokalizacji.

Czy ktoś wie, w jaki sposób mogę automatycznie obracać mapę za pomocą map API V2, tak jak robi to aplikacja map Google? Czy będę musiał zaimplementować tę funkcję samodzielnie, czy jest to w interfejsie API i po prostu go nie widzę? Doceniam wszelką pomoc.

+0

To był pomocny ... Ja nawet nie wiedziałem o tej funkcji, dzięki. Dla mnie działa dobrze (v7) –

+0

on, chcę zrobić to samo, proszę podzielić się rozwiązaniem, jeśli to zrobiłeś. –

Odpowiedz

22

Ok Oto, jak myślę, że powinno to zostać zrobione rok później. Proszę poprawić mnie, jeśli zauważysz jakieś problemy.

Większość poniższego kodu dotyczy rozbieżności między układami współrzędnych. Używam czujnika wektorowego obrotu. Z dokumentów: Y is tangential to the ground at the device's current location and points towards magnetic north. Z drugiej strony, łożysko w mapach Google wydaje się wskazywać na prawdziwą północ. this page shows how the conversion is done

1) uzyskać aktualny deklinacji z bieżącej lokalizacji GPS

@Override 
public void onLocationChanged(Location location) { 
    GeomagneticField field = new GeomagneticField(
      (float)location.getLatitude(), 
      (float)location.getLongitude(), 
      (float)location.getAltitude(), 
      System.currentTimeMillis() 
     ); 

    // getDeclination returns degrees 
    mDeclination = field.getDeclination(); 
} 

2) obliczyć mając od deklinacji i północy magnetycznej

@Override 
public void onSensorChanged(SensorEvent event) { 
    if(event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { 
     SensorManager.getRotationMatrixFromVector(
       mRotationMatrix , event.values); 
     float[] orientation = new float[3]; 
     SensorManager.getOrientation(mRotationMatrix, orientation); 
     float bearing = Math.toDegrees(orientation[0]) + mDeclination; 
     updateCamera(bearing); 
    } 
} 

3) zmiana mapy

private void updateCamera(float bearing) { 
    CameraPosition oldPos = mMap.getCameraPosition(); 

    CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing).build(); 
      mMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos)); 
} 
+1

mRotationMatrix? – Anthone

+1

'private float [] mRotationMatrix = new float [16];' 'getRotationMatrixFromVector' zapełni' mRotationMatrix' na podstawie wartości w zdarzeniu. –

+0

To powoduje efekt migotania na mapie, jak mogę ograniczyć rotację – Bytecode

1

Jest to możliwe, rejestrując swoją aplikację w odbiorniku czujnika Orientacja i uzyskanie kąta w stosunku do prawdziwej północy w środkuSensorChanged i odpowiednio zaktualizować kamerę. Kąt może być używany do łożyska. Poniższy kod może być użyty:

Instead of using Sensor.TYPE_ORIENTATION try using getOrinetation api. Sensor.TYPE_ORIENTATION 
has been deprecated. 

@Override 
protected void onResume() { 
    // TODO Auto-generated method stub 
    super.onResume(); 
    if (sensorManager != null) 
     sensorManager.registerListener(this, 
       sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), 
       SensorManager.SENSOR_DELAY_GAME); 
} 

public void onSensorChanged(SensorEvent event) { 

    float degree = Math.round(event.values[0]); 

    Log.d(TAG, "Degree ---------- " + degree); 

    updateCamera(degree); 

} 

private void updateCamera(float bearing) { 
    CameraPosition oldPos = googleMap.getCameraPosition(); 

    CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing) 
      .build(); 

    googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos)); 

} 
5

Mam powodzeniem wdrożony aleph_null rozwiązanie i tu dodam kilka szczegółów, które nie są wymienione w przyjętego rozwiązania:

Do powyższego roztworu do pracy trzeba zaimplementować Interfejs android.hardware.SensorEventListener.

Trzeba także zarejestrować na SensorEventListener w swoich metodach onResume i OnPause następujące:

@Override 
    protected void onResume() { 
    super.onResume(); 
    mSensorManager.registerListener(this, 
      mRotVectSensor, 
      SensorManager.SENSOR_STATUS_ACCURACY_LOW); 
    } 

@Override 
protected void onPause() { 
    // unregister listener 
    super.onPause(); 
    mSensorManager.unregisterListener(this); 
} 

Uwaga na „@Bytecode”: Aby uniknąć migotania, użyj małej wartości dla okresu pobierania próbek, coś SensorManager .SENSOR_STATUS_ACCURACY_LOW.

Zauważyłem też, że czujnik wysyła czasem więcej danych niż urządzenie może obsłużyć, w wyniku czego kamera map zaczyna poruszać się w dziwny sposób!

Aby kontrolować ilość danych obsługiwanych przez onSensorChanged, proponuję następującą realizacji:

@Override 
public void onSensorChanged(SensorEvent event) { 
    if(event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { 
     SensorManager.getRotationMatrixFromVector(
       mRotationMatrix, event.values); 
     float[] orientation = new float[3]; 
     SensorManager.getOrientation(mRotationMatrix, orientation); 
     if (Math.abs(Math.toDegrees(orientation[0]) - angle) > 0.8) { 
      float bearing = (float) Math.toDegrees(orientation[0]) + mDeclination; 
      updateCamera(bearing); 
     } 
     angle = Math.toDegrees(orientation[0]); 
    } 
} 
+0

'mRotVectSensor'? – theapache64

+0

gdzie zdefiniowano kąt – suulisin