Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Positioning image on Google Maps with rotate / scale / translate

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/

like image 487
luxcem Avatar asked Jan 29 '14 15:01

luxcem


1 Answers

Here is my version of it. @efux and @Ben answers are far more complete and well designed however the maps don't scale in/out when you zoom in/out. Overlays very likely need to do this since they are used to put a "second map" or photograph over the existing map.

Here is the JSFiddle: http://jsfiddle.net/adelriosantiago/3tzzwmsx/4/

The code that does the drawing is the following:

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

For sure this code could be implemented on efux and Ben code if needed but I haven't tried yet.

Note that the box marker does not updates its position when the rotation marker moves...

like image 156
adelriosantiago Avatar answered Oct 20 '22 00:10

adelriosantiago