Last updated:
0 purchases
geoengine
GeoEngine #
GeoEngine is a comprehensive Dart library designed for geospatial and geomatic calculations. It provides a wide range of functionalities including distance calculations, coordinate conversions, geocoding, polygon operations, geodetic network analysis, and much more. Whether you are a GIS professional, a geomatics engineer, or a developer working on geospatial applications, GeoEngine is the ultimate toolkit for all your geospatial needs.
Getting Started #
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
geoengine: any
copied to clipboard
Usage #
Here's a simple example to calculate the distance between two geographic coordinates:
import 'package:geoengine/geoengine.dart';
void main() {
var point1 = LatLng(37.7749, -122.4194);
var point2 = LatLng(34.0522, -118.2437);
var distance = Distance.haversine(point1, point2);
print('Distance between points is: ${distance.valueSI} meters');
}
copied to clipboard
Features #
Core Calculations
Distance and Bearings #
These are ported implementations of the java codes provided by Movable Type Scripts. This page presents a variety of calculations for latitude/longitude points, with the formulas and code fragments for implementing them.
Distance Calculation: Calculate the distance between two geographic coordinates using various algorithms like Haversine, Vincenty, and Great Circle.
var point1 = LatLng(dms2Degree(50, 03, 59), dms2Degree(-5, 42, 53));
var point2 = LatLng(dms2Degree(58, 38, 38), dms2Degree(-3, 04, 12));
print('Distance (Haversine): ${point1.distanceTo(point2, method: DistanceMethod.haversine)!.valueInUnits(LengthUnits.kilometers)} km');
print('Distance (Great Circle): ${point1.distanceTo(point2, method: DistanceMethod.greatCircle)!.valueInUnits(LengthUnits.kilometers)} km');
print('Distance (Vincenty): ${point1.distanceTo(point2, method: DistanceMethod.vincenty)!.valueInUnits(LengthUnits.kilometers)} km');
// Distance (Haversine): 968.8535467131387 km
// Distance (Great Circle): 968.8535467131394 km
// Distance (Vincenty): 969.9329875845247 km
copied to clipboard
Bearing Calculation: Calculate the initial and final bearing between two points on the Earth's surface.
var point1 = LatLng(dms2Degree(50, 03, 59), dms2Degree(-5, 42, 53));
var point2 = LatLng(dms2Degree(58, 38, 38), dms2Degree(-3, 04, 12));
print('Initial Bearing: ${point1.initialBearingTo(point2)}');
print('Final Bearing: ${point1.finalBearingTo(point2)}');
print('Mid Point: ${point1.midPointTo(point2)}');
// Initial Bearing: 9.119818104504077° or 0.15917085310658177 rad or 009° 07' 11.34518"
// Final Bearing: 11.275201271425715° or 0.19678938601142623 rad or 011° 16' 30.72458"
// Mid Point: 054° 21' 44.233" N, 004° 31' 50.421"
copied to clipboard
Destination Point: Given a start point, initial bearing, and distance, this will calculate the destination point and final bearing travelling along a (shortest distance) great circle arc.
var startPoint = LatLng(53.3206, -1.7297); // 53°19′14″N, 001°43′47″W
double bearing = 96.022222; // 096°01′18″
double distance = 124800; // 124.8 km
LatLng destinationPoint = startPoint.destinationPoint(distance, bearing);
var finalBearing = startPoint.finalBearingTo(destinationPoint);
print('Destination point: $destinationPoint');
print('Final bearing: $finalBearing');
// Destination point: 053° 11' 17.891" N, 000° 07' 59.875" E
// Final bearing: 97.51509150337512° or 1.7019594171174142 rad or 097° 30' 54.32941"
copied to clipboard
Interception: Intersection of two paths given start points and bearings
This is a rather more complex calculation than most others on this page, but I've been asked for it a number of times. This comes from Ed William’s aviation formulary.
var point1 = LatLng(51.8853, 0.2545);
var bearing1 = 108.55;
var point2 = LatLng(49.0034, 2.5735);
var bearing2 = 32.44;
var intercept = LatLng.intersectionPoint(point1, bearing1, point2, bearing2)!;
print('Interception Point: $intercept');
// Interception Point: 050° 54' 27.387" N, 004° 30' 30.869" E
copied to clipboard
Rhumb line: A ‘rhumb line’ (or loxodrome) is a path of constant bearing, which crosses all meridians at the same angle.
Sailors used to (and sometimes still) navigate along rhumb lines since it is easier to follow a constant compass bearing than to be continually adjusting the bearing, as is needed to follow a great circle. Rhumb lines are straight lines on a Mercator Projection map (also helpful for navigation).
var startPoint = LatLng(50.3667, -4.1340); // 50 21 59N, 004 08 02W
var endPoint = LatLng(42.3511, -71.0408); // 42 21 04N, 071 02 27W
var rhumbDist = startPoint.rhumbLineDistance(endPoint);
Bearing rhumbBearing = startPoint.rhumbLineBearing(endPoint);
LatLng rhumbMid = startPoint.rhumbMidpoint(endPoint);
print('Rhumb distance: ${rhumbDist.valueInUnits(LengthUnits.kilometers)} km');
print('Rhumb bearing: $rhumbBearing');
print('Rhumb midpoint: $rhumbMid');
// Rhumb distance: 5197.982109842136 km
// Rhumb bearing: Bearing: 256.66558069454646° or 4.479659459662955 rad or 256° 39' 56.09050"
// Rhumb midpoint: 047° 50' 9.060" N, 038° 13' 28.378" W
copied to clipboard
Given a start point and a distance d along constant bearing θ, this will calculate the destination point. If you maintain a constant bearing along a rhumb line, you will gradually spiral in towards one of the poles.
var sPt = LatLng(dms2Degree(51, 07, 32), dms2Degree(1, 20, 17));
var dist = 40230;
var bearing = dms2Degree(116, 38, 10);
print('Rhumb Destination: ${sPt.rhumbDestinationPoint(dist, bearing)}');
// Rhumb Destination: 050° 57' 48.074" N, 001° 51' 8.774" E
copied to clipboard
Geodesic Calculations: Find the shortest path between two points on the Earth's surface, taking into account the Earth's curvature which uses the Vincenty approach.
Coordinate Systems
Coordinate Systems #
Coordinate Conversion: Convert between different coordinate systems, such as latitude/longitude to UTM or MGRS.
Get the UTM zone number and letter
var u = UTMZones();
var uZone = u.getZone(latitude: 6.5655, longitude: -1.5646);
print(uZone); // 30P
print(u.getHemisphere(uZone)); // N
print(u.getLatZone(6.5655)); // P
copied to clipboard
Parse MGRS coordinates
print(MGRS.parse('31U DQ 48251 11932')); // 31U DQ 48251 11932
print(MGRS.parse('31UDQ4825111932')); // 31U DQ 48251 11932
copied to clipboard
Coordinate conversions
var ll = LatLng(6.5655, -1.5646);
print(ll.toMGRS());
print(ll.toUTM());
// 30N XN 58699 25944
// 30 N 658699.0 725944.0 0.0
print('');
var utm = UTM.fromMGRS(ll.toMGRS());
print(utm);
print(utm.toLatLng());
print(utm.toMGRS());
// 30 N 658699.0 725944.0 0.0
// 006° 33' 55.795" N, 001° 33' 52.586" W
// 30N XN 58699 25944
print('');
var mgrs = MGRS.parse(ll.toMGRS());
print(mgrs.toLatLng());
print(mgrs.toUTM());
print(mgrs);
// 006° 33' 55.795" N, 001° 33' 52.586" W
// 30 N 658699.0 725944.0
// 30N XN 58699 25944
copied to clipboard
Datum Transformations: Transform coordinates between different geodetic datums.
final LatLng pp = LatLng(6.65412, -1.54651, 200);
CoordinateConversion transCoordinate = CoordinateConversion();
Projection sourceProjection = Projection.get('EPSG:4326')!; // Geodetic
// Add a new CRS from WKT
Projection targetProjection = Projection.parse(
'PROJCS["Accra / Ghana National Grid",GEOGCS["Accra",DATUM["Accra",SPHEROID["War Office",6378300,296,AUTHORITY["EPSG","7029"]],TOWGS84[-199,32,322,0,0,0,0],AUTHORITY["EPSG","6168"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4168"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",4.666666666666667],PARAMETER["central_meridian",-1],PARAMETER["scale_factor",0.99975],PARAMETER["false_easting",900000],PARAMETER["false_northing",0],UNIT["Gold Coast foot",0.3047997101815088,AUTHORITY["EPSG","9094"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","2136"]]');
var res = transCoordinate.convert(
point: pp,
projSrc: sourceProjection,
projDst: targetProjection,
conversion: ConversionType.geodeticToGeodetic, // Geodetic to Geodetic conversion
);
print(pp);
// 006° 39' 14.832" N, 001° 32' 47.436" W, 200.000
print(res.asLatLng());
// 006° 39' 4.889" N, 001° 32' 48.303" W, 200.331
copied to clipboard
Map Projections: Support for various map projections and functions to transform coordinates between different projections.
final LatLng pp = LatLng(6.65412, -1.54651, 200);
CoordinateConversion transCoordinate = CoordinateConversion();
CoordinateType sourceCoordinateType = CoordinateType.geodetic;
CoordinateType targetCoordinateType = CoordinateType.projected;
// Get WGS84 Geographic Coordinate System
Projection sourceProjection = Projection.get('EPSG:4326')!;
// Get UTM CRS
Projection targetProjectionUTM =
transCoordinate.getUTMProjection(pp.longitude);
var res = transCoordinate.convert(
point: pp,
projSrc: sourceProjection,
projDst: targetProjectionUTM,
conversion: transCoordinate.getConversionType(
sourceCoordinateType, targetCoordinateType),
//conversion: ConversionType.geodeticToProjected,
);
print(pp);
// 006° 39' 14.832" N, 001° 32' 47.436" W, 200.000
print(res);
// Eastings: 660671.6505858237
// Northings: 735749.4963174305
// Height: 200.0
copied to clipboard
Julian Dates
Julian Date Functions #
The JulianDate class in GeoEngine provides an interface to work with Julian Dates, a continuous count of days since the beginning of the Julian Period on January 1, 4713 BCE. This system is widely used in astronomy and other fields. Here's how you can utilize some of the main functions of this class:
Initialization #
You can create a JulianDate object in different ways:
From a specific date: #
JulianDate date1 = JulianDate.fromDate(year: 2023, month: 8, day: 15);
copied to clipboard
Using a DateTime object: #
var date = DateTime(2023, 8, 15);
JulianDate originalDate = JulianDate(date);
copied to clipboard
Comparing Julian Dates #
You can compare two JulianDate objects using the common comparison operators:
JulianDate date2 = JulianDate.fromDate(year: 2023, month: 8, day: 20);
print(date1 == date2); // false
print(date1 < date2); // true
print(date1 <= date2); // true
print(date1 > date2); // false
print(date1 >= date2); // false
copied to clipboard
Conversion Functions #
To Julian Date: #
double jd = originalDate.toJulianDate();
print('Julian Date: $jd');
// Julian Date: 2460171.5
copied to clipboard
To Modified Julian Date: #
The Modified Julian Date (MJD) is calculated by subtracting 2,400,000.5 from the Julian Date. It's used for convenience and starts from November 17, 1858.
print('Modified Julian Date (1858/11/17): ${originalDate.toModifiedJulianDate()}');
// Modified Julian Date (1858/11/17): 60171.0
copied to clipboard
Referenced Julian Date: #
You can also get a referenced Julian Date by specifying a reference date:
print('Referenced Julian Date (1960/01/01): ${originalDate.toModifiedJulianDate(referenceDate: DateTime(1960, 1, 1))}');
// Referenced Julian Date (1960/01/01): 23237.0
copied to clipboard
Converting Back to DateTime #
If you have a Julian Date and wish to get the corresponding Gregorian date:
JulianDate convertedDate = JulianDate.fromJulianDate(jd);
print(convertedDate.dateTime);
// 2023-08-15 00:00:00.000
copied to clipboard
Example: #
To get the Modified Julian Date with a specific reference date:
print(JulianDate(DateTime(2023, 1, 1)).toModifiedJulianDate(referenceDate: DateTime(1960, 1, 11)));
// 23001.0
copied to clipboard
Remember, always refer to the documentation or source code for any additional functions or nuances with the JulianDate class in the GeoEngine library.
Least Squares Adjustment
Least Squares Adjustment #
The LeastSquaresAdjustment class in GeoEngine provides a robust way to perform least squares adjustments on geodetic and other types of data. This documentation breaks down the core components and usage of the class.
Overview #
Least squares adjustment is a statistical method to solve an overdetermined system of equations. In the context of GeoEngine, this class can handle various scaling methods, and can be utilized for various geodetic computations including network adjustments.
Initialization #
To initialize the LeastSquaresAdjustment class, you need to provide the design matrix A, the observation vector B, and an optional weight matrix W.
var lsa = LeastSquaresAdjustment(A: A, B: B);
copied to clipboard
Key Properties #
Here are some of the core properties of the class:
x: Unknown parameters.
v: Residuals.
uv: Unit variance.
N: The normal matrix.
qxx: Misclosure matrix
cx: Variance-Covariance of the Adjusted Heights
cv: Variance-Covariance of the Residuals
cl: Variance-Covariance of the Observations
standardDeviation: Standard deviation of the observations.
standardError: Standard error of the observations.
standardErrorsOfUnknowns: Standard errors of the unknowns.
standardErrorsOfResiduals: Standard errors of the residuals.
standardErrorsOfObservations: Standard errors of the observations.
chiSquared: Chi-squared value for the least squares adjustment.
rejectionCriterion: Rejection criterion for outlier detection, using the specified confidence level.
outliers: List of boolean values indicating whether each observation is an outlier (true) or not (false).
Methods #
Chi-Square Test #
To perform a Chi-Square goodness-of-fit test:
var chiSquareTest = lsa.chiSquareTest();
copied to clipboard
Covariance #
To compute the covariance matrix:
var covMatrix = lsa.covariance();
copied to clipboard
Error Ellipse #
Compute error ellipse parameters:
var eig = lsa.errorEllipse();
copied to clipboard
Outliers #
Automatically remove outliers:
var newLsa = lsa.removeOutliersIteratively();
print(newLsa);
copied to clipboard
Confidence Intervals #
Compute confidence intervals for the unknown parameters:
var lsa = LeastSquaresAdjustment(A: A, B: B);
var intervals = lsa.computeConfidenceIntervals();
print(intervals); // Output: [(lower1, upper1), (lower2, upper2), ...]
copied to clipboard
Custom Auto Scaling #
Automatically scales or normalizes the matrices based on custom functions:
var scaledLsa = lsa.customAutoScale(
matrixNormalizationFunction: (Matrix A) => A.normalize(),
columnNormalizationFunction: (ColumnMatrix B) => B.normalize(),
diagonalNormalizationFunction: (DiagonalMatrix W) => W.normalize()
);
copied to clipboard
Examples #
Here's an example to get you started:
var A = Matrix([
[-1, 0, 0, 0],
[-1, 1, 0, 0],
[0, -1, 1, 0],
[0, 0, -1, 0],
[0, 0, -1, 1],
[0, 0, 0, -1],
[1, 0, 0, -1],
]);
var W = DiagonalMatrix([1 / 16, 1 / 9, 1 / 49, 1 / 36, 1 / 16, 1 / 9, 1 / 25]);
var B = ColumnMatrix([0, 0, 0.13, 0, 0, -0.32, -0.53]);
var lsa = LeastSquaresAdjustment(A: A, B: B, W: W, confidenceLevel: 40);
var c = lsa.chiSquareTest();
print(c); // (chiSquared: 0.00340817748488164, degreesOfFreedom: 3)
print(lsa);
// Least Squares Adjustment Results:
// ---------------------------------
// Normal (N):
// Matrix: 4x4
// ┌ 0.2136111111111111 -0.1111111111111111 0.0 -0.04 ┐
// │ -0.1111111111111111 0.13151927437641722 -0.02040816326530612 0.0 │
// │ 0.0 -0.02040816326530612 0.1106859410430839 -0.0625 │
// └ -0.04 0.0 -0.0625 0.2136111111111111 ┘
//
// Unknown Parameters (x):
// Matrix: 4x1
// ┌ -0.06513489902716646 ┐
// │ -0.045703714070040764 │
// │ 0.1900882929187552 │
// └ 0.30911630747309227 ┘
//
// Residuals (v):
// Matrix: 7x1
// ┌ 0.06513489902716646 ┐
// │ 0.019431184957125695 │
// │ 0.10579200698879596 │
// │ -0.1900882929187552 │
// │ 0.11902801455433706 │
// │ 0.01088369252690774 │
// └ 0.1557487934997413 ┘
//
// Unit Variance (σ²): 0.0011360591616272134
//
// Standard Deviation (σ): 0.033705476730454556
//
// Chi-squared Test (Goodness-of-fit Test):
// Chi-squared value(χ²): 0.00340817748488164
// Degrees of Freedom: 3
//
// Standard Errors of Unknowns (Cx):
// [0.10509275934271714, 0.13339652325953671, 0.11787096037126248, 0.08536738678162376]
//
// Standard Errors of Residuals (Cv):
// [0.08445388398273435, 0.0340385190674456, 0.1853208260338704, 0.16433066214111094, 0.08042190803509813, 0.054193558000204894, 0.12767979681503475]
//
// Standard Errors of Observations (Cl):
// [0.10509275934271714, 0.09521508112867448, 0.14602428002855353, 0.11787096037126248, 0.10820934938363522, 0.08536738678162376, 0.1099970387144662]
//
// Rejection Criterion (Confidence Level 40.0): 0.01766173284889808
//
// Outliers (false = accepted, true = rejected):
// [false, true, false, false, true, false, false]
//
// Error Ellipse:
// [0.029441222484548304, 0.01187530402393495, 0.005032048784758579, 0.0036716992155236177]
//
// ---------------------------------
copied to clipboard
Levelling
Levelling #
This file describes the Levelling class, which represents a levelling survey. It allows you to define various parameters and perform calculations related to the survey. The class contains properties for the starting benchmark (TBM), closing TBM, accuracy, rounding digits, levelling method, etc. You can add measurements, compute reduced levels, get arithmetic checks, and print a summary of the results.
Initialization #
To initialize the Levelling class, you need to provide the accuracy accuracy, method method, starting TBM and an optional closing TBM.
var levelling = Levelling(
startingTBM: 100.0,
accuracy: 3,
roundDigits: 3,
method: LevellingMethod.riseFall,
);
copied to clipboard
Usage #
You can start with or with the closing TBM.
// Initialize with starting TBM
final startingTBM = 100.000;
// Initialize with closing TBM
final closingTBM = 98.050;
// Create a new instance of Levelling with starting TBM, closing TBM, accuracy, method, rounding digits
final leveling = Levelling(
startingTBM: startingTBM,
closingTBM: closingTBM,
accuracy: 5,
method: LevellingMethod.riseFall,
roundDigits: 3,
);
copied to clipboard
The can be in a form of List<List<Object?>> or list of LevellingMeasurement objects.
// Create the sample observation data
final data = [
['A', 1.751, null, null],
['B', null, 0.540, null],
['C', 0.300, null, 2.100],
['D', null, 1.100, null],
['E', null, 1.260, null],
['F', 1.500, null, 2.300],
['G', null, null, 1.110]
];
// Add the data to the levelling object
for (int i = 0; i < data.length; i++) {
final row = data[i];
levelling.addMeasurement(LevellingMeasurement(
bs: row[1], is_: row[2], fs: row[3], station: row[0]));
}
// or use this
for (var entry in data) {
leveling.addData(entry[0].toString(), entry[1], entry[2], entry[3]);
}
copied to clipboard
You can get the result as a data frame or as a list of maps.
leveling.computeReducedLevels();
print("Rise & Fall:");
print(leveling.getDataFrame());
// Calculate reduced levels using Rise & Fall algorithm
leveling.computeReducedLevels(LevellingMethod.hpc);
print("\n\nHPC:");
print(leveling.getDataFrame());
copied to clipboard
Once the data are added to the Levelling object, you can perform calculations. You can access all the results through the Levelling object.
You can access all the properties of the object.
print(leveling.numberSTN); // 3
print(leveling.allowableMisclose); // 5.196
print(leveling.misclose); // -0.009
print(leveling.correction); // 0.009
print(leveling.adjustmentPerStation); // 0.003
print(leveling.reducedLevels); // [100.0, 101.211, 99.651, 98.851, 98.691, 97.651, 98.041]
print(leveling.isWorkAccepted); // Work is not accepted
print(leveling.arithmeticCheckResult);
// Arithmetic Checks:
// Sum of BS = 3.551
// Sum of FS = 5.510
// First RL = 100.000
// Last RL = 98.041
// Sum of BS - Sum of FS = -1.959
// Last RL - First RL = -1.959
// Arithmetic Checks are OK.
copied to clipboard
This can simply be printed by just calling the levelling object for more detailed result.
print(leveling);
// ------ Levelling Summary -------
//
// Total measurements = 7
// Number of instrument stations = 3
// Starting TBM = 100.0
// Closing TBM = 98.05
//
// Allowable misclose = 8.660 mm
// Misclose = -0.009 m (-9.000 mm)
// Correction = 0.009
// Adjustment per station = 0.003
// Leveling Status: Work is not accepted.
//
// Arithmetic Checks:
// Sum of BS = 3.551
// Sum of FS = 5.510
// First RL = 100.000
// Last RL = 98.041
// Sum of BS - Sum of FS = -1.959
// Last RL - First RL = -1.959
// Arithmetic Checks are OK.
//
// BS IS FS Rise Fall Reduced Level (RL) Adjustment Adjusted RL Remarks
// ---------------------------------------------------------------------
// 1.751 100.000 0.000 100.000 A
// 0.540 1.211 101.211 0.003 101.214 B
// 0.300 2.100 -1.560 99.651 0.006 99.657 C
// 1.100 -0.800 98.851 0.006 98.857 D
// 1.260 -0.160 98.691 0.006 98.697 E
// 1.500 2.300 -1.040 97.651 0.009 97.660 F
// 1.110 0.390 98.041 0.009 98.050 G
copied to clipboard
Geocoding
Geocoding #
Geocoding is the process of converting addresses or place names into geographic coordinates (latitude and longitude). This allows you to perform various spatial operations, such as finding distances between locations or visualizing data on a map. In this readme, I will introduce a Dart class library for geocoding that provides different strategies for using geocoding services.
initialize Geocoding #
The GeoCoding library is designed to help you easily perform geocoding tasks in your Dart applications. It provides a set of classes and methods for working with geographic coordinates, addresses, and place names. The library supports multiple geocoding services and allows you to switch between them based on your needs.
Geocoder({
required Map<String, dynamic> strategyFactory,
Map<String, dynamic> config = const {},
Duration throttleDuration = const Duration(seconds: 1),
})
copied to clipboard
Strategies #
The GeoCoder library offers different strategies for using geocoding services:
GoogleStrategy: This strategy uses the Google Maps Geocoding API to perform geocoding. You will need an API key from Google Cloud Platform to use this strategy.
OpenStreetMapStrategy: This strategy uses the OpenStreetMap Nominatim service for geocoding. It is a free and open-source service that does not require any API keys.
LocalStrategy: This strategy uses the local database of the device to perform geocoding. It is a fast and efficient way to perform geocoding.
CustomStrategy: This strategy allows you to provide your own geocoding service implementation. You can create a custom class that implements the required methods and use it as a strategy in the GeoCoding library.
Usage GoogleStrategy #
Google strategy is the default strategy that is used by the GeoCoder library. It uses the Google Maps Geocoding API to perform geocoding. You will need an API key from Google Cloud Platform to use this strategy.
var point2 = LatLng(6, 0.7);
var googleGeocoder = Geocoder(
strategyFactory: GoogleStrategy.create('YOUR_GOOGLE_API_KEY'),
config: {
// Common Configurations
'language': 'en',
'requestTimeout': const Duration(seconds: 10),
// Google-Specific Configurations
'regionBias': 'US',
'resultType': 'address',
'locationType': 'ROOFTOP',
'components': 'country:US',
'rateLimit': 10, // Requests per second
}
);
GeocoderRequestResponse search = await googleGeocoder.search('Kotei');
print(search);
print('');
GeocoderRequestResponse rev = await googleGeocoder.reverse(point2);
print(rev);
print('');
copied to clipboard
Usage OpenStreetMapStrategy #
var openStreetMapGeocoder =
Geocoder(strategyFactory: OpenStreetMapStrategy.create(), config: {
// Common Configurations
'language': 'en',
'requestTimeout': const Duration(seconds: 10),
// OpenStreetMap-Specific Configurations
'email': '[email protected]', // For Nominatim usage policy
'countryCodes': 'us,uk',
'viewBox': 'left,bottom,right,top',
'boundedViewBox': '1', //bounded to viewbox
'limit': 5,
'addressDetails': 1,
});
// Geocode an address
GeocoderRequestResponse search = await openStreetMapGeocoder.search('KNUST');
print(search);
print('');
// Reverse geocode coordinates to get the address
GeocoderRequestResponse rev = await openStreetMapGeocoder.reverse(point2);
print(rev);
print('');
copied to clipboard
Result:
Geocoding Search Query: knust, Success: true, Timestamp: 2024-02-19 04:56:54.024349
GeocoderRequestResponse:
Success: true
Duration: 1035ms
Result: [{place_id: 125221183, licence: Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright, osm_type: way, osm_id: 32197062, lat: 53.741931199999996, lon: 9.842065240044334, class: natural, type: wood, place_rank: 22, importance: 0.2000099999999999, addresstype: wood, name: Knust, display_name: Knust, Quickborn, Kreis Pinneberg, Schleswig-Holstein, 25451, Germany, boundingbox: [53.7398546, 53.7444675, 9.8384852, 9.8500422]}, {place_id: 258247195, licence: Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright, osm_type: way, osm_id: 378466289, lat: 6.6785135, lon: -1.5754220088808766, class: amenity, type: university, place_rank: 30, importance: 0.3752824455605189, addresstype: amenity, name: Kwame Nkrumah University of Science & Technology, display_name: Kwame Nkrumah University of Science & Technology, Osei Tutu II Boulevard, Ayigya, Kumasi, Oforikrom Municipal District, Ashanti Region, AK385, Ghana, boundingbox: [6.6617810, 6.6953608, -1.5894842, -1.5323729]}, {place_id: 108558563, licence: Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright, osm_type: node, osm_id: 3362954799, lat: 49.5656112, lon: 9.4330658, class: place, type: locality, place_rank: 25, importance: 0.12500999999999995, addresstype: locality, name: Knust, display_name: Knust, Fuchsenloch, Waldstetten, Höpfingen, Verwaltungsverband Hardheim-Walldürn, Neckar-Odenwald-Kreis, Baden-Württemberg, 74746, Germany, boundingbox: [49.5556112, 49.5756112, 9.4230658, 9.4430658]}, {place_id: 122049626, licence: Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright, osm_type: node, osm_id: 4874767389, lat: 51.3722208, lon: 8.7031219, class: highway, type: bus_stop, place_rank: 30, importance: 0.00000999999999995449, addresstype: highway, name: Knust, display_name: Knust, L 3393, Heringhausen, Diemelsee, Landkreis Waldeck-Frankenberg, Hesse, 34519, Germany, boundingbox: [51.3721708, 51.3722708, 8.7030719, 8.7031719]}, {place_id: 379344893, licence: Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright, osm_type: node, osm_id: 1525291987, lat: 53.5581388, lon: 9.9679333, class: amenity, type: nightclub, place_rank: 30, importance: 0.00000999999999995449, addresstype: amenity, name: Knust, display_name: Knust, 30, Neuer Kamp, Karolinenviertel, St. Pauli, Hamburg-Mitte, Hamburg, 20357, Germany, boundingbox: [53.5580888, 53.5581888, 9.9678833, 9.9679833]}, {place_id: 98501560, licence: Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright, osm_type: node, osm_id: 1979116123, lat: 51.3126212, lon: 7.9976981, class: highway, type: bus_stop, place_rank: 30, importance: 0.00000999999999995449, addresstype: highway, name: Knust, display_name: Knust, Silmecke, Seidfeld (Sauerland), Sundern, Hochsauerlandkreis, North Rhine-Westphalia, 59846, Germany, boundingbox: [51.3125712, 51.3126712, 7.9976481, 7.9977481]}]
Reverse Geocoding Query: Location(6.0, 0.7), Success: true, Timestamp: 2024-02-19 04:56:55.029766
GeocoderRequestResponse:
Success: true
Duration: 1003ms
Result: {place_id: 34177377, licence: Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright, osm_type: way, osm_id: 517183740, lat: 5.999405087489885, lon: 0.7000142714680313, class: highway, type: unclassified, place_rank: 26, importance: 0.10000999999999993, addresstype: road, name: , display_name: Dabala, South Tongu District, Volta Region, Ghana, address: {town: Dabala, county: South Tongu District, state: Volta Region, ISO3166-2-lvl4: GH-TV, country: Ghana, country_code: gh}, boundingbox: [5.9949293, 5.9994108, 0.6890045, 0.7032672]}
copied to clipboard
Usage LocalStrategy #
The LocalStrategy in the GeoCoding library allows you to use a pre-defined dataset for geocoding and reverse geocoding. This is useful when you want to work with an offline dataset or need to process large amounts of data quickly without relying on network requests to external services. The Local Strategy requires you to provide a set of coordinates along with their associated addresses, places, or locations.
To create a GeoCoder instance using the Local Strategy, you can use the following code for dataset strategy:
List<Map<String, double>> points = [
{'latitude': 5.80736, 'longitude': 0.41074},
{'latitude': 6.13373, 'longitude': 0.81585},
{'latitude': 11.01667, 'longitude': -0.5},
{'latitude': 10.08587, 'longitude': -0.13587},
{'latitude': 9.35, 'longitude': -0.88333},
{'latitude': 10.73255, 'longitude': -1.05917},
];
copied to clipboard
Or using downloaded data from GeoNames data file with all world cities and population.
final geoData = await GeoData.readFile(
'example/GH.txt',
delimiter: '\t',
hasHeader: false,
coordinatesColumns: {
'latitude': 4,
'longitude': 5
}, // Specify column names and indices
);
// Print the number of records in the file
print(geoData.rows.length); // 23232
copied to clipboard
With the data created, geocoder can be used to create a local strategy using KDTree indexing. Other indexing methods will be implemented soon.
The only difference is the connection to data and associating the coordinates to x and y axis.
In this example, the geoData list contains the addresses, latitudes, and longitudes of different locations. The LocalStrategy.create() function is used to create a geocoding strategy using the provided data and specify the column names for coordinates. You can customize various configuration options for the Local Strategy, including search radius, limit, data preprocessing logic, cache size, and indexing strategy.
Once you have created the localGeocoder instance, you can use it to geocode an address or reverse geocode coordinates:
var localGeocoder = Geocoder(
strategyFactory: LocalStrategy.create(
entries: geoData.rows,
coordinatesColumnNames: (y: 'latitude', x: 'longitude'),
),
config: {
// Common Configurations
'language': 'en',
'requestTimeout': const Duration(seconds: 10),
// Local-Specific Configurations
'isGeodetic': true,
'searchRadius': 2000, // in meters
'limit': 5, // Number of results to return
'dataPreprocessing': (data) => {/* preprocessing logic */},
'cacheSize': 100,
'indexingStrategy': 'KDTree', // or 'RTree will be implemented soon'
});
// Geocode an address
GeocoderRequestResponse u = await localGeocoder.search('Kotei');
print(u);
print('');
// Reverse geocode coordinates to get the address
GeocoderRequestResponse rex = await localGeocoder.reverse(point2);
print(rex);
print('');
copied to clipboard
Geocoding Search Query: kotei, Success: true, Timestamp: 2024-02-19 05:13:55.706794
GeocoderRequestResponse:
Success: true
Duration: 42ms
Result: [{latitude: 6.66308, longitude: -1.55893, 0: 2299299, 1: Kotei, 2: Kotei, 3: Kotei, 4: 6.66308, 5: -1.55893, 6: P, 7: PPL, 8: GH, 9: , 10: 2, 11: 614, 12: , 13: , 14: 0, 15: , 16: 270, 17: Africa/Accra, 18: 06/12/2019}, {latitude: 6.60296, longitude: -1.66005, 0: 11780246, 1: Kotei, 2: Kotei, 3: "Kotei,Kotwi", 4: 6.60296, 5: -1.66005, 6: P, 7: PPL, 8: GH, 9: , 10: 2, 11: 613, 12: , 13: , 14: 0, 15: , 16: 242, 17: Africa/Accra, 18: 05/12/2019}]
Reverse Geocoding Query: Location(6.0, 0.7), Success: true, Timestamp: 2024-02-19 05:13:56.671350
GeocoderRequestResponse:
Success: true
Duration: 6ms
Result: [[{latitude: 5.98333, longitude: 0.7, 0: 2302105, 1: Dabala, 2: Dabala, 3: , 4: 5.98333, 5: 0.7, 6: H, 7: LK, 8: GH, 9: , 10: 0, 11: , 12: , 13: , 14: 0, 15: , 16: 1, 17: Africa/Accra, 18: 06/01/1994}, 1853.6194271649065], [{latitude: 5.98306, longitude: 0.69745, 0: 2305576, 1: Agbogbla, 2: Agbogbla, 3: "Agbogbla,Agoblan", 4: 5.98306, 5: 0.69745, 6: P, 7: PPL, 8: GH, 9: , 10: 8, 11: 401, 12: , 13: , 14: 0, 15: , 16: 3, 17: Africa/Accra, 18: 06/12/2019}, 1904.6339152449402]]
Initial Bearing: Bearing: 0.0° or 0.0 rad or 000° 00' 0.00000"
Final Bearing: Bearing: 180.0° or 3.1415926535897403 rad or 180° 00' 0.00000"
Distance (Haversine): 1.8536194271649065 km
Distance (Great Circle): 1.8536194278434843 km
Distance (Vincenty): 1.8434748739484934 km
Initial Bearing: Bearing: 8.514324846934187° or 0.14860300216336128 rad or 008° 30' 51.56945"
Final Bearing: Bearing: 188.51459101961586° or 3.2902003013427756 rad or 188° 30' 52.52767"
Distance (Haversine): 1.9046339152449403 km
Distance (Great Circle): 1.9046339162803452 km
copied to clipboard
The localGeocoder.search() and localGeocoder.reverse() functions work similarly to their online counterparts, allowing you to easily geocode addresses or reverse geocode coordinates from your pre-defined dataset.
Documentation #
For detailed documentation and examples for each feature, please visit the GeoEngine Documentation.
Contributing #
🍺 Pull requests are welcome! #
Don't forget that open-source makes no sense without contributors. No matter how big your changes are, it helps us a lot even it is a line of change.
There might be a lot of grammar issues in the docs. It's a big help to us to fix them if you are fluent in English. Reporting bugs and issues are contribution too, yes it is. Please file feature requests and bugs at the issue tracker.
Testing #
Tests are located in the test directory. To run tests, execute dart test in the project root.
Author #
Charles Gameti: gameticharles@GitHub.
License #
GeoEngine is licensed under the Apache License - Version 2.0.
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.