java - How to move marker along polyline using google map -
i trying move marker according polyline , animation. similar below image:
mapbox giving kind of demo. want achieve same using google maps. right marker not rotating along path. here have tried:
private void onready(list<latlng> polyz) { (int = 0; < 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); }
and animation:
private void animatemarker(googlemap mymap, final marker marker, final list<latlng> 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 = 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); } } } }); }
you can use task approach based on custom marker animation: animate separately car movement , car turns throughout direction points. need 2 kinds of animation:
1) animation car movement;
2) animation car turn;
which calls each other on end (car movement animation on end calls car turn animation , vice versa: car turn animation on end calls car movement animation , points of car path).
for example on fig.:
1) animation car movement p0
p1
;
2) animation car turn on p1
;
3) animation car movement p1
p2
and on.
car movement animation can implemented method this:
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 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 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(); } } }); }
where
mmarkericon
is:
bitmap mmarkericon; ... mmarkericon = bitmapfactory.decoderesource(getresources(), r.drawable.the_car); // car icon in file the_car.png in drawable folder
and car icon should north oriented:
for correct rotation apply
nextturnanimation()
- method called on end of car movement animation start car turn animation:
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); } }
in turn car turn animation method can this:
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(); } } }); }
where nextmoveanimation()
is:
private void nextmoveanimation() { if (mindexcurrentpoint < mpathpolygonpoints.size() - 1) { animatecarmove(mcarmarker, mpathpolygonpoints.get(mindexcurrentpoint), mpathpolygonpoints.get(mindexcurrentpoint+1), move_animation_duration); } }
the mpathpolygonpoints
(geopoints of car trip) is:
private list<latlng> mpathpolygonpoints;
and mindexcurrentpoint
variable index of current point on path (it should 0 @ start of animation , incremented on each turn of path in nextturnanimation()
method).
turn_animation_duration
- duration (in ms) animation car turn on path geopoint;
move_animation_duration
- duration (in ms) animation car movement along line segment of path;
to bearing can use method that:
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));; }
finally can start animations call animatecarmove()
once:
animatecarmove(mcarmarker, mpathpolygonpoints.get(0), mpathpolygonpoints.get(1), move_animation_duration);
other steps of animation called automatically each point of car path.
and should take account "special cases" like:
1) changing sign of of turn angle (e.g. bearing changes -120 150 degrees);
2) possibilities interrupt of animation user;
3) calculate animation duration on path segment length (e.g. 1 sec 1 km of segment length instead of fixed move_animation_duration
)
4) tune value 16
in handler.postdelayed(this, 16);
line better performance;
5) , on.
Comments
Post a Comment