Test people standing still or motion in titanium - android

Now I want to do a app to test people standing still or motion in titanium..I use accelerometer and operated acceleration in 3 axis x,y,z..What I must use formula to test that problem..!

Another option would be to use GPS.
var win = Ti.UI.createWindow({ backgroundColor: 'white' });
// WARNING: This will only work well outside, where the phone can get a good GPS signal.
var label = Ti.UI.createLabel({ text: 'Traveled 0 ft' });
win.add(label);
// Set up the geolocation code
Ti.Geolocation.accuracy = Ti.Geolocation.ACCURACY_BEST;
Ti.Geolocation.distanceFilter = 0.1;
Ti.Geolocation.purpose = 'To track how far you have traveled!';
var lastLocation = null, totalFtTraveled = 0;
/**
* This function is called by the phone every time we have new geolocation data. It writes out where the user currently is.
* #param e An argument given to us by the phone with information such as accuracy, latitude, and longitude.
*/
function reportPosition(e) {
if (!e.success || e.error) {
label.text = 'error: ' + JSON.stringify(e.error);
}
else {
if (lastLocation != null) {
var lat1 = lastLocation.latitude, lon1 = lastLocation.longitude;
var lat2 = e.coords.latitude, lon2 = e.coords.longitude;
var kmTraveled = 3963.0 * Math.acos(
Math.sin(lat1 / 57.2958) * Math.sin(lat2 / 57.2958)
+ Math.cos(lat1 / 57.2958) * Math.cos(lat2 / 57.2958)
* Math.cos(lon2 / 57.2958 - lon1 / 57.2958)
);
var ftTraveled = kmTraveled * 3280.8399;
totalFtTraveled += ftTraveled;
label.text = 'Traveled ' + totalFtTraveled + 'ft';
}
lastLocation = e.coords;
}
}
// This will get the location right now, and will get the phone ready to listen for the user's current location.
Ti.Geolocation.getCurrentPosition(reportPosition);
// And this fires whenever the "distance filter" is surpassed -- with a filter of 1, this happens every 1 meter or so.
Ti.Geolocation.addEventListener('location', reportPosition);
var reset = Ti.UI.createButton({ title: 'Reset', bottom: 10, height: 50, width: 200 });
reset.addEventListener('click', function() {
totalFtTraveled = 0;
label.text = 'Traveled 0ft';
});
win.add(reset);
win.open();

First, get scalar acceleration independent of movement direction by formula accel = sqrt(accel_x^2 + accel_y^2 + accel_z^2) where ^2 means power of 2 and sqrt means a square root. After that, apply some low-pass filter to get rid of random noise. Here is a good algorithm and using alpha=0.8 for it would be a good approach. Now, you can just see whether filtered acceleration is greater than some threshold value (sensitivity depends on this threshold). Good luck!

Related

How to get the Z,Y,X Rotation of Android/iOS Device in React Native? (Pitch,Yaw,Roll)?

I tried using: "react-native-sensors" library
https://github.com/react-native-sensors/react-native-sensors/blob/master/docs/API.md#orientation-observableqx-number-qy-number-qz-number-qw-number-pitch-number-roll-number-yaw-number-timestamp-string
import { orientation } from "react-native-sensors";
const subscription = orientation.subscribe(({ qx, qy, qz, qw, pitch, roll, yaw, timestamp }) =>
console.log({ qx, qy, qz, qw, pitch, roll, yaw, timestamp })
);
I tried using their given pitch,roll,yaw and converted from radian_to_degress still not the same values as the emulator.
They also provide a quaternion to Angles function
function quaternionToAngles(q) {
let data = q;
let ysqr = data.y * data.y;
let t0 = -2.0 * (ysqr + data.z * data.z) + 1.0;
let t1 = +2.0 * (data.x * data.y + data.w * data.z);
let t2 = -2.0 * (data.x * data.z - data.w * data.y);
let t3 = +2.0 * (data.y * data.z + data.w * data.x);
let t4 = -2.0 * (data.x * data.x + ysqr) + 1.0;
t2 = t2 > 1.0 ? 1.0 : t2;
t2 = t2 < -1.0 ? -1.0 : t2;
const toDeg = 180 / Math.PI;
const euler = {};
euler.pitch = Math.asin(t2) * toDeg;
euler.roll = Math.atan2(t3, t4) * toDeg;
euler.yaw = Math.atan2(t1, t0) * toDeg;
return euler;
}
The function gives wrong results for roll,yaw and pitch. I dont want to dive into the Math of this. google searching gives 100x different equations.
Im searching for simple equations to get the Z,Y,X Rotations of my Device just like the Android Emulator provides. If Z-Rot Value is "90"(on emulator) my program should also receive the same value. I have access to gyrometer,barometer,accelometer etc.
PS: I wasted way to much time on google for a problem that should be solvable with a copy paste after one google search so I hope this question will help.
You can use the 'expo-sensors' package.
To answer your question, you can use DeviceMotion API or Gyroscope API.
Gyroscope can be used directly from their documentation, so I am providing an example of DeviceMotion.
import { DeviceMotion } from 'expo-sensors';
....
....
componentDidMount(){
DeviceMotion.addListener((devicemotionData) => {
console.log(devicemotionData);
// call to setState reflecting the deviceMotion changes.
....
....
});
// set update delay in ms
DeviceMotion.setUpdateInterval(100);
}
componentWillUnmount(){
DeviceMotion.removeAllListeners();
}
....
....
the object received by the listener will be in the following format:
{
"acceleration": {
"z": -0.0005327463150024414,
"y": 0.0034074783325195312,
"x": 0.0005932972417213023
},
"accelerationIncludingGravity": {
"z": -0.8134145140647888,
"y": -9.769495010375977,
"x": 0.0011865944834426045
},
"orientation": 0,
"rotation": {
"gamma": -0.000039085680327843875,
"alpha": 0.00004289219214115292,
"beta": 1.4878977537155151
},
"rotationRate": { "gamma": 0, "alpha": 0, "beta": 0 }
}
for more examples of usage, you can refer to this article
My android device shows a different kind of measure. maybe this could help you get deductions:
alpha range : 0 to 360
beta range : -180 to 180
gamma range : in anticlockwise motion,
0 to 90 for 1st quadrant,
90 to 0 for 2nd quadrant,
0 to -90 for 3rd quadrant,
-90 to 0 for 4th quadrant

