网上有关这些的东西很多,但是试过之后有的计算偏差大一点,有的小一点。下面这几个相关计算我自己试过之后相对来说计算的误差小一点。
1、已知两点经纬度计算方位角
/**
* 以真北为0度起点,由东向南向西顺时针旋转360度,主要是用于控制象限。
* 根据2点经纬度,计算方位角
* 给定2点,获得经纬度
* 起点经纬度,都是以度为单位
* 终点经纬度,都是以度为单位
*/
public static double computeAzimuth(LatLng la1, LatLng la2) {
double lat1 = la1.getLatitude(), lon1 = la1.getLongitude(), lat2 = la2.getLatitude(),
lon2 = la2.getLongitude();
double result = 0.0;
int ilat1 = (int) (0.50 + lat1 * 360000.0);
int ilat2 = (int) (0.50 + lat2 * 360000.0);
int ilon1 = (int) (0.50 + lon1 * 360000.0);
int ilon2 = (int) (0.50 + lon2 * 360000.0);
lat1 = Math.toRadians(lat1);
lon1 = Math.toRadians(lon1);
lat2 = Math.toRadians(lat2);
lon2 = Math.toRadians(lon2);
if ((ilat1 == ilat2) && (ilon1 == ilon2)) {
return result;
} else if (ilon1 == ilon2) {
if (ilat1 > ilat2)
result = 180.0;
} else {
double c = Math
.acos(Math.sin(lat2) * Math.sin(lat1) + Math.cos(lat2)
* Math.cos(lat1) * Math.cos((lon2 - lon1)));
double A = Math.asin(Math.cos(lat2) * Math.sin((lon2 - lon1))
/ Math.sin(c));
result = Math.toDegrees(A);
if ((ilat2 > ilat1) && (ilon2 > ilon1)) {
} else if ((ilat2 < ilat1) && (ilon2 < ilon1)) {
result = 180.0 - result;
} else if ((ilat2 < ilat1) && (ilon2 > ilon1)) {
result = 180.0 - result;
} else if ((ilat2 > ilat1) && (ilon2 < ilon1)) {
result += 360.0;
}
}
return result;
}2、已知一点经纬度、方位角和距离,求另一点经纬度
/*
* 大地坐标系资料WGS-84 长半径a=6378137 短半径b=6356752.3142 扁率f=1/298.2572236
*/
/**
* 长半径a=6378137
*/
private static double a = 6378137;
/**
* 短半径b=6356752.3142
*/
private static double b = 6356752.3142;
/**
* 扁率f=1/298.2572236
*/
private static double f = 1 / 298.2572236;
/**
* 计算另一点经纬度
*
* @param, lon
* 经度
* @param, lat
* 维度
* @param, lonlat
* 已知点经纬度
* @param, brng
* 方位角 度
* @param, dist
* 距离(米)
* 已知一点经纬度,方位角,距离,求另一点经纬度
*/
public static LatLng getLatlngByFixedPointAziDistance(double brng, double dist, LatLng fixedPoint) {
double lon = fixedPoint.getLongitude();
double lat = fixedPoint.getLatitude();
double alpha1 = rad(brng);
double sinAlpha1 = Math.sin(alpha1);
double cosAlpha1 = Math.cos(alpha1);
double tanU1 = (1 - f) * Math.tan(rad(lat));
double cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1));
double sinU1 = tanU1 * cosU1;
double sigma1 = Math.atan2(tanU1, cosAlpha1);
double sinAlpha = cosU1 * sinAlpha1;
double cosSqAlpha = 1 - sinAlpha * sinAlpha;
double uSq = cosSqAlpha * (a * a - b * b) / (b * b);
double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
double cos2SigmaM = 0;
double sinSigma = 0;
double cosSigma = 0;
double sigma = dist / (b * A), sigmaP = 2 * Math.PI;
while (Math.abs(sigma - sigmaP) > 1e-12) {
cos2SigmaM = Math.cos(2 * sigma1 + sigma);
sinSigma = Math.sin(sigma);
cosSigma = Math.cos(sigma);
double 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 = dist / (b * A) + deltaSigma;
}
double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
double lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
(1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp));
double lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
double L = lambda - (1 - C) * f * sinAlpha
* (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
double revAz = Math.atan2(sinAlpha, -tmp); // final bearing
//System.out.println(revAz);
//Log.e("方位角",String.valueOf(revAz));
//Log.e("经纬度",String.valueOf(deg(lat2))+"经度"+String.valueOf(lon+deg(L)));
//System.out.println(+","+);
return new LatLng(deg(lat2), lon + deg(L));
}3、已知两个坐标和其对应的方位角,求另一点坐标
public static LatLng getLatlngByTwoFixedPointAziIntersect(double aziOne, double aziTwo, LatLng fixedPointOne, LatLng fixedPointTwo) {
double azi;
LatLng latLng;
if (fixedPointOne.getLongitude() > fixedPointTwo.getLongitude()) {
azi = aziOne;
latLng = fixedPointOne;
aziOne = aziTwo;
fixedPointOne = fixedPointTwo;
aziTwo = azi;
fixedPointTwo = latLng;
}
Double aziAB = computeAzimuth(fixedPointOne, fixedPointTwo);
Double aziBA = 180 + aziAB;
if (0 <= aziOne && aziOne < 180) {
if (aziOne <= aziAB) {
if (aziOne <= aziTwo && aziTwo < aziBA) {
Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
return new LatLng();
}
}
if (aziOne > aziAB) {
if ((0 <= aziTwo && aziTwo <= aziOne) || (aziBA < aziTwo && aziTwo <= 360)) {
Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
return new LatLng();
}
}
}
if (180 <= aziOne && aziOne < 270) {
if ((0 <= aziTwo && aziTwo <= aziOne) || (aziBA < aziTwo && aziTwo < 360)) {
Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
return new LatLng();
}
}
if (270 <= aziOne && aziOne < 360) {
if ((0 <= aziTwo && aziTwo < aziBA) || (aziOne < aziTwo && aziTwo < 360)) {
Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
return new LatLng();
}
}
double k1 = Math.tan(rad(90 - aziOne));
double k2 = Math.tan(rad(90 - aziTwo));
double y1 = fixedPointOne.getLatitude();
double x1 = fixedPointOne.getLongitude();
double y2 = fixedPointTwo.getLatitude();
double x2 = fixedPointTwo.getLongitude();
double lon = (y2 - y1 + k1 * x1 - k2 * x2) / (k1 - k2);
double lat = (k1 * y2 - k2 * y1 + k1 * k2 * x1 - k1 * k2 * x2) / (k1 - k2);
/* if (0 <= aziOne && aziOne < 180) {
if (aziOne < aziAB) {
if (lat < y1) {
Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
return new LatLng();
}
}
if (aziOne > aziAB) {
if (lat > y2) {
Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
return new LatLng();
}
}
}*/
if (lat > 90 || lat < -90) {
Toast.makeText(MyApplication.getContextObject(), "不能相交,请重新输入方位角", Toast.LENGTH_SHORT).show();
return new LatLng();
}
return new LatLng(lat, lon);
}度与弧度的转换关系
/**
* 度换成弧度
*
* @param d 度
* @return 弧度
*/
private static double rad(double d) {
return d * Math.PI / 180.0;
}
/**
* 弧度换成度
*
* @param x 弧度
* @return 度
*/
private static double deg(double x) {
return x * 180 / Math.PI;
}4、拓扑关系的相关运算
public class Topology {
/**
* 判断点是否在面内
*
* @param polygon 组成多边形的坐标串 多变形节点不能少于3
* @param point 测试的点
* @return 是否在多边形内
* @throws IllegalArgumentException
*/
public static boolean isPointInPolygon(List<LatLng> polygon, LatLng point) throws IllegalArgumentException {
if (polygon.size() < 3) {
throw new IllegalArgumentException("polygon 节点少于3");
}
LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.includes(polygon);
LatLngBounds bounds = builder.build();
if (!bounds.contains(point)) return false;
LatLng far = new LatLng(point.getLatitude(), -180.0); //向正西方向做一条射线
LineSegment ray = new LineSegment(point, far);
int intersectionCount = 0;
int count = polygon.size();
for (int i = 0; i < count; i++) {
LatLng latLng1 = polygon.get(i);
LatLng latLng2 = polygon.get((i + 1) % count);
LineSegment lineSeg = new LineSegment(latLng1, latLng2);
if (isPointOnLineSegment(point, lineSeg)) return true;
if (isSameDouble(latLng2.getLatitude(), latLng1.getLatitude())) continue;
if (isSameDouble(latLng1.getLatitude(), point.getLatitude()) && (latLng1.getLatitude() > latLng2.getLatitude())) {
intersectionCount++;
} else if (isSameDouble(latLng2.getLatitude(), point.getLatitude()) && (latLng2.getLatitude() > latLng1.getLatitude())) {
intersectionCount++;
} else {
if (isLineSegmentIntersect(lineSeg, ray)) {
intersectionCount++;
}
}
}
return (intersectionCount & 1) == 1;
}
public static class LineSegment {
public LatLng start;
public LatLng end;
private LatLngBounds bounds;
public LineSegment(LatLng start, LatLng end) {
this.start = start;
this.end = end;
}
public LatLngBounds getBounds() {
if (bounds == null) {
LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.include(start).include(end);
bounds = builder.build();
}
return bounds;
}
}
/**
* 线段是否相交
*
* @param l1
* @param l2
* @return
*/
public static boolean isLineSegmentIntersect(LineSegment l1, LineSegment l2) {
if (isLineSegmentExclusive(l1, l2)) return false; //矩形不相交
double slat1 = l1.start.getLatitude();
double slon1 = l1.start.getLongitude();
double elat1 = l1.end.getLatitude();
double elon1 = l1.end.getLongitude();
double slat2 = l2.start.getLatitude();
double slon2 = l2.start.getLongitude();
double elat2 = l2.end.getLatitude();
double elon2 = l2.end.getLongitude();
//跨立试验
double p1xq = crossProduct(slon1 - slon2, slat1 - slat2, elon2 - slon2, elat2 - slat2);
double p2xq = crossProduct(elon1 - slon2, elat1 - slat2, elon2 - slon2, elat2 - slat2);
double q1xp = crossProduct(slon2 - slon1, slat2 - slat1, elon1 - slon1, elat1 - slat1);
double q2xp = crossProduct(elon2 - slon1, elat2 - slat1, elon1 - slon1, elat1 - slat1);
return (p1xq * p2xq <= 0) && (q1xp * q2xp <= 0);
}
/**
* 线段 包围矩形是否 不相交
*
* @param l1
* @param l2
* @return
*/
public static boolean isLineSegmentExclusive(LineSegment l1, LineSegment l2) {
double W1 = Math.min(l1.start.getLongitude(), l1.end.getLongitude());
double E1 = Math.max(l1.start.getLongitude(), l1.end.getLongitude());
double N1 = Math.max(l1.start.getLatitude(), l1.end.getLatitude());
double S1 = Math.min(l1.start.getLatitude(), l1.end.getLatitude());
double W2 = Math.min(l2.start.getLongitude(), l2.end.getLongitude());
double E2 = Math.max(l2.start.getLongitude(), l2.end.getLongitude());
double N2 = Math.max(l2.start.getLatitude(), l2.end.getLatitude());
double S2 = Math.min(l2.start.getLatitude(), l2.end.getLatitude());
if (N1 < S2) return true;
if (S1 > N2) return true;
if (E1 < W2) return true;
if (W1 > E2) return true;
return false;
}
/**
* 点是否在线段上
*
* @param point
* @param line
* @return
*/
public static boolean isPointOnLineSegment(LatLng point, LineSegment line) {
LatLngBounds.Builder builder = new LatLngBounds.Builder();
LatLngBounds bounds = builder.include(line.start).include(line.end).build();
if (!bounds.contains(point)) {
return false;
}
LatLng start = line.start;
LatLng end = line.end;
double cp = crossProduct(end.getLongitude() - start.getLongitude(), end.getLatitude() - start.getLongitude(),
point.getLongitude() - start.getLongitude(), point.getLatitude() - start.getLatitude());
return Math.abs(cp) < 0.000000001;
}
/**
* 点到线段的距离
*
* @param point
* @param lineSegment
* @return
*/
public static double point2LineSegment(LatLng point, LineSegment lineSegment) {
double dis1 = point2Point(point, lineSegment.start);
double dis2 = point2Point(point, lineSegment.end);
double dis3 = point2Line(point, lineSegment);
return Math.min(dis1, Math.min(dis2, dis3));
}
/**
* 点到直线的距离
*
* @param point
* @param line
* @return
*/
public static double point2Line(LatLng point, LineSegment line) {
//先求过点 point 与 line垂直的直线与line 的交点
double x1 = line.start.getLongitude();
double x2 = line.end.getLongitude();
double y1 = line.start.getLatitude();
double y2 = line.end.getLatitude();
double xp = point.getLongitude();
double yp = point.getLatitude();
double x, y;
if (y1 == y2) {
y = y1;
x = xp;
return point.distanceTo(new LatLng(y, x));
} else if (x1 == x2) {
x = x1;
y = yp;
return point.distanceTo(new LatLng(y, x));
} else {
double k = (x2 - x1) / (y1 - y2);
double b = yp - (k * xp);
double k1 = (y2 - y1) / (x2 - x1);
double b1 = y1 - (k1 * x1);
x = (b1 - b) / (k - k1);
y = k * x + b;
return point.distanceTo(new LatLng(y, x));
}
}
/**
* 线段到面的距离
*
* @param lineSegment
* @param polygon
* @return
*/
public static double line2Polygon(LineSegment lineSegment, List<LatLng> polygon) {
//先判断线是否与面相交
double minDistance = Double.MAX_VALUE;
int count = polygon.size();
for (int i = 0; i < count; i++) {
LatLng latLng1 = polygon.get(i);
double dis = point2Line(latLng1, lineSegment);
minDistance = Math.min(dis, minDistance);
LatLng latLng2 = polygon.get((i + 1) % count);
LineSegment lineSeg = new LineSegment(latLng1, latLng2);
//如果相交,返回0
if (isLineSegmentIntersect(lineSeg, lineSegment)) {
return 0;
}
}
return minDistance;
}
/**
* 取模运算
*
* @param lineSegment
* @return
*/
private static double mod(LineSegment lineSegment) {
double x = lineSegment.end.getLongitude() - lineSegment.start.getLongitude();
double y = lineSegment.end.getLatitude() - lineSegment.start.getLatitude();
return Math.sqrt(x * x + y * y);
}
/**
* 点到点的距离
*
* @param latLng1
* @param latLng2
* @return
*/
public static double point2Point(LatLng latLng1, LatLng latLng2) {
return latLng1.distanceTo(latLng2);
}
/**
* 点和线段是否接近
*
* @param buffer 容差
* @param point 被判断的点
* @param lienStart 线段起点
* @param lineEnd 线段终点
* @return
*/
public static boolean isNearBy(LatLng point, LatLng lienStart, LatLng lineEnd, double buffer) {
//先使用经纬度筛选一遍
LineSegment lineSegment = new LineSegment(lienStart, lineEnd);
double dis = buffer / 111000; //换算为度
LatLngBounds bounds = lineSegment.getBounds();
if (bounds.getLatNorth() + dis < point.getLatitude()) return false;
if (bounds.getLatSouth() - dis > point.getLatitude()) return false;
if (bounds.getLonEast() + dis < point.getLongitude()) return false;
if (bounds.getLonWest() - dis > point.getLongitude()) return false;
double distance = Topology.point2LineSegment(point, lineSegment);
return distance <= buffer;
}
/**
* 求两条直线的交点
* 没有考虑重合的情况,重合的情况,这里返回不相交
*
* @param start1
* @param end1
* @param start2
* @param end2
* @return
*/
public static LatLng lineInterSection(LatLng start1, LatLng end1, LatLng start2, LatLng end2) {
//先判断是否相交
double deltaX1 = end1.getLongitude() - start1.getLongitude();
double deltaX2 = end2.getLongitude() - start2.getLongitude();
double deltaY1 = end1.getLatitude() - start1.getLatitude();
double deltaY2 = end2.getLatitude() - start2.getLatitude();
if (deltaX1 == 0.0 && deltaX2 == 0.0) return null;
double k1 = deltaY1 / deltaX1;
double k2 = deltaY2 / deltaX2;
double b1 = start1.getLatitude() - k1 * start1.getLongitude();
double b2 = start2.getLatitude() - k2 * start2.getLongitude();
double x = (b2 - b1) / (k1 - k2);
double y = k1 * x + b1;
return new LatLng(y, x);
}
/**
* 计算总路程
*
* @param latLngList
* @return 总里程(公里)
*/
public static double computeDistance(final List<LatLng> latLngList) {
if (latLngList.size() < 1) return 0.0;
double distance = 0.0;
int count = latLngList.size();
for (int i = 1; i < count; i++) {
distance += latLngList.get(i - 1).distanceTo(latLngList.get(i));
}
return distance / 1000;
}
/**
* 叉积
* 矢量积
*
* @param x1
* @param y1
* @param x2
* @param y2
* @return
*/
public static double crossProduct(double x1, double y1, double x2, double y2) {
return x1 * y2 - x2 * y1;
}
/**
* 盘点点在线的左边还是右边
* @param x1
* @param y1
* @param x2
* @param y2
* @param x3
* @param y3
* @return 左边 >0 右边 < 0
*/
public static int leftRight(double x1,double y1,double x2,double y2,double x3,double y3){
double f = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
if(f > 0) return 1;
if(f < 0) return -1;
return 0;
}
/**
* 点积 ,数量积
*
* @param x1
* @param y1
* @param x2
* @param y2
* @return
*/
public static double dopProduct(double x1, double y1, double x2, double y2) {
return x1 * x2 + y1 * y2;
}
public static boolean isSameDouble(double var1, double var2) {
return Math.abs(var2 - var1) < 0.000000000001;
}
}
















