Get position on canvas AFTER rotation / translation and recovery

Ok, this gets complicated ...

This situation:
I have a canvas sized 800x600.
My mouse is in a canvas position of 100x200 (for example).

I keep the state of the canvas.
Now I turn and translate the canvas, I draw a square.
I restore the state of the canvas.

Is there a way to determine if my mouse is above a square?
I think I would have to translate / rotate my mouse position, as well as in the opposite direction, but how would I do it?

+4
source share
2 answers

You can get the position / rotation of the world of objects by recursively applying this formula:

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

The javascript implementation will be:

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

Try using these objects:

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

Not long before you want to calculate the shortest angle between two objects, if you get deltaX (x2-x1) and deltaY (y2-y1) between two objects, you can get an angle with this function

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

Ultimately, it's better to learn how to use matrices. The equivalence of getting the pos / rot world is the world matrix. Here is some good information about matrices (in an SVG document, but this is not relevant): http://www.w3.org/TR/SVG/coords.html#NestedTransformations

So you would do it using matrices (and 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 ); }; 

Oh, I forgot, now, to finally register a click, you just get the coordinates of the mouse screen and compare them with the position of the objects + offset viewport.

+4
source

Yes, you need to either translate the coordinates of the mouse, or save the second set of coordinates for your figure. I recommend saving the second set of coordinates, since you will move the mouse more times than you transform the object. Try to use such an object

Insert

 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 } } 
-1
source

Source: https://habr.com/ru/post/1390749/


All Articles