solution for calculate trip distance

I am creating a trip distance calculation app for our drivers. Above way is working. but always calculate distance.
Why always return different LatLng(s) without moving mobile? (mobile on my desk)
Output
I am getting more than 10km result within 10 minutes without moving the device. Why is that?
double calculate(){
double cal = 0;
list.removeWhere((element) => element?.latitude == userLocation?.latitude || element?.longitude == userLocation?.longitude); //remove duplicate values
list.add(userLocation);
if (list.length > 1) {
LocationModel firstLoc = list.elementAt(list.length - 2);
LocationModel lastLoc = list.last;
cal = _cp.calculateDistance(firstLoc.latitude, firstLoc.longitude, lastLoc.latitude, lastLoc.longitude);
}
totalKm += cal;
retun totalKm;
}
double calculateDistance(lat1, lon1, lat2, lon2) {
var p = 0.017453292519943295;
var c = cos;
var a = 0.5 - c((lat2 - lat1) * p) / 2 + c(lat1 * p) * c(lat2 * p) * (1 - c((lon2 - lon1) * p)) / 2;
return 12742 * asin(sqrt(a));
}
GpsService Method
I am using geolocator plugin for that. (FusedLocationProviderClient or if not available the LocationManager on Android and CLLocationManager on iOS).
Future<LocationModel> getLocation() async {
try {
Position userLocation = await Geolocator.getCurrentPosition(forceAndroidLocationManager: false, desiredAccuracy: LocationAccuracy.high);
_currentLocation = LocationModel.fromGeoLocatorData(userLocation);
} on Exception catch (e) {
print('Could not get location: $e');
}
return _currentLocation;
}
Timer.periodic(Duration(seconds: 1), (Timer t) async {
userLocation = await locationService.getLocation().then(getLocation);
});
Location tracking is not very deterministic with mobile devices. Even if you stand still, as you poll position, it will change a little with every measurement. Also you should take accuracy of locations into account. Basically, a location you get, does not mean that the position is at exactly lat/long. It actually means, that with a confidence of 68%, the position is within a radius of accuracy meters around lat/long. [1].
Thus, you only should assume, that two locations are different, if the distance between them is bigger than the sum of both of its accuracies. And only if you've decided that a new location is different from the previous one, should you add the distance between them to the total distance.
Also, as one cannot move really far within a second (except perhaps in a race car or rocket) yoi could increase the time between measurements. This would also help in saving battery.
1: https://developer.android.com/reference/android/location/Location

What should I store in Firestore so that I can fetch data on the basis of details get from autocomplete place api? [duplicate]

