Commit 13634cfd by Rizal Hermawan

Initial commit

parents
# Files and directories created by pub
.dart_tool/
.packages
# Conventional directory for build outputs
build/
# Directory created by dartdoc
doc/api/
## [0.9.0]
- Change to const constructor for `LatLng`.
- remove `setLatitude()` and `setLongitude()`.
- Bump minimum dart version to 3.0.
## [0.8.2]
- Sexagesimal fixes and utils
- Upgrade dependencies
## [0.8.1]
- Add GeoJSON compliant toJson() and fromJson().
## [0.8.0]
- Use pedantic.
- camelCase constants.
- Add example.
- Other lint fixes.
## [0.7.0]
- Support null safety, forked from the original repo, which is now archived.
- Address https://github.com/MikeMitterer/dart-latlong/issues/1 and issue 2.
For previous releases, see https://pub.dev/packages/latlong/changelog.
Copyright 2015 Michael Mitterer (office@mikemitterer.at),
IT-Consulting and Development Limited, Austrian Branch
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied. See the License for the specific language
governing permissions and limitations under the License.
This is a fork of https://github.com/MikeMitterer/dart-latlong. The goal is to
keep it up to date with Dart language changes.
## LatLong provides a lightweight library for common latitude and longitude calculation.
This library supports both, the "Haversine" and the "Vincenty" algorithm.
"Haversine" is a bit faster but "Vincenty" is far more accurate!
<p align="center">
<img alt="LatLong" src="https://github.com/MikeMitterer/dart-latlong/raw/master/doc/images/latlong.jpg">
</p>
[Catmull-Rom algorithm](https://hawkesy.blogspot.co.at/2010/05/catmull-rom-spline-curve-implementation.html)
is used for smoothing out the path.
## Basic usage
### Distance
```dart
final Distance distance = new Distance();
// km = 423
final int km = distance.as(LengthUnit.Kilometer,
new LatLng(52.518611,13.408056),new LatLng(51.519475,7.46694444));
// meter = 422591.551
final int meter = distance(
new LatLng(52.518611,13.408056),
new LatLng(51.519475,7.46694444)
);
```
## Offset
```dart
final Distance distance = const Distance();
final num distanceInMeter = (earthRadius * math.pi / 4).round();
final p1 = new LatLng(0.0, 0.0);
final p2 = distance.offset(p1, distanceInMeter, 180);
// LatLng(latitude:-45.219848, longitude:0.0)
print(p2.round());
// 45° 13' 11.45" S, 0° 0' 0.00" O
print(p2.toSexagesimal());
```
## Path smoothing
```dart
// zigzag is a list of coordinates
final Path path = new Path.from(zigzag);
// Result is below
final Path steps = path.equalize(8,smoothPath: true);
```
<p align="center">
<img alt="Smooth path" src="https://github.com/MikeMitterer/dart-latlong/raw/master/doc/images/smooth-path.jpg">
</p>
## Features and bugs
Please file feature requests and bugs at the
[issue tracker](https://github.com/MikeMitterer/dart-latlong/issues).
## License
Copyright 2015 Michael Mitterer (office@mikemitterer.at),
IT-Consulting and Development Limited, Austrian Branch
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied. See the License for the specific language
governing permissions and limitations under the License.
If this plugin is helpful for you - please
[(Circle)](https://gplus.mikemitterer.at/) me or **star** this repo here on
GitHub
# Test the VM by default.
platforms: [ vm ]
paths:
- test/unit
import 'package:latlong2/latlong.dart';
const EARTH_RADIUS = 6371000.0;
void main() {
var distance = Distance();
// km = 423
final km = distance.as(LengthUnit.Kilometer, LatLng(52.518611, 13.408056),
LatLng(51.519475, 7.46694444));
// meter = 422591.551
final meter =
distance(LatLng(52.518611, 13.408056), LatLng(51.519475, 7.46694444));
print('km: $km, meter: $meter');
distance = const Distance();
final num distanceInMeter = (earthRadius * pi / 4).round();
final p1 = LatLng(0.0, 0.0);
final p2 = distance.offset(p1, distanceInMeter, 180);
// LatLng(latitude:-45.219848, longitude:0.0)
print(p2.round());
// 45° 13' 11.45" S, 0° 0' 0.00" O
print(p2.toSexagesimal());
//create a new distance calculator with Haversine algorithm
distance = const Distance(calculator: Haversine());
//create coordinates with NaN or Infinity state to check if the distance is calculated correctly
final point1 = LatLng(double.nan, 0.0);
final point2 = distance.offset(point1, distanceInMeter, 180);
var meterDistance = distance.as(LengthUnit.Meter,point1, point2);
print(meterDistance);
}
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// Helps with latitude / longitude calculations.
///
/// For distance calculations the default algorithm [Vincenty] is used.
/// [Vincenty] is a bit slower than [Haversine] but fare more accurate!
///
/// final Distance distance = new Distance();
///
/// // km = 423
/// final int km = distance.as(LengthUnit.Kilometer,
/// new LatLng(52.518611,13.408056),new LatLng(51.519475,7.46694444));
///
/// // meter = 422592
/// final int meter = distance(new LatLng(52.518611,13.408056),new LatLng(51.519475,7.46694444));
///
/// Find more infos on [Movable Type Scripts](http://www.movable-type.co.uk/scripts/latlong2.html)
/// and [Movable Type Scripts - Vincenty](http://www.movable-type.co.uk/scripts/latlong2-vincenty.html)
///
/// ![latlong2](http://eogn.com/images/newsletter/2014/Latitude-and-longitude.png)
///
/// ![Map](http://www.isobudgets.com/wp-content/uploads/2014/03/latitude-longitude.jpg)
///
library latlong2;
import 'dart:math' as math;
import 'package:latlong2/spline.dart';
import 'package:intl/intl.dart';
part 'latlong/interfaces.dart';
part 'latlong/calculator/Haversine.dart';
part 'latlong/calculator/Vincenty.dart';
part 'latlong/Distance.dart';
part 'latlong/LatLng.dart';
part 'latlong/LengthUnit.dart';
part 'latlong/Path.dart';
part 'latlong/Circle.dart';
/// Equator radius in meter (WGS84 ellipsoid)
const double equatorRadius = 6378137.0;
/// Polar radius in meter (WGS84 ellipsoid)
const double polarRadius = 6356752.314245;
/// WGS84
const double flattening = 1 / 298.257223563;
/// Earth radius in meter
const double earthRadius = equatorRadius;
/// The PI constant.
const double pi = math.pi;
/// Converts degree to radian
double degToRadian(final double deg) => deg * (pi / 180.0);
/// Radian to degree
double radianToDeg(final double rad) => rad * (180.0 / pi);
/// Rounds [value] to given number of [decimals]
double round(final double value, {final int decimals = 6}) =>
(value * math.pow(10, decimals)).round() / math.pow(10, decimals);
/// Convert a bearing to be within the 0 to +360 degrees range.
/// Compass bearing is in the rangen 0° ... 360°
double normalizeBearing(final double bearing) => (bearing + 360) % 360;
/// Converts a decimal coordinate value to sexagesimal format
///
/// final String sexa1 = decimal2sexagesimal(51.519475);
/// expect(sexa1, '51° 31\' 10.11"');
///
/// final String sexa2 = decimal2sexagesimal(-42.883891);
/// expect(sexa2, '42° 53\' 02.01"');
///
String decimal2sexagesimal(final double dec) {
final buf = StringBuffer();
final absDec = dec.abs();
final deg = absDec.floor();
buf.write(deg.toString() + '°');
final mins = (absDec - deg) * 60.0;
final min = mins.floor();
buf.write(' ' + zeroPad(min) + "'");
final secs = (mins - mins.floorToDouble()) * 60.0;
final sec = secs.floor();
final frac = ((secs - secs.floorToDouble()) * 100.0).round();
buf.write(' ' + zeroPad(sec) + '.' + zeroPad(frac) + '"');
return buf.toString();
}
/// Converts a string coordinate value in sexagesimal format to decimal
///
/// final dec1 = sexagesimal2decimal('51° 31\' 10.11"');
/// expect(dec1, 51.519475);
/// final dec2 = sexagesimal2decimal('19° 23\' 32.00"');
/// expect(dec2, 19.392222222222223);
///
double sexagesimal2decimal(final String str) {
final pattern = RegExp('''(\\d+)°\\s*(\\d+)'\\s*(\\d+).(\\d+)"''');
final m = pattern.firstMatch(str);
if (m != null) {
final deg = double.tryParse(m[1]!)!;
final min = double.tryParse(m[2]!)!;
final sec = double.tryParse(m[3]!)!;
final frac = double.tryParse(m[4]!)!;
final d = deg + min / 60 + sec / (60 * 60) + frac / (60 * 60 * 100);
return d;
} else {
throw 'Invalid sexagesimal: $str';
}
}
/// Pads a number with a single zero, if it is less than 10
String zeroPad(num number) => (number < 10 ? '0' : '') + number.toString();
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of latlong2;
/// Circle-base GEO algorithms.
///
/// Circle uses by default the Vincenty-Algorithm for distance computations
class Circle {
// final Logger _logger = new Logger('latlong2.Circle');
final double radius;
final LatLng center;
final DistanceCalculator _calculator;
const Circle(this.center, this.radius,
{final DistanceCalculator calculator = const Vincenty()})
: _calculator = calculator;
/// Checks if a [point] is inside the given [Circle]
///
/// final Circle circle = new Circle(new LatLng(0.0,0.0), 111319.0);
/// final LatLng newPos = new LatLng(1.0,0.0);
///
/// expect(circle.isPointInside(newPos),isTrue);
///
/// final Circle circle2 = new Circle(new LatLng(0.0,0.0), 111318.0);
///
/// expect(circle2.isPointInside(newPos),isFalse);
///
bool isPointInside(final LatLng point) {
final distance = Distance(calculator: _calculator);
final dist = distance(center, point);
return dist <= radius;
}
//- private -----------------------------------------------------------------------------------
}
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of latlong2;
/// Calculates the distance between points.
///
/// Default algorithm is [distanceWithVincenty], default radius is [earthRadius]
///
/// final Distance distance = new Distance();
///
/// // km = 423
/// final int km = distance.as(LengthUnit.Kilometer,
/// new LatLng(52.518611,13.408056),new LatLng(51.519475,7.46694444));
///
/// // meter = 422592
/// final int meter = distance(new LatLng(52.518611,13.408056),new LatLng(51.519475,7.46694444));
///
class Distance implements DistanceCalculator {
// final Logger _logger = new Logger('latlong2.Distance');
final double _radius;
final _roundResult;
final DistanceCalculator _calculator;
const Distance(
{final bool roundResult = true,
final DistanceCalculator calculator = const Vincenty()})
: _radius = earthRadius,
_roundResult = roundResult,
_calculator = calculator;
/// Radius must be greater than 0.
Distance.withRadius(final double radius,
{final bool roundResult = true,
final DistanceCalculator calculator = const Vincenty()})
: _radius = radius,
_roundResult = roundResult,
_calculator = calculator {
if (radius <= 0) {
throw ArgumentError.value(
radius, 'radius', 'Radius must be greater than 0');
}
}
double get radius => _radius;
/// Returns either [Haversine] oder [Vincenty] calculator
///
/// final Distance distance = const DistanceHaversine();
/// final Circle circle = new Circle(base, 1000.0,calculator: distance.calculator);
///
DistanceCalculator get calculator => _calculator;
/// Shortcut for [distance]
double call(final LatLng p1, final LatLng p2) {
return distance(p1, p2);
}
/// Converts the distance to the given [LengthUnit]
///
/// final int km = distance.as(LengthUnit.Kilometer,
/// new LatLng(52.518611,13.408056),new LatLng(51.519475,7.46694444));
///
double as(final LengthUnit unit, final LatLng p1, final LatLng p2) {
final dist = _calculator.distance(p1, p2);
// If the distance is NaN or infinite, return 0.0
if(dist.isNaN || dist.isInfinite) {
return 0.0;
}
return _round(LengthUnit.Meter.to(unit, dist));
}
/// Computes the distance between two points.
///
/// The function uses the [DistanceAlgorithm] specified in the CTOR
@override
double distance(final LatLng p1, final LatLng p2) =>
_round(_calculator.distance(p1, p2));
/// Returns the great circle bearing (direction) in degrees to the next point ([p2])
///
/// Find out about the difference between rhumb line and
/// great circle bearing on [Wikipedia](http://en.wikipedia.org/wiki/Rhumb_line#General_and_mathematical_description).
///
/// final Distance distance = const Distance();
///
/// final LatLng p1 = new LatLng(0.0, 0.0);
/// final LatLng p2 = new LatLng(-90.0, 0.0);
///
/// expect(distance.direction(p1, p2), equals(180));
double bearing(final LatLng p1, final LatLng p2) {
final diffLongitude = p2.longitudeInRad - p1.longitudeInRad;
final y = math.sin(diffLongitude);
final x = math.cos(p1.latitudeInRad) * math.tan(p2.latitudeInRad) -
math.sin(p1.latitudeInRad) * math.cos(diffLongitude);
return radianToDeg(math.atan2(y, x));
}
/// Returns a destination point based on the given [distance] and [bearing]
///
/// Given a [from] (start) point, initial [bearing], and [distance],
/// this will calculate the destination point and
/// final bearing travelling along a (shortest distance) great circle arc.
///
/// final Distance distance = const Distance();
///
/// final num distanceInMeter = (earthRadius * math.PI / 4).round();
///
/// final p1 = new LatLng(0.0, 0.0);
/// final p2 = distance.offset(p1, distanceInMeter, 180);
///
/// Bearing: Left - 270°, right - 90°, up - 0°, down - 180°
@override
LatLng offset(
final LatLng from, final num distanceInMeter, final num bearing) =>
_calculator.offset(from, distanceInMeter.toDouble(), bearing.toDouble());
//- private -----------------------------------------------------------------------------------
double _round(final double value) =>
(_roundResult ? value.round().toDouble() : value);
}
/// Shortcut for
/// final Distance distance = const Distance(calculator: const Vincenty());
///
class DistanceVincenty extends Distance {
const DistanceVincenty({final bool roundResult = true})
: super(roundResult: roundResult, calculator: const Vincenty());
/// Radius must be greater than 0.
DistanceVincenty.withRadius(final double radius,
{final bool roundResult = true})
: super.withRadius(radius,
roundResult: roundResult, calculator: const Vincenty()) {
if (radius <= 0) {
throw ArgumentError.value(
radius, 'radius', 'Radius must be greater than 0');
}
}
}
/// Shortcut for
/// final Distance distance = const Distance(calculator: const Haversine());
///
class DistanceHaversine extends Distance {
const DistanceHaversine({final bool roundResult = true})
: super(roundResult: roundResult, calculator: const Haversine());
/// Radius must be greater than 0.
DistanceHaversine.withRadius(final double radius,
{final bool roundResult = true})
: super.withRadius(radius,
roundResult: roundResult, calculator: const Haversine()) {
if (radius <= 0) {
throw ArgumentError.value(
radius, 'radius', 'Radius must be greater than 0');
}
}
}
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of latlong2;
/// Coordinates in Degrees
///
/// final Location location = new Location(10.000002,12.00001);
///
class LatLng {
// final Logger _logger = new Logger('latlong2.LatLng');
final double latitude;
final double longitude;
const LatLng(this.latitude, this.longitude)
: assert(latitude >= -90 && latitude <= 90),
assert(longitude >= -180 && longitude <= 180);
double get latitudeInRad => degToRadian(latitude);
double get longitudeInRad => degToRadian(longitude);
LatLng.fromJson(Map<String, dynamic> json)
: latitude = json['coordinates'][1],
longitude = json['coordinates'][0];
Map<String, dynamic> toJson() => {
'coordinates': [longitude, latitude]
};
@override
String toString() =>
'LatLng(latitude:${NumberFormat("0.0#####").format(latitude)}, '
'longitude:${NumberFormat("0.0#####").format(longitude)})';
/// Converts sexagesimal string into a lat/long value
///
/// final LatLng p1 = new LatLng.fromSexagesimal('''51° 31' 10.11" N, 19° 22' 32.00" W''');
/// print("${p1.latitude}, ${p1.longitude}");
/// // Shows:
/// 51.519475, -19.37555556
///
factory LatLng.fromSexagesimal(final String str) {
double _latitude = 0.0;
double _longitude = 0.0;
// try format '''47° 09' 53.57" N, 8° 32' 09.04" E'''
var splits = str.split(',');
if (splits.length != 2) {
// try format '''N 47°08'52.57" E 8°32'09.04"'''
splits = str.split('E');
if (splits.length != 2) {
// try format '''N 47°08'52.57" W 8°32'09.04"'''
splits = str.split('W');
if (splits.length != 2) {
throw 'Unsupported sexagesimal format: $str';
}
}
}
_latitude = sexagesimal2decimal(splits[0]);
_longitude = sexagesimal2decimal(splits[1]);
if (str.contains('S')) {
_latitude = -_latitude;
}
if (str.contains('W')) {
_longitude = -_longitude;
}
return LatLng(_latitude, _longitude);
}
/// Converts lat/long values into sexagesimal
///
/// final LatLng p1 = new LatLng(51.519475, -19.37555556);
///
/// // Shows: 51° 31' 10.11" N, 19° 22' 32.00" W
/// print(p1..toSexagesimal());
///
String toSexagesimal() {
var latDirection = latitude >= 0 ? 'N' : 'S';
var lonDirection = longitude >= 0 ? 'E' : 'W';
return '${decimal2sexagesimal(latitude)} $latDirection, ${decimal2sexagesimal(longitude)} $lonDirection';
}
@override
int get hashCode => latitude.hashCode + longitude.hashCode;
@override
bool operator ==(final Object other) =>
other is LatLng &&
latitude == other.latitude &&
longitude == other.longitude;
LatLng round({final int decimals = 6}) => LatLng(
_round(latitude, decimals: decimals),
_round(longitude, decimals: decimals));
//- private -----------------------------------------------------------------------------------
/// No qualifier for top level functions in Dart. Had to copy this function
double _round(final double value, {final int decimals = 6}) =>
(value * math.pow(10, decimals)).round() / math.pow(10, decimals);
}
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of latlong2;
class LengthUnit {
static const LengthUnit Millimeter = LengthUnit(1000.0);
static const LengthUnit Centimeter = LengthUnit(100.0);
static const LengthUnit Meter = LengthUnit(1.0);
static const LengthUnit Kilometer = LengthUnit(0.001);
static const LengthUnit Mile = LengthUnit(0.0006213712);
final double scaleFactor;
const LengthUnit(this.scaleFactor);
double to(final LengthUnit unit, final double value) {
if (unit.scaleFactor == scaleFactor) {
return value;
}
// Convert to primary unit.
final primaryValue = value / scaleFactor;
// Convert to destination unit.
return primaryValue * unit.scaleFactor;
}
}
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of latlong2;
/// Necessary for creating new instances T extends LatLng (Path<T extends LatLng>)
///
/// class Location extends LatLng {
/// ....
/// }
///
/// final Path<Location> path = new Path<Location>(factory: locationFactory);
///
typedef LatLngFactory = LatLng Function(double latitude, double longitude);
LatLng _defaultLatLngFactory(final double latitude, final double longitude) =>
LatLng(latitude, longitude);
/// Path of [LatLng] values
///
/// If you use [Path] with Generics - check out this sample:
///
/// class Location extends LatLng {
/// ....
/// }
///
/// final Path<Location> path = new Path<Location>(factory: locationFactory);
///
class Path<T extends LatLng> {
/// Coordinates managed by this class
final List<T> _coordinates;
/// For [Distance] calculations
final Distance _distance = const Distance();
final LatLngFactory _latLngFactory;
Path({final LatLngFactory factory = _defaultLatLngFactory})
: _coordinates = [],
_latLngFactory = factory;
Path.from(final Iterable<T> coordinates,
{final LatLngFactory factory = _defaultLatLngFactory})
: _coordinates = List<T>.from(coordinates),
_latLngFactory = factory;
List<T> get coordinates => _coordinates;
/// Removes all coordinates from path
void clear() => _coordinates.clear();
/// Add new [T] coordinate to path
void add(final T value) {
return _coordinates.add(value);
}
/// Add all coordinates from [List<T>] to path
void addAll(final List<T> values) {
return _coordinates.addAll(values);
}
T get first => _coordinates.first;
T get last => _coordinates.last;
/// Splits the path into even sections.
///
/// The section size is defined with [distanceInMeterPerTime].
/// [distanceInMeterPerTime] means that the original size on the given
/// path will stay the same but the created section could be smaller because of the "linear distance"
///
/// However - if you follow the steps in a given time then the distance from point to point (over time)
/// is correct. (Almost - because of the curves generate with [CatmullRomSpline2D]
///
/// final Path path = new Path.from(zigzag);
///
/// If [smoothPath] is turned on than the minimum of 3 coordinates is required otherwise
/// we need two
Path equalize(final double distanceInMeterPerTime,
{final bool smoothPath = true}) {
if (distanceInMeterPerTime <= 0) {
throw ArgumentError.value(distanceInMeterPerTime,
'distanceInMeterPerTime', 'Distance must be greater than 0');
}
if (!((smoothPath && _coordinates.length >= 3) ||
(!smoothPath && _coordinates.length >= 2))) {
throw ArgumentError.value(smoothPath, 'smoothPath',
'At least ${smoothPath ? 3 : 2} coordinates are needed to create the steps in between');
}
// If we "smooth" the path every second step becomes a spline - so every other step
// becomes a "Keyframe". A step on the given path
final stepDistance = smoothPath
? distanceInMeterPerTime * 2.0
: distanceInMeterPerTime.toDouble();
final baseLength = distance;
if (baseLength < stepDistance) {
throw ArgumentError(
'Path distance must be at least ${stepDistance}mn (step distance) but was $baseLength');
}
if (stepDistance > baseLength / 2) {
print(
'Warning: Equalizing the path (L: $baseLength) with a key-frame distance of $stepDistance leads to'
'weired results. Turn of path smooting.');
}
// no steps possible - so return an empty path
if (baseLength == stepDistance) {
return Path.from([_coordinates.first, _coordinates.last]);
}
final tempCoordinates = List<T>.from(_coordinates);
final path = Path();
var remainingSteps = 0.0;
double bearing;
path.add(tempCoordinates.first);
var baseStep = tempCoordinates.first;
for (var index = 0; index < coordinates.length - 1; index++) {
final distance =
_distance(tempCoordinates[index], tempCoordinates[index + 1]);
// Remember the direction
bearing =
_distance.bearing(tempCoordinates[index], tempCoordinates[index + 1]);
if (remainingSteps <= distance ||
(stepDistance - remainingSteps) <= distance) {
// First step position
var firstStepPos = stepDistance - remainingSteps;
final steps = ((distance - firstStepPos) / stepDistance) + 1;
final fullSteps = steps.toInt();
remainingSteps =
round(fullSteps > 0 ? steps % fullSteps : steps, decimals: 6) *
stepDistance;
baseStep = tempCoordinates[index];
for (var stepCounter = 0; stepCounter < fullSteps; stepCounter++) {
// Add step on the given path
// Intermediate step is necessary to stay type-safe
final tempStep = _distance.offset(baseStep, firstStepPos, bearing);
final nextStep =
_latLngFactory(tempStep.latitude, tempStep.longitude);
path.add(nextStep);
firstStepPos += stepDistance;
if (smoothPath) {
// Now - split it
CatmullRomSpline2D<double> spline;
if (path.nrOfCoordinates == 3) {
spline = _createSpline(path[0], path[0], path[1], path[2]);
// Insert new point between 0 and 1
path.coordinates.insert(1, _pointToLatLng(spline.percentage(50)));
} else if (path.nrOfCoordinates > 3) {
final baseIndex = path.nrOfCoordinates - 1;
spline = _createSpline(path[baseIndex - 3], path[baseIndex - 2],
path[baseIndex - 1], path[baseIndex]);
// Insert new point at last position - 2 (pushes the next 2 items down)
path.coordinates
.insert(baseIndex - 1, _pointToLatLng(spline.percentage(50)));
}
}
}
} else {
remainingSteps += distance;
}
}
// If last step is on the same position as the last generated step
// then don't add the last base step.
if (baseStep.round() != tempCoordinates.last.round() &&
baseStep.round() != tempCoordinates.first.round() &&
round(_distance(baseStep, tempCoordinates.last)) > 1) {
path.add(tempCoordinates.last);
}
if (smoothPath) {
// Last Spline between the last 4 elements
var baseIndex = path.nrOfCoordinates - 1;
if (baseIndex > 3) {
final spline = _createSpline(path[baseIndex - 3], path[baseIndex - 2],
path[baseIndex - 1], path[baseIndex - 0]);
path.coordinates
.insert(baseIndex - 1, _pointToLatLng(spline.percentage(50)));
}
// Check if there is a remaining gap between the last two elements - close it
// Could be because of reminder from path divisions
baseIndex = path.nrOfCoordinates - 1;
if (_distance(path[baseIndex - 1], path[baseIndex]) >= stepDistance) {
final spline = _createSpline(path[baseIndex - 1], path[baseIndex - 1],
path[baseIndex - 0], path[baseIndex - 0]);
path.coordinates
.insert(baseIndex, _pointToLatLng(spline.percentage(50)));
}
}
// Make sure we have no duplicates!
// _removeDuplicates();
return path;
}
/// Sums up all the distances on the path
///
/// final Path path = new Path.from(route);
/// print(path.length);
///
double get distance {
final tempCoordinates = List<T>.from(_coordinates);
var length = 0.0;
for (var index = 0; index < coordinates.length - 1; index++) {
length += _distance(tempCoordinates[index], tempCoordinates[index + 1]);
}
return round(length);
}
/// Calculates the center of a collection of geo coordinates
///
/// The function rounds the result to 6 decimals
LatLng get center {
if (coordinates.isEmpty) {
throw AssertionError('Coordinates must not be empty!');
}
var X = 0.0;
var Y = 0.0;
var Z = 0.0;
double lat, lon, hyp;
coordinates.forEach((final T coordinate) {
lat = coordinate.latitudeInRad;
lon = coordinate.longitudeInRad;
X += math.cos(lat) * math.cos(lon);
Y += math.cos(lat) * math.sin(lon);
Z += math.sin(lat);
});
final nrOfCoordinates = coordinates.length;
X = X / nrOfCoordinates;
Y = Y / nrOfCoordinates;
Z = Z / nrOfCoordinates;
lon = math.atan2(Y, X);
hyp = math.sqrt(X * X + Y * Y);
lat = math.atan2(Z, hyp);
return _latLngFactory(round(radianToDeg(lat)), round(radianToDeg(lon)));
}
/// Returns the number of coordinates
///
/// final Path path = new Path.from(<LatLng>[ startPos,endPos ]);
/// final int nr = path.nrOfCoordinates; // nr == 2
///
int get nrOfCoordinates => _coordinates.length;
/// Returns the [LatLng] coordinate form [index]
///
/// final Path path = new Path.from(<LatLng>[ startPos,endPos ]);
/// final LatLng p1 = path[0]; // p1 == startPos
///
T operator [](final int index) => _coordinates.elementAt(index);
//- private -----------------------------------------------------------------------------------
/// 4 Points are necessary to create a [CatmullRomSpline2D]
CatmullRomSpline2D<double> _createSpline(
final LatLng p0, final LatLng p1, final LatLng p2, final LatLng p3) {
return CatmullRomSpline2D(
Point2D(p0.latitude, p0.longitude),
Point2D(p1.latitude, p1.longitude),
Point2D(p2.latitude, p2.longitude),
Point2D(p3.latitude, p3.longitude));
}
/// Convert [Point2D] to [LatLng]
LatLng _pointToLatLng(final Point2D point) =>
_latLngFactory(point.x, point.y);
}
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of latlong2;
class Haversine implements DistanceCalculator {
// final Logger _logger = new Logger('latlong2.Haversine');
const Haversine();
/// Calculates distance with Haversine algorithm.
///
/// Accuracy can be out by 0.3%
/// More on [Wikipedia](https://en.wikipedia.org/wiki/Haversine_formula)
@override
double distance(final LatLng p1, final LatLng p2) {
final sinDLat = math.sin((p2.latitudeInRad - p1.latitudeInRad) / 2);
final sinDLng = math.sin((p2.longitudeInRad - p1.longitudeInRad) / 2);
// Sides
final a = sinDLat * sinDLat +
sinDLng *
sinDLng *
math.cos(p1.latitudeInRad) *
math.cos(p2.latitudeInRad);
final c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
return equatorRadius * c;
}
/// Returns a destination point based on the given [distance] and [bearing]
///
/// Given a [from] (start) point, initial [bearing], and [distance],
/// this will calculate the destination point and
/// final bearing travelling along a (shortest distance) great circle arc.
///
/// final Haversine distance = const Haversine();
///
/// final num distanceInMeter = (earthRadius * math.PI / 4).round();
///
/// final p1 = new LatLng(0.0, 0.0);
/// final p2 = distance.offset(p1, distanceInMeter, 180);
///
@override
LatLng offset(
final LatLng from, final double distanceInMeter, final double bearing) {
if (bearing < -180 || bearing > 180) {
throw ArgumentError.value(
bearing, 'bearing', 'Angle must be between -180 and 180 degrees');
}
final h = degToRadian(bearing.toDouble());
final a = distanceInMeter / equatorRadius;
final lat2 = math.asin(math.sin(from.latitudeInRad) * math.cos(a) +
math.cos(from.latitudeInRad) * math.sin(a) * math.cos(h));
final lng2 = from.longitudeInRad +
math.atan2(math.sin(h) * math.sin(a) * math.cos(from.latitudeInRad),
math.cos(a) - math.sin(from.latitudeInRad) * math.sin(lat2));
return LatLng(radianToDeg(lat2), radianToDeg(lng2));
}
//- private -----------------------------------------------------------------------------------
}
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of latlong2;
class Vincenty implements DistanceCalculator {
// final Logger _logger = new Logger('latlong2.Vincenty');
const Vincenty();
/// Calculates distance with Vincenty algorithm.
///
/// Accuracy is about 0.5mm
/// More on [Wikipedia](https://en.wikipedia.org/wiki/Vincenty%27s_formulae)
@override
double distance(final LatLng p1, final LatLng p2) {
var a = equatorRadius,
b = polarRadius,
f = flattening; // WGS-84 ellipsoid params
var l = p2.longitudeInRad - p1.longitudeInRad;
var u1 = math.atan((1 - f) * math.tan(p1.latitudeInRad));
var u2 = math.atan((1 - f) * math.tan(p2.latitudeInRad));
var sinU1 = math.sin(u1), cosU1 = math.cos(u1);
var sinU2 = math.sin(u2), cosU2 = math.cos(u2);
double sinLambda,
cosLambda,
sinSigma,
cosSigma,
sigma,
sinAlpha,
cosSqAlpha,
cos2SigmaM;
double lambda = l, lambdaP;
var maxIterations = 200;
do {
sinLambda = math.sin(lambda);
cosLambda = math.cos(lambda);
sinSigma = math.sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) +
(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) *
(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
if (sinSigma == 0) {
return 0.0; // co-incident points
}
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
sigma = math.atan2(sinSigma, cosSigma);
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
cosSqAlpha = 1 - sinAlpha * sinAlpha;
cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
if (cos2SigmaM.isNaN) {
cos2SigmaM = 0.0; // equatorial line: cosSqAlpha=0 (§6)
}
var C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
lambdaP = lambda;
lambda = l +
(1 - C) *
f *
sinAlpha *
(sigma +
C *
sinSigma *
(cos2SigmaM +
C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
} while ((lambda - lambdaP).abs() > 1e-12 && --maxIterations > 0);
if (maxIterations == 0) {
throw StateError('Distance calculation faild to converge!');
}
var uSq = cosSqAlpha * (a * a - b * b) / (b * b);
var A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
var B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
var deltaSigma = B *
sinSigma *
(cos2SigmaM +
B /
4 *
(cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
B /
6 *
cos2SigmaM *
(-3 + 4 * sinSigma * sinSigma) *
(-3 + 4 * cos2SigmaM * cos2SigmaM)));
var dist = b * A * (sigma - deltaSigma);
return dist;
}
/// Vincenty inverse calculation
///
/// More on [Wikipedia](https://en.wikipedia.org/wiki/Vincenty%27s_formulae)
@override
LatLng offset(
final LatLng from, final double distanceInMeter, final double bearing) {
final equatorialRadius = equatorRadius;
final latitude = from.latitudeInRad;
final longitude = from.longitudeInRad;
final alpha1 = degToRadian(bearing);
final sinAlpha1 = math.sin(alpha1);
final cosAlpha1 = math.cos(alpha1);
final tanU1 = (1 - flattening) * math.tan(latitude);
final cosU1 = 1 / math.sqrt((1 + tanU1 * tanU1));
final sinU1 = tanU1 * cosU1;
final sigma1 = math.atan2(tanU1, cosAlpha1);
final sinAlpha = cosU1 * sinAlpha1;
final cosSqAlpha = 1 - sinAlpha * sinAlpha;
final dfUSq = cosSqAlpha *
(equatorialRadius * equatorialRadius - polarRadius * polarRadius) /
(polarRadius * polarRadius);
final a = 1 +
dfUSq / 16384 * (4096 + dfUSq * (-768 + dfUSq * (320 - 175 * dfUSq)));
final b = dfUSq / 1024 * (256 + dfUSq * (-128 + dfUSq * (74 - 47 * dfUSq)));
var sigma = distanceInMeter / (polarRadius * a);
var sigmaP = 2 * pi;
var sinSigma = 0.0;
var cosSigma = 0.0;
var cos2SigmaM = 0.0;
double deltaSigma;
var maxIterations = 200;
do {
cos2SigmaM = math.cos(2 * sigma1 + sigma);
sinSigma = math.sin(sigma);
cosSigma = math.cos(sigma);
deltaSigma = b *
sinSigma *
(cos2SigmaM +
b /
4 *
(cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
b /
6 *
cos2SigmaM *
(-3 + 4 * sinSigma * sinSigma) *
(-3 + 4 * cos2SigmaM * cos2SigmaM)));
sigmaP = sigma;
sigma = distanceInMeter / (polarRadius * a) + deltaSigma;
} while ((sigma - sigmaP).abs() > 1e-12 && --maxIterations > 0);
if (maxIterations == 0) {
throw StateError('offset calculation faild to converge!');
}
final tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
final lat2 = math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
(1 - flattening) * math.sqrt(sinAlpha * sinAlpha + tmp * tmp));
final lambda = math.atan2(
sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
final c =
flattening / 16 * cosSqAlpha * (4 + flattening * (4 - 3 * cosSqAlpha));
final l = lambda -
(1 - c) *
flattening *
sinAlpha *
(sigma +
c *
sinSigma *
(cos2SigmaM +
c * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
var lon2 = longitude + l;
// print("LA ${radianToDeg(lat2)}, LO ${radianToDeg(lon2)}");
if (lon2 > pi) {
lon2 = lon2 - 2 * pi;
}
if (lon2 < -1 * pi) {
lon2 = lon2 + 2 * pi;
}
return LatLng(radianToDeg(lat2), radianToDeg(lon2));
}
//- private -----------------------------------------------------------------------------------
}
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of latlong2;
abstract class DistanceCalculator {
double distance(final LatLng p1, final LatLng p2);
LatLng offset(
final LatLng from, final double distanceInMeter, final double bearing);
}
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// Splines are most commonly used to draw a curve
/// line when a set of given points exists, which needs to be joined smoothly.
///
/// More about the [algorithm](http://www.dxstudio.com/guide_content.aspx?id=70a2b2cf-193e-4019-859c-28210b1da81f)
/// and [here](http://www.mvps.org/directx/articles/catmull/).
///
/// Java way: [A Catmull Rom Spline (curve) Implementation in Java](http://hawkesy.blogspot.co.at/2010/05/catmull-rom-spline-curve-implementation.html)
///
library spline;
//import 'package:logging/logging.dart';
part 'spline/CatmullRomSpline.dart';
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of spline;
class Point2D {
final double x;
final double y;
Point2D(this.x, this.y);
}
abstract class CatmullRom<R> {
const CatmullRom();
R position(final double distance);
R percentage(final num percent) => position(percent / 100);
}
class CatmullRomSpline extends CatmullRom<double> {
// final Logger _logger = new Logger('spline.CatmullRomSpline');
final double _p0, _p1, _p2, _p3;
const CatmullRomSpline(this._p0, this._p1, this._p2, this._p3);
const CatmullRomSpline.noEndpoints(final double p1, final double p2)
: _p0 = p1,
_p1 = p1,
_p2 = p2,
_p3 = p2;
@override
double position(final double distance) {
if (distance < 0 || distance > 1) {
throw ArgumentError.value(
distance, 'distance', 'Distance must be beteen 0 and 1.');
}
return 0.5 *
((2 * _p1) +
(_p2 - _p0) * distance +
(2 * _p0 - 5 * _p1 + 4 * _p2 - _p3) * distance * distance +
(3 * _p1 - _p0 - 3 * _p2 + _p3) * distance * distance * distance);
}
}
class CatmullRomSpline2D<T extends num> extends CatmullRom<Point2D> {
final Point2D _p0;
final Point2D _p1;
final Point2D _p2;
final Point2D _p3;
CatmullRomSpline2D(this._p0, this._p1, this._p2, this._p3);
CatmullRomSpline2D.noEndpoints(final Point2D p0, final Point2D p1)
: _p0 = p0,
_p1 = p0,
_p2 = p1,
_p3 = p1;
@override
Point2D position(final double distance) {
if (distance < 0 || distance > 1) {
throw ArgumentError.value(
distance, 'distance', 'Distance must be beteen 0 and 1.');
}
return Point2D(
CatmullRomSpline(_p0.x, _p1.x, _p2.x, _p3.x).position(distance),
CatmullRomSpline(_p0.y, _p1.y, _p2.y, _p3.y).position(distance));
}
}
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
url: "https://pub.dev"
source: hosted
version: "61.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
url: "https://pub.dev"
source: hosted
version: "5.13.0"
archive:
dependency: transitive
description:
name: archive
sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a"
url: "https://pub.dev"
source: hosted
version: "3.3.7"
args:
dependency: transitive
description:
name: args
sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a
url: "https://pub.dev"
source: hosted
version: "2.4.1"
async:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.11.0"
bazel_worker:
dependency: transitive
description:
name: bazel_worker
sha256: "500584fdb80bcb70a2990a5838338a757cc24bbf27d88bf791cbe9461c57cd5a"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
build:
dependency: transitive
description:
name: build
sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
build_config:
dependency: transitive
description:
name: build_config
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
url: "https://pub.dev"
source: hosted
version: "1.1.1"
build_daemon:
dependency: transitive
description:
name: build_daemon
sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
build_modules:
dependency: transitive
description:
name: build_modules
sha256: "66f0f746a239ff6cceba9d235a679ec70a6d9037ddddb36a24a0791a639a8486"
url: "https://pub.dev"
source: hosted
version: "5.0.7"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95
url: "https://pub.dev"
source: hosted
version: "2.2.0"
build_runner:
dependency: "direct dev"
description:
name: build_runner
sha256: "220ae4553e50d7c21a17c051afc7b183d28a24a420502e842f303f8e4e6edced"
url: "https://pub.dev"
source: hosted
version: "2.4.4"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
sha256: "30859c90e9ddaccc484f56303931f477b1f1ba2bab74aa32ed5d6ce15870f8cf"
url: "https://pub.dev"
source: hosted
version: "7.2.8"
build_test:
dependency: "direct dev"
description:
name: build_test
sha256: "927ef98b58c5603ec58923c0bb943a74743e58149732665885bb1eb92983befe"
url: "https://pub.dev"
source: hosted
version: "2.1.7"
build_web_compilers:
dependency: "direct dev"
description:
name: build_web_compilers
sha256: aad1d705faa53d060e7ccb7855ee74705a8e3d9ea1634e63e362cc2c1bd47afa
url: "https://pub.dev"
source: hosted
version: "4.0.9"
built_collection:
dependency: transitive
description:
name: built_collection
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
url: "https://pub.dev"
source: hosted
version: "5.1.1"
built_value:
dependency: transitive
description:
name: built_value
sha256: "2f17434bd5d52a26762043d6b43bb53b3acd029b4d9071a329f46d67ef297e6d"
url: "https://pub.dev"
source: hosted
version: "8.5.0"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.dev"
source: hosted
version: "2.0.3"
clock:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.1"
code_builder:
dependency: transitive
description:
name: code_builder
sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
url: "https://pub.dev"
source: hosted
version: "4.4.0"
collection:
dependency: transitive
description:
name: collection
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev"
source: hosted
version: "1.17.2"
convert:
dependency: transitive
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
coverage:
dependency: transitive
description:
name: coverage
sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097"
url: "https://pub.dev"
source: hosted
version: "1.6.3"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.3"
csslib:
dependency: transitive
description:
name: csslib
sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745
url: "https://pub.dev"
source: hosted
version: "0.17.2"
dart_style:
dependency: transitive
description:
name: dart_style
sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad
url: "https://pub.dev"
source: hosted
version: "2.3.1"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
glob:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
graphs:
dependency: transitive
description:
name: graphs
sha256: "772db3d53d23361d4ffcf5a9bb091cf3ee9b22f2be52cd107cd7a2683a89ba0e"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
html:
dependency: transitive
description:
name: html
sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8"
url: "https://pub.dev"
source: hosted
version: "0.15.3"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
intl:
dependency: "direct main"
description:
name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev"
source: hosted
version: "0.18.1"
io:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
js:
dependency: transitive
description:
name: js
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
version: "0.6.7"
json_annotation:
dependency: transitive
description:
name: json_annotation
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
url: "https://pub.dev"
source: hosted
version: "4.8.1"
lints:
dependency: "direct dev"
description:
name: lints
sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
logging:
dependency: transitive
description:
name: logging
sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
matcher:
dependency: transitive
description:
name: matcher
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
version: "0.12.16"
meta:
dependency: transitive
description:
name: meta
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
mime:
dependency: transitive
description:
name: mime
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
url: "https://pub.dev"
source: hosted
version: "1.0.4"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
path:
dependency: transitive
description:
name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev"
source: hosted
version: "1.8.3"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
url: "https://pub.dev"
source: hosted
version: "3.7.3"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
protobuf:
dependency: transitive
description:
name: protobuf
sha256: "01dd9bd0fa02548bf2ceee13545d4a0ec6046459d847b6b061d8a27237108a08"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
url: "https://pub.dev"
source: hosted
version: "1.2.3"
scratch_space:
dependency: transitive
description:
name: scratch_space
sha256: "8510fbff458d733a58fc427057d1ac86303b376d609d6e1bc43f240aad9aa445"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
shelf:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
url: "https://pub.dev"
source: hosted
version: "1.4.1"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
url: "https://pub.dev"
source: hosted
version: "1.1.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
url: "https://pub.dev"
source: hosted
version: "0.10.12"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
url: "https://pub.dev"
source: hosted
version: "1.11.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
stream_transform:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test:
dependency: "direct dev"
description:
name: test
sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46"
url: "https://pub.dev"
source: hosted
version: "1.24.3"
test_api:
dependency: transitive
description:
name: test_api
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev"
source: hosted
version: "0.6.0"
test_core:
dependency: transitive
description:
name: test_core
sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e"
url: "https://pub.dev"
source: hosted
version: "0.5.3"
timing:
dependency: transitive
description:
name: timing
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.2"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: f3743ca475e0c9ef71df4ba15eb2d7684eecd5c8ba20a462462e4e8b561b2e11
url: "https://pub.dev"
source: hosted
version: "11.6.0"
watcher:
dependency: transitive
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
url: "https://pub.dev"
source: hosted
version: "2.4.0"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
yaml:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.1.0 <3.5.0"
name: latlong2
description: Lightweight library for common latitude and longitude calculation
homepage: https://github.com/jifalops/dart-latlong
version: 0.9.0
environment:
sdk: ">=3.0.0 <4.0.0"
dependencies:
intl: '>=0.15.0 <1.0.0'
dev_dependencies:
test: any
lints: any
build_runner: any
build_test: any
build_web_compilers: any
//@TestOn("content-shell")
import 'package:test/test.dart';
import 'package:latlong2/latlong.dart';
// import 'package:logging/logging.dart';
// Browser
// import "package:console_log_handler/console_log_handler.dart";
// Commandline
// import "package:console_log_handler/print_log_handler.dart";
void main() {
// final Logger _logger = new Logger("test.Circle");
// configLogging();
final base = LatLng(0.0, 0.0);
final distance = const Distance();
final circle = Circle(base, 1000.0);
final Distance distanceHaversine = const DistanceHaversine();
final circleHaversine = Circle(base, 1000.0, calculator: const Haversine());
group('Circle with Vincenty', () {
setUp(() {});
test(
'> isInside - distance from 0.0,0.0 to 1.0,0.0 is 110574 meter (based on Vincenty)',
() {
final circle = Circle(LatLng(0.0, 0.0), 110574.0);
final newPos = LatLng(1.0, 0.0);
// final double dist = new Distance().distance(circle.center,newPos);
// print(dist);
expect(circle.isPointInside(newPos), isTrue);
final circle2 = Circle(LatLng(0.0, 0.0), 110573.0);
expect(circle2.isPointInside(newPos), isFalse);
}); // end of 'isInside - ' test
test('> isInside, bearing 0', () {
final num bearing = 0;
<num>[100, 500, 999, 1000].forEach((final num dist) {
expect(
circle.isPointInside(distance.offset(base, dist, bearing)), isTrue);
});
expect(
circle.isPointInside(distance.offset(base, 1001, bearing)), isFalse);
}); // end of 'isInside, bearing 0' test
test('> isInside, bearing 90', () {
final num bearing = 90;
<num>[100, 500, 999, 1000].forEach((final num dist) {
expect(
circle.isPointInside(distance.offset(base, dist, bearing)), isTrue);
});
expect(
circle.isPointInside(distance.offset(base, 1001, bearing)), isFalse);
}); // end of 'isInside, bearing 0' test
test('> isInside, bearing -90', () {
final num bearing = -90;
<num>[100, 500, 999, 1000].forEach((final num dist) {
expect(
circle.isPointInside(distance.offset(base, dist, bearing)), isTrue);
});
expect(
circle.isPointInside(distance.offset(base, 1001, bearing)), isFalse);
}); // end of 'isInside, bearing 0' test
test('> isInside, bearing 180', () {
final num bearing = 180;
<num>[100, 500, 999, 1000].forEach((final num dist) {
expect(
circle.isPointInside(distance.offset(base, dist, bearing)), isTrue);
});
expect(
circle.isPointInside(distance.offset(base, 1001, bearing)), isFalse);
}); // end of 'isInside, bearing 0' test
test('> isInside, bearing -180', () {
final num bearing = -180;
<num>[100, 500, 999, 1000].forEach((final num dist) {
expect(
circle.isPointInside(distance.offset(base, dist, bearing)), isTrue);
});
expect(
circle.isPointInside(distance.offset(base, 1001, bearing)), isFalse);
}); // end of 'isInside, bearing 0' test
});
// End of 'Circle with Haversine' group
group('Circle with Haversine', () {
test('> isInside, bearing 0', () {
final num bearing = 0;
<num>[100, 500, 999, 1000].forEach((final num dist) {
expect(
circleHaversine
.isPointInside(distanceHaversine.offset(base, dist, bearing)),
isTrue);
});
<num>[1001, 1002, 1003, 1004, 1005, 1006, 1007].forEach((final num dist) {
expect(
circleHaversine
.isPointInside(distanceHaversine.offset(base, dist, bearing)),
isFalse);
});
}); // end of 'isInside, bearing 0' test
test('> isInside, bearing 90', () {
final num bearing = 90;
<num>[100, 500, 999, 1000].forEach((final num dist) {
expect(
circleHaversine
.isPointInside(distanceHaversine.offset(base, dist, bearing)),
isTrue);
});
expect(
circleHaversine
.isPointInside(distanceHaversine.offset(base, 1001, bearing)),
isFalse);
}); // end of 'isInside, bearing 0' test
test('> isInside, bearing -90', () {
final num bearing = -90;
<num>[100, 500, 999, 1000].forEach((final num dist) {
expect(
circleHaversine
.isPointInside(distanceHaversine.offset(base, dist, bearing)),
isTrue);
});
expect(
circleHaversine
.isPointInside(distanceHaversine.offset(base, 1001, bearing)),
isFalse);
}); // end of 'isInside, bearing 0' test
test('> isInside, bearing 180', () {
final num bearing = 180;
<num>[100, 500, 999, 1000].forEach((final num dist) {
expect(
circleHaversine
.isPointInside(distanceHaversine.offset(base, dist, bearing)),
isTrue);
});
expect(
circleHaversine
.isPointInside(distanceHaversine.offset(base, 1001, bearing)),
isFalse);
}); // end of 'isInside, bearing 0' test
test('> isInside, bearing -180', () {
final num bearing = -180;
<num>[100, 500, 999, 1000].forEach((final num dist) {
expect(
circleHaversine
.isPointInside(distanceHaversine.offset(base, dist, bearing)),
isTrue);
});
expect(
circleHaversine
.isPointInside(distanceHaversine.offset(base, 1001, bearing)),
isFalse);
}); // end of 'isInside, bearing 0' test
}); // End of 'Circle with Vincenty' group
}
// - Helper --------------------------------------------------------------------------------------
//@TestOn("content-shell")
import 'package:test/test.dart';
import 'package:latlong2/latlong.dart';
// import 'package:logging/logging.dart';
// Browser
// import "package:console_log_handler/console_log_handler.dart";
// Commandline
// import "package:console_log_handler/print_log_handler.dart";
void main() {
// final Logger _logger = new Logger("test.Distance");
// configLogging();
group('Distance', () {
setUp(() {});
test('> Radius', () {
expect((Distance()).radius, earthRadius);
expect((Distance.withRadius(100.0)).radius, 100.0);
}); // end of 'Radius' test
test('> Distance to the same point is 0', () {
final compute = Distance();
final p = LatLng(0.0, 0.0);
expect(compute.distance(p, p), equals(0));
}); // end of 'Simple distance' test
test('> Distance between 0 and 90.0 is around 10.000km', () {
final distance = Distance();
final p1 = LatLng(0.0, 0.0);
final p2 = LatLng(90.0, 0.0);
// no rounding
expect(distance(p1, p2) ~/ 1000, equals(10001));
expect(
LengthUnit.Meter.to(LengthUnit.Kilometer, distance(p1, p2)).round(),
equals(10002));
// rounds to 10002
expect(distance.as(LengthUnit.Kilometer, p1, p2), equals(10002));
expect(distance.as(LengthUnit.Meter, p1, p2), equals(10001966));
}); // end of 'Distance between 0 and 90.0' test
test('> Distance between 0 and 90.0 is 10001.96572931165 km ', () {
final distance = Distance(roundResult: false);
final p1 = LatLng(0.0, 0.0);
final p2 = LatLng(90.0, 0.0);
expect(
distance.as(LengthUnit.Kilometer, p1, p2), equals(10001.96572931165));
}); // end of 'Round' test
test('> distance between 0,-180 and 0,180 is 0', () {
final distance = Distance();
final p1 = LatLng(0.0, -180.0);
final p2 = LatLng(0.0, 180.0);
expect(distance(p1, p2), 0);
}); // end of 'distance between 0,-180 and 0,180 is 0' test
group('Vincenty', () {
test('> Test 1', () {
final distance = Distance();
expect(
distance(
LatLng(52.518611, 13.408056), LatLng(51.519475, 7.46694444)),
422592);
expect(
distance.as(LengthUnit.Kilometer, LatLng(52.518611, 13.408056),
LatLng(51.519475, 7.46694444)),
423);
});
}); // End of 'Vincenty' group
group('Haversine - not so accurate', () {
test('> Test 1', () {
final distance = Distance(calculator: const Haversine());
expect(
distance(
LatLng(52.518611, 13.408056), LatLng(51.519475, 7.46694444)),
421786.0);
});
}); // End of 'Haversine' group
});
// End of 'Distance' group
group('Bearing', () {
test('bearing to the same point is 0 degree', () {
final distance = const Distance();
final p = LatLng(0.0, 0.0);
expect(distance.bearing(p, p), equals(0));
});
test('bearing between 0,0 and 90,0 is 0 degree', () {
final distance = const Distance();
final p1 = LatLng(0.0, 0.0);
final p2 = LatLng(90.0, 0.0);
expect(distance.bearing(p1, p2), equals(0));
});
test('bearing between 0,0 and -90,0 is 180 degree', () {
final distance = const Distance();
final p1 = LatLng(0.0, 0.0);
final p2 = LatLng(-90.0, 0.0);
expect(distance.bearing(p1, p2), equals(180));
});
test('bearing between 0,-90 and 0,90 is -90 degree', () {
final distance = const Distance();
final p1 = LatLng(0.0, -90.0);
final p2 = LatLng(0.0, 90.0);
expect(distance.bearing(p1, p2), equals(90));
});
test('bearing between 0,-180 and 0,180 is -90 degree', () {
final distance = const Distance();
final p1 = LatLng(0.0, -180.0);
final p2 = LatLng(0.0, 180.0);
expect(distance.bearing(p1, p2), equals(-90));
expect(normalizeBearing(distance.bearing(p1, p2)), equals(270));
});
}); // End of 'Direction' group
group('Offset', () {
test('offset from 0,0 with bearing 0 and distance 10018.754 km is 90,180',
() {
final distance = const Distance();
final num distanceInMeter = (earthRadius * pi / 2).round();
//print("Dist $distanceInMeter");
final p1 = LatLng(0.0, 0.0);
final p2 = distance.offset(p1, distanceInMeter.round(), 0);
//print(p2);
//print("${decimal2sexagesimal(p2.latitude)} / ${decimal2sexagesimal(p2.longitude)}");
expect(p2.latitude.round(), equals(90));
expect(p2.longitude.round(), equals(180));
});
test('offset from 0,0 with bearing 180 and distance ~ 5.000 km is -45,0',
() {
final distance = const Distance();
final num distanceInMeter = (earthRadius * pi / 4).round();
final p1 = LatLng(0.0, 0.0);
final p2 = distance.offset(p1, distanceInMeter, 180);
// print(p2.round());
// print(p2.toSexagesimal());
expect(p2.latitude.round(), equals(-45));
expect(p2.longitude.round(), equals(0));
});
test('offset from 0,0 with bearing 180 and distance ~ 10.000 km is -90,180',
() {
final distance = const Distance();
final num distanceInMeter = (earthRadius * pi / 2).round();
final p1 = LatLng(0.0, 0.0);
final p2 = distance.offset(p1, distanceInMeter, 180);
expect(p2.latitude.round(), equals(-90));
expect(p2.longitude.round(), equals(180)); // 0 Vincenty
});
test('offset from 0,0 with bearing 90 and distance ~ 5.000 km is 0,45', () {
final distance = const Distance();
final num distanceInMeter = (earthRadius * pi / 4).round();
final p1 = LatLng(0.0, 0.0);
final p2 = distance.offset(p1, distanceInMeter, 90);
expect(p2.latitude.round(), equals(0));
expect(p2.longitude.round(), equals(45));
});
}); // End of 'Offset' group
}
// - Helper --------------------------------------------------------------------------------------
/*
* Copyright (c) 2016, Michael Mitterer (office@mikemitterer.at),
* IT-Consulting and Development Limited.
*
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'package:test/test.dart';
import 'package:latlong2/latlong.dart';
// import 'package:logging/logging.dart';
// Browser
// import "package:console_log_handler/console_log_handler.dart";
// Commandline
// import "package:console_log_handler/print_log_handler.dart";
void main() {
// final Logger _logger = new Logger("test.LatLng");
// configLogging();
group('A group of tests', () {
setUp(() {});
test('> Range', () {
expect(() => LatLng(-80.0, 0.0), returnsNormally);
expect(() => LatLng(-100.0, 0.0), throwsAssertionError);
expect(() => LatLng(80.0, 0.0), returnsNormally);
expect(() => LatLng(100.0, 0.0), throwsAssertionError);
expect(() => LatLng(0.0, -170.0), returnsNormally);
expect(() => LatLng(0.0, -190.0), throwsAssertionError);
expect(() => LatLng(0.0, 170.0), returnsNormally);
expect(() => LatLng(0.0, 190.0), throwsAssertionError);
}); // end of 'Range' test
test('> Rad', () {
expect((LatLng(-80.0, 0.0)).latitudeInRad, -1.3962634015954636);
expect((LatLng(90.0, 0.0)).latitudeInRad, 1.5707963267948966);
expect((LatLng(0.0, 80.0)).longitudeInRad, 1.3962634015954636);
expect((LatLng(0.0, 90.0)).longitudeInRad, 1.5707963267948966);
}); // end of 'Rad' test
test('> toString', () {
expect((LatLng(-80.0, 0.0)).toString(),
'LatLng(latitude:-80.0, longitude:0.0)');
expect((LatLng(-80.123456, 0.0)).toString(),
'LatLng(latitude:-80.123456, longitude:0.0)');
}); // end of 'toString' test
test('> toJson', () {
expect((LatLng(-80.0, 0.0)).toJson(), {
'coordinates': [0.0, -80.0]
});
expect((LatLng(0.0, 80.0)).toJson(), {
'coordinates': [80.0, 0.0]
});
});
test('> fromJson', () {
expect(
LatLng.fromJson({
'coordinates': [0.0, -80.0]
}),
LatLng(-80.0, 0.0));
expect(
LatLng.fromJson({
'coordinates': [80.0, 0.0]
}),
LatLng(0.0, 80.0));
});
test('> equal', () {
expect(LatLng(-80.0, 0.0), LatLng(-80.0, 0.0));
expect(LatLng(-80.0, 0.0), isNot(LatLng(-80.1, 0.0)));
expect(LatLng(-80.0, 0.0), isNot(LatLng(0.0, 80.0)));
}); // end of 'equal' test
});
}
final Matcher throwsAssertionError = throwsA(isA<AssertionError>());
//@TestOn("content-shell")
import 'package:test/test.dart';
import 'package:latlong2/latlong.dart';
// import 'package:logging/logging.dart';
// Browser
// import "package:console_log_handler/console_log_handler.dart";
// Commandline
// import "package:console_log_handler/print_log_handler.dart";
void main() async {
// final Logger _logger = new Logger("test.LengthUnit");
// configLogging();
//await saveDefaultCredentials();
group('LengthUnit', () {
setUp(() {});
test('> Millimeter', () {
expect(LengthUnit.Millimeter.to(LengthUnit.Millimeter, 1.0), 1.0);
expect(LengthUnit.Millimeter.to(LengthUnit.Centimeter, 1.0), 0.1);
expect(LengthUnit.Millimeter.to(LengthUnit.Meter, 1000.0), 1.0);
expect(LengthUnit.Millimeter.to(LengthUnit.Kilometer, 1000000.0), 1);
}); // end of 'Millimeter' test
test('> Centimeter', () {
expect(LengthUnit.Centimeter.to(LengthUnit.Centimeter, 1.0), 1.0);
expect(LengthUnit.Centimeter.to(LengthUnit.Millimeter, 1.0), 10.0);
}); // end of 'Centimeter' test
test('> Meter', () {
expect(LengthUnit.Meter.to(LengthUnit.Meter, 100.0), 100.0);
expect(LengthUnit.Meter.to(LengthUnit.Kilometer, 1.0), 0.001);
}); // end of 'Meter' test
test('> Kilometer', () {
expect(LengthUnit.Kilometer.to(LengthUnit.Kilometer, 1.0), 1.0);
expect(LengthUnit.Kilometer.to(LengthUnit.Meter, 1.0), 1000.0);
}); // end of 'Kilometer' test
test('> Mike', () {
expect((LengthUnit.Mile.to(LengthUnit.Meter, 1.0) * 100).round() / 100,
1609.34);
}); // end of 'Mike' test
});
// End of 'LengthUnit' group
}
// - Helper --------------------------------------------------------------------------------------
//@TestOn("content-shell")
import 'package:test/test.dart';
import 'package:latlong2/latlong.dart';
// import 'package:logging/logging.dart';
// Browser
// import "package:console_log_handler/console_log_handler.dart";
// Commandline
// import "package:console_log_handler/print_log_handler.dart";
final Map<String, LatLng> cities = <String, LatLng>{
'berlin': LatLng(52.518611, 13.408056),
'moscow': LatLng(55.751667, 37.617778),
};
final List<LatLng> route = <LatLng>[
LatLng(51.513357512, 7.45574331),
LatLng(51.515400598, 7.45518541),
LatLng(51.516241842, 7.456494328),
LatLng(51.516722545, 7.459863183),
LatLng(51.517443592, 7.463232037),
LatLng(51.5177507, 7.464755532),
LatLng(51.517657233, 7.466622349),
LatLng(51.51722995, 7.468317505),
LatLng(51.516816015, 7.47011995),
LatLng(51.516308606, 7.471793648),
LatLng(51.515974782, 7.472437378),
LatLng(51.515413951, 7.472845074),
LatLng(51.514559338, 7.472909447),
LatLng(51.512195717, 7.472651955),
LatLng(51.511127373, 7.47140741),
LatLng(51.51029939, 7.469948288),
LatLng(51.509831973, 7.468446251),
LatLng(51.509978876, 7.462481019),
LatLng(51.510913701, 7.460678574),
LatLng(51.511594777, 7.459434029),
LatLng(51.512396029, 7.457695958),
LatLng(51.513317451, 7.45574331),
];
final List<LatLng> westendorf = <LatLng>[
LatLng(47.43074295001961, 12.21235112213462),
LatLng(47.43089093351458, 12.21272597555608),
LatLng(47.43112096728846, 12.21318739290575),
LatLng(47.43136362193013, 12.21357041557469),
LatLng(47.43151718768905, 12.21381341692645),
LatLng(47.43165029999054, 12.2140511609222),
LatLng(47.43197227207169, 12.21443856698021),
];
final List<LatLng> zigzag = <LatLng>[
LatLng(47.43082546234226, 12.21255804885847),
LatLng(47.43103958915331, 12.21268605330973),
LatLng(47.43105710900187, 12.21307899558343),
LatLng(47.43122940724644, 12.21334560213179),
LatLng(47.43140402736853, 12.21345312442578),
LatLng(47.43145463473182, 12.21370919972242),
LatLng(47.43152498372309, 12.21383217398376),
LatLng(47.43154236046533, 12.213861433609),
LatLng(47.43156491014229, 12.21389982585238),
LatLng(47.43170715787343, 12.21411329481371),
LatLng(47.4316056796912, 12.21427241091704),
LatLng(47.43148429441857, 12.21439779676563),
LatLng(47.43144240029867, 12.21446788249065),
LatLng(47.43150069195054, 12.21456420272734),
LatLng(47.4315919174373, 12.21469743884608),
LatLng(47.43163947608171, 12.21477097582562),
LatLng(47.43171300672132, 12.21474044606232),
LatLng(47.43178565483553, 12.21464852517297),
LatLng(47.43186412401507, 12.21455971070946),
LatLng(47.43196361890569, 12.21443596175264)
];
void main() {
// final Logger _logger = new Logger("test.Utils");
// configLogging();
group('Equalize path', () {
test(
'> The total size of a path with 1000m lengt devided by 10sections must have the same'
'length as the base path', () {
final distance = Distance();
final startPos = LatLng(0.0, 0.0);
final endPos = distance.offset(startPos, 1000, 0);
expect(distance(startPos, endPos), 1000);
final path = Path.from(<LatLng>[startPos, endPos]);
expect(path.distance, 1000);
final steps = path.equalize(100, smoothPath: false);
// _exportForGoogleEarth(steps);
expect(steps.distance, 1000);
expect(steps.coordinates.length, 11);
}); // end of '10 intermediate steps in 1000m should have the same length' test
test(
'> 10 smoothd out steps in total have approximatly!!! the same lenght '
'as the base path', () {
final distance = Distance();
final startPos = LatLng(0.0, 0.0);
final endPos = distance.offset(startPos, 1000, 0);
expect(distance(startPos, endPos), 1000);
final path = Path.from(<LatLng>[startPos, endPos]);
expect(path.distance, 1000);
final steps = path.equalize(100, smoothPath: false);
expect(steps.distance, inInclusiveRange(999, 1001));
expect(steps.coordinates.length, 11);
//_exportForGoogleEarth(steps);
for (var index = 0; index < steps.nrOfCoordinates - 1; index++) {
// 46?????
expect(distance(steps[index], steps[index + 1]),
inInclusiveRange(46, 112));
}
}); // end of '10 intermediate steps in 1000m should have the same length' test
test('> Path with 3 sections', () {
final distance = Distance();
final startPos = LatLng(0.0, 0.0);
final pos1 = distance.offset(startPos, 50, 0);
final pos2 = distance.offset(pos1, 15, 0);
final pos3 = distance.offset(pos2, 5, 0);
expect(distance(startPos, pos3), 70);
final path = Path.from(<LatLng>[startPos, pos1, pos2, pos3]);
expect(path.distance, 70);
final steps = path.equalize(30, smoothPath: false);
//_exportForGoogleEarth(steps);
expect(steps.nrOfCoordinates, 4);
}); // end of 'Path with 3 sections' test
test(
'> Reality Test - Westendorf, short, should 210m (same as Google Earth)',
() {
final path = Path.from(westendorf);
expect(path.distance, 210);
// first point to last point!
final distance = Distance();
expect(distance(westendorf.first, westendorf.last), 209);
final steps = path.equalize(5);
expect(steps.nrOfCoordinates, 44);
_exportForGoogleEarth(steps, show: false);
}); // end of 'Reality Test - Westendorf, short' test
test(
'> ZigZag, according to Google-Earth - 282m,'
'first to last point 190m (acc. movable-type.co.uk (Haversine)', () {
final path = Path.from(zigzag);
expect(path.distance, 282);
// first point to last point!
final distance = Distance();
expect(distance(zigzag.first, zigzag.last), 190);
final steps = path.equalize(8, smoothPath: true);
// 282 / 8 = 35,25 + first + last
expect(steps.nrOfCoordinates, 36);
expect(steps.coordinates.length, inInclusiveRange(36, 37));
_exportForGoogleEarth(steps, show: false);
// Distance check makes no sense - path is shorter than the original one!
// double sumDist = 0.0;
// for(int index = 0;index < steps.nrOfCoordinates - 1;index++) {
// sumDist += distance(steps[index],steps[index + 1]);
// }
}); // end of 'ZigZag' test
}); // End of 'Intermediate steps' group
group('PathLength', () {
test('> Distance of empty path should be 0', () {
final path = Path();
expect(path.distance, 0);
}); // end of 'Distance of empty path should be 0' test
test('> Path length should be 3377m', () {
final path = Path.from(route);
expect(path.distance, 3377);
}); // end of 'Path length should be 3377m' test
test('> Path lenght should be 3.377km', () {
final path = Path.from(route);
expect(
round(LengthUnit.Meter.to(LengthUnit.Kilometer, path.distance),
decimals: 3),
3.377);
}); // end of 'Path length should be 3.377km' test
}); // End of 'PathLength' group
group('Center', () {
test(
'> Center between Berlin and Moscow should be near Minsk '
'(54.743683,25.033239)', () {
final path = Path.from([cities['berlin']!, cities['moscow']!]);
expect(path.center.latitude, 54.743683);
expect(path.center.longitude, 25.033239);
}); // end of 'Center' test
}); // End of 'Center' group
group('Utils', () {
setUp(() {});
test('> Round', () {
expect(round(123.1), 123.1);
expect(round(123.123456), 123.123456);
expect(round(123.1234567), 123.123457);
expect(round(123.1234565), 123.123457);
expect(round(123.1234564), 123.123456);
expect(round(123.1234564, decimals: 0), 123);
expect(round(123.1234564, decimals: -1), 120);
expect(round(123.1234564, decimals: -3), 0);
expect(round(523.1234564, decimals: -3), 1000);
expect(round(423.1234564, decimals: -3), 0);
}); // end of 'Round' test
});
// End of 'Utils' group
}
// - Helper --------------------------------------------------------------------------------------
/// Print CSV-date on the cmdline
void _exportForGoogleEarth(final Path steps, {final bool show = true}) {
if (show) {
final distance = Distance();
print('latitude,longitude,distance');
for (var index = 0; index < steps.nrOfCoordinates - 1; index++) {
print(
'${steps[index].latitude}, ${steps[index].longitude}, ${distance(steps[index], steps[index + 1])}');
}
print('${steps.last.latitude}, ${steps.last.longitude}, 0');
}
}
//@TestOn("content-shell")
import 'package:test/test.dart';
import 'package:latlong2/latlong.dart';
// import 'package:logging/logging.dart';
// Browser
// import "package:console_log_handler/console_log_handler.dart";
// Commandline
// import "package:console_log_handler/print_log_handler.dart";
void main() async {
// final Logger _logger = new Logger("test.Sexagesimal");
// configLogging();
//await saveDefaultCredentials();
group('Sexagesimal', () {
setUp(() {});
test('> decimal2sexagesimal', () {
final sexa1 = decimal2sexagesimal(51.519475);
final sexa2 = decimal2sexagesimal(-19.392222222222223);
final sexa3 = decimal2sexagesimal(50.0);
expect(sexa1, '51° 31\' 10.11"');
expect(sexa2, '19° 23\' 32.00"');
expect(sexa3, '50° 00\' 00.00"');
final p1 = LatLng(51.519475, -19.392222222222223);
expect(p1.toSexagesimal(), '51° 31\' 10.11" N, 19° 23\' 32.00" W');
}); // end of 'decimal2sexagesimal' test
test('> sexagesimal2decimal', () {
// the code in the function documentation
final dec1 = sexagesimal2decimal('51° 31\' 10.11"');
expect(dec1, 51.519475);
final dec2 = sexagesimal2decimal('19° 23\' 32.00"');
expect(dec2, 19.392222222222223);
// round value
expect(50.0, sexagesimal2decimal('50° 00\' 00.00"'));
}); // end of 'sexagesimal2decimal' test
test('> sexagesimal2decimal2sexagesimal', () {
final sexa = '51° 31\' 10.11" N, 19° 23\' 32.00" W';
expect(LatLng.fromSexagesimal(sexa).toSexagesimal(), sexa);
}); // end of 'sexagesimal2decimal2sexagesimal' test
});
// End of 'Sexagesimal' group
}
// - Helper --------------------------------------------------------------------------------------
import 'package:test/test.dart';
import 'package:latlong2/spline.dart';
// import 'package:logging/logging.dart';
// Browser
// import "package:console_log_handler/console_log_handler.dart";
// Commandline
// import "package:console_log_handler/print_log_handler.dart";
void main() async {
// final Logger _logger = new Logger("test.CatmullRom");
// configLogging();
group('CatmullRom 1D', () {
setUp(() {});
test('> one dimension', () {
final spline = CatmullRomSpline(1, 2, 2, 1);
expect(spline.position(0.25), 2.09375);
expect(spline.position(0.5), 2.125);
expect(spline.position(0.75), 2.09375);
}); // end of 'one dimension' test
test('> no endpoints', () {
final spline = CatmullRomSpline.noEndpoints(1, 2);
expect(spline.position(0.25), 1.203125);
expect(spline.position(0.5), 1.5);
expect(spline.percentage(50), 1.5);
expect(spline.position(0.75), 1.796875);
}); // end of 'no endpoints' test
});
// End of 'CatmullRom 1D' group
group('CatmullRom 2D', () {
test('> Simple values', () {
final spline = CatmullRomSpline2D(
Point2D(1, 1), Point2D(2, 2), Point2D(2, 2), Point2D(1, 1));
expect(spline.position(0.25).x, 2.09375);
expect(spline.position(0.25).y, 2.09375);
expect(spline.position(0.5).x, 2.125);
expect(spline.position(0.5).y, 2.125);
expect(spline.percentage(50).x, 2.125);
expect(spline.percentage(50).y, 2.125);
expect(spline.position(0.75).x, 2.09375);
expect(spline.position(0.75).y, 2.09375);
});
test('> no Endpoints', () {
final spline =
CatmullRomSpline2D.noEndpoints(Point2D(1, 1), Point2D(2, 2));
expect(spline.position(0.25).x, 1.203125);
expect(spline.position(0.25).y, 1.203125);
}); // end of 'no Endpoints' test
test('> Exception', () {
final spline =
CatmullRomSpline2D.noEndpoints(Point2D(1, 1), Point2D(2, 2));
expect(() => spline.position(3.0).x, throwsArgumentError);
}); // end of 'Exception' test
}); // End of 'CatmullRom 2D' group
}
// - Helper --------------------------------------------------------------------------------------
import 'package:grinder/grinder.dart';
main(final List<String> args) => grind(args);
@DefaultTask()
@Depends(test)
build() {
}
@Task()
@Depends(analyze, testUnit)
test() {
}
@Task()
testUnit() {
new TestRunner().testAsync(files: "test/unit");
// All tests with @TestOn("content-shell") in header
// new TestRunner().test(files: "test/unit",platformSelector: "content-shell");
}
@Task()
analyze() {
final List<String> libs = [
"lib/latlong.dart"
];
libs.forEach((final String lib) => Analyzer.analyze(lib));
Analyzer.analyze("test");
}
@Task()
clean() => defaultClean();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment