Categories
Berita PDSI

Geo Location Flutter: Aku Peta, Aku Peta

Geo Location atau posisi suatu titik di dalam permukaan bumi banyak digunakan pada aplikasi-aplikasi pada khusunya aplikasi berbasis mobile. Flutter memiliki plugin untuk menangani lokasi secara realtime dan dapat diatur untuk mengoptimalkan performa dan baterai.

Daftar Isi

Map Flutter

Flutter memudahkan pengembang dalam membuat aplikasi mobile yang menggunakan posisi berbasis GPS secara realtime hanya dengan beberapa baris kode saja.

— Geo Location Flutter: Aku Peta, Aku Peta
https://pdsi.unisayogya.ac.id/geo-location-flutter-aku-peta-aku-peta/ 2021-08-13 20:55:43

Konsep Lokasi Bumi (Geo Location)

Konsep lokasi di bumi berbeda dengan konsep lokasi di atas kertas. Bumi adalah bola 3D, sedangkan kertas adalah bangun datar 2D. Rumus yang melibatkan titik di atas kertas 2D berbeda dengan rumus yang melibatkan titik pada ruang bola 3D.

Sebagai contoh, rumus untuk menghitung jarak 2 titik di atas kertas adalah √(xb-xa)2+(yb-ya)2 , sedangkan rumus untuk menghitung jarak 2 titik pada permukaan bola 3D tidak sesederhana itu (baca: https://en.wikipedia.org/wiki/Haversine_formula).

Jarak dua titik pada permukaan bola 3D
Menentukan User di dalam atau di luar?

Untuk menentukan lokasi suatu titik [C]/[E] berada di dalam atau di dalam suatu batas (lingkaran), dibutuhkan informasi: titik pusat [A], jari-jari/radius batas (lingkaran) [AD] dan titik yang dicari itu sendiri [C]/[E].

Apabila jari-jari tidak diketahui, maka harus diketahui salah satu titik yang ditentukan sebagai batas [B]. Kemudian, jari-jari didapat dari jarak [AB].

Apabila jarak suatu titik dengan titik pusat [AC]/[AE] lebih kecil atau sama dengan dari jari-jari [AB]/[AD], maka titik tersebut berada di dalam suatu batas (lingkaran). Apabila jarak suatu titik dengan titik pusat [AC]/[AE] lebih besar dari jari-jari [AB]/[AD], maka titik tersebut berada di dalam suatu batas (lingkaran).

Kelas Lokasi di Bumi (GeoLocation)

//filename: ./library/geolocationpoint.dart
import 'package:geolocator/geolocator.dart';
import 'package:location/location.dart';

class GeoLocation{
  GeoPoint userlocation       = new GeoPoint.createZeroPoint();

  GeoPoint centerlocation     = new GeoPoint.createZeroPoint();
  GeoPoint outerlocation      = new GeoPoint.createNullPoint();
  double   radiuscentermeters = 0.0;
  bool     isInRange          = false;

  //constructor
  GeoLocation({required this.userlocation});

  GeoLocation.createZeroUserPoint()
  {
    this.userlocation = new GeoPoint.createZeroPoint();
  }

  GeoLocation.createUserPoint(double lat, double long)
  {
    setPointUser(lat, long);
  }

  GeoLocation.createUserPointLocationData(LocationData loc)
  {
    setPointUser(loc.latitude!, loc.longitude!);
  }

  GeoLocation.fromJson(Map<String, dynamic> json)
  {
    setPointUser(json['latitude'], json['longitude']);
  }

  //setter
  void setPointUserLocationData(LocationData loc)
  {
    setPointUser(loc.latitude!, loc.longitude!);
  }

  void setPointUser(double lat, double long)
  {
    userlocation.setPoint(lat, long);
    this._calculateRadiusMetersAndInRange();
  }

  void setPointOuterLocationData(LocationData loc)
  {
    setPointOuter(loc.latitude!, loc.longitude!);
  }

  void setPointOuter(double lat, double long)
  {
    outerlocation.setPoint(lat, long);
    this._calculateRadiusMetersAndInRange();
  }

  void setPointCenterLocationData(LocationData loc)
  {
    setPointCenter(loc.latitude!, loc.longitude!);
  }

  void setPointCenter(double lat, double long)
  {
    centerlocation.setPoint(lat, long);
    this._calculateRadiusMetersAndInRange();
  }

  set setRadius(double radiusmeters)
  {
    this.radiuscentermeters = radiusmeters;
    _calculateInRange();
  }

  //measure
  double distanceUserFromCenter()
  {
    return centerlocation.distanceWith(userlocation);
  }

  double distanceOuterFromCenter()
  {
    return centerlocation.distanceWith(outerlocation);
  }

  double distanceUserFromOuter()
  {
    double radius = this.distanceUserFromCenter() - this.distanceOuterFromCenter();
    return radius < 0 ? -radius : radius;
  }

  //calculation
  void _calculateRadiusMetersAndInRange()
  {
    if (this.radiuscentermeters == 0.0)
      this._calculateRadiusMeters();
    _calculateInRange();
  }

  void _calculateRadiusMeters()
  {
    if (this.outerlocation.latitude != null && this.outerlocation.longitude != null)
      this.radiuscentermeters = this.distanceOuterFromCenter();
  }

  void _calculateInRange()
  {
    this.isInRange = this.radiuscentermeters >= this.distanceUserFromCenter();
  }
}

class GeoPoint{
  double? latitude;
  double? longitude;

  GeoPoint({required this.latitude, required this.longitude});

  GeoPoint.createNullPoint()
  {
    this.latitude  = null;
    this.longitude = null;
  }

  GeoPoint.createZeroPoint()
  {
    this.latitude  = 0.0;
    this.longitude = 0.0;
  }

  void setPoint(double lat, double long)
  {
    this.latitude  = lat;
    this.longitude = long;
  }

  double distanceWith(GeoPoint otherpoint)
  {
    return GeolocatorPlatform.instance.distanceBetween(this.latitude!, this.longitude!, otherpoint.latitude!, otherpoint.longitude!);
  }


}

Konstanta

Konstanta ini dipakai untuk latitude dan longitude pada saat uji coba.

//filename: ./utils/const.dart
final double dummyCenterLatitude  = -7.8002;
final double dummyCenterLongitude = 110.3914;

Kelas Layanan Lokasi (LocationService)

Kelas ini akan memberikan informasi lokasi (latitude dan longitude) alat pengguna. Terdapat dua alternatif yang dapat digunakan. Pada uji coba ini digunakan alternatif 1.

//filename: ./service/location_service.dart
import 'dart:async';
import '../library/geolocationpoint.dart';
import 'package:location/location.dart';

class LocationService {

  //alternatif 1: dinamis, otomatis berubah ketika posisi berubah
  //inisialisasi memulai mengaktifkan service lokasi
  LocationService() {
    Location location = Location();
    location.requestPermission().then((granted) {
      if (granted == PermissionStatus.granted) {
        location.onLocationChanged.listen((dataLokasi) {
          _locationController.add(GeoLocation.createUserPointLocationData(dataLokasi));
        });
      }
    });
  }
  //update lokasi (lewat stream)
  StreamController<GeoLocation> _locationController =  StreamController<GeoLocation>();
  Stream<GeoLocation> get locationStream => _locationController.stream;

  //alternatif 2: statis, hanya menampilkan ketika getLocation dipanggil
  Future<GeoLocation?> getLocation() async {
    Location location = Location();
    GeoLocation? _currentLocation;
    try {
      var userLocation = await location.getLocation();
      _currentLocation = GeoLocation.createUserPointLocationData(userLocation);
    } on Exception catch (e) {
      print('Gagal ambil lokasi: ${e.toString()}');
    }
    return _currentLocation;
  }
}

Kelas Utama

//filename: ./main.dart
import './library/geolocationpoint.dart';
import './view/home_view.dart';

import 'package:akupeta/service/location_service.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamProvider<GeoLocation>(
      //data awal: titik (0, 0)
      initialData: GeoLocation.createZeroUserPoint(),
      //baca lokasi pada saat pertama kali
      create: (context) => LocationService().locationStream,
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: HomeView(),
      ),
    );
  }
}

