Как обновить маркер, используя местоположение в реальном времени вдоль полилинии? - PullRequest
0 голосов
/ 27 февраля 2019

Мои заголовки вопросов кажутся уже существующими, но вот мой полный сценарий.

У меня есть действие для операций на основе карты, где я рисую полилинию вдоль дороги, скажем, маршрут между двумяместах.В основном приложение отслеживает текущее местоположение пользователя (Путешествие на машине).Таким образом, пока часть все не работает, как показано на рисунке, маршрут правильно отображается, API определения местоположения устройства предоставляет обновления местоположения (вроде точного), а также я смог плавно изменить обновления местоположения,

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

Я также изучил API-интерфейсы ROAD, но не получаю правильную помощь,даже из некоторых ранее заданных вопросов.

Можно ли будет заставить маркер двигаться только по дороге?

Буду признателен за любую помощь.

1 Ответ

0 голосов
/ 01 марта 2019

Вы можете привязать маркер к пути путем проекции маркера на ближайший сегмент пути.Ближайший отрезок вы можете найти через PolyUtil.isLocationOnPath():

PolyUtil.isLocationOnPath(carPos, segment, true, 30)

и проекции маркера на этот отрезок вы можете найти путем преобразования геодезических сферических координат в ортогональные экранные координатывычисление ортогональных координат проекции и преобразование их обратно в сферические (WGS84 LatLng -> Screen x,y -> WGS84 LatLng):

Point carPosOnScreen = projection.toScreenLocation(carPos);
Point p1 = projection.toScreenLocation(segment.get(0));
Point p2 = projection.toScreenLocation(segment.get(1));
Point carPosOnSegment = new Point();

float denominator = (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y);
// p1 and p2 are the same
if (Math.abs(denominator) <= 1E-10) {
    markerProjection = segment.get(0);
} else {
    float t = (carPosOnScreen.x * (p2.x - p1.x) - (p2.x - p1.x) * p1.x
            + carPosOnScreen.y * (p2.y - p1.y) - (p2.y - p1.y) * p1.y) / denominator;
    carPosOnSegment.x = (int) (p1.x + (p2.x - p1.x) * t);
    carPosOnSegment.y = (int) (p1.y + (p2.y - p1.y) * t);
    markerProjection = projection.fromScreenLocation(carPosOnSegment);
}

С полным исходным кодом:

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {

    private GoogleMap mGoogleMap;
    private MapFragment mapFragment;

    private Button mButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mapFragment = (MapFragment) getFragmentManager()
                .findFragmentById(R.id.map_fragment);
        mapFragment.getMapAsync(this);

        mButton = (Button) findViewById(R.id.button);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mGoogleMap = googleMap;
        mGoogleMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
            @Override
            public void onMapLoaded() {
                List<LatLng> sourcePoints = new ArrayList<>();
                PolylineOptions polyLineOptions;
                LatLng carPos;

                sourcePoints.add(new LatLng(-35.27801,149.12958));
                sourcePoints.add(new LatLng(-35.28032,149.12907));
                sourcePoints.add(new LatLng(-35.28099,149.12929));
                sourcePoints.add(new LatLng(-35.28144,149.12984));
                sourcePoints.add(new LatLng(-35.28194,149.13003));
                sourcePoints.add(new LatLng(-35.28282,149.12956));
                sourcePoints.add(new LatLng(-35.28302,149.12881));
                sourcePoints.add(new LatLng(-35.28473,149.12836));

                polyLineOptions = new PolylineOptions();
                polyLineOptions.addAll(sourcePoints);
                polyLineOptions.width(10);
                polyLineOptions.color(Color.BLUE);
                mGoogleMap.addPolyline(polyLineOptions);

                carPos = new LatLng(-35.281120, 149.129721);
                addMarker(carPos);
                mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(sourcePoints.get(0), 15));

                for (int i = 0; i < sourcePoints.size() - 1; i++) {
                    LatLng segmentP1 = sourcePoints.get(i);
                    LatLng segmentP2 = sourcePoints.get(i+1);
                    List<LatLng> segment = new ArrayList<>(2);
                    segment.add(segmentP1);
                    segment.add(segmentP2);

                    if (PolyUtil.isLocationOnPath(carPos, segment, true, 30)) {
                        polyLineOptions = new PolylineOptions();
                        polyLineOptions.addAll(segment);
                        polyLineOptions.width(10);
                        polyLineOptions.color(Color.RED);
                        mGoogleMap.addPolyline(polyLineOptions);
                        LatLng snappedToSegment = getMarkerProjectionOnSegment(carPos, segment, mGoogleMap.getProjection());
                        addMarker(snappedToSegment);
                        break;
                    }
                }
            }
        });
        mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(sourcePoints.get(0), 15));
    }

    private LatLng getMarkerProjectionOnSegment(LatLng carPos, List<LatLng> segment, Projection projection) {
        LatLng markerProjection = null;

        Point carPosOnScreen = projection.toScreenLocation(carPos);
        Point p1 = projection.toScreenLocation(segment.get(0));
        Point p2 = projection.toScreenLocation(segment.get(1));
        Point carPosOnSegment = new Point();

        float denominator = (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y);
        // p1 and p2 are the same
        if (Math.abs(denominator) <= 1E-10) {
            markerProjection = segment.get(0);
        } else {
            float t = (carPosOnScreen.x * (p2.x - p1.x) - (p2.x - p1.x) * p1.x
                    + carPosOnScreen.y * (p2.y - p1.y) - (p2.y - p1.y) * p1.y) / denominator;
            carPosOnSegment.x = (int) (p1.x + (p2.x - p1.x) * t);
            carPosOnSegment.y = (int) (p1.y + (p2.y - p1.y) * t);
            markerProjection = projection.fromScreenLocation(carPosOnSegment);
        }    
        return markerProjection;
    }

    public void addMarker(LatLng latLng) {
        mGoogleMap.addMarker(new MarkerOptions()
                .position(latLng)
        );
    }
}

вы получите что-то вроде этого:

Marker snapped to path

Но лучший способ - это рассчитать расстояние до начала пути и найти его положение на пути с помощью SphericalUtil.interpolate(), потому что если несколькосегменты пути расположены близко друг к другу (например, на разных полосах одной и той же дороги), например:

Wrong nearest segment

. Текущее положение автомобиля может быть ближайшим «неправильным».сегмент.Итак, рассчитайте расстояние до начала маршрута и используйте SphericalUtil.interpolate() для точного определения точки на пути.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...