序言:Google地图API有一个issue logged,要求能够更正街景图块的滚动角度以补偿山丘。我想出了一个客户端解决方法,涉及到tile容器上的一些css魔法。这是我的旋转功能:
rotate: function() {
var tilesLoaded = setInterval(function() {
var tiles = $('map-canvas').getElementsByTagName('img');
for (var i=0; i<tiles.length; i++) {
if (tiles[i].src.indexOf(maps.panorama.getPano()) > -1) {
if (typeof maps.panorama.getPhotographerPov != 'undefined') {
var pov = maps.panorama.getPhotographerPov(),
pitch = pov.pitch,
cameraHeading = pov.heading;
/**************************
// I need help with my logic here.
**************************/
var yaw = pov.heading - 90;
if (yaw < 0) yaw += 360;
var scale = ((Math.abs(maps.heading - yaw) / 90) - 1) * -1;
pitch = pov.pitch * scale;
tiles[i].parentNode.parentNode.style.transform = 'rotate(' + pitch + 'deg)';
clearInterval(tilesLoaded);
return;
}
}
}
}, 20);
}
完整(且更全面评论)的概念验证是this JSFiddle。奇怪的是,如果我在JSFiddle中的示例中根本没有计算,那么地平线就是完全水平的,但是这个结果对于每个Lat / Lng都不一致。这只是巧合。
所以,我需要根据客户标题,摄影师的标题和摄影师的音调来计算客户端标题的滚动。假设摄影师面朝上坡或下坡,pov.pitch
是最高级的(最小或最大限制)。如何在一定程度上计算出面向侧面的所需音高?
编辑:我发现了一个似乎运作良好的等式。我更新了代码和小提琴。虽然它似乎非常接近答案,但我的算法是线性的。我相信正确的方程应该是对数的,导致更接近相机前进和相反的更微妙的调整,而相机的左右调整更大。
答案 0 :(得分:1)
我找到了我想要的答案。计算涉及球形三角学,在研究这个问题之前我甚至都不知道。如果有人注意到任何问题,请发表评论。或者,如果你有一个比我找到的解决方案更好的解决方案,请随意添加你的答案,如果它比我自己更可靠或效率更高,我可能会接受它。
无论如何,如果瓷砖画布是一个球体,0间距(地平线)是一个平面,而相机间距是另一个与摄影师相交的平面,两个平面将spherical lune投影到画布上。此lune可用于计算spherical triangle其中:
有两个角度和一个边可用,可以使用spherical law of sines计算球面三角形的其他属性。不需要整个三角形 - 只有与极角相对的一侧。因为这是超出我技能的数学,我不得不借用this spherical triangle calculator的逻辑。特别感谢emfril!
The jsfiddle已更新。我的生产辊吸气剂已更新如下:
function $(what) { return document.getElementById(what); }
var maps = {
get roll() {
function acos(what) {
return (Math.abs(Math.abs(what) - 1) < 0.0000000001)
? Math.round(Math.acos(what)) : Math.acos(what);
}
function sin(what) { return Math.sin(what); }
function cos(what) { return Math.cos(what); }
function abs(what) { return Math.abs(what); }
function deg2rad(what) { return what * Math.PI / 180; }
function rad2deg(what) { return what * 180 / Math.PI; }
var roll=0;
if (typeof maps.panorama.getPhotographerPov() != 'undefined') {
var pov = maps.panorama.getPhotographerPov(),
clientHeading = maps.panorama.getPov().heading;
while (clientHeading < 0) clientHeading += 360;
while (clientHeading > 360) clientHeading -= 360;
// Spherical trigonometry method
a1 = deg2rad(abs(pov.pitch));
a2 = deg2rad(90);
yaw = deg2rad((pov.heading < 0 ? pov.heading + 360 : pov.heading) - clientHeading);
b1 = acos((cos(a1) * cos(a2)) + (sin(a1) * sin(a2) * cos(yaw)));
if (sin(a1) * sin(a2) * sin(b1) !== 0) {
roll = acos((cos(a1) - (cos(a2) * cos(b1))) / (sin(a2) * sin(b1)));
direction = pov.heading - clientHeading;
if (direction < 0) direction += 360;
if (pov.pitch < 0)
roll = (direction < 180) ? rad2deg(roll) * -1 : rad2deg(roll);
else
roll = (direction > 180) ? rad2deg(roll) * -1 : rad2deg(roll);
} else {
// Fall back to algebraic estimate to avoid divide-by-zero
var yaw = pov.heading - 90;
if (yaw < 0) yaw += 360;
var scale = ((abs(clientHeading - yaw) / 90) - 1) * -1;
roll = pov.pitch * scale;
if (abs(roll) > abs(pov.pitch)) {
var diff = (abs(roll) - abs(pov.pitch)) * 2;
roll = (roll < 0) ? roll + diff : roll - diff;
}
}
}
return roll;
}, // end maps.roll getter
// ... rest of maps object...
} // end maps{}
旋转全景图块容器后,还需要展开容器以隐藏空白角。我最初使用的是二维正弦法,但我发现了more efficient shortcut。谢谢谭先生!
function deg2rad(what) { return what * Math.PI / 180; }
function cos(what) { return Math.cos(deg2rad(what)); }
function sin(what) { return Math.sin(deg2rad(what)); }
var W = $('map-canvas').clientWidth,
H = $('map-canvas').clientHeight,
Rot = Math.abs(maps.originPitch);
// pixels per side
maps.growX = Math.round(((W * cos(Rot) + H * cos(90 - Rot)) - W) / 2);
maps.growY = Math.round(((W * sin(Rot) + H * sin(90 - Rot)) - H) / 2);
此答案将不再编辑,因为我不希望将其转换为社区维基答案。当我发生更新时,它们将应用于fiddle。