Как определить координаты XY(пиксельные) точки на плане? если известны координаты gps 4-ех его углов
Есть план картинка, у которого известны ширина, высота, а также координаты gps всех углов плана.
Как получить пиксельные координаты случайной точки на плане, если известны её gps координаты?
- План на "карте" может находиться под любым углом.
- Высота над уровнем моря не важна, кривизной земли тоже можно пренебречь.
- Заранее известно что точка 100% лежит на плане, и не может лежать за его границами
- План строго имеет прямоугольную форму
Go шаблон
package main
import (
"fmt"
)
type Point struct {
Num uint `json:"num" xml:"num" bson:"num" sql:"unique_index:idx_point_num"`
X float64 `json:"x" xml:"x" bson:"x"`
Y float64 `json:"y" xml:"y" bson:"y"`
LatLng
}
type LatLng struct {
Lat float64 `json:"lat" xml:"lat" bson:"lat"`
Lon float64 `json:"lon" xml:"lon" bson:"lon"`
}
func main() {
points := make([]Point, 4)
points[0].Num = 1 //Левый Верхний
points[0].X = 0.0
points[0].Y = 0.0
points[0].LatLng.Lat = 59.94082501317843
points[0].LatLng.Lon = 30.313837582926084
points[1].Num = 2 //Правый Верхний
points[1].X = 1182.0
points[1].Y = 0.0
points[1].LatLng.Lat = 59.934845940050806
points[1].LatLng.Lon = 30.36341272121419
points[2].Num = 3 //Правый Нижний
points[2].X = 1182.0
points[2].Y = 174.0
points[2].LatLng.Lat = 59.931189953842654
points[2].LatLng.Lon = 30.361653262718022
points[3].Num = 4 //Левый Нижний
points[3].X = 0.0
points[3].Y = 174.0
points[3].LatLng.Lat = 59.937169032133106
points[3].LatLng.Lon = 30.312080655319818
targetPoint := LatLng{Lat:59.937169032133106, Lon:30.312080655319818}
X := ???
Y := ???
fmt.Println(X)
fmt.Println(Y)
}
points - массив точек (кол-во 4) описывающий координаты всех 4 углов прямоугольника/плана
targetPoint - gps координаты точки, пиксельные координаты которой требуется определить.
Ответы (1 шт):
Автор решения: Sergey
→ Ссылка
за неимением ответа решил через сопоставление прямоугольников, с последующим расчётом через треугольник. В пределах одного здания, и даже стадиона, точность конвертации координат очень велика. Проверил и в северном и в южном полушарии, и при разных углах поворота плана относительно карты мира.
private static ImmutablePair<Integer,Integer> GetPixelFromGps(
CalibrationPoints[] points, //массив из 4 точек, обозначающих углы плана
GpsCoordinates gps, // координаты точки в gps
double width, // ширина плана
double height // высота плана
) {
double w = distanceInKmBetweenEarthCoordinates( //расстояние от левого вернего угла до правого верхнего, он же width в километрах
points[0].getLat(),
points[0].getLon(),
points[1].getLat(),
points[1].getLon()
);
double h = distanceInKmBetweenEarthCoordinates( //расстояние от левого вернего угла до левого нижнего, он же height в километрах
points[0].getLat(),
points[0].getLon(),
points[3].getLat(),
points[3].getLon()
);
double x0 = distanceInKmBetweenEarthCoordinates( //расстояние от левого вернего угла до точки, в километрах
points[0].getLat(),
points[0].getLon(),
gps.getLat(),
gps.getLon()
);
double x1 = distanceInKmBetweenEarthCoordinates( //расстояние от правого вернего угла до точки, в километрах
meta.getCalibrationPoints()[1].getLat(),
meta.getCalibrationPoints()[1].getLon(),
gps.getLat(),
gps.getLon()
);
BigDecimal kefX = BigDecimal.valueOf(w).divide(BigDecimal.valueOf(meta.getWidth()), 20, RoundingMode.UP); // коеф. отношения ширины в километрах к пикселям
BigDecimal kefY = BigDecimal.valueOf(h).divide(BigDecimal.valueOf(meta.getHeight()), 20, RoundingMode.UP); //коеф. отношения высоты в километрах к пикселям
double pX = (w + x0 + x1) / 2; // полупериметр
BigDecimal zX = BigDecimal.valueOf(Math.sqrt(pX * (pX - w) * (pX - x0) * (pX- x1))).multiply(BigDecimal.valueOf(2)).divide(new BigDecimal(w),20, RoundingMode.UP); // высота треугольника
BigDecimal xtX = BigDecimal.valueOf(Math.sqrt(BigDecimal.valueOf( x0 * x0 ).subtract(zX.multiply(zX)).doubleValue())); // катет треугольника
BigDecimal x = xtX.divide(kefX,20, RoundingMode.UP);
BigDecimal y = zX.divide(kefY,20, RoundingMode.UP);
return new ImmutablePair<Integer,Integer>(Math.round( x.doubleValue()), Math.round(y.doubleValue()) );
}
private static double distanceInKmBetweenEarthCoordinates(double lat1, double lon1, double lat2, double lon2) {
double earthRadiusKm = 6371.0;
double dLat = degreeToRadian(lat2-lat1);
double dLon = degreeToRadian(lon2 - lon1);
lat1 = degreeToRadian(lat1);
lat2 = degreeToRadian(lat2);
double a = Math.sin(dLat/2)*Math.sin(dLat/2) + Math.sin(dLon/2)*Math.sin(dLon/2)*Math.cos(lat1)*Math.cos(lat2);
double c = 2*Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return earthRadiusKm * c;
}
для наглядности
