Google Maps Utils for Flutter

Google Maps Utils for Dart/Flutter

A faithful Dart port of the core geometry classes from Google's android-maps-utils library.

Pub Version Pub Points Popularity Pub Likes GitHub Stars GitHub Forks GitHub Issues License CI


✨ Features

Class What it does
SphericalUtils Distances, headings, offsets, interpolation, areas, and bounding boxes on a sphere
PolyUtils Polyline encoding/decoding, Douglas-Peucker simplification, point-in-polygon, and on-path/on-edge tests
MathUtils Low-level haversine, Mercator projections, clamping, and wrapping helpers

All calculations use the same spherical algorithms as the original Android Java/Kotlin library β€” results are identical.


πŸš€ Getting Started

Installation

Add to your pubspec.yaml:

dependencies:
  google_maps_utils: ^4.0.0

Then run:

dart pub get

Import

import 'package:google_maps_utils/google_maps_utils.dart';

Quick Start β€” Facade Pattern

Use the GoogleMapsUtils class as a unified namespace:

// Spherical geometry
final distance = GoogleMapsUtils.spherical.computeDistanceBetween(from, to);
final heading = GoogleMapsUtils.spherical.computeHeading(from, to);

// Polyline utilities
final path = GoogleMapsUtils.poly.decode(encodedString);
final simplified = GoogleMapsUtils.poly.simplify(path, 5000.0);

// Math helpers
final wrapped = GoogleMapsUtils.math.wrap(190.0, -180.0, 180.0); // -170.0

The original static classes (SphericalUtils, PolyUtils, MathUtils) remain available for direct access if you prefer.


πŸ“– Usage

Distance Between Two Points

final from = Point<double>(0.0, 0.0);
final to = Point<double>(10.0, 5.0);

final distance = SphericalUtils.computeDistanceBetween(from, to);
// 1241932.5985192063 meters

Heading (Bearing)

final heading = SphericalUtils.computeHeading(from, to);
// 26.302486345342523 degrees (clockwise from North)

Angle Between Points

final angle = SphericalUtils.computeAngleBetween(from, to);
// 0.19493500057547358 radians (unit-sphere arc distance)

Compute Offset (Move a Point)

// Move 1000 meters east (heading 90Β°) from the origin
final origin = Point<double>(0.0, 0.0);
final destination = SphericalUtils.computeOffset(origin, 1000.0, 90.0);
// Returns the Point at the new location

Compute Offset Origin (Reverse Lookup)

// Given a destination, distance, and heading β€” find where you started
final origin = SphericalUtils.computeOffsetOrigin(destination, 1000.0, 90.0);
// Returns Point? (null if no solution exists)

Interpolation (SLERP)

// Find the point 25% of the way between two locations
final quarter = SphericalUtils.interpolate(from, to, 0.25);

Path Length

final path = <Point<double>>[
  Point(0.0, 0.0),
  Point(1.0, 1.0),
  Point(2.0, 0.0),
];

final length = SphericalUtils.computeLength(path);
// Total distance in meters along the path

Compass Cardinal Direction

final cardinal = SphericalUtils.getCardinal(45.0);
// 'NE'

final cardinal2 = SphericalUtils.getCardinal(200.0);
// 'SSW'

Polyline Decoding

// Decode a Google Encoded Polyline string into coordinates
final path = PolyUtils.decode(
    'wjiaFz`hgQs}GmmBok@}vX|cOzKvvT`uNutJz|UgqAglAjr@ijBz]opA');
// Returns List<Point<double>> with 17 points

Polyline Encoding

// Encode coordinates back to a compact string
final encoded = PolyUtils.encode(path);

Douglas-Peucker Simplification

// Reduce points while preserving shape (tolerance in meters)
final simplified = PolyUtils.simplify(path, 5000.0);
// 17 points β†’ 6 points

Point-in-Polygon

final point = Point<double>(-31.623060, -60.686690);

