aves/plugins/aves_map/lib/src/geo_utils.dart
2022-04-25 17:12:25 +09:00

134 lines
5.2 KiB
Dart

import 'dart:math';
import 'package:latlong2/latlong.dart';
class GeoUtils {
static LatLng getLatLngCenter(List<LatLng> points) {
double x = 0;
double y = 0;
double z = 0;
points.forEach((point) {
final lat = point.latitudeInRad;
final lng = point.longitudeInRad;
x += cos(lat) * cos(lng);
y += cos(lat) * sin(lng);
z += sin(lat);
});
final pointCount = points.length;
x /= pointCount;
y /= pointCount;
z /= pointCount;
final lng = atan2(y, x);
final hyp = sqrt(x * x + y * y);
final lat = atan2(z, hyp);
return LatLng(radianToDeg(lat), radianToDeg(lng));
}
static bool contains(LatLng sw, LatLng ne, LatLng? point) {
if (point == null) return false;
final lat = point.latitude;
final lng = point.longitude;
final south = sw.latitude;
final north = ne.latitude;
final west = sw.longitude;
final east = ne.longitude;
return (south <= lat && lat <= north) && (west <= east ? (west <= lng && lng <= east) : (west <= lng || lng <= east));
}
// cf https://epsg.io/EPSGCODE.proj4
// cf https://github.com/stevage/epsg
// cf https://github.com/maRci002/proj4dart/blob/master/test/data/all_proj4_defs.dart
static String? epsgToProj4(int? epsg) {
// `32767` refers to user defined values
if (epsg == null || epsg == 32767) return null;
if (3038 <= epsg && epsg <= 3051) {
// ETRS89 / UTM (N-E)
final zone = epsg - 3012;
return '+proj=utm +zone=$zone +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs';
} else if (26700 <= epsg && epsg <= 26799) {
// US State Plane (NAD27): 267xx/320xx
if (26703 <= epsg && epsg <= 26722) {
final zone = epsg - 26700;
return '+proj=utm +zone=$zone +datum=NAD27 +units=m +no_defs';
}
// NAD27 datum requires loading `nadgrids` for accurate transformation:
// cf https://github.com/proj4js/proj4js/pull/363
// cf https://github.com/maRci002/proj4dart/issues/8
if (epsg == 26746) {
// NAD27 / California zone VI
return '+proj=lcc +lat_1=33.88333333333333 +lat_2=32.78333333333333 +lat_0=32.16666666666666 +lon_0=-116.25 +x_0=609601.2192024384 +y_0=0 +datum=NAD27 +units=us-ft +no_defs';
} else if (epsg == 26771) {
// NAD27 / Illinois East
return '+proj=tmerc +lat_0=36.66666666666666 +lon_0=-88.33333333333333 +k=0.9999749999999999 +x_0=152400.3048006096 +y_0=0 +datum=NAD27 +units=us-ft +no_defs';
}
} else if ((26900 <= epsg && epsg <= 26999) || (32100 <= epsg && epsg <= 32199)) {
// US State Plane (NAD83): 269xx/321xx
if (epsg == 26966) {
// NAD83 Georgia East
return '+proj=tmerc +lat_0=30 +lon_0=-82.16666666666667 +k=0.9999 +x_0=200000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs';
}
} else if (32200 <= epsg && epsg <= 32299) {
// WGS72 / UTM northern hemisphere: 322zz where zz is UTM zone number
final zone = epsg - 32200;
return '+proj=utm +zone=$zone +ellps=WGS72 +towgs84=0,0,4.5,0,0,0.554,0.2263 +units=m +no_defs';
} else if (32300 <= epsg && epsg <= 32399) {
// WGS72 / UTM southern hemisphere: 323zz where zz is UTM zone number
final zone = epsg - 32300;
return '+proj=utm +zone=$zone +south +ellps=WGS72 +towgs84=0,0,4.5,0,0,0.554,0.2263 +units=m +no_defs';
} else if (32400 <= epsg && epsg <= 32460) {
// WGS72BE / UTM northern hemisphere: 324zz where zz is UTM zone number
final zone = epsg - 32400;
return '+proj=utm +zone=$zone +ellps=WGS72 +towgs84=0,0,1.9,0,0,0.814,-0.38 +units=m +no_defs';
} else if (32500 <= epsg && epsg <= 32599) {
// WGS72BE / UTM southern hemisphere: 325zz where zz is UTM zone number
final zone = epsg - 32500;
return '+proj=utm +zone=$zone +south +ellps=WGS72 +towgs84=0,0,1.9,0,0,0.814,-0.38 +units=m +no_defs';
} else if (32600 <= epsg && epsg <= 32699) {
// WGS84 / UTM northern hemisphere: 326zz where zz is UTM zone number
final zone = epsg - 32600;
return '+proj=utm +zone=$zone +datum=WGS84 +units=m +no_defs';
} else if (32700 <= epsg && epsg <= 32799) {
// WGS84 / UTM southern hemisphere: 327zz where zz is UTM zone number
final zone = epsg - 32700;
return '+proj=utm +zone=$zone +south +datum=WGS84 +units=m +no_defs';
}
return null;
}
}
// cf https://www.maptiler.com/google-maps-coordinates-tile-bounds-projection/
class MapServiceHelper {
final int tileSize;
late final double initialResolution, originShift;
MapServiceHelper(this.tileSize) {
initialResolution = 2 * pi * 6378137 / tileSize;
originShift = 2 * pi * 6378137 / 2.0;
}
int matrixSize(int zoomLevel) {
return 1 << zoomLevel;
}
Point<double> pixelsToMeters(double px, double py, int zoomLevel) {
double res = resolution(zoomLevel);
double mx = px * res - originShift;
double my = -py * res + originShift;
return Point(mx, my);
}
double resolution(int zoomLevel) {
return initialResolution / matrixSize(zoomLevel);
}
Point<double> tileTopLeft(int tx, int ty, int zoomLevel) {
final px = tx * tileSize;
final py = ty * tileSize;
return pixelsToMeters(px.toDouble(), py.toDouble(), zoomLevel);
}
}