Does the new firestore database from firebase natively support location based geo queries? i.e. Find posts within 10 miles, or find the 50 nearest posts?
I see that there are some existing projects for the real-time firebase database, projects such as geofire- could those be adapted to firestore as well?
UPDATE: Firestore does not support actual GeoPoint queries at present so while the below query executes successfully, it only filters by latitude, not by longitude and thus will return many results that are not nearby. The best solution would be to use geohashes. To learn how to do something similar yourself, have a look at this video.
This can be done by creating a bounding box less than greater than query. As for the efficiency, I can't speak to it.
Note, the accuracy of the lat/long offset for ~1 mile should be reviewed, but here is a quick way to do this:
SWIFT 3.0 Version
func getDocumentNearBy(latitude: Double, longitude: Double, distance: Double) {
// ~1 mile of lat and lon in degrees
let lat = 0.0144927536231884
let lon = 0.0181818181818182
let lowerLat = latitude - (lat * distance)
let lowerLon = longitude - (lon * distance)
let greaterLat = latitude + (lat * distance)
let greaterLon = longitude + (lon * distance)
let lesserGeopoint = GeoPoint(latitude: lowerLat, longitude: lowerLon)
let greaterGeopoint = GeoPoint(latitude: greaterLat, longitude: greaterLon)
let docRef = Firestore.firestore().collection("locations")
let query = docRef.whereField("location", isGreaterThan: lesserGeopoint).whereField("location", isLessThan: greaterGeopoint)
query.getDocuments { snapshot, error in
if let error = error {
print("Error getting documents: \(error)")
} else {
for document in snapshot!.documents {
print("\(document.documentID) => \(document.data())")
}
}
}
}
func run() {
// Get all locations within 10 miles of Google Headquarters
getDocumentNearBy(latitude: 37.422000, longitude: -122.084057, distance: 10)
}
UPDATE: Firestore does not support actual GeoPoint queries at present so while the below query executes successfully, it only filters by latitude, not by longitude and thus will return many results that are not nearby. The best solution would be to use geohashes. To learn how to do something similar yourself, have a look at this video.
(First let me apologize for all the code in this post, I just wanted anyone reading this answer to have an easy time reproducing the functionality.)
To address the same concern the OP had, at first I adapted the GeoFire library to work with Firestore (you can learn a lot about geo-stuff by looking at that library). Then I realized I didn't really mind if locations were returned in an exact circle. I just wanted some way to get 'nearby' locations.
I can't believe how long it took me to realize this, but you can just perform a double inequality query on a GeoPoint field using a SW corner and NE corner to get locations within a bounding box around a center point.
So I made a JavaScript function like the one below (this is basically a JS version of Ryan Lee's answer).
/**
* Get locations within a bounding box defined by a center point and distance from from the center point to the side of the box;
*
* #param {Object} area an object that represents the bounding box
* around a point in which locations should be retrieved
* #param {Object} area.center an object containing the latitude and
* longitude of the center point of the bounding box
* #param {number} area.center.latitude the latitude of the center point
* #param {number} area.center.longitude the longitude of the center point
* #param {number} area.radius (in kilometers) the radius of a circle
* that is inscribed in the bounding box;
* This could also be described as half of the bounding box's side length.
* #return {Promise} a Promise that fulfills with an array of all the
* retrieved locations
*/
function getLocations(area) {
// calculate the SW and NE corners of the bounding box to query for
const box = utils.boundingBoxCoordinates(area.center, area.radius);
// construct the GeoPoints
const lesserGeopoint = new GeoPoint(box.swCorner.latitude, box.swCorner.longitude);
const greaterGeopoint = new GeoPoint(box.neCorner.latitude, box.neCorner.longitude);
// construct the Firestore query
let query = firebase.firestore().collection('myCollection').where('location', '>', lesserGeopoint).where('location', '<', greaterGeopoint);
// return a Promise that fulfills with the locations
return query.get()
.then((snapshot) => {
const allLocs = []; // used to hold all the loc data
snapshot.forEach((loc) => {
// get the data
const data = loc.data();
// calculate a distance from the center
data.distanceFromCenter = utils.distance(area.center, data.location);
// add to the array
allLocs.push(data);
});
return allLocs;
})
.catch((err) => {
return new Error('Error while retrieving events');
});
}
The function above also adds a .distanceFromCenter property to each piece of location data that's returned so that you could get the circle-like behavior by just checking if that distance is within the range you want.
I use two util functions in the function above so here's the code for those as well. (All of the util functions below are actually adapted from the GeoFire library.)
distance():
/**
* Calculates the distance, in kilometers, between two locations, via the
* Haversine formula. Note that this is approximate due to the fact that
* the Earth's radius varies between 6356.752 km and 6378.137 km.
*
* #param {Object} location1 The first location given as .latitude and .longitude
* #param {Object} location2 The second location given as .latitude and .longitude
* #return {number} The distance, in kilometers, between the inputted locations.
*/
distance(location1, location2) {
const radius = 6371; // Earth's radius in kilometers
const latDelta = degreesToRadians(location2.latitude - location1.latitude);
const lonDelta = degreesToRadians(location2.longitude - location1.longitude);
const a = (Math.sin(latDelta / 2) * Math.sin(latDelta / 2)) +
(Math.cos(degreesToRadians(location1.latitude)) * Math.cos(degreesToRadians(location2.latitude)) *
Math.sin(lonDelta / 2) * Math.sin(lonDelta / 2));
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return radius * c;
}
boundingBoxCoordinates(): (There are more utils used in here as well that I've pasted below.)
/**
* Calculates the SW and NE corners of a bounding box around a center point for a given radius;
*
* #param {Object} center The center given as .latitude and .longitude
* #param {number} radius The radius of the box (in kilometers)
* #return {Object} The SW and NE corners given as .swCorner and .neCorner
*/
boundingBoxCoordinates(center, radius) {
const KM_PER_DEGREE_LATITUDE = 110.574;
const latDegrees = radius / KM_PER_DEGREE_LATITUDE;
const latitudeNorth = Math.min(90, center.latitude + latDegrees);
const latitudeSouth = Math.max(-90, center.latitude - latDegrees);
// calculate longitude based on current latitude
const longDegsNorth = metersToLongitudeDegrees(radius, latitudeNorth);
const longDegsSouth = metersToLongitudeDegrees(radius, latitudeSouth);
const longDegs = Math.max(longDegsNorth, longDegsSouth);
return {
swCorner: { // bottom-left (SW corner)
latitude: latitudeSouth,
longitude: wrapLongitude(center.longitude - longDegs),
},
neCorner: { // top-right (NE corner)
latitude: latitudeNorth,
longitude: wrapLongitude(center.longitude + longDegs),
},
};
}
metersToLongitudeDegrees():
/**
* Calculates the number of degrees a given distance is at a given latitude.
*
* #param {number} distance The distance to convert.
* #param {number} latitude The latitude at which to calculate.
* #return {number} The number of degrees the distance corresponds to.
*/
function metersToLongitudeDegrees(distance, latitude) {
const EARTH_EQ_RADIUS = 6378137.0;
// this is a super, fancy magic number that the GeoFire lib can explain (maybe)
const E2 = 0.00669447819799;
const EPSILON = 1e-12;
const radians = degreesToRadians(latitude);
const num = Math.cos(radians) * EARTH_EQ_RADIUS * Math.PI / 180;
const denom = 1 / Math.sqrt(1 - E2 * Math.sin(radians) * Math.sin(radians));
const deltaDeg = num * denom;
if (deltaDeg < EPSILON) {
return distance > 0 ? 360 : 0;
}
// else
return Math.min(360, distance / deltaDeg);
}
wrapLongitude():
/**
* Wraps the longitude to [-180,180].
*
* #param {number} longitude The longitude to wrap.
* #return {number} longitude The resulting longitude.
*/
function wrapLongitude(longitude) {
if (longitude <= 180 && longitude >= -180) {
return longitude;
}
const adjusted = longitude + 180;
if (adjusted > 0) {
return (adjusted % 360) - 180;
}
// else
return 180 - (-adjusted % 360);
}
A new project has been introduced since #monkeybonkey first ask this question. The project is called GEOFirestore.
With this library you can perform queries like query documents within a circle:
const geoQuery = geoFirestore.query({
center: new firebase.firestore.GeoPoint(10.38, 2.41),
radius: 10.5
});
You can install GeoFirestore via npm. You will have to install Firebase separately (because it is a peer dependency to GeoFirestore):
$ npm install geofirestore firebase --save
As of today, there is no way to do such a query. There are other questions in SO related to it:
Is there a way to use GeoFire with Firestore?
How to query closest GeoPoints in a collection in Firebase Cloud Firestore?
Is there a way to use GeoFire with Firestore?
In my current Android project I may use https://github.com/drfonfon/android-geohash to add a geohash field while Firebase team is developing native support.
Using Firebase Realtime Database like suggested in other questions means that you can't filter your results set by location and other fields simultaneously, the main reason I want to switch to Firestore in the first place.
As of late 2020 there is now also documentation of how to do geoqueries with Firestore.
These solutions for iOS, Android, and Web, build on top of a slimmed down version of the Firebase-created GeoFire libraries, and then show how to:
Generate geohash values and store them in Firestore
Determine geohash ranges of the bounding box for a certain point and radius
Perform queries across these geohash ranges
This a bit more low-level than most of the other libraries presented here, so it may be a better fit for some use-cases and a worse fit for others.
Hijacking this thread to hopefully help anyone still looking. Firestore still does not support geo-based queries, and using the GeoFirestore library isnt ideal either as it will only let you search by location, nothing else.
I've put this together:
https://github.com/mbramwell1/GeoFire-Android
It basically lets you do nearby searches using a location and distance:
QueryLocation queryLocation = QueryLocation.fromDegrees(latitude, longitude);
Distance searchDistance = new Distance(1.0, DistanceUnit.KILOMETERS);
geoFire.query()
.whereNearTo(queryLocation, distance)
.build()
.get();
There are more docs on the repo. Its working for me so give it a try, hopefully it will do what you need.
For Dart
///
/// Checks if these coordinates are valid geo coordinates.
/// [latitude] The latitude must be in the range [-90, 90]
/// [longitude] The longitude must be in the range [-180, 180]
/// returns [true] if these are valid geo coordinates
///
bool coordinatesValid(double latitude, double longitude) {
return (latitude >= -90 && latitude <= 90 && longitude >= -180 && longitude <= 180);
}
///
/// Checks if the coordinates of a GeopPoint are valid geo coordinates.
/// [latitude] The latitude must be in the range [-90, 90]
/// [longitude] The longitude must be in the range [-180, 180]
/// returns [true] if these are valid geo coordinates
///
bool geoPointValid(GeoPoint point) {
return (point.latitude >= -90 &&
point.latitude <= 90 &&
point.longitude >= -180 &&
point.longitude <= 180);
}
///
/// Wraps the longitude to [-180,180].
///
/// [longitude] The longitude to wrap.
/// returns The resulting longitude.
///
double wrapLongitude(double longitude) {
if (longitude <= 180 && longitude >= -180) {
return longitude;
}
final adjusted = longitude + 180;
if (adjusted > 0) {
return (adjusted % 360) - 180;
}
// else
return 180 - (-adjusted % 360);
}
double degreesToRadians(double degrees) {
return (degrees * math.pi) / 180;
}
///
///Calculates the number of degrees a given distance is at a given latitude.
/// [distance] The distance to convert.
/// [latitude] The latitude at which to calculate.
/// returns the number of degrees the distance corresponds to.
double kilometersToLongitudeDegrees(double distance, double latitude) {
const EARTH_EQ_RADIUS = 6378137.0;
// this is a super, fancy magic number that the GeoFire lib can explain (maybe)
const E2 = 0.00669447819799;
const EPSILON = 1e-12;
final radians = degreesToRadians(latitude);
final numerator = math.cos(radians) * EARTH_EQ_RADIUS * math.pi / 180;
final denom = 1 / math.sqrt(1 - E2 * math.sin(radians) * math.sin(radians));
final deltaDeg = numerator * denom;
if (deltaDeg < EPSILON) {
return distance > 0 ? 360.0 : 0.0;
}
// else
return math.min(360.0, distance / deltaDeg);
}
///
/// Defines the boundingbox for the query based
/// on its south-west and north-east corners
class GeoBoundingBox {
final GeoPoint swCorner;
final GeoPoint neCorner;
GeoBoundingBox({this.swCorner, this.neCorner});
}
///
/// Defines the search area by a circle [center] / [radiusInKilometers]
/// Based on the limitations of FireStore we can only search in rectangles
/// which means that from this definition a final search square is calculated
/// that contains the circle
class Area {
final GeoPoint center;
final double radiusInKilometers;
Area(this.center, this.radiusInKilometers):
assert(geoPointValid(center)), assert(radiusInKilometers >= 0);
factory Area.inMeters(GeoPoint gp, int radiusInMeters) {
return new Area(gp, radiusInMeters / 1000.0);
}
factory Area.inMiles(GeoPoint gp, int radiusMiles) {
return new Area(gp, radiusMiles * 1.60934);
}
/// returns the distance in km of [point] to center
double distanceToCenter(GeoPoint point) {
return distanceInKilometers(center, point);
}
}
///
///Calculates the SW and NE corners of a bounding box around a center point for a given radius;
/// [area] with the center given as .latitude and .longitude
/// and the radius of the box (in kilometers)
GeoBoundingBox boundingBoxCoordinates(Area area) {
const KM_PER_DEGREE_LATITUDE = 110.574;
final latDegrees = area.radiusInKilometers / KM_PER_DEGREE_LATITUDE;
final latitudeNorth = math.min(90.0, area.center.latitude + latDegrees);
final latitudeSouth = math.max(-90.0, area.center.latitude - latDegrees);
// calculate longitude based on current latitude
final longDegsNorth = kilometersToLongitudeDegrees(area.radiusInKilometers, latitudeNorth);
final longDegsSouth = kilometersToLongitudeDegrees(area.radiusInKilometers, latitudeSouth);
final longDegs = math.max(longDegsNorth, longDegsSouth);
return new GeoBoundingBox(
swCorner: new GeoPoint(latitudeSouth, wrapLongitude(area.center.longitude - longDegs)),
neCorner: new GeoPoint(latitudeNorth, wrapLongitude(area.center.longitude + longDegs)));
}
///
/// Calculates the distance, in kilometers, between two locations, via the
/// Haversine formula. Note that this is approximate due to the fact that
/// the Earth's radius varies between 6356.752 km and 6378.137 km.
/// [location1] The first location given
/// [location2] The second location given
/// sreturn the distance, in kilometers, between the two locations.
///
double distanceInKilometers(GeoPoint location1, GeoPoint location2) {
const radius = 6371; // Earth's radius in kilometers
final latDelta = degreesToRadians(location2.latitude - location1.latitude);
final lonDelta = degreesToRadians(location2.longitude - location1.longitude);
final a = (math.sin(latDelta / 2) * math.sin(latDelta / 2)) +
(math.cos(degreesToRadians(location1.latitude)) *
math.cos(degreesToRadians(location2.latitude)) *
math.sin(lonDelta / 2) *
math.sin(lonDelta / 2));
final c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
return radius * c;
}
I just published a Flutter package based on the JS code above
https://pub.dartlang.org/packages/firestore_helpers
Yes, this is an old topic, but I want to help only on Java code. How I solved a problem with longitude? I used a code from Ryan Lee and Michael Teper.
A code:
#Override
public void getUsersForTwentyMiles() {
FirebaseFirestore db = FirebaseFirestore.getInstance();
double latitude = 33.0076665;
double longitude = 35.1011336;
int distance = 20; //20 milles
GeoPoint lg = new GeoPoint(latitude, longitude);
// ~1 mile of lat and lon in degrees
double lat = 0.0144927536231884;
double lon = 0.0181818181818182;
final double lowerLat = latitude - (lat * distance);
final double lowerLon = longitude - (lon * distance);
double greaterLat = latitude + (lat * distance);
final double greaterLon = longitude + (lon * distance);
final GeoPoint lesserGeopoint = new GeoPoint(lowerLat, lowerLon);
final GeoPoint greaterGeopoint = new GeoPoint(greaterLat, greaterLon);
Log.d(LOG_TAG, "local general lovation " + lg);
Log.d(LOG_TAG, "local lesserGeopoint " + lesserGeopoint);
Log.d(LOG_TAG, "local greaterGeopoint " + greaterGeopoint);
//get users for twenty miles by only a latitude
db.collection("users")
.whereGreaterThan("location", lesserGeopoint)
.whereLessThan("location", greaterGeopoint)
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
UserData user = document.toObject(UserData.class);
//here a longitude condition (myLocation - 20 <= myLocation <= myLocation +20)
if (lowerLon <= user.getUserGeoPoint().getLongitude() && user.getUserGeoPoint().getLongitude() <= greaterLon) {
Log.d(LOG_TAG, "location: " + document.getId());
}
}
} else {
Log.d(LOG_TAG, "Error getting documents: ", task.getException());
}
}
});
}
Just inside after issuing the result set the filter to longitude:
if (lowerLon <= user.getUserGeoPoint().getLongitude() && user.getUserGeoPoint().getLongitude() <= greaterLon) {
Log.d(LOG_TAG, "location: " + document.getId());
}
I hope this will help someone.
Have a nice day!
You should use GeoFire (works with Firestore). With this you can filter documents on server and read less documents from your Firestore db. This will reduce your read count as well.
Check this lib for GroFire: https://github.com/patpatchpatrick/GeoFirestore-iOS
"patpatchpatrick" made this to Swift 5 compatible.
Just do a pod install as follows:
pod 'Geofirestore', :git => 'https://github.com/patpatchpatrick/GeoFirestore-iOS'
I am using this library in one of my projects and it works fine.
To set a location:
let location: CLLocation = CLLocation(latitude: lat, longitude: lng)
yourCollection.setLocation(location: location, forDocumentWithID: "YourDocId") { (error) in }
To remove location:
collection.removeLocation(forDocumentWithID: "YourDocId")
To get docs:
let center = CLLocation(latitude: lat, longitude: lng)
let collection = "Your collection path"
let circleQuery = collection.query(withCenter: center, radius: Double(yourRadiusVal))
let _ = circleQuery.observe(.documentEntered, with: { (key, location) in
//Use info as per your need
})
I have used .documentEntered, you can use other available geo queries like (Document Exited, Document Moved) as per your need.
You can query using GeoPoint as well.
This is not fully tested yet it should be a bit of an improvement on Ryan Lee's answer
My calculation is more accurate and then I filter the answers to remove hits which fall within the bounding box but outside the radius
Swift 4
func getDocumentNearBy(latitude: Double, longitude: Double, meters: Double) {
let myGeopoint = GeoPoint(latitude:latitude, longitude:longitude )
let r_earth : Double = 6378137 // Radius of earth in Meters
// 1 degree lat in m
let kLat = (2 * Double.pi / 360) * r_earth
let kLon = (2 * Double.pi / 360) * r_earth * __cospi(latitude/180.0)
let deltaLat = meters / kLat
let deltaLon = meters / kLon
let swGeopoint = GeoPoint(latitude: latitude - deltaLat, longitude: longitude - deltaLon)
let neGeopoint = GeoPoint(latitude: latitude + deltaLat, longitude: longitude + deltaLon)
let docRef : CollectionReference = appDelegate.db.collection("restos")
let query = docRef.whereField("location", isGreaterThan: swGeopoint).whereField("location", isLessThan: neGeopoint)
query.getDocuments { snapshot, error in
guard let snapshot = snapshot else {
print("Error fetching snapshot results: \(error!)")
return
}
self.documents = snapshot.documents.filter { (document) in
if let location = document.get("location") as? GeoPoint {
let myDistance = self.distanceBetween(geoPoint1:myGeopoint,geoPoint2:location)
print("myDistance:\(myDistance) distance:\(meters)")
return myDistance <= meters
}
return false
}
}
}
Functions which accurately measure the distance in Meters between 2 Geopoints for filtering
func distanceBetween(geoPoint1:GeoPoint, geoPoint2:GeoPoint) -> Double{
return distanceBetween(lat1: geoPoint1.latitude,
lon1: geoPoint1.longitude,
lat2: geoPoint2.latitude,
lon2: geoPoint2.longitude)
}
func distanceBetween(lat1:Double, lon1:Double, lat2:Double, lon2:Double) -> Double{ // generally used geo measurement function
let R : Double = 6378.137; // Radius of earth in KM
let dLat = lat2 * Double.pi / 180 - lat1 * Double.pi / 180;
let dLon = lon2 * Double.pi / 180 - lon1 * Double.pi / 180;
let a = sin(dLat/2) * sin(dLat/2) +
cos(lat1 * Double.pi / 180) * cos(lat2 * Double.pi / 180) *
sin(dLon/2) * sin(dLon/2);
let c = 2 * atan2(sqrt(a), sqrt(1-a));
let d = R * c;
return d * 1000; // meters
}
The easiest way is to calculate a "geo hash" when storing the location in the database.
A geo hash is a string which represents a location down to a certain accuracy. The longer the geo hash, the closer the locations with said geo hash must be. Two location which are e.g. 100m apart may have the same 6-char geo hash but when calculating a 7-char geo hash the last char might be different.
There are plenty libraries allowing you to calculate geo hashes for any language. Just store it alongside the location and use a == query to find locations with the same geo hash.
In javascript you can simply
const db = firebase.firestore();
//Geofire
import { GeoCollectionReference, GeoFirestore, GeoQuery, GeoQuerySnapshot } from 'geofirestore';
// Create a GeoFirestore reference
const geofirestore: GeoFirestore = new GeoFirestore(db);
// Create a GeoCollection reference
const geocollection: GeoCollectionReference = geofirestore.collection('<Your_collection_name>');
const query: GeoQuery = geocollectionDrivers.near({
center: new firebase.firestore.GeoPoint(location.latitude, location.longitude),
radius: 10000
});
query.onSnapshot(gquerySnapshot => {
gquerySnapshot.forEach(res => {
console.log(res.data());
})
});
A workaround for Flutter till we have native query in Firestore to pull ordered documents based on lat/long:
https://pub.dev/packages/geoflutterfire
A plugin to store geo hashes in the Firestore and query the same.
Limitations: limit not supported
There's a GeoFire library for Firestore called Geofirestore: https://github.com/imperiumlabs/GeoFirestore (Disclaimer: I helped develop it). It's super easy to use and offers the same features for Firestore that Geofire does for Firebase Realtime DB)

