Closed brwskitime closed 7 years ago
Looks like it's always shifted in the same direction, towards the y coordinate being too low.
I have tested it on several locations (it could be a latitude issue so I tested it from lalitude 0.23 to latitude 40) and the marker I set is always precisely located in a vertex of the polyline. Could you share the code that you are using to create your RichPolyline?
Sure. Here's the class I created wrapping the functionality.
public class SpeedGradientPolyline implements IPolyline {
public static final double LOW_SPEED_CLAMP_MpS = 0;
public static final int[] COLORS = {Color.rgb(47,163,0),Color.rgb(247,255,29), Color.rgb(248,78,0)};
private double HIGH_SPEED_CLAMP_KMpH = 95.5; // 60 miles/h
private double HIGH_SPEED_CLAMP_MpS = HIGH_SPEED_CLAMP_KMpH * 1000 / (60 * 60);
protected GoogleMap mMap;
protected RichLayer richLayer;
protected RichPolyline polyline;
public SpeedGradientPolyline(View mapContainer, GoogleMap googleMap) {
this(mapContainer,googleMap,0);
}
public SpeedGradientPolyline(View mapContainer, GoogleMap googleMap, float lineWidth) {
mMap = googleMap;
richLayer = new RichLayer.Builder(mapContainer,googleMap).zIndex(0).build();
RichPolylineOptions polylineOptions = new RichPolylineOptions(null)
.zIndex(1)
.strokeWidth((int)lineWidth)
.strokeColor(COLORS[0]) // the base color
.linearGradient(true);
polyline = polylineOptions.build();
richLayer.addShape(polyline);
}
@Override
public void addPoint(Location location) {
addPoint(location,true);
}
private void addPoint(Location location, boolean refresh) {
if (location == null || !location.hasSpeed()) return;
float prop = getSpeedProportion(location.getSpeed());
int color = interpolateColor(prop);
polyline.add(new RichPoint(new LatLng(location.getLatitude(),location.getLongitude())).color(color));
if (refresh) richLayer.refresh();
}
@Override
public void setPoints(List<Location> points) {
if (points==null) return;
for(int i = 0; i < points.size(); i++) {
addPoint(points.get(i),false);
}
richLayer.refresh();
}
@Override
public void refresh() {
richLayer.refresh();
}
public void clear() {
richLayer.removeShape(polyline);
}
@Override
public void hide() {
richLayer.removeShape(polyline);
}
@Override
public void show() {
richLayer.addShape(polyline);
}
public float getSpeedProportion(double metersPerSecond) {
return (float)(Math.max(Math.min(metersPerSecond, HIGH_SPEED_CLAMP_MpS), LOW_SPEED_CLAMP_MpS) / HIGH_SPEED_CLAMP_MpS);
}
private int interpolateColor(float proportion) {
int rTotal = 0, gTotal = 0, bTotal = 0;
// We correct the ratio to COLORS.length - 1 so that
// for i == COLORS.length - 1 and p == 1, then the final ratio is 1 (see below)
float p = proportion * (COLORS.length - 1);
for (int i = 0; i < COLORS.length; i++) {
// The ratio mostly resides on the 1 - Math.abs(p - i) calculation :
// Since for p == i, then the ratio is 1 and for p == i + 1 or p == i -1, then the ratio is 0
// This calculation works BECAUSE p lies within [0, length - 1] and i lies within [0, length - 1] as well
float iRatio = Math.max(1 - Math.abs(p - i), 0.0f);
rTotal += (int)(Color.red(COLORS[i]) * iRatio);
gTotal += (int)(Color.green(COLORS[i]) * iRatio);
bTotal += (int)(Color.blue(COLORS[i]) * iRatio);
}
return Color.rgb(rTotal, gTotal, bTotal);
}
}
Google's polyline: Richpolyline
Also here's the method where I load the points and set the start/end markers
private void loadTrackFromDB(long trackId) {
Cursor data = null;
ArrayList<Location> points = new ArrayList<>();
try {
data = SQLite.select().from(TrackLocation.class).where(TrackLocation_Table.track_id.eq(trackId)).orderBy(TrackLocation_Table.time, true).query();
} catch (Exception e) {
return;
}
// repopulate the map
if (data == null) {
return;
}
try {
if (!data.moveToFirst()) {
return;
}
int latIndex = data.getColumnIndex("latitude");
int lonIndex = data.getColumnIndex("longitude");
int speedIndex = data.getColumnIndex("speed");
LatLng point = new LatLng(data.getDouble(latIndex), data.getDouble(lonIndex));
Location location = new Location("snocru");
location.setLatitude(point.latitude);
location.setLongitude(point.longitude);
location.setSpeed(data.getFloat(speedIndex));
BitmapDescriptor startPinDescriptor = BitmapDescriptorFactory.fromResource(R.drawable.pin_green);
MarkerOptions startMarkerOptions = new MarkerOptions()
.title(getString(R.string.track_start))
.position(point)
.icon(startPinDescriptor);
startMarker = googleMap.addMarker(startMarkerOptions);
points.add(location);
while (data.moveToNext()) {
location = new Location("snocru");
location.setLatitude(data.getDouble(latIndex));
location.setLongitude(data.getDouble(lonIndex));
location.setSpeed(data.getFloat(speedIndex));
points.add(location);
}
mapPolyline.setPoints(points);
speedGradientPolyline.setPoints(points);
densityMap.setPoints(points);
point = new LatLng(location.getLatitude(),location.getLongitude());
// set the end marker
if (curLocMarker != null) {
curLocMarker.remove();
}
MarkerOptions currentLocationMarker = new MarkerOptions()
.title(getString(R.string.current_location))
.position(point)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.pin_blue));
curLocMarker = googleMap.addMarker(currentLocationMarker);
} catch (Throwable t) {
Log.e(TAG, "Error reloading the map", t);
try {
Crashlytics.logException(t);
} catch (Throwable ct) {
}
} finally {
data.close();
}
}
Here's the class for the google polyline.
public class MapPolyline implements IPolyline {
private GoogleMap googleMap;
private Polyline polyline;
public MapPolyline(GoogleMap googleMap, int color, float lineWidth) {
this.googleMap = googleMap;
this.polyline = googleMap.addPolyline(new PolylineOptions().geodesic(false).color(color).width(lineWidth));
}
@Override
public void addPoint(Location location) {
List<LatLng> points = polyline.getPoints();
points.add(new LatLng(location.getLatitude(),location.getLongitude()));
polyline.setPoints(points);
}
@Override
public void setPoints(List<Location> locations) {
if (locations == null) locations = new ArrayList<>();
List<LatLng> points = polyline.getPoints();
points.clear();
for(int i = 0; i < locations.size(); i++) {
Location location = locations.get(i);
points.add(new LatLng(location.getLatitude(),location.getLongitude()));
}
polyline.setPoints(points);
}
@Override
public void hide() {
polyline.setVisible(false);
}
@Override
public void show() {
polyline.setVisible(true);
}
@Override
public void clear() {
polyline.setPoints(new ArrayList<LatLng>());
}
@Override
public void refresh() {
}
}
I have tested the project and I still can't find the problem.
Could you test it using the following MapActivity
class? It will show you a green RichPolyline
(richmaps), a blue Polyline
(Google Maps) and two Marker
s:
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleMap.OnCameraIdleListener {
private RichLayer richLayer;
private View mMapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
mMapView = mapFragment.getView();
}
@Override
public void onMapReady(final GoogleMap googleMap) {
googleMap.setOnCameraIdleListener(this);
richLayer = new RichLayer.Builder(mMapView, googleMap).zIndex(0).build();
LatLng ll1 = new LatLng(43.591921, -116.211426);
LatLng ll2 = new LatLng(43.591834, -116.211456);
LatLng ll3 = new LatLng(43.591741, -116.211429);
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(ll2, 21));
googleMap.addMarker(new MarkerOptions().position(ll1).icon(
BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
googleMap.addMarker(new MarkerOptions().position(ll3).icon(
BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));
RichPolylineOptions polylineOpts = new RichPolylineOptions(null)
.zIndex(3)
.strokeWidth(15)
.strokeColor(Color.GREEN)
.linearGradient(true)
.add(new RichPoint(ll1))
.add(new RichPoint(ll2))
.add(new RichPoint(ll3));
richLayer.addShape(polylineOpts.build());
googleMap.addPolyline(new PolylineOptions()
.add(ll1)
.add(ll2)
.add(ll3)
.color(Color.BLUE)
.width(3));
}
@Override
public void onCameraIdle() {
richLayer.refresh();
}
}
Ok finally I figured out what's happening. You can set padding on the google map and google's polyline takes it into account.
We added bottom padding to account for the panel height we draw over the top of our map.
googleMap.setPadding(0, 0, 0, slidingUpPanelLayout.getPanelHeight());
This explains why the line was always shifted up in the y direction.
I have just updated richmaps to take into account vertical (top/bottom) padding. I have tried to do the same for horizontal (left/right) padding but it seems to work different so I need to put more effort on it. I hope this gets you closer to solve your issue.
Thanks! By the way thanks for creating this project. Other than the padding thing, everything worked better than expected right out of the box.
Thank you for your patience. Glad to hear it was helpful! :)
Compared to the standard google maps Polyline, the RichPolyline doesn't line up. This can be seen by adding a google map Marker.