Google 地图 Android API:根据 GroundOverlay 的 PNG 已知像素绘制多边形
Google Maps Android API: Draw polygon based on pixels known from GroundOverlay's PNG
我正在使用 Google 地图 Android API 使用以下代码在 Google 地图上添加一个 PNG 文件作为自己的平面图:
GroundOverlayOptions groundOverlayOptions = new GroundOverlayOptions();
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromAsset("building-d.png");
groundOverlayOptions.image(bitmapDescriptor);
groundOverlayOptions.anchor(0, 1);
LatLng buildingSW = new LatLng(47.014815, 8.305098);
LatLng buildingNE = new LatLng(47.015148, 8.305440);
LatLng buildingNW = new LatLng(47.015168, 8.305144);
LatLng buildingSE = new LatLng(47.014792, 8.305385);
Location swLoc = locationFromLatLng(buildingSW);
Location seLoc = locationFromLatLng(buildingSE);
Location nwLoc = locationFromLatLng(buildingNW);
Location neLoc = locationFromLatLng(buildingNE);
float angle = swLoc.bearingTo(nwLoc);
groundOverlayOptions.bearing(angle);
float width = swLoc.distanceTo(seLoc);
groundOverlayOptions.position(buildingSW, width);
mMap.addGroundOverlay(groundOverlayOptions);
现在我知道在 PNG 中像素坐标 422/301、708/301、422/10 和 708/10(这些是角)处有一个房间。我想在覆盖那个房间的 GroundOverlay
上画一个多边形。我该怎么做?我是否需要将我的像素坐标转换为 LatLng
,如果需要,如何转换?
顺便说一下:我真的必须为 GroundOverlay
使用 PNG 吗?是否没有其他受支持的矢量格式,如 eps、pdf、...?
你应该这样工作:
你的室内地图位置应该相对于一个特定的点(比如说 BOTTOM-LEFT 是 0,0),然后所有其他位置都将相对于那个点以米为单位,所以你通常会得到小于 100 米的值。
有了这个你就得"move, rotate and scale"关于世界的室内地图。
只需在桌面上拿一张不是 LAT/LNG 的地图,然后找到您拥有的相同室内点的坐标(通常我们会得到左下角和右上角位置的真实和室内位置),这样您就可以找到它的位置应该在世界上。
也看看比例因子(取决于纬度,地图必须缩放)
https://en.wikipedia.org/wiki/Mercator_projection#Scale_factor
我们通过执行类似 1/cos(latitudeINradians)
的操作来计算该值
public static double getScalingFactor(double latitude) {
return 1 / (Math.cos(Math.toRadians(latitude)));
}
如果你能找到办法,请告诉我,否则我会搜索并尝试剥离我们的代码
看到你对另一个答案的评论,让我用一些代码来完成:
在 latlng 47.014816、8.305098 中设置 "origin" 后,您必须将这些坐标转换为墨卡托坐标,您可以执行类似于以下操作的操作:
public boolean initializeByTwoCouplesOfCooordsAndScale(double[] coordAreal, double[] coordBreal, double[] coordAvirtual, double[] coordBvirtual, double scalingFactor) {
if (coordAreal[0] == coordBreal[0] && coordAvirtual[1] == coordBvirtual[1] && coordAreal[1] == coordBreal[1] && coordAvirtual[0] == coordBvirtual[0]) {
System.err.println("Coordinates must not be the same!");
return false;
}
// aPoint is considered the "origin" point (0,0)
aPoint = coordAreal;
bPoint = coordAvirtual;
// now calculate the angle of the Real world coordinate for the points
double deltaRy = coordBreal[1] - coordAreal[1];
double deltaRx = coordBreal[0] - coordAreal[0];
double aR = Math.atan2(deltaRy, deltaRx);
// Now calculate the angle of the virtual world coordinates
double deltaVy = coordBvirtual[1] - coordAvirtual[1];
double deltaVx = coordBvirtual[0] - coordAvirtual[0];
double aV = Math.atan2(deltaVy, deltaVx);
// Set the transformation angle as the difference between the real and the virtual angles.
mPhi= (aR - aV);
// Set the scaling factor as the provided one
mScale = (scalingFactor);//scaling factor is in function below
// Calculate the scaling factor error correction using the distances of the two systems.
return true;
}
public static double getScalingFactor(double latitude) {
return 1 / (Math.cos(Math.toRadians(纬度)));
}
所以你可以调用方法:
initializeByTwoCouplesOfCooordsAndScale(new double[]{MERCATOR_LNG,MERCATOR_LAT},//real coordinates for point A REMEMBER: LNG,LAT = x,y!
new double[]{0d,0d}, //Virual coordinates for point A
new double[]{MERCATOR_POINT_B_LNG, MERCATOR_POINT_B_LAT},//real point B
new double[]{X_METERS,Y_METERS},//coordinates in meters of point B in virtual map
getScalingFactor(47.014816));
那你就可以用这个函数变形了:
public double[] transform(double[] coord) {
double[] transCoord = new double[2];
double xscaled = (coord[0] - bPoint[0]) * mScale; // XXX bPoint is the position of origin point in the "VIRTUAL" world. [0] is the x coordinate
double yscaled = (coord[1] - bPoint[1]) * mScale;
transCoord[0] = (xscaled * Math.cos(mPhi)) - (yscaled * Math.sin(mPhi)) + aPoint[0]; //aPoint is the point with real coordinates of origin!
transCoord[1] = (xscaled * Math.sin(mPhi)) + (yscaled * Math.cos(mPhi)) + aPoint[1];
return transCoord;
}
您可以在网上找到一种将 latlng 转换为 mercator 的方法,它只是一堆数学 ;)
我正在使用 Google 地图 Android API 使用以下代码在 Google 地图上添加一个 PNG 文件作为自己的平面图:
GroundOverlayOptions groundOverlayOptions = new GroundOverlayOptions();
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromAsset("building-d.png");
groundOverlayOptions.image(bitmapDescriptor);
groundOverlayOptions.anchor(0, 1);
LatLng buildingSW = new LatLng(47.014815, 8.305098);
LatLng buildingNE = new LatLng(47.015148, 8.305440);
LatLng buildingNW = new LatLng(47.015168, 8.305144);
LatLng buildingSE = new LatLng(47.014792, 8.305385);
Location swLoc = locationFromLatLng(buildingSW);
Location seLoc = locationFromLatLng(buildingSE);
Location nwLoc = locationFromLatLng(buildingNW);
Location neLoc = locationFromLatLng(buildingNE);
float angle = swLoc.bearingTo(nwLoc);
groundOverlayOptions.bearing(angle);
float width = swLoc.distanceTo(seLoc);
groundOverlayOptions.position(buildingSW, width);
mMap.addGroundOverlay(groundOverlayOptions);
现在我知道在 PNG 中像素坐标 422/301、708/301、422/10 和 708/10(这些是角)处有一个房间。我想在覆盖那个房间的 GroundOverlay
上画一个多边形。我该怎么做?我是否需要将我的像素坐标转换为 LatLng
,如果需要,如何转换?
顺便说一下:我真的必须为 GroundOverlay
使用 PNG 吗?是否没有其他受支持的矢量格式,如 eps、pdf、...?
你应该这样工作: 你的室内地图位置应该相对于一个特定的点(比如说 BOTTOM-LEFT 是 0,0),然后所有其他位置都将相对于那个点以米为单位,所以你通常会得到小于 100 米的值。
有了这个你就得"move, rotate and scale"关于世界的室内地图。 只需在桌面上拿一张不是 LAT/LNG 的地图,然后找到您拥有的相同室内点的坐标(通常我们会得到左下角和右上角位置的真实和室内位置),这样您就可以找到它的位置应该在世界上。 也看看比例因子(取决于纬度,地图必须缩放) https://en.wikipedia.org/wiki/Mercator_projection#Scale_factor
我们通过执行类似 1/cos(latitudeINradians)
的操作来计算该值public static double getScalingFactor(double latitude) {
return 1 / (Math.cos(Math.toRadians(latitude)));
}
如果你能找到办法,请告诉我,否则我会搜索并尝试剥离我们的代码
看到你对另一个答案的评论,让我用一些代码来完成:
在 latlng 47.014816、8.305098 中设置 "origin" 后,您必须将这些坐标转换为墨卡托坐标,您可以执行类似于以下操作的操作:
public boolean initializeByTwoCouplesOfCooordsAndScale(double[] coordAreal, double[] coordBreal, double[] coordAvirtual, double[] coordBvirtual, double scalingFactor) {
if (coordAreal[0] == coordBreal[0] && coordAvirtual[1] == coordBvirtual[1] && coordAreal[1] == coordBreal[1] && coordAvirtual[0] == coordBvirtual[0]) {
System.err.println("Coordinates must not be the same!");
return false;
}
// aPoint is considered the "origin" point (0,0)
aPoint = coordAreal;
bPoint = coordAvirtual;
// now calculate the angle of the Real world coordinate for the points
double deltaRy = coordBreal[1] - coordAreal[1];
double deltaRx = coordBreal[0] - coordAreal[0];
double aR = Math.atan2(deltaRy, deltaRx);
// Now calculate the angle of the virtual world coordinates
double deltaVy = coordBvirtual[1] - coordAvirtual[1];
double deltaVx = coordBvirtual[0] - coordAvirtual[0];
double aV = Math.atan2(deltaVy, deltaVx);
// Set the transformation angle as the difference between the real and the virtual angles.
mPhi= (aR - aV);
// Set the scaling factor as the provided one
mScale = (scalingFactor);//scaling factor is in function below
// Calculate the scaling factor error correction using the distances of the two systems.
return true;
}
public static double getScalingFactor(double latitude) { return 1 / (Math.cos(Math.toRadians(纬度))); }
所以你可以调用方法:
initializeByTwoCouplesOfCooordsAndScale(new double[]{MERCATOR_LNG,MERCATOR_LAT},//real coordinates for point A REMEMBER: LNG,LAT = x,y!
new double[]{0d,0d}, //Virual coordinates for point A
new double[]{MERCATOR_POINT_B_LNG, MERCATOR_POINT_B_LAT},//real point B
new double[]{X_METERS,Y_METERS},//coordinates in meters of point B in virtual map
getScalingFactor(47.014816));
那你就可以用这个函数变形了:
public double[] transform(double[] coord) {
double[] transCoord = new double[2];
double xscaled = (coord[0] - bPoint[0]) * mScale; // XXX bPoint is the position of origin point in the "VIRTUAL" world. [0] is the x coordinate
double yscaled = (coord[1] - bPoint[1]) * mScale;
transCoord[0] = (xscaled * Math.cos(mPhi)) - (yscaled * Math.sin(mPhi)) + aPoint[0]; //aPoint is the point with real coordinates of origin!
transCoord[1] = (xscaled * Math.sin(mPhi)) + (yscaled * Math.cos(mPhi)) + aPoint[1];
return transCoord;
}
您可以在网上找到一种将 latlng 转换为 mercator 的方法,它只是一堆数学 ;)