I'm using onLocationChanged to:
//set the location of a point
point1 = (new LatLng(location.getLatitude() , location.getLongitude()));
I'm trying to construct a polyline that points in the direction of the heading as I'm moving. Ive used the computeHeading method to calculate the heading and then I put that in computeOffset to generate another point x feet away as the far point to generate a polyline. This is done like this:
#Override
public void onLocationChanged(Location location) {
point1 = (new LatLng(location.getLatitude() , location.getLongitude()));
point2 = (new LatLng(location.getLatitude() , location.getLongitude()));
heading = SphericalUtil.computeHeading(point1, point2);
navOrigin = (new LatLng(location.getLatitude() , location.getLongitude()));
navSecPoint = SphericalUtil.computeOffset(point2, 500, heading);
PolylineOptions navigation = new PolylineOptions()
.add(navOrigin)
.add(navSecPoint)
.color(Color.MAGENTA);
if(navigationalLine !=null) { navigationalLine.remove(); }
else { navigationalLine = getMap().addPolyline(navigation); }
navigationalLine = getMap().addPolyline(navigation);
Only problem is to determine an instantaneous heading I need a distinct location for point1 and for point2. Currently as they are both in my onLocationChanged they both fill with the same location data. You can't compute a heading if both points are in the same spot.
How do I create some sort of timer or location based firing mechanism that gives some millisecond time delay between when point1 is filled with location data and a couple feet later to fill point2 with location data.
You can see the problem illustrated here
Using a timer to offset the location of two points is not necessary. Although a heading could be calculated with the spherical util tools the android.location series has a getBearing() method that continually updates with the heading of the device.
The
navSecPoint = SphericalUtil.computeOffset(point2, 500, heading);
could be substituted with:
navSecPoint = SphericalUtil.computeOffset(point2, 500, bearing);
the getBearing() method is a float and the computeOffset requires a double. This can be done:
float floatbearing = location.getBearing();
double bearing = floatbearing;
If you did decide to use a timer. Use the java.util.TimerTask.
Follow this tutorial:
run() with Timer
Related
Is there a possibility to connect two marker locations with a line? I have two location marker:
LocationMarker point1 = new LocationMarker(
20.501925,
44.792181,
new AnnotationRenderer("point1 ")
);
LocationMarker point2 = new LocationMarker(
20.502972,
44.790873,
new AnnotationRenderer("point2 ")
);
Any example? I use ArCore Location
The code below will draw a line between two points - the points are associated with anchors in Sceneform - this is adapted from the answer here https://stackoverflow.com/a/52816504/334402:
private void drawLine(AnchorNode node1, AnchorNode node2) {
//Draw a line between two AnchorNodes
Log.d(TAG,"drawLine");
Vector3 point1, point2;
point1 = node1.getWorldPosition();
point2 = node2.getWorldPosition();
//First, find the vector extending between the two points and define a look rotation
//in terms of this Vector.
final Vector3 difference = Vector3.subtract(point1, point2);
final Vector3 directionFromTopToBottom = difference.normalized();
final Quaternion rotationFromAToB =
Quaternion.lookRotation(directionFromTopToBottom, Vector3.up());
MaterialFactory.makeOpaqueWithColor(getApplicationContext(), new Color(0, 255, 244))
.thenAccept(
material -> {
/* Then, create a rectangular prism, using ShapeFactory.makeCube() and use the difference vector
to extend to the necessary length. */
Log.d(TAG,"drawLine insie .thenAccept");
ModelRenderable model = ShapeFactory.makeCube(
new Vector3(.01f, .01f, difference.length()),
Vector3.zero(), material);
/* Last, set the world rotation of the node to the rotation calculated earlier and set the world position to
the midpoint between the given points . */
Anchor lineAnchor = node2.getAnchor();
nodeForLine = new Node();
nodeForLine.setParent(node1);
nodeForLine.setRenderable(model);
nodeForLine.setWorldPosition(Vector3.add(point1, point2).scaled(.5f));
nodeForLine.setWorldRotation(rotationFromAToB);
}
);
}
Update: Full working example available here:
https://github.com/mickod/LineView
In my Android application I have to use my current heading (using accelerometer and magnetometer) and current bearing to targetLocation (location.bearingTo(targetLocation)).
I already know that using accelerometer and magnetometer to figure out current heading starts at 0° on magnetic North and current Bearing starts on geographical North. So i figured out, that i have to add to headingValue, depending on my current location, a value called declination.
For example, I pick up a certain GPS point from google-maps, adding this point as locationpoint in the application. Starting application, moving before measuring the device like a infinity-sign in the air and holding the device in front of me focused in target direction. So i notice that heading != bearing. Can anyone explain to me the error? Assume that i tried different distances between 50 and 3 meters and that my device is calibrated correctly. Below are important methods of source code:
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values.clone();
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values.clone();
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
double tempAzimuth = Math.toDegrees(orientation[0]); // orientation contains: azimut, pitch and roll
if(tempAzimuth < 0){
currentHeading = tempAzimuth + 360;
} else {
currentHeading = tempAzimuth;
}
TVheadingMag.setText(""+String.format( "%.2f",currentHeading)+"°");
}
}
}
#Override
public void onLocationChanged(Location location) {
//Declination http://stackoverflow.com/questions/4308262/calculate-compass-bearing-heading-to-location-in-android
geoField = new GeomagneticField(
Double.valueOf(location.getLatitude()).floatValue(),
Double.valueOf(location.getLongitude()).floatValue(),
Double.valueOf(location.getAltitude()).floatValue(),
System.currentTimeMillis());
if(location.bearingTo(this.target)<0){
currentBearing = location.bearingTo(this.target)+360;
} else {
currentBearing = location.bearingTo(this.target);
}
headingWithDeclination = currentHeading;
headingWithDeclination += geoField.getDeclination();
currentDistance = location.distanceTo(this.target);
TVheading.setText(""+String.format( "%.2f", headingWithDeclination)+"°");
TVheadingMag.setText(""+String.format( "%.2f",currentHeading)+"°");
TVbearing.setText(""+String.format( "%.2f",currentBearing)+"°");
TVgps.setText(""+ String.format( "%.6f",location.getLatitude()) + " " + String.format( "%.6f",location.getLongitude()));
}
UPDATE
Picture: https://pl.vc/1r6ap
The orange marked position is targetLocation.
Both position are heading to targetLocation.
Can you agree that these results are quiet correctly displayed?
During creation of this pic, i've noticed that both white marks are not equal to positions i was standing at. It seems like bad gps data is the reason because of the problem, isnt it?
Heading is the direction where you look, e.g a tank in which direction it would shoot, while bearing is the direction this vehicle moves. So that should answer why bearing is not heading.
They have different names, and meanings, they are different caluclated, they could not be expected to deliver the same value.
More details
You can move North (bearing = North) , but look at NE. (heading)
Gps delivers bearing (or course (over ground)), the direction the vehicle moves (altough some Api wrongly call it heading)
Compass (=magnetometer) delivers the direction in which you hold the device = (heading)
When you calculate the bearing between the two locations defined as coordinates in lat,lon , as you do in targetLocation (location.bearingTo(targetLocation)). then this is bearing! It is not heading!
And neither the compass not the accelrometer will deliver a decent heading value.
Some android device are very wrong in their magnetomter ( I saw +-20 degrees compared to +/- 2 degrees of my iPhone., Always use a traditional high quality compass as reference)
The ios devices shows the heading well within +/- 2 degress when well calibrated, (you have to calibrate each time before looking at the decice value, not only when you are asked by the operating system to calibrate).
GPS when moving > 10 km(h delives goot bearing results, but not heading.
Magnetometer can be off by some degree even when calibrated.
And usually the declination is smaller than the error.
Declination is nearly nothing in europe, 3 degress very north (europe), only a few places have a high declination >6-7°(north alaska)
Update to your further explantion in your graphic:
You have placed two points with a distance of only 15m, while GPS will not be much more acurate than 3-6m.
So imagine 6m offset of start or destination: such a triangle where a = 6m, b = 15, has an angle of atan2(6 / 15.0) = 21°. So you have an offset of 21° only by inacuracy of location. However still think at the differnce of heading by compass and bearing by line of sight between two locations.
Hi I've been following this tutorial http://googledevelopers.blogspot.com/2014/12/building-scalable-geofencing-api-on.html , and here's my problem,
I have a list of longitude and latitude coordinates that I've added to a JTS(Java Topology Suite) STR tree as Points.
Now I would like to send an area that is in the shape of a circle to the STR tree to find all of the Points that land in the circle.
Coordinate center = new Coordinate(entity.getLongitude(), entity.getLatitude());
GeometricShapeFactory gsf = new GeometricShapeFactory();
gsf.setCentre(center);
gsf.setNumPoints(20);
**gsf.setSize(320.0);**
Polygon poly = gsf.createCircle();
Coordinate[] coordinates = poly.getCoordinates();
//Create polygon from the coordinates.
GeometryFactory fact = new GeometryFactory();
LinearRing linear_ring = new GeometryFactory().createLinearRing(coordinates);
Polygon polygon = new Polygon(linear_ring, null, fact);
List<STRLeaf> items = strTree.query(polygon.getEnvelopeInternal());
However the result of the search sends back all of the data in the in the tree of longitude and latitude Points. When I lower the size of the circle below 320 then I receive no results from the search of the STR tree. Does anyone have experience with this ideally I would like to create the circle that finds all the points within a circle of ~7miles.
thanks for your time
It turns out that I had a silly mistake in the backend. When I added the items to the tree I mixed up the x and y coords, so that the Lat Longs were reversed. After switching them, I can now set the size of the circle to around 0.1 and it works well.
I have a circle on my map. Now I want to detect if the user (or me) is inside the circle.
Circle circle = map.addCircle(new CircleOptions()
.center(new LatLng(14.635594, 121.032962))
.radius(55)
.strokeColor(Color.RED)
);
I have this code:
LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
LocationListener ll = new myLocationListener();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,ll);
Location.distanceBetween( pLat,pLong,
circle.getCenter().latitude, circle.getCenter().longitude, distance);
if( distance[0] > circle.getRadius() ){
Toast.makeText(getBaseContext(), "Outside", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getBaseContext(), "Inside", Toast.LENGTH_LONG).show();
}
And on myLocationListener I have this:
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
pLong = location.getLongitude();
pLat = location.getLatitude();
}
It works correctly if I parameter inside distanceBetween is the coordinates of marker, however, the toast displays Outside even though my location is inside the radius.
Any ideas how to do this correctly? Please help. Thanks!
EDIT
I discovered something odd.
On the picture, you can see I have a textView above which has 5 numbers (circle Latitude, circle longitude, distance at index 0 , distance at index 1 , distance2). distance is a float array to store the distance between the center of the circle and the user location. I set the radius to 100, and I think the unit is meters, however, as you can see, the values at the distance array are : 1.334880E7 , -81.25308990478516 , -10696092987060547 . What is the formula for the computation of the distance? And also, 1.something times 10 raise to 7 is about 13 million which is really greater than 100. Please help its really confusing right now. According to documentation of Circle (The radius of the circle, specified in meters. It should be zero or greater.) and distanceBetween (Computes the approximate distance in meters between two locations) so I don't know why is this the result.
tl;dr? jsFiddle here - look at your console output.
Basically there're two ways to do this:
Check if the (marker of) the user is inside the Circle Bounds
Compute the distance between the user and the center of the Circle. Then check if it is equal or smaller than the Circle Radius. This solution needs the spherical library to work.
Circle Bounds
Just add a circle:
circle = new google.maps.Circle( {
map : map,
center : new google.maps.LatLng( 100, 20 ),
radius : 2000,
strokeColor : '#FF0099',
strokeOpacity : 1,
strokeWeight : 2,
fillColor : '#009ee0',
fillOpacity : 0.2
} )
and then check if the marker is inside:
circle.getBounds().contains( new google.maps.LatLng( 101, 21 ) );
At a first glance you might think this works. But it doesn't. In the background google (still) uses a rectangle, so everything inside the rectangular bounding box, but outside the circle will be recognized as inside the latLng bounds. It's wrong and a known problem, but it seems Google doesn't care.
If you now think that it would work with rectangular bounds, then you're wrong. Those don't work either.
Spherical Distance
The easiest and best way is to measure the distance. Include the spherical library by appending &library=spherical to your google maps script call. Then go with
google.maps.geometry.spherical.computeDistanceBetween(
new google.maps.LatLng( 100, 20 ),
new google.maps.LatLng( 101, 21 )
) <= 2000;
I know this question had been asked more than a year ago but I have
the same problem and fixed it using the distanceBetween static function of Location.
float[] distance = new float[2];
Location.distanceBetween(latLng.latitude, latLng.longitude, circle.getCenter().latitude,circle.getCenter().longitude,distance);
if ( distance[0] <= circle.getRadius())
{
// Inside The Circle
}
else
{
// Outside The Circle
}
Use GoogleMap.setOnMyLocationChange(OnMyLocationChangeListener) instead of LocationManager. This way you will get Locations that are the same as blue dot locations.
I am working on an Android app and I have latitude and longitude of a geographic point and I would like to get coordinates of the place located from X meters (North) and Y meters (West). GeoPoint does not implement this kind of functionality so I have to find a way to do it by myself...
I made some searches but I did not find anything interesting, do you have any idea how to proceed?
Tricky, because the distance between two whole longitudes depends on the latitude, and the distance also depends on the altitude...
To make things simple, I'd try and guess the longitude and latitude, and check the distance between the guess and the origin point. This is easier because getting the distance between two points has already been done.
Start with one axis, and do a kind of binary search until you find the location X meters to the north. Then do the same for the other axis.
With the following method you will get the latitude and longitude to add to the original location to get to the final one. Have in mind that this only works over relatively small distances, as it is ignoring the earth curvature.
private static final float GAP_LAT_LON = 0.00005f; //aprox 5 meters
private float results[] = new float[1];
private PointF getGaps(Location initial, float distanceX, float distanceY, PointF gaps){
Location.distanceBetween(initial.getLatitude(), initial.getLongitude(), initial.getLatitude(), initial.getLongitude() + GAP_LAT_LON, results);
double factorX = GAP_LAT_LON / results[0];
Location.distanceBetween(initial.getLatitude(), initial.getLongitude(), initial.getLatitude() + GAP_LAT_LON, initial.getLongitude(), results);
double factorY = GAP_LAT_LON / results[0];
if(gaps == null)
gaps = new PointF();
gaps.set((float)(distanceX * factorX), (float)(distanceY * factorY));
return gaps;
}
//to use
private void teste(){
PointF gaps = null;
Location initial = new Location("");
initial.setLatitude(23.5);
initial.setLongitude(13.2);
//100 meters West/East and 300 meters North/South
getGaps(initial, 100, 300, gaps);
//gaps.x returns x offset to add/subtract to initial latitude
//gaps.y returns y offset to add/subtract to initial longitude
}
good luck