使用旋转/缩放/平移在Google地图上定位图像 [英] Positioning image on Google Maps with rotate / scale / translate

查看:155
本文介绍了使用旋转/缩放/平移在Google地图上定位图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发用于在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 $ b

I'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.

http://jsbin.com/iQEbIzo/4/

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