Kelas Tampilan

Radius dan titik pusat dapat diganti dengan data yang diambil dari basis data atau melalui mekanisme lain.

//filename: ./view/home_view.dart
import '../library/geolocationpoint.dart';

import 'package:akupeta/utils/const.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class HomeView extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _HomeViewPageState();
  }
}

class _HomeViewPageState extends State<HomeView> {
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      body: _buildInputDataBody(context),
    );
  }

  Widget _buildInputDataBody(BuildContext context) {
    var userLocation = Provider.of<GeoLocation>(context);
    userLocation.radiuscentermeters = 1000; //100 meters
    userLocation.setPointCenter(dummyCenterLatitude, dummyCenterLongitude);
    return Container(
        color: Colors.white,
        padding: EdgeInsets.all(12.0),
        child: ListView(children: <Widget>[
          Text(
            'Lokasi',
            textScaleFactor: 1.2,
            style: TextStyle(
                fontWeight: FontWeight.w700, color: Colors.blueAccent),
          ),
          SizedBox(width: 15),
          Text(
              'Latitude \t\t\t\t: ${userLocation.userlocation.latitude} '
                  '\nLongitude \t: ${userLocation.userlocation.longitude}'
                  '\nIn Range? \t: ${userLocation.isInRange}',
              textScaleFactor: 1,
              style: TextStyle(color: Colors.blueAccent)),
        ]
        ))
    ;
  }
}

Pelatihan Mobile Programming with Flutter hari keempat (13/8/2021) sebagai bagian dari penggunaan dana hibah PKKM tahun anggaran 2021 dengan mentor Faizal Rahman (https://pdsi.unisayogya.ac.id/unisa-yogyakarta-menerima-bantuan-pemerintah-pkkm-tahun-anggaran-2021/) [bst]

By basit

Biro Pengembangan Teknologi Dan Sistem Informasi

One reply on “Geo Location Flutter: Aku Peta, Aku Peta”

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.