final polygon = <Point<double>>[
  Point(-31.624115, -60.688734),
  Point(-31.624115, -60.684657),
  Point(-31.621594, -60.686717),
  Point(-31.624115, -60.688734),
];

final isInside = PolyUtils.containsLocationPoly(point, polygon);
// true

// Also supports geodesic (great-circle) edges:
final isInsideGeodesic = PolyUtils.containsLocationPoly(
  point, polygon, geodesic: true,
);

Point-on-Path Detection

final route = <Point<double>>[
  Point(0.0, 0.0),
  Point(0.0, 10.0),
];

// Is the point on or near the polyline? (default tolerance: 0.1m)
final isOnPath = PolyUtils.isLocationOnPath(
  Point(0.0, 5.0), route, true, // geodesic
);
// true

// Get which segment the point falls on
final segmentIndex = PolyUtils.locationIndexOnPath(
  Point(0.0, 5.0), route, true,
);
// 0 (between route[0] and route[1])

Point-on-Edge (Polygon Boundary)

final square = <Point<double>>[
  Point(0.0, 0.0),
  Point(0.0, 10.0),
  Point(10.0, 10.0),
  Point(10.0, 0.0),
];

// Includes the closing segment (last→first)
final isOnEdge = PolyUtils.isLocationOnEdge(
  Point(5.0, 0.0), square, true,
);
// true

Distance to a Line Segment

final p = Point<double>(-23.54545, -23.898098);
final start = Point<double>(0.0, 0.0);
final end = Point<double>(10.0, 5.0);

final dist = PolyUtils.distanceToLine(p, start, end);
// 3675538.019968191 meters

Compute Area

final area = SphericalUtils.computeArea(polygon);
// Area in square meters

final signedArea = SphericalUtils.computeSignedArea(polygon);
// Positive = counter-clockwise, negative = clockwise

Bounding Boxes

// Create bounds from a center point + radius
final bounds = SphericalUtils.toBounds(-23.55, -46.63, 1000.0);

// Create bounds from a list of points
final bounds = SphericalUtils.toBoundsFromPoints(path);

// Get the center of a bounds
final center = SphericalUtils.centerFromLatLngBounds(bounds);

// Split bounds into a grid (divisionΒ² sub-bounds)
final tiles = SphericalUtils.toSubBounds(bounds, division: 3);
// Returns 9 sub-bounds

Closed Polygon Check

PolyUtils.isClosedPolygon(polygon); // true if first == last point

Custom Tolerance (On-Path / On-Edge)

// Default tolerance is 0.1 meters. Use custom tolerance for proximity:
final isNear = PolyUtils.isLocationOnPathTolerance(
  point, polyline, true, 50.0, // 50 meters tolerance
);

// Same for edges:
final isNearEdge = PolyUtils.isLocationOnEdgeTolerance(
  point, polygon, true, 50.0,
);

// With index:
final idx = PolyUtils.locationIndexOnPathTolerance(
  point, polyline, true, 50.0,
);

MathUtils (Low-Level Helpers)

// Clamp a value to a range
MathUtils.clamp(15.0, 0.0, 10.0); // 10.0

// Wrap a value into [min, max) β€” useful for longitude
MathUtils.wrap(190.0, -180.0, 180.0); // -170.0

// Non-negative modulo
MathUtils.mod(-1.0, 360.0); // 359.0

// Mercator projection (radians)
final y = MathUtils.mercator(latInRadians);
final lat = MathUtils.inverseMercator(y);

// Haversine / inverse haversine
final h = MathUtils.hav(angleInRadians);
final angle = MathUtils.arcHav(h);

// Haversine distance on unit sphere
final havDist = MathUtils.havDistance(lat1, lat2, dLng);

Degree / Radian Conversions

SphericalUtils.toRadians(90.0);  // 1.5707963... (Ο€/2)
SphericalUtils.toDegrees(pi);    // 180.0

πŸ“‹ Full Example

See example/example.dart for a complete runnable demo covering all features.

