自动计算与存储在Firebase Firestore Flutter中的地理坐标数据的距离 [英] Auto Calculate Distance from Geo Coordiates data stored in Firebase Firestore Flutter

查看:81
本文介绍了自动计算与存储在Firebase Firestore Flutter中的地理坐标数据的距离的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已在Firestore数据库中存储了项目的纬度和经度(字段为:item_latitude和item_longitude).因此,所有项目都具有经度和纬度.我可以使用流来获取项目,例如:

I have stored latitude and longitude for items in firestore database (the fields are: item_latitude and item_longitude). Therefore, all items have latitude and longitude. I can use a stream to get the items for example:

  Stream<QuerySnapshot> getItems() async* {
   yield* FirebaseFirestore.instance.collection("items").snapshots();
  }

使用StreamBuilder或FutureBuilder,我可以获得项目的各个属性,例如纬度和经度. Geolocator有一种计算距离的方法,这也是一种未来:

Using a StreamBuilder or FutureBuilder, I can get the items individual properties such as the latitude and longitude. Geolocator has a method to calculate distance which is also a future:

double distance = await geolocator.distanceBetween(lat, long, lat1, long1);

我能够获取用户的当前位置,在这种情况下,它是lat1,long1(这是一条记录).问题是:Strem getItems获取经度和纬度流,对于每个项目,我需要参考当前位置计算其当前距离.这意味着,当我遍历GridView等项目时,我需要计算并显示距离. 我已经以抽象的方式编写了这个问题,以便答案将解决如何基于数据的同步流进行异步计算,从而使数据显示在页面的构建部分中,而计算则在外部进行,因为并非如此,构建将不会接受带有同步的异步计算. 我的尝试导致以下结果:第一次尝试:

I am able to get the users current location and in this case it is lat1, long1 (which is an individual record). The problem is: the Strem getItems gets a stream of latitudes and longitudes and for each item, I need to calculate its current distance in reference to the current location. This means, as I iterate through the items for example in a GridView, I need to calculate and display the distance. I have written this question in an abstract manner so that the answer will address how to do an asynchronous calculation based on a sychronous stream of data such that while the data is displayed in the build section of the page, the calculations are done outside because as it is not, the build will not accept an asychronous calculation with synchronous. My attempts have led to the following: First Attempt:

child: StreamBuilder(
       stream: FetchItems().getItems(),
       builder: (context, snapshot) {
         if (!snapshot.hasData) {
            return Text("KE");
         }
         if (snapshot.hasData) {
         DocumentSnapshot data = snapshot.data.docs[index];
         double lat = data.data()[Str.ITEM_LATITUDE];
         double long = data.data()[Str.ITEM_LATITUDE];
         return 
         Text(getDistance(usersCurrentLocationLat,usersCurrentLocationLong,lat,long).toString());
       //This fails and returns on the Text place holder the following: Instance of 'Future<dynamic>'
     }
    }),

我的第二次尝试如下:

child: StreamBuilder(
       stream: FetchItems().getItems(),
       builder: (context, snapshot) {
         if (!snapshot.hasData) {
            return Text("KE");
         }
         if (snapshot.hasData) {
         DocumentSnapshot data = snapshot.data.docs[index];
         double lat = data.data()[Str.ITEM_LATITUDE];
         double long = data.data()[Str.ITEM_LATITUDE];
         double x = getDistance(usersCurrentLocationLat,usersCurrentLocationLong,lat,long);
         return Text(x.toString());
       //This fails and gives erro: type 'Future<dynamic>' is not a subtype of type 'double'
     }
    }),

进一步的调查显示,以下用于获取当前位置并在iniState中引用的方法的确获取了值(假设Gps已启用为偏离路线):

Further investigation shows that the below method which is used to get current location and is also referenced in the iniState does actually get the values (assuming Gps is enabled offcourse):

  _getUserCurrentLocation() {
final Geolocator geolocator = Geolocator()..forceAndroidLocationManager;

geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.best).then(
  (Position position) {
    setState(
      () {
        _currentPosition = position;
        usersCurrentLocationLat = _currentPosition.latitude;
        usersCurrentLocationLong = _currentPosition.longitude;
     //a system print here returns current location as 0.3714267 32.6134379 (same for the 
     //StreamBuilder)
      },
    );
  },
).catchError((e) {
  print(e);
 });
}

下面是计算距离的方法-使用提供的Geolocator distanceBetween()方法.

Below is the method for calculcating distance - using the provided Geolocator distanceBetween() method.

  getDistance(double lat, double long, double lat1, double long1) async {
    return distance = await geolocator.distanceBetween(lat, long, lat1, long1);
  }

  @override
  void initState() {
  super.initState();
  _getUserCurrentLocation();
  }

我将如何遍历获得其经度和纬度的项目,计算距离并将其显示在文本上?这是一个普遍的问题,可能的解决方案组合将非常受欢迎.请注意,在StreamBuilder中,实际上可以使用以下命令打印每个控制台的坐标:

How will I be able to iterate through the items getting their latitude and longitudes, calculate the distance and display it on the text? This is a general question, possible solution combinations will be very welcome. Note in the StreamBuilder, am actually able to print to console the coordinates for each using the below:

print("FROM CURRENT LOCATION HERE ----" + usersCurrentLocationLat.toString() +"::::::::" +
      usersCurrentLocationLong.toString());
print("FROM STREAM FROM DB SURE ----" + lat.toString() +"::::::::" + long.toString());

在控制台中将数据库中的所有项目打印为(一个示例):

Which prints in console for all the items in the db as (one example):

I/flutter (30351): FROM CURRENT LOCATION HERE ----0.3732317::::::::32.6128083
I/flutter (30351): FROM STREAM FROM DB SURE ----2.12323::::::::2.12323

证明坐标是实际得到的. 主要错误:类型'Future'不是类型'double'的子类型,并且用于显示距离的文本被拉伸为红色.指导是否可以采用最佳方法-将来也可能对某人有所帮助.

Proving that the coordinates are actuall got. The main error: type 'Future' is not a subtype of type 'double' remains and the Text to display the distance is stretched red. Guide if one can on the best approach - it may help someone in the future too.

推荐答案

我的方法如下:

以以下方式查询整个文档:

Query the whole documents in the following manner:

//This a synchronus operation    
final data = await Firestore.instance
            .collection('collection_name')
            .getDocuments();

然后将所有文档传递到列表中: 由于DocumentSnapshotList<dynamic>

Then pass all the documents into a list: Since DocumentSnapshot is a List<dynamic>

List doc = data.documents;

现在计算出firestore中每个LatLng与当前位置LatLng的距离,然后将其附加到一个空的list上,在迭代时,您可以在gridView中使用它:

now calculate the distance for each LatLng in your firestore with the current location LatLng and go on appending it to an empty list which on iteration you can use in a gridView:

List distanceList=[]; //define and empty list
doc.forEach((e){
double lat=e.data[ITEM_LATITUDE]; //asuming ITEM_LATITUDE is the field name in firestore doc.
double lng=e.data[ITEM_LONGITUDE];//asuming ITEM_LONGITUDE is the field name in firestore doc.
distanceList.add(your distance calculating function); //call this inside an async function if you are using await;
});

我没有使用异步gelocator.distance,而是在dart中使用"haversine"公式编写了一个函数以找到最短的函数:

Instead of using an Async gelocator.distance I have written a function in dart using the ‘haversine’ formula to find the shortest function:

double calculateDistance (double lat1,double lng1,double lat2,double lng2){
    double radEarth =6.3781*( pow(10.0,6.0));
    double phi1= lat1*(pi/180);
    double phi2 = lat2*(pi/180);
    
    double delta1=(lat2-lat1)*(pi/180);
    double delta2=(lng2-lng1)*(pi/180);
    
    double cal1 = sin(delta1/2)*sin(delta1/2)+(cos(phi1)*cos(phi2)*sin(delta2/2)*sin(delta2/2));
    
   double cal2= 2 * atan2((sqrt(cal1)), (sqrt(1-cal1)));
    double distance =radEarth*cal2;
    
    return (distance);
    
}

这是一个synchronous function,其代码将在firestore doc.forEach();列表函数中如下所示:

This a synchronous function and the code would be as follows inside the firestore doc.forEach(); list function:

List distanceList; //define and empty list
doc.forEach((e){
double lat=e.data[ITEM_LATITUDE]; //asuming ITEM_LATITUDE is the field name in firestore doc.
double lng=e.data[ITEM_LONGITUDE];//asuming ITEM_LONGITUDE is the field name in firestore doc.
double distance = calculateDistance(currentLat,currentLng, lat,lng);
distanceList.add(distance);
});
//Now the distanceList would contain all the shortest distance between 
// current LatLng and all the other LatLng in your firestore documents:

在再次用于存储距离之前,请先清空distanceList.

整个代码如下;

//Shortest Distance Function definition:
double calculateDistance (double lat1,double lng1,double lat2,double lng2){
double radEarth =6.3781*( pow(10.0,6.0));
double phi1= lat1*(pi/180);
double phi2 = lat2*(pi/180);
    
double delta1=(lat2-lat1)*(pi/180);
double delta2=(lng2-lng1)*(pi/180);
    
double cal1 = sin(delta1/2)*sin(delta1/2)+(cos(phi1)*cos(phi2)*sin(delta2/2)*sin(delta2/2));
    
double cal2= 2 * atan2((sqrt(cal1)), (sqrt(1-cal1)));
double distance =radEarth*cal2;
    
return (distance);
    
}

List distanceList; //list defination

// Call this function every time you want to calculate distance between currentLocation and all location in firestore.
void calculateDistanceAndStore(double currentLat, double currentLng) async{
distanceList=[];p;
final data = await Firestore.instance
            .collection('collection_name')
            .getDocuments();
doc.forEach((e){
double lat=e.data[ITEM_LATITUDE]; //asuming ITEM_LATITUDE is the field name in firestore doc.
double lng=e.data[ITEM_LONGITUDE];//asuming ITEM_LONGITUDE is the field name in firestore doc.
    double distance = calculateDistance(currentLat,currentLng, lat,lng);
    distanceList.add(distance);
    });
}

这篇关于自动计算与存储在Firebase Firestore Flutter中的地理坐标数据的距离的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