how to get distance of 2 beacons and make a condtion base on that distance

I'm trying to know what floor I'm at by getting the distance of 2 beacons with the same id1,1d2 and the id3 is 1 for beacon 1 and 2 for beacon 2...but my code does not work :( ... Im not that good in programming and I dont know how to use most of the functions or methods of altbeacon .... can someone help me how to get distance of beacons and make a condtion base on that distances of 2 beacons .... Is there a sample codes in doing this?
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if((beacon.getId3().equals(Identifier.parse("1")) && beacon.getDistance() < 0.5) && (beacon.getDistance() > 5 && beacon.getId3().equals(Identifier.parse("2"))
logToDisplay("1st floor");
}
}
this is the math for distance
var R = 6371; // km
var φ1 = toRad(lat1);
var φ2 = toRad(lat2);
var Δφ = toRad((lat2-lat1));
var Δλ = toRad((lon2-lon1));
var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
// printing distance to 2 decimal points in KM
$("#distance").append(d.toFixed(2) + " Km")
you will need to get the distance of the two beacons, save them to a variable and then write something like this
var beacon1 = foo
var beacon2 = baa
if ( beacon1 - beacon2 <= 0.5 ) {
do something
} else {
do something else
}

Android How to calclulate the movement speed without the getSpeed()

As we all know GPS system is far from perfect and when you go around with your app using the gps when the GPS loses the signal and it starts calculating again. And if you try to calculate the distance correctly it will start calculating and for example if you were 30 meters away from your destination it will calculate for example 130 meters. Which messes my how calculation of the distance up. So I found some suggestion that I should filter the GPS coordination using the speed.
I want to calculate the speed without the location.getSpeed() I want to calculate the speed by comparing the distance from the last known coordinates to the coordinates at some given point and I get the speed of the device moving. And if the speed is for example greater than 15 m/h coordinates are invalid and don't re-calculate the distance.
It is as simple as V = (Distance) / (Elapsed time).
So lets say you read your location1 at time X.
Than at some point after X lets say at time Y you read your location again.
Than you'll have
float distance = location1.distanceTo(location2);
which is float in meters (see this http://developer.android.com/reference/android/location/Location.html#distanceTo(android.location.Location)
To have your velocity as in meters per seconds if you calculate X - Y as
float X = System.currentTimeMillis(); //When you get the first location
float Y = System.currentTimeMillis(); //When you get the second location
//...
//Than when calculating
float timeElapsed= (Y - X)/1000; //In seconds
Than the velocity in meters per second will be
float V = distance/timeElapsed;
If you want to calculate average velocity, you need to store the velocities in a list lets say, and than calculate average from all those velocities calculated between each two points. So if you have location l1, l2, l3, l4 ..... ln, V1 will be velocity between l1 and l2, V2 will be between l2 and l3, and Vn-1 will be between ln-1 and ln. You will store all Vn in a list (for example) than you caluclate the average as
Vavg = (V1 + V2 + V3 ... + Vn)/n
UPDATE:
In your activity
Location previousLocation = null;
float previousTime = 0;
float velocity = 0;
Than:
public void onLocationChanged(Location loc) {
boolean hasPrevious = true;
if (previousLocation == null || previousTime == 0) {
hasPrevious = false;
}
float currentTime = System.currentTimeMillis();
if (hasPrevious) {
float timeElapsed = (currentTime - previousTime)/1000;
velocity = loc.distanceTo(previousLocation)/timeElapsed;
}
storeToPrevious(loc, currentTime);
}
In a different function
private void storeToPrevious(Location l, float time) {
previousLocation = new Location(l);
previousTime = time;
}
This may do what you want. It is written in Kotlin. It applies a weighted moving average. Most recent locations have a heavier weight. It can "smooth" out the speed, at the cost of adding more lag. This was to get around a bug in certain situations that I could not use getSpeed(). But normally if you use "Fused" location on Android, the speed is quite stable and accurate on a typical modern, ACTIVE phone.
var recentGPSLocationSegments = listOf<Pair<android.location.Location, android.location.Location>>()
fun applyWeightedMovingAverageSpeed(location: android.location.Location, previous: android.location.Location): Double
{
recentGPSLocationSegments += Pair(location, previous)
val cachedLocationsNs = location.elapsedRealtimeNanos - 4500000000 // 4.5 seconds, This will typically get 4 entries (1 second apart)
val targetZeroWeightNs = location.elapsedRealtimeNanos - 5000000000 // 5.0 seconds, Weights will be approx 5000000000, 4000000000, 3000000000, 1000000000
// Toss old locations
recentGPSLocationSegments = recentGPSLocationSegments.filter { it -> it.first.elapsedRealtimeNanos > cachedLocationsNs }
// Total up all the weights. Weight is based on age, younger has higher weight
val weights = recentGPSLocationSegments.map { it.first.elapsedRealtimeNanos - targetZeroWeightNs }.sum()
// Apply the weights and get average speed in meters/second
return recentGPSLocationSegments.map { speedFromGPS(it.first, it.second) * (it.first.elapsedRealtimeNanos - targetZeroWeightNs) }.sum() / weights
}
fun speedFromGPS(location: android.location.Location, previous: android.location.Location): Double
{
val dist = location.distanceTo(previous)
val time = (location.elapsedRealtimeNanos - previous.elapsedRealtimeNanos) / 1000000000.0
return dist / time
}
val locationManagerExample: LocationListener = object : LocationListener
{
var lastLocation: android.location.Location? = null
var lastPreviousLocation: android.location.Location? = null
override fun onLocationChanged(location: android.location.Location?)
{
if (location != null)
{
if (lastPreviousLocation != null)
{
currentSpeed = applyWeightedMovingAverageSpeed(location, lastPreviousLocation!!)
lastPreviousLocation = lastLocation
}
lastLocation = location
if (currentSpeed < 0.0)
{
currentSpeed = 0.0
}
}
}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle)
{
}
override fun onProviderEnabled(provider: String)
{
}
override fun onProviderDisabled(provider: String)
{
}
}

Categories

Resources