Займите положение на холсте ПОСЛЕ поворота / перевода и восстановления - PullRequest
4 голосов
/ 13 января 2012

Хорошо, это усложняется ...

В данной ситуации:
У меня есть холст размером 800x600.
Моя мышь находится в положении холста 100x200 (например).

Я сохраняю свое состояние холста.
Теперь я поворачиваю и перевожу холст, рисую квадрат.
Я восстанавливаю свое состояние холста.

Есть ли способ определить, находится ли моя мышь над квадратом?
Думаю, мне бы тоже пришлось перевести / повернуть положение мыши - в противоположном направлении, но как мне это сделать?

Ответы [ 2 ]

4 голосов
/ 13 января 2012

Вы можете получить мировое положение / вращение объектов, рекурсивно применяя эту формулу:

worldX = parentX + x * Math.cos( parentR ) - y * Math.sin( parentR );
worldY = parentY + x * Math.sin( parentR ) + y * Math.cos( parentR );
worldR = parentR + r;

Реализация javascript будет:

var deg2rad, rad2deg, getXYR;

deg2rad = function ( d ) { return d * Math.PI / 180 };
rad2deg = function ( r ) { return r / Math.PI * 180 };

getXYR = function ( node ) {
  var x, y, r,
      parentXYR, pX, pY, pR,
      nX, nY;

  x = y = r = 0;

  if ( node ) {
    parentXYR = getXYR( node.parent );
    pX = parentXYR.x;
    pY = parentXYR.y;
    pR = deg2rad( parentXYR.r );
    nX = node.x;
    nY = node.y;

    x = pX + nX * Math.cos( pR ) - nY * Math.sin( pR );
    y = pY + nX * Math.sin( pR ) + nY * Math.cos( pR );
    r = rad2deg( pR + deg2rad( node.r ) );
  }

  return { x:x, y:y, r:r };
};

Попробуйте это с этими объектами:

el1 = {x:3,y:0,r:45};
el2 = {x:0,y:0,r:45};
el1.parent = el2;
getXYR(el1);

Это не займет много времени, прежде чем вы захотите рассчитать кратчайший угол между двумя объектами, если вы получите deltaX (x2-x1) и deltaY (y2-y1) между двумя объектами, вы можете получить угол с помощью этой функции :

var getAngle = function ( dx, dy ) {
  var r = Math.atan2( dy, dx ) * 180 / Math.PI;
  return ( r > 180 )  ? r-360 :
         ( r < -180 ) ? r+360 :
         r;
}

В долгосрочной перспективе лучше учиться с использованием матриц. Эквивалентность получения мира pos / rot - это мировая матрица. Вот немного полезной информации о матрицах (в документе SVG, но это не актуально): http://www.w3.org/TR/SVG/coords.html#NestedTransformations

Вот как вы это сделаете с матрицами (и с gl-matrix lib https://github.com/toji/gl-matrix):

var getWorldMatrix = function ( node ) {
    var parentMatrix;

    if ( !node )
        return mat4.identity();

    parentMatrix = getWorldMatrix( node.parent );
    return mat4.multiply( parentMatrix, node.matrix );
};

О, я забыл, теперь, чтобы, наконец, зарегистрировать щелчок, достаточно получить координаты экрана мыши и сравнить их с положением объектов + смещением области просмотра холста.

0 голосов
/ 13 января 2012

Да, вам нужно либо перевести координаты мыши, либо сохранить второй набор координат для вашей фигуры. Я рекомендую сохранить второй набор координат, поскольку вы будете перемещать мышь больше раз, чем трансформируете объект. Попробуйте использовать объект, подобный этому

коробка

function Box(x, y, w, h){
    this.x = x;
    this.y = y;
    this.tx = x;    //transformed x
    this.ty = y;    //transformed y
    this.w = w;
    this.h = h;

    this.mouseover = function(x, y){
        if (this.tx < x && this.tx + this.w > x && this.ty < y && this.ty + this.h > y){
            return true;
        }
        return false;
    }

    this.applyTransformation = function(transformation){
        switch(transformation){
        case 'rotation':
            //update tx/ty to match rotation
            break;
        case 'translation':
            //update tx/ty to match translation
            break;
       default:
            //do nothing or raise exception
    }
}
...