【问题标题】:Positioning image on Google Maps with rotate / scale / translate使用旋转/缩放/翻译在 Google 地图上定位图像
【发布时间】:2014-02-21 12:06:17
【问题描述】:

我正在开发一个用于在谷歌地图上定位图像的用户界面。 我从:http://overlay-tiler.googlecode.com/svn/trunk/upload.html 开始,这与我想要的非常接近。

但我想要一个旋转工具、一个缩放工具和一个平移工具(后者存在),而不是 3 个接触点。

我尝试添加一个旋转工具,但它没有按预期工作:

我在左下角放了一个点来控制旋转(围绕图像的中心)。鼠标拖动控制点,我计算其他 3 个点。

我的代码基于移动器对象,但我更改了 onMouseMove 函数:

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;
};

不幸的是,精度和角度符号存在问题。

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

经过几次旋转后,图像高度失真,仅支持一个方向的旋转。

我想知道如何才能实现高精度且不失真。

也许我的方法在这里没用(尝试将角移动到正确的坐标),我尝试使用画布旋转图像但我的尝试不成功。

编辑:完整工作版:http://jsbin.com/iQEbIzo/7/

【问题讨论】:

    标签: javascript google-maps image-manipulation image-rotation


    【解决方案1】:

    这是我的版本。 @efux 和 @Ben 的答案更加完整且设计精良,但是当您放大/缩小时,地图不会按比例放大/缩小。覆盖很可能需要这样做,因为它们用于在现有地图上放置“第二张地图”或照片。

    这里是 JSFiddle:http://jsfiddle.net/adelriosantiago/3tzzwmsx/4/

    绘制的代码如下:

    DebugOverlay.prototype.draw = function() {
                    var overlayProjection = this.getProjection();
                    var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
                    var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
        var div = this.div_;
        div.style.left = sw.x + 'px';
        div.style.top = ne.y + 'px';
        div.style.width = (ne.x - sw.x) + 'px';
        div.style.height = (sw.y - ne.y) + 'px';
        div.style.transform = 'rotate(' + rot + 'deg)';
    };
    

    如果需要,可以肯定此代码可以在 efux 和 Ben 代码上实现,但我还没有尝试过。

    请注意,当旋转标记移动时,框标记不会更新其位置...

    【讨论】:

    • 我在 JSFiddle 上遗漏了一些东西。我一直看到point1(NaN, NaN)point2(NaN, NaN),但控制台中的任何地方都没有错误。我根本没有在输出的任何地方看到灰色矩形图像,更不用说旋转机会了。我做错了吗?
    • @zipzit 我修复了 JSFiddle,看来谷歌地图现在使用 lat() 和 lng() 而不是 .k 和 .D 值。
    • 哇。惊人的。所以.. 我刚刚在堆栈上发布了this 问题。我不应该那样做吗?哎哟。我喜欢你的 JS 小提琴!
    • @zipzit 谢谢!关于另一个问题,我认为它很好,我会保持原样,看看它是否能得到答案。
    【解决方案2】:

    仅支持单向旋转

    这是由于您如何计算两个向量之间的角度。 不管鼠标是否在点的右边,它总是给你相同的向量。我在german math board 中找到了解决方案(不幸的是,如果不使用 Google 的缓存,我无法访问该网站:cached version)。

    请注意,在此示例中,角度 α 在两侧是相同的,而不是您所期望的第二个中的 -α。要确定向量 a 是否始终在向量 b 的“同一侧”,您可以使用此公式。

    ax*by - ay*bx
    

    这是正面的或负面的。您只需将角度的符号更改为α * -1

    我修改了你的部分代码。

    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();
    };
    

    如果你想知道我是如何旋转点的,请参考this sitethis 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;                                                                                    
     };
    

    你可以看到我写了一些向量计算的函数(只是为了让代码更具可读性):

    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)))) ;
    }
    

    这是我的工作解决方案。有不明白的地方可以评论,让我的回答更全面。

    工作示例:JSBin

    哇,这太难了。

    【讨论】:

    • 恭喜!看起来它有效,我想我在角度和旋转功能上错了。
    • @BenR 很高兴我能帮上忙。我添加了进一步的注释和图形来指出我认为的主要问题。
    • 有时脚本冻结,图像恢复到原来的位置,点不能移动...控制台没有错误。
    • @BenR 移动地图时显然出错了。我通过计算相对于点的实际屏幕位置的角度来纠正这个问题。我希望这是您的意思,如果不告诉我错误发生的时间和方式,以便我可以重现它。我已经更新了上面的代码以及 JSBin。
    • 我觉得不错,恭喜!非常感谢。这确实是一个艰难的过程。
    猜你喜欢
    • 2018-10-17
    • 1970-01-01
    • 2022-01-10
    • 2020-09-07
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    相关资源
    最近更新 更多