Click to expand example output
Heading: 26.302486345342523 degrees
Angle: 0.19493500057547358 radians
Distance to Line: 3675538.019968191 meters
path size length: 17
simplified path: wjiaFz`hgQcjIke\t{d@|aOutJz|UokC}xWomJdjM
path size simplified length: 6
Distance: 1241932.5985192063 meters
Distance: 1066.7243813716539 meters of polygon
point is inside polygon?: true

πŸ“ API Reference

SphericalUtils

Method Description
computeDistanceBetween(from, to) Distance in meters between two points
computeHeading(from, to) Heading in degrees [-180, 180)
computeAngleBetween(from, to) Angle in radians (unit-sphere distance)
computeOffset(from, distance, heading) Point at a given distance/heading
computeOffsetOrigin(to, distance, heading) Inverse of computeOffset
interpolate(from, to, fraction) Spherical interpolation (SLERP)
computeLength(path) Total path length in meters
computeArea(path) Enclosed area in mΒ²
computeSignedArea(path) Signed area (determines winding)
distanceRadians(lat1, lng1, lat2, lng2) Arc distance on unit sphere (radians in, radians out)
toBounds(lat, lng, radius) Bounding box from center + radius
toBoundsFromPoints(points) Bounding box from point list
centerFromLatLngBounds(bounds) Center point of a bounds
toSubBounds(bounds, division:) Split bounds into a grid
getCardinal(angle) 16-point compass abbreviation
toRadians(deg) Degrees to radians
toDegrees(rad) Radians to degrees

PolyUtils

Method Description
decode(encoded) Decode a polyline string to points
encode(path) Encode points to a polyline string
simplify(poly, tolerance) Douglas-Peucker simplification
containsLocationPoly(point, polygon) Spherical point-in-polygon test
isLocationOnPath(point, polyline, geodesic) Point-on-polyline test (0.1m tolerance)
isLocationOnPathTolerance(point, polyline, geodesic, tolerance) Point-on-polyline with custom tolerance
isLocationOnEdge(point, polygon, geodesic) Point-on-polygon-edge test (0.1m tolerance)
isLocationOnEdgeTolerance(point, polygon, geodesic, tolerance) Point-on-edge with custom tolerance
locationIndexOnPath(point, polyline, geodesic) Segment index or -1
locationIndexOnPathTolerance(point, poly, geodesic, tolerance) Segment index with custom tolerance
locationIndexOnEdgeOrPath(point, poly, closed, geodesic, tolerance) Full control: closed/open + tolerance
distanceToLine(point, start, end) Distance to a line segment
isClosedPolygon(poly) Whether first == last point

MathUtils

Method Description
earthRadius Earth's mean radius in meters (6371008.7714)
clamp(x, low, high) Restrict value to range
wrap(n, min, max) Wrap into [min, max)
mod(x, m) Non-negative modulo
hav(x) Haversine
arcHav(x) Inverse haversine
sinFromHav(h) sin(|x|) given hav(x)
havFromSin(x) hav(asin(x))
sinSumFromHav(x, y) sin(arcHav(x) + arcHav(y))
mercator(lat) Latitude (radians) β†’ Mercator Y
inverseMercator(y) Mercator Y β†’ latitude (radians)
havDistance(lat1, lat2, dLng) Haversine distance on unit sphere

πŸ“Š Status

3 of 78 classes from android-maps-utils have been converted β€” these are the most widely used. Need another class? Open an issue and I'll prioritize it.


πŸ’š Sponsor

This package is proudly sponsored by bus2.me.

If this package saves you time, consider supporting its development.



🀝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes with tests
  4. Ensure dart analyze --fatal-infos and dart test pass
  5. Open a Pull Request

πŸ“„ License

This project is licensed under the Apache License 2.0 β€” see the LICENSE file for details.

Original Java source: Copyright 2008, 2013 Google Inc.

Libraries

google_maps_utils
Google Maps Utils β€” a port of the android-maps-utils library.
google_maps_utils_facade
math_utils
poly_utils
spherical_utils
utils/stack