I want to create a regular polygon shape no matter the order of click on map. Currently I am facing a problem if a click on the map to draw polygon in the following manner then it works fine order is following
top left top right bottom right bottom left. IF this order is maintained then polygon drawn is perfectly fine similarly if i click on top right ,top left bottom right bottom it is also drawing perfectly fine. If when I change a single pint in order it does not draw proper shaped polygon
Image1
Image 2
Code 2 draw polygon is following
gMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
llClearSelection.setVisibility(View.VISIBLE);
gMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).icon(BitmapDescriptorFactory.fromResource(R.drawable.marker)).position(latLng));
if (markerClicked) {
// latLngArrayListPolygon.clear();
if (polygon != null) {
polygon.remove();
polygon = null;
}
polygonOptions.add(latLng);
latLngArrayListPolygon.add(latLng);
polygonOptions.strokeColor(Color.RED);
polygonOptions.fillColor(shadeColor);
polygon = gMap.addPolygon(polygonOptions);
if (latLngArrayListPolygon.size() > 1)
ivSaveMap.setVisibility(View.VISIBLE);
else
ivSaveMap.setVisibility(View.GONE);
} else {
if (polygon != null) {
polygon.remove();
polygon = null;
}
polygonOptions = new PolygonOptions().add(latLng);
latLngArrayListPolygon.add(latLng);
markerClicked = true;
}
}
});
My concern is I want to draw a regular shape irrespective of the order of click on map
Finally I derived solution to create regular shape polygon. This is not related to Convex hull.
Following are the Step to create regular shape polygon whether you click clock wise on map or counter clock wise on map.
Find the mid points of the edges of polygon
Calculate the nearest coordinate by finding distance between mid point of each edge and the coordinate to be drawn
The nearest coordinate = the edge with minimum distance from mid point to the coordinate to be drawn
move the nearest coordinate at the end by shifting array right
Following is the code :
ArrayList<LatLng> latLngArrayListPolygon = new ArrayList<>();
ArrayList<Double> distancesFromMidPointsOfPolygonEdges = new ArrayList<>();
private void adjustPolygonWithRespectTo(LatLng point) {
double minDistance = 0;
if (latLngArrayListPolygon.size() > 2) {
distancesFromMidPointsOfPolygonEdges.clear();
//midPointsOfPolygonEdges?.removeAll()
for (int i = 0; i < latLngArrayListPolygon.size(); i++) {
// 1. Find the mid points of the edges of polygon
ArrayList<LatLng> list = new ArrayList<>();
if (i == (latLngArrayListPolygon.size() - 1)) {
list.add(latLngArrayListPolygon.get(latLngArrayListPolygon.size() - 1));
list.add(latLngArrayListPolygon.get(0));
} else {
list.add((latLngArrayListPolygon.get(i)));
list.add((latLngArrayListPolygon.get(i + 1)));
}
LatLng midPoint = computeCentroid(list);
// 2. Calculate the nearest coordinate by finding distance between mid point of each edge and the coordinate to be drawn
Location startPoint = new Location("");
startPoint.setLatitude(point.latitude);
startPoint.setLongitude(point.longitude);
Location endPoint = new Location("");
endPoint.setLatitude(midPoint.latitude);
endPoint.setLongitude(midPoint.longitude);
double distance = startPoint.distanceTo(endPoint);
distancesFromMidPointsOfPolygonEdges.add(distance);
if (i == 0) {
minDistance = distance;
} else {
if (distance < minDistance) {
minDistance = distance;
}
}
//midPointsOfPolygonEdges?.append(midPoint)
}
// 3. The nearest coordinate = the edge with minimum distance from mid point to the coordinate to be drawn
int position = minIndex(distancesFromMidPointsOfPolygonEdges);
// 4. move the nearest coordinate at the end by shifting array right
int shiftByNumber = (latLngArrayListPolygon.size() - position - 1);
if (shiftByNumber != latLngArrayListPolygon.size()) {
latLngArrayListPolygon = rotate(latLngArrayListPolygon, shiftByNumber);
}
}
// 5. Now add coordinated to be drawn
latLngArrayListPolygon.add(point);
}
public static int minIndex(ArrayList<Double> list) {
return list.indexOf(Collections.min(list));
}
public static <T> ArrayList<T> rotate(ArrayList<T> aL, int shift) {
if (aL.size() == 0)
return aL;
T element = null;
for (int i = 0; i < shift; i++) {
// remove last element, add it to front of the ArrayList
element = aL.remove(aL.size() - 1);
aL.add(0, element);
}
return aL;
}
private LatLng computeCentroid(List<LatLng> points) {
double latitude = 0;
double longitude = 0;
int n = points.size();
for (LatLng point : points) {
latitude += point.latitude;
longitude += point.longitude;
}
return new LatLng(latitude / n, longitude / n);
}
And to draw polygon on clicking on map is Following
gMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
gMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).icon(BitmapDescriptorFactory.fromResource(R.drawable.marker)).position(latLng));
if (markerClicked) {
if (polygon != null) {
polygon.remove();
polygon = null;
}
adjustPolygonWithRespectTo(latLng);
PolygonOptions polygonOptions = null;
for (int i = 0; i < latLngArrayListPolygon.size(); i++)
if (i == 0)
polygonOptions = new PolygonOptions().add(latLngArrayListPolygon.get(0));
else
polygonOptions.add(latLngArrayListPolygon.get(i));
polygonOptions.strokeColor(Color.BLACK);
polygonOptions.strokeWidth(5f);
polygonOptions.fillColor(shadeColor);
polygon = gMap.addPolygon(polygonOptions);
} else {
if (polygon != null) {
polygon.remove();
polygon = null;
}
polygonOptions = new PolygonOptions().add(latLng);
latLngArrayListPolygon.add(latLng);
markerClicked = true;
}
}
});
Have a look at How can I determine whether a 2D Point is within a Polygon?
As your user clicks on the map you have to determine if the new vertex is within the polygon or outside. If it is inside, ignore. Else, add the polygon and run the algorithm for every point in polygon.
Hope this helps.
Related
Is there a way I can change the icon of start and end of marker like blue for start and red for end, add different details and add connecting polyline?
Button:
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for (int i = 0; i < list_location.size(); i++) {
createMarker(list_location.get(i).getLatitude(), list_location.get(i).getLongitude());
}
}
});
Marker:
private void createMarker(String latitude, String longitude) {
// Adding the taped point to the ArrayList
BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.ic_menu_camera);
Double lat = Double.parseDouble(latitude);
Double Longitude = Double.parseDouble(longitude);
map.addMarker(new MarkerOptions()
.position(new LatLng(lat, Longitude))
.anchor(0.5f, 0.5f)
.title("title")
.snippet("snippet")
.icon(icon));
}
It's easy but seems you haven't tried much
you can use index to find first and last points
and draw different color based on position
i.e.
for (int i = 0; i < list_location.size(); i++) {
createMarker(i, list_location.get(i).getLatitude(),list_location.get(i).getLongitude());
}
and in your createMarker() method
private void createMarker(int index, String latitude, String longitude) {
// Adding the taped point to the ArrayList
if (index == 0)
color = BitmapDescriptorFactory.COLOR_THAT_SUITS;
else if (index == list_location.size()-1)
color = BitmapDescriptorFactory.COLOR_THAT_SUITS;
//set this color to your marker
.....
.....
.icon(BitmapDescriptorFactory.defaultMarker(color)));
}
I have this method:
public void crowdArea(){
for (int n=0; n<place.length; n++) {
Location locationFromDB2 = new Location("");
locationFromDB2.setLatitude(latt2[n]);
locationFromDB2.setLongitude(longg2[n]);
total = 0;
double c [][]=new double[100][2];
double p [][]=new double[100][2];
for (int n2 = 0; n2 < latt.length; n2++) {
Location locationFromDB3 = new Location("");
locationFromDB3.setLatitude(latt[n2]);
locationFromDB3.setLongitude(longg[n2]);
float dist = locationFromDB2.distanceTo(locationFromDB3);
if (dist < 500f) {
c [total][0]=latt[n2];
c [total][1]=longg[n2];
p [total][0]=prelatt[n2];
p [total][1]=prelongg[n2];
total++;
}
}
if (total >= 5) {
draw(latt2[n], longg2[n]);
state[n]="yes";
boolean b=bearing2(c,p);
Log.d("diriction is: ", b+"");
}
else{
state[n]="no";
// draw2(latt2[n], longg2[n]);
}
}
}
public void draw(double lat, double lonng){
Circle myCircle;
LatLng lt=new LatLng(lat, lonng);
CircleOptions circleOptions = new CircleOptions()
.center(lt) //set center
.radius(500) //set radius in meters
.fillColor(0x40ff0000) //default
.strokeColor(Color.RED)
.strokeWidth(5);
myCircle = map.addCircle(circleOptions);
}
which draws a circle on my map.
this method is called every 15 secs, but it draws a circle on the previous circle and so on. what I want is to remove previous circles before adding the new one.
how to do this?
You can use map.clear() to clear the map before drawing the new circle.
Alternatively, if you have drawn other objects on the map and you don't want to delete them, just your previous Circle, you can do:
private Circle myCircle;
// ...
public void draw(double lat, double lonng){
LatLng lt=new LatLng(lat, lonng);
CircleOptions circleOptions = new CircleOptions()
.center(lt) //set center
.radius(500) //set radius in meters
.fillColor(0x40ff0000) //default
.strokeColor(Color.RED)
.strokeWidth(5);
if (myCircle != null) {
myCircle.remove();
}
myCircle = map.addCircle(circleOptions);
}
FOLLOWUP based on your code update:
private List<Circle> circles = new ArrayList<>();
public void crowdArea(){
clearCircles();
for (int n=0; n<place.length; n++) {
Location locationFromDB2 = new Location("");
locationFromDB2.setLatitude(latt2[n]);
locationFromDB2.setLongitude(longg2[n]);
total = 0;
double c [][]=new double[100][2];
double p [][]=new double[100][2];
for (int n2 = 0; n2 < latt.length; n2++) {
Location locationFromDB3 = new Location("");
locationFromDB3.setLatitude(latt[n2]);
locationFromDB3.setLongitude(longg[n2]);
float dist = locationFromDB2.distanceTo(locationFromDB3);
if (dist < 500f) {
c [total][0]=latt[n2];
c [total][1]=longg[n2];
p [total][0]=prelatt[n2];
p [total][1]=prelongg[n2];
total++;
}
}
if (total >= 5) {
draw(latt2[n], longg2[n]);
state[n]="yes";
boolean b=bearing2(c,p);
Log.d("diriction is: ", b+"");
}
else{
state[n]="no";
// draw2(latt2[n], longg2[n]);
}
}
}
public void draw(double lat, double lonng){
LatLng lt=new LatLng(lat, lonng);
CircleOptions circleOptions = new CircleOptions()
.center(lt) //set center
.radius(500) //set radius in meters
.fillColor(0x40ff0000) //default
.strokeColor(Color.RED)
.strokeWidth(5);
circles.add(map.addCircle(circleOptions));
}
private void clearCircles() {
for (Circle circle : circles) {
circle.remove();
}
circles.clear();
}
I suggest you to use
if(mapCircle!=null){
mapCircle.remove();
}
instead of map.clear() because this will remove every objects on the map
I'm trying to keep a user from leaving the custom overlay area that I'm putting up on my google map for an android device.
The problem is all my attempts to keep the user's view within GPS constraints end up fighting each other and bouncing the map back and forth.
What I did was I set up a listener and multiple methods to move the camera if it went out of bounds:
map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition position) {
firstMapRegionCheck = true;
VisibleRegion vr = mMap.getProjection().getVisibleRegion();
double left = vr.latLngBounds.southwest.longitude;
double top = vr.latLngBounds.northeast.latitude;
double right = vr.latLngBounds.northeast.longitude;
double bottom = vr.latLngBounds.southwest.latitude;
zoomFix(position);
checkXAxis(position, left, top, right, bottom);
checkYAxis(position, left, top, right, bottom);
}
});
}
I get all the latitude and longitude points first. Then I run them through a method "zoomFix" that
public void zoomFix(CameraPosition position){
if (position.zoom < DEFAULT_ZOOM) {
CameraUpdate defaultZoomMove = CameraUpdateFactory.zoomTo(DEFAULT_ZOOM);
mMap.moveCamera(defaultZoomMove);
}
else if (position.zoom > 17){
CameraUpdate zoomOut = CameraUpdateFactory.zoomTo(DEFAULT_ZOOM);
mMap.moveCamera(zoomOut);
}
}
Originally I checked both the Latitude and Longitude both being too small and too big all at once. I thought that was why they were fighting back and forth.
So I created two methods, one that checks the x coordinates and one that checks the y coordinates.
I thought by splitting the x and y coordinates up- that may have fixed the problem. But it didn't.
checkXAxis:
public void checkXAxis(CameraPosition position, double left, double top, double right, double bottom){
if (left < -87.896567) {
LatLng southwest = new LatLng(bottom, -87.896567);
LatLng northeast = new LatLng(top, right);
LatLngBounds newBounds = new LatLngBounds(southwest, northeast);
CameraUpdate camerageUpdate = CameraUpdateFactory.newLatLngBounds(newBounds, 0);
mMap.moveCamera(camerageUpdate);
zoomFix(position);
}
else if (right > -87.874628)
{
LatLng southwest = new LatLng(bottom, left);
LatLng northeast = new LatLng(top, -87.874628);
LatLngBounds newBounds = new LatLngBounds(southwest, northeast);
CameraUpdate camerageUpdate = CameraUpdateFactory.newLatLngBounds(newBounds, 0);
mMap.moveCamera(camerageUpdate);
zoomFix(position);
}
}
checkYAxis:
public void checkYAxis(CameraPosition position, double left, double top, double right, double bottom){
if (top > 43.178949){
LatLng southwest = new LatLng(bottom, left);
LatLng northeast = new LatLng(43.179501, right);
LatLngBounds newBounds = new LatLngBounds(southwest, northeast);
CameraUpdate camerageUpdate = CameraUpdateFactory.newLatLngBounds(newBounds, 0);
mMap.moveCamera(camerageUpdate);
zoomFix(position);
if (firstMapRegionCheck){
firstMapRegionCheck = false;
checkXAxis(position, left, top, right, bottom);
}
}
else if (bottom < 43.169292){
LatLng southwest = new LatLng(43.169292, left);
LatLng northeast = new LatLng(top, right);
LatLngBounds newBounds = new LatLngBounds(southwest, northeast);
CameraUpdate camerageUpdate = CameraUpdateFactory.newLatLngBounds(newBounds, 0);
mMap.moveCamera(camerageUpdate);
zoomFix(position);
if (firstMapRegionCheck){
firstMapRegionCheck = false;
checkXAxis(position, left, top, right, bottom);
}
}
Anyways, if anyone can figure out how to prevent the fixes from fighting each other and not fully fixing the issue before hitting the onCameraChange listener again (which I assume is the problem) I would appreciate it!
Thanks!
Setup up the listener:
mMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition position) {
VisibleRegion vr = mMap.getProjection().getVisibleRegion();
double left = vr.latLngBounds.southwest.longitude;
double top = vr.latLngBounds.northeast.latitude;
double right = vr.latLngBounds.northeast.longitude;
double bottom = vr.latLngBounds.southwest.latitude;
zoomFix(position);
checkXYAxis(left, top, right, bottom);
}
});
Zoom check method:
public void zoomFix(CameraPosition position) {
if (position.zoom < DEFAULT_ZOOM) {
CameraUpdate defaultZoomMove = CameraUpdateFactory.zoomTo(DEFAULT_ZOOM);
mMap.moveCamera(defaultZoomMove);
} else if (position.zoom > 17) {
CameraUpdate zoomOut = CameraUpdateFactory.zoomTo(DEFAULT_ZOOM);
mMap.moveCamera(zoomOut);
}
}
X and Y coordinate bounds:
public void checkXYAxis(double left, double top, double right, double bottom) {
//X
if (left < -87.896567) {
left = -87.896567;
}
else if (right > -87.874628) {
right = -87.874628;
}
//Y
if (top > 43.178949) {
top = 43.169292;
}
else if (bottom < 43.169292) {
bottom = 43.169292;
}
//update camera position
LatLng southwest = new LatLng(bottom, left);
LatLng northeast = new LatLng(top, right);
LatLngBounds newBounds = new LatLngBounds(southwest, northeast);
CameraUpdate update = CameraUpdateFactory.newLatLngBounds(newBounds, 0);
mMap.moveCamera(update);
}
I have current location marker and near by places marker.i have to move my current position marker to the destination position.
But my current position marker was moving out of poly line.it's not moving on the poly line path.can anyone suggest correct solution to me.Please, Thanks in Advance
My code for moving marker on map
public void animateMarker(final Marker marker, final LatLng toPosition, final boolean hideMarker)
{
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = googleMap.getProjection();
Point startPoint = proj.toScreenLocation(marker.getPosition());
final long duration =1000;
final LinearInterpolator interpolator = new LinearInterpolator();
handler.post(new Runnable()
{
public void run()
{
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed
/ duration);
double lng = t * latlng_value.longitude + (1 - t)
* latlng.longitude;
double lat = t * latlng_value.latitude + (1 - t)
* latlng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0)
{
// Post again 16ms later.
handler.postDelayed(this, 10);
}
else
{
if (hideMarker)
{
marker.setVisible(false);
}
else
{
marker.setVisible(true);
}
}
}
});
}
I would look at the code for this: http://ddewaele.github.io/GoogleMapsV2WithActionBarSherlock/part3
it's a very good example, basically you have to concatenate a set of animation for each "subline" of the polyline.
To get a subpath of the line you can use the library "google-maps-utils" that has an interpolate function
I've searched for similar questions here but none of them helped me.
I have an application running on the map that shows the path taken by the user and an icon in the form of "police". What I want now is that this icon to move the map behind me. So I created a method (stalk) that calculates a new point given the current position of the user, the position of the icon and the map. The method works, but the problem is that when I run my application icon only moves once, because his position is not updated.
Here's part of my code:
public void onMyLocationChange(Location location) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
lat = String.valueOf(latitude);
longi = String.valueOf(longitude);
posCurrent = new LatLng(latitude, longitude);
posAtuais.add(posCurrent);
posInicial = posAtuais.get(0);
Marker marker = map.addMarker(new MarkerOptions().position(posInicial));
map.moveCamera(CameraUpdateFactory.newLatLngZoom(posCurrent, 19));
PolylineOptions options = new PolylineOptions().width(5).color(mudaLinhaCor(heart_rate)).geodesic(true);
for (int z = 0; z < posAtuais.size(); z++) {
LatLng point = posAtuais.get(z);
options.add(point);
}
line = map.addPolyline(options);
LatLng posPolice = stalk(posCurrent, POLICE, map);
Marker init = map.addMarker(new MarkerOptions().position(posPolice)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.police)));
}
//A method that computes a new position
public LatLng stalk(LatLng player,LatLng police,GoogleMap mapView){
Projection projection = mapView.getProjection();
Point pointInicial = new Point(); //police
pointInicial = projection.toScreenLocation(police);
Point pointFinal = new Point(); //player
pointFinal = projection.toScreenLocation(player);
double y=0.2;
int x=0;
if((pointInicial.x==pointFinal.x)){
y=pointInicial.y+1;
}else{
double m=(pointFinal.y-pointInicial.y)/(pointFinal.x-pointInicial.x);
double b=pointInicial.y-(m*pointInicial.x);
int i=1;
while(y != (int)y){
if(pointInicial.x<pointFinal.x){
x=pointInicial.x+i;
//System.out.println("entrou no x<xfnal: "+x);
}
else if(pointInicial.x>pointFinal.x){
//System.out.println("entrou no x>xfnal");
x=pointInicial.x-i;
}
y=m*x+b;
//System.out.println("y: : "+y);
i++;
}
}
return projection.fromScreenLocation(new Point(x, (int) y));
}
Someone could help me.
Implement OnMarkerDragListener in your activity then
#Override
public void onMarkerDragStart(Marker arg0) {
markerOptions.position(latLng);
}
#Override
public void onMarkerDragEnd(Marker arg0) {
myMap.clear();
latLng = arg0.getPosition();
markerOptions.position(latLng);
Marker marker = myMap.addMarker(markerOptions);
}