/**
* Author:domjun
* description:Calculate spatial distances
* usage:
* 1 getInstance()->get an instance
* 2 calculatedSpatial()->getLocation3Dlist
* 3 getSpatial()->getSpatialData
*/
public class SpatialDisUtil {
public float Data_fitting_a = 0, Data_fitting_b = 0, Data_fitting_c = 0;
private List<Location3D> outlist;
private static SpatialDisUtil INSTANCE;
public static SpatialDisUtil getInstance() {
if (INSTANCE == null) {
synchronized (SpatialDisUtil.class) {
if (INSTANCE == null) {
INSTANCE = new SpatialDisUtil();
}
}
}
return INSTANCE;
}
private SpatialDisUtil() {
}
/**
* @param location3D
* @param spatialDataCall
* Calculate the closest horizontal, vertical,
* and three-dimensional distances between latitude
* and longitude points and the dataset
*/
public void getSpatial(Location3D location3D,SpatialDataCall spatialDataCall) {
try {
float hdis = calculateLineDistance(getOutlist().get(0), location3D);
float vdis = Math.abs(location3D.getAltitude() - getOutlist().get(0).getAltitude());
float sdis = (float) Math.sqrt(Math.pow(hdis, 2) + Math.pow(vdis, 2));
for (int i = 1; i < getOutlist().size(); i++) {
float hdiss = calculateLineDistance(getOutlist().get(i), location3D);
float vdiss = Math.abs(location3D.getAltitude() - getOutlist().get(i).getAltitude());
float sdiss = (float) Math.sqrt(Math.pow(hdiss, 2) + Math.pow(vdiss, 2));
if (sdiss < sdis) {
hdis = hdiss;
vdis = vdiss;
sdis =sdiss;
}
}
spatialDataCall.dataCall(hdis,vdis,sdis);
} catch (Exception e) {
e.printStackTrace();
spatialDataCall.dataCall(0,0,0);
}
}
/**
* @param a start point
* @param b any point
* @param c end point
* @param spatialCalculatCall
* Enter three latitude and longitude points to get the fitting set
* If the distance between point A and point C is more than 5000 meters, it cannot be calculated
*/
public void calculatedSpatial(Location3D a, Location3D b, Location3D c, SpatialCalculatCall spatialCalculatCall) {
try {
new Thread(new Runnable() {
@Override
public void run() {
outlist = new ArrayList<>();
List<Location3D> location3DList = new ArrayList<>();
long num = (int) (calculateLineDistance(a, c) * 1000);
if (num > 5000000) {
spatialCalculatCall.calculatSucces(false,INSTANCE);
return;
}
location3DList.add(a);
location3DList.add(b);
location3DList.add(c);
Data_fitting(location3DList);
float latdif = (float) ((c.getLatitude() - a.getLatitude()) / num);
float londif = (float) ((c.getLongitude() - a.getLongitude()) / num);
outlist.add(a);
for (int i = 0; i < num; i++) {
Location3D location3D = new Location3D(a.getLatitude() + (latdif * (i + 1)), a.getLongitude() + (londif * (i + 1)));
float dis = calculateLineDistance(a, location3D);
float y = (float) ((Math.pow(dis, 2) * Data_fitting_a) + (dis * Data_fitting_b) + Data_fitting_c);
location3D.setAltitude(y);
outlist.add(location3D);
}
outlist.add(c);
setOutlist(outlist);
spatialCalculatCall.calculatSucces(true,INSTANCE);
}
}).start();
} catch (Exception e) {
e.printStackTrace();
spatialCalculatCall.calculatSucces(false,INSTANCE);
}
}
//The unary quadratic equation ABC is calculated from three latitude and longitude points
private void Data_fitting(List<Location3D> terrainInformation) {
try {
final WeightedObservedPoints obs = new WeightedObservedPoints();
for (int i = 0; i < terrainInformation.size(); i++) {
float X = calculateLineDistance(terrainInformation.get(0), terrainInformation.get(i));
float Y = terrainInformation.get(i).getAltitude();
obs.add(X, Y);
}
final PolynomialCurveFitter fitter = PolynomialCurveFitter.create(2);
final double[] coeff = fitter.fit(obs.toList());
Data_fitting_a = (float) coeff[2];
Data_fitting_b = (float) coeff[1];
Data_fitting_c = (float) coeff[0];
} catch (Exception e) {
e.printStackTrace();
}
}
//The distance is calculated from xyz using latitude and longitude as the origin
private Location3D xyzToLonLat(Location3D location3D,float x,float y,float z){
try {
double lat=location3D.getLatitude();
double lon=location3D.getLongitude();
double a = 6378137;
double b = 6356752.3142;
double PI = 3.141592653589793238;
double f = 1 / 298.2572236;
float dis= (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
float dist= (float) Math.sqrt(Math.pow(dis, 2) + Math.pow(z, 2));
float brng = (float) Math.atan2(x,y);
if(brng>180){
brng=brng-360;
}
else if(brng<-180) {
brng=brng+360;
}
if(brng<0){
brng=brng+360;
}
double alpha1 = brng * PI / 180.0;
double sinAlpha1 = Math.sin(alpha1);
double cosAlpha1 = Math.cos(alpha1);
double tanU1 = (1 - f) * Math.tan( lat * PI / 180.0);
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)));
LatLng get_LatLng =new LatLng( lat2 * PI / 180.0,lon+( L * PI / 180.0));
return new Location3D(get_LatLng.latitude,get_LatLng.longitude,location3D.getAltitude()+z);
}catch (Exception e){
e.printStackTrace();
return null;
}
}
//Calculate the distance between two points
private float calculateLineDistance(Location3D var0, Location3D var1) {
try {
double var4 = var0.longitude;
double var6 = var0.latitude;
double var8 = var1.longitude;
double var10 = var1.latitude;
var4 *= 0.01745329251994329D;
var6 *= 0.01745329251994329D;
var8 *= 0.01745329251994329D;
var10 *= 0.01745329251994329D;
double var12 = Math.sin(var4);
double var14 = Math.sin(var6);
double var16 = Math.cos(var4);
double var18 = Math.cos(var6);
double var20 = Math.sin(var8);
double var22 = Math.sin(var10);
double var24 = Math.cos(var8);
double var26 = Math.cos(var10);
double[] var28 = new double[3];
double[] var29 = new double[3];
var28[0] = var18 * var16;
var28[1] = var18 * var12;
var28[2] = var14;
var29[0] = var26 * var24;
var29[1] = var26 * var20;
var29[2] = var22;
double var30 = Math.sqrt((var28[0] - var29[0]) * (var28[0] - var29[0]) + (var28[1] - var29[1]) * (var28[1] - var29[1]) + (var28[2] - var29[2]) * (var28[2] - var29[2]));
return (float) (Math.asin(var30 / 2.0D) * 1.27420015798544E7D);
} catch (Exception e) {
e.printStackTrace();
return 0f;
}
}
public List<Location3D> getOutlist() {
return outlist;
}
public void setOutlist(List<Location3D> outlist) {
this.outlist = outlist;
}
public interface SpatialCalculatCall {
void calculatSucces(boolean success,SpatialDisUtil spatialDisUtil);
}
public interface SpatialDataCall {
void dataCall(float hdis, float vdis, float sdis);
}
}
需要导入jar包commons-math3-3.6.1.jar