'use strict';
const { Point2D } = require('../shared.js');
/**
* This mixin provides 2D transformation operations for classes with 'x', 'y',
* 'scale' and 'rotation' properties.
*
* @private
* @memberof module:mixins
*
* @mixin
*/
const Transformable2D = (sclass) =>
class Transformable2D extends sclass {
/**
* Move the transformable by the given amounts.
*
* @memberof module:mixins.Transformable2D
*
* @param {number} [ dx=0 ] - Movement along the x axis.
* @param {number} [ dy=0 ] - Movement along the y ayis.
*/
moveBy(dx = 0, dy = 0) {
this.x += dx;
this.y += dy;
}
/**
* Move the transformable to the given coordinates.
*
* @memberof module:mixins.Transformable2D
*
* @param {number} [ x=this.x ] - x coordinate to move to.
* @param {number} [ y=this.y ] - y coordinate to move to.
*/
moveTo(x = this.x, y = this.y) {
this.x = x;
this.y = y;
}
/**
* Rotate the transformable by the given amount, in radians, around the given
* x,y point.
*
* @memberof module:mixins.Transformable2D
*
* @param {number} [ radians=0 ] - The amount of rotation to apply to the
* transformable, in radians.
* @param {number} [ px=this.x ] - The x coordinate of the point around which
* to rotate.
* @param {number} [ py=this.y ] - The y coordinate of the point around which
* to rotate.
*/
rotateBy(radians = 0, px = this.x, py = this.y) {
const delta = new Point2D(this.x - px, this.y - py).rotate(radians);
this.x = px + delta.x;
this.y = py + delta.y;
this.rotation = this.rotation - radians;
}
/**
* Adjust the transformable by the given scale.
*
* @memberof module:mixins.Transformable2D
*
* @param {number} [ ds=1 ] - Change in desired scale.
* @param {number} [ mx=this.x ] - The x coordinate of the point around which
* to scale.
* @param {number} [ my=this.y ] - The y coordinate of the point around which
* to scale.
* @param {string} [ deltaFn='times' ] - The Point2D operation to apply to
* the delta point to extract the corrext this.x and this.y values. Should be
* one of 'times' or 'divideBy' depending on the use case.
*/
scaleBy(ds = 1, mx = this.x, my = this.y, deltaFn = 'multiplyBy') {
const delta = new Point2D(this.x - mx, this.y - my)[deltaFn](ds);
this.x = mx + delta.x;
this.y = my + delta.y;
this.scale = ds * this.scale;
}
/**
* Transforms a point from the transformable space to the default space. That
* is, it applies to the point the same transformations that apply to this
* Transformable2D, but in reverse.
*
* @memberof module:mixins.Transformable2D
*
* @param {number} x - x coordinate to transform.
* @param {number} y - y coordinate to transform.
*
* @return {module:shared.Point2D} The transformed point.
*/
transformPoint(x, y) {
return new Point2D(x, y).rotate(-this.rotation).divideBy(this.scale).add(this);
}
/**
* Reverses "transformPoint"
*
* @memberof module:mixins.Transformable2D
*
* @param {number} x - x coordinate to transform.
* @param {number} y - y coordinate to transform.
*
* @return {module:shared.Point2D} The transformed point.
*/
reversePoint(x, y) {
return new Point2D(x, y).minus(this).multiplyBy(this.scale).rotate(this.rotation);
}
/**
* Transforms a "change" point from the transformable space to the default
* space. Very much like the 'transformPoint' function, except that it does
* not apply translation.
*
* @memberof module:mixins.Transformable2D
*
* @param {number} dx - dx coordinate to transform.
* @param {number} dy - dy coordinate to transform.
*
* @return {module:shared.Point2D} The transformed point.
*/
transformPointChange(dx, dy) {
return new Point2D(dx, dy).rotate(-this.rotation).divideBy(this.scale);
}
/**
* Reverses "transformPointChange"
*
* @memberof module:mixins.Transformable2D
*
* @param {number} dx - dx coordinate to transform.
* @param {number} dy - dy coordinate to transform.
*
* @return {module:shared.Point2D} The transformed point.
*/
reversePointChange(dx, dy) {
return new Point2D(dx, dy).multiplyBy(this.scale).rotate(this.rotation);
}
};
module.exports = Transformable2D;