使用旋转/缩放/平移在Google地图上定位图像 [英] Positioning image on Google Maps with rotate / scale / translate
问题描述
我正在开发用于在Google地图上定位图片的用户界面。
我开始于:和这一个。
overlaytiler.Rotater.prototype.onMouseMove_ = function(e){
var dots = this.controlDots_;
var center = overlaytiler.Rotater.prototype.getCenter_(dots);
//获取画布相对于屏幕的位置
var rect = new Array();
rect [0] = dots [0] .canvas_.getBoundingClientRect();
rect [1] = dots [1] .canvas_.getBoundingClientRect();
rect [2] = dots [2] .canvas_.getBoundingClientRect();
//计算图像的相对中心
var relCenter = {
x:(rect [0] .left + rect [2] .left)/ 2,
y:(rect [0] .top + rect [2] .top)/ 2
};
//计算图片中心到左下方的矢量
dotCorner = {
x:rect [1] .left - (rect [1] .left - relCenter.x)* 2 - relCenter.x,
y:rect [1] .top - (rect [1] .top - relCenter.y)* 2 - relCenter.y
};
//计算从中心到鼠标位置的矢量
mousePos = {
x:e.clientX - relCenter.x,
y:e.clientY - relCenter .y
};
//计算两个向量之间的角度
theta = calculateAngle(dotCorner,mousePos);
//是点向量左边的鼠标向量 - > (dotCorner.y * mousePos.x - dotCorner.x * mousePos.y> 0){
theta * = -1;参考德语数学板
;
}
//计算点的新位置并渲染它们
overlaytiler.Rotater.prototype.rotateDot_(dots [2],theta,center);
overlaytiler.Rotater.prototype.rotateDot_(dots [1],theta,center);
overlaytiler.Rotater.prototype.rotateDot_(dots [0],theta,center);
//渲染
this.render();
this.cx = e.clientX;
this.cy = e.clientY;
};
你可以看到我为矢量计算编写了一些函数(只是为了使代码更具可读性):
函数calculateScalarProduct(v1,v2)
{
return(v1.x * v2.x + v1.y * v2.y);
}
函数calculateLength(v1)
{
return(Math.sqrt(v1.x * v1.x + v1.y * v1.y)) ;
函数calculateAngle(v1,v2)
{
return(Math.acos(calculateScalarProduct(v1,v2)/(calculateLength(v1)* calculateLength v2))));
}
这是我的工作解决方案。如果您不明白某些内容,请留言,以便我的回答更全面。
工作示例: JSBin
哇,这真是一件难事。
b $ bI'm developing a user-interface for positioning an image on a google map. I started from : http://overlay-tiler.googlecode.com/svn/trunk/upload.html which is pretty close to what I want.
But instead of 3 contact points I want a rotate tool, a scale tool and a translate tool (the later exists).
I tried to add a rotate tool but it doesn't work as I expected :
I put a dot on the left bottom corner that control the rotation (around the center of the image). The mouse drag the control dot and I calculate the 3 others points.
My code is based on the mover object but I changed the onMouseMove function :
overlaytiler.Rotater.prototype.rotateDot_ = function(dot, theta, origin) {
dot.x = ((dot.x - origin.x) * Math.cos(theta) - (dot.y - origin.y) * Math.sin(theta)) + origin.x;
dot.y = ((dot.x - origin.x) * Math.sin(theta) + (dot.y - origin.y) * Math.cos(theta)) + origin.y;
dot.render();
};
overlaytiler.Rotater.prototype.onMouseMove_ = function(e) {
var dots = this.controlDots_;
var center = overlaytiler.Rotater.prototype.getCenter_(dots);
// Diagonal length
var r = Math.sqrt(Math.pow(this.x - center.x, 2) + Math.pow(this.y - center.y, 2));
var old = {
x: this.x,
y: this.y
};
// Real position
var newPos = {
x: this.x + e.clientX - this.cx,
y: this.y + e.clientY - this.cy
}
var newR = Math.sqrt(Math.pow(newPos.x - center.x, 2) + Math.pow(newPos.y - center.y, 2));
var theta = - Math.acos((2 * r * r - (Math.pow(newPos.x - old.x, 2) + Math.pow(newPos.y - old.y, 2))) / (2 * r * r));
// Fixed distance position
this.x = (newPos.x - center.x) * (r / newR) + center.x;
this.y = (newPos.y - center.y) * (r / newR) + center.y;
dots[1].x = center.x + (center.x - this.x);
dots[1].y = center.y + (center.y - this.y);
dots[1].render();
overlaytiler.Rotater.prototype.rotateDot_(dots[2], theta, center);
overlaytiler.Rotater.prototype.rotateDot_(dots[0], theta, center);
// Render
this.render();
this.cx = e.clientX;
this.cy = e.clientY;
};
Unfortunately there is a problem with precision and angle sign.
After a few rotations the image is highly distorted and rotation is supported only in one direction.
I wonder how I can achieve a great precision and without any distortion.
Maybe my approach is useless here (try to move the corners at the right coordinates), I tried to rotate the image with the canvas but my attempts were unsuccessful.
Edit : Full working version : http://jsbin.com/iQEbIzo/7/
rotation is supported only in one direction
This is due to how you calculate the angle between two vectors. It always gives you the same vector no matter if the mouse is right of the dot or not. I've found a solution in a german math board (unfortunately I cant access the site without using the cache of Google : cached version).
Note that in this example the angle α is on both sides the same and not as you would expect -α in the second one. To find out if the vector a is always on "the same side" of vector b you can use this formula.
ax*by - ay*bx
This is either positive or negative. You you simply can change the sign of the angle to α * -1
.
I modified some parts of your code.
overlaytiler.Rotater.prototype.rotateDot_ = function(dot, theta, origin) {
// translate to origin
dot.x -= origin.x ;
dot.y -= origin.y ;
// perform rotation
newPos = {
x: dot.x*Math.cos(theta) - dot.y*Math.sin(theta),
y: dot.x*Math.sin(theta) + dot.y*Math.cos(theta)
} ;
dot.x = newPos.x ;
dot.y = newPos.y ;
// translate back to center
dot.x += origin.x ;
dot.y += origin.y ;
dot.render();
};
If you want to know, how I rotate the points please reference to this site and this one.
overlaytiler.Rotater.prototype.onMouseMove_ = function(e) {
var dots = this.controlDots_;
var center = overlaytiler.Rotater.prototype.getCenter_(dots);
// get the location of the canvas relative to the screen
var rect = new Array() ;
rect[0] = dots[0].canvas_.getBoundingClientRect() ;
rect[1] = dots[1].canvas_.getBoundingClientRect() ;
rect[2] = dots[2].canvas_.getBoundingClientRect() ;
// calculate the relative center of the image
var relCenter = {
x: (rect[0].left + rect[2].left) / 2,
y: (rect[0].top + rect[2].top) / 2
} ;
// calculate a vector from the center to the bottom left of the image
dotCorner = {
x: rect[1].left - (rect[1].left - relCenter.x) * 2 - relCenter.x,
y: rect[1].top - (rect[1].top - relCenter.y) * 2 - relCenter.y
} ;
// calculate a vector from the center to the mouse position
mousePos = {
x: e.clientX - relCenter.x,
y: e.clientY - relCenter.y
} ;
// calculate the angle between the two vector
theta = calculateAngle(dotCorner, mousePos) ;
// is the mouse-vector left of the dot-vector -> refer to the german math board
if(dotCorner.y*mousePos.x - dotCorner.x*mousePos.y > 0) {
theta *= -1 ;
}
// calculate new position of the dots and render them
overlaytiler.Rotater.prototype.rotateDot_(dots[2], theta, center);
overlaytiler.Rotater.prototype.rotateDot_(dots[1], theta, center);
overlaytiler.Rotater.prototype.rotateDot_(dots[0], theta, center);
// Render
this.render();
this.cx = e.clientX;
this.cy = e.clientY;
};
You can see that I wrote some function for vector calculations (just to make the code more readable):
function calculateScalarProduct(v1,v2)
{
return (v1.x * v2.x + v1.y * v2.y) ;
}
function calculateLength(v1)
{
return (Math.sqrt(v1.x*v1.x + v1.y*v1.y)) ;
}
function calculateAngle(v1, v2)
{
return (Math.acos(calculateScalarProduct(v1,v2) / (calculateLength(v1)*calculateLength(v2)))) ;
}
This is my working solution. Comment if you don't understand something, so I can make my answer more comprehensive.
Working example: JSBin
Wow, this was a tough one.
这篇关于使用旋转/缩放/平移在Google地图上定位图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!